反射基础概念

这种动态的获取信息及动态调用方法的机制在Java中称为“反射”(reflection)。 
Java反射机制主要提供以下功能: 

在运行时判断任意一个对象所属的类; 
在运行时构造任意一个类的对象; 
在运行时判断任意一个类所具有的成员变量和方法; 
在运行时调用任意一个对象的方法。 

Reflection 是Java被视为动态(或准动态)语言的一个关键性质。这个机制允许程序在运行时透过Reflection APIs取得任何一个已知名称的class的内部信息,包括其modifiers(诸如public, static 等等)、superclass(例如Object)、实现之interfaces(例如Serializable),也包括fields和methods 的所有信息,并可于运行时改变fields内容或调用methods。 


一般而言,开发者社群说到动态语言,大致认同的一个定义是:“程序运行时,允许改变程序结构或变量类型,这种语言称为动态语言”。 


在JDK中,主要由以下类来实现Java反射机制,这些类都位于java.lang.reflect包中: 
Class类:代表一个类; 
Field 类:代表类的成员变量(成员变量也称为类的属性); 
Method类:代表类的方法; 
Constructor 类:代表类的构造方法; 
Array类:提供了动态创建数组,以及访问数组的元素的静态方法; 

在java.lang.Object 类中定义了getClass()方法,因此对于任意一个Java对象,都可以通过此方法获得对象的类型。Class类是Reflection API 中的核心类,它有以下方法: 
getName():获得类的完整名字; 
getFields():获得类的public类型的属性(包括继承的类的public属性); 
getDeclaredFields():获得类的所有属性; 
getMethods():获得类的public类型的方法; (包括继承的类的public方法); 
getDeclaredMethods():获得类的所有方法; 
getMethod(String name, Class[] parameterTypes):获得类的特定方法,name参数指定方法的名字,parameterTypes 参数指定方法的参数类型; 
getConstructors():获得类的public类型的构造方法; 
getConstructor(Class[] parameterTypes):获得类的特定构造方法,parameterTypes 参数指定构造方法的参数类型; 
newInstance():通过类的不带参数的构造方法创建这个类的一个对象; 

(2)通过默认构造方法创建一个新对象: 
Object objectCopy=classType.getConstructor(new Class[]{}).newInstance(new Object[]{}); 
以上代码先调用Class类的getConstructor()方法获得一个Constructor 对象,它代表默认的构造方法,然后调用Constructor对象的newInstance()方法构造一个实例。 



(3)获得对象的所有属性: 
Field fields[]=classType.getDeclaredFields(); 
Class 类的getDeclaredFields()方法返回类的所有属性,包括public、protected、默认和private访问级别的属性。 
import java.lang.reflect.Array;      

public class ArrayTester1      
{      
public static void main(String args[]) throws Exception      
{      
Class<?> classType = Class.forName("java.lang.String");      
// 创建一个长度为10的字符串数组      
Object array = Array.newInstance(classType, 10);      
// 把索引位置为5的元素设为"hello"      
Array.set(array, 5, "hello");      
// 获得索引位置为5的元素的值      
String s = (String) Array.get(array, 5);      
System.out.println(s);      
}      
}  


Java允许我们从多种途径为一个class生成对应的Class object。 



(一)运用getClass()方法: 

String str = "abc"; 

Class class = str.getClass(); 



(二)运用Class.getSuperclass()方法: 

Button b = new Button(); 

Class c1 = b.getSuperclass(); 

Class c2 = c1.getSuperclass(); 



(三)运用静态方法Class.forName(),这个最常用: 

Class c1 = Class.forName("java.lang.String"); 

Class c2 = Class.forName("java.util.Date"); 



(四)运用.class语法: 

Class c1 = String.class; 

Class c2 = java.awt.Button.class; 

Class c3 = int.class; 

Class C4 = int[].class; 



(五)运用原始包装类的TYPE方法: 

Class c1 = Integer.TYPE; 

Class c2 = Character.TYPE; 

Class c3 = Boolean.TYPE; 

Class c4 = Void.TYPE; 


通过这五种方法,可以生成我们想要的类对象。 


其他 


类加载器ClassLoader 


类加载器就是寻找类或接口字节码文件进行解析并构造JVM内部对象表示的组件,在Java中,类加载器把一个类装入JVM中,要经过以下几个步骤: 
1.装载,查找和导入Class文件。 
2.连接,执行校验,准备和解析步骤,其中解析步骤是可以选择的。 
校验:检查载入Class文件数据的正确性。 
准备:给类的静态变量分配内存空间。 
解析:将符号引用转换成直接引用。 
3.初始化:对类的静态变量,静态代码块执行初始化工作。 
类装载工作由ClassLoader及其子类负责,ClassLoader是一个重要的Java运行时系统组件,他负责运行时查找和装入Class字节文件。JVM在运行时会生成三个ClassLoader,根装载器,ExtClassLoader(扩展类装载器)和AppClassLoader(系统类装载器)其中根装载器我们在Java中看不到它,它负责装载JRE的核心类库,ExtClassLoader负责装载JRE扩展目录ext中的JAR类包,AppClassLoader负责装载Classpath路径下的类包。这三个类装载器之间存在父子层级关系,根装载器是ExtClassLoader的父装载器,ExtClassLoader是AppClassLoader的父装载器。默认情况下使用AppClassLoader装载应用程序的类。 
JVM装载类时使用“全盘负责委托机制”,“全盘负责”是指当一个ClassLoader装载一个类时,除非显示地使用另一个ClassLoader,该类所依赖及引用的类也由这个ClassLoader载入,“委托机制”是指委托父类装载器寻找目标类,只有在找不到的情况下才从自己的类路径中查找并装载目标类,这一点是从安全角度考虑的。试想如果有人编写一个恶意的java.lang.String并装载到JVM中将会引起什么可怕的后果,但是由于有了全盘负责制,java.lang.String永远都是由根装载器来装载的。 

ClassLoader重要方法: 


在Java中,ClassLoader是一个抽象类,位于Java.lang包中,下面对该类的一些重要接口方法进行介绍: 


Class loaderClass(String name): name参数指定类装载器需要装载类的名字,必须使用全限定类型(包名+类名)该方法有一个重载方法loaderClass(String name,boolean resolve)其中resolve参数告诉类装载器是否需要解析该类,在初始化之前,应考虑进行类解析工作,但并不是所有的类都需要解析,如果JVM只需要知道该类是否存在或找出该类的超类,那么就不需要进行解析。 


Class defineClass(String name,byte[] bt,int off,int len): 将类文件的字节数组转换成JVM内部的java.lang.Class对象,字节数组可以从本地文件系统,远程网络获取,name为字节数组对象的全限定名。 
Class findSystemClass(String name):从本地文件系统载入Class文件,如果本地文件系统不存在该Class文件,将抛出ClassNotFoundException异常。该方法是JVM默认的装载机制。 


Class findLoadedClass(String name)调用该方法来查看ClassLoader是否已装入某个类,如果已装入那么返回java.lang.Class对象,否则返回null,如果强行装载已存在的类,将会抛出链接错误。 
ClassLoader getParent()获取类装载器的父装载器,除根装载器之外,所有的类装载器都有仅有一个父类装载器。除了JVM默认的三个ClassLoader以外,第三方可以编写自己的类装载器,以显现一些特殊的需求,类文件被装载并解析后,在JVM将拥有一个对应的java.lang.Class类描述对象。该类的实例都拥有指向这个类描述对象的引用,而类描述对象又拥有指向关联ClassLoader的引用。 


每一个类在JVM中都拥有一个对应的java.lang.Class对象,他提供了类结构信息的描述,数组,枚举,以及基本的Java类型,甚至void都拥有对应Class对象,Class没有public的构造方法,Class对象是在装载类时由JVM通过调用类装载器中的defineClass()方法自动创造的。 
Java的反射机制:通过以上的介绍我们可以看到Class反射对象描述类语义结构,可以Class对象中获取构造函数,成员变量,方法类等类元素的反射对象,并以编程的方式通过这些反射对象对目标类对象进行操作。这些反射类对象在java.reflect包中定义。下面介绍主要的三个反射类: 


Constructor:类构造函数反射类,通过Class.getConstructors()方法可以获得类的所有构造函数反射对象数组。在JDK5.0以上的版本我们可以使用getConstructors(Class[] paramerTypes)获取拥有特定入参的构造函数反射对象。Constructor的一个主要方法是newInstance(Object[] initargs)通过该方法我们可以创建一个对象类的实例,相当于使用new关键字。 
Method:类方法的反射类,通过Class.getDeclaredMethods()方法可以获取类的所有方法放射对象数组Method[],在JDK5.0以上的版本我们可以使用getDeclaredMethods(String name,Class parameterTypes)获取特定签名方法,name为方法名,Class为方法入参列表, 

Method最主要的方法是invoke(Object obj,Object[] arges)obj为操作目标对象,arges为方法入参。  
Method 还有很多用于获取类方法更多信息的方法。  
Class getRetunType():获取方法的返回值类型。 
Class getParameterTypes():获取方法的入参类型数组。等等...更多方法参见API。 


Field:类的成员变量的反射类,通过Class#getDeclaredFields()方法可以获取类的成员变量反射对象数组,通过getDeclaredFields(String name)则可以获取某个特定名称的成员变量反射对象。Field类主要的方法是:set(Object obj, Object value) obj表示操作的目 

标对象,通过value为目标对象的成员变量设置值,如果成员变量为基础类型,用户可以使用Field类中提供的带类型名的值设置方法。如 

setBoolean(Object obj,Boolean value). 
在JDK5.0以上还为包及注解提供了AnnotatedElement反射类,总之:Java的反射体系保证了可以通过程序化的方式访问目标类中的所有元素,对于private或protected的成员变量和方法,只要是JVM的安全机制允许,也可以通过反射机制进行调用。 


我们只需要用setAccessible(Boolean bool)方法进行设置就可以取消访问修饰符的限制。 
true表示取消Java语言访问限制,flase表示不取消访问限制。如果在访问private,protected成员变量和方法时没有设置是否取消限制则会抛出IllegalAccessException.如果JVM的安全管理器设置相应的安全机制,调用该方法将抛出SecurityException。 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值