本文最后更新于2 分钟前,文中所描述的信息可能已发生改变。
有关java的一些零散知识点。
java基础
Comparable与Comparator两个接口的区别
Comparable(java.lang)接口:实现此接口只能定义一种排序规则,通过实现接口中的int compareTo(T o)方法来比较,需要待排序类自己实现。
Comparator(java.util)接口:使用此接口待比较对象不需要自己实现,即可以保持待比较类的原样实现比较功能。实现此接口的类即为比较器,可以在此类中的compare方法中定义比较规则,通过多个比较器可以实现按照不同属性进行排序的功能。
equals()与hashCode()
"="比较的为地址,equals()比较两个对象是否等价(值是否相等)。重写了equals()方法一定要重写hashCode()方法,等价的两个对象hashCode一定相等但是hashCode相等的两个对象不一定等价,hashCode的计算具有随机性导致。HashMap(key使用)与HashSet是使用hashCode来计算对象的存储位置,所以当重写了equals而不重写hashCode方法会导致在集合中添加相同的元素。
浅拷贝与深拷贝
浅拷贝:拷贝对象与原始对象的引用(地址)是相同的,拷贝的是引用。 深拷贝:拷贝对象与原始对象的引用不同,拷贝的是值。
Object中的clone()方法为浅拷贝。使用此法需要实现Cloneable接口,既复杂又有风险,还需要进行类型转换不推荐使用此方法进行拷贝。可以使用对象拷贝工厂或拷贝构造函数来进行拷贝一个对象。例如
public class A{
public int age;
...
//拷贝构造函数
public A(A a){
this.age = a.age;
...
}
}
接口与抽象类
- 接口:方法和字段默认都是public(只能为此),且字段默认都是是static final修饰。java8开始接口中的方法可以有默认实现,java9开始方法可以被private修饰(这样就可以定义一些私密的复用代码,即只在本接口中使用的)。
- 抽象类:访问修饰符没有限制,只能被继承不能实例化。
- 使用时机:
- 接口:需要让不相关的类都实现同一个方法、需要使用多重继承。
- 抽象类:需要让相关的类中共享代码、需要控制方法的访问权限、需要继承非静态字段与非常量字段。
重写与重载
- 重写:外壳不变,核心改变(返回值类型需为父类方法中的返回值类型或其子类,异常与访问权限也是如此,即只能小不能扩大范围)。
- 重载:方法名相同,但参数列表要唯一(即参数类型、个数、顺序至少有一个不同)。
泛型
泛型是一种特殊的类型,即在创建对象或调用方法时才会明确其具体的类型。主要使用有泛型类、泛型接口、泛型方法。静态方法访问不到类上的泛型声明,需要自己声明(即定义为一个泛型方法)。
/* 泛型类的声明 */
public class Ciallo<T>{
public static<T> void A(T a){
//这个类型T的实际类型可以与类上声明的T类型相同也可不同
System.out.println(a);
}
public void B(T b){
//这个T类型必须和类上声明的T类型一致
System.out.println(b);
}
//泛型方法的声明
public <T> void C(T c){
//这个T是一个新的类型T,即可以与类上的T类型相同也可不同
System.out.println(c);
}
}
部分内容参考自
java容器
分为两大类Collection与Map。
Collection:
- Set:
- TreeSet:基于红黑树实现,支持有序性操作。
- HashSet:基于哈希表实现,支持快速查找,但不支持有序性操作。并且失去元素的插入顺序信息。
- LinkedHashSet:具有 HashSet 的查找效率,并且内部使用双向链表维护元的插入顺序。
- List:
- ArrayList:基于动态数组实现,支持随机访问。
- Vector:和 ArrayList 类似,但它是线程安全的。
- LinkedList:基于双向链表实现,只能顺序访问,但是可以快速地在链表中插入和删除元素。不仅如此,LinkedList 还可以用作栈、队列和双向队列。
- Queue:
- LinkedList:可以用它来实现双向队列。
- PriorityQueue:基于堆结构实现,可以用它来实现优先队列。
Map:
- TreeMap:基于红黑树实现。
- HashMap:基于哈希表实现。
- HashTable:和 HashMap 类似,但它是线程安全的,它是遗留类,不应该去使用它,而是使用 ConcurrentHashMap 来支持线程安全。
源码学习
ArrayList的扩容:默认数组大小为10(实际是0,只有添加了第一个元素才会生成一个大小为10的数组),扩容后的大小=老的容量大小+老的容量大小>>1,即扩容后为原来的1.5倍,>>1需要取整(偶数时扩容为1.5倍)。
部分内容参考自
JVM
JDK与JRE
- JDK(Java Development Kit) Java 开发工具包,提供了 Java 的开发及运行环境。JDK 是 Java 开发的核心,集成了 JRE 以及一些其它的工具,比如编译 Java 源码的编译器 javac 等(JRE+java开发辅助工具)。
- JRE(Java Runtime Environment) Java 运行环境的简称,为 Java 的运行提供了所需的环境。它是一个 JVM 程序,主要包括了 JVM 的标准实现和一些 Java 基本类库(JVM+java程序运行时所需要的类库)。
JVM的总体机制
JAVA 源程序编译运行过程:java 源程序->编译->.class字节码文件->类加载到 JVM 上运行。
JVM 的总体运行机制:
- 使用类加载器加载 .class 字节码文件到 JVM 内存中的方法区。
- 在 JVM 的内存中存储相关数据(类的信息、静态变量、常量)。
- 在执行引擎中将 .class 翻译为 CPU 能够执行的指令。
- 将指令发送给 CPU 执行
类加载机制
- 类加载器子系统负责从文件系统或网络中加载.class字节码文件。
- CLassLoader 只负责字节码文件的加载,由执行引擎来判断此字节码文件是否可以运行。
- JVM中有四中类加载器(前三中为JVM自带):启动类加载器Bootstrap(爷爷)、扩展类加载器Extension(爸爸)、应用类加载器AppClassLoader(儿子)、用户自定义加载器(程序员自己开发一个继承 java.lang.ClassLoader 的类来定制类加载方式)。其中启动类加载器由C++编写,不是 ClassLoader 的子类,在 java 中打印时为 null。
- 父子关系(逻辑上):通过parent属性维护。
- 加载顺序(双亲委派机制):先获取要加载的类所对应范围的类加载器,此加载器不会立即查找而是会将任务上移交给其上一级加载器,一直到顶级的应用类加载器,然后从应用类加载器开始查找,找到就加载并到此为止,否则抛出 ClassNotFoundException。
- 双亲委派机制的好处:
- 防止重复加载类,保证了JVM范围内类的全限定名是类的唯一标识。
- 安全机制,防止恶意替换JRE定义的核心API(沙箱安全机制)。
JVM内存
线程私有
- 程序计数器: 记录正在执行的虚拟机字节码指令地址(就是记录指令地址),执行的是本地方法则为NULL。
- JAVA虚拟机栈: 由一个个栈帧组成,栈帧中存储有 局部变量表、操作数栈、常量池应用等信息。
- 本地方法栈:
线程共有
参考文献
待定…
其它
在保证x是2的n次方的时候y%x的结果与y&(x-1)的结果是一样的。