1.ClassLoader类
1.1类加载器的一些基础概念
ClassLoader在JVM运行的时候回加载Java核心的API,以满足程序最基本的需求。Java主要有三个类加载器:Bootstrap Loader、ExtClassLoader和AppClassLoader。
Bootstrap Loader是由C++编写的。称为启动类加载器,是Java类加载层次中最顶层的类加载器,负责加载JDK中相关的类库,例如rt.jar、resource.jar等。默认加载的是jre/lib或者jre/classes下的jar文件。
ExtClassLoader称为扩展类加载器,负责加载java的扩展类库,默认加载的是jre/lib/ext目录下的所有jar。
AppClassLoader称为系统类加载器,默认加载的是classpath目录下的所有jar和class文件。
注意: 除了Java默认提供的三个ClassLoader之外,用户还可以根据需要定义自已的ClassLoader,而这些自定义的ClassLoader都必须继承自java.lang.ClassLoader类,也包括Java提供的另外二个ClassLoader(Extension ClassLoader和App ClassLoader)在内。
1.2类加载流程
当运行一个程序的时候,JVM启动,运行Bootstrap classLoder,该ClassLoader加载Java核心API。之后会载入ExtClassLoader,并且将ExtClassLoder的parent设为BootstrapLoader。ExtClassLoader会加载扩展API。然后BootstrapLoader再载入AppClassLoader,并且将AppClassLoader的parent设为ExtClassLoader。AppClassLoader会加载classpath目录下的class和jar。自底向上检查类是否加载,自顶向下加载类。
注意:JVM在判断两个类是否相同时,不仅要判断类名是否相同,还要判断两个类是否是同一个类加载器实例ss加载的。
JVM加载类的时候需要三步:装载、连接、初始化。装载就是找到相应的类,读入JVM;连接分为三步:第一步验证class是否符合规格,第二步准备,为类变量分配内存的同时设置初始默认值,第三步解释,是指根据类中的符号引用查找相应的实体,再把符号引用替换成一个直接引用的过程。初始化即class文件初始化。Class类中的Class.forName()方法在加载的时候回将Class进行解释和初始化。而ClassLoader不会,它仅仅加载了类。
2.Java使用了中间缓存变量的机制
- 读取变量j的值到缓存;
- 改变变量j的值为缓存值;
- 改变变量j的值,将其增1。
- 读取变量j的值 (0) 到缓存。
- 改变变量j的值,将其增1 (变为1)。
- 改变变量j的值为缓存值 (变为0)。
在Java中执行自增自减运算时,会为每一个操作分配一个临时变量,如果是++i,先i=i+1,再将i的值赋给临时变量;如果是i++,先赋给临时变量,再加1。运算最终使用的值是临时变量,而不是变量本身。
例如:
i = i++ + ++i;(i的初值为0) ----答案为 2
i++等于如下两步:
int temp = i = 0;
i = i + 1 = 1;
++i等于如下两步:
i = i + 1 = 2;
int temp = i;
最后两个temp相加等于2赋给i;
3.三目运算中第一个是返回布尔值的表达式,后面两个操作数或者表达式必须返回类型一致。
两边的操作数不一致时,涉及到三元操作符的转换规则:
若两个操作数不可转换,返回值为Object类型;
若两个操作数有明确类型的表达式(比如变量),则按照正常的二进制数字来转换,int转换为long类型,long转换为float类型;
若两个操作数中有一个是数字S,另一个是表达式,且类型为T,若数字S在T的范围内,则转换为T类型;若S超过了T的范围,则T转换为S类型。
若两个操作数都是直接数字,则返回值类型为范围较大者。
4.& 、|、^ 这三个除了是位运算符之外,还可以充当布尔逻辑运算符,前提是两边的数据类型都要是布尔类型。布尔逻辑运算符的优先级要高于逻辑运算符。最大的区别是 布尔逻辑运算符是非短路运算,逻辑运算符是短路运算。
短路运算:但凡&&前面的是false,则后面的表达式不再做了。但凡||前面的是true,后面的表达式也不用继续运算。
非短路运算:无论运算符前面的是true或者false,运算符后面的表达式都要继续运算。
5.Java中若移位运算,会对移位的位数先进行模32或者模64运算,再移位。
6.final关键字
6.1final成员:这个变量一旦被初始化,便不可改变。意思是对基本类型来说其值是不可变的,而对于对象变量来说其引用不可变。初始化可以在两个地方,一个是其定义处,一个是构造函数中。
6.2final方法:将方法声明为final有两个原因,一个是已经知道该方法提供的功能满足要求,不需要进行扩展,并且不允许任何从此类继承的类来覆写这个方法,但是可以继承,可以使用。第二就是允许编译器将所有对此方法的调用转化为inline调用的机制。在调用final方法时,直接将代码主题插入到调用处。
6.3final类:无法被任何类继承,且所有的方法就是final类型。类中的成员可以是final型,也可以不是final型。
7.finalize:该方法是在Object类中定义的,因此所有的类都继承了它。子类覆盖finalize()方法以整理系统资源或者执行其他清理工作。finalize()方法是在垃圾收集器删除对象之前对这个对象调用的。
8.反射机制:反射主要是指程序可以访问,检测和修改它本身状态或行为的一种能力,并根据自身行为的状态和结果,调整或修改应用所描述行为的状态和相关的语义。通过反射机制访问java对象的属性,方法和构造方法等。
8.1通过反射得到类对象
//第一种方法
Class c1 = Class.forName("Employee");
//第二种方法
Class c2 = Employee.class;
//第三种方法
Employee e = new Employee();
Class c3 = e.getClass();
8.2获取到类以后创建对象
Object o = c1.newInstance();