静态加载和动态加载
4种加载时机,只有反射是动态加载
静态加载举个例子
Cat父类Animal
mao是Cat类独有方法
Animal a=new Cat();
a.mao();//编译看左边
//左边类型为Animal(会加载Animal类,编译时进行加载叫静态加载)
//然后加载Animal类的时候,Animal里面没有mao方法就会报错
比如这个图中可能输入的不是1
Dog类也会加载,因为Dog类是静态加载
反射->动态加载
而我们的Person就是动态加载,只有在运行到它的时候加载
就是当这个输入是2运行到了
Class.forName()才会加载
静态加载就是只要没有你写的类就报错
动态加载就是执行到需要加载类的部分发现没有对应的类,然后报错
类加载流程图
类加载的五个个阶段
加载-验证-准备-解析-初始化
下面会一一讲解
类加载五个阶段
加载阶段
就是把class文件的二进制数据加载到方法区
同时在堆中生成一个对应的Class对象
他们之间是相互关联的
连接阶段
验证
这个Dog.class文件就是cafebabe开头,合法的class文件
3.加这个开关可以降低类验证阶段效率的降低
值检测一些类验证措施
准备
就是在准备阶段-对静态变量进行默认赋值
不同类型的变量有不同的分配内存和赋值方式
实例变量是不进行内存分配的-这也是为什么,静态方法中不能使用实例变量
静态变量先赋默认值(0,false等),不会先赋定义的值!
而final static 比较特殊,它不会赋默认的值,而是会在准备阶段直接赋我们定义的值,之后就不变了
解析
虚拟机将常量池的符号引用转为直接引用的过程
可以理解为刚开始A类写一个1应用到B类写一个2
可以理解为一种符号引用
然后我们类加载要分配内存,再具体分配对应的引用
先搭个框架,然后把具体的引用放进去
没必要了解太深
初始化阶段
需要了解的是这个初始化阶段还是只处理静态的代码/变量
class B{
static{
System.out.println("B静态代码块被执行");
num = 300;
}
static int num=100;
public B(){System.out.println("B()构造器被执行");}
}
这样写-可能认为是错的,因为静态代码如果前后执行是不是就是num先赋值300
然后再进行的定义static int num = 100;
而其实我们的num在连接阶段以及分配内存并且赋了初值
所以num=300和num=100其实都相当于赋值操作
然后比如我们子另一个类中
new B();
会怎么输出呢-一步一步看
加载阶段-生成Class对象和在方法区生成二进制文件
连接阶段-把我们的num = 0;(赋默认值)
初始化阶段-按前后顺序收集并合并静态代码/语句
相当于运行了
<clinit>(
System.out.println("B静态代码块被执行");
num = 300;
num=100;
)
然后介绍构造器执行
如果只调用静态属性就不会调用构造器
3.加载类的时候有一个同步机制控制,只有一个线程能在同一时间加载同一个类
源码
防止在堆里同时产生多个Class对象
通过反射获取类的结构信息
class对象获取
演示代码
package yuan.hsp.reflection.Class;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Iterator;
//常用方法进行一个类的信息获取
@SuppressWarnings({"all"})
public class structget {
public static void main(String[] args) throws ClassNotFoundException {
//1.得到class对象-forName,前面有好多得到类名的方法
Class cls = Class.forName("yuan.hsp.reflection.Class.Person");
//2.getName:获取全类名
System.out.println(cls.getName());
//3.getSimpleName:获取简单类名
System.out.println(cls.getSimpleName());
//4.getFields:获取所有public修饰的属性,包含父类以及本类的
Field[] fields = cls.getFields();
for(Field aField:fields) {
System.out.println("public本类属性和父类的"+aField.getName());
}
//5.getDeclaredFields:获取本类的所有属性
Field[] declaredFields = cls.getDeclaredFields();
for(Field bField:declaredFields) {
System.out.println("本类所有属性"+bField.getName());
}
//6.getMethods:获取所有的public修饰的方法,包含本类以及父类的
Method[] methods = cls.getMethods();
for(Method cMethod:methods) {
System.out.println("public本类和父类方法"+cMethod.getName());
}
//7.getDeclaredMethods:获取本类的所有方法
Method[] declaredMethods = cls.getDeclaredMethods();
for(Method dMethod:declaredMethods) {
System.out.println("本类所有方法"+dMethod.getName());
}
//8.getConstructors:获取所有public修饰构造器,包含本类
Constructor[] constructors = cls.getConstructors();
for(Constructor e:constructors) {
System.out.println("获取public构造器本类"+e.getName());
}
//9.getDeclaredConstructors:获取本类所有构造器
Constructor[] declaredConstructors = cls.getDeclaredConstructors();
for(Constructor g:declaredConstructors) {
System.out.println("本类的所有构造器"+g.getName());
}
//10.getPackage:以Package形式返回包信息
System.out.println(cls.getPackageName());
//11.getSuperClass:以Class形式返回父类信息
System.out.println("父类Class对象获取简单类名"+cls.getSuperclass().getSimpleName());
//12.getInterfaces:以Class[]返回接口信息
Class[] interfaces = cls.getInterfaces();
for(Class h:interfaces) {
System.out.println("接口"+h.getSimpleName());
}
//13.getAnnotations:以Annotation[]形式返回注解信息
Annotation[] annotations = cls.getAnnotations();
for(Annotation i:annotations) {
System.out.println("注解"+i);
}
}
}
class A{
public String hobby;
public void hi() {
}
}
interface B{}
interface C{}
@SuppressWarnings({"all"})
@Deprecated
class Person extends A implements B,C{
public String name;
protected int age;
String job;
private double salary;
public Person(){
}
public Person(String name) {
}
public void m1() {
}
protected void m2() {
}
void m3(){
}
private void m4() {
}
}
运行结果
yuan.hsp.reflection.Class.Person
Person
public本类属性和父类的name
public本类属性和父类的hobby
本类所有属性name
本类所有属性age
本类所有属性job
本类所有属性salary
public本类和父类方法m1
public本类和父类方法hi
public本类和父类方法wait
public本类和父类方法wait
public本类和父类方法wait
public本类和父类方法equals
public本类和父类方法toString
public本类和父类方法hashCode
public本类和父类方法getClass
public本类和父类方法notify
public本类和父类方法notifyAll
本类所有方法m2
本类所有方法m1
本类所有方法m3
本类所有方法m4
获取public构造器本类yuan.hsp.reflection.Class.Person
获取public构造器本类yuan.hsp.reflection.Class.Person
本类的所有构造器yuan.hsp.reflection.Class.Person
本类的所有构造器yuan.hsp.reflection.Class.Person
yuan.hsp.reflection.Class
父类Class对象获取简单类名A
接口B
接口C
注解@java.lang.Deprecated(forRemoval=false, since="")
Field类获取
Method类获取
Constructor类获取