类是如何加载的?
- 1.加载
- 将类的.class文件加载到方法区
- 创建一个class对象(表示就是.class文件) 相当于文件的对象
- 2.连接
- 验证 验证一下类的内部结构(成员变量 和 方法)
- 转呗 为静态变量开辟空间 赋初始值
- 解析 将局部变量进行替换 替换成对应值
-
int a = 10 下面将所有的a 直接 替换成 10
- 3.初始化
- 创建对象 new对象(堆内存开辟空间 跟之前一样)
类是什么时候被加载的?(加载时机)
- 当你使用类的时候 该类一定会被加载
- 加载该类时 会先加载该类父类
类是用什么加载的?
- 使用类加载器加载类
- 1.根加载器 加载jdk的lib文件夹下的jar文件
- 2.扩展加载器 加载ext文件夹下的文件
- 3.系统加载器 自定义类或者导入jar都是用系统加载器
反射
- 反射可以将一个正在运行的类(加载完成的类)
- 通过这个class文件的对象 可以直接获取类内部的所有方法和成员变量(包括私有的)
例1:
/*
* 获取class文件对象
* 1.通过对象获取
* 2.通过类获取
* 3.通过class中的 静态方法获取(ClassForName() 常用)
*/
//通过对象获取
Person person = new Person();
//获取person类的 class文件对象
Class<? extends Person> c1 = person.getClass();
System.out.println(c1);
//通过类获取
Class<Person> c2 = Person.class;
System.out.println(c2);
//常用(只需要一个字符串 就能获取该类的class对象)
//注意:参数要填全类名 包名+类名
Class<?> c3 = Class.forName("com.lanou3g.reflect.Person");
System.out.println(c3);
例2:
//通过Class文件对象 获取类中构造方法
Class<?> c = Class.forName(“com.lanou3g.reflect.Person”);
// 获取所有的公有的(public)构造方法
Constructor<?>[] constructors = c.getConstructors();
//遍历
for (Constructor<?> constructor : constructors) {
System.out.println(constructor);
}
//获取单个构造方法
Constructor<?> constructor = c.getConstructor();
//利用该构造方法创建对象
Object newInstance = constructor.newInstance();
System.out.println(newInstance);
//有参构造创建对象(参数是 参数类的文件类型)
Constructor<?> constructor1 = c.getConstructor(String.class, int.class);
Object newInstance2 = constructor1.newInstance("王龙",30);
System.out.println(newInstance2);
例3:
/*
* 通过Class文件对象 快速创建对象
* 前提:
* 1.类必须用public
* 2.必须提供无参构造方法
* 3.该无参构造方法必须是public修饰
*/
Class<?> c = Class.forName(“com.lanou3g.reflect.Person”);
//快速创建对象(直接使用类中 无参构造方法创建)
Object object = c.newInstance();
System.out.println(object);
例4:
//获取类中所有的构造方法(包括私有)
//通过Class文件对象 获取类中构造方法
Class<?> c = Class.forName(“com.lanou3g.reflect.Person”);
Constructor<?>[] declaredConstructors = c.getDeclaredConstructors();
for (Constructor<?> constructor : declaredConstructors) {
System.out.println(constructor);
}
//获取私有的构造方法
Constructor<?> declaredConstructor = c.getDeclaredConstructor(int.class,String.class);
//打开私有方法使用权限
declaredConstructor.setAccessible(true);
//创建对象
Object newInstance = declaredConstructor.newInstance(30,“王龙”);
//打印对象
System.out.println(newInstance);
例5:
//通过Class文件对象 获取类中构造方法
Class<?> c = Class.forName(“com.lanou3g.reflect.Person”);
//获取所有公开的成员变量
Field[] fields = c.getFields();
for (Field field : fields) {
System.out.println(field);
}
//单独获取指定成员变量
Field field = c.getField(“name”);
//创建一个Person
Object newInstance = c.newInstance();
//通过反射 给该属性赋值
field.set(newInstance, “gorilla”);
System.out.println(newInstance);
//获取私有成员变量 age 并 赋值 打印
Field declaredField = c.getDeclaredField("age");
//打开访问权限
declaredField.setAccessible(true);
declaredField.set(newInstance, 30);
System.out.println(newInstance);
例6:
Class<?> c = Class.forName(“com.lanou3g.reflect.Person”);
//获取类中所有的公开方法(包括父类的)
Method[] methods = c.getMethods();
for (Method method : methods) {
//System.out.println(method);
}
//获取指定的成员方法
//参数1: 获取的方法名字
//参数2: 获取的方法的参数的Class类型
Method method = c.getMethod(“eat”);
System.out.println(method);
//调用该方法
method.setAccessible(true);
Object newInstance = c.newInstance();
//参数1:调用该方法的对象
//参数2:调用该方法 要传入的参数
Object invoke = method.invoke(newInstance);
System.out.println(invoke);
Method method2 = c.getMethod("speak", String.class);
Object invoke2 = method2.invoke(newInstance, "国语教学");
System.out.println(invoke2);
Method declaredMethod = c.getDeclaredMethod("play", String.class);
//开启权限
declaredMethod.setAccessible(true);
//调用方法
Object invoke3 = declaredMethod.invoke(newInstance, "LOL");
System.out.println(invoke);
例7:
/*
* 利用反射
* 向ArraryList中 添加 Integer数据 Person对象
* 注意: 编译成class文件 泛型不存在
*/
ArrayList<String> list = new ArrayList<>();
//获取class文件对象 ArrayList
Class<? extends ArrayList> class1 = list.getClass();
//获取ArrayList类中的 add方法
Method method = class1.getMethod("add", Object.class);
//调用该方法存值
method.invoke(list, 123);
method.invoke(list, new Person("王龙",30));
method.invoke(list, "哈哈");
//打印查看
System.out.println(list);