Java经典面试题及答案Word文档下载推荐.docx
- 文档编号:19949780
- 上传时间:2023-01-12
- 格式:DOCX
- 页数:12
- 大小:57.66KB
Java经典面试题及答案Word文档下载推荐.docx
《Java经典面试题及答案Word文档下载推荐.docx》由会员分享,可在线阅读,更多相关《Java经典面试题及答案Word文档下载推荐.docx(12页珍藏版)》请在冰豆网上搜索。
和&
&
的区别?
运算符有两种用法:
(1)按位与;
(2)逻辑与。
运算符是短路与运算。
逻辑与跟短路与的差别是非常巨大的,虽然二者都要求运算符左右两端的布尔值都是true整个表达式的值才是true。
之所以称为短路运算是因为,如果&
左边的表达式的值是false,右边的表达式会被直接短路掉,不会进行运算。
很多时候我们可能都需要用&
而不是&
,例如在验证用户登录时判定用户名不是null而且不是空字符串,应当写为:
username!
=null&
!
username.equals(“”),二者的顺序不能交换,更不能用&
运算符,因为第一个条件如果不成立,根本不能进行字符串的equals比较,否则会产生NullPointerException异常。
注意:
逻辑或运算符(|)和短路或运算符(||)的差别也是如此。
补充:
如果你熟悉JavaScript,那你可能更能感受到短路运算的强大,想成为JavaScript的高手就先从玩转短路运算开始吧。
5、Math.round(11.5)等于多少?
Math.round(-11.5)等于多少?
Math.round(11.5)的返回值是12,Math.round(-11.5)的返回值是-11。
四舍五入的原理是在参数上加0.5然后进行下取整。
6、用最有效率的方法计算2乘以8?
2<
<
3(左移3位相当于乘以2的3次方,右移3位相当于除以2的3次方)。
我们为编写的类重写hashCode方法时,可能会看到如下所示的代码,其实我们不太理解为什么要使用这样的乘法运算来产生哈希码(散列码),而且为什么这个数是个素数,为什么通常选择31这个数?
前两个问题的答案你可以自己XX一下,选择31是因为可以用移位和减法运算来代替乘法,从而得到更好的性能。
说到这里你可能已经想到了:
31*num<
==>
(num<
5)-num,左移5位相当于乘以2的5次方(32)再减去自身就相当于乘以31。
现在的VM都能自动完成这个优化。
7、在Java中,如何跳出当前的多重嵌套循环?
在最外层循环前加一个标记如A,然后用breakA;
可以跳出多重循环。
(Java中支持带标签的break和continue语句,作用有点类似于C和C++中的goto语句,但是就像要避免使用goto一样,应该避免使用带标签的break和continue,因为它不会让你的程序变得更优雅,很多时候甚至有相反的作用,所以这种语法其实不知道更好)
8、两个对象值相同(x.equals(y)==true),但却可有不同的hashcode,这句话对不对?
不对,如果两个对象x和y满足x.equals(y)==true,它们的哈希码(hashcode)应当相同。
Java对于eqauls方法和hashCode方法是这样规定的:
(1)如果两个对象相同(equals方法返回true),那么它们的hashCode值一定
要相同;
(2)如果两个对象的hashCode相同,它们并不一定相同。
当然,你未必要按照要求去做,但是如果你违背了上述原则就会发现在使用容器时,相同的对象可以出现在Set集合中,同时增加新元素的效率会大大下降(对于使用哈希存储的系统,如果哈希码频繁的冲突将会造成存取性能急剧下降)。
关于equals和hashCode方法,很多Java程序都知道,但很多人也就是仅仅知道而已,equals方法的:
首先equals方法必须满足自反性(x.equals(x)必须返回true)、对称性(x.equals(y)返回true时,y.equals(x)也必须返回true)、传递性(x.equals(y)和y.equals(z)都返回true时,x.equals(z)也必须返回true)和一致性(当x和y引用的对象信息没有被修改时,多次调用x.equals(y)应该得到同样的返回值),而且对于任何非null值的引用x,x.equals(null)必须返回false。
实现高质量的equals方法的诀窍包括:
1.使用==操作符检查“参数是否为这个对象的引用”;
2.使用instanceof操作符检查“参数是否为正确的类型”;
3.对于类中的关键属性,检查参数传入对象的属性是否与之相匹配;
4.编写完equals方法后,问自己它是否满足对称性、传递性、一致性;
5.重写equals时总是要重写hashCode;
6.不要将equals方法参数中的Object对象替换为其他的类型,在重写时不要忘掉@Override注解。
9、当一个对象被当作参数传递到一个方法后,此方法可改变这个对象的属性,并可返回变化后的结果,那么这里到底是值传递还是引用传递?
是值传递。
Java编程语言只有值传递参数。
当一个对象实例作为一个参数被传递到方法中时,参数的值就是对该对象的引用。
对象的属性可以在被调用过程中被改变,但对象的引用是永远不会改变的。
C++和C#中可以通过传引用或传输出参数来改变传入的参数的值。
Java中没有传引用实在是非常的不方便,这一点在Java8中仍然没有得到改进,正是如此在Java编写的代码中才会出现大量的Wrapper类(将需要通过方法调用修改的引用置于一个Wrapper类中,再将Wrapper对象传入方法),这样的做法只会让代码变得臃肿,尤其是让从C和C++转型为Java程序员的开发者无法容忍。
10、重载(Overload)和重写(Override)的区别。
重载的方法能否根据返回类型进行区分?
方法的重载和重写都是实现多态的方式,区别在于前者实现的是编译时的多态性,而后者实现的是运行时的多态性。
重载发生在一个类中,同名的方法如果有不同的参数列表(参数类型不同、参数个数不同或者二者都不同)则视为重载;
重写发生在子类与父类之间,重写要求子类被重写方法与父类被重写方法有相同的返回类型,比父类被重写方法更好访问,不能比父类被重写方法声明更多的异常(里氏代换原则)。
重载对返回类型没有特殊的要求。
华为的面试题中曾经问过这样一个问题:
为什么不能根据返回类型来区分重载,说出你的答案吧!
11、char型变量中能不能存贮一个中文汉字?
为什么?
char类型可以存储一个中文汉字,因为Java中使用的编码是Unicode(不选择任何特定的编码,直接使用字符在字符集中的编号,这是统一的唯一方法),一个char类型占2个字节(16bit),所以放一个中文是没问题的。
使用Unicode意味着字符在JVM内部和外部有不同的表现形式,在JVM内部都是Unicode,当这个字符被从JVM内部转移到外部时(例如存入文件系统中),需要进行编码转换。
所以Java中有字节流和字符流,以及在字符流和字节流之间进行转换的转换流,如InputStreamReader和OutputStreamReader,这两个类是字节流和字符流之间的适配器类,承担了编码转换的任务;
对于C程序员来说,要完成这样的编码转换恐怕要依赖于union(联合体/共用体)共享内存的特征来实现了。
12、静态嵌套类(StaticNestedClass)和内部类(InnerClass)的不同?
StaticNestedClass是被声明为静态(static)的内部类,它可以不依赖于外部类实例被实例化。
而通常的内部类需要在外部类实例化后才能实例化,其语法看起来挺诡异的,如下所示。
13、抽象的(abstract)方法是否可同时是静态的(static),是否可同时是本地方法(native),是否可同时被synchronized修饰?
都不能。
抽象方法需要子类重写,而静态的方法是无法被重写的,因此二者是矛盾的。
本地方法是由本地代码(如C代码)实现的方法,而抽象方法是没有实现的,也是矛盾的。
synchronized和方法的实现细节有关,抽象方法不涉及实现细节,因此也是相互矛盾的。
14、是否可以从一个静态(static)方法内部发出对非静态(non-static)方法
的调用?
不可以,静态方法只能访问静态成员,因为非静态方法的调用要先创建对象,因此在调用静态方法时可能对象并没有被初始化。
15、GC是什么?
为什么要有GC?
GC是垃圾收集的意思,内存处理是编程人员容易出现问题的地方,忘记或者错误的内存回收会导致程序或系统的不稳定甚至崩溃,Java提供的GC功能可以自动监测对象是否超过作用域从而达到自动回收内存的目的,Java语言没有提供释放已分配内存的显示操作方法。
Java程序员不用担心内存管理,因为垃圾收集器会自动进行管理。
要请求垃圾收集,可以调用下面的方法之一:
System.gc()或Runtime.getRuntime().gc(),但JVM可以屏蔽掉显示的垃圾回收调用。
垃圾回收可以有效的防止内存泄露,有效的使用可以使用的内存。
垃圾回收器通常是作为一个单独的低优先级的线程运行,不可预知的情况下对内存堆中已经死亡的或者长时间没有使用的对象进行清除和回收,程序员不能实时的调用垃圾回收器对某个对象或所有对象进行垃圾回收。
在Java诞生初期,垃圾回收是Java最大的亮点之一,因为服务器端的编程需要有效的防止内存泄露问题,然而时过境迁,如今Java的垃圾回收机制已经成为被诟病的东西。
移动智能终端用户通常觉得iOS的系统比Android系统有更好的用户体验,其中一个深层次的原因就在于Android系统中垃圾回收的不可预知性。
垃圾回收机制有很多种,包括:
分代复制垃圾回收、标记垃圾回收、增量垃圾回收等方式。
标准的Java进程既有栈又有堆。
栈保存了原始型局部变量,堆保存了要创建的对象。
Java平台对堆内存回收和再利用的基本算法被称为标记和清除,但是Java对其进行了改进,采用“分代式垃圾收集”。
这种方法会跟Java对象的生命周期将堆内存划分为不同的区域,在垃圾收集过程中,可能会将对象移动到不同区域:
伊甸园(Eden):
这是对象最初诞生的区域,并且对大多数对象来说,这里是它们唯一存在过的区域。
幸存者乐园(Survivor):
从伊甸园幸存下来的对象会被挪到这里。
终身颐养园(Tenured):
这是足够老的幸存对象的归宿。
年轻代收集(Minor-GC)过程是不会触及这个地方的。
当年轻代收集不能把对象放进终身颐养园时,就会触发一次完全收集(Major-GC),这里可能还会牵扯到压缩,以便为大对象腾出足够的空间。
与垃圾回收相关的JVM参数:
-Xms/-Xmx---堆的初始大小/堆的最大大小
-Xmn---堆中年轻代的大小
-XX:
-DisableExplicitGC---让System.gc()不产生任何作用
+PrintGCDetail---打印GC的细节
+PrintGCDateStamps---打印GC操作的时间戳
16、接口是否可继承(extends)接口?
抽象类是否可实现(implements)接口?
抽象类是否可继承具体类(concreteclass)?
接口可以继承接口。
抽象类可以实现(implements)接口,抽象类可继承具体类,但前提是具体类必须有明确的构造函数。
17、AnonymousInnerClass(匿名内部类)是否可以继承其它类?
是否可以
实现接口?
可以继承其他类或实现其他接口,在Swing编程中常用此方式来实现事件监听和回调。
18、Java中的final关键字有哪些用法?
(1)修饰类:
表示该类不能被继承;
(2)修饰方法:
表示方法不能被重写;
(3)修饰变量:
表示变量只能一次赋值以后值不能被修改(常量)。
19、数据类型之间的转换:
1)如何将字符串转换为基本数据类型?
2)如何将基本数据类型转换为字符串?
1)调用基本数据类型对应的包装类中的方法parseXXX(String)或valueOf(String)即可返回相应基本类型;
2)一种方法是将基本数据类型与空字符串(””)连接(+)即可获得其所对应的字符串;
另一种方法是调用String类中的valueOf(…)方法返回相应字符串
20、怎样将GB2312编码的字符串转换为ISO-8859-1编码的字符串?
代码如下所示:
Strings1="
你好"
;
Strings2=newString(s1.getBytes("
GB2312"
),"
ISO-8859-1"
);
12、打印昨天的当前时刻。
22、什么时候用assert?
assertion(断言)在软件开发中是一种常用的调试方式,很多开发语言中都支持这种机制。
一般来说,assertion用于保证程序最基本、关键的正确性。
assertion检查通常在开发和测试时开启。
为了提高性能,在软件发布后,assertion检查通常是关闭的。
在实现中,断言是一个包含布尔表达式的语句,在执行这个语句时假定该表达式为true;
如果表达式计算为false,那么系统会报告一个AssertionError。
断言用于调试目的:
assert(a>
0);
//throwsanAssertionErrorifa<
=0
断言可以有两种形式:
assertExpression1;
assertExpression1:
Expression2;
Expression1应该总是产生一个布尔值。
Expression2可以是得出一个值的任意表达式;
这个值用于生成显示更多调试信息的字符串消息。
断言在默认情况下是禁用的,要在编译时启用断言,需使用source1.4标记:
javac-source1.4Test.java
要在运行时启用断言,可使用-enableassertions或者-ea标记。
要在运行时选择禁用断言,可使用-da或者-disableassertions标记。
要在系统类中启用断言,可使用-esa或者-dsa标记。
还可以在包的基础上启用或者禁用断言。
可以在预计正常情况下不会到达的任何位置上放置断言。
断言可以用于验证传递给私有方法的参数。
不过,断言不应该用于验证传递给公有方法的参数,因为不管是否启用了断言,公有方法都必须检查其参数。
不过,既可以在公有方法中,也可以在非公有方法中利用断言测试后置条件。
另外,断言不应该以任何方式改变程序的状态。
23、try{}里有一个return语句,那么紧跟在这个try后的finally{}里的code会不会被执行,什么时候被执行,在return前还是后?
会执行,在方法返回调用者前执行。
Java允许在finally中改变返回值的做法是不好的,因为如果存在finally代码块,try中的return语句不会立马返回调用者,而是记录下返回值待finally代码块执行完毕之后再向调用者返回其值,然后如果在finally中修改了返回值,这会对程序造成很大的困扰,C#中就从语法上规定不能做这样的事。
24、Java语言如何进行异常处理,关键字:
throws、throw、try、catch、f
inally分别如何使用?
Java通过面向对象的方法进行异常处理,把各种不同的异常进行分类,并提供了良好的接口。
在Java中,每个异常都是一个对象,它是Throwable类或其子类的实例。
当一个方法出现异常后便抛出一个异常对象,该对象中包含有异常信息,调用这个对象的方法可以捕获到这个异常并进行处理。
Java的异常处理是通过5个关键词来实现的:
try、catch、throw、throws和finally。
一般情况下是用try来执行一段程序,如果出现异常,系统会抛出(throw)一个异常,这时候你可以通过它的类型来捕捉(catch)它,或最后(finally)由缺省处理器来处理;
try用来指定一块预防所有“异常”的程序;
catch子句紧跟在try块后面,用来指定你想要捕捉的“异常”的类型;
throw语句用来明确地抛出一个“异常”;
throws用来标明一个成员函数可能抛出的各种“异常”;
finally为确保一段代码不管发生什么“异常”都被执行一段代码;
可以在一个成员函数调用的外面写一个try语句,在这个成员函数内部写另一个try语句保护其他代码。
每当遇到一个try语句,“异常”的框架就放到栈上面,直到所有的try语句都完成。
如果下一级的try语句没有对某种“异常”进行处理,栈就会展开,直到遇到有处理这种“异常”的try语句。
25、列出一些你常见的运行时异常?
ArithmeticException(算术异常)
ClassCastException(类转换异常)
IllegalArgumentException(非法参数异常)
IndexOutOfBoundsException(下表越界异常)
NullPointerException(空指针异常)
SecurityException(安全异常)
26、Java中实现多线程有几种方法
继承Thread类;
实现Runnable接口;
实现Callable接口通过FutureTask包装器来创建Thread线程;
使用ExecutorService、Callable、Future实现有返回结果的多线程(也就是使用了ExecutorService来管理前面的三种方式)。
27、notify()和notifyAll()有什么区别?
notify可能会导致死锁,而notifyAll则不会任何时候只有一个线程可以获得锁,也就是说只有一个线程可以运行synchronized中的代码使用notifyall,可以唤醒所有处于wait状态的线程,使其重新进入锁的争夺队列中,而notify只能唤醒一个。
wait()应配合while循环使用,不应使用if,务必在wait()调用前后都检查条件,如果不满足,必须调用notify()唤醒另外的线程来处理,自己继续wait()直至条件满足再往下执行。
notify()是对notifyAll()的一个优化,但它有很精确的应用场景,并且要求正确使用。
不然可能导致死锁。
正确的场景应该是WaitSet中等待的是相同的条件,唤醒任一个都能正确处理接下来的事项,如果唤醒的线程无法正确处理,务必确保继续notify()下一个线程,并且自身需要重新回到WaitSet中。
28、volatile是什么?
可以保证有序性吗?
一旦一个共享变量(类的成员变量、类的静态成员变量)被volatile修饰之后,那么就具备了两层语义:
1)保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量的值,这新值对其他线程来说是立即可见的,volatile关键字会强制将修改的值立即写入主存。
2)禁止进行指令重排序。
volatile不是原子性操作什么叫保证部分有序性?
当程序执行到volatile变量的读操作或者写操作时,在其前面的操作的更改肯定全部已经进行,且结果已经对后面的操作可见;
在其后面的操作肯定还没有进行;
由于flag变量为volatile变量,那么在进行指令重排序的过程的时候,不会将语句3放到语句1、语句2前面,也不会讲语句3放到语句4、语句5后面。
但是要注意语句1和语句2的顺序、语句4和语句5的顺序是不作任何保证的。
使用Volatile一般用于状态标记量和单例模式的双检锁。
29、为什么wait,notify和notifyAll这些方法不在thread类里面?
明显的原因是JAVA提供的锁是对象级的而不是线程级的,每个对象都有锁,通过线程获得。
如果线程需要等待某些锁那么调用对象中的wait()方法就有意义了。
如果wait()方法定义在Thread类中,线程正在等待的是哪个锁就不明显了。
简单的说,由于wait,notify和notifyAll都是锁级别的操作,所以把他们定义在Object类中因为锁属于对象。
30、Java中interrupted和isInterruptedd方法的区别?
interrupted()和isInterrupted()的主要区别是前者会将中断状态清除而后者不会。
Java多线程的中断机制是用内部标识来实现的,调用Thread.interrupt()来中断一个线程就会设置中断标识为true。
当中断线程调用静态方法Thread.interrupted()来检查中断状态时,中断状态会被清零。
而非静态方法isInterrupted()用来查询其它线程的中断状态且不会改变中断状态标识。
简单的说就是任何抛出InterruptedException异常的方法都会将中断状态清零。
无论如何,一个线程的中断状态有有可能被其它线程调用中断来改变。
31、有三个线程T1,T2,T3,如何保证顺序执行?
在多线程中有多种方法让线程按特定顺序执行,你可以用线程类的join()方法在一个线程中启动另一个线程,另外一个线程完成该线程继续执行。
为了确保三个线程的顺序你应该先启动后一个(T3调用T2,T2调用T1),这样T1就会先完成而T3后完成。
实际上先启动三个线程中哪一个都行,因为在每个线程的run方法中用join方法限定了三个线程的执行顺序。
32、什么是线程安全
线程安全就是说多线程访问同一代码,不会产生不确定的结果。
在多线程环境中,当各线程不共享数据的时候,即都是私有(private)成员,那么一定是线程安全的。
但这种情况并不多见,在多数情况下需要共享数据,这时就需要进行适当的同步控制了。
线程安全一般都涉及到synchronized,就是一段代码同时只能有一个线程来操作不然中间过程可能会产生不可预制的结果。
如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码。
如果每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。
33、Java线程池中submit()和execute()方法有什
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Java 经典 试题 答案