Java面试宝典
从2013年9月开始找工作,在几个月的Java程序员求职过程中,总结了一些被问到的笔试题和面试题。Java语言博大精深,是整个程序界的上乘语言,应该得到重视。
###1. Java标识符,命名规范?
- 不能以数字开头;rake post title=”hello world” category=”life” date=”2013-04-21” tags=”” description=”description”
- 区分大小写;
- 不能有@、‘-‘(运算符);
- 可以出现中文;
- java关键字不能做为变量名;
###2. Java基本类型及其范围
基本类型 | 大小 | 最小值 | 最大值 | 包装器 | 默认值 | 说明 |
boolean | - | - | - | Boolean | false | 没有大小 |
char | 16bits | Unicode 0 | Unicode 216-1 | Character | \u0000‘ ‘ | 可以用来表示中文 |
byte | 8bits | -128 | 127 | Byte | 0 | 与C++中的char相同 |
short | 16bits | -215 | 215-1 | Short | 0 | |
int | 32bits | -231 | 231-1 | Integer | 0 | |
long | 64bits | -263 | 263-1 | Long | 0 | |
float | 32bits | IEEE754 | IEEE754 | Float | 0.0 | 指数8位 |
double | 64bits | IEEE754 | IEEE754 | Double | 0.0 | 指数16位 |
void | - | - | - | Void | null | Void可以定义变量 |
###3. Java中变量的初始化
- 局部变量必须初始化,如果没有初始化而使用,会编译错误。数组会自动初始化;
- 类中的变量可以在调用构造函数的时候自动初始化,且有默认值;
- Java对于变量初始化赋值很严格,float f = 0.0(0.0为double类型),这在C++中是会有警告,而在Java中是编译不过的。
###4. Java操作有优先级?
优先级 | 运算符 | 结合性 |
1 | () [] . | 从左到右 |
2 | ! +(正) -(负) ~ ++ -- | 从右向左 |
3 | * / % | 从左向右 |
4 | +(加) -(减) | 从左向右 |
5 | << >> >>> | 从左向右 |
6 | < <= > >= instanceof | 从左向右 |
7 | == != | 从左向右 |
8 | &(按位与) | 从左向右 |
9 | ^ | 从左向右 |
10 | | | 从左向右 |
11 | && | 从左向右 |
12 | || | 从左向右 |
13 | ?: | 从右向左 |
14 | = += -= *= /= %= &= |= ^= ~= <<= >>= >>>= | 从右向左 |
###5. 自加++、自减–操作符
- 前缀操作,可以理解为先加再赋值,后缀操作是先赋值再加;
- 如果为后缀自加,加的操作在该语句执行结束后执行;
-
当有多种可以解析的情况下,如下,可以解析成test1+(++test2)或者test1++ + test2,会从左至右就近的匹配。test3是1而不是2。
int test1 = 0; int test2 = 1; int test3 = test1+++test2;
###6. 负数如何进行取模运算? 对于负数,先对其绝对值取模,再加上符号。
###7. 是什么操作符?
- Java中新增了一种操作符,无符号右移»>,无论正负数,高位都是补0;
- 有符号右移»,正数时高位补0,负数时高位补1(1是符号位);
- 移位运算符可以高效的实现与2的倍数的乘除法。
###8. &与&&的区别?
- &是按位与运算,也可以进行boolean运算;
- 与&&的区别是,&&可以进行短路求值。
###9. 8 | 9 & 10 ^ 11的运算结果? | |
、&、^操作符的优先顺序是&、^、 | ,首先9(1001)&10(1010)=8(1000) ,然后8(1000)^11(1011)=3 ,最后(0011)8(1000)|3(0011)=11(1011) 。 |
###10. 下面代码的输出是什么?
int n = 7;
n <<= 3;
n = n & n + 1 | n + 2 ^ n + 3;
n >>= 2;
System.out.println(n); n向左移3位,相当于乘以8,得到56。+的优先级高于按位操作符的优先级,先进行加法,变成`56&57|58^59`,剩下的操作与9题类似,得到14。
###11. 下面代码的执行结果是什么?
x = 5;
y = 3;
int z = x + (x++) + (++x) + y; 根据优先级,要先执行x++,x后加,先赋值5,最后再加,现在还不加;然后执行++x,先加,再赋值,此时x为6。注意,此时第一个x也是6,这是比较容易出错的地方。最后再加y,6+5+6+3=20。
###12. equals()和==的区别?
==
是二元运算符,在判断基本数据类型的时候,是判断其值,值相等则为true;在判断引用对象的时候,是判断其内存地址,是同一个变量则为true;- equals()是Object的一个函数,默认通过hashCode()来判断时候相等,而hashCode()是通过计算引用对象的内存地址得到的。可以重写这两个函数来判断两个引用对象的内容是否相等;
==
用于判断原生类型(primitive)相等,equals()用于判断对象的相等。
###13. 描述一下Java中的参数传递?
- 对于基本类型,Java采用按值传递,参数的值是不能够修改的;
- 而如果传递的是对象的引用,则会按引用传递。这个也不矛盾,如果是对象的引用,可以理解成是传递的是对象的地址,这个地址是按值传递的,我们不能修改,而这个地址的对象,我们是可以修改的,这和C++中的是一样的。
###14. 如何获得数组的长度?
int arr[] = new int[4];
arr.length;
###15. private和protected是否可以是class的访问修饰符?
- 不能。class只支持public和friendly(不写,默认的)访问修饰符,其余的都不支持;
- 一个.java文件中最多只能有一个public类,作为该文件对外的接口,且该类要与文件名相同(一个文件中可以有多个类);
- 如果想定义成private那样的类,可以将其构造函数定义成private的访问权限,也可达到目的。
###16. final、finally、finalize的区别?
- final用来定义常量,使其初始化之后不能修改。定义函数,使其在继承类中不能被覆盖,也能实现内嵌调用,从而提高效率。定义类,该类则不能被继承,例如String;
- finally是try/catch块之后执行且总是被执行,会在return之前被调用;
- finalize()是Object中的一个方法,释放内存时会被调用,可以覆盖该函数来实现内存的释放。
###17. Java访问修饰符?
当前类 | 当前包 | 继承类 | 其他包 | |
public | √ | √ | √ | √ |
protected | √ | √ | √ | × |
包访问权限(friendly) | √ | √ | × | × |
private | √ | × | × | × |
###18. 下面代码的执行结果是什么?
class AA extends BB {
private int radius = 1;
public void draw() {
System.out.println("A.draw(),radius=" + radius);
}
public AA(int radius) {
this.radius = radius;
System.out.println("A constructor");
}
}
class BB {
private int radius = 10;
public void draw() {
System.out.println("B.draw(),radius=" + radius);
}
public BB() {
System.out.println("B constructor");
draw();
}
public BB(int radius) {
System.out.println("B constructor with parameter");
draw();
}
}
B constructor
A.draw(),radius=1
A constructor 调用构造函数的一般顺序:
- 父类的静态变量初始化;
- 子类的静态变量初始化;
- 父类的非静态变量初始化;
- 父类的静态代码块初始化(只在声明的时候初始化);
- 父类的非静态代码块初始化;
- 父类的无参数构造函数初始化;
- 子类的非静态变量初始化;
- 子类的静态代码块初始化;
- 子类的非静态代码块初始化;
- 子类被调用的构造函数初始化。
此题中,先调用父类的无参数构造函数,输出B constructor,再调用draw函数,draw是自己的draw函数(draw函数被覆盖)。
###19. 下面语句有什么问题?
if (x) {
x = 0;
} Java中的if条件表达式只支持boolean类型,这不同于C++中还可以支持整型。
###20. 可以用于switch条件表达式的类型是什么?
- switch支持整型表达式,默认支持int;
- byte、char、short可以自动向下转换,不会造成数据丢失,所以也可以使用;
- long、float、double转换成int时会丢失数据,不能使用。
- Java 7之后,switch开始支持字符串String。
###21. 下列代码的执行结果是什么?
int i = 10, j = 18, k = 30;
switch(j - i) {
case 8: System.out.println(++k);
case 9: System.out.println(k+=3);
case 10: System.out.println(k<<=1);
default: System.out.println(k/=j);
} 如果匹配到case,从该case开始执行,直到遇到break为止。该题目中,四个语句都执行过,++k得到31,k+=3得到34,k乘以2得到68,再除以18得到3(小数部分抹掉)。
###22. Throwable的子类是哪两个?
- Error
- Exception
###23. 下面代码的输出结果是什么?
try {
String a = null;
a.length();
} catch(nullPointerException e) {
System.out.println("NullPointerException");
} catch(Exception e) {
System.out.println("Exception");
} finally {
System.out.println("finally");
} 会输出NullPointerException和finally,并列的多个catch,要先写子类,再写父类,匹配到一个catch后,不再匹配,执行finally语句。
**补充一点: **处理异常的机制是为了保证程序正常的运行。比如,一段代码用来处理一段文本,当文本格式发生变化之后,可以修改代码,增加if
等判断语句;也可以之前就增加catch
语句,一开始就能提供默认处理方式。
###24. throw和throws的区别?
- throws定义函数,声明这个方法会抛出这种类型的异常,使其他地方调用它时知道要捕获这个异常。使用try/catch来捕获;
- throw是具体向外抛异常的动作,所以它一定会抛出一个异常实例。
###25. Java支持多继承么? Java默认只支持单继承extends,C++中的多继承对于继承的概念不是很严谨,因为继承多个对象无法确定该对象到底是属于哪个类型。而Java又提供了接口,可以被实现implements,一个类可以实现多个接口。这也是实现多继承的一种方式,而且也符合继承的概念,一个类只能有一个父类,这样不会造成混乱,实现多个接口,又能增加其他类中才有的功能。
###26. 什么是重载?
- 对于同一个动作,可以有不同的执行方法,这时就需要重载;
- 重载函数名必须相同;
- 参数表必须不同,只能通过参数表来区别重载函数;
- 返回值不能用来区别重载函数。如果只有返回值不同,由于返回值可以转换类型,所以不能用来区别重载函数。
###27. 什么是重写?
- 在继承关系中,子类可以重写继承到的父类的函数,来定义自己的功能实现;
- 重写的函数,函数名,返回值,参数表必须完全相同;
- 子类重写的函数的访问修饰符不能比父类的小;
- 子类重写的函数抛出的异常不能比父类的多。
###28. 下面代码的执行结果是什么?
public class Parent{
public int x;
public int y;
public Parent(int x, int y) {
this.x = x;
this.y = y;
}
public void increaseX(int x) {
this.x = getX() + x;
}
public int getX() {
return x;
}
public void increaseY(int y) {
this.y = getY() + y;
}
public int getY() {
return y;
}
}
public class Child extends Parent {
private int x;
private int y;
public Child(int x, int y) {
super(x, y);
this.y = y + 250;
this.x = x + 150;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
}
Child child = new Child(50, 50);
child.increaseX(100);
child.increaseY(100); x和y结果分别是200和300。在重写当中,具体还可以分为覆盖和隐藏。对于函数,子类中重写的函数会覆盖掉父类的函数,而对于变量,子类中重写的变量将会隐藏掉父类的变量。在new Child(50, 50)的时候,调用父类的带参数构造函数,在这里对x和y赋值,x和y是父类的x和y,不会影响到子类的x和y。接着this.y = y + 250,这里修改的是子类的x和y,得到200和300。接着执行increaseX和increaseY,子类并没有定义这两个函数,调用的是父类的这两个函数,而调用的时候修改的是父类中x和y的值,不会影响到子类的结果。
###29. 下列代码插入标记处不会编译出错的是哪一个?
class MyTest extends Test {
int count;
public MyTest(int cnt, int num) {
super(num);
count = cnt;
}
// insert code here
}
public class Test {
int number;
public Test(int i) {
number = i;
}
} + MyTest() {} + MyTest(int cnt) {count = cnt} + MyTest(int cnt) {super(); count = cnt;} + MyTest(int cnt) {count = cnt; super(cnt);} + MyTest(int cnt) {this(cnt, cnt);} + MyTest(int cnt) {super(cnt); this(cnt, 0)}
首先,Java中子类的构造函数会默认有一句super(),来调用父类的构造函数,该语句可以省略。该语句需要放在构造函数第一行; Java中this()也可以用在构造函数的第一行,用来调用本类的其他构造函数。this()和super()不能同时使用; 如果为super增加参数,那可以调用父类对应带参数的构造函数; 如果父类不定义构造函数,会自动为其分配一个不带参数的构造函数。如果父类定义了构造函数,那么将不再会自动分配。也就是说,定义了一个带参数的构造函数,那么该类就没有不带参数的构造函数了; 上题中,A、B、C、都显示或隐式地调用了super()函数,而父类没有定义不带参数的构造函数。D中super不在第一行。F同时使用了super和this。答案为E。
###30. Java是否可以手动释放内存? Java提供了一个方法,System.gc(),建议Java虚拟机去释放内存,当JVM决定去释放内存是,会调用该对象的finalize()方法。Java中申请内存由程序员实现,内存会申请到堆中,释放内存由GC实现。
###31. Java是否会出现内存泄漏?
GC会自动回收垃圾,GC采用有向图的方法,一般情况下,如果一个对象没有被引用,则该对象所占的内存将会被释放。例如,o2=o1后,o2原本引用的内存将会被释放;
Vector v = new Vector(10);
for (int i=1;i<100; i++)
{
Object o=new Object();
v.add(o);
o=null;
} 但是当一个对象没有被引用,但是在有向图中又是可达的,而且又没有用处,那么此时就发生了内存泄漏。o=null后,由于之前指向的内存可以从v可达,那么该部分内存将不可被释放,知道v=null或v的内存释放为止。
###32. Thread的五个状态?
- 创建状态
- 就绪状态
- 运行状态
- 阻塞状态
- 死亡状态
###33. Thread中run()和start()的区别?
- start()会立刻返回。调用start()方法,会创建一个线程,处于就绪状态,调用run()方法运行线程体,运行结束后,该线程结束;
- run()就是一个方法,不会创建新线程。
###34. Thread中run()和start()的区别?
- start()会立刻返回。调用start()方法,会创建一个线程,处于就绪状态,调用run()方法运行线程体,运行结束后,该线程结束;
- run()就是一个方法,不会创建新线程。
###35. synchronized和java.util.concurrent.Locks.Lock的区别? synchronized可以作用域函数,代码块,静态函数中。在函数中使用,以当前实例为锁,表示当前实例this在不同的线程中要互斥访问。在代码块中使用,要为synchronized增加参数,要以对象为锁,互斥访问,如果以this同步,和之前的以函数同步含义相同。也可以指定对象来同步。如果同步的是静态函数,函数调用的时候可能还没有实例,不能使用this,可以使用Foo.class作为锁。
Public synchronized void method(){
//......
}
public void method()
{
synchronized (this)
{
//......
}
}
public void method(SomeObject so) {
synchronized(so)
{
//......
}
} + 所有对象都自动含有单一的锁。 JVM负责跟踪对象被加锁的次数。如果一个对象被解锁,其计数变为0。在任务(线程)第一次给对象加锁的时候,计数变为1。每当这个相同的任务(线程)在此对象上获得锁时,计数会递增。 只有首先获得锁的任务(线程)才能继续获取该对象上的多个锁。 + Lock有比Synchronized更精确的线程域城予以和更好的性能。Synchronized会自动释放锁,但是Lock一定要求程序员手工释放,并且必须在finally从句中释放。
###36. wait()、notify()、notifyAll()的作用?
- 这三个方法最终调用的都是jvm级的native方法。随着jvm运行平台的不同可能有些许差异。
- 如果对象调用了wait方法就会使持有该对象的线程把该对象的控制权交出去,然后处于等待状态。
- 如果对象调用了notify方法就会通知某个正在等待这个对象的控制权的线程可以继续运行。
- 如果对象调用了notifyAll方法就会通知所有等待这个对象控制权的线程继续运行。
Java面试中也会常常去问对于Java包源码的理解。下面按照根据Java包来介绍。 java.lang包,Java的基础包,编译时会自动导入,主要包含Java基类Object,包装类Boolean、Character、Byte、Short、Integer、Long、Float、Double,Enum,String、StringBuffer、StringBuilder,Thread,Process,Math,Throwable,Error,Exception。
###37. java.lang.Object
方法 | 说明 |
public final native Class<?> getClass(); | 返回一个对象的运行时类 |
public native int hashCode(); | 返回该对象的哈希码值,将对象在内存中的地址转成int并返回 |
public boolean equals(Object obj) { return (this == obj); } | 指示某个其他对象是否与此对象“相等”。默认使用==来判断引用对象的地址。 |
protected native Object clone() throws CloneNotSupportedException; | 创建并返回此对象的一个副本。该对象要实现Cloneable接口,否则会抛出CloneNotSupportedException异常 |
public String toString() { return getClass().getName() + "@" + Integer.toHexString(hashCode()); } | 返回该对象的字符串表示,用hashCode()辅助实现 |
public final native void notify(); | 唤醒在此对象监视器上等待的单个线程 |
public final native void notifyAll(); | 唤醒在此对象监视器上等待的所有线程 |
public final native void wait(long timeout) throws InterruptedException; | 导致当前的线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者超过指定的时间量 |
public final void wait(long timeout, int nanos) throws InterruptedException | 导致当前的线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者其他某个线程中断当前线程,或者已超过某个实际时间量 |
public final void wait() throws InterruptedException { wait(0); } | 导致当前的线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法 |
protected void finalize() throws Throwable { } | 当垃圾回收器确定不存在对该对象的更多引用时,由对象的垃圾回收器调用此方法 |
###38. java.lang.Math Math是一个final类,不能被继承,提供了一套静态方法,实现数字计算的常见功能。
方法 | 说明 |
public static double ceil(double a) { return StrictMath.ceil(a); // default impl. delegates to StrictMath } | 向上取整 |
public static double floor(double a) { return StrictMath.floor(a); // default impl. delegates to StrictMath } | 向下取整 |
public static int round(float a) { if (a != 0x1.fffffep-2f) // greatest float value less than 0.5 return (int)floor(a + 0.5f); else return 0; } | 加0.5后向下取整。 ceil和floor返回的都是double,round返回的是int和long |
###39. java.lang.String String是一个final类,不可以被继承。Java里是没有运算符重载的,String+是StringBuffer的append()方法来实现的,如:String str = new String(“abc”);编译时等效于String str = new StringBuffer().append(“a”).append(“b”).append(“c”).toString();
类方法或变量 | 说明 |
private final char value[]; | String是封装的字符数组,而且被定义成final类型,一经赋值,不能修改 |
private int hash; | 默认为0,hashCode()的返回值 |
public String() { this.value = new char[0]; } | |
public String(String original) { this.value = original.value; this.hash = original.hash; } | |
public String(char value[]) { this.value = Arrays.copyOf(value, value.length); } | |
public String(char value[], int offset, int count); | 根据字符数组一部分对象创建字符串对象 |
public String(int[] codePoints, int offset, int count); | |
public int length() { return value.length; } | 返回字符数组长度 |
public char charAt(int index) { if ((index < 0) || (index >= value.length)) { throw new StringIndexOutOfBoundsException(index); } return value[index]; } | |
public boolean equals(Object anObject); | 根据字符数组逐个比较 |
public int compareTo(String anotherString); | 相同返回0,当前字符串大,返回整数;小,返回负数 |
public int indexOf(int ch) { return indexOf(ch, 0); } | 返回字符ch首先出现的位置,没有返回-1 |
public String substring(int beginIndex, int endIndex); | 通过索引和value,创建一个新的String并返回。不包括endIndex所指的字符。 Java 6之前,String类内部还有两个成员变量count和offset,当调用substring并返回时,同样还是引用的同一个字符数组,只是改变了count和offset。当你有一个非常长的字符串,而你只是想保留其中的一小部分,Java 6会一直保存着整个字符串,这样会造成性能问题。解决的方法是x = x.substring(i, j) + “”; Java 7会帮你new一个新的字符串并只保留substring要用到的字符。 |
public String concat(String str); | 创建一个新的字符数组,将当前字符数组和str的都放到该数组中,用这个数组创建一个新的String并返回 |
public String replace(char oldChar, char newChar); | 用newChar替换所有当前字符串中oldChar并创建一个新String返回 |
###40. java.lang.StringBuilder StringBuilder是可变长字符串,是Java 5.0新增的,之前的是StringBuffer,相比于StringBuffer,StringBuilder是线程不安全的,但性能得到提升。这两个类的接口是保持一致的。Java 5.0之后,字符串+操作符采用StringBuilder实现
类变量或方法 | 说明 |
char[] value; | AbstractStringBuilder类中,可以返回capacity |
int count; | AbstractStringBuilder类中 |
public StringBuilder(String str) { super(str.length() + 16); append(str); } | 默认空的StringBuilder的capacity为16,以String初始化的capacity为String的长度加16 |
public StringBuilder append(String str) { super.append(str); return this; } | |
public StringBuilder delete(int start, int end) { super.delete(start, end); return this; } | |
public StringBuilder insert(int index, char[] str, int offset, int len) { super.insert(index, str, offset, len); return this; } | |
public int length() { return count; } | |
public int capacity() { return value.length; } | capacity与length不同,length()个返回保存的字符串长度,capacity()返回申请的字符数组大小 |
public void setLength(int newLength) |
###41. 包装类java.lang.Integer
public final class Integer extends Number implements Comparable<Integer>
类变量或方法 | 说明 |
public static final int MIN_VALUE = 0x80000000; | |
public static final int MAX_VALUE = 0x7fffffff; | |
public static int parseInt(String s, int radix) throws NumberFormatException | |
public static int reverse(int i) |
java.util包包含Date,容器类Collection,日历Calendar,随机数Random。其中,容器类是常见的面试内容。 集合类主要分类两大类,Collection和Map。Collection允许有重复对象。继承Collection的有List、Set、Vector、Stack接口。List要求有序,可以有重复元素。Set表示集合,无序,但不能有重复元素。
###42. java.util.Collection Collection接口中常见操作
接口变量或方法 | 说明 |
int size(); | |
boolean isEmpty() | 判断集合时候有任何元素 |
boolean contains(Object o); | |
Iterator iterator() | 返回迭代器,用来访问各个元素 |
boolean add(E e); | 在最后增加元素e |
boolean remove(Object o); | 从当前List中删除第一次出现的元素o |
boolean containsAll(Collection c) | |
boolean addAll(Collection c) | |
void clear(); | 删除所有元素 |
void removeAll(Collection c) | |
void retainAll(Collection c) | 从集合中删除集合c中不包含的元素 |
boolean equals(Object o); | |
int hashCode(); | |
Object[] toArray() | 返回含集合所有元素的数组 |
Object[] toArray(Object[] a) | 返回含集合所有元素的数组,返回的数组与参数a的类型相同 |
###43. java.util.List
接口变量或方法 | 说明 |
E get(int index); | 获得指定位置的元素 |
E set(int index, E element); | 将指定位置的元素替换为element |
List<E> subList(int fromIndex, int toIndex); | 不包括toIndex指定的元素 |
List有两个实现类,ArrayList和LinkedList,都是线程不安全的。LinkedList使用双向链表实现,保存头结点first和尾结点last。ArrayList使用动态数组实现,默认容量为10,每当容量不够的时候,就要重新申请新的内存,并将之前的内容复制进来。
int newCapacity = oldCapacity + (oldCapacity » 1);
申请的内存是之前的1.5倍。ArrayList可以随机访问,但是增加和删除消耗大,每次这样的操作都要移动其余的元素。而LinkedList按索引访问时要按照指针一次遍历,访问消耗大。
然而,如果每次插入和删除都是在队列尾部,ArrayList效率要高,因为不需要移动元素。
Vector同样实现的是List接口,是一个重量级列表,线程安全的。也是采用动态数组实现,每次动态分配的内存和ArrayList不同,默认是2倍。
int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
capacityIncrement : oldCapacity);
###43. java.util.Set Set不存在重复的元素,依靠equals()来检测独一性。与Collection有着完全一样的接口,根据值来确定。
- HashSet。实现了SortedSet接口。其对快速查找进行了优化。存入的元素必须定义hashCode()。
- TreeSet。底层为树结构。可以从Set中提取有序的序列。元素必须实现Comparable接口。
- LinkedHashSet。具有HashSet的查询速度,内部使用链表维护元素的顺序(插入的顺序),使用迭代器遍历Set时,会按照插入的顺序显示。存入的元素必须实现hashCode()方法。
###44. java.util.Iterator List可以通过get来遍历整个链表,但是对于其他的数据接口,这些遍历方法将不能通用。所以使用Iterator接口来封装遍历操作,使遍历所有的集合,都能有一个共同的接口。
接口变量或方法 | 说明 |
boolean hasNext(); | |
E next(); | 将指定位置的元素替换为element |
void remove(); | 删除上一次iterator返回的元素 |
###45. java.util.Map Map中不允许有重复的key。
接口变量或方法 | 说明 |
Object put(Object key, Object value); | |
Object remove(Object key); | 根据key删除元素 |
void putAll(Map m); | 将m中所有元素存入当前map |
void clear(); | |
Object get(Object key); | 根据key获得元素 |
int size(); | |
boolean isEmpty(); | |
boolean containsKey(Object key); | 检测是否有指定key的对象 |
boolean containsValue(Object value); | 检测是否有指定value的对象 |
boolean equals(Object o); | |
Set<K> keySet(); | 返回一个Set,里面保存map中所有的key |
Collection<V> values(); | 返回一个Collection,保存map中的所有value |
Set<Map.Entry<K, V>> entrySet(); | 返回一个Set,保存所有mappings |
interface Entry<K,V> | 存储单个键/值对 |
HashMap。Java 2.0引入,是非同步的,但是提高了性能。基于散列表实现,解决哈希冲突使用链接法。 HashMap哈希的方法,是将key的hashCode与key的总数求余,得到哈希的索引。如果key是常量,则有可能相同,即使不同,与key的总数求余也有可能有哈希冲突。HashMap使用链接法解决冲突。
int hash = key.hashCode();
int index = hash % Entity[].length;
Entity[index] = value; ![Hash](https://res.cloudinary.com/cyeam/image/upload/v1537933530/cyeam/javacollection_hash.png)
public V put(K key, V value) {
if (table == EMPTY_TABLE) {
inflateTable(threshold);
}
if (key == null)
return putForNullKey(value);
int hash = hash(key);
int i = indexFor(hash, table.length);
for (Entry<K,V> e = table[i]; e != null; e = e.next) {
Object k;
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
}
modCount++;
addEntry(hash, key, value, i);
return null;
} + Hashtable是Dictionary的子类,是同步的。 + TreeMap。采用红黑树实现,可以获得字数subTree()。
###47. java.io Java IO采用Decorator模式,可以动态装配不同功能的Stream。IO体系分Input/Output和Reader/Writer两类,区别在于Reader/Writer读写文本时自动转换内码。 System.out是PrintStream的一个子类,PrintStream继承了FilterOutputStream类,FilterOutputStream类继承了OutputStream类。
###48. Servlet生命周期
- 装载Servlet。
- 创建Servlet实例。
- 调用Servlet的init()方法。Servlet只初始化一次。
- 当一个客户端请求到达后,创建一个request对象和一个response对象。
- 调用service()方法,处理数据,并将结果返回客户端。
- 当服务器不再需要Servlet时,调用destroy()方法。
###49. Servlet的转发和重定向 javax.servlet.RequestDispatcher的forward方法 javax.servlet.http.HttpServletResponse的sendRedirect(String)方法
原文链接:Java面试宝典,转载请注明来源!
–EOF–