Java程序员面试笔试宝典(第2版)
上QQ阅读APP看书,第一时间看更新

1.21 常见面试笔试真题

(1)下面程序的输出结果是什么?

A.Finally

B.编译失败

C.代码正常运行但没有任何输出

D.运行时抛出异常

答案:A。

(2)下面程序能否编译通过?如果把ArithmeticException换成IOException呢?

答案:能编译通过。由于ArithmeticException属于运行时异常,编译器没有强制对其进行捕获并处理,因此编译可以通过。但是如果换成IOException后,由于IOException属于检查异常,编译器强制去捕获此类型的异常。因此如果不对异常进行捕获将会有编译错误。

(3)异常包含下列哪些内容?( )

A.程序中的语法错误

B.程序的编译错误

C.程序执行过程中遇到的事先没有预料到的情况

D.程序事先定义好的可能出现的意外情况

答案:C。

(4)以下关于异常的说法正确的是( )

A.一旦出现异常,程序运行就终止了

B.如果一个方法声明将抛出某个异常,它就必须真的抛出那个异常

C.在catch子句中匹配异常是一种精确匹配

D.可能抛出系统异常的方法是不需要声明异常的

答案:D。

(5)下面的代码运行的结果是什么?

A.Load B1 Load B2 Create B Load A Create A

B.Load B1 Load B2 Load A Create B Create A

C.Load B2 Load B1 Create B Create A Load A

D.Create B Create A Load B1 Load B2 Load A

答案:B。

(6)下面代码的输出结果是什么?

A.AC

B.ABC

C.C

D.BC

答案:A。类加载的初始化阶段会执行静态代码块中的代码。访问B.c的时候需要加载父类A,因此会执行父类的静态代码块,首先输出A然后才输出B,因为类B不需要加载,所以不会输出C。

(7)下面代码的输出结果是什么?

A.TestA

B.A Test A

C.A Test

D.Test

答案:A。使用ClassLoader加载类,不会导致类的初始化,也就是说不会调用clinit方法,因此类A的静态代码块不会被执行。而Class.forName()方法不仅会加载类,而且还会执行类的初始化方法,因此会执行静态代码块。

(8)下列关于构造方法的叙述中,错误的是( )

A.Java语言规定构造方法名与类名必须相同

B.Java语言规定构造方法没有返回值,但不用void声明

C.Java语言规定构造方法不可以重载

D.Java语言规定构造方法只能通过new自动调用

答案:C。可以定义多个构造方法,只要不同的构造方法有不同的参数即可。

(9)下列说法正确的有( )

A:class中的constructor不可省略

B:constructor必须与class同名,但方法不能与class同名

C:constructor在一个对象被new时执行

D:一个class只能定义一个constructor

答案:C。

(10)Java中提供了哪两种用于多态的机制?

答案:编译时多态和运行时多态。编译时多态是通过方法重载实现的,运行时多态是通过方法重写(子类覆盖父类方法)实现的。

(11)下面代码的运行结果是什么?

A.B.g() is called

B.编译错误

C.运行时错误

答案:B。因为A中没有方法g(),所以会有编译错误。

(12)如下代码输出结果是什么?

答案:编译错误。因为方法不能以返回值来区分,虽然父类与子类中的方法有着不同的返回值,但是它们有着相同的方法签名,所以无法区分。

(13)在接口中以下哪条定义是正确的?

A.void methoda();

B.public double methoda();

C.public final double methoda();

D.static void methoda(double d1);

E.protected void methoda(double d1);

F.int a;

G.int b=1;

答案:A、B、G。从上面的分析可知,接口中的方法只能用关键字public和abstract来修饰,因此选项C、E都是错误的。被static修饰的方法必须有方法的实现,因此选项D是错误的。接口中的属性默认都为public static final,由于属性被final修饰,它是常量,常量在定义的时候就必须初始化,因此F是错误的。

(14)下列正确的说法有( )

A.声明抽象方法,大括号可有可无

B.声明抽象方法不可写出大括号

C.抽象方法有方法体

D.abstract可修饰属性、方法和类

答案:B。抽象方法不能有方法体,同理也就不能有大括号。abstract只能用来修饰类与方法,不能用来修饰属性。

(15)不能用来修饰外部interface的有( )

A.private

B.public

C.protected

D.static

答案:A、C、D。

(16)JDK中哪些类是不能被继承的?

答案:从上面的介绍可以知道,不能继承的类是那些用final关键字修饰的类。一般比较基本的类型为防止扩展类无意间破坏原来方法的实现都应该是final的,在JDK中,String、StringBuffer等都是基本类型。所以,String和StringBuffer等类似不能继承的。

(17)下面程序的运行结果是什么?

A.ABCD

B.ACDB

C.ACBD

D.不确定

答案:C。finally语句在任何情况下都会被执行,当前面有return语句时,首先执行return的语句但不返回,然后执行finally块,最后才返回。

(18)下面代码的输出结果是什么?

A.0

B.1

C.2

D.编译失败

答案:D。在Java语言中,不能在成员函数内部定义static变量。

(19)是否可以把一个数组修饰为volatile?

答案:在Java中可以用volatile来修饰数组,但是volatile只作用在这个数组的引用上,而不是整个数组的内容。也就是说如果一个线程修改了这个数组的引用,这个修改会对其他所有线程可见。但是如果只是修改了数组的内容,则无法保证这个修改对其他数组可见。

(20)下列表达式正确的是( )

A.byte b=128;

B.boolean flag=null;

C.float f=0.9239;

D.long a=2147483648L;

答案:D。A中byte能表示的取值范围为[-128, 127],因此不能表示128。B中boolean的取值只能是true或false,不能为null。C中0.9239为double类型,需要进行数据类型转换。

(21)String是最基本的数据类型吗?

答案:不是。基本数据类型包括byte、int、char、long、float、double、boolean和short。

(22)int和Integer有什么区别?

答案:Java语言提供两种不同的类型:引用类型和原始类型(或内置类型)。int是Java语言的原始数据类型,Integer是Java语言为int提供的封装类。Java为每个原始类型提供了封装类。

引用类型与原始类型的行为完全不同,并且它们具有不同的语义。而且,引用类型与原始类型具有不同的特征和用法。

(23)赋值语句float f=3.4是否正确?

答案:不正确。3.4默认情况下是double类型,即双精度浮点数,将double类型数值赋值给float类型的变量,会造成精度损失,因此需要强制类型转换,即将3.4转换成float类型或者将3.4强制写成float类型。所以,float f=(float)3.4或者float f=3.4F写法都是可以的。

(24)下面代码的输出结果是什么?

答案:运行结果为:

分析:在解答这道题前首先需要掌握下面几个知识点:

1)使用==比较的时候比较的是两个对象的引用(也就是地址);

2)使用equals比较的是两个Integer对象的数值;

3)Long对象的equals方法,它会首先检查方法的参数是否也是Long类型,如果不是则直接返回false;

4)在Java中,Integer内部维护了一个可以保存-128~127的缓存池。

5)如果比较的某一边有操作表达式(例如a+b),那么比较的是具体数值。

根据以上的知识点,可以得出下面的分析结果:

1)Integer c=3;内部会调用Integer.valueOf(3)方法,这个方法的源码如下:

从上面的代码可以看出:

1)c和d都是用过valueOf方法获取的且指向相同的对象,因此c==d为true。

2)e和f超出了缓存池缓存的范围,因此会对e和f创建两个不同的对象,它们的地址不相等,所以e==f为false。

3)对于c==(a+b),由于比较的一边有表达式,比较的是具体数值,因此它的值为true。

4)对于g.equals(a+b),由于g的类型为Long,但是a+b的类型为Integer,因此equals方法会返回false。

5)对于i==j,当使用new实例化对象的时候,它会在堆上创建新的对象并返回,i和j是两个独立的对象,它们有着不同的地址,因此比较结果为false。

(25)在Java中,哪个数据类型可以用来表示Money?

答案:可以用BigDecimal来表示Money,可能很多程序员都会有疑问,为什么不能使用float或者double呢?因为float与double只是计算了一个近似值,无法表示非常精确的值。float与double类型数据的计算结果在不同的JVM上可能会有不同的实现。而要表示Money,就必须使用一个非常精确的值。需要注意的是,在使用BigDecimal时候,需要使用String类型的构造方法,不能使用参数类型为double的构造方法,因为参数类型为double时,BigDecimal内部还是使用double作为类型进行运算的,从而会导致计算结果不精确。下面给出一个示例代码:

程序运行结果为:

(26)下例说法正确的是( )

A.call by value(值传递)不会改变实际参数的值

B.call by reference(引用传递)能改变实际参数

C.call by reference(引用传递)不能改变实际参数的地址

D.call by reference(引用传递)能改变实际参数的内容

答案:A、C、D。见上面讲解。

(27)设x=1,y=2,z=3,则表达式y+=z--/++x的值是( )

A.3

B.3.5

C.4

D.5

答案:A。

(28)i++是线程安全的吗?

答案:因为i++在底层实现的时候是通过下面三个步骤来实现的:

由此可见,i++不是一个原子操作,因此不是线程安全的,那么如何能实现i++的线程安全呢?这里重点介绍三种实现方式:使用原子变量、sychronized关键字和Lock锁实现。下面通过示例代码来说明它们的用法。

1)原子变量。AtomicInteger是一个提供原子操作的Integer类,通过线程安全的方式操作加减,示例代码如下:

程序运行结果为:

每次运行可能会得到不同的答案,但是从运行结果可以看出有5个线程同时运行的时候,使用AtomicInteger方法每个线程输出的值都不同,而且最大的值为4;而使用num1++,不同的线程可能会输出相同的值,而且最大值也没有到4。

2)sychronized关键字。使用sychronized来修饰getIncrease方法,确保在同一时刻只会有一个线程调用getIncrease方法,从而实现线程安全。

3)Lock。把++操作放在锁内从而实现++操作的线程安全。

(29)假设有以下代码String s="hello";String t="hello";char c[]={'h','e','l','l','0'},下列选项中返回false语句的是( )

A.s.equals(t)

B.t.equals(c)

C.s==t

D.t.equals(new String("hello"))

答案:B。A与D显然会返回true,选项C的返回值也为true。对于B,由于t与c分别为字符串类型和数组类型,因此返回值为false。

(30)下面程序的输出结果是什么?

答案:true。"ab"+"c"在编译器就被转换为"abc",存放在常量区,因此输出结果为true。

(31)Set里的元素是不能重复的,那么用什么方法来区分是否重复呢?是用“==”还是equals()?它们有何差别?

答案:用equals()方法来区分是否重复。