集合
1、试分析HashSet和TreeSet分别如何实现去重?
答:(1)HashSet的去重机制:hashCode() + equals()。底层先对对象进行hash运算得到一个hash值,
通过hash值得到table表中的索引,如果此时表中索引处没有元素,则直接加入。如果此时表中索引处存在元素,
那么进行 equals()比较,(equals()可以自己重写),如果比较不同,则将元素插入到该位置所对应的链表之后。
如果循环比较后相同,即table表索引处所对应的链表中有相同元素,那么就不加入
(2)TreeSet去重机制:如果在构造TreeSet时传入了一个comparator,则按照传入的comparator进行比较,
如果这个方法返回0,则认为存在相同的元素,就不添加。
如果在构造时没有传入comparator,就按照添加对象实现的Comparable接口的ComparabTo去重
2、下面代码运行会不会抛出一场,并从源码角度说明原因
TreeSet treeSet = new TreeSet();
treeset.add(new Person());
答:因为构造TreeSet时,没有传入Comparator函数,所以在底层
Comparable<? super K> k = (Comparable<? super K>) key;
即把Person对象转成Comparable类型
所以当Person实现了Comparable接口时,就不会报异常
如果PerSon没有实现这个接口,就会报ClassCastException
3、试写出ArrayList和Vector的比较
底层结构 版本 线程安全/效率 扩容倍数
ArrayList 可变数组 jdk1.2 不安全,效率高 如果使用无参构造:第一次扩容到10,后面按1.5倍扩容
Vector 可变数组 jdk1.0 安全,效率不高 如果使用无参构造:默认10,后面按2倍扩容
4、java的动态绑定机制是什么
(1)当调用对象的方法时,该方法会和对象的内存地址/运行类型绑定
(2)当调用对象的属性时,没有动态绑定机制,哪里声明,哪里使用
5、我们创建一个子类对象时,他们的静态代码块,静态属性初始化,
普通代码块,普通属性初始化,构造方法的调用顺序是什么
1. 父类的静态代码块和静态属性
2. 子类的静态代码块和静态属性
3. 父类的普通代码块和普通属性初始化
4. 父类的构造方法
5. 子类的普通代码块和普通属性初始化
6. 子类的构造方法
6、看下面代码,输出结果是什么?为什么
public void method1()
{
Integer i = new Integer(1);
Integer j = new Integer(1);
System.out.println(i == j);
//false
//因为i,j是两个不同的对象,i==j表示判断两者是否是同一对象,所以是false
Integer m = 1;//底层使用Integer.vlaueOf(1)
Integer n = 1;//底层使用Integer.vlaueOf(1)
System.out.println(m == n);
//true 下面放源码
//public static Integer valueOf(int i) {
//if (i >= Integer.IntegerCache.low && i <= Integer.IntegerCache.high)
// return Integer.IntegerCache.cache[i + (-Integer.IntegerCache.low)];
//return new Integer(i);
//其中
//static final int low = -128;
//而high的初始值为127,所以在(-128,127)范围内,不用创建新的Integer对象,因此m==n
}
Integer x = 128;
Integer y = 128;
System.out.println(x == y);
//false
//因为128不在(-128,127)范围内,所以x,y都是new出来的Integer对象
Integer k = 128;
int l = 128
System.out.println(k == l);
//true
//只要有基本数据类型,那么==判断的就是值是否相等
}