日期:2014-05-20  浏览次数:20876 次

java面试题(1)

?

网上找到一份java的面试题,感觉写得很详细且易懂,所以把里面的内容做了一下归纳。附件中pdf的出处为http://zangweiren.iteye.com/blog/241218

?

1.类的初始化顺序

对于静态变量、静态初始化块、变量、初始化块、构造器,它们的初始化顺序依次是(静态变量、静态初始化块)>(变量、初始化块)>构造器。

?

子类的静态变量和静态初始化块的初始化是在父类的变量、初始化块和构造器初始化之前就完成了。

?

静态变量和静态初始化块是依照他们在类中的定义顺序进行初始化的。同样,变量和初始化块也遵循这个规律。

?

2.到底创建了几个 String 对象?

只有使用引号包含文本的方式创建的String 对象之间使用“+”连接产生的新对象才会被加入字符串池中。对于所有包含 new 方式新建对象(包括 null)的“+”连接表达式,它所产生的新对象都不会被加入字符串池中。

?

栈(stack):主要保存基本类型(或者叫内置类型)(char、byte、short、int、long、float、double、boolean)和对象的引用,数据可以共享,速度仅次于寄存器(register),快于堆。

堆(heap):用于存储对象。

?

当执行String a="abc";时,JAVA 虚拟机会在栈中创建三个char 型的值'a'、'b'和'c',然后在堆中创建一个String 对象,它的值(value)是刚才在栈中创建的三个char 型值组成的数组{'a','b','c'},最后这个新创建的String 对象会被添加到字符串池中。如果我们接着执行 String b=new String("abc");代码,由于"abc"已经被创建并保存于字符串池中,因此JAVA 虚拟机只会在堆中新创建一个String 对象,但是它的值(value)是共享前一行代码执行时在栈中创建的三个char 型值值'a'、'b'和'c'。

?

3.变量(属性)的覆盖

变量的值取决于我们定义的变量的类型,而不是创建的对象的类型。当变量类型是父类时,不管我们创建的对象是父类的还是子类的,都不存在属性覆盖的问题。

?

访问修饰符并不影响属性的覆盖。

?

静态变量和静态常量属于类,不属于对象,因此它们不能被覆盖。

?

常量可以被覆盖。

?

对于基本类型和对象,它们适用同样的覆盖规律。

?

4.final、finally 和 finalize 的区别

如果一个变量或方法参数被final 修饰,就表示它只能被赋值一次,但是JAVA 虚拟机为变量设定的默认值不记作一次赋值。

?

被final 修饰的变量必须被初始化。初始化的方式有以下几种:

  1. 在定义的时候初始化。
  2. final 变量可以在初始化块中初始化,不可以在静态初始化块中初始化。
  3. 静态final 变量可以在静态初始化块中初始化,不可以在初始化块中初始化。
  4. final 变量还可以在类的构造器中初始化,但是静态final 变量不可以。

final 变量(常量)和静态final 变量(静态常量)未被初始化时,编译会报错。

?

当 final 用来定义一个方法时,这个方法不可以被子类重写,但是它这不影响它被子类继承。

?

由关键字abstract 定义的抽象类含有必须由继承自它的子类重载实现的抽象方法,因此无法同时用final 和abstract 来修饰同一个类。同样的道理,final 也不能用来修饰接口。 final 的类的所有方法都不能被重写,但这并不表示 final 的类的属性(变量)值也是不可改变的,要想做到final 类的属性值不可改变,必须给它增加final 修饰。

?

finally只能用在try/catch 语句中,并且附带着一个语句块,表示这段语句最终总是被执行。

?

finalize()方法是在GC 清理它所从属的对象时被调用的,如果执行它的过程中抛出了无法捕获的异常(uncaught exception),GC 将终止对改对象的清理,并且该异常会被忽略;直到下一次GC 开始清理这个对象时,它的finalize()会被再次调用。

?

由于finalize()属于Object 类,因此所有类都有这个方法,Object 的任意子类都可以重写(override)该方法,在其中释放系统资源或者做其它的清理工作,如关闭输入输出流。

?

5.传了值还是传了引用?

  1. 对于基本类型,在方法体内对方法参数进行重新赋值,并不会改变原有变量的值。
  2. 对于引用类型,在方法体内对方法参数进行重新赋予引用,并不会改变原有变量所持有的引用。
  3. 方法体内对参数进行运算,不影响原有变量的值。
  4. 方法体内对参数所指向对象的属性进行运算,将改变原有变量所指向对象的属性值。

当基本类型的变量被当作参数传递给方法时,JAVA 虚拟机所做的工作是把这个值拷贝了一份,然后把拷贝后的值传递到了方法的内部。

当引用型变量被当作参数传递给方法时,它会拷贝一份这个变量所持有的引用,然后把它传递给JAVA 虚拟机为方法创建的局部变量,从而这两个变量指向了同一个对象。

?

结论:

  1. 基本类型和基本类型变量被当作参数传递给方法时,是值传递。在方法实体中,无法给原变量重新赋值,也无法改变它的值。
  2. 对象和引用型变量被当作参数传递给方法时,在方法实体中,无法给原变量重新赋值,但是可以改变它所指向对象的属性。

?

6.字符串(String)杂谈

为什么一个中文汉字可以保存在一个char 变量里呢?

因为在JAVA 中,一个char 是2 个字节(byte),而一个中文汉字是一个字符,也是2 个字节。而英文字母都是一个字节的,因此它也能保存到一个byte 里,一个中文汉字却不能保存到一个byte 里。

?

“+”运算符被用于字符串和字符串之间,或者字符串和其他类型变量之间时,它产生的效果是字符串的拼接;但当它被用于字符和字符之间时,效果等同于用于数字和数字之间,是一种算术运算。

?

7.聊聊基本类型(内置类型)

int 型值可以赋给所有数值类型的变量;long 型值可以赋给long、float、double 类型的变量;float 型值可以赋给float、double 类型的变量;double 型值只能赋给double 类型变量。

?

当使用+、-、*、/、%运算符对基本类型进行运算时,遵循如下规则:

  1. 只要两个操作数中有一个是double 类型的,另一个将会被转换成double 类型,并且结果也是double 类型;
  2. 否则,只要两个操作数中有一个是float 类型的,另一个将会被转换成float 类型,并且结果也是float 类型;
  3. 否则,只要两个操作数中有一个是long 类型的,另一个将会被转换成long 类型,并且结果也是long 类型;
  4. 否则,两个操作数(包括 byte、short、int、char)都将会被转换成int 类型,并且结果也是int 类型。

当使用+=、-=、*=、/=、%=、运算符对基本类型进行运算时,遵循如下规则:

运算符右边的数值将首先被强制转换成与运算符左边数值相同的类型,然后再执行运算,且运算结果与运算符左边数值类型相同。

?

short s1=1;s1=s1+1;有什么错?short s1=1;s1+=1;有什么错?

在s1=s1+1; 中,s1+1运算的结果是int型,把它赋值给一个 short型变量s1,所以会报错;而在s1+=1;中,由于是s1是short类型的,所以1首先被强制转换为short型,然后再参与运算,并且结果 也是short类型的,因此不会报错。那么,s1=1+1;为什么不报错呢?这是因为1+1是个编译时可以确定的常量,“+”运算在编译时就被执行了,而 不是在程序执行的时候,这个语句的效果等同于s1=2,所以不会报错。

?

当使用“==”运算符在基本类型和其包装类对象之间比较时,遵循如下规则:

  1. 只要两个操作数中有一个是基本类型,就是比较它们的数值是否相等。
  2. 否则,就是判断这两个对象的内存地址是否相等,即是否是同一个对象。

Math 类的round()方法的运算结果是一个<=(参数值+0.5)的最大整数。

?

switch 语句总结:

  1. byte、char、short、int 四种基本类型以及它们的包装类(需要 Java5.0/1.5 以上版本支持)都可以用于switch 语句。
  2. long、float、double、boolean 四种基本类型以及它们的包装类(在Java 所有版本中)都不能用于switch 语句。
  3. enum 类型,即枚举类型可以用于switch 语句,但是要在Java5.0(1.5)版本以上才支持。
  4. 所有类型的对象(包括 String 类,但在Java5.0/1.5 以上版本中,该项要排除byte、char、short、int 四种基本类型对应的包装类)都不能用于switch 语句。

?

8.话说多线程

实现线程的方式有两种:

  1. ?继承java.lang.Thread,并重写它的run()方法,将线程的执行主体放入其中。
  2. ?实现java.lang.Runnable 接口,实现它的run()方法,并将线程的执行主体放入其中。

线程的状态

Java 5.0 及以上版本中,线程的状态被扩充为NEW(新建)、RUNNABLE(可运行、就绪)、 BLOCKED(阻塞、中断)、 WAITING(等待)、TIMED_WAITING(定时等待)、TERMINATED(死亡、终止)六种。

?

sleep()和wait()的区别

共同点:都成产生让当前运行的线程停止运行的效果。

不同点:sleep()方法是本地方法,属于Thread 类,不释放释放同步锁;wait()方法也是本地方法,属于Object 类,释放释放同步锁。

?

9.checked exception和unchecked exception的区别

unchecked exception也就是runtime excerption,它的抛出通常是因为我们程序自身的问题,也就是说,我们编的程序有问题,我们不用抛出这类异常,编译器会帮我们抛出的;常见的runtime excerption有:NullPointerException(空指针异常),ArrayIndexOutOfBoundsException(数组越界异常),ClassCastException(类型强制转换异常)。

而checked exception就是像IOException这样的异常,通常是需要程序员抛出的,也是通过try catch或者throw来抛出的。