类加载器与反射

   类的加载

当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过加载,连接,初始化三步来实现对这个类进行初始化。

 加载

就是指将class文件读入内存,并为之创建一个Class对象。

任何类被使用时系统都会建立一个Class对象

 连接

验证 是否有正确的内部结构,并和其他类协调一致

准备 负责为类的静态成员分配内存,并设置默认初始化值

解析 将类的二进制数据中的符号引用替换为直接引用

  初始化

就是我们以前讲过的初始化步骤

   类初始化时机

1. 创建类的实例

2. 类的静态变量,或者为静态变量赋值

3. 类的静态方法

4. 使用反射方式来强制创建某个类或接口对应的java.lang.Class对象

5. 初始化某个类的子类

6. 直接使用java.exe命令来运行某个主类

     类加载器

 负责将.class文件加载到内存中,并为之生成对应的Class对象。

  虽然我们不需要关心类加载机制,但是了解这个机制我们就能更好的理解程序的运行

     类加载器的组成

  Bootstrap ClassLoader 根类加载器

也被称为引导类加载器,负责Java核心类的加载

比如System,String等。在JDK中JRE的lib目录下rt.jar文件中

Extension ClassLoader 扩展类加载器

负责JRE的扩展目录中jar包的加载。

在JDK中JRE的lib目录下ext目录

 System ClassLoader 系统类加载器

    反射

   Class类

代码演示:

 1 public class Person {
 2     public String name;
 3     private int age;
 4     public Person(){
 5         System.out.println("公共构造方法");
 6     }
 7     public Person(String name,int age){
 8         this.name=name;
 9         this.age=age;
10         System.out.println("公共有参构造");
11     }
12     private Person(int age,String name){
13         System.out.println("私有有参构造");
14     }
15     public void eat(){
16         System.out.println("公共方法");
17     }
18     public void sleep(String name){
19         System.out.println(name+"公共有参方法");
20     }
21     private void playGames(){
22         System.out.println("私有方法");
23     }
24     @Override
25     public String toString() {
26         return "Person [name=" + name + ", age=" + age + "]";
27     }
28 
29 }
 1 //获取字节码文件对象的三种方式
 2     public static void method1() throws ClassNotFoundException{
 3         //1.通过对象获取
 4         Person p=new Person();
 5         Class c=p.getClass();
 6         System.out.println(c);
 7         //2.通过类名获取
 8         Class c1=Person.class;
 9         System.out.println(c1);
10         System.out.println(c==c1);
11         System.out.println(c.equals(c1));
12         //3.通过Class类的静态方法forName(包名.类名)获取
13         Class c2=Class.forName("com.oracle.demo03.Person");
14         System.out.println(c2);
15     }

   通过反射获取构造方法并使用

 1 //获取构造方法
 2     public static void method2() throws Exception{
 3         //获取字节码文件对象
 4         Class c=Class.forName("com.oracle.demo03.Person");
 5         //获取非私有构造方法数组
 6         /*Constructor[] cons=c.getConstructors();
 7         for(Constructor con:cons){
 8             System.out.println(con);
 9         }*/
10     /*    //获取空参构造
11         Constructor con=c.getConstructor();
12         //使用空参构造创建对象
13         Object obj=con.newInstance();
14         Person p=(Person)obj;
15         p.eat();*/
16         //获取有参构造方法并调用
17         /*Constructor con=c.getConstructor(String.class,int.class);
18         Object obj=con.newInstance("张三",18);
19         System.out.println(obj);*/
20         //针对空参构造有一个快速创建对象的方式
21         //1.Person类中必须有空参构造方法
22         //2.空参构造方法必须是public修饰
23         Object obj=c.newInstance();
24         System.out.println(obj);
25     }

通过反射方式,获取构造方法,创建对象

1. 获取到Class对象

2. 获取指定的构造方法

3. 通过构造方法类Constructor中的方法,创建对象

public T newInstance(Object... initargs)

通过反射方式,获取私有构造方法,创建对象

通过反射获取成员变量并使用

代码展示:

 1     //通过反射获取私有构造---暴力反射  不推荐使用
 2     //它破坏了我们程序的封装性、安全性
 3     //抢银行方式
 4     public static void method3()throws Exception{
 5         //获取字节码文件对象
 6         Class c=Class.forName("com.oracle.demo03.Person");
 7         //获取所有构造方法
 8         /*Constructor[] cons=c.getDeclaredConstructors();
 9         for(Constructor con:cons){
10             System.out.println(con);
11         }*/
12         //获取私有构造方法并使用
13         Constructor con=c.getDeclaredConstructor(int.class,String.class);
14         //取消Java对我的检查
15         con.setAccessible(true);
16         Object obj=con.newInstance(18,"李四");
17         System.out.println(obj);
18     }
19     public static void method4() throws Exception{
20         //获取字节码文件对象
21         Class c=Class.forName("com.oracle.demo03.Person");
22         Object obj=c.newInstance();
23         //获取公共成员变量并使用
24         Field field=c.getField("name");
25         field.set(obj,"张三");
26         //获取私有成员变量并使用
27         Field f=c.getDeclaredField("age");
28         f.setAccessible(true);
29         f.set(obj, 18);
30         System.out.println(obj);
31         //System.out.println(field.get(obj));
32     }
33     public static void method5() throws Exception{
34         //获取字节码文件对象
35         Class c=Class.forName("com.oracle.demo03.Person");
36         Object obj=c.newInstance();
37         //获取空参的成员方法并运行
38         Method method=c.getMethod("eat");
39         method.invoke(obj);
40         //获取有参成员方法并运行
41         Method method1=c.getMethod("sleep", String.class);
42         method1.invoke(obj, "张三");
43     }

    泛型擦除

反射配置文件

 1 public class Demo {
 2 
 3     public static void main(String[] args) throws Exception {
 4         //反射配置文件实现
 5         //把我们要运行的类和方法以键值对的形式写在文本中
 6         //我们想要运行哪个类里面的方法 只需要改配置文件即可
 7         /*步骤:
 8          * 1.准备配置文件,键值对
 9          * 2.IO读取配置文件,Reader
10          * 3.将文件中的键值对保存在Properties集合中,键值对就是类和方法名
11          * 4.通过反射获取指定类的class文件对象
12          * 5.通过class文件对象获取指定方法
13          * 6.运行方法
14          * */
15         FileReader fr=new FileReader("src/config.properties");
16         Properties pro=new Properties();
17         pro.load(fr);
18         String className=pro.getProperty("className");
19         String methodName=pro.getProperty("methodName");
20         Class c=Class.forName(className);
21         Object obj=c.newInstance();
22         Method method=c.getMethod(methodName);
23         method.invoke(obj);
24         
25     }

配置文件:

1 #className=com.oracle.demo04.Person
2 #methodName=eat
3 className=com.oracle.demo04.Student
4 methodName=study
5 className=com.oracle.demo04.Worker
6 methodName=work
原文地址:https://www.cnblogs.com/2734156755z/p/9560021.html