Java反射机制的理解与运用,如何通过反射获取Class对象、获取成员变量、成员方法、构造方法以及如何通过暴力反射获取私有构造、私有方法、私有属性

反射

可以理解为是解剖class对象的一个技术,能解剖class对象的成员变量、成员方法、构造方法。使用反射可以让代码变的更通用,更灵活。

下面是类加载到内存的大致过程
在这里插入图片描述

万物皆对象

  1. Class文件有Class对象,描述Class对象的类叫做Class类
  2. 成员变量有Field对象,描述Field对象的类叫做Field类
  3. 成员方法有Method对象,描述Method对象的类叫做Method类
  4. 构造方法有Constructor对象,描述Constructor对象的类叫做Constructor类

想要使用反射,首先我们需要获取Class对象

获取Class对象

反射获取Class对象有三种方法,下面依次介绍,首先创建一个Person类

public class Person {
    private String name;
    private Integer age;
    public Person() {
    }
    private Person(Integer age,String name){ //私有构造
        this.age = age;
        this.name = name;
    }
    public Person(String name, Integer age) {
        this.name = name;
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Integer getAge() {
        return age;
    }
    public void setAge(Integer age) {
        this.age = age;
    }
    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
  1. 调用Object中的getClass方法:Class <?> getClass()
public class GetClass {
    @Test
    public void get1()throws Exception{
        Person person = new Person();
        Class<? extends Person> Class1 = person.getClass();
    }
}
  1. 不管是基本类型还是引用类型,jvm都为其提供了一个静态成员:class
public class GetClass {
    @Test
    public void get1()throws Exception{
        Class<Person> Class1 = Person.class;
    }
}

  1. Class类中的静态方法:static Class<?> forName(String className) className传递的是类的全限定名(包名.类名)

在这里插入图片描述

public class GetClass {
    @Test
    public void get1()throws Exception{
        Class<?> Class1 = Class.forName("test.Person");
    }
}

因为其参数为String,所以这种方法也可以和properties文件结合使用。
在这里插入图片描述

public class Main {
    public static void main(String[] args)throws Exception {
        Properties properties = new Properties();
        FileInputStream in = new FileInputStream("module1\\properties");
        properties.load(in);
        String className = properties.getProperty("className");
        System.out.println(className);
        Class<?> Class1 = Class.forName(className);
        System.out.println("Class1 = " + Class1);
    }
}

利用反射获取Class对象中的构造方法

Class类中的方法:
Constructor<?>[] getConstructors():获取所有public的构造方法

public class Main {
    public static void main(String[] args) {
        Class<Person> Class1 = Person.class; //获取Class对象
        Constructor<?>[] constructors = Class1.getConstructors(); //获取所有public的构造
        for (Constructor<?> constructor : constructors) {
            System.out.println(constructor);
        }
    }
}

在这里插入图片描述

利用反射获取空参公有构造并创建对象

Constructor<T> getConstructor(Class<?>... parameterTypes):获取指定的public的构造。其中的 parameterTypes为可变参数,可以传递0个或者多个参数。如果获取的是空参构造,参数不用写。如果获取的是有参构造,参数写参数类型的class对象

Constructor类中的方法:T newInstance(Object...initargs)创建对象,initargs传递的是构造方法的实参。如果根据无参构造new对象,initargs不写了,如果根据有参构造new对象,initargs传递实参 。

public class Main {
    public static void main(String[] args)throws Exception {
        Class<Person> Class1 = Person.class; //获取Class对象
        Constructor<Person> constructor = Class1.getConstructor();
        System.out.println("constructor = " + constructor);
        Person person = constructor.newInstance(); //好比是Person person = new Person()
        System.out.println(person);//好比是直接输出对象名,默认调用toString
    }
}

利用反射获取有参公有构造并创建对象

public class Main {
    public static void main(String[] args)throws Exception {
        Class<Person> aClass = Person.class; //获取Class对象
        Constructor<Person> constructor = aClass.getConstructor(String.class, Integer.class);
        System.out.println("constructor = " + constructor);
        Person person = constructor.newInstance("张三", 66); //创建对象,好比是Person person = new Person("张三",66)
        System.out.println(person);//好比是直接输出对象名,默认调用toString
    }
}

利用反射获取私有构造(暴力反射)

  1. Constructor<?>[] getDeclaredConstructors()获取所有构造方法,包括private
public class Main {
    public static void main(String[] args) {
        Class<Person> Class1 = Person.class;
        Constructor<?>[] dc = Class1.getDeclaredConstructors();
        for (Constructor<?> constructor : dc) {
            System.out.println(constructor);
        }
    }
}

从运行结果可以看到,私有的也拿到了。
在这里插入图片描述

  1. Constructor<T> getDeclaredConstructor(类<?>... parameterTypes)获取指定构造,包括private。parameterTypes为参数类型的class对象
  2. Constructor有一个父类叫做AccessibleObject ,里面有一个方法void setAccessible(boolean flag) 能修改访问权限,flag为true表示解除私有权限

以下是获取指定构造

public class Main {
    public static void main(String[] args) throws Exception{
        Class<Person> Class1 = Person.class;
        Constructor<Person> dc = Class1.getDeclaredConstructor(Integer.class, String.class);
        System.out.println("dc = " + dc);
        dc.setAccessible(true);//解除私有权限->暴力反射
        Person person = dc.newInstance(66,"张三");
        System.out.println(person);
    }
}

在这里插入图片描述

利用反射获取Class对象中的成员方法

Class类中方法:
Method[] getMethods():获取所有public的方法,包括父类中的public方法。

public class Main {
    public static void main(String[] args) throws Exception{
        Class<Person> Class1 = Person.class;
        Method[] methods = Class1.getMethods();
        for (Method method : methods) {
            System.out.println(method);
        }
    }
}

在这里插入图片描述

利用反射获取指定的公有方法

Class类中的方法:
Method getMethod(String name, Class<?>... parameterTypes):获取指定的public的成员方法,name传递方法名,parameterTypes:方法参数类型的class对象
Method对象中的方法:
Object invoke(Object obj, Object... args):执行方法,obj根据构造new出来的对象,args方法实参,如果有参数,直接传递实参,否则不用传。返回值Object接收被执行方法的返回值,如果方法没有返回值就不用接收。

public class Main {
    public static void main(String[] args) throws Exception{
        Class<Person> Class1 = Person.class;
        Constructor<Person> constructor = Class1.getConstructor();
        Person person = constructor.newInstance(); //创建对象
        Method setName = Class1.getMethod("setName", String.class);
        setName.invoke(person,"张三"); //相当于person.setName("张三")
        System.out.println(person);//好比调用toString方法
    }
}

还有另一种利用空参构造创建对象的快捷方式,不过jdk17已经不建议使用了

public class Main {
    public static void main(String[] args) throws Exception {
        Class<Person> Class1 = Person.class;
        Person person = Class1.newInstance(); //创建对象
        //获取有参方法
        Method setName = Class1.getMethod("setName", String.class);
        setName.invoke(person, "张三"); //相当于person.setName("张三")
        System.out.println(person);//好比调用toString方法
        //获取无参方法
        Object o = getName.invoke(person); //好比是person.getName()
        System.out.println(o);
    }
}

在这里插入图片描述

利用反射获取私有方法

Method[] getDeclaredMethods():获取所有的成员方法,包括private的

public class Main {
    public static void main(String[] args) throws Exception {
        Class<Person> Class1 = Person.class;
        Method[] dm = Class1.getDeclaredMethods();
        for (Method method : dm) {
            System.out.println(method);
        }
    }
}

public Method getDeclaredMethod(String name, Class<?>... parameterTypes):获取执行成员方法,包括private,name传递方法名,parameterTypes是方法参数类型的class对象
void setAccessible(boolean flag):解除私有权限

public class Person {
    private void test(){
        System.out.println("hhhhhhhhhhhhhh");
    }
}
public class Main {
    public static void main(String[] args) throws Exception {
        Class<Person> Class1 = Person.class;
        Constructor<Person> constructor = Class1.getConstructor();
        Person person = constructor.newInstance();
        Method method = Class1.getDeclaredMethod("test");
        method.setAccessible(true);
        method.invoke(person);
    }
}

在这里插入图片描述

利用反射获取Class对象中的成员变量

获取所有属性

Class类中的方法:
Field[] getFields():获取所有public的属性

public class Person {
    private String name;
    public Integer age;
}

public class Main {
    public static void main(String[] args) throws Exception {
        Class<Person> Class1 = Person.class;
        Field[] fields = Class1 .getFields();
        for (Field field : fields) {
            System.out.println(field);
        }
    }
}

在这里插入图片描述

Field[] getDeclaredFields():获取所有属性,包括priavte的。

public class Main {
    public static void main(String[] args) throws Exception {
        Class<Person> Class1 = Person.class;
        Field[] df = Class1.getDeclaredFields();
        for (Field field : df) {
            System.out.println(field);
        }
    }
}

在这里插入图片描述

获取指定属性

Class类中的方法:
Field getField(String name)获取指定public的属性
Field getDeclaredField(String name):获取指定属性,包括priavte的
Field类中的方法:
void set(Object obj,Object value):为属性赋值,相当于javabean中的set方法,obj代表对象,value代表赋予的值
Object get(Object obj):获取属性值,obj是对象

获取指定public的属性

public class Main {
    public static void main(String[] args) throws Exception {
        Class<Person> Class1 = Person.class;
        Person person = Class1.newInstance();
        Field age = Class1.getField("age");
        age.set(person,10);//调用set方法为public属性赋值
        System.out.println(age.get(person));//调用get方法获取public属性值,相当于javabean中的get方法
    }
}

获取指定属性,包括priavte的

public class Main {
    public static void main(String[] args) throws Exception {
        Class<Person> Class1 = Person.class;
        Person person = Class1.newInstance();
        Field name = Class1.getDeclaredField("name");
        name.setAccessible(true);//解除私有权限
        name.set(person,"张三");//调用set方法为属性赋值
        System.out.println(name.get(person));//调用get方法获取属性值 -> 相当于javabean中的get方法
    }
}
  • 9
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值