java Class 与反射
2021-08-27 14:49:48 0 举报
AI智能生成
java Class 与反射
作者其他创作
大纲/内容
RTTI
RTTI - 运行时类型识别 - Run-Time Type Identification
RTTI是什么?和反射是什么关系?
- RTTI是指一种思想:当有一个指向基础型别(父类)的reference(引用)时,RTTI机制让你找出其所指的确切型别。
- 反射是RTTI的一种实现技术。RTTI的实现有2种, 分别是编译期确定 和 反射reflection机制(后期绑定)。
什么是后期绑定机制?java中的多态是怎么实现的?
- 首先Java的所有方法绑定都采用“后期绑定”技术!!!
- 要实现后期绑定机制, 那么java需要提供一些工具, 以便方法在运行时间正确判断对象类型,并调用适当的方法。这个工具就是“反射技术”。
- java多态就是隐式的(非程序员主动发起)使用了反射技术,在方法运行时, 判断方法的对象归属, 从而调用适当的方法。
深入理解Class对象
这里首先做概念上的定义和区分:
Java类 Java对象 Class类 Class对象
Java类
一个.class文件 对应一个Java类
Java对象
.class文件被加载进JVM后,被JVM new出来的一个实例
Class类
也属于一个java类,是一个泛型的类。
- Java.lang.Class是一个比较特殊的类,它用于封装被装入到JVM中的类(包括类和接口)的信息。
- Class类只存私有构造函数,因此对应Class对象只能有JVM创建和加载。
Class对象
虚拟机会为每个.class文件创建一个Class对象, 里面保存的是基本信息, 用于实现RTTI运行时类型识别。
Class对象的加载及其获取方式
首先 Class对象是由JVM自动加载的!!!
JVM加载Class对象的时机是?
实际上所有的类都是在对其第一次使用时动态加载到JVM中的,当程序创建第一个对类的静态成员引用时,JVM就会加载这个被使用的类.
实际上所有的类都是在对其第一次使用时动态加载到JVM中的,当程序创建第一个对类的静态成员引用时,JVM就会加载这个被使用的类.
什么是类加载?
把这个类的字节码文件, 转换为内存模型保存到JVM方法区中。
把这个类的字节码文件, 转换为内存模型保存到JVM方法区中。
什么是类初始化?
在类加载完成后, 在堆区创建描述这个类的java.lang.Class对象
在类加载完成后, 在堆区创建描述这个类的java.lang.Class对象
上面说, 当程序第一次对类的静态成员引用时才会触发类加载,为什么在new 对象时,类加载也会被触发?
new表达式简单理解创建对象并初始化!
new表达式简单理解创建对象并初始化!
获取Class对象
调用Object类的getClass()方法
所有Java对象都具备这个方法,该方法用于返回调用该方法的对象的所属类关联的Class对象
List list = new ArrayList();
System.out.println(list.getClass().getName()); // java.util.ArrayList
List list = new ArrayList();
System.out.println(list.getClass().getName()); // java.util.ArrayList
可以通过这个方法了解一个对象的运行时类型
因为抽象类和接口不可能实例化对象,因此不能通过Object的getClass方法获得与抽象类和接口关联的Class对象
使用.class的方式 只是字面常量
使用类名加“.class”的方式即会返回与该类对应的Class对象.
Class clazz = String.class;
System.out.println(clazz.getName()); // java.lang.String
Class clazz = String.class;
System.out.println(clazz.getName()); // java.lang.String
可以直接获得与指定类关联的Class对象,而并不需要有该类的对象存在。
为什么使用字面常量的方式获取Class对象的引用不会触发类的初始化?
我们获取字面常量的Class引用时,触发的应该是加载阶段。
因为不涉及对象的创建,也不涉及到对静态成员的引用,只是获取类的相关信息,加载过程没到初始化阶段。
我们获取字面常量的Class引用时,触发的应该是加载阶段。
因为不涉及对象的创建,也不涉及到对静态成员的引用,只是获取类的相关信息,加载过程没到初始化阶段。
首先了解类加载过程:
- 加载:类加载过程的一个阶段:通过一个类的完全限定查找此类字节码文件,并利用字节码文件创建一个Class对象
- 链接:验证字节码的安全性和完整性,准备阶段正式为静态域分配存储空间,注意此时只是分配静态成员变量的存储空间,不包含实例成员变量,如果必要的话,解析这个类创建的对其他类的所有引用。
- 初始化:类加载最后阶段,若该类具有超类,则对其进行初始化,执行静态初始化器和静态初始化成员变量。
使用Class.forName方法
- 该方法可以根据字符串参数所指定的类名获取与该类关联的Class对象。
- 如果该类还没有被装入,该方法会将该类装入JVM。
- JVM装入被加载类后对其进行初始化,调用了其static块中的代码。
小总结
获取Class对象引用的方式3种:
- 通过继承自Object类的getClass方法
- Class类的静态方法forName
- 字面常量的方式”.class”
实例类的getClass方法 和 Class.forName()都将会触发类的初始化阶段, 而字面常量获取Class对象的方式则不会触发初始化。
如果要问为什么, 仔细看上面的分析。
如果要问为什么, 仔细看上面的分析。
初始化是类加载的最后一个阶段,也就是说完成这个阶段后类也就加载到内存中(Class对象在加载阶段已被创建),此时可以对类进行各种必要的操作了(如new对象,调用静态成员等),注意在这个阶段,才真正开始执行类中定义的Java程序代码或者字节码。
instanceof 关键字与isInstance方法
事实上instanceOf 与isInstance方法产生的结果是相同的
关于instanceof 关键字,它返回一个boolean类型的值,意在告诉我们对象是不是某个特定的类型实例。
isInstance方法则是Class类中的一个Native方法,也是用于判断对象类型的
Class类的常用方法
例如:x.getClass.newInstance(),创建了一个同x一样类型的新实例。newInstance()方法调用默认构造器(无参数构造器)初始化新建对象。
虚拟机为每种类型管理一个独一无二的Class对象。因此可以使用==操作符来比较类对象。例如: if(e.getClass() == Employee.class)
//下面两句等同于Dog dog = (Dog) animal;
Class<Dog> dogType = Dog.class;
Dog dog = dogType.cast(animal)
- getName()
- newInstance()
例如:x.getClass.newInstance(),创建了一个同x一样类型的新实例。newInstance()方法调用默认构造器(无参数构造器)初始化新建对象。
- getClassLoader()
- getComponentType()
- getSuperclass()
- isArray()
虚拟机为每种类型管理一个独一无二的Class对象。因此可以使用==操作符来比较类对象。例如: if(e.getClass() == Employee.class)
- cast
//下面两句等同于Dog dog = (Dog) animal;
Class<Dog> dogType = Dog.class;
Dog dog = dogType.cast(animal)
反射
反射的作用
在运行时判断任意一个对象所属的类;
在运行时获取类的对象;
在运行时访问java对象的属性,方法,构造方法等。
反射机制的示例
通过一个对象获得完整的包名和类名
Demo demo=new Demo();
demo.getClass().getName()
demo.getClass().getName()
实例化Class类对象
Class<?> demo = Class.forName("Reflect.Demo");
通过Class实例化一个类的对象
Person per = demo.newInstance();
取得一个类的构造函数
Constructor<?> cons[]=demo.getConstructors();
返回一个类实现的接口
Class<?> intes[]=demo.getInterfaces();
取得一个类中的父类
Class<?> temp=demo.getSuperclass();
取得一个类的全部属性
Field[] field = demo.getDeclaredFields();
通过反射调用一个类中的方法
Method method=demo.getMethod("sayChina");
method.invoke(demo.newInstance());
method.invoke(demo.newInstance());
通过反射操作属性
Field field = demo.getDeclaredField("sex");
field.setAccessible(true);
field.set(obj, "男");
field.setAccessible(true);
field.set(obj, "男");
0 条评论
下一页