Java-反射1


1.反射

概述:

  • 通过一个Class文件对象去使用或者修改文件对象中的成员变量,构造方法,成员方法(无论是否私有,都能获取并使用)

之前学习:

  • 我们在使用成员之前,得先有一个java文件,然后在实例化的时候,new一下就完事了。
    Person p = new Person();
    p.eat(“汉堡”);

现在的船新概念:

  • 总归来说,无论是调用什么成员,都是有个对象,归根结底,对象是根据类来的,实际上底层是依赖一个class文件
    对于java程序来说,依赖的是这个class文件对应的Class文件对象。

class类:

  • 成员变量:Field
  • 构造方法:Constructor
  • 成员方法:Method

如何获取一个类的对应的Class文件对象呢?

  • 方式1:通过Object类中的getClass()方法,返回此Object类的运行时的类
  • 方式2:在不new的前提下,获取该类的class文件对象,java中每一个类都有一个静态的属性class
  • 方式3:Class类中有一个静态的方法,获取该类的class文件对象 (最常用的)

获取对象对应的class文件对象代码

public class ReflexDemo1 {
    public static void main(String[] args) {
        //方式一:通过Object类中的getClass()方法,返回此Object类运行时的类
        Person person1 = new Person();
        Class<? extends Person> c1 = person1.getClass();
        Person person2 = new Person();
        Class<? extends Person> c2 = person2.getClass();
        System.out.println(c1 == c2); //true

        //方式二:在不 new 的情况下,获取该类的class文件对象,java中的每一个类都有一个静态的属性class
        Class<Person> c3 = Person.class;
        System.out.println(c1 == c3); //true
        System.out.println(c2 == c3); //true

        //方式三:Class类中有一个静态方法,获取该类的class文件对象(最常用的)
        //static Class<?> forName(String className)
        //返回与给定字符串名称的类或接口相关联的 类对象。
        try {
            Class<?>  c4 = Class.forName("com.bigdat.java.day29.Person");
            System.out.println(c4);
            System.out.println(c1 == c4); //true
            System.out.println(c1 == c4); //true
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

如何通过反射获取Class文件对象并使用其中的构造方法创建对象呢?

  • getConstructors() 返回一个包含Constructor对象的数组,反映由此Constructor对象表示的类的所有公共类函数
  • getDeclaredConstructors() 获取的是该类中的所有构造方法,包括私有,被保护的,默认的,公共的
  • getConstructor() 返回一个 Constructor对象,该对象反映 Constructor对象表示的类的指定的公共 类函数。
  • getDeclaredConstructor() 获取单个私有的带参数的构造方法

注意点:

  • newInstance(Object… initargs)
    使用此 Constructor对象表示的构造函数,使用指定的初始化参数来创建和初始化构造函数的声明类的新实例。如果使用带参数的构造方法newInstance创建对象,参数必须一样。形如:Object o = con1.newInstance(“张三”);
  • 如果获取带参数的构造方法,里面填的参数是:**类型.class**
    如:Constructor<?> con2 = c1.getDeclaredConstructor(String.class, int.class);
public class ReflexDemo2 {
    public static void main(String[] args) {
        //获取person类的Class文件对象
        Class<?> c1 = null;
        try {
            c1 = Class.forName("com.bigdatjava.day29.Person");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

        //获取Class文件对象的构造方法
        //public Constructor<?>[] getConstructors() throws SecurityException
        //返回一个包含Constructor对象的数组,反应由此Constructor对象表示的类的所有的公共类函数
        Constructor<?>[] cons1 = c1.getConstructors();
        for (Constructor<?> c : cons1) {
            System.out.println(c);
        }
        System.out.println("===========================================================");
        //public Constructor<?>[] getDeclaredConstructors() throws SecurityException
        //返回Constructor 对象表名的类声明的所有Constructor对象的数组类
        //获取的是该类中的所有构造方法,包括私有,被保护,默认和公共的
        Constructor<?>[] cons2 = c1.getDeclaredConstructors();
        for (Constructor<?> c : cons2) {
            System.out.println(c);
        }
        System.out.println("=================================================================");
        //获取单个的构造方法
        //Constructor<T> getConstructor(类<?>... parameterTypes)
        //返回一个 Constructor对象,该对象反映 Constructor对象表示的类的指定的公共 类函数。
        Constructor<?> con1 = null;
        try {
            con1 = c1.getConstructor(String.class);
            System.out.println(con1);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        //获取单个私有的带参数的构造方法
//        Constructor<?> con2 = c1.getConstructor(String.class, int.class);
//        System.out.println(con2);
        Constructor<?> con2 = null;
        try {
            con2 = c1.getDeclaredConstructor(String.class, int.class);
            System.out.println(con2);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        System.out.println("======================================================================");
        //使用公共的构造方法创建对象
        //使用公共的构造方法创建对象
        //T newInstance(Object... initargs)
        //使用此 Constructor对象表示的构造函数,使用指定的初始化参数来创建和初始化构造函数的声明类的新实例。
        try {
            Object o = con1.newInstance("我真蠢!");
            Person p = (Person)o; // 向下转型
            System.out.println(p);
        } catch (Exception e) {
            e.printStackTrace();
        }
        try {
            con2.setAccessible(true);
            Object two = con2.newInstance("我是小垃圾", 19);
            // 向下转型
            Person o1 = (Person) two;
            System.out.println(o1);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

通过反射获取Class文件对象中私有的构造方法并创建对象

重点

  • 当还是象访问公共对象去访问私有变量时会报 IllegalAccessException 非法的访问异常

解决办法:暴力访问

  • 通过setAccessible(true)方法暴力访问。值是true的化,表示反射对象在使用的时候,取消Java语言的访问检查
public class ReflexDemo3 {
    public static void main(String[] args) {
        Class<?> a = null;
        try {
             a = Class.forName("com.bigdat.java.day29.Person");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        //获取私有的构造方法
        Constructor<?> dec1 = null;
        try {
             dec1 = a.getDeclaredConstructor(String.class, int.class);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        try {
            // .IllegalAccessException 非法的访问异常
            //构造方法是私有的,可以获取的到,但是不能这么使用
            //通过构造方法创建对象
            //暴力访问
            dec1.setAccessible(true); // 如果这里是 true 的话,表示反射对象在这里用的话,取消Java语言的访问检查
            Object xh = dec1.newInstance("小花", 100);
            //向下转型
            Person p = (Person) xh;
            System.out.println(p);
            p.eat("红烧肉");
        } catch (Exception e) {
            e.printStackTrace();
        }
        }


    }

反射获取类Class文件对象中的成员变量并使用

  • getFields() 返回包含一个数组 Field对象反射由此表示的类或接口的所有可访问的公共字段 类对象。获取当前类所有被public修饰的成员变量
  • getDeclaredFields() 返回的数组 Field对象反映此表示的类或接口声明的所有字段 类对象。获取当前类中所有的成员变量,包括私有的,公共的,被保护的,默认的字段,不包括继承的字段。
  • getField() 获取单个的成员变量
  • getDeclaredField() 获取私有的成员变量并赋值
  • 暴力访问: name.setAccessible(true);
public class ReflexDemo4 {
    public static void main(String[] args)throws Exception {
        Class<?> c1 = null;
        //获取Class的文件对象
        try {
          c1 = forName("com.bigdat.java.day29.Person");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        //Field[] getFields()
        //返回一个包含一个数组的 Filed 对象反射由此表示的类或接口的所有可访问的公共字段 类对象。
        //获取当前类所有被public修饰的成员变量
        Field[] fields = c1.getFields();
        for (Field field : fields) {
            System.out.println(field); //public java.lang.String com.bigdat.java.day29.Person.id
        }
        System.out.println("==============================================================");
        //Field[] getDeclaredFields()
        //返回的数组 Field对象反映此表示的类或接口声明的所有字段 类对象。
        //获取当前类中所有的成员变量,包括私有的,公共的,被保护的,默认的字段,不包括继承的字段。
        Field[] dec = c1.getDeclaredFields();
        for (Field field : dec) {
            System.out.println(field);
        }
        System.out.println("-----------------------------------------------------------------");
        //此方法并不能获得该类继承的其父类的任何属性
         Class<?> c2 = null;
        try {
            c2 = forName("com.bigdat.java.day29.B");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        Field[] declaredFields = c2.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            System.out.println(declaredField);
        }

        System.out.println("========================================================");
        //获取Class文件的对象
        Class<?> c = forName("com.bigdat.java.day29.Person");
        //通过 getConstructor 方法来创建一个构造器
        Constructor<?> ctr = c.getConstructor();
        //通过构造方法来创建一个对象
        Object o = ctr.newInstance();

        //获取单个的成员变量
        Field id = c1.getField("id");
        //void set(Object obj, Object value)
        //将指定对象参数上的此 Field对象表示的字段设置为指定的新值。
        //id.set(o,"1001");//给对象o中的成员变量id赋值为"1001"
        id.set(o, "1001");
        System.out.println(o);

        //获取私有的成员变量并赋值
        Field name = c1.getDeclaredField("name");
        name.setAccessible(true); // 在使用私有的成员变量时需要进行暴力访问
        name.set(o, "名字");
        System.out.println(o); // IllegalAccessException 不暴力访问的话会报异常
        System.out.println("================================================================");
        Field age = c1.getDeclaredField("age");
        age.set(o, 101);
        System.out.println(o);
        Field address = c1.getDeclaredField("address");
        address.set(o,"中国-云南-保山");
        System.out.println(o);
    }
}
class A{
    private String aaa;
    public int bbb;
}
class B extends A{
}

通过反射获取Class文件对象中的成员方法并使用

-== Method[] getMethods()== 返回包含一个数组 方法对象反射由此表示的类或接口的所有公共方法 类对象,包括那些由类或接口和那些从超类和超接口继承的声明。

  • getDeclaredMethods() 获取本类中的所有方法,包括私有的,被保护的,默认的,公共的。不获取继承关系父类中的方法
public class ReflexDemo5 {
    public static void main(String[] args) throws Exception{
        //获取person类的class文件对象
        Class<?> c = Class.forName("com.bigdat.java.day29.Person");
        //获取方法
        //Method[] getMethods()
        //返回包含一个数组 方法对象反射由此表示的类或接口的所有公共方法 类对象,包括那些由类或接口和那些从超类和超接口继承的声明。
        //获取本类以及父类中所有的公共方法(被public所修饰的方法)
        Method[] methods = c.getMethods();
        for (Method method : methods) {
            System.out.println(method);
        }
        System.out.println("===========================================================");
        //获取本类中的所有方法,包括私有,被保护,默认,公共的方法,但是不获取继承关系的父类方法
        Method[] declaredMethods = c.getDeclaredMethods();
        for (Method declaredMethod : declaredMethods) {
            System.out.println(declaredMethod);
        }
        System.out.println("======================================================================");
        //创建对象的构造器
        Constructor<?>  con  = c.getConstructor();
        Object o = con.newInstance();

        //获取单个的方法并使用
        //Object invoke(Object obj, Object... args)
        //在具有指定参数的 方法对象上调用此 方法对象表示的底层方法。
        Method fun1 = c.getMethod("fun1" );
        fun1.invoke( o );
        System.out.println("================================================================================");
        //获取私有的成员方法使用
        Method fun2 = c.getDeclaredMethod("fun2",String.class);
        `fun2.setAccessible(true);`
        fun2.invoke( o ,"你好!");
        System.out.println("==================================================================================");
        Method fun3 = c.getDeclaredMethod("fun3");
        fun3.invoke( o );
        Method fun4 = c.getDeclaredMethod("fun4" );
        fun4.invoke( o );
    }
}

原创文章,作者:6024010,如若转载,请注明出处:https://blog.ytso.com/244396.html

(0)
上一篇 2022年4月17日
下一篇 2022年4月17日

相关推荐

发表回复

登录后才能评论