java入门篇 (31)反射机制

一、反射机制

1.1 概念

当一个类加载进内存后,会生成相应的字节码文件,我们可以通过这个字节码文件获得类的一些信息,来得到类的属性,调用类的一些功能。

1.2 获取类的字节码文件对象

  • 通过Object类中的 getClass()

所有该类的实例通过该方法获得的字节码对象是一样的

public class text1 {
    String name;
    String sge;

    public static void main(String[] args) {
        text1 a = new text1();
        text1 b = new text1();
       Class class1 = a.getClass();
       Class class2 = b.getClass();
        System.out.println(class1 == class2);
    }
}

  • 通过类的静态属性获得

通过类的静态class属性与类的getclass()方法获得的字节码文件对象时一样的。

public class text1 {
    String name;
    String sge;

        public static void main(String[] args) {
        text1 a = new text1();
        Class class1 = a.getClass();
        Class class3 = text1.class;
        System.out.println(class1 == class3);
    }
}

  • 通过 Class 类中的一个静态方法来获取

  • static Class<?> forName (String className)
    返回与带有给定字符串名的类或接口相关联的 Class 对象。
    通过一个类的全路径,就可以获取到该类的字节码文件对象
    类的全路径: 类的包名+类的名称:

public class text1 {
    String name;
    String sge;
        public static void main(String[] args) throws ClassNotFoundException {
            Class class3 = text1.class;
            Class class4 = Class.forName("net.text1");
            System.out.println(class3 == class4);
    }
}

结果:
true

1.3 进一步通过类的字节码文件对象获取类的构造方法

  • public Constructor<?>[] getConstructors ()
    获取所有的构造方法不包含私有的

示例:

public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException {
            Class class3 = text1.class;
            Constructor[] constructor = class3.getConstructors();
            for(Constructor cons: constructor) {
                System.out.println(cons);
            }

        }

结果:
public net.text1()
public net.text1(java.lang.String,java.lang.String)
  • public Constructor<?>[] getDeclaredConstructors ()
    获取所有的构造方法 包括私有的
  • public Constructor getConstructor (Class < ? >…parameterTypes)
    获取单个的构造方法 不包含私有的
  • public Constructor getDeclaredConstructor (Class < ? >…parameterTypes)
    获取单个的构造方法包含私有的

示例:

public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException {
            Class class3 = text1.class;
            System.out.println(class3.getDeclaredConstructor());
            System.out.println(class3.getConstructor(String.class, String.class));
        }
        
结果:
public net.text1()
public net.text1(java.lang.String,java.lang.String)

注意:
获取单个构造方法时,你要获什么构造方法,里面就是对应类型的class类型。

1.4 进一步通过构造方法创建类对象

  • newInstance(Object…initargs)
    使用此 Constructor 对象表示的构造方法来创建该类的实例,并用指定的初始化方法初始化该实例。
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
            Class class3 = text1.class;
            Constructor constructor = class3.getDeclaredConstructor();
            Constructor constructor1 = class3.getConstructor(String.class, String.class);
            Object o = constructor.newInstance();
            Object o1 = constructor1.newInstance("张三","10");
            text1 text = (text1)o;
            text1 text2 = (text1)o1;
            System.out.println(text.name + " " + text.age);
            System.out.println(text2.name + " " + text2.age);
        }
        
结果:
null null
张三 10

  • void setAccessible(boolean value)
    该方法可以取消语法规则,如下例在使用了该方法后,我们可以通过类的私有构造方法来创建实例。
public static void main(String[] args) throws Exception{
          Class class1 = text1.class;
            Constructor constructor = class1.getDeclaredConstructor(String.class, String.class);
            constructor.setAccessible(false);
            Object o = constructor.newInstance("张三", "19");
            text1 te = (text1)o;
            System.out.println(te.name + " " + te.age);
        }

1.5 通过构造方法获取类的属性(成员变量)

  • public Field[] getFields ()
    获取所有的成员变量包含从父类继承过来的
  • public Field[] getDeclaredFields ()
    获取所有的成员变量 包含私有的 也包含从父类继承过来的成员变量
public static void main(String[] args) throws Exception{
                Class class1 = text1.class;
                Field[] fields = class1.getFields();
                for(Field field : fields) {
                    System.out.println(field);
                }
        }
  • public Field getField (String name)
    获取单个成员变量
  • public Field getDeclaredField (String name)
    获取单个成员变量,包括私有的
 public static void main(String[] args) throws Exception{
            Class class1 = text1.class;
            Field one = class1.getField("TWO");
            System.out.println(one);
        }

注意:获取单个成员变量时,参数是成员变量的名称。

1.6 给对象的成员变量设置

  • void set (Object obj, Object value)
    给指定类的实例的成员变量设值。

步骤:

  • 通过类的字节码文件对象创建类的实例
  • 通过反射机制获取类的成员变量的对象
  • 通过set方法给指定类的实例的成员变量设值
  • 通过get方法得到设置后的成员变量的值

注意:哪个成员变量的对象调用的set方法只能设值该成员变量的值

示例:

 public static void main(String[] args) throws Exception{
            Class class1 = student.class;
            Field name = class1.getDeclaredField("name");
            name.setAccessible(true);
            Object o =class1.newInstance();
            name.set(o, "张三");
            Object o1 = name.get(o);
            System.out.println(o1);
        }

1.8 获取类的成员方法

  • public Method[] clazz.getMethods()
    获取类的所有成员方法,不包括私有的

  • public Method[] clazz.getDeclaredMethods()
    获取类的所有的成员方法,包括私有的,不包括从父类继承的。

  • public Method getMethod(String method_name, 参数类型的class类型列表)
    获取类的某一个成员方法,不包括私有的

  • public Method getDeclaredMethod(String method_name, 参数类型的class类型列表)
    获取类的某一个成员方法,包括私有的

示例:


  public static void main(String[] args) throws Exception {
        Class class1 = student.class;
        Method[] methods = class1.getMethods();
        for (Method method : methods) {
            System.out.println(method);
        }
        System.out.println("---------------------------------------");
        Method[] method1 = class1.getDeclaredMethods();
        for (Method method2 : method1) {
            System.out.println(method2);
        }
        System.out.println("---------------------------------------");
        Method method = class1.getDeclaredMethod("show2");
        System.out.println(method);
        Method method2 = class1.getMethod("show1", int.class);
        System.out.println(method2);
    }

1.9 调用类的成员方法

  • Object invoke (Object obj, Object…args)
    对带有指定参数的指定对象调用由此 Method 对象表示的底层方法。
public static void main(String[] args) throws Exception {
        Class class1 = student.class;
        Method method = class1.getDeclaredMethod("show2");
        method.setAccessible(true);
        Object o = class1.newInstance();
        method.invoke(o);
    }
  
结果:
show2方法

注意:如果调用的方法要传参数的话,就正常的传参即可。

1.10 总结

通过反射机制获取类的成员方法参数是参数类型的class类型,获取类的属性的参数是属性名称。

二、通过反射运行配置文件的内容

2.1 读取简单配置文件案例

内容:通过读取配置文件里的内容,来执行配置文件中的方法。

public class text {
    public static void main(String[] args) throws Exception {
        Properties pro = new Properties();
        pro.load(new FileReader("config"));
        Class class1 = Class.forName(pro.getProperty("classname"));
        Method method = class1.getDeclaredMethod(pro.getProperty("methodname"));
        method.setAccessible(true);
        Object o = class1.newInstance();
        method.invoke(o);
    }
}

2.2 通过反射越过泛型检查

案例:
我给你ArrayList 的一个对象,我想在这个集合中添加一个字符串数据,如何实现呢?
思路:
泛型:只在编译期有效,运行期就擦除了
反射机制在运行期发挥作用

public class txet {
    public static void main(String[] args) throws Exception {
        ArrayList<Integer> list = new ArrayList();
        list.add(90);
        list.add(20);
        list.add(19);
        Class class1 = list.getClass();
        Method add = class1.getMethod("add", Object.class);
        add.invoke(list,"张三");
        System.out.println(list);
    }
}

结果:
[90, 20, 19, 张三]

还可以这样遍历:

 for(Object obj : list) {
            System.out.println(obj);
        }

2.3 写一个工具类设置某个对象的某个成员变量为指定的值

工具类:

public class Set {
    public static void set(Object obj, String old_valeue, Object new_value) throws Exception {
        Class class1 = obj.getClass();
        Field field = class1.getDeclaredField(old_valeue);
        field.setAccessible(true);
        field.set(obj, new_value);
    }
}

测试:

public class txet {
    public static void main(String[] args) throws Exception {
        student stu = new student();
        Set.set(stu, "name", "张三");
        Set.set(stu, "age", "18");
        System.out.println(stu.name + " " + stu.age);
    }
}

结果:

张三 18
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值