类加载和反射

2、反射
在我们使用类之前会有一个进入内存的步骤,其中分为三步,加载、连接、初始化三步。
第一个加载过程是class文件读入内存,并且在栈里面创建一个class对象。(不论是什么类使用之前都会创建一个class对象)。
连接:
初始化:
类初始化时机就是如何在栈里面建内存的步骤行为。类的加载。
1、new person
2、静态变量
3、静态方法
4、使用反射方式来强制创建某个类或接口对应的java.lang.class对象
5、进内存的父类的子类
6、main  java.exe命令
类加载器:
是将程序的.class文件加载到内存(程序的.class文件是由上面的6中方式产生的。),并且产生class对象,我们自定义的类都会出现一个class对象,因为他是对象,所以我们可以用对象.方法名()调取能够访问的所有方法。
类加载器的组成。
跟类加载器 核心
jar包 拓展类加载器
系统及在其 平时自定义的类。
如何获取反射?
反射的意义是java在运行状态时,对任意类都能知道所有的属性和方法,对于一个类,我们可以调用它的任意一个方法和属性。
1、Class类
通过类加载器,我们知道,class类不是自己创建出来的,而是系统让类加载进栈内存产生的,所以我们获取的class对象只能获取并不能new对象修改,因为它没有构造方法。
开头第一步之获取Class类
①通过Object 的getObject()获取最高类Object 中的getClass
person p=new person();
Class c=p.getClass();
②通过类名.class获取字节码文件对象(任意数据类型都具备一个class静态属性)
Class c1=person.class();
③通过class方法中调取静态方法.forName(JDBC工具类使用这个,每一个类中只能存在一个
通过完整的包名+类名获取
Class c2=class.forName("com.oracle.demo03.Person");传入要获取的类名。

第二步之如何通过反射获取构造方法:
如获取所有的public修饰的公共构造方法:
1、首先获取class对象,同上面三条那一条都可以
2、通过class对象调取所有public方法或者单个方法,[]或者单个

Constructor[] cons=c.getConstructors();


获取所有构造方法数组(包括私有)
Constructor[] cons=c.getDeclaredConstructors();

person类

package com.oracle.demo02;

public class Person {
    //私有
    private int age;
    //公共
    public String name;
    //公共空参构造
    public Person(){
        System.out.println("公共空参构造");
    }
    //公共有参构造
    public Person(int age,String name){
        this.name=name;
        this.age=age;
        System.out.println("公共有参构造");
    }
    //私有有参构造
    private Person(String name,int age){
        this.name=name;
        this.age=age;
        System.out.println("私有有参构造");
    }
    public void eat(){
        System.out.println("公共空参方法");
    }
    
    public void sleep(String name){
    
        System.out.println("公共有参方法");
    }
    private void plagname(int age){
        System.out.println("私有有参方法");
    }
    static{
        System.out.println("person静态代码块");
    }
    @Override
    public String toString() {
        return "Person [age=" + age + ", name=" + name + "]";
    }

}
获取所有的构造方法,因为默认调取的是toString,所以是以字符串显示的。
              //获取person类的字节码文件对象
        Class c=Person.class;
    Constructor[] cons=c.getDeclaredConstructors();
        //遍历
        for(Constructor con:cons){//String获取出来是tostring类型,哪一个包下的
            System.out.println(con);
        }


如果获取单个有参构造(需要在方法内传入类中的参数,顺序内容一样。

Constructor con1=c.getConstructor(int.class,String.class);

如果获取单个无参构造:
Constructor con=c.getConstructor();
3、【数组】需要通过超级for遍历。单个不需要(对获取的对象进行遍历)


获取到构造并进行创建对象:
Object obj=con.newInstance("小红",18);有参
Object obj=c.newInstance();无参,快速创建对象。后面的操作基本用它。
字节码文件对象:
获取指定的成员变量并使用

//获取指定的成员变量并使用
        //获取person的字节码文件对象
        Class c=Class.forName("com.oracle.demo02.Person");
        //获取公共成员变量
        Field f=c.getField("name");
        //给成员变量赋值
        //快速创建person对象
        Object obj=c.newInstance();
        //调取方法
        //给成员变量赋值
        f.set(obj, "哈哈哈哈哈");
        System.out.println(obj);

        //获取文件字节码对象,现在只是赋值没有输出
        Class c=Person.class;
        //调取公共有参成员方法对象
        Method m=c.getMethod("sleep", String.class);
        //快速创建person对象
        Person p =(Person)c.newInstance();
        //调用方法
        m.invoke(p, "智障障");


top1:反射的两个使用案例,泛型擦除

public class Demo05 {  //反射擦除泛型是因为泛型不进class文件
    public static void main(String[] args) throws NoSuchMethodException, SecurityException, 
IllegalAccessException, IllegalArgumentException, InvocationTargetException {
//泛型擦除 ArrayList<Integer> arr=new ArrayList<Integer>(); arr.add(1); //arr.add("aaa"); //获取ArrayList类的class对象 Class c=arr.getClass();//object 获取到没被限定泛型时的Object类对象 //获取add方法对象 Method m=c.getMethod("add", Object.class);//获取arr里的方法add,无泛型都可传入。 //调用add方法 m.invoke(arr, "aaa");//m获取到无泛型的add方法,就可以随意传入各种类型了。相当于时光回溯到没有泛型之前。 System.out.println(arr); }

 流程,通过先获取到并没有被泛型限制的arr集合对象,获得一个可以存取所有数据的Object对象,然后接着获取arr下方法add,通过成员变量的有参方法,传入,再调用invoke方法添加(无泛型类,想要存取的值)就可以了。

top2:通过反射配置文件

设置三个实体类:
public class Person {
        public void eat(){
            System.out.println("人吃饭");
        }
}
public class Student {
    public void study(){
        System.out.println("学生学习");
    }

public class Worker {
    public void work(){
        System.out.println("工作");
    }

配置一个往里面存取键值对

ClassName=com.oracle.demo03.Worker
MethodName=work
配置完成后,只需要改这里的信息,就可以再次执行其他对象
public static void main(String[] args) throws IOException, ClassNotFoundException, 
NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
//明确数据源 FileReader fr=new FileReader("src/com/oracle/demo03/config.properties"); //创建Properties集合 Properties pro=new Properties(); //将文件中的键值对读到集合中 pro.load(fr); //从集合中获取类名 String classname=pro.getProperty("ClassName"); //从集合中获取方法名 String methodname=pro.getProperty("MethodName"); //通过类名获取该类的字节码文件对象,也就是获取到在文件里被书写的类地址。 Class c=Class.forName(classname); //通过字节码文件对象获取指定方法对象 通过对象.方法()获取到 Method m=c.getMethod(methodname); //快速创建空参对象 Object obj=c.newInstance(); //调用 m.invoke(obj); }

原文地址:https://www.cnblogs.com/a199706/p/11479256.html