一:继承、抽象类与接口区别、访问控制(private, public, protected,默认)、多态相关 !1、interface和 abstract class的区别 interface是接口,abstract class是抽象类。 1,语法层次 抽象类中可以拥有任意范围的成员数据,可以定义非抽象方法。而接口中只能拥有静态的不能修改的成员数据,同时所有的方法必须是抽象的。 所以说接口是抽象类的一种特例。 2,跨域不同 a,抽象类是对类的整体进行抽象,包括类的属性和行为。接口是对类的局部(行为)进行抽象。 b,抽象类是is-a,跨域的是具有相似特点的类。接口是like-a,可以跨域不同的类。 例如猫、狗可以抽象一个动物类的抽象类,具备叫的方法。鸟、飞机可以实现Fly接口,具备飞的行为。 3,设计层次 抽象类是自下而上的一种设计思想,而接口是自顶而下的一种设计思想。 抽象类中我们要知道子类才能抽象出父类。而接口不同,它只需要定义一个规则即可。 !2、是否可以继承多个接口,是否可以继承多个抽象类 java可以实现多个接口,对于类是单继承体系结构。 %3、Static Nested Class 和 Inner Class的不同 静态内部类没有了指向外部的引用,可以直接被实例化而不需要依附与外部类的实例化。 非静态内部类保留了指向外部的引用,必须依附于外部类的实例化才能够实例化内部类。 静态嵌套类内部中:内部类不能访问外部类的非静态成员。外部类不能直接访问静态类中的属性,需要通过内部类去访问。 非静态内部类中:内部类可以直接访问外部类的属性成员。外部类不能直接访问静态类中的属性,需要通过内部类去访问。 延伸:使用内部类最吸引人的原因是:每个内部类都能独立地继承一个类,所以无论外围类是否已经继承某个类,对内部类都没有影响。 内部类:成员内部类(直接在外部类中)、局部内部类(内部类在方法或者作用域中)、嵌套内部类(static 修饰的内部类)、匿名内部类 这里需要说明一点:局部内部类和匿名内部类访问局部变量时为和需要加final关键字? 局部变量的生命周期与局部内部类的对象的生命周期的不一致性。例如内部类innerClass在方法f()中,而方法f()中定义局部变量i且被内部类使用。 当方法f()运行结束后,局部变量i就已经死亡不存在了,但局部内部类对象可能还存在(直道没有人再引用该对象才会消亡),这时出现一种情况就是 局部内部类要访问一个已经不存在的局部变量。而当变量被final修饰时,通过final将局部变量"复制"一份,复制品直接作为局部变量中的数据成员。 !4、Overload和Override的区别。Overloaded的方法是否可以改变返回值的类型? overload重载和override重写是Java多态性的不同表现。 overload是一个类多态性的表现,override是父类与之类多态性的不同表现。 override:子类中定义与父类相同的名称及签名. overload:方法相同方法签名不同。 注意:不能通过访问权限、返回类型、抛出的异常进行重载 !5、abstract的method是否可同时是static,是否可同时是native,是否可同时是synchronized static 修饰的方法不能够被重写。 !6、是否可以继承String类 不可以,String是被final修饰的类。
!7、构造器Constructor是否可被override? 构造器不能被继承,所以也不能够被重写。 !8、作用域public,protected,private,以及不写时的区别? 不写时默认是default,这里主要说明这几个作用域的使用范围。 作用域 当前类 同一package 子孙类 其他package public √ √ √ √ protected √ √ √ × friendly √ √ × × private √ × × × 这里需要说明的是在同一个package, public、protected、friendly使用范围一致。 而在其他package中,只有子孙类中protected才能被访问。 二:collections相关的数据结构及API http://cmsblogs.com/?p=106 !1、列举几个Java Collection类库中的常用类 此处应该有Collection类图。 Collection是java.util 中的一个接口。继承自Iterable。 子接口:List、Set、Queue... 实现类:ArrayList、LinkedList、HashSet、TreeSet、Vector、Stack 其他相关类:Iterator、TreeMap、HashTable、HashMap Collection接口是最基本的集合接口,它不提供直接的实现,Java SDK提供的类都是继承自Collection的"子接口" 如List和Set。Collection所代表的是一种规则,它所包含的元素都必须遵循一条或者多条规则。 如有些允许重复而有些则不能重复、有些必须要按照顺序插入而有些则是散列,有些支持排序但是有些则不支持。
!2、List、Set、Map是否都继承自Collection接口? List、Set继承自Collection接口,而Map不是。 (1)List 所代表的是有序的Collection。实现List接口的集合主要有:ArratList、LinkedList、Vector、Stack。 (2) Set是一种不包括重复元素的Collection。实现了Set接口的集合有:EnumSet、HashSet、TreeSet。 (3)Map与List、Set接口不同,它是由一系列键值对组成的集合,提供了key到Value的映射。同时它也没有继承Collection。 实现map的有:HashMap、TreeMap、HashTable、Properties、EnumMap。 !3、HashMap和Hashtable的区别 需查看源码。 1、历史原因:Hashtable是基于陈旧的Dictionary类的,HashMap是Java 1.2引进的Map接口的一个实现 。 2、同步性:Hashtable是线程安全的,也就是说是同步的,而HashMap是线程序不安全的,不是同步的 。 3、值:只有HashMap可以让你将空值作为一个表的条目的key或value 。 1.HashTable的方法是同步的,在方法的前面都有synchronized来同步,HashMap未经同步,所以在多线程场合要手动同步 2.HashTable不允许null值(key和value都不可以) ,HashMap允许null值(key和value都可以)。 3.HashTable有一个contains(Object value)功能和containsValue(Object value)功能一样。 4.HashTable使用Enumeration进行遍历,HashMap使用Iterator进行遍历。 5.HashTable中hash数组默认大小是11,增加的方式是 old*2+1。HashMap中hash数组的默认大小是16,而且一定是2的指数。 6.哈希值的使用不同,HashTable直接使用对象的hashCode,代码是这样的: int hash = key.hashCode(); int index = (hash & 0x7FFFFFFF) % tab.length; 而HashMap重新计算hash值,而且用与代替求模:
1 int hash = hash(k);
2 int i = indexFor(hash, table.length);
3 static int hash(Object x) {
4 h ^= (h >>> 20) ^ (h >>> 12);
5 return h ^ (h >>> 7) ^ (h >>> 4);
6 }
&&延展: A、HashMap与HashSet的关系 1、HashSet底层是采用HashMap实现的:
public HashSet() {
map = new HashMap<E,Object>();
}
2、调用HashSet的add方法时,实际上是向HashMap中增加了一行(key-value对),该行的key就是向HashSet增加的那个对象,该行的value就是一个Object类型的常量。
private static final Object PRESENT = new Object();
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
public boolean remove(Object o) {
return map.remove(o)==PRESENT;
}
B、HashMap 和 ConcurrentHashMap 的关系 关于这部分内容建议自己去翻翻源码,ConcurrentHashMap 也是一种线程安全的集合类,他和HashTable也是有区别的,主要区别就是加锁的粒度以及如何加锁,ConcurrentHashMap 的加锁粒度要比HashTable更细一点。将数据分成一段一段的存储,然后给每一段数据配一把锁,当一个线程占用锁访问其中一个段数据的时候,其他段的数据也能被其他线程访问。 %4、HashMap中是否任何对象都可以做为key,用户自定义对象做为key有没有什么要求? 用户自定义的对象当作key需要实现Map中的hashCode和Equals方法。 HashMap用可以的哈希值来存储和查找键值对。 当插入一个Entry时,HashMap会计算Entry Key 的哈希值。Map会根据这个哈希值把Entry插入到相应的位置。 查找时,HashMap通过计算Key的哈希值到特定的位置查找这个Entry。 如果我们在使用自定义对象做为Key时,我们需要保证当改变对象的状态的时候,不改变它的哈希值。 !5、Collection 和 Collections的区别 Collection 是一个接口,它是各种集合结构的父接口。 Collections是一个包装类,它包含有各种有关集合操作的静态方法。Collcetions不能被实例化,它的构造函数是私有的。 例如: sort():专门针对LIST进行排序,在实际开发中,我们确实经常需要对一个装有一些对象的LIST进行排序! min/max():如果,我们想取一个集合中的最小、最大值,如何快速的取到呢?上面的方法将帮我们实现。 reverse():如果,我们仅仅需要得到一个LIST的相反顺序! Shuffle():通过这个方法,将使得LIST中元素的顺序不可预测,即顺序是随机的,混排的。 synchronizedList():返回指定列表支持的同步(线程安全的)列表。 ... %6、其他的集合类:concurrenthashmap,treemap,treeset,linkedhashmap等。 (1)ConcurrentHashMap:http://www.cnblogs.com/ITtangtang/p/3948786.html (2)TreeMap: (3)TreeSet: (4)LinkedHashMap: 三:异常体系 !1、Error、Exception和RuntimeException的区别,作用又是什么?列举3个以上的RuntimeException Throwable是java语言中所有错误和异常的超类。它有两个子类:Error、Exception。 Error为错误的意思,是程序无法处理的,如OutOfMemoryErro、ThreadDeath等,出现这种情况你唯一能做的就是听之任之,交由JVM来处理,不过JVM在大多数情况下会选择中止线程。 Exception是程序可以处理的异常,分为CheckedException(受检异常),另一种是UncheckedException(不受检异常)。其中CheckExpection是发生在编译阶段,必须要使用try...catch(或者throws),否则编译不通过。 而UnceckedException发生在运行期,具有不确定性,主要是由程序的逻辑问题引起的,难以排查,我们一般需要纵观全局才能够发现这类的异常错误。所以在程序设计中我们需要认真考虑,尽量处理异常,即使产生了异常,也能尽量保证程序朝着有利方向发展。
!2、Java中的异常处理机制的简单原理和应用 (1)当Java程序违反了Java的语义规则时,Java虚拟机就会将发生的错误表示为一个异常。 违反语义规则包括2种情况: (a)一种是Java类库内置的语义检查。 (b)另一种情况就是Java允许程序员扩展这种语义检查,程序员可以创建自己的异常,并自由选择在何时用throw关键字引发异常。 (2)所有的异常都是java.lang.Throwable的子类。
!3、内存溢出和内存泄露 http://wade6.iteye.com/blog/1842907 内存溢出:指在指定大小的内存空间,写入了超出大小的数据,从而导致了内存益处。通俗地说,就是内存不够,没办法支持当前程序。 当发生内存益出时,程序将无法进行,强制终止。 内存泄露:指某个程序已不再执行,却始终占用着内存,不释放,从而消耗着资源,称其为内存泄露。 当发生内存泄露,那么可用内存会逐渐减少,从而降低性能。 (a)对于内存的溢出可能发生的情况,大概有几种: 1、在程序中存在死循环,或者循环过多,而产生了过多重复的对象的实例。 2、存在对象的引用,使用完后没有清除,导致Java虚拟机不能回收。 3、一次操作时,在内存中加载了大量的数据,原则上说,在java中,由于它的自动垃圾回收机制,出现内存溢出的可能性并不是很大。 (b)对于内存泄露可能发生的情况,大概有几种: 1、长生命周期的对象持有短生命周期的引用。 这是内存泄露最常见的场景,也是代码设计中经常出现的问题。 例如:在全局静态map中缓存局部变量,且没有清空操作,随着时间的推移,这个map会越来越大,造成内存泄露。
2、修改hashset中对象的参数值,且参数是计算哈希值的字段。 当一个对象被存储进HashSet集合中以后,就不能修改这个对象中的那些参与计算哈希值的字段,否则对象修改后的哈希值与最初存储进HashSet集合中时的哈希值就不同了,在这种情况下,即使在contains方法使用该对象的当前引用作为参数去HashSet集合中检索对象,也将返回找不到对象的结果,这也会导致无法从HashSet集合中删除当前对象,造成内存泄露。
3、机器的连接数和关闭时间设置。 长时间开启非常耗费资源的连接,也会造成内存泄露。
解决方案: 1、尽早释放无用对象的引用 2、使用字符串处理,避免使用String,应大量使用StringBuffer,每一个String对象都得独立占用内存一块区域 3、尽量少用静态变量,因为静态变量存放在永久代(方法区),永久代基本不参与垃圾回收 4、避免在循环中创建对象 5、开启大型文件或从数据库一次拿了太多的数据很容易造成内存溢出,所以在这些地方要大概计算一下数据量的最大值是多少,并且设定所需最小及最大的内存空间值。 四:其他 !1、String和StringBuffer、StringBuilder的区别 http://www.cnblogs.com/xudong-bupt/p/3961159.html 1,可变与不可变化性 String类中使用字符数组保存字符串,因为有final修饰,所以string是不可变的。 private final char value[]; 关于不可变性:http://www.hollischuang.com/archives/1230 StringBUilder和StringBuffer的公共父类是:AbstracStringBuilder类,在AbstracStringBu中也是使用字符数组保存字符串,可知这两种对象都是可变的。 char[] value; 2,是否多线程安全 String中对象是不可变得,也可以理解为常量,显然是线程安全的。 StringBuffer对方法加了同步锁或者对调用的方法加了同步锁,所以是线程安全的。 StringBuilder并没有对方法进行加同步锁,所以是非线程安全的。 !2、String s = “123”;这个语句有几个对象产生 创建了一个对象,将“123”存储到常量池中。 延展:String s = new String("abc")这个语句创建了几个对象? 这种题目主要就是为了考察程序员对字符串对象的常量池掌握与否。上述的语句中是创建了2个对象,第一个对象是”abc”字符串存储在常量池中,第二个对象在JAVA Heap中的 String 对象。 !3、reader和inputstream区别 首先要分清reader和inputstream,一个是读取字符流,一个是读取字节流。 InputStream是表示字节输入流的所有类的超类,Reader是用于读取字符流的抽象类 InputStream提供的是字节流的读取,而非文本读取,这是和Reader类的根本区别。 即用Reader读取出来的是char数组或者String ,使用InputStream读取出来的是byte数组。 http://blog.sina.com.cn/s/blog_6d3183b50101cri5.html
!4、==和equals的区别 1.基本数据类型,也称原始数据类型。byte,short,char,int,long,float,double,boolean 他们之间的比较,应用双等号(==),比较的是他们的值。 2.复合数据类型(类) 当他们用(==)进行比较的时候,比较的是他们在内存中的存放地址,所以,除非是同一个new出来的对象,他们的比较后的结果为true,否则比较后结果为false。 JAVA当中所有的类都是继承于Object这个基类的,在Object中的基类中定义了一个equals的方法,这个方法的初始行为是比较对象的内存地 址,但在一些类库当中这个方法被覆盖掉了,如String,Integer,Date在这些类当中equals有其自身的实现,而不再是比较类在堆内存中的存放地址了。 对于复合数据类型之间进行equals比较,在没有覆写equals方法的情况下,他们之间的比较还是基于他们在内存中的存放位置的地址值的,因为Object的equals方法也是用双等号(==)进行比较的,所以比较后的结果跟双等号(==)的结果相同。
对于String复写Object的equals方法,只是比较字符串值是否相等: String类中的equals()方法:
1 public boolean equals(Object anObject)
2 {
3 //如果是同一个对象
4 if (this == anObject)
5 {
6 return true;
7 }
8 //如果传递进来的参数是String类的实例
9 if (anObject instanceof String)
10 {
11 String anotherString = (String)anObject;
12 int n = count;//字符串长度
13 if (n == anotherString.count) //如果长度相等就进行比较
14 {
15 char v1[] = value;//取每一个位置的字符
16 char v2[] = anotherString.value;
17 int i = offset;
18 int j = anotherString.offset;
19 while (n-- != 0) //对于每一位置逐一比较
20 {
21 if (v1[i++] != v2[j++])
22 return false;
23 }
24 return true;
25 }
26 }
27 return false;
28 }
%5、hashCode的作用 http://www.cnblogs.com/dolphin0520/p/3681042.html 很多地方都会利用到hash表来提高查找效率。在Java的Object类中有一个方法: public native int hashCode(); hashCode方法的主要作用是为了配合基于散列的集合一起正常运行,这样的散列集合包括HashSet、HashMap以及HashTable。 考虑一种情况,当向集合中插入对象时,如何判别在集合中是否已经存在该对象了?(注意:集合中不允许重复的元素存在) 也许大多数人都会想到调用equals方法来逐个进行比较,这个方法确实可行。但是如果集合中已经存在一万条数据或者更多的数据,如果采用equals方法去逐一比较,效率必然是一个问题。此时hashCode方法的作用就体现出来了,当集合要添加新的对象时,先调用这个对象的hashCode方法,得到对应的hashcode值,实际上在HashMap的具体实现中会用一个table保存已经存进去的对象的hashcode值,如果table中没有该hashcode值,它就可以直接存进去,不用再进行任何比较了;如果存在该hashcode值, 就调用它的equals方法与新元素进行比较,相同的话就不存了,不相同就散列其它的地址,所以这里存在一个冲突解决的问题,这样一来实际调用equals方法的次数就大大降低了,说通俗一点:Java中的hashCode方法就是根据一定的规则将与对象相关的信息(比如对象的存储地址,对象的字段等)映射成一个数值,这个数值称作为散列值。
%6、hashCode和equals方法的关系 在有些情况下,程序设计者在设计一个类的时候为需要重写equals方法,比如String类,但是千万要注意,在重写equals方法的同时,必须重写hashCode方法。 也就是说对于两个对象,如果调用equals方法得到的结果为true,则两个对象的hashcode值必定相等; 如果equals方法得到的结果为false,则两个对象的hashcode值不一定不同; 如果两个对象的hashcode值不等,则equals方法得到的结果必定为false; 如果两个对象的hashcode值相等,则equals方法得到的结果未知。
?7、Object类中有哪些方法,列举3个以上(可以引导) 妈蛋,这个在我校招也是我参加的第一次面试时问到了,当时觉得怎么会问这么简单的问题,但是最后自己还是回答不全。 Object方法:equals()、toString()、finalize()、hashCode()、getClass()、clone()、wait()、notify()、notifyAll()
!8、char型变量中能不能存贮一个中文汉字?为什么? CHAR类型变量时能够定义成为一个中文的,因为java中以unicode编码,一个char占16个字节,所以放一个中文是没问题的。 char型变量是用来存储Unicode编码的字符的,unicode编码字符集中包含了汉字,所以,char型变量中当然可以存储汉字啦。不过,如果某个特殊的汉字没有被包含在unicode编码字符集中,那么,这个char型变量中就不能存储这个特殊汉字。补充说明:unicode编码占用两个字节,所以,char类型的变量也是占用两个字节。
%9、了解过哪些JDK8的新特性,举例描述下相应的特性? !10、Input/OutputStream和Reader/Writer有何区别?何为字符,何为字节? !11、如何在字符流和字节流之间转换? InputStreamReader是字节流向字符流的桥梁,它使用指定的charset读取字节并将其解码为字符。 OutputStreamWriter是字符流通向字节流的桥梁,它使用指定的charset将要写入流中的字符编码成字节,它使用的字符集可以由名称指定或显示给定,否则将接受默认的字符集: !12、启动一个线程是用run()还是start()? start()方法是启动(即开辟)一个线程的方法,因此线程的启动必须通过此方法, 而run()方法,只是Thread类的一个方法,它本身并不能开辟线程。 %13、海量数据查询、存储 !14、switch可以使用那些数据类型 A switch works with the byte, short, char, and int primitive data types. It also works with enumerated types (discussed in Enum Types), the String class, and a few special classes that wrap certain primitive types: Character, Byte, Short, and Integer (discussed in Numbers and Strings).
!15、多线程与死锁 实现多线程的几种方式: 继承Thread/实现Runnable接口。 所谓死锁: 是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。 %16、Java的四种引用 !17、序列化与反序列化 !18、自动装箱与拆箱 !19、正则表达式 五:JAVA开发工具、环境的使用 IDE、maven、svn/git、Linux、Firebug |