java中可以为所欲为的机制------反射

反射基础

在这里插入图片描述

反射基本概念

反射在程序运行过程中,动态的创建对象。
只要知道该类的名称,就可以使用它的字节码对象创建该类的一个对象,对于这个类中的任何一个对象和属性,我们都可以访问或者使用它。

反射的基石

——字节码对象
.java 文件通过 javac 命令编译后产生 .class 字节码文件,最后执行字节码文件

jvm把字节文件加载到内存中去,字节码文件就变成了字节码文件对象


字节码文件对象

字节码文件对象的类型是Class---->类型----->引用数据类型

获得类或者对象的字节码文件对象

  1. 通过Object类的getClass()方法
  2. 类型Class属性
  3. Class类的forName(类的全路径名)
Class Person{
    
        // 创建一个Person类

}

Class Student{
    
       // 创建一个Student类

}

public class ReflectDemo {
    
    
    public static void main(String[] args) throws Exception{
    
       // 为方便处理,此处将异常抛出
        // 1. 通过父类(Object)中的getClass()方法获得字节码对象
        Class personClass1=new Person().getClass();
        // 2. 通过class 属性获得
        Class studentClass1=Student.class;
        Class personClass2=Person.class;
        // 3. 通过forName()方法获得
        Class studentClass2=Class.forName("Reflect.ReflectDemo"); // 参数为全路径名,Reflect是我的包名,RelectDemo是我的类名
        System.out.println(personClass1.equals(personClass2));
 System.out.println(studentClass1.equals(studentClass2));
    }
}

输出

ture
ture

思考:同一个类的对象或者同一个类得到的字节码文件对象是否是同一个?
答:是同一个,创建类对象时,根据类的字节码文件创建,在程序运行时,只会加载一次字节码文件,所以同一个类的不同对象或者同一个类得到的字节码对象是同一个。

字节码文件的加载时机

注意:一个类的字节码文件只会加载一次

  1. new 一个类的时候
  2. 访问一个类的静态成员的是时候
  3. 调用一个类静态方法的时候
  4. 通过反射的方式创建一个类的字节码对象的时候
  5. 创建一个子类的对象的时候(使用父类对象指向子类对象)
  6. java命令执行一个字节码文件的时候

字节码文件对象的组成

类                            字节码文件对象   类型

构造方法---------------------> 构造方法对象  (Constructor)

成员方法---------------------> 成员方法对象   (Method)

成员变量---------------------> 成员变量对象   (Field)
构造方法对象
package Reflect;

import java.lang.reflect.Constructor;

/**
 * @author Steven
 * @create 2020-06-06 21:02
 */
public class ReflectDemo {
    
    
    public static void main(String[] args) throws Exception{
    
       // 为方便处理,此处将异常抛出
        // 1. 通过父类(Object)中的getClass()方法获得字节码对象
        Class personClass1=new Person().getClass();
        // 2. 通过class 属性获得
        Class studentClass1=Student.class;
        Class personClass2=Person.class;
        // 3. 通过forName()方法获得
        Class studentClass2=Class.forName("Reflect.Student");
        System.out.println(personClass1.equals(personClass2));
        System.out.println(studentClass1.equals(studentClass2));
        // 获得Person类的所有构造方法对象
        Constructor[] constructors=personClass1.getConstructors();
        for (Constructor c:constructors
             ) {
    
    
            System.out.println(c);
            /*======此处将会输出:=======
             public Reflect.Person()
             public Reflect.Person(java.lang.String)
             public Reflect.Person(int)
             public Reflect.Person(java.lang.String,int)
             */
        }
        Constructor constructor=personClass1.getConstructor(String.class);
        System.out.println(constructor);
        /*======此处会输出=========
        *public Reflect.Person(java.lang.String)
        */
        //   运用构造方法对象创建对象
        Object o=constructor.newInstance("Steven");
        System.out.println(o);
        Person p1= (Person) constructor.newInstance("Steven");
        System.out.println(p1);
        /*======此处会输出=========
         姓名: Steven
         年龄: 18
         姓名: Steven
         年龄: 18
         */

    }
}

class Person{
    
    
    String name;
    int age=18;

    // 定义构造方法的4个重载方法
    public Person(String name, int age) {
    
    
        this.name = name;
        this.age = age;
    }

    public Person(int age) {
    
    
        this.age = age;
    }

    public Person(String name) {
    
    
        this.name = name;
    }

    public Person() {
    
    
    }

    @Override
    public String toString() {
    
    
        return "姓名: "+this.name+"\n年龄: "+this.age;
    }
}

class Student{
    
    

}


取得构造器的常用API
public Constructor getConstructor(Class<?>… parameterTypes); // 得到某一个构造方法的构造方法对象
public Constructor<?>[] getConstructors(); //得到该字节码文件对象的所有公有的(public)构造方法
注:以上方法只能得到公共的构造方法;若想得到私有的构造方法
public Constructor getDeclaredConstructor(Class<?>… parameterTypes);
public Constructor<?>[] getDeclaredConstructors();



import java.lang.reflect.Constructor;

/**
 * @author Steven
 * @create 2020-06-07 0:04
 */

public class ReflectDemo2 {
    
    
    public static void main(String[] args) throws Exception {
    
      //  将异常抛出
        //完整的运用构造器创建对象,JDK中常见

        //   Hello hello = new Hello();   构造方法私有化,不能访问

        //  使用反射方式强制实例化对象
        Class hello = Hello.class;

//        Constructor constructor=hello.getConstructor();        constructor 只能得到公共的构造方法  public
        Constructor constructor = hello.getDeclaredConstructor();

//      会报IllegalAccessException异常,非法访问错误,可以设置强制访问       注:此时已经拿到构造器对象
        constructor.setAccessible(true);   // 将构造器访问权限设置为true
        Object o = constructor.newInstance();
        System.out.println(o);

        // 便携方法创建
        Class t=T.class;
        Object j=t.newInstance();
        System.out.println(j);
        
        // 便携方法的缺点:
        // 不能访问非公有的构造方法和不含无参构造方法的类
    }
}

class Hello {
    
    
    private Hello() {
    
    
    }
    @Override
    public String toString() {
    
    
        return "Hello world";
    }
}

class T{
    
    
    @Override
    public String toString() {
    
    
        return "hello~~~Steven";
    }
}
/*
* 此输出:
* Hello world
* hello~~~Steven
* */

成员方法对象和成员变量对象可参照构造方法对象学习

后续更新中……

猜你喜欢

转载自blog.csdn.net/weixin_45727731/article/details/106597854
今日推荐