Java基础
1. i++
与++i
,在字节码中如何体现的
- i++ :先读取i的值,然后在将本地变量表中的i增加1
int b = a++
在字节码中的表现,假设a在本地变量表中的index是1,b的index是2iload_1
//先读取a的值,放入栈顶iinc 1 by 1
// iinc,修改本地变量的值,第一个1是变量在本地变量表中的的下标,后一个1是增加的值istore_2
// 将栈顶元素赋值给本地变量表中的第二个变量,也就是b
- ++i :先将本地变量表中的i值增加1,然后在读取i的值
int b = ++a
在字节码中的表现iinc 1 by 1
iload_1
istore_2
2. java的自动装箱与拆箱
- Java的自动装箱拆箱其实就是Java的语法糖,简化代码.实际上在编译阶段JVM已经自动将类型转换写入到了字节码中. 装箱时自动调用Integer.valueOf(int),拆箱时调用Integer.intValue()
Integer a = 6
在字节码中的表现,假设a在本地变量表中的index为1sipush 6
// 将int型6压入栈顶invokestatic #2 <java/lang/Integer.valueOf>
// 调用静态方法Integer.valueOf(6)astore_1
int b = a
在字节码中的表现,a的index为1,值为Integer类型的6,b的index为2aload_1
//将a压入栈顶invokevirtual #3 <java/lang/Integer.intValue>
// 调用实例方法a.intValue()astore_2
3. Object类中的equals和hashCode方法的作用?什么时候要重写hashCode?
- Object中的equals和hashCode方法
- equals:直接比较两个对象地址是否相同
- hashCode:native方法,根据对象地址算出一个hash值
- 为啥修改equals的时候要同时修改hashCode?
因为在使用散列表的情况下,比如HashMap,HashSet
会先根据hashCode来计算对象在散列表中的位置,
如果修改了equals的逻辑,但是没有修改hashCode,就可能造成错误.
比方说现在有个Ball类,它有个color属性,我们重写了equals方法,只要color相同就行,我们将各种颜色的球都放入HashSet中,要求如果HashSet中不能有相同颜色的球.
如果没有重写hashCode方法,那么hashCode返回的是对象内存地址相关的值,不同的对象肯定不相同
HashMap在put时,会根据hash值算出它在table中的index,如果当前table的index位置没有数据,就直接放入,如果有数据,依次遍历这些数据,判断原有数据是否等于要put的对象,如果等于的话,根据需要替换对象或者不替换.
关键就在这个判断原有数据是否等于要加入的数据:
hashMap中先判断两个数据的hash值是否相同,如果不相同,就认为这两个对象不相同
只有hash值相同了,才会去调用equals看是否相同.
p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k)))
p表示hashMap中现有的数据,
首先判断要put的数据的hash值是否等于现有的数据,如果不等于,就认为put数据和原有数据不相等.
- HashMap中对hashCode的运用:
在HashMap内部维护了一个table数组,
对象通过一定的hash算法确定在table中的index
如何获得对象放入HashMap中table的index:
1, 调用自身的hashCode
获取一个hash值
2,hash ^ (hash>>>16)
获取对象在HashMap中的hash值
3,index = (length-1) & hash
通常HashMap长度不会很大,使用(length-1) & hash获取到index的时候,
大多只有hash低位的在参与运算,决定index的值,
而通过第2步,hash值与自身右移16位后亦或,将hash值的高位信息融入到低位,
这样就能减小hash冲突的概率
3-1. Runnable和Callable接口
- 实现方法:
- Runnable需要实现
public abstract void run();
- Callable需要实现
V call() throws Exception;
- Runnable需要实现
- 相同之处:
- Runnable和Callable都是接口,都是为了要执行某一任务
- 不同之处:
- call方法有返回值,而run没有返回值
- call方法能够抛出checked exception,而run不行
- Callable和Runnable都可以用于Executors,而Thread类只支持Runnable
- Future接口,一般都是取回Callable执行状态用的,主要方法有:
- cancel,取消Callable的执行,当Callable还没有完成时
- get,获取Callable的返回值
- isCancled,判断是否取消了
- isDone,判断是否完成
- Future接口,一般都是取回Callable执行状态用的,主要方法有: