JavaSE进阶之(十)反射

十、反射

10.1 反射的概述

JavaSE进阶之(十)反射

  • 反射的应用场合
    在编译时根本无法知道该对象或者类可能属于哪些类,程序只依靠运行时的信息来发现该对象和类的真实信息。
  • 反射的作用
    通过反射可以使程序代码访问装载到JVM中的类的内部信息:
    1. 获取已装载类的属性信息;
    2. 获取已装载类的方法;
    3. 获取已装载累类的构造方法的信息。
  • 反射的机制
    在JDK中,主要由这些类来实现java反射机制,这些类都位于java.lang.reflect包中:
    1. Class类:代表一个类;
    2. Field类:代表类的成员变量(属性);
    3. Method类:代表类的成员方法;
    4. Constructor类:代表类的构造方法;
    5. Array类:提供了动态创建数组,以及访问数组的元素的静态方法。
  • Class类
    • Class类是java反射机制的起源和入口
    1. 用于获取与类相关的各种信息;
    2. 提供了获取类信息的相关方法;
    3. Class类继承自Object类。
    • Class类是所有类的共同的图纸
    1. 每个类都有自己的对象,好比图纸和实物的关系;
    2. 每个类也可以看做是一个对象,有共同的图纸Class,存放类的结构信息,能够通过相应方法取出相应信息(类的名字、属性、方法、构造方法、父类和接口)。

10.2 反射的优缺点

  • 优点
  1. 反射提高了java程序的灵活性和扩展性,降低耦合性,提高自适应能力。它允许程创建和控制人格类的对象,无需提前硬编码目标类;
  2. 反射是其他一些常用语言。如C、C++、Fortran或者Pascal等都不具备的;
  3. java反射技术应用领域很广,如软件测试、EJB、JavaBean等;
  4. 许多流行的开源框架例如Struts、Hibernate、Spring在实现过程中都采用了该技术。
  • 缺点
  • 性能问题
    使用反射基本上是一种解释操作,用于字段和方法接入时要远慢于直接代码。因此java反射机制主要应用在对灵活性和扩展性要求很高的系统框架上,普通程序不建议使用。
  • 使用反射会模糊程序内部逻辑
    程序人员希望在源代码中看到程序的逻辑,反射的等绕过了源代码的技术,因而会带来维护问题。反射代码比相应的直接代码更复杂。

10.3 反射的方法和使用

Class类的常用方法:

方法名 功能说明
getFields() 获得类的public类型的属性
getDeclaredFieldds() 获得类的所有属性
getField(Strign name) 获得类的指定属性
getMethods() 获得类的public类型的方法
getMethod(String name,Class[] args) 获得类的指定方法
getConstrutors() 获得类的public类型的构造方法
getConstrutor(Class[] args) 获得类的特定构造方法
newInstance() 通过类的无参构造方法创建该类的一个对象
getName() 获得类的完整名字
getPackage() 获取此类所属的包
getSuperclass() 获得此类的父类对应的Class对象

使用反射来实例化对象:

public class demo1 {
    public static void main(String[] args) {
        try {
            //1.加载类(加载到JVM中)
            Class clz = Class.forName("com.qhj.fanshe.Administrator");
            //2.1 实例化对象1
            Object objInstance1 = clz.newInstance();//相当于执行Administrator administrator = new Administrator();
            System.out.println(objInstance1);
            //2.2 实例化对象2(使用构造函数)
            Constructor ct = clz.getDeclaredConstructor(null);
            Object objInstance2 = ct.newInstance(null);
            System.out.println(objInstance2);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Administrator类:

public class Administrator {
    public String sex;
    String pox;
    protected double money;
    /**
     * 管理员编号
     */
    private String adminNumber;
    /**
     * 管理员密码
     */
    private String adminPwd;
    /**
     * 管理员名字
     */
    private String adminName;

    public String getAdminNumber() {
        return adminNumber;
    }

    public void setAdminNumber(String adminNumber) {
        this.adminNumber = adminNumber;
    }

    public String getAdminPwd() {
        return adminPwd;
    }

    public void setAdminPwd(String adminPwd) {
        this.adminPwd = adminPwd;
    }

    public String getAdminName() {
        return adminName;
    }

    public void setAdminName(String adminName) {
        this.adminName = adminName;
    }

    public Administrator() {
    }

    public Administrator(String adminNumber, String adminPwd, String adminName) {
        this.adminNumber = adminNumber;
        this.adminPwd = adminPwd;
        this.adminName = adminName;
    }
    public void Hello1(){
//        System.out.println("Hello1");
    }
    public String Hello2(){
        return "success";
    }
    private int Hello3(){
        return 1;
    }
    public void Hello4(String name,int age){
        System.out.println("大家好!我是:"+name+"今年:"+age+"岁了!");
    }
    public String Hello5(String name,int age){
        return "success5";
    }
}
  • 属性(Field)

    /**
    * 通过反射得到类里面的属性(字段)
    */
    public void c1(){
       try {
           //1.加载类(加载到jvm中)
           Class cls = Class.forName("com.qhj.fanshe.Administrator");
           //2.得到类中所有的public属性
           Field[] f = cls.getFields();
           //3.得到类中的所有属性
           Field[] f = cls.getDeclaredFields();
           //4.获得类中指定的public类型属性
           Field ff = cls.getField("sex");
           System.out.println(ff.getName()+"\t访问类型:"+ff.getType()+"\t访问修饰符:"+ff.getModifiers());
    
           for (Field field:f){
               System.out.println(field.getName()+"\t访问类型:"+field.getType().getSimpleName()+"\t访问修饰符:"+ Modifier.toString(field.getModifiers()));
           }
       } catch (Exception e) {
           e.printStackTrace();
       }
    }
    
  • 访问类型

    field.getType();//表示完整的输出(含包名)
    field.getType().getSimpleName();//表示只输出类型(不含包名)
    
  • 属性名

    field.getName();
    
  • 访问修饰符

    /**
    *default 0
    *public  1
    *private 2
    */
    field.getModifiers();//输出数字
    Modifier.toString(field.getModifiers());//输出名字
    
  • 给属性赋值和获取属性值

    /**
    * 通过反射给类中的属性赋值
    */
    public void c2(){
       try {
           //1.加载类(加载到jvm中)
           Class cls = Class.forName("com.qhj.fanshe.Administrator");
           /**
            * 2.获得类中指定的属性
            * 实例化对象,相当于
            * Administrator administrator = new Administrator();
            * administrator.setSex("男");
            */
           Field f1 = cls.getField("sex");
           //实例化对象
           Object objInstance = cls.newInstance();
           //给sex属性赋值
           f1.set(objInstance,"男");
           //得到sex的属性值
           System.out.println(f1.get(objInstance));
       } catch (Exception e) {
           e.printStackTrace();
       }
    }
    
  • 方法(类中的方法)

    /**
    * 通过反射访问类中的方法
    */
    public void c3() {
       try {
           //1.加载类(加载到jvm中)
           Class cls = Class.forName("com.qhj.fanshe.Administrator");
           /**
            * 2.获取的是类的所有共有方法,这就包括自身的所有public方法,和从基类继承的、从接口实现的所有public方法
            */
           Method[] ms = cls.getMethods();
           /**
            * 3.获取的是类自身声明的所有方法,包含public、protected和private方法
            */
           Method[] ms = cls.getDeclaredMethods();
           /**
            * 4.获得类中指定的方法(只有public类型的方法可以指定)
            */
           Method mm1 = cls.getMethod("Hello2");//无参
           Method mmm1 = cls.getMethod("Hello5",String.class,int.class);//有参
    
           Method mm2 = cls.getDeclaredMethod("Hello2");//无参
           Method mmm2 = cls.getDeclaredMethod("Hello5", String.class, int.class);//有参
           Object objInstance = cls.newInstance();
    
           mm1.invoke(objInstance);//invoke()表示调用当前方法并返回执行当前方法的结果
           System.out.println("方法名:"+mm1);
           mmm1.invoke(objInstance,"张三",23);
           mmm1.invoke(objInstance,new Object[]{"李四",12});
    
           mm2.invoke(objInstance);
           System.out.println("方法名:"+mm2.getName());
           System.out.println("返回值:"+mmm2.invoke(objInstance,"王五",52));//获得返回值
           /**
            * 5.构造方法
            */
           //5.1获得类的public类型的无参构造方法
           Constructor cz1 = cls.getConstructor();
           System.out.println("方法名:"+cz1.getName()+"\t访问修饰符:"+Modifier.toString(cz1.getModifiers()));
           //5.2获得类的public类型的有参构造方法
           Constructor cz2 = cls.getDeclaredConstructor(new Class[]{String.class,String.class,String.class});
           Object objInstance2 = cz2.newInstance(new Object[]{"1001","103651","赵六"});
           for (Method m:ms){
               System.out.println("方法名:"+m.getName()+"\t访问修饰符:"+Modifier.toString(m.getModifiers())+"\t返回值类型:"+m.getReturnType().getSimpleName());
           }
       } catch (Exception e) {
           e.printStackTrace();
       }
    }
    
  • 访问方法名

    m.getName();
    
  • 访问修饰符

    m.getModifiers();//数字
    Modifier.toString(m.getModifiers());//名字
    
  • 返回值类型

    m.getReturnType();//完整类型
    m.getReturnType().getSimpleName();//只有返回值类型
    
  • /**
    * 通过反射访问类
    */
    public void c4(){
       try {
           //1.加载类(加载到jvm中)
           Class cls = Class.forName("com.qhj.fanshe.Administrator");
           //2.类的完整名字
           System.out.println(cls.getName());
           //3.类所在的包
           System.out.println(cls.getPackage().getName());
           //4.此类的父类
           System.out.println(cls.getSuperclass());
       } catch (Exception e) {
           e.printStackTrace();
       }
    }
    
  • 类完整名字

    cls.getName();
    
  • 类所在包

    cls.getPackage();
    
  • 此类的父类

    cls.getSuperclass();
    
  • 数组

  • 一维数组

    /**
     * 通过反射动态创建数组并存取元素
     */
    public void c5(){
        try {
            //1.加载类(加载到jvm)
            Class cls = Class.forName("java.lang.Integer");
            //2.创建数组对象
            Object arr = Array.newInstance(cls,10);
            //3.给数组赋值
            Array.set(arr,5,20);
            //4.取出元素
            Object elem = Array.get(arr,5);
            System.out.println(elem);
            /**
             * 相当于
             * int arr[]=new int[10];
             * arr[5]=20;
             * System.out.println(arr[5]);
             */
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
  • 多维数组

    /**
    * 通过反射动态创建数组并存取元素(多维)
    */
    public void c6(){
       // 创建一个含有10*15*18个元素的整型数组
       int dims[] = { 10, 15, 18 };
       Object arr = Array.newInstance(int.class, dims);
       // 给arr[5][8][10]赋值
       Object arr5 = Array.get(arr, 5);
       Object arr58 = Array.get(arr5, 8);
       Array.set(arr58, 10, 30);
       // 取出arr[5][8][10]值并输出
       Object elem = Array.get(arr58, 10);
       System.out.println(elem);
       /**
        * 相当于执行语句:
        * int arr[ ][ ][ ]=new int[10][15][18];
        * arr[5][8][10]=20; System.out.println(arr[5][8][10]);
        */
    }
    
上一篇:Java反射机制总结


下一篇:linux内核分析第一周学习笔记