public static void main(String[] args) {
Integer a = 128, b = 128, c = 127, d = 127;
System.out.println(a == b);
System.out.println(c == d);
}
返回false、true:因为Integer会构建一个缓冲区,大小为(-128-127)在这个缓冲区内,相等的数字会被赋给缓冲区内的对象,这个范围以外的数字会创建新的对象
数据分为两种数据类型,一是存放在栈中的基本数据类型,二是对于对象的引用地址(真实对象存放在堆中)
浅拷贝:对于基础数据类型直接复制其数据值;对于引用数据类型,则直接复制其引用地址,也就是说,修改浅拷贝来的引用数据会更改原本的文件
深拷贝:对于基本数据类型来说,直接复制其数值,对于引用数据类型来说,开辟新的内存空间来复制一个一模一样的对象,修改其中之一不会相互影响。
Java中只有值传递,只不过在传递对象时,传递的值的内容是对象的引用
下面程序的运行结果:
public class InitialTest {
public static void main(String[] args) {
A ab = new B();
ab = new B();
}
}
class A {
static { // 父类静态代码块
System.out.print("A");
}
public A() { // 父类构造器
System.out.print("a");
}
}
class B extends A {
static { // 子类静态代码块
System.out.print("B");
}
public B() { // 子类构造器
System.out.print("b");
}
}
父类静态变量 -> 子类静态变量 ->父类构造器 ->子类构造器
抽象类只能单继承,接口可以多实现
抽象类中可以有构造方法
抽象类中可以有成员变量和常量,接口中只有常量
思想上:
接口是对于行为的规范,即我需要这个行为,但这个行为具体怎么做需要具体的实现类来实现。
抽象类是对于某些类似行为的抽象,其提供了对某一类行为的通用实现,而如果存在具体差异,我们也可以提供抽象方法来支持自定义的实现。
Error和Exception都是Throwable的子类,都表示程序出现了不正常的情况
Error代表系统级的错误,不能通过设计来解决,Exception代表设计或实现问题,应该是程序正常运行情况下不会遇到的问题
避免死锁就是破坏上面的四个条件之一
线程工厂:用于创建工作线程
核心线程数:线程池要保持的线程的最小数量,如果线程池中的线程数小于这个数量,就会进行创建
最大线程数:允许的最大的线程数量
保持存活时间:线程空闲且超过核心线程数时会将多余的线程终止
队列:用于保留任务并移交给线程的阻塞队列
ArrayList和Vector几乎一致,Vector使用Synchronized线程安全
包括HashMap和HashTable也是这样的关系
HashMap在JDK1.8时将底层实现由数组+链表转为数组+链表+红黑树
当一个节点中的冲突情况超过8个时,冲突就会由链表转为红黑树。但如果此时数组内容少于64时,会优先将数组扩容
红黑树的节点定义为红色或者黑色,
根节点为黑色,
所有的叶子结点都是黑色
每个红色节点都必须有两个黑色的结点
从任意结点到其每个叶子都必须有相同数目的黑色节点(黑高)
HshTable -> 线程安全的HashMap
Cocurrent HashMap -> 线程安全的HashMap,同时还能保证一定的效率
CocurrentHashMap会将一个个的HashEntry组合起来形成一个个的Segment,而Synchronized会将锁加在Segment中,相当于局部线程安全
LinkedHashMap -> 能记录访问顺序的HashMap
TreeMap -> 通过实现Comparator来实现自定义排序的Map
HashMap的扩容是将其扩为原来的两倍