反照基础概念
反射基础概念
这种动态的获取信息及动态调用方法的机制在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。
这种动态的获取信息及动态调用方法的机制在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。