类加载&&反射实例
类加载
反射机制是java实现动态语言的关键,也就是通过反射实现类动态加载。
1.静态加载:编译时加载相关类,如果没有则报错,依赖性强
2.动态加载:运行时加载需要的类,如果运行时不用该类则不报错。
package reflection.class_;
public class classLoad_ {
public static void main(String[] args) {
}
}
class A {
//属性-成员变量-字段
//分析类加载的链接阶段-准备 属性是如何处理
//1. n1 是实例属性, 不是静态变量,因此在准备阶段,是不会分配内存
//2. n2 是静态变量,分配内存 n2 是默认初始化 0 ,而不是20
//3. n3 是static final 是常量, 他和静态变量不一样, 因为一旦赋值就不变 n3 = 30
public int n1 = 10;
public static int n2 = 20;
public static final int n3 = 30;
}
- 当创建对象时(new) //静态加裁
- 当子类被加载时,父类也加载〃静态加载
- 调用类中的静态成员时〃静态加载
- 通过反射〃动态加载
Class.forName("com.test.CatM);
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iioEJREU-1634287779550)(
)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9tJIBCOW-1634287779553)(C:\Users\Admin\AppData\Roaming\Typora\typora-user-images\image-20211015164128668.png)]
加载阶段
- 目的是为了确保Class文件的字节流中包含的信息符合当前虚拟机的要求,并且不 会危害虚拟机自身的安全。
- 包括:文件榕式验证(是否以魔数oxcafebabe开头)、元数据验证、字节码验证和 符号引用验证库例说明]
- 可以考虑使用-Xverify:none参数来关闭大部分的类验证措施,缩短虚拟机类加载 的时间。
- JVM会在该阶段对静态变量,分配内存并默认初始化(对应数据类型的默认初始 值,如0、OL null、false等)。这些变量所使用的内存都将在方法区中进行分 配
反射实例
package reflection;
import sun.management.Agent;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
public class ReflecCreateInstance {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
//1. 先获取到User类的Class对象
Class<?> userClass = Class.forName("reflection.User");
//2. 通过public的无参构造器创建实例
Object o = userClass.newInstance();
System.out.println(o);
//3. 通过public的有参构造器创建实例
/*
constructor 对象就是
public User(String name) {//public的有参构造器
this.name = name;
}
*/
/* Constructor<?> name = userClass.getConstructor(String.class,int.class);
Object o1 = name.newInstance("陆泉衡",18);
System.out.println(o1);*/
//3.1 先得到对应构造器
Constructor<?> constructor = userClass.getConstructor(String.class);
//3.2 创建实例,并传入实参
Object hsp = constructor.newInstance("ll");
//4. 通过非public的有参构造器创建实例
//4.1 得到private的构造器对象
Constructor<?> constructor1 = userClass.getDeclaredConstructor(int.class, String.class);
//4.2 创建实例
//暴破【暴力破解】 , 使用反射可以访问private构造器/方法/属性, 反射面前,都是纸老虎
constructor1.setAccessible(true);
Object user2 = constructor1.newInstance(100, "张三丰");
System.out.println("user2=" + user2);
}
}
class User { //User类
private int age = 10;
private String name = "韩顺平教育";
public User() {//无参 public
}
public User(String name) {//public的有参构造器
this.name = name;
}
private User(int age, String name) {//private 有参构造器
this.age = age;
this.name = name;
}
public String toString() {
return "User [age=" + age + ", name=" + name + "]";
}
}
package reflection;
import org.junit.Test;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class ReflecAccessMethod {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
//1. 得到Boss类对应的Class对象
Class<?> bossCls = Class.forName("reflection.Boss");
//2. 创建对象
Object o = bossCls.newInstance();
//3. 调用public的hi方法
//Method hi = bossCls.getMethod("hi", String.class);//OK
//3.1 得到hi方法对象
Method hi = bossCls.getDeclaredMethod("hi", String.class);//OK
//3.2 调用
hi.invoke(o, "会飞的小陆~");
//4. 调用private static 方法
//4.1 得到 say 方法对象
Method say = bossCls.getDeclaredMethod("say", int.class, String.class, char.class);
//4.2 因为say方法是private, 所以需要暴破,原理和前面讲的构造器和属性一样
say.setAccessible(true);
System.out.println(say.invoke(o, 100, "张三", '男'));
//4.3 因为say方法是static的,还可以这样调用 ,可以传入null
System.out.println(say.invoke(null, 200, "李四", '女'));
//5. 在反射中,如果方法有返回值,统一返回Object , 但是他运行类型和方法定义的返回类型一致
Object reVal = say.invoke(null, 300, "王五", '男');
System.out.println("reVal 的运行类型=" + reVal.getClass());//String
//在演示一个返回的案例
Method m1 = bossCls.getDeclaredMethod("m1");
Object reVal2 = m1.invoke(o);
System.out.println("reVal2的运行类型=" + reVal2.getClass());//Monster
}
}
class Monster {}
class Boss {//类
public int age;
private static String name;
public Boss() {//构造器
}
public Monster m1() {
return new Monster();
}
private static String say(int n, String s, char c) {//静态方法
return n + " " + s + " " + c;
}
public void hi(String s) {//普通public方法
System.out.println("hi " + s);
}
}
练习
1利用Class类的forname获取File类的class对象
2.利用newInstance的方法创建File对象,并创建Mynew.txt;
package reflection;
import com.sun.xml.internal.ws.org.objectweb.asm.ClassAdapter;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
public class lianxi {
public static void main(String[] args) throws Exception {
//(1) 加载类, 返回Class类型的对象cls
Class<?> aClass = Class.forName("java.io.File");
//遍历该类的所有构造器
Constructor<?>[] declaredConstructors = aClass.getDeclaredConstructors();
for (Constructor<?> d : declaredConstructors) {
System.out.println(d);
}
//取出该类的一个构造器
Constructor<?> constructor = aClass.getConstructor(String.class);
String fileAllPath = "e:\\mynew.txt";
//(1) 加载类, 返回Class类型的对象o
Object o = constructor.newInstance(fileAllPath);
// (4) getMethod 调用方法: 即通过方法对象来实现调用方法
Method createNewFile = aClass.getMethod("createNewFile");
//传统方法 对象.方法() , 反射机制 方法.invoke(对象)
createNewFile.invoke(o);
System.out.println(o.getClass());
System.out.println(fileAllPath);
}
}
teNewFile = aClass.getMethod(“createNewFile”);
//传统方法 对象.方法() , 反射机制 方法.invoke(对象)
createNewFile.invoke(o);
System.out.println(o.getClass());
System.out.println(fileAllPath);
}}
``