反射(Reflecting)是Java的特征之一,它允许Java程序在运行期间,操作类或对象的内部属性。
Oracle官方对反射的解释是:
Reflection enables Java code to discover information about the fields, methods and constructors of loaded classes, and to use reflected fields, methods, and constructors to operate on their underlying counterparts, within security restrictions. The API accommodates applications that need access to either the public members of a target object (based on its runtime class) or the members declared by a given class. It also allows programs to suppress default reflective access control.
反射使Java代码具有在安全限制下发现装载类字段,方法和构造器并且使用反射字段,方法和构造来操作类的的底层对象。
API容纳需要访问目标对象的公共成员(基于其运行时类)或给定类声明的成员的应用程序。它还允许程序抑制默认的反射访问控制。
反射的用途 反射使得Java程序能在运行时 ,动态获取创建参数并获取其属性。
Java 反射主要提供以下功能:
在运行时判断任意一个对象所属的类;
在运行时构造任意一个类的对象;
在运行时判断任意一个类所具有的成员变量和方法(通过反射甚至可以调用private方法);
在运行时调用任意一个对象的方法
具体应用 :在Spring系列框架中,大量使用了反射,比如判断应用参数动态加载类的内容。比如类的序列化中,获取对象的readObject\writeObject方法等等。
反射的具体运用 Java反射机制主要通过class,Constructor,Field,Method 四个类来实现。
反射的相关内容基本都在java.util.relfect 包下。
获得Class对象 1 2 3 4 5 Class<?> a = new Person ().getClass(); Class<?> b = Person.class; Class<?> c = Class.forName("bean.Person" ); System.out.println(a.equals(b) && a.equals(c));
判断是否为某个类的实例 1 2 3 System.out.println(new Person () instanceof Father); System.out.println(Father.class.isInstance(new Person ()));
使用instanceof
关键字来判断是否为某个类的实例
也可使用反射中Class对象的isInstance()
方法来判断是否为某个类的实例(native方法)
创建实例 1 2 3 4 5 6 7 8 9 10 Person reflectPerson0 = Person.class.newInstance();Person reflectPerson1 = new Person ().getClass().newInstance();Person reflectPerson2 = (Person) Class.forName("bean.Person" ).newInstance();Constructor<Person> constructor = Person.class.getConstructor(String.class,Integer.class,Gender.class); Person reflectPerson3 = constructor.newInstance("zibu" ,new Integer (11 ),Gender.MALE);
获取方法 获取某个class对象的方法集合,有以下三种方法
getDeclardMethods
可以获取私有方法 ,但不能访问继承方法
1 2 3 4 5 6 7 8 9 10 public Method[] getDeclaredMethods() throws SecurityExceptionpublic Method[] getMethods() throws SecurityExceptionpublic Method getMethod (String name, Class<?>... parameterTypes)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 Method[] methods = Person.class.getMethods(); Method[] declaredMethods = Person.class.getDeclaredMethods(); Method toStringMethod = Person.class.getMethod("toString" );System.out.println("getMethods获取的方法:" ); for (Method m:methods){ System.out.println(m); } System.out.println("getDeclaredMethods获取的方法:" ); for (Method m:declaredMethods){ System.out.println(m); } System.out.println(toStringMethod); getMethods获取的方法: public java.lang.String bean.Person.toString()public final void java.lang.Object.wait(long ,int ) throws java.lang.InterruptedExceptionpublic final native void java.lang.Object.wait(long ) throws java.lang.InterruptedExceptionpublic final void java.lang.Object.wait() throws java.lang.InterruptedExceptionpublic boolean java.lang.Object.equals(java.lang.Object)public native int java.lang.Object.hashCode()public final native java.lang.Class java.lang.Object.getClass()public final native void java.lang.Object.notify()public final native void java.lang.Object.notifyAll()getDeclaredMethods获取的方法: public java.lang.String bean.Person.toString()private void bean.Person.readObject(java.io.ObjectInputStream) throws java.io.IOException,java.lang.ClassNotFoundExceptionprivate void bean.Person.writeObject(java.io.ObjectOutputStream) throws java.io.IOExceptionpublic java.lang.String bean.Person.toString()
获取类的成员变量(字段)信息
getField
:访问公有(public)的成员变量
getDeclaredField
:所有已声明的成员变量,但不能得到父类的成员变量
使用方法同method, 不再赘述。
调用方法 当我们通过反射获取到类的method时,可以通过invoke()
方法来调用这个方法。
1 2 3 public Object invoke (Object obj, Object... args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException
1 2 3 4 5 6 7 8 9 10 11 Method method = Person.class.getMethod("test" ,String.class);method.invoke(Person.class.newInstance(),"111111" ); public void test (String temp) { System.out.println(temp); }
利用反射创建数组 1 2 3 4 5 6 7 8 9 10 11 12 Class<?> cls = Class.forName("java.lang.String" ); Object array = Array.newInstance(cls,25 );Array.set(array,0 ,"hello" ); Array.set(array,1 ,"Java" ); Array.set(array,2 ,"fuck" ); Array.set(array,3 ,"Scala" ); Array.set(array,4 ,"Clojure" ); System.out.println(Array.get(array,3 ));
Array
是java.lang.reflect包下的final对象。
1 2 3 4 5 6 7 8 public static Object newInstance (Class<?> componentType, int length) throws NegativeArraySizeException { return newArray(componentType, length); } private static native Object newArray (Class<?> componentType, int length) throws NegativeArraySizeException;
源码目录:openjdk\hotspot\src\share\vm\runtime\reflection.cpp
Array 类的 set
和 get
方法都为 native 方法,在 HotSpot JVM 里分别对应 Reflection::array_set
和 Reflection::array_get
方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 arrayOop Reflection::reflect_new_array (oop element_mirror, jint length, TRAPS) { if (element_mirror == NULL ) { THROW_0 (vmSymbols::java_lang_NullPointerException ()); } if (length < 0 ) { THROW_0 (vmSymbols::java_lang_NegativeArraySizeException ()); } if (java_lang_Class::is_primitive (element_mirror)) { Klass* tak = basic_type_mirror_to_arrayklass (element_mirror, CHECK_NULL); return TypeArrayKlass::cast (tak)->allocate (length, THREAD); } else { Klass* k = java_lang_Class::as_Klass (element_mirror); if (k->oop_is_array () && ArrayKlass::cast (k)->dimension () >= MAX_DIM) { THROW_0 (vmSymbols::java_lang_IllegalArgumentException ()); } return oopFactory::new_objArray (k, length, THREAD); } }
总结 本文主要讲述了反射的基础内容,围绕着class,Constructor,Field,Method 四个类讲述了反射的使用。关于反射更为具体的实现,原理等内容等待下次完善。