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