面试题(一)

1.面向对象的特征有哪些方面?

面向对象的特征主要有以下几个方面:
    封装:封装是指将对象的实现细节隐藏起来,然后通过一些公用方法来暴露该对象的功能.
    继承:继承是面向对象实现软件复用的重要手段,当子类继承父类后,子类作为一种特殊的父类,将直接获得父类的属性和方法.
    多态:多态指的是子类对象可以直接赋值给父类变量,但运行时依然表现出子类的行为特征,这意味着同一个类型的对象在执行同一个方法时,可能表现出多种行为特征.
    注:抽象也是面向对象的重要部分,抽象就是忽略一个主题中与当前目标无关的那些方面,以便更充分的注意与当前目标有关的方面,抽象并不打算了解全部问题,而只是考虑部分问题.
    虽然抽象是面向对象的重要部分,但它不是面向对象的特征之一,因为所有的编程语言都需要抽象,当开发者进行抽象时应该考虑哪些特征是软件系统所需要的,那么这些特征就应该使用程序记录并表现出来,因此,需要抽象哪些特征没有必要的规定,而是取决于软件系统的功能需求.

2.String是最基本的数据类型吗?

    不是,java中基本数据类型只有8个:byte,short,int,long,float,double,char,boolean.除了基本类型,剩下的都是引用类型,java5以后引入的枚举类型也算一种比较特殊的引用类型.

3.float f = 3.4;是否正确?

    不正确,3.4是双精度数,将双精度(double)赋值给浮点类型(float)属于下转型,会造成精度损失,因此需要强制类型转换float f = (float)3.4;或者写成float f = 3.4F;

4.int和Integer有什么区别?

    答:java是一个近乎纯洁的面向对象编程语言,但是为了编程的方便,java为每个基本类型都引入了对应的包装类型,int的包装类就是Integer,从java5开始引入了自动装箱/拆箱机制,使得二者可以互相转换.
面试代码题(一)

class AutoUnboxingTest{
  public static void main(String[] args){
    Integer a = new Integer(3);
    //将3自动封装成Integer类型
    Integer b = 3;
    int c = 3;
    //false 两个引用没有引用同一个对象
    System.out.print(a == b);
    //true a自动拆箱成int类型再和c比较
    System.out.print(a == c);
  }
}  

面试代码题(二)

public class Test{
  public static void main(String[] args){
    Integer f1 = 100,f2 = 100,f3 = 150,f4 = 150;
    //true
    System.out.println(f1 == f2);
    //false 
    //Integer值的范围在-128 ~ 127之间,如果在这个范围内,不会new新的Integer对象,而是直接引用常量池中的Integer对象.
    System.out.printlm(f3 == f4);
  }
}

5.&和&&的区别?

    &运算符有两种用法:(1)按位与;(2)逻辑与.&&运算符是短路与运算.逻辑与与短路与的差别非常巨大,虽然二者都要求运算符左右两端的布尔值都是true整个表达式的值才是true.&&之所以称为短路运算是因为,如果&&左边的表达式的值是false,右边的表达式会被直接短路掉,不会进行运算.
    很多时候我们可能都需要用&&而不是&,例如在验证用户登录时判定用户名不是null而且不是空字符串,应当写为:username != null && !username.equals(“”),二者的顺序不能交换,更不能用&运算符,因为第一个条件如果不成立,根本不能进行字符串的equals比较,否则会产生NullPointerException异常,注意:逻辑或运算符(|)和短路运算符(||)的差别也是如此.

6.解释内存中的栈(stack),堆(heap)和方法区(method area)的用法.

    通常我们定义了一个基本数据类型的变量,一个对象的引用,还有就是函数调用的现场保存都使用JVM中栈空间,而通过new关键字和构造器创建的对象则放在堆空间,堆是垃圾收集器管理的主要区域,由于现在的垃圾收集器都采用分代收集算法,所以堆空间还可以细分为新生代和老生代,再具体一点可以分为Eden,Survivor(又分为From Survivor和To Survivor),Tenured;方法区和堆都是各个线程共享的内存区域,用于存储已经被快JVM加载的类信息,常量,静态变量,JIT编译器编译后的代码等数据;程序中的字面量如直接书写的100,’hello’和常量都是放在常量池中,常量池也是方法区的一部分,栈空间操作起来最但是栈很小,栈空间用光了会引发StackOverflowError,而对和常量池空间不足则会引发OutOfMemoryError.
例子:
String str = new String("hello");
上面的语句变量str放在栈上,用new创建出来的字符串对象放在堆上,而”hello”这个字面量是放在方法区的.

7.switch是否能作用在byte上,是否能作用在long上,是否能作用在String上?

    在java5以前,switch(expr)中,expr只能在byte,short,char,int.从java5开始,java中引入了枚举类型,expr也可以是enum类型,从java7开始,expr还可以是字符串String,但是long类型在目前所有版本中都是不可以的.

8.Math.roud(11.5)等于多少?Math.round(-11.5)等于多少?

    Math.round(11.5)的返回值是12,Math.round(-11.5)的返回值是-11,四舍五入的原理是在参数上加0.5然后进行下取整.

9.用最有效的方法计算2乘以8?

    2<<3(左移3位相当于乘以2的3次方,右移3位相当于除以2的3次方).

10.数组中有没有length()方法,String有没有length()方法?

    数组中没有length()方法,有length的属性,String有length()方法.

11.构造器(constructor)是否被重写(override)?

    构造器不能被继承,因此不能被重写,但可以被重载.

12.两个对象值相同(x.equals(y)==true),但却可有不同的hash code,这句话对不对?

    不对,如果两个对象满足x.equals(y)==true,它们的哈希吗(hash code)应当相同,java对于equals方法和hashCode方法是这样规定的:(1)如果两个对象相同(equals方法返回true),那么它们的hashCode值一定相同;(2)如果两个对象的hashCode相同,它们并不一定相同

13.是否可以继承String类?

    String类是final类,不可以被继承.
    继承String本身就是一个错误,对String类型最好的重用方式是关联关系和依赖关系而不是继承关系

14.当一个对象被当作参数传递到哟个方法后,此方法可改变这个对象的属性,并可返回变化后的结果,那么这里到底是值传递还是引用传递?

    值传递,java语言的方法调用只支持参数的值传递,当一个对象实例作为一个参数被传递到方法中时,参数的值就是对该对象的引用,对象的属性可以在被调用过程中被改变,但对对象引用的改变是不会影响到调用者的.

15.String和StringBuilder,StringBuffer的区别?

    String类是不可变类,即一旦一个String对象被创建以后,包含在这个对象中的字符串序列是不可改变的,直至这个对象被销毁.
    StringBuffer对象则代表一个字符序列可变的字符串,当一个StringBuffer被创建以后,通过StringBuffer提供的append(),insert(),reverse(),setCharAt(),setLength()等方法可以改变这个字符串对象的字符序列,一旦通过StringBuffer生成了最终想要的字符串,就可以调用它的toString()方法,将其转换为一个String对象.
     StringBuilder类,它也代表字符串对象,实际上,StringBuilder和StringBuffer基本相似,两个类的构造器和方法也基本相同,不同的是,StringBuffer是线程安全的,而StringBuilder则没有实现线程安全功能,所以性能略高,因此在通常情况下,如果需要创建一个内容可变的字符串对象,则应该优先使用StringBuilder类.
三者的总结
    StringBuffer是线程安全的,每次操作字符串,String会生成一个新的对象,而StringBuffer不会,StringBUilder是非线程安全的.
    三者在执行速度方面比较:StringBuilder>StringBuffer>String
    1.如果操作少量的数据用String
    2.单线程操作字符串下操作大量数据用StringBuilder.
    3.多线程操作字符串缓冲流下操作大量数据用StringBuffer.
面试题1
    什么情况下用+运算符进行字符串连接比调用StringBuffer/StringBuilder对象的append方法连接字符串性能更高?

如果在编写代码的过程中大量使用+进行字符串评价还是会对性能造成比较大的影响,但是使用的个数在1000以下还是可以接受的,大于10000的话,执行时间将可能超过1s,会对性能产生较大影响。如果有大量需要进行字符串拼接的操作,最好还是使用StringBuffer或StringBuilder进行。

面试题2

public class Main {
  public static void main(String[] args) {
    String s1 = "Programming";
    String s2 = new String("Programming");
    String s3 = "Program";
    String s4 = "ming";
    String s5 = "Program" + "ming";
    String s6 = s3 + s4;
    //false
    System.out.println(s1 == s2);
    //true
    System.out.println(s1 == s5);
    //false
    System.out.println(s1 == s6);
    //true
    System.out.println(s1 == s6.intern());
    //false
    System.out.println(s2 == s2.intern());
  }
}

    补充:解答上面的面试题需要清楚两点:1.String对象的intern方法会得到字符串对象在常量池中对应的版本的引用(如果常量池中有一个字符串与String对象的equals结果是true),如果常量池中没有对应的字符串,则该字符串将被添加到常量池中,然后返回常量池中字符串的引用;2.字符串的+操作其本质是创建了StringBuilder对象进行append操作,然后及nag拼接后的StringBuilder对象用toString方法处理成String对象.

16.重载(Overload)和重写(Override)的区别.

    方法的重载和重写都是实现多态的方式,区别在于前者实现的是编译的多态性,而后者实现的是运行时的多态性.
    重载要求两同一不同:同一个类中方法名相同,参数列表不同(参数个数不同,类型不同,顺序不同),至于方法的其他部分,如方法返回值类型,修饰符等,与方法重载没有任何关系.
    重写一般用于子类继承父类时,重写父类中的方法.
    重写的规则:
    1.重写方法的参数列表必须完全与被重写的方法相同.
    2.重写方法的访问修饰符一定要大于被重写方法的访问修饰符(public>protected>default>private)
    3.重写方法所抛出的异常必须和被重写方法所抛出的异常一致,或者是其子类.
    4.重写方法的返回值必须和被重写方法的返回值一致.
    5.被重写方法不能为private,否则在其子类中只是定义了一个方法,并没有对其进行重写.
    6.静态方法不能被重写为非静态方法.(会编译错误)
面试题:
    为什么不能根据返回类型来区分重载?

对于int f(){}和void f(){}两个方法,如果这样调用int result = f();,系统可以识别是调用返回值类型为int的方法,但是java调用方式时可以忽略方法返回值,如果采用如下方法来调用f();,你能判断是调用哪个方法吗?如果你尚且布恩那个判断,那么java系统也会糊涂,在编程过程中有一条重要规则:不能让系统糊涂,系统一糊涂,肯定就是你错了,因此,java里不能使用方法返回值类型作为区分方法重载的依据.  

17.描述一下JVM加载class文件的原理机制

    JVM中类的装载是由类加载器(ClassLoader)和它的子类来实现的,java中的类加载器是一个重要的java运行时系统组件,它负责在运行时查找和装入类文件中的类.
    由于java的跨平台性,经过编译的java源程序并不是一个可执行程序,而是一个或多个类文件,当java程序需要使用某一个类时,JVM会确保这个类已经被加载,连接(验证,准备和解析)和初始化.类的加载是指把类的.class文件中的数据读入到内存中,通常是创建一个字节数组读入.class文件,然后产生与所加载类对应的class对象,加载完成后,class对象还不完整,所以此时的类还不可用,当类被加载后就进入连接阶段,这一阶段包括验证,准备(为静态变量分配内存并设置默认的初始值)和解析(将符号引用替换为直接引用)三个步骤,最后JVM对类进行初始化,包括:1).如果类存在直接的父类并且这个类还没有被初始化,那么就先初始化父类,2).如果类中存在初始化语句,就依次执行这些初始化语句.
    类的加载是由类加载器完成后,类加载器包括:根加载器(Bootstrap),扩展加载器(Extension),系统加载器(System)和用户自定义加载器(java.lang.ClassLoader的子类).从java2(jdk1.2)开始,类加载器过程采取了父类委托机制(PDM).PDM更好的保证了java平台的安全性,类的加载首先请求父类加载器加载,父类加载器无能为力时才由其子类加载器自行加载.JVM不会向java程序提供Bootstrap的引用,下面是关于几个类加载器的说明:

  • 根加载器(Bootstrap):一般用本地代码实现,负责加载JVM基础核心类库(rt.jar);
  • 扩展加载器(Extension):从java.ext.dirs系统属性所指定的目录中加载类库,它的父加载器是Bootstrap;
  • 系统加载器(System):又叫应用类加载器,其父类是Extension,它是应用最广泛的类加载器,它从环境变量classpath或者系统属性java.class.path所指定的目录记载类,是用户自定义加载器的默认父加载器.

18.char型变量中能不能存贮一个中文汉字,为什么?

    char类型可以存储一个中文汉字,因为java中使用的编码是Unicode(不选择任何特定的编码,直接使用字符在字符集中的编码,这是统一的唯一方法),一个char类型占用2个字节(16bit),所以放一个中文是没问题的.

19.抽象类(abstract class)和接口(interface)有什么异同?

接口和抽象类很像,它们都具有如下特征.

  • 接口和抽象类都不能被实例化,它们都位于继承树的顶端,用于被其他类实现和继承.
  • 接口和抽象类都可以包含抽象方法,实现接口或继承抽象类的普通子类都必须实现这些这些抽象方法.
    但接口和抽象类之间的差别非常大,这种差别主要体现在二者设计目的上,下面具体分析二者的差别.
        接口作为系统与外界交互的窗口,接口体现的是一种规范,对于接口的实现者而言,接口规定了实现者必须向外提供哪些服务(以方法的形式来提供);对于接口的调用者而言,接口规定了调用者可以调用哪些服务,以及如何调用这些服务(就是如何来调用方法),当在一个程序中使用接口时,接口是多个模块间的耦合标准;当在多个应用程序之间使用接口时,接口是多个程序之间的通信标准.
        从某种程度上来看,接口类似于整个系统的”总纲”,它制定了系统各模块应该遵循的标准,因此一个系统中的接口不应该经常改变,一旦接口被改变,对整个系统甚至其他系统的影响将是辐射式的,导致系统中大部分类都需要改写.
        抽象类则不一样,抽象类作为系统中多个子类的共同父类,它所体现的是一种模版式设计.抽象类作为多个子类的抽象父类,可以被当成系统实现过程中的中间产品,这个中间产品已经实现了系统的部分功能(那些已经提供实现的方法),但这个产品依然不能当成最终产品,必须有更进一步的完善,这种完善可能有几种不同方法.
        除此之外,接口和抽象类在用法上也存在如下差别.

  • 接口里只能包含抽象方法和默认方法,不能为普通方法提供方法实现;抽象类则完全可以包含普通方法.

  • 接口里不能定义静态方法;抽象类里可以定义静态方法.
  • 接口里只能定义公共静态常量,不能定义普通成员变量;抽象类里则既可以定义普通成员变量,也可以定义静态常量.
  • 接口里不包含构造器;抽象类里可以包含构造器,抽象类里的构造器并不是用于创建对象,而是让其子类调用这些构造器来完成属于抽象类的初始化操作.
  • 接口里不能包含初始化块,但抽象类则完全可以包含初始化块.
  • 一个类最多只能有一个直接父类,包括抽象类;但一个类可以直接实现多个接口,通过实现多个接口可以弥补java单继承的不足.

20.java中会存在内存泄漏吗,请简单描述.

     理论上java因为垃圾回收机制(GC)不会存在内存泄漏问题(这也是java被广泛使用于服务器端编程的一个重要原因);然而渣实际开发中,可能会存在无用但可达的对象,这些对象不能被GC回收,因此也会导致内存泄漏的发生,例如Hibernate的Session(一级缓存)中的对象属于持久态,垃圾回收器是不会回收这些对象的,然而这些对象中坑呢存在无用的垃圾对象,如果不及时关闭(close)或清空(flush)一级缓存就可能内存泄漏.

21.抽象的方法是否可同时是静态的,是否可同时是本地方法,是否可同时被synchronized修饰?

    都不能,抽象方法需要子类重写,而静态的方法无法被重写,因此二者是矛盾的,本地方法是由本地代码实现的方法,而抽象方法是没有实现的,也是矛盾的.synchronized和方法的实现细节有关,抽象方法不涉及实现细节,因此也是相互矛盾的.

22.阐述静态变量和实例变量的区别.

    静态变量是被static修饰符修饰的变量,也称为类变量,它属于类,不属于类的任何一个对象,一个类不管创建多少个对象,静态变量在内存中有且仅有一个拷贝;实例变量必须依存于某一实例,需要先创建对象然后通过对象才能够访问它,静态变量可以实现让多个对象共享内存.
补充:在java开发中,上下文类和工具类中通常会有大量的静态成员.

23.是否可以从一个静态方法内部发出对非静态方法的调用?

    不可以,静态方法只能访问静态成员,因为非静态方法的调用要先创建对象,在调用静态方法时可能对象不能够没有被初始化.

24.如何实现对象克隆?

有两种方式:
    1).实现Cloneable接口并重写Object类中的clone()方法;
    实现Serializable接口,通过对象的序列化和反序列化实现克隆,可以实现真正的深度克隆.
补充:基于序列化和反序列化实现的克隆不仅仅是深度克隆,更重要的是通过泛型限定,可以检查出要克隆的对象是否支持序列化,这项检查是编译器完成的,不是在运行时抛出异常,这种方案明显优于使用Object类的clone方法克隆对象,让问题在编译的时候暴露出来总是好过把问题留到运行时.

25.java GC是在什么时候,对什么东西,做了什么事情?

在什么时候:

    1.在新生代有一个Eden区和两个survivor区,首先将对象放入Eden区,如果空间不足就向其中一个survivor区上放,如果仍然放不下就会引发一次发生在新生代的minor GC,将存活的对象放入另一个survivor区中,然后清空Eden和之前的那个survivor区的内存里去.
    2.大对象以及长期存活的对象直接进入老年区.
    3.当每次执行minor GC的时候应该对要晋升到老年代的对象进行分析,如果这些马上要到老年区的老年对象的大小超过了老年区的剩余大小,那么执行一次Full GC以尽可能的获得老年区的空间.

对什么东西:

    从GC Roots搜索不到,而且经过一次标记清理之后仍没有复活的对象.

做什么:

    新生代:复制清理;
    老年代:标记-清理和标记-压缩算法;
    永久代:存放java中的类和加在类的类加载器本身.

GC Roots都有哪些:

    1.虚拟机栈中的引用的对象
    2.方法区中静态属性引用的对象,常量引用的对象
    3.本地方法栈中JNI(即一般说的Native方法)引用的对象.
补充:垃圾回收机制有很多种,包括:分代复制垃圾回收,标记垃圾回收,增量垃圾回收等方式,标准的java进程既有栈又有堆,栈保存了原始型局部变量,堆保存了要创建的对象,java平台对堆内存回收和再利用的基本算法被称为标记和清除,但是java对其进行了改进,采用”分代式垃圾收集”.这种方法会跟java对象的生命周期堆内存划分为不同的区域,在垃圾收集过程中,可能会将对象移到不同区域:

  • 伊甸园(Eden):这是对象最初诞生的区域,并且对大多数对象来说,这里是它们唯一存在过的区域.
  • 幸存者乐园(Survivor):从伊甸园幸存下来的对象会被挪到这里.
  • 终身颐养园(Tenured):这是足够老的幸存对象的归宿,年轻代收集(Minor-GC)过程是不会触及这个地方的,当年轻代收集不能把对象放进终身颐养园时,就会触发一次完全收集(Major-GC),这里可能还会牵扯到压缩,以便为大对象腾出足够的空间.

26.String s = new String(“xyz”);创建了几个字符串对象?

    两个对象,一个是静态区的”xyz”,一个是用new创建在堆上的对象.

27.接口是否可继承接口,?抽象类是否可实现接口?抽象类是否可继承具体类?

    接口可以继承接口,而且支持多重继承,抽象类可以实现接口,抽象类可继承具体类也可以继承抽象类.

28.匿名内部类是否可以继承其他类?是否可以实现接口?

    可以继承其他类或实现其他接口,在Swing编程和Android开发中常用次方式来实现时间监听和回调.

29.内部类可以引用它的包含类(外部类)的成员吗?有没有限制?

    一个内部类对象可以访问创建它的外部类对象的成员,包括私有成员.

30.java中的final关键字有哪些用法?

    1).修饰符:表示该类不能被继承;2).修饰方法:表示方法不能被重写;3).修饰变量:表示变量只能一次赋值以后值不能被修改(常量).

31.比较java和javascript.

    **基于对象和面向对象:**java是一种真正的面向对象的语言,即使是开发简单的程序,必须设计对象;javascript是种脚本语言,它可以用来制作与网络无关的,与用户交互作用的复杂软件,它是一种基于对象和事件驱动的编程语言,因而它本身提供了丰富的内部对象提供设计人员使用.
    **解释和编译:**java的源代码在执行之前,必须经过编译,javascript是一种解释型变成语言,其源代码不需要经过编译,由浏览器解释执行.(目前的浏览器几乎都使用了JIT(即时编译)技术来提升javascript的运行效率).
    **强类型变量和类弱型变量:**java采用强类型变量检查,即所有变量在编译之前必须作声明;javascript中变量是弱类型的,甚至在使用变量钱可以不作声明,javascript的解析器在运行时检查推断其数据类型.

32.什么时候用断言(assert)?

    断言在软件开发中是一种常用的调试方式,很多开发语言中都支持这种机制.一般来说,断言用于保证程序最基本,关键的正确性,断言检查通常在开发和测试时开启,为了保证程序的执行效率,在软件发布后断言检查通常是关闭的,断言是一个包含不二表达式的语句,在执行这个语句时假定该表达式为true,如果表达式为false,那么表达式的值为false,那么系统会报告一个AssertionError,断言的使用如下面的代码所示:
assert(a>0);//throws an AssertionError if a <= 0
断言可以有两种方式:
    1.assert Expression1;
    2.assert Expression1:Expression2;
    Expression1 应该总是产生一个布尔值.
    Expression2可以是得出一个值的任意表达式;这个值用于生成显示更多调试信息的字符串消息.
    要在运行时启用断言,可以在启动JVM时使用-enableassertions或者-ea标记, 要在运行时选择禁用断言,可以在启动JVM时使用-da或者-disableassertions标记.要在系统类中启用或禁用断言,可使用-esa或-dsa标记,还可以在包的基础上启用或者禁用断言.
注意:断言不应该以任何方式改变程序的状态,简单的来说,如果希望在不满足某些条件时阻止代码的执行,就可以考虑用断言来阻止它.

33.Error和Exceeption有什么区别?

    Error错误,一般是指与虚拟机相关的问题,如系统崩溃,虚拟机错误,动态连接失败等,这种错误无法恢复或不可能捕获,将导致应用程序中断,通常应用程序无法处理这些错误.
    Exception表示需要捕捉或者需要需要程序进行处理的异常,是一种设计或实现问题,也就是说,它表示如果程序运行正常,从不会发生的情况.

34.当java程序执行try块,catch块时遇到了return或throw语句会怎么执行?

    当java程序执行try块,catch块时遇到return或throw语句,这两个语句都会导致该方法立即结束,但是系统执行这两个语句并不会结束该方法,而是去寻找该异常处理流程中是否包含finally块,如果没有finally块,程序立即执行return或throw语句,方法终止;如果有finally块,系统立即开始执行finally块–只有当finally块执行完成后,系统才会再次跳回来执行try块里的return或throw语句,如果finally块里也使用了return或throw等导致方法终止的语句,finally块已经终止了方法,系统将不会跳回去执行try块,catch块里的任何代码.
注意:尽量避免在finally块里使用return或throw等导致方法终止的语句,否则可能出现一些很奇怪的情况.

35.java语言如何进行异常处理,关键字:throws,throw,try,catch,finally分别如何使用?

答:java通过面向对象的方法进行异常处理,把各种不同的异常进行分类,并提供了良好的接口,在java中,每个异常都是一个对象,它是Throwable类或其他子类的实例,当一个方法出现异常后便抛出一个异常对象,该对象中包含有异常信息,调用这个对象的方法可以捕获到这个异常并可以对其进行处理.java的异常处理是通过5个关键字来实现的:try,catch,throw,throws和finally,一般情况下是用try来执行一段程序,如果系统会抛出一个异常对象,可以通过它的类型来捕获它,或通过总是执行代码块来处理;try用来指定一块预防所有异常的程序;catch子句紧跟在try块后面,用来指定你想要捕获的异常的类型;throw语句用来明确地抛出一个异常;throws用来声明一个方法肯呢个抛出的各种异常(当然声明异常时允许无病呻吟);finally为确保一段代买不敢发生什么异常状况都要被执行;try语句可以嵌套,每当遇到一个try语句,异常的结构就会被放入异常栈中,直到所有的try语句都完成,如果下一级语句的try语句没有对某种异常进行处理,异常栈就会执行出栈操作,直到遇到有处理这种异常的try语句或者最终将异常抛给JVM.

36.运行时异常与受检异常有何异同?

    异常表示程序运行过程中可能出现的非正常状态,运行时异常表示虚拟机的通常操作中可能遇到的异常,是一种常见运行错误,只要程序设计的没有问题就不会发生,受检异常跟程序运行的上下文环境有关,即使程序设计无误,仍然可能因使用的问题而引发,java编译器要求方法必须声明抛出可能发生的受检异常,但是并不要求必须声明抛出未被捕获的运行时异常,异常和继承一样,是面向对象程序设计中经常被滥用的东西,在Effective java中对异常的使用给出了以下指导原则:

  • 不要将异常处理用于正常的控制流(设计良好的API不应该强迫它的调用者为了正常的控制流而使用异常)
  • 对可以恢复的情况使用受检异常,对编译错误使用运行时异常
  • 避免不必要的使用受检异常(可以通过一些状态检测手段来避免异常的发生)
  • 优先使用标准的异常
  • 每个方法抛出的异常都要有文档
  • 保持异常的原子性
  • 不要在catch中忽略掉捕获到的异常

37.列出一些你常见的运行时异常?

  • ArithmeticException(算术异常)
  • ClassCastException(类转换异常)
  • IllegalArgumentException(非法参数异常)
  • IndexOutOfBoundsException(下标越界异常)
  • NullpointerException(空指针异常)
  • SecurityException(安全异常)

38.阐述final,finally,finalize的区别?

  • final:修饰符(关键字)有三种用法:如果一个类被声明final,
    意味着它不能再派生出新的子类,即不能被继承,因此它和abstract是反义词.将变量声明为final,可以保证它们在使用中不被改变,被声明为final的变量必须在声明时给定初值,而在以后的引用中只能读取不可修改,被声明为final的方法也同样只能使用,不能在子类中被重写.
  • finally:通常放在try… catch…的后面构造总是执行代码块,这就意味着程序无论正常执行还是发生异常,这里的代码只要JVM不关闭都能执行,可以将释放外部资源的代码写在finally块中.
  • finalize:Object类中定义的方法,java中允许使用finalize()方法在垃圾收集器将对象从内存中清除出去之前做必要的清理工作,这个方法是由垃圾收集器在销毁对象时调用的,通过重写finalize()方法可以整理系统资源或者执行其他清理工作.

猜你喜欢

转载自blog.csdn.net/kbh528202/article/details/80502439