java 反射类的理解与应用
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java 反射类的理解与应用相关的知识,希望对你有一定的参考价值。
本文主要解析的类是:
ClassLodaer,Class,Field,Method,Constructor.
本文的目标很简单,只是对这些常用的反射类进行简单解释。对这些类中常用方法进行介绍。
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
Java反射机制主要提供了以下功能: 在运行时判断任意一个对象所属的类;在运行时构造任意一个类的对象;在运行时判断任意一个类所具有的成员变量和方法;在运行时调用任意一个对象的方法;生成动态代理。
Class:
public final class Class<T> extends Object implements Serializable, GenericDeclaration, Type, AnnotatedElement
class 的声明表示class是一个终类,是一个对象,并且可序列化。
Class 没有公共构造方法。Class
对象是在加载类时由 Java 虚拟机以及通过调用类加载器中的 defineClass
方法自动构造的。
以下示例使用 Class
对象来显示对象的类名:(利用Object.getClass())
Object obj=new Object(); System.out.println(obj.getClass().getName());
这里注意下getClass() 方法:
public final native Class<?> getClass();
调用了本地方法来获取该类的Class。
class 关键字 和 getClass() 的区别。
public class Animal{} public class Dog extends Animal { public static void main(String[] args) { Animal animal = new Dog(); System.out.println("getClass(): "+animal.getClass().getName()); System.out.println("class: "+Animal.class.getName()); } } 输出结果 getClass(): com.abc.Dog class: com.abc.Animal
由于object.getclass()的方法存在,内存中任意对象都可以获得自身的类型。而反射的是通过对字节码文件进行解析。
反射方法: forName()
@CallerSensitive public static Class<?> forName(String className) throws ClassNotFoundException { Class<?> caller = Reflection.getCallerClass(); return forName0(className, true, ClassLoader.getClassLoader(caller), caller); }
这是最常用的反射方法。对于一个字节码文件名进行解析,得到class。其中也可以看到,forName()在解析时,类加载器也进行了参与。
ClassLoader是什么?有什么作用?
大家都知道,一个Java程序是由若干个.class文件组织而成的。当程序在运行时,即会调用该程序的一个入口函数来调用系统的相关功能,而这些功能都被封装在不同的class文件当中,所以经常要从这个class文件中要调用另外一个class文件中的方法,如果另外一个文件不存在的,则会引发系统异常。而程序在启动的时候,并不会一次性加载程序所要用的所有class文件,而是根据程序的需要,通过Java的类加载机制(ClassLoader)来动态加载某个class文件到内存当中的,从而只有class文件被载入到了内存之后,才能被其它class所引用。所以ClassLoader就是用来动态加载class文件到内存当中用的。
类加载器所创建对象的方法和构造方法可以引用其他类。为了确定引用的类,Java 虚拟机将调用最初创建该类的类加载器的 loadClass
方法。
例如,应用程序可以创建一个网络类加载器,从服务器中下载类文件。示例代码如下所示:
ClassLoader loader = new NetworkClassLoader(host, port); Object main = loader.loadClass("Main", true).newInstance();
(classLoader的相关知识点,不在本文中进行梳理。)
Class.forName(String className);
有效类名称的示例包括:(package.className)
"java.lang.String" "javax.swing.JSpinner$DefaultEditor" "java.security.KeyStore$Builder$FileBuilder$1" "java.net.URLClassLoader$3$1"
Class.forName(String className) 需抛出异常:ClassNotFoundException。
Class clazz=Class.forName("testReflect.ATest"); System.out.println(clazz.getClass().getName()); System.out.println(clazz.getClassLoader()); Object obj=clazz.newInstance(); System.out.println("此对象是"+obj.getClass().getName()); 输出结果 java.lang.Class [email protected] 此对象是testReflect.ATest
后面所介绍类采用代码介绍
被用来反射的类
package testReflect; public class ATest { private int field1=1; public String field2="field2"; private int method1(){ return 1; } public String method2(String a){ return "method2"; } public ATest(){} public ATest(int b){} }
测试类
package testReflect; import java.lang.reflect.*; public class Main { public static void main(String[] args) { try { Class clazz=Class.forName("testReflect.ATest"); System.out.println(clazz.getClass().getName()); System.out.println(clazz.getClassLoader()); Object obj=clazz.newInstance(); System.out.println("此对象是"+obj.getClass().getName()); /** * class 中获取field 的方法为 * 1.getDeclaredField("field1"); * 2.getDeclaredFields(); 返回 Field 对象的一个数组,这些对象反映此 Class * 对象所表示的类或接口所声明的所有字段。包括公共、保护、默认(包)访问和私有字段,但不包括继承的字段。 * 3.getFields(); * 4.getFields("field2"); * * * * */ Field field1=clazz.getDeclaredField("field1"); field1.setAccessible(true); System.out.println(field1); System.out.println(field1.getName()+":"+field1.get(obj)); Field[] fields1=clazz.getFields(); Field[] fields2=clazz.getDeclaredFields(); System.out.println(fields1.length); System.out.println(fields2.length); Method method1=clazz.getDeclaredMethod("method1", null); method1.setAccessible(true); System.out.println(method1); Object value1=method1.invoke(obj, null); System.out.println("method1 返回的值为"+value1); Method method2=clazz.getDeclaredMethod("method2",String.class); System.out.println(method2); System.out.println(method2.getParameterTypes().length); System.out.println("method2 返回的值为"+method2.invoke(obj,"1")); Method[] methods1=clazz.getDeclaredMethods(); //返回的方法数组,方法的顺序并不确定 for(int i=0;i<methods1.length;i++){ System.out.println(methods1[i]); if("method2".equals(methods1[i].getName())) System.out.println("method2的参数列表"+methods1[i].getParameterTypes()); } Constructor cons1=clazz.getDeclaredConstructor(null); Constructor cons2=clazz.getDeclaredConstructor(int.class); System.out.println(cons1); System.out.println(cons2); Object o1=cons2.newInstance(1); System.out.println(o1.getClass()); } catch (ClassNotFoundException e) { // TODO 自动生成的 catch 块 e.printStackTrace(); } catch (InstantiationException e) { // TODO 自动生成的 catch 块 e.printStackTrace(); } catch (IllegalAccessException e) { // TODO 自动生成的 catch 块 e.printStackTrace(); } catch (NoSuchFieldException e) { // TODO 自动生成的 catch 块 e.printStackTrace(); } catch (SecurityException e) { // TODO 自动生成的 catch 块 e.printStackTrace(); } catch (NoSuchMethodException e) { // TODO 自动生成的 catch 块 e.printStackTrace(); } catch (IllegalArgumentException e) { // TODO 自动生成的 catch 块 e.printStackTrace(); } catch (InvocationTargetException e) { // TODO 自动生成的 catch 块 e.printStackTrace(); } } }
输出结果:
java.lang.Class
[email protected]
此对象是testReflect.ATest
private int testReflect.ATest.field1
field1:1
1
2
private int testReflect.ATest.method1()
method1 返回的值为1
public java.lang.String testReflect.ATest.method2(java.lang.String)
1
method2 返回的值为method2
private int testReflect.ATest.method1()
public java.lang.String testReflect.ATest.method2(java.lang.String)
method2的参数列表[Ljava.lang.Class;@52e922
public testReflect.ATest()
public testReflect.ATest(int)
class testReflect.ATest
本文的目的,不在于详解。所以大家也可直接拿代码去做测试。
以上。
以上是关于java 反射类的理解与应用的主要内容,如果未能解决你的问题,请参考以下文章