您的位置:首页 > 职场人生

助你快速踏入高薪职场——2017面试集锦之java基础(三)

2017-11-20 16:38 363 查看
       这套面试题主要目的是帮助那些还没有 java 软件开发实际工作经验,而正在努力寻找 java软件开发工作的朋友在笔试时更好地赢得笔试和面试。 由于这套面试题涉及的范围很泛, 很广, 很杂, 大家不可能一天两天就看完和学完这套面试宝典, 即使你已经学过了有关的技术,那么至少也需要一个月的时间才能消化和掌握这套面试宝典,所以,大家应该早作准备,从拿到这套面试宝典之日起,就要坚持在每天闲暇之余学习其中几道题目,日积月累,等到出去面试时,一切都水到渠成,面试时就自然会游刃有余了。答题时,先答是什么,再答有什么作用和要注意什么(这部分最重要,展现自己的心得)答案的段落分别,层次分明,条理清晰都非常重要,从这些表面的东西也可以看出一个人的习惯、办事风格、条理等。要讲你做出答案的思路过程,或者说你记住答案的思想都写下来。把答题想着是辩论赛。答题就是给别人讲道理、摆事实。答题不局限于什么格式和形式,就是要将自己的学识展现出来!别因为人家题目本来就模棱两可,你就心里胆怯和没底气了,不敢回答了。你要大胆地指出对方题目很模糊和你的观点,
不要把面试官想得有多高, 其实他和你就是差不多的, 你想想,如果他把你招进去了,你们以后就是同事了,可不是差不多的吗?关于就业薪水,如果你是应届生,那不能要高工资,好比大饼的故事,没有文凭还想拿高工资,就去中关村缺什么补什么吧!少数人基础确实很好,在校期间确实又做过一些项目,那仍然是可以要到相对高的工资的。

1、一个".java"源文件中是否可以包括多个类(不是内部类)?有什么限制?

2、Java 有没有 goto? 

3、说说&和&&的区别。

4、在 JAVA 中如何跳出当前的多重嵌套循环?

5、switch 语句能否作用在 byte 上,能否作用在 long 上,能否作用在 String 上? 

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

7、char 型变量中能不能存贮一个中文汉字?为什么? 

8、用最有效率的方法算出 2 乘以 8 等于几? 

9、请设计一个一百亿的计算器

10、使用 final 关键字修饰一个变量时,是引用不能变,还是引用的对象不能变? 

11、"=="和 equals 方法究竟有什么区别?

12、静态变量和实例变量的区别?

13、是否可以从一个 static 方法内部发出对非 static 方法的调用? 

14、Integer 与 int 的区别

15、Math.round(11.5)等於多少? Math.round(-11.5)等於多少?

16、下面的代码有什么不妥之处?

17、请说出作用域 public,private,protected,以及不写时的区别 

18、Overload 和 Override 的区别。Overloaded 的方法是否可以改变返回值的类型?

19、构造器 Constructor 是否可被 override? 

20、 接口是否可继承接口?抽象类是否可实现(implements)接口?抽象类是否可继承具体类(concrete class)?抽象类中是否可以有静态的 main 方法?

21、写 clone()方法时,通常都有一行代码,是什么?

22、面向对象的特征有哪些方面

23、java 中实现多态的机制是什么?

24、abstract class 和 interface 有什么区别?

25、abstract 的 method 是否可同时是 static,是否可同时是 native,是否可同时是synchronized? 

26、什么是内部类?Static Nested Class 和 Inner Class 的不同。 

27、内部类可以引用它的包含类的成员吗?有没有什么限制?

28、Anonymous Inner Class (匿名内部类)是否可以 extends(继承)其它类,是否可以implements(实现)interface(接口)?

29、super.getClass()方法调用

30、String 是最基本的数据类型吗?

31、String s = "Hello";s = s + " world!";这两行代码执行后,原始的 String 对象中的内容到底变了没有?

32、是否可以继承 String 类?

33、String s = new String("xyz");创建了几个 String Object?二者之间有什么区别?

34、String 和 StringBuffer 的区别

35、如何把一段逗号分割的字符串转换成一个数组? 

36、数组有没有 length()这个方法? String 有没有 length()这个方法?

37、下面这条语句一共创建了多少个对象:String s="a"+"b"+"c"+"d";

38、try {}里有一个 return 语句,那么紧跟在这个 try 后的 finally {}里的 code 会不会被执行,什么时候被执行,在 return 前还是后? 

39、下面的程序代码输出的结果是多少?

40、final, finally, finalize 的区别。 

41、运行时异常与一般异常有何异同?

42、error 和 exception 有什么区别?

43、Java 中的异常处理机制的简单原理和应用。

44、请写出你最常见到的 5 个 runtime exception。

45、JAVA 语言如何进行异常处理,关键字:throws,throw,try,catch,finally 分别代表什么意义?在 try 块中可以抛出异常吗?

46、java 中有几种方法可以实现一个线程?用什么关键字修饰同步方法? stop()和

suspend()方法为何不推荐使用?

47、sleep()和 wait()有什么区别? 

48、同步和异步有何异同,在什么情况下分别使用他们?举例说明。 

49. 下面两个方法同步吗?(自己发明)

50、多线程有几种实现方法?同步有几种实现方法? 

51、启动一个线程是用 run()还是 start()?

52、当一个线程进入一个对象的一个 synchronized 方法后,其它线程是否可进入此对象的其它方法?
53、线程的基本概念、线程的基本状态以及状态之间的关系 (53以上请看上一篇)

54、简述 synchronized 和 java.util.concurrent.locks.Lock 的异同?

55、设计 4 个线程,其中两个线程每次对 j 增加 1,另外两个线程对 j 每次减少 1。写出程序。

56、子线程循环 10 次,接着主线程循环 100,接着又回到子线程循环 10 次,接着再回到主线程又循环 100,如此循环 50 次,请写出程序。

57、介绍 Collection 框架的结构 

58、Collection 框架中实现比较要实现什么接口 

59、ArrayList 和 Vector 的区别 

60、HashMap 和 Hashtable 的区别 

61、List 和 Map 区别? 

62、List, Set, Map 是否继承自 Collection 接口?

63、List、Map、Set 三个接口,存取元素时,各有什么特点?

64、说出 ArrayList,Vector, LinkedList 的存储性能和特性 

65、去掉一个 Vector 集合中重复的元素

66、Collection 和 Collections 的区别。 

67、Set 里的元素是不能重复的,那么用什么方法来区分重复与否呢?是用==还是

equals()?它们有何区别? 

68、你所知道的集合类都有哪些?主要方法?

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

70、TreeSet 里面放对象,如果同时放入了父类和子类的实例对象,那比较时使用的是父类的 compareTo 方法,还是使用的子类的 compareTo 方法,还是抛异常! 

71、说出一些常用的类,包,接口,请各举 5 个

72、java 中有几种类型的流?JDK 为每种类型的流提供了一些抽象类以供继承,请说出他们分别是哪些类?

73、字节流与字符流的区别

74、什么是 java 序列化,如何实现 java 序列化?或者请解释 Serializable 接口的作用。

75、描述一下 JVM 加载 class 文件的原理机制? 

76、heap 和 stack 有什么区别。

77、GC 是什么?为什么要有 GC? 

78、垃圾回收的优点和原理。并考虑 2 种回收机制。

79、 垃圾回收器的基本原理是什么?垃圾回收器可以马上回收内存吗?有什么办法主动通知虚拟机进行垃圾回收?

80、什么时候用 assert。

81、java 中会存在内存泄漏吗,请简单描述。

82、能不能自己写个类,也叫 java.lang.String? 

83. Java 代码查错 


基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法, 异常的语法,线程的语法,集合的语法,io 的语法,虚拟机方面的语法。

53 、线程的基本概念、线程的基本状态以及状态之间的关系 线程的基本概念、线程的基本状态以及状态之间的关系

       一个程序中可以有多条执行线索同时执行, 一个线程就是程序中的一条执行线索, 每个线程上都关联有要执行的代码,即可以有多段程序代码同时运行,每个程序至少都有一个线程,即 main 方法执行的那个线程。如果只是一个 cpu,它怎么能够同时执行多段程序呢?这是从宏观上来看的,cpu 一会执行 a 线索,一会执行 b 线索,切换时间很快,给人的感觉是a,b 在同时执行,好比大家在同一个办公室上网,只有一条链接到外部网线,其实,这条网

线一会为 a 传数据,一会为 b 传数据,由于切换时间很短暂,所以,大家感觉都在同时上网。状态: 就绪, 运行, synchronize 阻塞, wait 和 sleep 挂起, 结束。 wait 必须在 synchronized内部调用。调用线程的 start 方法后线程进入就绪状态,线程调度系统将就绪状态的线程转为运行状态,遇到 synchronized 语句时,由运行状态转为阻塞,当 synchronized 获得锁后,由阻塞转为运行,在这种情况可以调用 wait 方法转为挂起状态,当线程关联的代码执行完后,线程变为结束状态。

54 、简述 synchronized 和 和 java.util.concurrent.locks.Lock  的异同?

       主要相同点:Lock 能完成 synchronized 所实现的所有功能

       主要不同点:Lock 有比 synchronized 更精确的线程语义和更好的性能。synchronized 会自动释放锁,而 Lock 一定要求程序员手工释放,并且必须在 finally 从句中释放。Lock 还有更强大的功能,例如,它的 tryLock 方法可以非阻塞方式去拿锁。举例说明(对下面的题用 lock 进行了改写) :

package com.huawei.interview;

import java.util.concurrent.locks.Lock;

import java.util.concurrent.locks.ReentrantLock;

publicclass ThreadTest {

/**

* @paramargs

*/

private int j;

private Lock lock =newReentrantLock();

public static voidmain(String[] args) {

// TODO Auto-generated method stub

ThreadTest tt = new ThreadTest();

for(int i=0;i<2;i++)

{

new Thread(tt.new Adder()).start();

new Thread(tt.new Subtractor()).start();

}

}

private class SubtractorimplementsRunnable

{

@Override

public void run() {

// TODO Auto-generated methodstub

while(true)

{

/*synchronized (ThreadTest.this) {

System.out.println("j--="+ j--);

//这里抛异常了,锁能释放吗?

}*/

lock.lock();

try

{

System.out.println("j--="+ j--);

}finally

{

lock.unlock();

}

}

}

}

private class AdderimplementsRunnable

{

@Override

public void run() {

// TODO Auto-generated methodstub

while(true)

{

/*synchronized (ThreadTest.this) {

System.out.println("j++="+ j++);

}*/

lock.lock();

try

{

System.out.println("j++="+ j++);

}finally

{

lock.unlock();

}

}

}

}

}

55 、设计 4  个线程,其中两个线程每次对 j  增加 1 ,另外两个线程对 j 每次减少 每次减少

       1 。写出程序。

       以下程序使用内部类实现线程,对 j 增减的时候没有考虑顺序问题。

public class ThreadTest1

{

private int j;

public static void main(String args[]){

ThreadTest1 tt=newThreadTest1();

Inc inc=tt.new Inc();

Dec dec=tt.new Dec();

for(inti=0;i<2;i++){

Thread t=newThread(inc);

t.start();

t=new Thread(dec);

t.start();

}

}

private synchronized void inc(){

j++;

System.out.println(Thread.currentThread().getName()+"-inc:"+j);

}

private synchronized void dec(){

j--;

System.out.println(Thread.currentThread().getName()+"-dec:"+j);

}

class Inc implements Runnable{

public void run(){

for(inti=0;i<100;i++){

inc();

}

}

}

class Dec implements Runnable{

public void run(){

for(inti=0;i<100;i++){

dec();

}

}

}

}

     ----------随手再写的一个-------------

class A

{

JManger j =new JManager();

main()

{

new A().call();

}

void call

{

for(int i=0;i<2;i++)

{

new Thread(

newRunnable(){ public void run(){while(true){j.accumulate()}}}

).start();

new Thread(newRunnable(){ public void run(){while(true){j.sub()}}}).start();

}

}

}

class JManager

{

private j = 0;

public synchronized voidsubtract()

{

j--

}

public synchronized voidaccumulate()

{

j++;

}

}

56 、子线程循环 10  次,接着主线程循环 100 ,接着又回到子线程循环 10 次, 次,接着再回到主线程又循环 接着再回到主线程又循环 100 ,如此循环 50  次,请写出程序。

      最终的程序代码如下:

public class ThreadTest {

/**

* @paramargs

*/

public static voidmain(String[] args) {

// TODO Auto-generated method stub

new ThreadTest().init();

}

public void init()

{

final Business business =newBusiness();

new Thread(

new Runnable()

{

public voidrun() {

for(inti=0;i<50;i++)

{

business.SubThread(i);

}

}

}

).start();

for(int i=0;i<50;i++)

{

business.MainThread(i);

}

}

private class Business

{

booleanbShouldSub =true;//这里相当于定义了控制该谁执行的一个信号灯

public synchronized voidMainThread(int i)

{

if(bShouldSub)

try {

this.wait();

} catch(InterruptedException e) {

// TODO Auto-generatedcatch block

e.printStackTrace();

}

for(int j=0;j<5;j++)

{

System.out.println(Thread.currentThread().getName()+ ":i=" + i +",j=" + j);

}

bShouldSub =true;

this.notify();

}

public synchronized voidSubThread(int i)

{

if(!bShouldSub)

try {

this.wait();

} catch (InterruptedExceptione) {

// TODO Auto-generatedcatch block

e.printStackTrace();

}

for(intj=0;j<10;j++)

{

System.out.println(Thread.currentThread().getName()+ ":i=" + i +",j=" + j);

}

bShouldSub =false;

this.notify();

}

}

}

       备注:不可能一上来就写出上面的完整代码,最初写出来的代码如下,问题在于两个线程的代码要参照同一个变量,即这两个线程的代码要共享数据,所以,把这两个线程的执行代码搬到同一个类中去:

package com.huawei.interview.lym;

publicclass ThreadTest {

private static booleanbShouldMain=false;

public static void main(String[]args) {

// TODO Auto-generated method stub

/*new Thread(){

public void run()

{

for(int i=0;i<50;i++)

{

for(int j=0;j<10;j++)

{

System.out.println("i="+ i + ",j=" + j);

}

}

}

}.start();*/

//final String str = newString("");

new Thread(

new Runnable()

{

public voidrun()

{

for(inti=0;i<50;i++)

{

synchronized(ThreadTest.class) {

if(bShouldMain)

{

try {

ThreadTest.class.wait();}

catch(InterruptedException e) {

e.printStackTrace();

}

}

for(intj=0;j<10;j++)

{

System.out.println(

Thread.currentThread().getName()+

"i="+ i + ",j=" + j);

}

bShouldMain= true;

ThreadTest.class.notify();

}

}

}

}

).start();

for(int i=0;i<50;i++)

{

synchronized (ThreadTest.class){

if(!bShouldMain)

{

try {

ThreadTest.class.wait();}

catch(InterruptedException e) {

e.printStackTrace();

}

}

for(intj=0;j<5;j++)

{

System.out.println(

Thread.currentThread().getName()+

"i=" + i +",j=" + j);

}

bShouldMain =false;

ThreadTest.class.notify();

}

}

}

}

下面使用 jdk5中的并发库来实现的:

import java.util.concurrent.Executors;

import java.util.concurrent.ExecutorService;

import java.util.concurrent.locks.Lock;

import java.util.concurrent.locks.ReentrantLock;

import java.util.concurrent.locks.Condition;

public class ThreadTest

{

private static Locklock = new ReentrantLock();

private staticCondition subThreadCondition = lock.newCondition();

private staticboolean bBhouldSubThread = false;

public static voidmain(String [] args)

{

ExecutorServicethreadPool = Executors.newFixedThreadPool(3);

threadPool.execute(newRunnable(){

publicvoid run()

{

for(inti=0;i<50;i++)

{

lock.lock();

try

{

if(!bBhouldSubThread)

subThreadCondition.await();

for(intj=0;j<10;j++)

{

System.out.println(Thread.currentThread().getName()+ ",j=" + j);

}

bBhouldSubThread= false;

subThreadCondition.signal();

}catch(Exceptione)

{

}

finally

{

lock.unlock();

}

}

}

});

threadPool.shutdown();

for(inti=0;i<50;i++)

{

lock.lock();

try

{

if(bBhouldSubThread)

subThreadCondition.await();

for(intj=0;j<10;j++)

{

System.out.println(Thread.currentThread().getName()+ ",j=" + j);

}

bBhouldSubThread= true;

subThreadCondition.signal();

}catch(Exceptione)

{

}

finally

{

lock.unlock();

}

}

}

}

57 、介绍 Collection  框架的结构

       答:随意发挥题,天南海北谁便谈,只要让别觉得你知识渊博,理解透彻即可。

58 、Collection  框架中实现比较要实现什么接口

       comparable/comparator

59 、ArrayList 和 和 Vector  的区别

       答:这两个类都实现了 List 接口(List 接口继承了 Collection 接口) ,他们都是有序集合,即存储在这两个集合中的元素的位置都是有顺序的, 相当于一种动态的数组, 我们以后可以按位置索引号取出某个元素, ,并且其中的数据是允许重复的,这是 HashSet 之类的集合的最大不同处,HashSet 之类的集合不可以按索引号去检索其中的元素,也不允许有重复的元素。(本来题目问的与 hashset 没有任何关系,但为了说清楚 ArrayList 与 Vector 的功能,我们使用对比方式,更有利于说明问题)
。接着才说 ArrayList 与 Vector 的区别,这主要包括两个方面:.

     (1)同步性:Vector 是线程安全的, 也就是说是它的方法之间是线程同步的, 而 ArrayList 是线程序不安全的,它的方法之间是线程不同步的。如果只有一个线程会访问到集合,那最好是使用 ArrayList,因为它不考虑线程安全,效率会高些;如果有多个线程会访问到集合,那最好是使用 Vector,因为不需要我们自己再去考虑和编写线程安全的代码。备注:对于 Vector&ArrayList、Hashtable&HashMap,要记住线程安全的问题,记住 Vector与 Hashtable 是旧的,
是 java 一诞生就提供了的, 它们是线程安全的, ArrayList 与 HashMap是 java2时才提供的,它们是线程不安全的。所以,我们讲课时先讲老的。

    (2)数据增长:ArrayList 与 Vector 都有一个初始的容量大小, 当存储进它们里面的元素的个数超过了容量时,就需要增加 ArrayList 与 Vector 的存储空间,每次要增加存储空间时,不是只增加一个存储单元, 而是增加多个存储单元, 每次增加的存储单元的个数在内存空间利用与程序效率之间要取得一定的平衡。Vector 默认增长为原来两倍,而 ArrayList 的增长策略在文档中没有明确规定(从源代码看到的是增长为原来的1.5倍) 。ArrayList 与 Vector 都可以设置初始的空间大小,Vector
还可以设置增长的空间大小,而 ArrayList 没有提供设置增长空间的方法。

      总结:即 Vector 增长原来的一倍,ArrayList 增加原来的0.5倍。

60 、HashMap 和 和 Hashtable  的区别

      (条理上还需要整理,也是先说相同点,再说不同点)

        HashMap 是 Hashtable 的轻量级实现(非线程安全的实现) ,他们都完成了 Map 接口,主要区别在于 HashMap 允许空(null)键值(key),由于非线程安全,在只有一个线程访问的情况下,效率要高于 Hashtable。

HashMap 允许将 null 作为一个 entry 的 key 或者 value,而 Hashtable 不允许。HashMap 把 Hashtable 的 contains 方法去掉了, 改成 containsvalue 和 containsKey。 因为contains 方法容易让人引起误解。Hashtable 继承自 Dictionary 类, 而 HashMap 是 Java1.2引进的 Map interface 的一个实现。最大的不同是,Hashtable 的方法是 Synchronize 的,而
HashMap 不是,在多个线程访问Hashtable 时,不需要自己为它的方法实现同步,而 HashMap 就必须为之提供外同步。Hashtable 和 HashMap 采用的 hash/rehash 算法都大概一样, 所以性能不会有很大的差异。就 HashMap 与 HashTable 主要从三方面来说。

      一.历史原因:Hashtable 是基于陈旧的 Dictionary 类的,HashMap 是 Java 1.2引进的 Map接口的一个实现

      二.同步性:Hashtable 是线程安全的,也就是说是同步的,而 HashMap 是线程序不安全的,不是同步的

      三.值:只有 HashMap 可以让你将空值作为一个表的条目的 key 或 value

61 、List  和 Map  区别?

       一个是存储单列数据的集合,另一个是存储键和值这样的双列数据的集合,List 中存储的数据是有顺序,并且允许重复;Map 中存储的数据是没有顺序的,其键是不能重复的,它的值是可以有重复的。

62 、List, Set, Map  是否继承自 Collection  接口?

       List,Set 是,Map 不是

63 、List 、Map 、Set  三个接口,存取元素时,各有什么特点?

       这样的题属于随意发挥题:这样的题比较考水平,两个方面的水平:一是要真正明白这些内容,二是要有较强的总结和表述能力。如果你明白,但表述不清楚,在别人那里则等同于不明白。首先,List 与 Set 具有相似性,它们都是单列元素的集合,所以,它们有一个功共同的父接口,叫 Collection。Set 里面不允许有重复的元素,所谓重复,即不能有两个相等(注意,不是仅仅是相同)的对象,即假设 Set 集合中有了一个 A 对象,现在我要向 Set 集合再存

入一个 B 对象,但 B 对象与 A 对象 equals 相等,则 B 对象存储不进去,所以,Set 集合的add 方法有一个 boolean 的返回值,当集合中没有某个元素,此时 add 方法可成功加入该元素时,则返回 true,当集合含有与某个元素equals 相等的元素时,此时 add 方法无法加入该元素,返回结果为 false。Set 取元素时,没法说取第几个,只能以 Iterator 接口取得所有的元素,再逐一遍历各个元素。List 表示有先后顺序的集合,注意,不是那种按年龄、按大小、按价格之类的排序。当我们多次调用
add(Obj e)方法时, 每次加入的对象就像火车站买票有排队顺序一样, 按先来后到的顺序排序。有时候,也可以插队,即调用 add(int index,Obj e)方法,就可以指定当前对象在集合中的存放位置。一个对象可以被反复存储进 List 中,每调用一次 add 方法,这个对象就被插入进集合中一次,其实,并不是把这个对象本身存储进了集合中,而是在集合中用一个索引变量指向这个对象,当这个对象被 add 多次时,即相当于集合中有多个索引指向了这个对象,如图 x 所示。List 除了可以以 Iterator
接口取得所有的元素,再逐一遍历各个元素之外,还可以调用 get(index i)来明确说明取第几个。Map 与 List 和 Set 不同,它是双列的集合,其中有 put 方法,定义如下:put(obj key,objvalue),每次存储时,要存储一对 key/value,不能存储重复的 key,这个重复的规则也是按 equals 比较相等。取则可以根据 key 获得相应的 value,即 get(Object key)返回值为 key 所对应的 value。另外,也可以获得所有的 key 的结合,还可以获得所有的
value的结合,还可以获得 key 和 value 组合成的 Map.Entry 对象的集合。

List 以特定次序来持有元素,可有重复元素。Set 无法拥有重复元素,内部排序。Map 保存key-value 值,value 可多值。HashSet 按照 hashcode 值的某种运算方式进行存储, 而不是直接按 hashCode 值的大小进行存储。例如, "abc"---> 78,"def" ---> 62,"xyz" ---> 65在 hashSet 中的存储顺序不是62,65,78,这些问题感谢以前一个叫崔健的学员提出,最后通过查看源代码给他解释清楚,看本次培训学员当中有多少能看懂源码。 LinkedHashSet
按插入的顺序存储, 那被存储对象的 hashcode 方法还有什么作用呢?学员想想!hashset 集合比较两个对象是否相等, 首先看hashcode 方法是否相等, 然后看 equals 方法是否相等。 new 两个 Student 插入到 HashSet中,看 HashSet 的 size,实现 hashcode 和 equals 方法后再看 size。同一个对象可以在 Vector 中加入多次。往集合里面加元素,相当于集合里用一根绳子连接到了目标对象。往 HashSet 中却加不了多次的。

64 、说出 ArrayList,Vector, LinkedList  的存储性能和特性

       ArrayList 和 Vector 都是使用数组方式存储数据,此数组元素数大于实际存储的数据以便增加和插入元素, 它们都允许直接按序号索引元素, 但是插入元素要涉及数组元素移动等内存操作,所以索引数据快而插入数据慢,Vector 由于使用了 synchronized 方法(线程安全) ,通常性能上较 ArrayList 差,而 LinkedList 使用双向链表实现存储,按序号索引数据需要进行前向或后向遍历,但是插入数据时只需要记录本项的前后项即可,所以插入速度较快。LinkedList 也是线程不安全的,
LinkedList 提供了一些方法, 使得 LinkedList 可以被当作堆 可以被当作堆栈和队列来使用。

65 、去掉一个 Vector  集合中重复的元素

Vector newVector = new Vector();

For (int i=0;i<vector.size();i++)

{

Object obj = vector.get(i);

if(!newVector.contains(obj);

newVector.add(obj);

}

还有一种简单的方式,HashSet set = new HashSet(vector);

66 、Collection  和 Collections 的 的区别。

       Collection 是集合类的上级接口,继承与他的接口主要有 Set 和 List.Collections 是针对集合类的一个帮助类,他提供一系列静态方法实现对各种集合的搜索、排序、线程安全化等操作。

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

      Set 里的元素是不能重复的,元素重复与否是使用 equals()方法进行判断的。equals()和==方法决定引用值是否指向同一对象 equals()在类中被覆盖,为的是当两个分离的对象的内容和类型相配的话,返回真值。

68 、你所知道的集合类都有哪些?主要方法?

       最常用的集合类是 List 和 Map。 List 的具体实现包括 ArrayList 和 Vector,它们是可变大小的列表,比较适合构建、存储和操作任何类型对象的元素列表。 List 适用于按数值索引访问元素的情形。Map 提供了一个更通用的元素存储方法。 Map 集合类用于存储元素对(称作"键"和"值") ,其中每个键映射到一个值。我记的不是方法名,而是思想,我知道它们都有增删改查的方法,但这些方法的具体名称,我记得不是很清楚,对于 set,大概的方法是 add, remove, contains;对于
map,大概的方法就是 put,remove,contains 等,因为,我只要在 eclispe 下按点操作符,很自然的这些方法就出来了。我记住的一些思想就是 List 类会有 get(int index)这样的方法,因为它可以按顺序取元素, 而 set 类中没有 get(int index)这样的方法。 List 和 set 都可以迭代出所有元素,迭代时先要得到一个 iterator 对象,所以,set 和 list 类都有一个 iterator 方法,用于返回那个 iterator 对象。map 可以返回三个集合,一个是返回所有的
key 的集合,另外一个返回的是所有 value 的集合,再一个返回的 key 和 value 组合成的 EntrySet 对象的集合,map 也有 get 方法,参数是 key,返回值是 key 对应的 value。

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

       对。如果对象要保存在 HashSet 或 HashMap 中,它们的 equals 相等,那么,它们的 hashcode值就必须相等。如果不是要保存在HashSet或HashMap, 则与hashcode没有什么关系了, 这时候hashcode不等是可以的,例如 arrayList 存储的对象就不用实现 hashcode,当然,我们没有理由不实现,通常都会去实现的。

70 、TreeSet 里面放对象,如果同时放入了父类和子类的实例对象,那比较时使 里面放对象,如果同时放入了父类和子类的实例对象,那比较时使用的是父类的 用的是父类的 compareTo  方法,还是使用的子类的 compareTo 方法,还是抛 方法,还是抛异常!

     (应该是没有针对问题的确切的答案,当前的 add 方法放入的是哪个对象,就调用哪个对象的 compareTo 方法,至于这个 compareTo 方法怎么做,就看当前这个对象的类中是如何编写这个方法的)实验代码:

public class ParentimplementsComparable {

private int age = 0;

public Parent(int age){

this.age = age;

}

public int compareTo(Object o){

// TODO Auto-generated method stub

System.out.println("method ofparent");

Parent o1 = (Parent)o;

return age>o1.age?1:age<o1.age?-1:0;

}

}

public class Childextends Parent {

public Child(){

super(3);

}

public int compareTo(Object o){

// TODO Auto-generated methodstub

System.out.println("methodof child");

// Child o1 = (Child)o;

return 1;

}

}

public class TreeSetTest {

/**

* @paramargs

*/

public static voidmain(String[] args) {

// TODO Auto-generated method stub

TreeSet set = new TreeSet();

set.add(newParent(3));

set.add(new Child());

set.add(newParent(4));

System.out.println(set.size());

}

}

71 、说出一些常用的类,包,接口,请各举 5  个

       要让人家感觉你对 java ee 开发很熟,所以,不能仅仅只列 core java 中的那些东西,要多列你在做 ssh 项目中涉及的那些东西。就写你最近写的那些程序中涉及的那些类。

       常用的类:BufferedReader BufferedWriter FileReader FileWirter String Integer java.util.Date,System,Class,List,HashMap

       常用的包:java.lang java.io java.util java.sql,javax.servlet,org.apache.strtuts.action,org.hibernate

       常用的接口:Remote List Map Document NodeList, Servlet, HttpServletRequest, HttpServletResponse, Transaction(Hibernate)、Session(Hibernate),HttpSession



72、 、 java  中有几种类型的流?JDK 为每种类型的流提供了一些抽象类以供继承, 为每种类型的流提供了一些抽象类以供继承,请说出他们分别是哪些类? 请说出他们分别是哪些类?


       字节流,字符流。字节流继承于 InputStream OutputStream,字符流继承于InputStreamReader OutputStreamWriter。在 java.io 包中还有许多其他的流,主要是为了提高性能和使用方便。

73 、字节流与字符流的区别

        要把一片二进制数据数据逐一输出到某个设备中,或者从某个设备中逐一读取一片二进制数据,不管输入输出设备是什么,我们要用统一的方式来完成这些操作,用一种抽象的方式进行描述,这个抽象描述方式起名为 IO 流,对应的抽象类为 OutputStream 和InputStream,不同的实现类就代表不同的输入和输出设备,它们都是针对字节进行操作的。在应用中,经常要完全是字符的一段文本输出去或读进来,用字节流可以吗?计算机中的一切最终都是二进制的字节形式存在。对于“中国”这些字符,首先要得到其对应的字节,然后将字节写入到输出流。读取时,首先读到的是字节,可是我们要把它显示为字符,我们需要将字节转换成字符。由于这样的需求很广泛,人家专门提供了字符流的包装类。底层设备永远只接受字节数据,
有时候要写字符串到底层设备, 需要将字符串转成字节再进行写入。 字符流是字节流的包装, 字符流则是直接接受字符串,它内部将串转成字节,再写入底层设备,这为我们向 IO 设别写入或读取字符串提供了一点点方便。字符向字节转换时,要注意编码的问题,因为字符串转成字节数组,其实是转成该字符的某种编码的字节形式,读取也是反之的道理。讲解字节流与字符流关系的代码案例:

import java.io.BufferedReader;

import java.io.FileInputStream;

import java.io.FileOutputStream;

import java.io.FileReader;

import java.io.FileWriter;

import java.io.InputStreamReader;

import java.io.PrintWriter;

public class IOTest {

public static void main(String[]args) throws Exception {

String str = "中国人";

/*FileOutputStreamfos = newFileOutputStream("1.txt");

fos.write(str.getBytes("UTF-8"));

fos.close();*/

/*FileWriter fw =new FileWriter("1.txt");

fw.write(str);

fw.close();*/

PrintWriter pw =new PrintWriter("1.txt","utf-8");

pw.write(str);

pw.close();

/*FileReader fr =new FileReader("1.txt");

char[] buf = newchar[1024];

int len =fr.read(buf);

String myStr = newString(buf,0,len);

System.out.println(myStr);*/

/*FileInputStreamfr = new FileInputStream("1.txt");

byte[] buf = newbyte[1024];

int len =fr.read(buf);

String myStr = newString(buf,0,len,"UTF-8");

System.out.println(myStr);*/

BufferedReader br =new BufferedReader(

newInputStreamReader(

newFileInputStream("1.txt"),"UTF-8"

)

);

String myStr =br.readLine();

br.close();

System.out.println(myStr);

}

}

74 、 什么是 java  序列化, 如何实现 java  序列化?或者请解释 Serializable 接口 接口的作用。

       我们有时候将一个 java 对象变成字节流的形式传出去或者从一个字节流中恢复成一个 java对象,例如,要将 java 对象存储到硬盘或者传送给网络上的其他计算机,这个过程我们可以自己写代码去把一个 java 对象变成某个格式的字节流再传输,但是,jre 本身就提供了这种支持,我们可以调用 OutputStream 的 writeObject 方法来做,如果要让 java 帮我们做,要被传输的对象必须实现 要被传输的对象必须实现 serializable  接口,这样,javac 编译时就会进行特殊处理,编译的类才可以被
writeObject 方法操作,这就是所谓的序列化。需要被序列化的类必须实现

Serializable 接口,该接口是一个 mini 接口,其中没有需要实现的方法,implementsSerializable  只是为了标注该对象是可被序列化的。例如,在 web 开发中,如果对象被保存在了 Session 中,tomcat 在重启时要把 Session 对象序列化到硬盘,这个对象就必须实现 Serializable 接口。如果对象要经过分布式系统进行网络传输或通过 rmi 等远程调用,这就需要在网络上传输对象,被传输的对象就必须实现Serializable 接口。

75 、描述一下 JVM  加载 class  文件的原理机制?

      JVM 中类的装载是由 ClassLoader 和它的子类来实现的,Java ClassLoader 是一个重要的Java 运行时系统组件。它负责在运行时查找和装入类文件的类。

76 、heap 和 和 stack  有什么区别。

        java 的内存分为两类,一类是栈内存,一类是堆内存。栈内存是指程序进入一个方法时,会为这个方法单独分配一块私属存储空间, 用于存储这个方法内部的局部变量, 当这个方法结束时,分配给这个方法的栈会释放,这个栈中的变量也将随之释放。堆是与栈作用不同的内存,一般用于存放不放在当前方法栈中的那些数据,例如,使用 new

创建的对象都放在堆里,所以,它不会随方法的结束而消失。方法中的局部变量使用 方法中的局部变量使用 final修饰后,放在堆中,而不是栈中。

77 、GC  是什么? 为什么要有 GC?

       GC 是垃圾收集的意思(Gabage Collection),内存处理是编程人员容易出现问题的地方,忘记或者错误的内存回收会导致程序或系统的不稳定甚至崩溃,Java 提供的 GC 功能可以自动监测对象是否超过作用域从而达到 自动回收内存的目的,Java 语言没有提供释放已分配内存的显示操作方法。

78 、垃圾回收的优点和原理。并考虑 2  种回收机制。

       Java 语言中一个显著的特点就是引入了垃圾回收机制,使 c++程序员最头疼的内存管理的问题迎刃而解,它使得 Java 程序员在编写程序的时候不再需要考虑内存管理。由于有个垃圾回收机制,Java 中的对象不再有"作用域"的概念,只有对象的引用才有"作用域"。垃圾回收可以有效的防止内存泄露, 有效的使用可以使用的内存。 垃圾回收器通常是作为一个单独的低级别的线程运行, 不可预知的情况下对内存堆中已经死亡的或者长时间没有使用的对象进行清楚和回收,程序员不能实时的调用垃圾回收器对某个对象或所有对象进行垃圾回收。回收机制有分代复制垃圾回收和标记垃圾回收,增量垃圾回收。

79、垃圾回收器的基本原理是什么?垃圾回收器可以马上回收内存吗?有什么 、垃圾回收器的基本原理是什么?垃圾回收器可以马上回收内存吗?有什么办法主动通知虚拟机进行垃圾回收? 法主动通知虚拟机进行垃圾回收?

       对于 GC 来说, 当程序员创建对象时, GC 就开始监控这个对象的地址、 大小以及使用情况。通常,GC  采用有向图的方式记录和管理堆(heap)中的所有对象。通过这种方式确定哪些对象是"可达的",哪些对象是"不可达的"。当 GC 确定一些对象为"不可达"时,GC 就有责任回收这些内存空间。可以。程序员可以手动执行 System.gc(),通知 GC 运行,但是 Java 语言规范并不保证 GC 一定会执行。

80 、什么时候用 assert 。

       assertion(断言)在软件开发中是一种常用的调试方式,很多开发语言中都支持这种机制。在实现中,assertion 就是在程序中的一条语句,它对一个 boolean 表达式进行检查,一个正确程序必须保证这个 boolean 表达式的值为 true;如果该值为 false,说明程序已经处于不正确的状态下,assert 将给出警告或退出。一般来说,assertion 用于保证程序最基本、关 用于保证程序最基本、关键的正确性。assertion 检查通常在开发和测试时开启。为了提高性能,在软件发布后,assertion
检查通常是关闭的。

package com.huawei.interview;

publicclass AssertTest {

/**

* @paramargs

*/

public static voidmain(String[] args) {

// TODO Auto-generated method stub

int i = 0;

for(i=0;i<5;i++)

{

System.out.println(i);

}

//假设程序不小心多了一句--i;

--i;

assert i==5;

}

}

81 、java  中会存在内存泄漏吗,请简单描述。

       所谓内存泄露就是指一个不再被程序使用的对象或变量一直被占据在内存中。java 中有垃圾回收机制,它可以保证一对象不再被引用的时候,即对象编程了孤儿的时候,对象将自动被垃圾回收器从内存中清除掉。由于 Java 使用有向图的方式进行垃圾回收管理,可以消除引用循环的问题,例如有两个对象,相互引用,只要它们和根进程不可达的,那么 GC 也是可以回收它们的,例如下面的代码可以看到这种情况的内存回收:

package com.huawei.interview;

import java.io.IOException;

publicclass GarbageTest {

/**

* @paramargs

* @throwsIOException

*/

public static voidmain(String[] args)throws IOException {

// TODO Auto-generated method stub

try {

gcTest();

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

System.out.println("hasexited gcTest!");

System.in.read();

System.in.read();

System.out.println("out begingc!");

for(int i=0;i<100;i++)

{

System.gc();

System.in.read();

System.in.read();

}

}

private static voidgcTest()throws IOException {

System.in.read();

System.in.read();

Person p1 = new Person();

System.in.read();

System.in.read();

Person p2 = new Person();

p1.setMate(p2);

p2.setMate(p1);

System.out.println("beforeexit gctest!");

System.in.read();

System.in.read();

System.gc();

System.out.println("exitgctest!");

}

private static classPerson

{

byte[] data =new byte[20000000];

Person mate = null;

public void setMate(Personother)

{

mate = other;

}

}

}

       java 中的内存泄露的情况: 长生命周期的对象持有短生命周期对象的引用就很可能发生内存泄露, 尽管短生命周期对象已经不再需要, 但是因为长生命周期对象持有它的引用而导致不能被回收,这就是 java 中内存泄露的发生场景,通俗地说,就是程序员可能创建了一个对象,以后一直不再使用这个对象,这个对象却一直被引用,即这个对象无用但是却无法被垃圾回收器回收的,这就是 java 中可能出现内存泄露的情况,例如,缓存系统,我们加载了一个对象放在缓存中(例如放在一个全局 map 对象中),然后一直不再使用它,这个对象一直被缓存引用,但却不再被使用。检查
java 中的内存泄露,一定要让程序将各种分支情况都完整执行到程序结束,然后看某个对象是否被使用过,如果没有,则才能判定这个对象属于内存泄露。如果一个外部类的实例对象的方法返回了一个内部类的实例对象, 这个内部类对象被长期引用了,即使那个外部类实例对象不再被使用,但由于内部类持久外部类的实例对象,这个外部类对象将不会被垃圾回收,这也会造成内存泄露。下面内容来自于网上 (主要特点就是清空堆栈中的某个元素,并不是彻底把它从数组中拿掉,而是把存储的总数减少,本人写得可以比这个好,在拿掉某个元素时,顺便也让它从数组中消失,将那个元素所在的位置的值设置为
null 即可) :我实在想不到比那个堆栈更经典的例子了,以致于我还要引用别人的例子,下面的例子不是我想到的,是书上看到的,当然如果没有在书上看到,可能过一段时间我自己也想的到,可是那时我说是我自己想到的也没有人相信的。

public class Stack {

private Object[] elements=new Object[10];

private int size = 0;

public void push(Object e){

ensureCapacity();

elements[size++] = e;

}

public Object pop(){

if( size == 0)

throw new EmptyStackException();

return elements[--size];

}

private void ensureCapacity(){

if(elements.length == size){

Object[] oldElements = elements;

elements = new Object[2 * elements.length+1];

System.arraycopy(oldElements,0, elements, 0, size);

}

}

}

       上面的原理应该很简单,假如堆栈加了10个元素,然后全部弹出来,虽然堆栈是空的,没有我们要的东西,但是这是个对象是无法回收的,这个才符合了内存泄露的两个条件:无用,无法回收。但是就是存在这样的东西也不一定会导致什么样的后果, 如果这个堆栈用的比较少, 也就浪费了几个 K 内存而已,反正我们的内存都上 G 了,哪里会有什么影响,再说这个东西很快就会被回收的,有什么关系。下面看两个例子。

       例子1

public class Bad{

public static Stack s=Stack();

static{

s.push(new Object());

s.pop(); //这里有一个对象发生内存泄露

s.push(new Object()); //上面的对象可以被回收了,等于是自愈了

}

}

       因为是 static,就一直存在到程序退出,但是我们也可以看到它有自愈功能,就是说如果你的 Stack 最多有100个对象,那么最多也就只有100个对象无法被回收其实这个应该很容易理解,Stack 内部持有100个引用,最坏的情况就是他们都是无用的,因为我们一旦放新的进取,以前的引用自然消失!内存泄露的另外一种情况:当一个对象被存储进 HashSet 集合中以后,就不能修改这个对象中的那些参与计算哈希值的字段了,否则,对象修改后的哈希值与最初存储进 HashSet集合中时的哈希值就不同了,在这种情况下,即使在
contains 方法使用该对象的当前引用作为的参数去 HashSet 集合中检索对象,也将返回找不到对象的结果,这也会导致无法从HashSet 集合中单独删除当前对象,造成内存泄露。

82 、能不能自己写个类,也叫 java.lang.String ?

        可以,但在应用的时候,需要用自己的类加载器去加载,否则,系统的类加载器永远只是去加载 jre.jar 包中的那个 java.lang.String。 由于在 tomcat 的 web 应用程序中, 都是由 webapp自己的类加载器先自己加载 WEB-INF/classess 目录中的类, 然后才委托上级的类加载器加载,如果我们在 tomcat 的 web 应用程序中写一个 java.lang.String,这时候 Servlet 程序加载的就是我们自己写的 java.lang.String,但是这么干就会出很多潜在的问题,原来所有用了
java.lang.String 类的都将出现问题。虽然 java 提供了 endorsed 技术,可以覆盖 jdk 中的某些类,具体做法是….。但是,能够被覆盖的类是有限制范围,反正不包括 java.lang 这样的包中的类。(下面的例如主要是便于大家学习理解只用,不要作为答案的一部分,否则,人家怀疑是题目泄露了)例如,运行下面的程序:

package java.lang;

publicclass String {

/**

* @paramargs

*/

public static voidmain(String[] args) {

// TODO Auto-generated method stub

System.out.println("string");

}

}

       报告的错误如下:java.lang.NoSuchMethodError:main     Exception inthread "main",这是因为加载了 jre 自带的 java.lang.String,而该类中没有 main 方法。

83. Java  代码查错

      1.

abstract class Name {

private String name;

public abstract boolean isStupidName(String name) {}

}

      大侠们,这有何错误?

      答案: 错。abstract method 必须以分号结尾,且不带花括号。

      2.

public class Something {

void doSomething () {

private String s = "";

int l = s.length();

}

}

       有错吗?

       答案: 错。局部变量前不能放置任何访问修饰符 (private,public,和 protected)。final 可以用来修饰局部变量

(final 如同 abstract 和 strictfp,都是非访问修饰符,strictfp 只能修饰 class 和 method 而非variable)。

       3.

abstract class Something {

private abstract String doSomething ();

}

       这好像没什么错吧?

       答案: 错。abstract 的 methods 不能以 private 修饰。abstract 的 methods 就是让子类implement(实现)具体细节的,怎么可以用 private 把 abstractmethod 封锁起来呢? (同理,abstract method 前不能加 final)。

       4.

public class Something {

public int addOne(final int x) {

return ++x;

}

}

       这个比较明显。

       答案: 错。int x 被修饰成 final,意味着 x 不能在 addOne method 中被修改。

       5.

public class Something {

public static void main(String[] args) {

Other o = new Other();

new Something().addOne(o);

}

public void addOne(final Other o) {

o.i++;

}

}

class Other {

public int i;

}

       和上面的很相似,都是关于 final 的问题,这有错吗?

       答案: 正确。在 addOne method 中,参数 o 被修饰成 final。如果在 addOne method 里我们修改了 o 的 reference(比如: o = new Other();),那么如同上例这题也是错的。但这里修改的是 o 的 member vairable(成员变量),而 o 的 reference 并没有改变。

       6.

class Something {

int i;

public void doSomething() {

System.out.println("i = "+ i);

}

}

       有什么错呢? 看不出来啊。

       答案: 正确。输出的是"i = 0"。int i 属於 instant variable (实例变量,或叫成员变量)。instant variable 有 default value。int 的 default value 是0。

       7.

class Something {

final int i;

public void doSomething() {

System.out.println("i = "+ i);

}

}

       和上面一题只有一个地方不同,就是多了一个 final。这难道就错了吗?

       答案: 错。final int i 是个 final 的 instant variable (实例变量,或叫成员变量)。final 的 instant variable 没有 default value,必须在 constructor (构造器)结束之前被赋予一个明确的值。可以修改为"final int i =0;"。

       8.

public class Something {

public static void main(String[] args) {

Something s = new Something();

System.out.println("s.doSomething() returns " + doSomething());

}

public String doSomething() {

return "Do something ...";

}

}

       看上去很完美。

       答案: 错。看上去在 main 里 call doSomething 没有什么问题,毕竟两个 methods 都在同一个 class 里。但仔细看,main 是 static 的。static method 不能直接 call non-staticmethods。可改成 "System.out.println("s.doSomething() returns " + s.doSomething());"。同理,static method 不能访问 non-static instant variable。

       9.

       此处,Something 类的文件名叫 OtherThing.java

class Something {

private static void main(String[] something_to_do){

System.out.println("Dosomething ...");

}

}

       这个好像很明显。

       答案: 正确。从来没有人说过 Java 的 Class 名字必须和其文件名相同。但 public class 的名字必须和文件名相同。

       10.

interface A{

int x = 0;

}

class B{

int x =1;

}

class C extends B implements A {

public void pX(){

System.out.println(x);

}

public static void main(String[] args) {

new C().pX();

}

}

       答案:错误。在编译时会发生错误(错误描述不同的 JVM 有不同的信息,意思就是未明确的x 调用,两个 x 都匹配(就象在同时 import java.util 和 java.sql 两个包时直接声明 Date 一样) 。对于父类的变量,可以用 super.x 来明确,而接口的属性默认隐含为 public staticfinal.所以可以通过 A.x 来明确。

       11.

interface Playable {

void play();

}

interface Bounceable {

void play();

}

interface Rollable extends Playable, Bounceable {

Ball ball = new Ball("PingPang");

}

class Ball implements Rollable {

private String name;

public String getName() {

return name;

}

public Ball(String name) {

this.name =name;

}

public void play() {

ball = newBall("Football");

System.out.println(ball.getName());

}

}

       这个错误不容易发现。

       答案: 错。"interfaceRollable extends Playable, Bounceable"没有问题。interface 可继承多个 interfaces,所以这里没错。问题出在 interface Rollable 里的"Ball ball =new Ball("PingPang");"。任何在 interface 里声明的 interface variable (接口变量,也可称成员变量),默认为 public static final。也就是说"Ball ball = new
Ball("PingPang");"实际上是"public staticfinal Ball ball = new Ball("PingPang");"。在 Ball 类的 Play()方法中,"ball =newBall("Football");"改变了ball的reference, 而这里的ball来自Rollable interface, Rollable interface 里的 ball 是 public static final 的,final 的 object 是不能被改变 reference
的。因此编译器将在"ball = newBall("Football");"这里显示有错。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: