Java基础篇:反射入门(上)

反射入门篇幅有点长,但我不想打散了,因为只看其中一部分也没啥意义,所以分为了上中下3篇,写的不好的方面,希望大家指出

简介

反射能干什么?你只需要给我一个类的地址,我就能知道类的全部信息(类名称、父类、继承的接口、方法、属性、甚至实例化并赋值),那么下面我们就来看看它怎么办到的吧!

预备工作

这次我们准备用了一个Customer类,我们把它当成反射的对象,我们希望通过反射获取它的全部信息,我们先来看看这个类吧!

  • Customer类,(包名有点随意了):
    • (注意,下面要用)有一个无参数构造方法和一个private的构造方法
    • 为了方便后面测试效果,实现了Person接口,但是Person接口没有抽象方法
package com.bridge.security.util.bean;

/**
 * @创建人 zhangtaiyuan
 * @创建时间 2020/7/2 
 * @描述
 */
public class Customer implements Person{
    private String name;
    private String email;
    private int age;

    public Customer() { }

    private Customer(String name, String email, int age) {
        this.name = name;
        this.email = email;
        this.age = age;
    }

    public String getName() { return name;  }

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

    public String getEmail() { return email; }

    public void setEmail(String email) {  this.email = email;  }

    public int getAge() {  return age; }

    public void setAge(int age) {  this.age = age; }

    @Override
    public String toString() {
        return "Customer{" +
                "name='" + name + '\'' +
                ", email='" + email + '\'' +
                ", age='" + age + '\'' +
                '}';
    }
}
  • 什么也没做的Person接口
package com.bridge.security.util.bean;
public interface Person { }

上面准备好了,我们就可以通过反射获取Customer类信息了

获得Class信息

获得对象信息之前,我们必须获得Class信息,然后从Class中获取类对应的信息,获取Clss有3种方法,如下:

  • 通过实体类获得
        Customer customer = new Customer()  ; // 已经存在有指定类的实例化对象
        Class<? extends Customer> cls = customer.getClass() ;
        System.out.println(cls.getName());	//输出结果:com.bridge.security.util.bean.Customer
  • 直接从XXX.class获得
        Class<? extends Customer> cls = Customer.class;
        System.out.println(cls.getName());	//输出结果:com.bridge.security.util.bean.Customer
  • 从类的路径获得
        Class<?> cls = Class.forName("com.bridge.security.util.bean.Customer") ;
        System.out.println(cls.getName());//输出结果:com.bridge.security.util.bean.Customer

上面3个方式获得的Class都一样,最后一个通过传入String就能获得Class对象,是不是让我们想起了JDBC,哈哈

通过Class获得各种属性

通过Class实例化对象
  • 在JDK9之前:class.newInstance()(jDK9开始不建议使用这个方法了)
  • 在JDK9之后:clazz.getDeclaredConstructor().newInstance()
    • 大部分公司还在用jdk8,所以例子用的9之前的方式:
        Class<?> cls = Class.forName("com.bridge.security.util.bean.Customer") ;
        Object obj = cls.newInstance() ;	// 实例化对象,JDK 9后被废除了
        //Object obj = cls.getDeclaredConstructor().newInstance() ;  JDK 9之后才能用
        System.out.println(obj); // 由于没有赋值:输出的都是null 输出结果:Customer{name='null', email='null', age='0'}
  • 看着上面,你是不是明白了,如果没有反射,那么工厂模式创建实现类时,就会出现很多判断语句,并且当有新的工厂的实现类时,你就得修改代码并且升级版本,所以,没有反射,这种设计模式几乎不可能实现的(维护太麻烦)
通过Class获取属性
  • 获得包路径:public Package getPackage();//比下面多一个“package”
  • 获得包路径:public Package getPackageName();
        Class<?> cls = Class.forName("com.bridge.security.util.bean.Customer") ;
        System.out.println(cls.getPackage()); // package com.bridge.security.util.bean
        System.out.println(cls.getPackageName()); // com.bridge.security.util.bean
  • 获得父类:public Class<? super T> getSuperclass()
        Class<?> cls = Class.forName("com.bridge.security.util.bean.Customer") ;
        Class superclass = cls.getSuperclass();// 返回的是class
        System.out.println(superclass);// class java.lang.Object
  • 获得接口:public Class<?>[] getInterfaces()
        Class<?> clazz = Class.forName("com.bridge.security.util.bean.Customer") ;
        for (Class<?> inter:clazz.getInterfaces()){ //获得接口,是一个class数组
            System.out.println(inter.getName()); //com.bridge.security.util.bean.Person
        }
  • 构造方法
    • 获取所有构造方法:public Constructor<?>[] getDeclaredConstructors()

    • 获取指定的构造方法:public Constructor getDeclaredConstructor(Class<?>… parameterTypes)

    • 获取所有公开的构造方法:public Constructor<?>[] getConstructors()

    • 获取公开的指定构造方法:public Constructor getConstructor​(Class<?>… parameterTypes)

      • 全部构造方法
        Class<?> clazz = Class.forName("com.bridge.security.util.bean.Customer") ;
        for (Constructor<?> constructor:clazz.getDeclaredConstructors()){ //获得所有构造方法,包括非公开的 Customer中有个private方法
            System.out.println(constructor.getName() + Arrays.toString(constructor.getParameterTypes())); 
        }
        /**
        * 下面是输出结果
        * com.bridge.security.util.bean.Customer[]
        * com.bridge.security.util.bean.Customer[class java.lang.String, class java.lang.String, int]
        */
  • 指定构成方法
        Class<?> clazz = Class.forName("com.bridge.security.util.bean.Customer") ;
        System.out.println(clazz.getDeclaredConstructor().getName() + Arrays.toString(clazz.getDeclaredConstructor().getParameterTypes()));
        //下面是获得private 的够着方法
        System.out.println(clazz.getDeclaredConstructor(String.class,String.class,int.class).getName() + Arrays.toString(clazz.getDeclaredConstructor(String.class,String.class,int.class).getParameterTypes()));
        /**
         *  输出结果:
         *  com.bridge.security.util.bean.Customer[]
         *  com.bridge.security.util.bean.Customer[class java.lang.String, class java.lang.String, int]
         */
  • 公开的构造方法,下面就没有private构造方法了
        Class<?> clazz = Class.forName("com.bridge.security.util.bean.Customer") ;
        for (Constructor<?> constructor:clazz.getConstructors()){ //获得所有构造方法,包括非公开的 Customer中有个private方法
            System.out.println(constructor.getName() + Arrays.toString(constructor.getParameterTypes()));
        }
    	/**
        * 下面是输出结果
        * com.bridge.security.util.bean.Customer[]
        */
  • 指定的公开的构造方法,下面尝试去获得private的构造方法,就会直接报错
        Class<?> clazz = Class.forName("com.bridge.security.util.bean.Customer") ;
        System.out.println(clazz.getConstructor().getName() + Arrays.toString(clazz.getConstructor().getParameterTypes()));
        //下面是获得private 的够着方法
        System.out.println(clazz.getConstructor(String.class,String.class,int.class));
        /**
         *  输出结果:
         *  com.bridge.security.util.bean.Customer[]
         *  Exception in thread "main" java.lang.NoSuchMethodException: com.bridge.security.util.bean.Customer.<init>(java.lang.String, java.lang.String, int)
         * 	at java.base/java.lang.Class.getConstructor0(Class.java:3322)
         * 	at java.base/java.lang.Class.getConstructor(Class.java:2108)
         * 	at com.bridge.security.util.bean.TestDemo.main(TestDemo.java:16)
         */

总结

反射提供了另外一种设计思路,比如工厂模式,很多框架软件里都能看到它应用场景,比如:JDBC

未完…… 还有反射入门(中、下)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章