初识java反射

类型信息

一.Class对象

        
Class对象其实就是用来创建所有类的所有的“常规”对象的。java使用Class对象来执行其RTTI(运行时识别类和对象的信息),即使你正在执行的是类似转型这样的操作。

        
类是程序的一部分,每个类都有一个Class对象,换个说法就是每当编写了一个新类的时候,就会产生一个Class对象。为了生成这个类的对象,运行这个程序的java虚拟机(JVM)将使用“类加载器”的子系统。

        
类加载器子系统实际上可以包含一条类加载器链,但是只有一个原生类加载器,它是JVM实现的一部分。原生类加载器加载的是所谓的可信类,包括java API类,它们通常是从本地盘加载。在这条链中,通常不需要添加额外的类加载器,但是如果你有特殊需求(例如以某种特殊的方式加载类,以支持Web服务器应用,或者在网络中下载类),那么你有一种方式可以挂接额外的类加载器。

        
所有的类都是在对其第一次使用时,动态加载到JVM中的,当程序 创建一个对类的静态成员的引用时,就会加载这个类。这个证明构造器也是类的静态方法,即使在构造器之前并没有使用static关键字,因此,使用new操作符创建类的新对象也会被当作对类的静态成员的引用。

        
因此,java程序在他开始运行之前并非完全被加载,其各个部分是在必需时才加载的。

        
类加载器首先检查这个类的Class对象是否已经加载。如果尚未加载,默认的类加载器就会根据类名查找.class文件(例如,某个附加类加载器可能会在数据库中查找字节码)。在这个类的字节码被加载时,它们会接受验证,以确保没有被破坏。并且不包含不良的java代码。

        
一旦某个类的Class对象被载入内存中,它就被用来创建这个类的所有对象

        
Class.forName(“类名”)可以根据提供的类名而取得操作此类对象的引用。如果此方法没有找到你所写的类名,那么他就会抛出一个异常 ClassNotFoundException,无论什么时候,只要你想在运行时使用类型信息,就必须首先获得对恰当的Class对象的引用。Class.forName(“类名”)就是实现此功能的便捷途径,因为你不需要为了获得Class引用而持有该类型的对象。但是如果你已经有个该对象(例如你已经new了你想要的对象),那么就可以此对象调用getClass方法来获取Class引用。这个方法属于根类Object的一部分,它将返回表示该对象的实际类型的Class引用。

通过Class对象可以在运行时发现一个对象完整的类继承结构

获得Class对象的的三种方式
  1. 调用运行时类本身的class属性(不需要实例化对象):

    例如 Class s=String,class

  2. 调用Class.forName()方法(不需要实例化对象):只需要在里面传入所需得到class对象的全路径名即可

    例如:Class

1.2类字面常量

java还提供了另外一种方法来生成对Class对象的引用,即使用类字面常亮,语法如下 类名.class

        
类字面常量不仅可以应用于普通的类,也可以应用于接口,数组以及基本数据类型。

        
当使用“.class”来创建对Class对象的引用时,不会自动的初始化该Class对象。为了使用类而做的准备工作有下面三个步骤:

  1. 加载。这是由类加载器执行的,该步骤将查找字节码(通常在classpath所指定的路径中查找,但是这并非是必须的),并从这些字节码中创建一个Class对象。
  2. 链接。在链接阶段将验证类中的字节码,为静态域分配存储空间,并且如果必需的话,将解析这个类创建的对其他类的所有引用。
  3. 初始化。如果该类具有超类,则对其进行初始化,执行静态初始化器和静态初始化块。

1.3泛化的Class引用

Class引用总是指向某个Class对象,它可以制造类的实例,并包含可作用这些实例的所有方法代码.它还包含该类的静态成员,因此,Class引用表示的就是他所指向的对象的确切类型,而该对象便是Class类的一个对象

        
一次java SE5的设计者看准机会,将它的类型变得更加具体,而这是通过允许你对Class引用所指向的Class对象的类型进行限定而实现的,这里用到了泛型语法,即可以在Class<限定>这样来加泛型以限定想要的Class引用.

        
注意:当使用Class.newInstance()获得实例对象的时候,此对象必须要有一个默认的构造器,不然会报异常

        
当将泛型语法用于Class对象的时候:newInstance()将返回该对象的确切信息,而不仅仅是Object,但是如果你手头上是此对象的超类Class对象,那么如果你调用此超类Class的newInstance()方法那么只能用Object对象接收

二.类型转换前先做检查

        
目前我们已知的运行时识别类的类型信息以下三种:

  1. 传统的类型转换,例如 A a=(A)b.但是如果执行了一个错误的类型转换,就会抛出一个ClassCastException异常.
  2. 代表对象的类型Class对象,通过查询Class对象可以获取运行时所需的信息.
  3. 关键字instanceof.它返回一个布尔值,告诉我们对象是不是某个特定类型的实例.

三.反射:运行时的类信息

3.1反射是什么,与RTTI的区别

        
主要是指程序可以访问、检测和修改它本身状态或行为的一种能力.重要的是,我们要认识到反射并没有什么神奇的地方,当通过反射与一个未知类型的对象打交道的时候,JVM知识简单的检查这个对象,看它属于哪个特定的类(就像RTTI一样).在用它做其他事情之前必须先加载哪个类的Class对象.因此,哪个类的.class文件对于JVM来说必须是可获取的:即要么在本地机器上,要么可以通过网络取得所以RTTI和反射之间真正的区别,对RTTI来说,编译器在编译时打开和检查.class文件(换句话说,我们可以用普通方式调用对象的所有方法).但是对于反射来说.class文件在编译时是不可获取的.所以在运行时打开和检查.class文件

        
Class类和java.lang.reflect类库一起对反射的概念进行了支持,该类库包含了Field,Method以及Constructor类(每个类都实现了Member接口).这些类型的对象是由JVM在运行时创建的,用以表示未知类里所对应的成员信息.这样就可以用Constructor创建新的对象,用哪个get()和set()方法读取和修改Field对象关联的字段,用invoke()方法调用与Method对象关联的方法,另外,还可以调用getFields(),getMethods()和getConstructors()等很便利的方法,以返回表示字段,方法以及构造器的对象的数组

getDeclaredFields()和getFields()方法的区别

        
如果类中有属性的话,两个方法都是返回一个Field数组.其中getDeclaredFields()方法返回的是所有参数包括public, protected, default,private.而getFields()只返回public的参数. getMethods(), getConstructors()都是一样的

        
有下面一个domain类,可以通过反射将他的所有属性信息,方法信息以及构造器的信息在运行时给读取出来

/**
 * @description  TBapInterParadomain
 * @author hu_pf@suixingpay.com
 * @date   20180301 15:47:23
 * @review hu_pf@suixingpay.com/2018-03-01
 */
public class TBapInterPara{
    /**
     * UUID
     */
        private String uuid;

    /**
     * 字段名称
     */
        private String fieldNm;

    /**
     * 字段类型
     */
        private String fieldTyp;

    /**
     * 是否要求输入
     */
        private String required;

    /**
     * 备注
     */
        private String remarks;

    /**
     * 等级
     */
        private String levelPara;

    /**
     * 信息表UUID
     */
        private String infoUuid;

        private ParameVo parameVo;

        private List<ParameVo> parameVos;


    public TBapInterPara() {
        super();
    }

    /**
     * get UUID
     */
        public String getUuid() {
            return uuid;
        }

    /**
     * set UUID
     */
        public void setUuid(String uuid) {
            this.uuid = uuid;
        }

    /**
     * get 字段名称
     */
        public String getFieldNm() {
            return fieldNm;
        }

    /**
     * set 字段名称
     */
        public void setFieldNm(String fieldNm) {
            this.fieldNm = fieldNm;
        }

    /**
     * get 字段类型
     */
        public String getFieldTyp() {
            return fieldTyp;
        }

    /**
     * set 字段类型
     */
        public void setFieldTyp(String fieldTyp) {
            this.fieldTyp = fieldTyp;
        }

    /**
     * get 是否要求输入
     */
        public String getRequired() {
            return required;
        }

    /**
     * set 是否要求输入
     */
        public void setRequired(String required) {
            this.required = required;
        }

    /**
     * get 备注
     */
        public String getRemarks() {
            return remarks;
        }

    /**
     * set 备注
     */
        public void setRemarks(String remarks) {
            this.remarks = remarks;
        }

    /**
     * get 等级
     */
        public String getLevelPara() {
            return levelPara;
        }

    /**
     * set 等级
     */
        public void setLevelPara(String levelPara) {
            this.levelPara = levelPara;
        }

    /**
     * get 信息表UUID
     */
        public String getInfoUuid() {
            return infoUuid;
        }

    /**
     * set 信息表UUID
     */
        public void setInfoUuid(String infoUuid) {
            this.infoUuid = infoUuid;
        }

}

/**
 * @program: demo
 * @description: 反射
 * @author: hu_pf@suixingpay.com
 * @create: 2018-03-29 16:02
 **/
public class Demo11 {
    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
        Class<TBapInterPara> tBapInterParaClass=TBapInterPara.class;
        Field[] fields = tBapInterParaClass.getDeclaredFields();//获得所有的字段,包括private的
        Method[] methods = tBapInterParaClass.getMethods();
        tBapInterParaClass.getDeclaredMethods();
        Constructor<?>[] constructors = tBapInterParaClass.getConstructors();
        for (int i = 0; i < fields.length; i++) {
            System.out.println(fields[i].getType());
            System.out.println(fields[i].getName());
            System.out.println("-----------------");

        }
        System.out.println("methods:");
        for (int k = 0; k < methods.length; k++) {
            System.out.println(methods[k].getName());
            System.out.println("-----------------");
        }
        System.out.println("constructors:");
        for (int j = 0; j < constructors.length; j++) {
            System.out.println(constructors[j]);
        }
    }
}

运行结果

class java.lang.String
uuid
-----------------
class java.lang.String
fieldNm
-----------------
class java.lang.String
fieldTyp
-----------------
class java.lang.String
required
-----------------
class java.lang.String
remarks
-----------------
class java.lang.String
levelPara
-----------------
class java.lang.String
infoUuid
-----------------
class tese2.ParameVo
parameVo
-----------------
interface java.util.List
parameVos
-----------------
methods:
getUuid
-----------------
setUuid
-----------------
getFieldNm
-----------------
setFieldNm
-----------------
getFieldTyp
-----------------
setFieldTyp
-----------------
getRequired
-----------------
setRequired
-----------------
getRemarks
-----------------
setRemarks
-----------------
getLevelPara
-----------------
setLevelPara
-----------------
getInfoUuid
-----------------
setInfoUuid
-----------------
wait
-----------------
wait
-----------------
wait
-----------------
equals
-----------------
toString
-----------------
hashCode
-----------------
getClass
-----------------
notify
-----------------
notifyAll
-----------------
constructors:
public tese2.TBapInterPara()
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值