你必须掌握的Java基础之反射

2018-01-28  本文已影响0人  付凯强

0. 序言

这里只讲解关于反射的基础知识,以后会补充更多的扩展知识,毕竟是基础系列。

1. 类的加载概述

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

2. 类的加载时机

3. 类加载器的概述和分类

4. 反射概述

5. 反射的三种方式

反射的三种方式.png
        try {
            Class clazz_01 = Class.forName("test.Person");

            Class clazz_02 = Person.class;

            Person person = new Person("Mr.Fu", 20);
            Class clazz_03 = person.getClass();

            System.out.println(clazz_01==clazz_02);
            System.out.println(clazz_02==clazz_03);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

6. Class.forName()获取字节码对象和字节码对象通过newInstance创建对象实例

public class test01 {
    public static void main(String[] args) {
        Juicer juicer = new Juicer();
        juicer.run(new Apple());
        juicer.run(new Orange());
    }
}

class Juicer {
    public void run(Fruit fruit) {
        fruit.squeeze();
    }
}

interface Fruit {
    void squeeze();
}

class Apple implements Fruit {
    public void squeeze() {
        System.out.println("榨出一杯苹果汁");
    }
}

class Orange implements Fruit {
    public void squeeze() {
        System.out.println("榨出一杯橘子汁");
    }
}
榨出一杯苹果汁
榨出一杯橘子汁
test.Apple  //类名

test.Orange
public class test01 {
    public static void main(String[] args) {
        Juicer juicer = new Juicer();
        try {
            // 创建输入流对象,关联配置文件
            BufferedReader reader = new BufferedReader(new FileReader("config.properties.txt"));
            try {
                //读取配置文件一行内容,获取该类的字节码对象
                Class clazz = Class.forName(reader.readLine());
                try {
                    //通过字节码对象创建实例对象
                    Fruit fruit = (Fruit) clazz.newInstance();
                    fruit.squeeze();
                } catch (InstantiationException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }

    }
}
榨出一杯橘子汁

7. getConstructor获取构造方法并使用

class Person {

    private String mName;
    private int mAge;

    public Person(String mName, int mAge) {
        this.mName = mName;
        this.mAge = mAge;
    }

    public String getmName() {
        return mName;
    }

    public int getmAge() {
        return mAge;
    }
}
public class test01 {
    public static void main(String[] args) {
        try {
            Class clazz = Class.forName("test.Person");
            try {
               Person person = (Person) clazz.newInstance();
               System.out.println(person);
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}
java.lang.InstantiationException: test.Person
    at java.lang.Class.newInstance(Class.java:427)
    at test.test01.main(test01.java:8)
        Class clazz = null;
        try {
            clazz = Class.forName("test.Person");
            Constructor constructor = null;
            try {
                //因为还处于反射阶段,所以参数是字节码对象
                constructor = clazz.getConstructor(String.class, int.class);
                Person person = (Person) constructor.newInstance("张三", 28);
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

8. getField和getDeclaredField获取字段

Class clazz = null;
        try {
            clazz = Class.forName("test.Person");
            Constructor constructor = clazz.getConstructor(String.class, int.class);
            Person person = (Person) constructor.newInstance("张三", 15);

            Field field = clazz.getField("mName");
            field.set(person,"李四");
            System.out.println(person);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
java.lang.NoSuchFieldException: mName
    at java.lang.Class.getField(Class.java:1703)
    at test.test01.main(test01.java:16)
java.lang.IllegalAccessException: Class test.test01 can not access a member of class test.Person with modifiers "private"
    at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:102)
    at java.lang.reflect.AccessibleObject.slowCheckMemberAccess(AccessibleObject.java:296)
    at java.lang.reflect.AccessibleObject.checkAccess(AccessibleObject.java:288)
    at java.lang.reflect.Field.set(Field.java:761)
    at test.test01.main(test01.java:17)
field.setAccessible(true);

9. getMethod或getDeclaredMethod获取方法

无参:
            Method eat = clazz.getMethod("eat"); //获取
            eat.invoke(person); //执行
            
            我在人民广场吃炸鸡
有参:
            Method eat = clazz.getMethod("eat",int.class);//获取
            eat.invoke(person,10); //执行

10. 通过反射越过泛型检查

ArrayList<Integer> list = new ArrayList<>();
            list.add(10);
            list.add(20);
            Class clazz = Class.forName("java.util.ArrayList");
            Method add = clazz.getMethod("add", Object.class);
            add.invoke(list, "abc");

            System.out.println(list);
[10, 20, abc]

11. 写一个通用的设置某个对象的某个属性为指定的值

public class Tool {
    public void setProperty(Object o, String property, Object value) {
        try {
            Class clazz = o.getClass(); //获取字节码对象
            Field declaredField = clazz.getDeclaredField(property); //暴力反射获取字段
            declaredField.setAccessible(true); //去除权限
            declaredField.set(o, value);
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }
}
        Person person = new Person("张三",10);

        Tool tool = new Tool();
        tool.setProperty(person,"mName","李四");

        System.out.println(person.getmName());
上一篇 下一篇

猜你喜欢

热点阅读