Java-反射

概述

Java的反射(reflection)机制是指在程序的运行中,可以获取任意一个对象所属的类(Class),可以构造任意一个类的对象(Constructor),可以了解任意一个类的成员变量(Field)和方法(Method),可以调用任意一个对象的属性和方法。这种动态获取程序信息以及动态调用对象的功能称为Java语言的反射机制。

反射被视为动态语言的关键。

Class类

Java 在将 .class 字节码文件载入时,JVM将自动为之创建一个 Class 对象,用于表示这个类的类型信息。代表该 .class 字节码文件,从该 Class 对象中可以获得类的许多基本信息,这就是反射机制基础

public final class Class extends Object implements Serializable, GenericDeclaration, Type, AnnotatedElement

📌 获取Class对象三种方式:

  • Object类的getClass()方法
  • 类静态属性class
  • public static Class forName(String className)
public class ClassDemo {
    public static void main(String[] argv) throws ClassNotFoundException {
        // 1、Object类的getClass()方法
        Stu s1 = new Stu();
        Class<? extends Stu> c1 = s1.getClass();

        Stu s2 = new Stu();
        Class<? extends Stu> c2 = s1.getClass();

        System.out.println(s1 == s2);// false
        System.out.println(c1 == c2);// true

        // 2、静态属性class
        Class<Stu> c3 = Stu.class;
        System.out.println(c1 == c3);// true

        // 3、Class类中的静态方法:public static Class forName(String className)
        Class<?> c4 = Class.forName("反射.Stu");
        System.out.println(c1 == c4);// true
    }
}

输出:
false
true
true
true

📌 继承中的类对象

public class ClassDemo {
    public static void main(String[] argv) throws ClassNotFoundException {
        UserDao ud = new UserDaoImpl();

        System.out.println(ud.getClass() == UserDao.class);
        System.out.println(ud.getClass() == UserDaoImpl.class);
    }
}

输出:
false
true

对象 ud 实际 Class 对象是 实现类 UserDaoImpl 的类对象。

Constructor类

  • public Constructor<T> getConstructor(Class<?>... parameterTypes):获取指定构造方法。参数表示的是:你要获取的构造方法数据类型的class字节码文件对象。
  • public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes:获取指定构造方法。
  • public Constructor[] getConstructors():所有公共构造方法。不包含父类构造方法
  • public Constructor[] getDeclaredConstructors():所有构造方法。包括私有构造方法不包含父类构造方法
  • public T newInstance(Object... initargs)实例化对象。
  • public void setAccessible(boolean flag:暴力访问。
public class ReflexDemo {
    public static void main(String[] argv) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException,
            InvocationTargetException, InstantiationException {
        Class<?> clazz = Class.forName("反射.Stu");

        Constructor<?> constructor = clazz.getConstructor(String.class, int.class, String.class, String.class);
        System.out.println(constructor);
        Stu stu = (Stu)constructor.newInstance("jack", 28, "5", "98");
        System.out.println(stu);

        // 获取私有构造方法对象
        Constructor<?> constructor2 = clazz.getDeclaredConstructor(String.class, String.class);
        System.out.println(constructor2);

        // 值为true则指示反射的对象在使用时应该取消Java语言访问检查。
        constructor2.setAccessible(true);
        Stu stu2 = (Stu)constructor2.newInstance("5", "98");
        System.out.println(stu2);

        System.out.println("\n+++getConstructors+++");
        Constructor<?>[] constructors = clazz.getConstructors();
        for (Constructor con : constructors){
            System.out.println(con);
        }

        System.out.println("\n+++getDeclaredConstructors+++");
        Constructor<?>[] declaredConstructors = clazz.getDeclaredConstructors();
        for (Constructor con : declaredConstructors){
            System.out.println(con);
        }
    }
}

class person{
    public String name;
    public int age;
    private String person;

    public person() {}
    
    public person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    public int getAge() { return age; }
    public void setAge(int age) { this.age = age; }

    public void test(){
        System.out.println("person test");
    }
}

class Stu extends person{
    public String grade;
    private String score;

    public Stu() {}

    private Stu(String grade, String score) {
        this.grade = grade;
        this.score = score;
    }

    public Stu(String name, int age, String grade, String score) {
        super(name, age);
        this.grade = grade;
        this.score = score;
    }

    public String getGrade() { return grade; }
    public void setGrade(String grade) { this.grade = grade; }
    public String getScore() { return score; }
    public void setScore(String score) { this.score = score; }

    public void test(){
        System.out.println("Stu test");
    }

    private String test2(String name){
        System.out.println(score +" Stu test2 " + name);
        return name;
    }

    @Override
    public String toString() {
        return "Stu{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", grade='" + grade + '\'' +
                ", score='" + score + '\'' +
                '}';
    }
}

输出:
public 反射.Stu(java.lang.String,int,java.lang.String,java.lang.String)
Stu{name='jack', age=28, grade='5', score='98'}
private 反射.Stu(java.lang.String,java.lang.String)
Stu{name='null', age=0, grade='5', score='98'}

+++getConstructors+++
public 反射.Stu(java.lang.String,int,java.lang.String,java.lang.String)
public 反射.Stu()

+++getDeclaredConstructors+++
public 反射.Stu(java.lang.String,int,java.lang.String,java.lang.String)
private 反射.Stu(java.lang.String,java.lang.String)
public 反射.Stu()

💦通过方法getConstructors()getDeclaredConstructors() 均不能获取父类构造方法getDeclaredConstructors可以获取私有构造方法

💦基本的 Java 类型(boolean、byte、char、short、int、long、float 和 double)和关键字 void 也表示为 Class 对象。 比如,int类型的Class对象获取方法是 int.class ,而不是Integer.class。

Field类

  • public Field getField(String name):返回指定公共成员字段Field 对象。
  • public Field getDeclaredField(String name):返回指定字段Field 对象。
  • public Field[] getFields():返回所有公共成员字段Field 对象组。包含父类属性字段,但不包含私有属性
  • public Field[] getDeclaredFields():返回所有字段Field 对象组。包含私有属性,但不包含父类属性
  • public void set(Object obj, Object value):属性赋值。
  • public Object get(Object obj):获取属性值。
  • public void setAccessible(boolean flag):暴力访问。
public class ReflexDemo {
    public static void main(String[] argv) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException,
            InvocationTargetException, InstantiationException, NoSuchFieldException {
        Class<?> clazz = Class.forName("反射.Stu");

        Constructor<?> constructor = clazz.getConstructor(String.class, int.class, String.class, String.class);
        Stu stu = (Stu)constructor.newInstance("jack", 28, "5", "98");
        System.out.println(stu);

        // 获取单个的成员变量
        Field field = clazz.getField("name");
        field.set(stu, "lucy");
        System.out.println(stu);

        // 获取私有成员属性
        Field field1 = clazz.getDeclaredField("score");
        field1.setAccessible(true);
        field1.set(stu, "90");
        System.out.println(stu);

        System.out.println("\n+++getFields+++");
        Field[] fields = clazz.getFields();
        for(Field f : fields){
            System.out.println(f);
        }

        System.out.println("\n+++getDeclaredFields+++");
        Field[] declaredFields = clazz.getDeclaredFields();
        for(Field f : declaredFields){
            System.out.println(f);
        }
    }
}

输出:
Stu{name='jack', age=28, grade='5', score='98'}
Stu{name='lucy', age=28, grade='5', score='98'}
Stu{name='lucy', age=28, grade='5', score='90'}

+++getFields+++
public java.lang.String 反射.Stu.grade
public java.lang.String 反射.person.name
public int 反射.person.age

+++getDeclaredFields+++
public java.lang.String 反射.Stu.grade
private java.lang.String 反射.Stu.score
类名publicprivate
personname ageperson
Stugradescore
getFields:person.name 、person.age、 Stu.grade
getDeclaredFields:Stu.grade、Stu.score

Method类

  • public Method getMethod(String name, Class<?>... parameterTypes):返回指定方法名的Method 对象。
  • public Method getDeclaredMethod(String name, Class<?>... parameterTypes):返回指定方法名(可以私有)的Method 对象。
  • public Method[]getMethods():返回所有Method 对象组。包含父类方法,但不包含私有方法
  • public Method[] getDeclaredMethods():返回所有Method 对象组。包含私有方法,但不包含父类方法
  • public Object invoke(Object obj, Object... args):执行对象obj的方法,传参args。
  • public void setAccessible(boolean flag):暴力访问。
public class ReflexDemo {
    public static void main(String[] argv) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException,
            InvocationTargetException, InstantiationException, NoSuchFieldException {
        Class<?> clazz = Class.forName("反射.Stu");

        Constructor<?> constructor = clazz.getConstructor(String.class, int.class, String.class, String.class);
        Stu stu = (Stu)constructor.newInstance("jack", 28, "5", "98");
        System.out.println(stu);

        // public Method getMethod(String name,Class<?>... parameterTypes)
        Method method = clazz.getMethod("test");
        method.invoke(stu);

        // 获取私有方法
        Method method1 = clazz.getDeclaredMethod("test2", String.class);
        method1.setAccessible(true);
        method1.invoke(stu, "lalala");

        System.out.println("\n+++getMethods+++");
        Method[] methods = clazz.getMethods();
        for(Method m : methods){
            System.out.println(m);
        }

        System.out.println("\n+++getDeclaredMethods+++");
        Method[] declaredMethods = clazz.getDeclaredMethods();
        for(Method m : declaredMethods){
            System.out.println(m);
        }
    }
}

输出:
Stu{name='jack', age=28, grade='5', score='98'}
Stu test
98 Stu test2 lalala
lalala

+++getMethods+++
public java.lang.String 反射.Stu.toString()
public void 反射.Stu.test()
public java.lang.String 反射.Stu.getScore()
public void 反射.Stu.setGrade(java.lang.String)
public java.lang.String 反射.Stu.getGrade()
public void 反射.Stu.setScore(java.lang.String)
public java.lang.String 反射.person.getName()
public void 反射.person.setName(java.lang.String)
public int 反射.person.getAge()
public void 反射.person.setAge(int)
public final void java.lang.Object.wait() throws java.lang.InterruptedException
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
public boolean java.lang.Object.equals(java.lang.Object)
public native int java.lang.Object.hashCode()
public final native java.lang.Class java.lang.Object.getClass()
public final native void java.lang.Object.notify()
public final native void java.lang.Object.notifyAll()

+++getDeclaredMethods+++
public java.lang.String 反射.Stu.toString()
public void 反射.Stu.test()
private java.lang.String 反射.Stu.test2(java.lang.String)
public java.lang.String 反射.Stu.getScore()
public void 反射.Stu.setGrade(java.lang.String)
public java.lang.String 反射.Stu.getGrade()
public void 反射.Stu.setScore(java.lang.String)

getMethods():获取自己以及父亲的公共方法。
getDeclaredMethods():获取自己的所有的方法,包含私有方法。示例中的 private java.lang.String 反射.Stu.test2(java.lang.String)。

应用

📅ArrayList<Integer>集合越过泛型检查添加一个字符串数据

public class ArrayListDemo {
    public static void main(String[] argv) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        ArrayList<Integer> list = new ArrayList<>();
        list.add(10);
        System.out.println(list);

        Class<? extends ArrayList> clazz = list.getClass();
        Method method = clazz.getMethod("add", Object.class);

        method.invoke(list, "jack");
        method.invoke(list,"lucy");
        method.invoke(list, 8);
        System.out.println(list);
    }
}

输出:
[10]
[10, jack, lucy, 8]

💦 先获取集合的 Class 对象,然后通过 Class 对象获取 add() 方法类Method,再调用方法插入字符串数据。

📅编写一个工具类,可以修改任意类对象属性。

public class ToolDemo {
    public static void main(String[] argv) throws NoSuchFieldException, IllegalAccessException {
        Stu stu = new Stu("jack", 28, "5", "98");
        System.out.println(stu);
        Tool.setProperty(stu, "score", "90");
        System.out.println(stu);

        person person = new person("lucy", 11);
        System.out.println(person);
        Tool.setProperty(person,"person", "lalala");
        System.out.println(person);
    }
}

class Tool{
    public static void setProperty(Object obj,String key,String value) throws NoSuchFieldException, IllegalAccessException {
        // 根据对象获取字节码文件对象
        Class<?> clazz = obj.getClass();

        // 获取该对象的propertyName成员变量
        Field field = clazz.getDeclaredField(key);

        // 给对象的成员变量赋值为指定的值
        field.setAccessible(true);
        field.set(obj, value);
    }
}

输出:
Stu{name='jack', age=28, grade='5', score='98'}
Stu{name='jack', age=28, grade='5', score='90'}
person{name='lucy', age=11, person='null'}
person{name='lucy', age=11, person='lalala'}

💦 可以为不同的对象设置属性的值。

📅忽略大小写、下划线复制两个对象

📌 People属性:peopleName、peopleAge
📌 People2属性:people_name、people_age

通过方法将 People.peopleName 赋值给 People2.people_name,People.peopleAge 赋值给 People2.people_age。

/* 不区分大小写、下划线复制两个类对象*/
public class CopyDemo {
    public static void main(String[] argv) throws IllegalAccessException {
        People p1 = new People("jack", 22);
        People2 p2 = new People2("tom", 18);
        System.out.println(p1);
        System.out.println(p2);
        //BeanUtils.copyProperties(stu2,stu1);

        copy(p1,p2);
        System.out.println(p1);
        System.out.println(p2);
    }

    public static void copy(Object src,Object dest) throws IllegalAccessException {
        // 1.1、获取源对象属性集合
        Class<?> sClass = src.getClass();
        Field[] sfields = sClass.getDeclaredFields();
        // 1.2、定义HashMap储存源对象属性和值
        HashMap<String, Object> hash = new HashMap<>();
        for(Field f : sfields){
            String key = f.getName().replace("_","").toLowerCase();
            System.out.println(f.get(src));
            hash.put(key,f.get(src));
        }

        // 2.1、获取目标对象属性集合
        Class<?> dClass = dest.getClass();
        Field[] dfields = dClass.getDeclaredFields();
        for(Field f : dfields){
            String key = f.getName().replace("_","").toLowerCase();
            f.setAccessible(true);
            // 2.2、通过源HashMap获取源对象属性值,赋值给目标对象相应属性。
            f.set(dest, hash.get(key));
        }
    }
}

class People{
    public String peopleName;
    public int peopleAge;

    public People(String peopleName, int peopleAge) {
        this.peopleName = peopleName;
        this.peopleAge = peopleAge;
    }

    public String getPeopleName() {return peopleName;}
    public void setPeopleName(String peopleName) {this.peopleName = peopleName;}
    public int getPeopleAge() {return peopleAge;}

    public void setPeopleAge(int peopleAge) {this.peopleAge = peopleAge;}

    @Override
    public String toString() {
        return "People{" +
                "peopleName='" + peopleName + '\'' +
                ", peopleAge=" + peopleAge +
                '}';
    }
}

class People2{
    public String people_name;
    public int people_age;

    public People2(String people_name, int people_age) {
        this.people_name = people_name;
        this.people_age = people_age;
    }

    public String getPeople_name() {return people_name;}
    public void setPeople_name(String people_name) {this.people_name = people_name;}
    public int getPeople_age() {return people_age;}
    public void setPeople_age(int people_age) {this.people_age = people_age;}

    @Override
    public String toString() {
        return "People2{" +
                "people_name='" + people_name + '\'' +
                ", people_age=" + people_age +
                '}';
    }
}

输出:
People{peopleName='jack', peopleAge=22}
People2{people_name='tom', people_age=18}

People{peopleName='jack', peopleAge=22}
People2{people_name='jack', people_age=22}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不会叫的狼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值