Java学习路线(23)——反射机制

一、概述
(一)什么是反射: 反射指的是任何一个Class类,在“运行时”都可以直接得到全部成分。
(二)动态可获取的对象: 构造器对象——Constructor,成员变量对象——Field,成员方法对象——Method。
(三)反射关键: 第一步都是得到编译后的Class对象,然后可以获得Class全部成分。


二、反射相关对象的获取
(一)获取Class对象

//过程:Hello.java -> javac -> Hello.class
Class c = Hello.class;

1、Object.forName(String className) -> 源码阶段获取
2、Object.class -> 内存阶段获取
3、Object.class() -> 实例化阶段获取

public class getClassInfoDemo {
    public static void main(String[] args) {
        try {
            /*forName(类全名)*/
            Class c = Class.forName("com.zengoo.reflected.Student");
            System.out.println(c);
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        }

        /*类获取*/
        System.out.println(Student.class);

        /*对象获取*/
        System.out.println(new Student().getClass());
    }
}

class Student{
    private String id;
    private String name;

    public Student() {
    }

    public Student(String id, String name) {
        this.id = id;
        this.name = name;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Student{" +
                "id='" + id + '\'' +
                ", name='" + name + '\'' +
                '}';
    }
}

/*打印输出*/
class com.zengoo.reflected.Student
class com.zengoo.reflected.Student
class com.zengoo.reflected.Student

(二)获取构造器

1、相关API

方法 说明
Constructor[] getConstructors() 获取public修饰的所有构造器对象
Constructor[] getDecalaredConstructors() 获取所有构造器对象
Constructor getConstructor(Class… parameterTypes) 根据参数类型返回单个public构造器
Constructor getDecalaredConstructor(Class… parameterTypes) 根据参数类型获取单个构造器对象

2、获取构造器示例

public class getClassConstructorDemo {
    public static void main(String[] args) {

        Class c = Student.class;

        //获取所有public构造器
        Constructor[] c1 = c.getConstructors();
        System.out.println("=============获取所有public构造器=============");
        for (Constructor constructor :c1) {
            System.out.println(constructor.getName() + "===>" + constructor.getParameterCount());
        }
        //获取所有构造器
        System.out.println("=============获取所有构造器=============");
        Constructor[] c2 = c.getDeclaredConstructors();
        for (Constructor constructor :c2) {
            System.out.println(constructor.getName() + "===>" + constructor.getParameterCount());
        }

        //获取单个public构造器对象
        System.out.println("=============获取单个public构造器对象=============");
        try {
            Constructor c3 = c.getConstructor();
            System.out.println(c3.getName() + "===>" + c3.getParameterCount());
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        }

        //获取单个构造器对象
        System.out.println("=============获取单个构造器对象=============");
        try {
            Constructor c4 = c.getDeclaredConstructor(String.class,String.class);
            System.out.println(c4.getName() + "===>" + c4.getParameterCount());
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        }
    }
}

/*打印输出*/
=============获取所有public构造器=============
com.zengoo.reflected.Student===>0
com.zengoo.reflected.Student===>2
=============获取所有构造器=============
com.zengoo.reflected.Student===>0
com.zengoo.reflected.Student===>2
=============获取单个public构造器对象=============
com.zengoo.reflected.Student===>0
=============获取单个构造器对象=============
com.zengoo.reflected.Student===>2

3、获取构造器并调用

(1)作用: 获取构造器的作用是为了初始化一个对象返回。
(2)相关API

方法 说明
T newInstance(Object initargs) 根据指定构造器创建对象
void setAccessible(boolean flag) 设置true表示无视访问限制,暴力反射

(3)使用示例

class useConstructor{
    public static void main(String[] args) throws Exception {
        Constructor constructor = Student.class.getConstructor(String.class,String.class);
        constructor.setAccessible(true); //暴力破解私有权限,若构造器为公开权限,则不需要
        Student student = (Student) constructor.newInstance(UUID.randomUUID().toString(),"金牙齿");
        System.out.println(student);
    }
}

/*打印输出*/
Student{id='77430b37-a65f-4379-b181-437dc5544032', name='金牙齿'}

(三)获取成员变量

1、相关API

方法 说明
Field[] getFields() 获取public修饰的所有成员变量
Field[] getDeclaredFields() 获取所有成员变量
Field getField(String name) 根据参数名称返回单个public成员变量
Field getDecalaredField(String name) 根据参数名称返回单个成员变量
void set(Object obj,Object value) 给对象注入某个成员变量数据
Object get(Object obj) 根据参数名称返回单个成员变量
void setAccessible(boolean b) 暴力开权限
Class getType() 获取属性的类型,返回Class对象
String getName() 获取属性名称

2、使用示例

public class getClassFieldDemo {
    public static void main(String[] args) throws NoSuchFieldException {
        Class c = Student.class;

        //获取所有public成员变量
        Field[] fields = c.getFields();
        for (Field f :fields) {
            System.out.println(f.getType() + " " + f.getName());
        }

        //获取所有成员变量
        Field[] fields1 = c.getDeclaredFields();
        for (Field f :fields1) {
            System.out.println(f.getType() + " " + f.getName());
        }

        //获取单个public成员变量
        Field field = c.getDeclaredField("name");
        System.out.println(field.getType() + " " + field.getName());

        //获取单个成员变量
        Field field1 = c.getDeclaredField("id");
        System.out.println(field1.getType() + " " + field1.getName());
    }
}

/*打印变量*/
class java.lang.String id
class java.lang.String name
class java.lang.String name
class java.lang.String id

class useField{
    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
        Class c = Student.class;

        Field id = c.getDeclaredField("id");
        Field name = c.getDeclaredField("name");

        id.setAccessible(true);
        name.setAccessible(true);

        Student s = new Student();
        id.set(s, UUID.randomUUID().toString());
        name.set(s, "金钟罩");

        System.out.println(id.getType() + " " + id.get(s));
        System.out.println(name.getType() + " " + name.get(s));
    }
}

/*打印输出*/
class java.lang.String d368bc5c-76c9-413a-ad2d-565729b7afe9
class java.lang.String 金钟罩

(四)获取成员方法

1、相关API

方法 说明
Method[] getMethods() 返回所有public修饰的成员方法对象的数组
Method[] getDeclaredMethods() 返回所有成员方法对象的数组
Method getMethod(String name,Class… parameterTypes) 根据方法名,参数列表属性,返回单个public修饰的成员方法对象
Method getDecalaredField(String name,Class… parameterTypes) 根据方法名,参数列表属性,返回单个修饰的成员方法对象
void setAccessible(boolean b) 暴力开权限

2、使用示例

public class getClassMethodDemo {
    public static void main(String[] args) throws NoSuchMethodException {
        Class c = Student.class;


        //获取所有public成员方法
        Method[] methods = c.getMethods();
        for (Method method :methods) {
            System.out.println(method.getGenericParameterTypes().toString() + " " + method.getName());
        }

        //获取所有成员方法
        Method[] methods1 = c.getDeclaredMethods();
        for (Method method :methods1) {
            System.out.println(method.getGenericParameterTypes().toString() + " " + method.getName());
        }

        //获取单个public成员变量
        Method method = c.getMethod("getName");
        System.out.println(method.getGenericParameterTypes().toString() + " " + method.getName());

        //获取单个成员变量
        Method method1 = c.getMethod("setId", String.class);
        System.out.println(method1.getGenericParameterTypes().toString() + " " + method1.getName());
    }
}

/*打印输出*/
[Ljava.lang.Class;@67b64c45 getName
[Ljava.lang.Class;@68837a77 toString
[Ljava.lang.Class;@6be46e8f setName
[Ljava.lang.Class;@3567135c getId
[Ljava.lang.Class;@327471b5 setId
[Ljava.lang.Class;@4157f54e wait
[Ljava.lang.Class;@90f6bfd wait
[Ljava.lang.Class;@47f6473 wait
[Ljava.lang.Class;@15975490 equals
[Ljava.lang.Class;@6b143ee9 hashCode
[Ljava.lang.reflect.Type;@9f70c54 getClass
[Ljava.lang.Class;@234bef66 notify
[Ljava.lang.Class;@737996a0 notifyAll
[Ljava.lang.Class;@61dc03ce getName
[Ljava.lang.Class;@50f8360d toString
[Ljava.lang.Class;@2cb4c3ab setName
[Ljava.lang.Class;@13c78c0b getId
[Ljava.lang.Class;@12843fce setId
[Ljava.lang.Class;@3dd3bcd getName
[Ljava.lang.Class;@97e1986 setId

3、方法调用

class useMethod{
    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        Class c = Student.class;
        Constructor constructor = c.getConstructor(String.class,String.class);
        constructor.setAccessible(true);

        Student student = (Student) constructor.newInstance(UUID.randomUUID().toString(),"金环法");

        System.out.println(student);

        Method method = c.getMethod("setName", String.class);

        method.setAccessible(true);
        method.invoke(student,"新名称");

        System.out.println(student);
    }
}

/*打印输出*/
Student{id='d001810b-88e7-468d-bb8c-bc4129970191', name='金环法'}
Student{id='d001810b-88e7-468d-bb8c-bc4129970191', name='新名称'}


三、反射的作用

(一)绕过编译阶段为集合添加数据(原理是泛型擦除,即强制执行)

class useClassDemo{
    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        List<Integer> list1 = new ArrayList<>();
        List<Integer> list2 = new ArrayList<>();

        list1.add(1);
        list1.add(2);
        list1.add(3);

        list2.add(1);
        list2.add(2);
        list2.add(3);

        System.out.println(list1.getClass());
        System.out.println(list2.getClass());

        System.out.println(list1.getClass() == list2.getClass());

        System.out.println("===========================");

        Class c = list2.getClass();

        Method method = c.getMethod("add", Object.class);

        method.invoke(list2,"字符串");

        System.out.println(list1.getClass() == list2.getClass());
        System.out.println(list1);
        System.out.println(list2);
    }
}

/*打印输出*/
class java.util.ArrayList
class java.util.ArrayList
true
===========================
true
[1, 2, 3]
[1, 2, 3, 字符串]

(二)通用框架的底层原理(重点)

用反射做通用框架示例

/**
* 需求:给定任意对象,在不清楚对象字段的情况下,将对象的字段名和对应值存储到文件中去。
*/

public class useReflectedToFrame {
    public static void main(String[] args) {
      Shop shop = new Shop(UUID.randomUUID().toString(),"店名","xxx市xxx区xxx街道xxx");
      Goods goods = new Goods(UUID.randomUUID().toString(),"商品名",28.5);

      String parentPath = "D:\\JavaBase\\JavaSEpro\\src\\com\\zengoo\\outDir\\";

      TestUtil.save(shop,parentPath+"shop.txt");
      TestUtil.save(goods,parentPath+"goods.txt");
      System.out.println("打印完毕");
    }
}

/*自定义通用框架*/
class TestUtil{
    public static void save(Object obj,String pathname) {
        try(PrintStream printStream = new PrintStream(new FileOutputStream(pathname))){
            //1、提取对象的所有成员变量
            Class c = obj.getClass();

            Field[] fields = c.getDeclaredFields();
            for (Field field:fields) {
                field.setAccessible(true);
                //2、获取变量名
                String name = field.getName();
                //3、获取变量名对应的值
                String value = " = " + field.get(obj);

                printStream.println(name + value);
            }
        } catch (IllegalAccessException | FileNotFoundException e) {
            throw new RuntimeException(e);
        }
    }
}

class Shop{
    private String id;
    private String shopName;
    private String address;

    public Shop() {
    }

    public Shop(String id, String shopName, String address) {
        this.id = id;
        this.shopName = shopName;
        this.address = address;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getShopName() {
        return shopName;
    }

    public void setShopName(String shopName) {
        this.shopName = shopName;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return "Shop{" +
                "id='" + id + '\'' +
                ", shopName='" + shopName + '\'' +
                ", address='" + address + '\'' +
                '}';
    }
}

class Goods{
    private String id;
    private String goodsName;
    private double price;

    public Goods() {
    }

    public Goods(String id, String goodsName, double price) {
        this.id = id;
        this.goodsName = goodsName;
        this.price = price;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getGoodsName() {
        return goodsName;
    }

    public void setGoodsName(String goodsName) {
        this.goodsName = goodsName;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }


    @Override
    public String toString() {
        return "Goods{" +
                "id='" + id + '\'' +
                ", goodsName='" + goodsName + '\'' +
                ", price=" + price +
                '}';
    }
}

shop.txt

id = cd23f6eb-91c3-4f19-adf5-654ef4602b2e
shopName = 店名
address = xxx市xxx区xxx街道xxx

goods.txt

id = 77d46cea-04ec-45dd-b806-f39179bfa37e
goodsName = 商品名
price = 28.5

你可能感兴趣的:(java,学习,开发语言)