• Java反射机制


    虚拟机在class文件的加载阶段,把类信息保存在方法区数据结构中,并在Java堆中生成一个Class对象,作为类信息的入口。

    假如你写了一段代码:Object o=new Object();

    运行了起来!

    首先JVM会启动,你的代码会编译成一个.class文件,然后被类加载器加载进jvm的内存中,你的类Object加载到方法区中,创建了Object类的class对象到堆中,注意这个不是new出来的对象,而是类的类型对象,每个类只有一个class对象,作为方法区类的数据结构的接口。jvm创建对象前,会先检查类是否加载,寻找类对应的class对象,若加载好,则为你的对象分配内存,初始化也就是代码:new Object()。

    反射之中包含了一个“反”的概念,所以要想解释反射就必须先从“正”开始解释:一般而言,当用户使用一个类的时候,应该先知道这个类,而后通过这个类产生实例化对象。

    但是“反”指的是通过对象找到类。

    package cn.design.factory;
    
    public class ReflactTest {
        public static void main(String[] args) {
            BenzSport bs=new BenzSport();
            System.out.println(bs.getClass().getName());
        }
    }

    以上的代码使用了一个getClass()方法,而后就可以得到对象所在的“包.类”名称,这就属于“反”了,但是在这个“反”的操作之中有一个getClass()就作为发起一切反射操作的开端。

    BenzSport的父类是Object类,而上面所使用getClass()方法就是Object类之中所定义的方法。

    取得Class对象:public final Class<?> getClass(),反射之中的所有泛型都定义为?,返回值都是Object。

    而这个getClass()方法返回的对象是Class类的对象(在堆中的class类对象作为方法区数据接口的接口)所以这个Class就是所有反射操作的源头。

    但是在讲解其真正使用之前还有一个需要先解释的问题,既然Class是所有反射操作的源头,那么这个类肯定是最为重要的,而如果要想取得这个类的实例化对象,Java中定义了三种方式:
    方式一:通过Object类的getClass()方法取得,基本不用:
    package cn.design.factory;
    
    public class ReflactTest {
        public static void main(String[] args) {
            BenzSport bs=new BenzSport();//通过类获取对象
            Class<?> c=bs.getClass();//通过对象获取类对象
            System.out.println(c);//反着来
        }
    }

    方式二:使用“类.class”取得,在日后学习Hibernate开发的时候使用

    package cn.design.factory;
    
    public class ReflactTest {
        public static void main(String[] args) {
            BenzSport bs=new BenzSport();//通过类获取对象
            Class<?> c=BenzSport.class;//通过对象获取类对象
            System.out.println(c.getName());//反着来
        }
    }

    方式三:使用Class类内部定义的一个static方法,主要使用

    public static Class<?> forName(String className) throws ClassNotFoundException

    package cn.design.factory;
    
    public class ReflactTest {
        public static void main(String[] args) throws Exception {
            BenzSport bs=new BenzSport();
            
            Class<?> c=Class.forName("cn.design.factory.BenzSport");
            
            System.out.println(c.getName());
        }
    }

    取得了Class类的对象有什么用处呢?对于对象的实例化操作之前一直依靠构造方法和关键字new完成,可是有了Class类对象之后,现在又提供了另外一种对象的实例化方法:

    package cn.design.factory;
    
    public class ReflactTest {
        public static void main(String[] args) throws Exception {
            BenzSport bs=new BenzSport();
            
            Class<?> c = Class.forName("cn.design.factory.BenzSport");//获取类对象(Object对象)
            Object o=c.newInstance();//实例化一个对象和new的作用一样
            BenzSport bbs=(BenzSport) o;//向下转型为你需要的类型
            System.out.println(bbs);
        }
    }

    反射的深入应用

    以上只是利用了Class类作为了反射实例化对象的基本应用,但是对于一个实例化对象而言,它需要调用类之中的构造方法、普通方法、属性,而这些操作都可以通过反射机制完成。

    一:调用构造方法

    package cn.design.factory;
    
    import java.lang.reflect.Constructor;
    
    public class ReflactTest {
        public static void main(String[] args) throws Exception {
            BenzSport bs=new BenzSport();
            
            Class<?> c = Class.forName("cn.design.factory.BenzSport");//获取类对象(Object对象)
            Constructor<?> con[]=c.getConstructors();//获取全部的构造方法
            for(int i=0;i<con.length;i++){
                System.out.println(con[i]);
            }
            
        }
    }

    如果被反射的类中没有无参构造方法的话会报错

    package cn.design.factory;
    
    import java.lang.reflect.Constructor;
    
    public class ReflactTest {
        public static void main(String[] args) throws Exception {
            
            Class<?> c = Class.forName("cn.design.factory.BenzSport");//获取类对象(Object对象)
            Object o=c.newInstance();
            
        }
    }

    package cn.design.factory;
    
    import java.lang.reflect.Constructor;
    
    public class ReflactTest {
        public static void main(String[] args) throws Exception {
            
            Class<?> c = Class.forName("cn.design.factory.BenzSport");//获取类对象(Object对象)
            Constructor<?> cons=c.getConstructor(String.class);
            Object o =cons.newInstance("C级别轿跑");
        }
    }

    很明显,调用无参构造方法实例化对象要比调用有参构造的更加简单、方便,所以在日后的所有开发之中,凡是有简单Java类出现的地方,都一定要提供无参构造。

    二:调用普通方法

    package cn.design.factory;
    import java.lang.reflect.Method;
    public class ReflactTest {
        public static void main(String[] args) throws Exception {
            
            Class<?> c = Class.forName("cn.design.factory.BenzSport");//获取类对象(Object对象)
            Method meths[]=c.getMethods();//获取类中全部的方法包括自身类的方法及父类的方法
            for(int i=0;i<meths.length;i++){
                System.out.println(meths[i]);
            }
        }
    }

    package cn.design.factory;
    import java.lang.reflect.Method;
    public class ReflactTest {
        public static void main(String[] args) throws Exception {
            
            Class<?> c = Class.forName("cn.design.factory.BenzSport");//获取类对象(Object对象)
            Object obj=c.newInstance();
            Method runMet=c.getMethod("run");//调用run方法
            runMet.invoke(obj);//调用无参方法run()
            String attr="Name";
            Method setMet=c.getMethod("set"+attr, String.class);//调用set(String)方法
            Method getMet=c.getMethod("get"+attr);//调用String get()方法
            setMet.invoke(obj, "梅赛德斯奔驰");
            System.out.println(getMet.invoke(obj));
            
        }
    }

    在日后的所有框架技术开发之中,简单Java类都是如此应用的,所以必须按照标准进行。

    三:调用成员

    package cn.design.factory;
    import java.lang.reflect.Field;
    public class ReflactTest {
        public static void main(String[] args) throws Exception {
            
            Class<?> c = Class.forName("cn.design.factory.BenzSport");//获取类对象(Object对象)
            Field field[]=c.getDeclaredFields();//获取全部属性
            for(int i=0;i<field.length;i++){
                System.out.println(field[i]);
            }
        }
    }

    package cn.design.factory;
    import java.lang.reflect.Field;
    public class ReflactTest {
    public static void main(String[] args) throws Exception {
    
    Class<?> c = Class.forName("cn.design.factory.BenzSport");//获取类对象(Object对象)
    Field field[]=c.getDeclaredFields();//获取全部属性
    for(int i=0;i<field.length;i++){
    System.out.println(field[i]);
    }
    Object obj=c.newInstance();// 对象实例化属性才会分配空间
    Field nameField=c.getDeclaredField("name");
    nameField.setAccessible(true);//解除封装
    nameField.set(obj, "翎野君");//对象.name="翎野君"
    System.out.println(nameField.get(obj));//对象.name
    }
    }

  • 相关阅读:
    Oracle数据库的备份及恢复策略研讨
    ast入门 (一)
    DisableThreadLibraryCalls
    写入注册表实现自启动
    QT学习1 hello程序
    打印断言函数
    注册表基本知识
    RAS详解
    const
    QT安装
  • 原文地址:https://www.cnblogs.com/lingyejun/p/7124713.html
Copyright © 2020-2023  润新知