一、类加载(将class文件读入内存,创建一个java.lang.Class对象)
当程序还未使用某个类的时候,如果该类没有被加载到内存中,则系统会通过类的加载、类的连接、类得初始化三个步骤对类进行初始化,如果不要出现意外,JVM虚拟机会连续执行这三个操作,所以会把这三个步骤统称为类加载或类的初始化。
1、类加载时机
二、反射
反射机制:在运行时去获取一个类的变量或方法信息。然后通过获取到的信息来创建对象,调用方法的一种机制。这种动态性,极大增强了程序的灵活性,程序不用再编译期就完成确定,运行期仍可以拓展。
通过Class类(字节码文件对象)使用Student或者Teacher类中的成员变量、方法等,就是反射。内存中只存在一个相同类的字节码对象。
1、获取Class对象的三种方法
//1、通过类class属性
Class<Student> stu = Student.class;
//2、对象的getClass方法
Student student = new Student();
Class<? extends Student> stu2 = student.getClass();
System.out.println(stu == stu2); //true 同一个类内存只有一个字节码对象
//3、Class的静态方法forName
Class<?> stu3 = Class.forName("com.example.demo.practice.Student");
System.out.println(stu == stu3);
2、反射获取构造方法、创建实例对象
//获取所有公共的构造方法
Constructor<?>[] cons = stu.getConstructors();
//获取所有构造方法
Constructor<?>[] consAll = stu.getDeclaredConstructors();
//反射获取无参构造方法,创建对象
Constructor<Student> con = stu.getConstructor();
Student student2 = con.newInstance();
System.out.println(student2);
//反射获取有参构造方法,有参创建对象
Constructor<Student> con2 = stu.getConstructor(String.class,int.class,String.class);
Student student3 = con2.newInstance("xin",22,"beijng");
System.out.println(student3);
//反射获取私有的构造方法创建对象
Constructor<Student> conprivate = stu.getDeclaredConstructor(String.class);
//私有的构造方法获取没有问题,创建实例对象需要设置暴力反射
conprivate.setAccessible(true); //true 取消访问检查
Student stupri = conprivate.newInstance("wang");
System.out.println(stupri);
3、反射获取私有变量以及赋值
//获取属性
Field[] fields = stu3.getFields(); //获取所有公共的
Field[] fields2 = stu3.getDeclaredFields(); //获取所有的
//Field address = stu3.getField("address"); //获取指定名公共的
//Field name = stu3.getDeclaredField("name"); //获取指定名的
//为属性赋值
Constructor<?> constru = stu3.getConstructor();
Object obj = constru.newInstance();
Field address = stu3.getField("address"); //获取指定名公共的
Field name = stu3.getDeclaredField("name"); //获取指定名的
name.setAccessible(true);//name是private
name.set(obj, "xincm");
address.set(obj, "neimeng");
System.out.println(obj.toString());
4、反射获取成员方法
//获取方法
Method[] methods = stu3.getMethods();
Method[] methods2 = stu3.getDeclaredMethods();
//使用方法
Method method = stu3.getMethod("method1");
Constructor<?> constru = stu3.getConstructor();
Object obj = constru.newInstance();
method.invoke(obj);
//带参数、返回值方法
Method m2 = stu3.getMethod("method3", String.class);
Object res = m2.invoke(obj, "哈哈");
//private的方法
Method m3 = stu3.getDeclaredMethod("method2");
m3.setAccessible(true);
m3.invoke(obj);
5、反射越过泛型检查:向一个泛型为Integer的list中添加字符串
实现关键、因为集合add方法接收参数就是Object类型,本身集合不存在泛型,泛型只是一种规范。在jvm编译的时候语法糖就做了反省擦拭操作
List<Integer> list = new ArrayList<Integer>();
Class<? extends List> listclass = list.getClass();
Method add = listclass.getDeclaredMethod("add", Object.class);
add.invoke(list, "str");
System.out.println(list);
6、配置文件方法执行方法
Properties prop = new Properties();
FileReader file = new FileReader("D:\\Users\\sts-workspace-success\\querydsl-jpa\\src\\main\\java\\com\\example\\demo\\practice\\properties.txt");
prop.load(file);
file.close();
String className = (String) prop.get("className");
String methodName = (String) prop.get("methodName");
Class<?> stud = Class.forName(className);
Method meth = stud.getDeclaredMethod(methodName);
Constructor<?> construc = stud.getConstructor();
Object stunew = construc.newInstance();
meth.invoke(stunew);