day26 Java 反射


I know, i know
地球另一端有你陪我




一、类加载

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

	加载
		就是指将class文件读入内存,并为之创建一个Class对象
		任何类被使用时系统都会建立一个Class对象
	连接
		验证 是否有正确的内部结构,并和其他类协调一致
		准备 负责为类的静态成员分配内存,并设置默认初始化值
	解析 
		将类的二进制数据中的符号引用替换为直接引用
	初始化 
		静态初始化 — 父类初始化 — 子类初始化
		静态代码块 — 构造代码块 — 构造函数
		父类 — 子类

二、反射

	反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;
	对于任意一个对象,都能够调用它的任意一个方法和属性;
	这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制

1、获取 class对象

/*
        反射:就是通过class文件对象去使用该文件中的成员变量,
        构造方法,成员方法

        我们之前写过很多的类java文件,再去实例化的时候,直接new就可以了
        Person person = new Person();
        person.eat();

        但是,现在并没有现成的java文件,只拿到一个class文件怎么办呢?
        换句话说,就算你是用java文件去创建对象,底层依旧是需要一个class文件
        也就是说想要创建对象,就必须要得到一个class文件,
        也就是获取该class的文件对象

        class类:
            成员变量: Fields
            构造方法: Constructor
            成员方法: Method

        1、怎么获取到class文件对象呢?
            1)通过Object中的getClass()方法获取,返回该Object的运行时类
            2)通过类名获取静态属性class
            3)Class类中的静态方法
            public static 类<?> forName(String className)
                返回与给定字符串名称的类或接口相关联的类对象。
 */
public class Reflect1 {
    
    

    public static void main(String[] args) throws Exception{
    
    

        Pokemon p1 = new Pokemon("piplup");
        Pokemon p2 = new Pokemon("ralts");
        Class<? extends Pokemon> c1 = p1.getClass();
        Class<? extends Pokemon> c2 = p2.getClass();
        //	方式1:
        //	通过Object中的getClass()方法获取
        System.out.println(c1==c2);
        System.out.println("-----------------------");
        //	方式2:
        //	通过类名获取静态属性class
        Class<Pokemon> c3 = Pokemon.class;
        System.out.println(c3==c1);
        System.out.println("-----------------------");

        //	方式3:
        //	Class类中的静态方法(开发中最常用的方式)
        //	public static 类<?> forName(String className)
        //	返回与给定字符串名称的类或接口相关联的类对象。
        //	注意:这里需要写该类再本项目中完整路径,不加 src
        Class<?> c4 = Class.forName(
                "javase.day25.Reflect.Pokemon");
        System.out.println(c4==c3);
    }
}

2、获取构造方法 & 对象

public class Reflect2 {
    
    

    public static void main(String[] args) throws Exception{
    
    
        //  获取class文件对象
        Class<?> c = Class.forName("javase.day25.Reflect.Pokemon");

        //  public Constructor<?>[] getConstructors()
        //  获取该类中所有 public 的构造方法
        Constructor<?>[] sc = c.getConstructors();
        for (Constructor<?> constructor : sc) {
    
    
            System.out.println(constructor);
        }
        System.out.println("-----------------------------");

        //  public Constructor<?>[] getDeclaredConstructors()
        //  获取所有的构造方法
        //  包括public,protect,默认(包)访问和 private 字段
        Constructor<?>[] dcs = c.getDeclaredConstructors();
        for (Constructor<?> constructor : dcs) {
    
    
            System.out.println(constructor);
        }
        System.out.println("----------------------------");

        //  public Constructor<T> getConstructor(
        //										Class<?>... parameterTypes)
        //  获取单个 public 构造方法
        Constructor<?> con = c.getConstructor(String.class, int.class);
        System.out.println(con);
        System.out.println("---------------------------");

        //  public Constructor<T> getDeclaredConstructor(
        //											类<?>...parameterTypes)
        //  获取任意构造方法
        //  包括 public,protect,默认(包)访问和 private 字段
        Constructor<?> dc = c.getDeclaredConstructor();
        System.out.println(dc);
        System.out.println("--------------------------");

        
        //  创建对象
        //  public T newInstance(Object... initargs)
        //  使用指定参数和构造方法创建对象
        Object o1 = con.newInstance("piplup",5);
        System.out.println(o1);
        System.out.println("--------------------------");

        //  在通过使用获取到私有的构造方法创建对象的时候,报错非法访问异常
        //  java.lang.IllegalAccessException
        //  public T setAccessible(true)
        //  暴力访问
        dc.setAccessible(true);
        Object o2 = dc.newInstance();
        System.out.println(o2);
    }
}

3、获取成员变量 & 对象赋值

public class Reflect3 {
    
    

    public static void main(String[] args) throws Exception{
    
    

        Class<?> c = Class.forName("javase.day25.Reflect.Pokemon");

        //  public Field[] getFields()
        //  获取该类中所有 public 的成员变量
        Field[] fields = c.getFields();
        for (Field field : fields) {
    
    
            System.out.println(field);
        }
        System.out.println("-------------------------");

        //  public Field[] getDeclaredFields()
        //  获取所有的成员变量
        //  包括public,protect,默认(包)访问和 private 字段
        Field[] declaredFields = c.getDeclaredFields();
        for (Field declaredField : declaredFields) {
    
    
            System.out.println(declaredField);
        }
        System.out.println("-------------------------");

        //  public Field getField(String name)
        //  获取单个 public 的成员变量
        //  name - 字段名称
        Field gender = c.getField("gender");
        System.out.println(gender);
        System.out.println("-------------------------");

        //  public Field getDeclaredField(String name)
        //  获取任意成员变量
        //  包括public,protect,默认(包)访问和 private 字段
        Field name = c.getDeclaredField("name");
        Field level = c.getDeclaredField("level");
        System.out.println(name);
        System.out.println("-------------------------");


        //  通过反射获取无参构造方法
        //  然后再通过反射一个一个成员变量进行赋值
        Constructor<?> dc = c.getDeclaredConstructor();
        dc.setAccessible(true);
        Object o = dc.newInstance();

        //  Field类中有一个方法可以给成员变量进行赋值
        //  void set(Object obj, Object value)
        //  暴力访问
        name.setAccessible(true);
        level.setAccessible(true);

        name.set(o,"ralts");
        level.set(o,5);
        gender.set(o,1);

        System.out.println(o);
    }
}

4、获取成员变量 & 对象赋值

public class Reflect4 {
    
    

    public static void main(String[] args) throws Exception{
    
    

        Class<?> c = Class.forName("javase.day25.Reflect.Pokemon");

        //  public 方法[] getMethods()
        //  获取所有的成员 public 的方法,还包括父类的
        Method[] methods = c.getMethods();
        for (Method method : methods) {
    
    
            System.out.println(method);
        }
        System.out.println("---------------------------");

        //  public 方法[] getDeclaredMethods()
        //  获取所有的成员的方法,仅自身
        Method[] declaredMethods = c.getDeclaredMethods();
        for (Method declaredMethod : declaredMethods) {
    
    
            System.out.println(declaredMethod);
        }
        System.out.println("---------------------------");

        //  public 方法 getMethod(String name,类<?>... parameterTypes)
        //  获取一个指名的 public 方法
        //  注意:只写方法名,不写小括号
        Method funlevel = c.getMethod("funlevel", int.class);
        System.out.println(funlevel);
        System.out.println("---------------------------");

        //  public 方法 getDeclaredMethod(String name,类<?>... parameterTypes)
        //  获取任意一个指名方法
        Method funname = c.getDeclaredMethod("funname", String.class);
        System.out.println(funname);
        System.out.println("---------------------------");


        //  获取show方法并调用
        //  创建对象
        Constructor<?> con = c.getConstructor(String.class, int.class);
        Object o = con.newInstance("piplup",5);

        //  Object invoke(Object obj, Object... args)
        //  在具有指定参数的 方法对象上调用此 方法对象表示的底层方法
        funlevel.invoke(o,5);

        //  private 方法,暴力访问
        funname.setAccessible(true);
        funname.invoke(o,"piplup");
    }
}

5、通过配置文件运行类中的方法

配置
里面的内容基本上都是 键–值 成对成对存在的

  例:
    className=javase.day27.Pokemon
    methodName=study
//	测试类
public class Pokemon {
    
    

    public void study(){
    
    
        System.out.println("学会了撞击");
    }
}
public class Reflect1 {
    
    

    public static void main(String[] args) throws Exception{
    
    

        //在此之前是通过创建对象,调用方法
        //学习反射之后,ava里面提供了一个配置文件类
        //Properties
        //获得、读取配置文件
        Properties properties = new Properties();
        FileReader fr = new FileReader("configure.txt");
        properties.load(fr);
        fr.close();
        String className = properties.getProperty("className");
//        System.out.println(className);
        String methodName = properties.getProperty("methodName");
//        System.out.println(methodName);

        //获取构造方法,获取对象
        Class<?> c = Class.forName(className);
        Constructor<?> dc = c.getDeclaredConstructor();
        dc.setAccessible(true);
        Object o = dc.newInstance();
        Pokemon p = (Pokemon) o;

        //获取方法,并调用
        Method dm = c.getDeclaredMethod(methodName);
        dm.setAccessible(true);
        dm.invoke(p);
    }
}
运行结果:学会了撞击

6、修改成员变量方法

   写一个方法
    public void setProperty(Object obj, String propertyName
                          , Object value){},
    此方法可将obj对象中名为propertyName的属性的值设置为value
    可以修改 private 成员
public class Reflect2 {
    
    

    public static void main(String[] args) {
    
    

        Pokemon p = new Pokemon();

        Reflect2.setProterty(p,"name","piplup");
        Reflect2.setProterty(p,"level",5);

        System.out.println(p);

    }

    public static void setProterty(Object obj, String propertyName
                                 , Object value) {
    
    
        //  获取 class 对象
        Class<?> c = obj.getClass();

        Field df = null;
        try {
    
    
            //  获取成员变量并修改
            df = c.getDeclaredField(propertyName);
            df.setAccessible(true);
            df.set(obj,value);

            } catch (IllegalAccessException | NoSuchFieldException e) {
    
    
            e.printStackTrace();
        }
    }
}

总结

反射
获取 class 对象

Class<?> c4 = Class.forName("javase.day25.Reflect.Pokemon");

获取所有构造方法

public Constructor<?>[] getDeclaredConstructors()

利用指定构造方法创建对象

public T newInstance(Object... initargs)

暴力访问
注:访问非公共时使用,用到谁就暴力访问谁

public T setAccessible(true)

获取所有成员变量

public Field[] getDeclaredFields()

对指定对象的成员变量赋值

void set(Object obj, Object value)

获取所有成员方法

public 方法[] getDeclaredMethods()

在指定对象上调用指定方法

Object invoke(Object obj, Object... args)

猜你喜欢

转载自blog.csdn.net/qq_41464008/article/details/120988241
今日推荐