为了正常的体验网站,请在浏览器设置里面开启Javascript功能!

Java反射机制

2017-08-31 25页 doc 61KB 9阅读

用户头像

is_215732

暂无简介

举报
Java反射机制Java反射机制 Java反射机制 一、 Java反射机制 1、什么是java语言的反射机制 JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。 2、Java反射机制主要提供了以下功能: , 在运行时判断任意一个对象所属的类 , 在运行时构造任意一个类的对象 , 在运行时判断任意一个类所具有的成员变量和方法 , 在运行时调用任意一个对象的方法 , 生成动态代理...
Java反射机制
Java反射机制 Java反射机制 一、 Java反射机制 1、什么是java语言的反射机制 JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和;对于任意一个对象,都能够调用它的任意一个方法;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。 2、Java反射机制主要提供了以下功能: , 在运行时判断任意一个对象所属的类 , 在运行时构造任意一个类的对象 , 在运行时判断任意一个类所具有的成员变量和方法 , 在运行时调用任意一个对象的方法 , 生成动态代理 3、Java反射的用途 Java 语言的反射机制提供了一种非常通用的动态连接程序组件的方法。它允许你的程序创建和维护任何类的对象(服从安全限制),而不需要提前对目标类进行硬编码。这些特征使得反射在创建与对象一同工作的类库中的通用方法方面非常有用。例如,反射经常被用于那些数据库,XML,Eclipse或者其它的外部的框架中,如Struts,Spring,Hibernate。 二、类加载机制与ClassLoader 1、什么是类加载器 Classloader 与普通程序不同的是,Java程序(class文件)并不是本地的可执行程序。当运行Java程序时,首先运行JVM(Java虚拟机),然后再把Java class加载到JVM里头CodeSegment(代码段)运行,负责加载Java class的这部分就叫做Class Loader。因此Classloader也叫做类加载器。 2、Java类加载机制 , 类加载是动态执行的,也就是说当我们用到的时候才会去加载,如果不用的话,就不会 去加载我们的类。 , 类加载有两种方式:第一种就是new一个对象的时候,另一种就是当一个类的静态代码 被调用的时候 , 静态初始化语句块在加载时只执行一次,而初始化语句块在每次new出新的对象是都会 执行,等同于构造方法中的语句。 , java-verbose:class可以观察类的具体加载过程 以下代码可以说明类加载过程: package com.puckasoft.reflect; public class TestClassLoader { public static void main(String[] args) { new A(); System.out.println("after load A"); new B(); new C(); new C(); new D(); new D(); } } class A { } class B { } class C { static { System.out.println("invoke C static block"); } } class D { { System.out.println("invoke D init block"); } } 运行结果: [Opened E:\Program\MyEclipse 6.0\jre\lib\rt.jar] [Opened E:\Program\MyEclipse 6.0\jre\lib\jsse.jar] [Opened E:\Program\MyEclipse 6.0\jre\lib\jce.jar] [Opened E:\Program\MyEclipse 6.0\jre\lib\charsets.jar] . . . [Loaded java.lang.Object from E:\Program\MyEclipse 6.0\jre\lib\rt.jar] [Loaded java.io.Serializable from E:\Program\MyEclipse 6.0\jre\lib\rt.jar] [Loaded java.lang.Comparable from E:\Program\MyEclipse 6.0\jre\lib\rt.jar] [Loaded java.lang.CharSequence from E:\Program\MyEclipse 6.0\jre\lib\rt.jar] [Loaded java.lang.String from E:\Program\MyEclipse 6.0\jre\lib\rt.jar] [Loaded java.lang.reflect.GenericDeclaration from E:\Program\MyEclipse 6.0\jre\lib\rt.jar] [Loaded java.lang.reflect.Type from E:\Program\MyEclipse 6.0\jre\lib\rt.jar] [Loaded java.lang.reflect.AnnotatedElement from E:\Program\MyEclipse 6.0\jre\lib\rt.jar] [Loaded java.lang.Class from E:\Program\MyEclipse 6.0\jre\lib\rt.jar] [Loaded java.lang.Cloneable from E:\Program\MyEclipse 6.0\jre\lib\rt.jar] [Loaded java.lang.ClassLoader from E:\Program\MyEclipse 6.0\jre\lib\rt.jar] [Loaded java.lang.System from E:\Program\MyEclipse 6.0\jre\lib\rt.jar] [Loaded java.lang.Throwable from E:\Program\MyEclipse [Loaded com.puckasoft.reflect.TestClassLoader from file:/E:/MyCode/Teaching/Reflect/WebRoot/WEB-INF/classes/] [Loaded com.puckasoft.reflect.A from file:/E:/MyCode/Teaching/Reflect/WebRoot/WEB-INF/classes/] after load A [Loaded com.puckasoft.reflect.B from file:/E:/MyCode/Teaching/Reflect/WebRoot/WEB-INF/classes/] [Loaded com.puckasoft.reflect.C from file:/E:/MyCode/Teaching/Reflect/WebRoot/WEB-INF/classes/] invoke C static block [Loaded com.puckasoft.reflect.D from file:/E:/MyCode/Teaching/Reflect/WebRoot/WEB-INF/classes/] invoke D init block invoke D init block [Loaded java.lang.Shutdown from E:\Program\MyEclipse 6.0\jre\lib\rt.jar] [Loaded java.lang.Shutdown$Lock from E:\Program\MyEclipse 6.0\jre\lib\rt.jar] 从运行结果可以看出来,JVM首先Load进来的是Object类,然后load一些核心类或 接口。比如System类,String类,Serializable接口等,接着开始load我们自定的 TestClassLoader类,进入main方法后,JVM依次load了A、B、C、D类。加载完A后,打 印“after load A”再加载B,说明类是动态加载,需要时才加载。“invoke C static block” 打印一次,说明静态初始化语句块只在类加载后才调用,且只调用一次。“invoke D init block”打印两次,说明初始化语句块在每次实例化对象时就会被调用。 3、JDK 内置 ClassLoader JVM本身包含了一个ClassLoader称为Bootstrap ClassLoader,和JVM一样,Bootstrap ClassLoader是用本地代码实现的,它负责加载核心Java Class(即所有java.*开头的类)。另外JVM还会提供两个ClassLoader,它们都是用Java语言编写的,由Bootstrap ClassLoader加载;其中Extension ClassLoader负责加载扩展的Java class(例如所有javax.*开头的类和存放在JRE的ext目录下的类),Application ClassLoader负责加载应用程序自身的类。如下表: Class loader 类型 用途 bootstrap class loader 用本地语言实现如:汇编,C或C++ 用于加载jdk的核心类 extesion class loader 加载jre/lib/ext中的类 application class loader 加载自定义类 ClassLoader.getSystemClassLoader() other class loader SecureClassLoader URLClassLoader 以下代码显示了不同类的是类加载器 package com.puckasoft.reflect; public class TestJDKClassLoader { public static void main(String[] args) { System.out.println("String的类加载器是:" + String.class.getClassLoader()); System.out.println("JDK_HOME\\jre\\lib\\ext\\sunjco_provider. jar中的AESCipher的类加载器:"+com.sun.crypto.provider .AESCipher.class.getClassLoader().getClass().getName()); System.out.println("自定义类TestJDKClassLoader的类加载器是:" + TestJDKClassLoader.class.getClassLoader().getClass() .getName()); } } 运行结果: String的类加载器是:null JDK_HOME\jre\lib\ext\sunjco_provider.jar中的AESCipher的类加载器:sun.misc.Launcher$ExtClassLoader 自定义类TestJDKClassLoader的类加载器是:sun.misc.Launcher$AppClassLoader String的类加载器是bootstrap class loader,由于bootstrap class loader不是用java实现的,所以显示为null 4、JDK Class Loader的层次关系 Bootstrap class loader Extension class loaloader application class loader . . . . . . classloader在load class的时候首先找上一层loader是不是load过了,如果已经load了,就不能再次load 每个ClassLoader加载Class的过程是: 1.检测此Class是否载入过(即在cache中是否有此Class),如果有到8,如果没有到2 2.如果parent classloader不存在(没有parent,那parent一定是bootstrap classloader 了),到4 3.请求parent classloader载入,如果成功到8,不成功到5 4.请求jvm从bootstrap classloader中载入,如果成功到8 5.寻找Class文件(从与此classloader相关的类路径中寻找)。如果找不到则到7. 6.从文件中载入Class,到8. 7.抛出ClassNotFoundException. 8.返回Class. 三、Java Reflect API Java的反射机制的实现要借助于4个类:Class,Constructor,Field,Method;其中class代表的是类对象,Constructor,类的构造器对象,Field,类的属性对象,Method,类的方法对象。通过这四个对象我们可以粗略的看到一个类的各个组成部分。 1、java.lang.Class Class,反射的核心类,所有的操作都是围绕该类来生成的,Class类十分的特殊,和其他的类一样继承与Object类,其实例用来表达java在运行时的classes和interface ,也用来表达enum、array、primitive java types(boolean, byte, char, short, int, long, float, double)以及关键字void。当一個class被加载,或当类加载器(class loader)的defineClass()被JVM 调用,JVM 便自动的产生一個Class object实例。 Class 类用以表达Java程序运行时的classes和interfaces,也用来表达enum、array、 primitive Java types(boolean, byte, char, short, int, long, float, double)以及关键词void。 Class对象的取得途径如下: 获得Class对象的方法 示例 运用getClass() String str = "abc"; 注:每个class 都有此函数 Class c1 = str.getClass(); 运用Class.getSuperclass() Button b = new Button(); Class c1 = b.getClass(); Class c2 = c1.getSuperclass(); 运用static method Class c1 = Class.forName Class.forName()(最常被使用) ("java.lang.String"); Class c2 = Class.forName ("java.awt.Button"); Class c3 = Class.forName ("java.util.LinkedList$Entry"); Class c4 = Class.forName ("I"); Class c5 = Class.forName ("[I"); 运用.class 语法 Class c1 = String.class; Class c2 = java.awt.Button.class; Class c3 = Main.InnerClass.class; Class c4 = int.class; Class c5 = int[].class; 运用primitive wrapper Class c1 = Boolean.TYPE; classes的TYPE 语法 Class c2 = Byte.TYPE; Class c3 = Character.TYPE; Class c4 = Short.TYPE; Class c5 = Integer.TYPE; Class c6 = Long.TYPE; Class c7 = Float.TYPE; Class c8 = Double.TYPE; Class c9 = Void.TYPE; 实例代码片段 public static Class getClass() throws ClassNotFoundException { Class clazz = null; // 对象的getClass() clazz = new Date().getClass(); // 通过类名加载 clazz = Class.forName("java.util.Date"); // 类型.class clazz = Date.class;// 类 类型 clazz = Serializable.class;// 接口 类型 clazz = int.class;// 基本数据 类型 clazz = int[].class;// 基本数据数组 类型 clazz = String[].class;// 类数组 类型 // 运行包装类的.TYPE clazz = Boolean.TYPE; clazz = Void.TYPE; return clazz; } 2、Java classes 组成:Method,Constructor,Field 我们用java.util.HashMap为例,观察java class的组成。 package java.util; //1 import java.io.*;.. //2 public //3 class HashMap //4 //5 extends AbstractMap //6 implements Map, Cloneable, Serializable //7 { static class Entry implements Map.Entry {...} //8 public HashMap(){...} //9 public V put(K key, V value){...} //10 transient int size; //11 } 下表为java class 内部结构及对应的api方法 Java Java class 相应之Reflection 返回值类型class 内部模块 内部模块说明 API,多半为Class (return type) methods。 (1) package class隶属哪package getPackage() Package (2) import class导入哪classes 无直接对应之API。 (3) modifier class(或methods, int getModifiers() int fields)的属性 Modifier.toString(String bool int) Modifier.isInterfa ce(int) (4) class name class/interface String 名称getName() or interface name (5) type getTypeParameters TypeVariable 参数化类型的名称 parameters () [] (6) base class getSuperClass() Class base class(只可能一 个) (7) getInterfaces() Class[] 实现有哪interfaces implemented interfaces (8) getDeclaredClassesClass[] 内部classes inner classes () (8') getDeclaringClass Class 如果我们观察的class outer class () 本身是inner classes, 那么相对它就会有个 outer class。 (9) Constructor 构造函数不论 public 或constructors getDeclaredConstru[] private 或其它 ctors() access level,皆可获 得。另有功能近似之取得 函数。 (10) methods Method[] 操作函数不论 public 或 getDeclaredMethodsprivate 或其它 () access level,皆可获 得。另有功能近似之取得 函数。 (11) fields getDeclaredFields(Field[] 字段(成员变量) )不论 public 或 private 或其它 access level,皆可获 得。另有功能近似之取得 函数。 以下是一个实例用于打印String的内部结构,包括String的类定义,成员变量定义, 构造方法定义和方法定义。它的功能类似与Eclipse中的OutLine面板显示的信息。 package com.puckasoft.reflect; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; public class TestClass { public static void main(String[] args) { Class clazz = String.class; StringBuffer stringBuffer = new StringBuffer(); // 包 -> Package Package _package = clazz.getPackage(); if (_package != null) { stringBuffer.append("package " + _package.getName() + "\n"); } // 类修饰符 -> Modifier // clazz.getModifiers()返回一个数字->2进制数对应下表能推算出修饰符的组合 // 1 1 1 1 1 // final static protected private public // 关键词 "interface" 已含于modifier int i = clazz.getModifiers(); if (i != 0) { stringBuffer.append(Modifier.toString(i) + " "); } if (!Modifier.isInterface(i)) { stringBuffer.append("class "); } // 类、接口名 stringBuffer.append(clazz.getSimpleName() + " "); // 类直接父类 Class _super = clazz.getSuperclass(); if (_super != null && _super != Object.class) { stringBuffer.append("extends " + _super.getSimpleName() + " "); } // 类直接实现接口 Class[] _interfaces = clazz.getInterfaces(); if (_interfaces != null && _interfaces.length > 0) { stringBuffer.append("implements "); for (Class _interface : _interfaces) { stringBuffer.append(_interface.getSimpleName() + ","); } stringBuffer.deleteCharAt(stringBuffer.length() - 1); } stringBuffer.append("\n"); // 类的属性(修饰符+属性类型+属性名) -> Field Field[] fields = clazz.getDeclaredFields(); if (fields != null && fields.length > 0) { for (Field field : fields) { // 属性修饰符 // displayModifiers(field, stringBuffer); int i1 = field.getModifiers(); if (i1 != 0) { stringBuffer.append(Modifier.toString(i1) + " "); } // 属性类型 stringBuffer.append(field.getType().getSimpleName() + " "); // 属性的名称 stringBuffer.append(field.getName() + "\n"); } } // 类的构造方法(修饰符+类名+参数列表) ->Constructor Constructor[] constructors = clazz.getDeclaredConstructors(); if (constructors != null && constructors.length > 0) { for (Constructor constructor : constructors) { // 构造方法修饰符 int i1 = constructor.getModifiers(); if (i1 != 0) { stringBuffer.append(Modifier.toString(i1) + " "); } // 构造方法名 stringBuffer.append(clazz.getSimpleName() + " "); // 参数列表 Class[] paramTypes = constructor.getParameterTypes(); stringBuffer.append("("); if (paramTypes != null && paramTypes.length > 0) { for (Class paramType : paramTypes) { stringBuffer.append(paramType.getSimpleName() + ","); } stringBuffer.deleteCharAt(stringBuffer.length() - 1); } stringBuffer.append(")\n"); } } // 类的方法(修饰符+返回值类型+方法名+参数列表)->Method Method[] methods = clazz.getDeclaredMethods(); if (methods != null && methods.length > 0) { for (Method method : methods) { // 方法修饰符 int i1 = method.getModifiers(); if (i1 != 0) { stringBuffer.append(Modifier.toString(i1) + " "); } // 方法返回值 stringBuffer.append(method.getReturnType().getSimpleName() + " "); // 方法名 stringBuffer.append(method.getName()); // 参数列表 Class[] paramTypes = method.getParameterTypes(); stringBuffer.append("("); if (paramTypes != null && paramTypes.length > 0) { for (Class paramType : paramTypes) { stringBuffer.append(paramType.getSimpleName() + ","); } stringBuffer.deleteCharAt(stringBuffer.length() - 1); } stringBuffer.append(")\n"); } } System.out.println(stringBuffer.toString()); } } 运行结果: package java.lang public final class String implements Serializable,Comparable,CharSequence private final char[] value private final int offset private final int count private int hash private static final long serialVersionUID private static final ObjectStreamField[] serialPersistentFields public static final Comparator CASE_INSENSITIVE_ORDER public String (char[],int,int) public String (int[],int,int) public String (byte[],int,int,int) public String (byte[],int) public String (char[]) public String (String) public String (byte[],String) public String (byte[],int,int) public String (byte[]) public String (StringBuffer) public String (StringBuilder) String (int,int,char[]) public String (byte[],int,int,String) public String () public int hashCode() public int compareTo(String) public volatile int compareTo(Object) public int indexOf(int,int) public int indexOf(int) public int indexOf(String) public int indexOf(String,int) static int indexOf(char[],int,int,char[],int,int,int) public boolean equals(Object) public String toString() public char charAt(int) private static void checkBounds(byte[],int,int) public int codePointAt(int) public int codePointBefore(int) public int codePointCount(int,int) public int compareToIgnoreCase(String) public String concat(String) public boolean contains(CharSequence) public boolean contentEquals(StringBuffer) public boolean contentEquals(CharSequence) public static String copyValueOf(char[],int,int) public static String copyValueOf(char[]) public boolean endsWith(String) public boolean equalsIgnoreCase(String) public static transient String format(Locale,String,Object[]) public static transient String format(String,Object[]) public byte[] getBytes() public byte[] getBytes(String) public void getBytes(int,int,byte[],int) void getChars(char[],int) public void getChars(int,int,char[],int) public native String intern() static int lastIndexOf(char[],int,int,char[],int,int,int) public int lastIndexOf(int) public int lastIndexOf(int,int) public int lastIndexOf(String,int) public int lastIndexOf(String) public int length() public boolean matches(String) public int offsetByCodePoints(int,int) public boolean regionMatches(boolean,int,String,int,int) public boolean regionMatches(int,String,int,int) public String replace(CharSequence,CharSequence) public String replace(char,char) public String replaceAll(String,String) public String replaceFirst(String,String) public String[] split(String,int) public String[] split(String) public boolean startsWith(String) public boolean startsWith(String,int) public CharSequence subSequence(int,int) public String substring(int) public String substring(int,int) public char[] toCharArray() public String toLowerCase() public String toLowerCase(Locale) public String toUpperCase(Locale) public String toUpperCase() public String trim() public static String valueOf(char[]) public static String valueOf(char) public static String valueOf(int) public static String valueOf(long) public static String valueOf(float) public static String valueOf(double) public static String valueOf(Object) public static String valueOf(boolean) public static String valueOf(char[],int,int) 四、 Reflection 的三个动态性质 1、运行时生成实例 在java机制中有两种方式可以动态实例化一个对象, , 其一调用无参的构造方法 public T newInstance() --java.lang.Class , 其二调用带参数的构造方法 public T newInstance(Object... initargs)--java.lang.reflect. Constructor initargs - 将作为变量传递给构造方法调用的对象数组;基本类型的值被包装在适当类型的包装器对象(如 Float 中的 float)中。 package com.puckasoft.reflect; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; public class TestConstructor { public static void main(String[] args) throws InstantiationException, IllegalAccessException, SecurityException, NoSuchMethodException, IllegalArgumentException, InvocationTargetException { //调用String空参构造方法创建String对象 String string = String.class.newInstance(); //得到String(char[],int,int)这个构造方法 Constructor constructor = String.class.getConstructor(new Class[] { char[].class, int.class, int.class }); char[] chars = { 'a', 'b', 'c' }; //调用String(char[],int,int)构造方法生成String对象的实例 string = (String) constructor.newInstance(chars, 0, 2); System.out.println(string); } } 2、运行时调用方法 , 根据方法名称和参数类型得到Method对象 public Method getDeclaredMethod(String name,... parameterTypes)—java.lang.Class name - 方法名 parameterTypes - 参数数组 , 调用方法 public Object invoke(Object obj, Object... args)—java.lang.reflect.Method obj :从中调用底层方法的对 args:用于方法调用的参数 package com.puckasoft.reflect; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public class TestMethod { public static void main(String[] args) throws SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException { String str = new String("one world,one dream"); //获得String类的equalsIgnoreCase(String)这个方法(Method)对象 //第一个参数是方法名字,后面的参数是方法形参的类型 Method method = String.class.getMethod("equalsIgnoreCase", String.class); //动态调用str对象的equalsIgnoreCase //第一个参数是方法的调用者,后面的参数是方法的实参 Boolean isEquals = (Boolean) method.invoke(str, "One World,One Dream"); System.out.println(isEquals); } } 3、运行时变更成员变量的 根据成员变量的名字得到Field对象 public Field getDeclaredField(String name)—java.lang.Class name - 字段名 public void set(Object obj, Object value)—java.lang.refect.Field obj - 应该修改其字段的对象 value - 正被修改的 obj 的字段的新值 package com.puckasoft.reflect; import java.lang.reflect.Field; public class TestField { public int intValue; public String strValue; public static void main(String[] args) throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException { TestField testField = new TestField(); // 返回一个 Field 对象,它描述类或接口中的公共成员变量的 // 这里返回的是TestField的公共成员变量strValue这个Field Field strField = TestField.class.getField("strValue"); // 将指定对象变量上此 Field 对象表示的字段设置为指定的新值。 // 这里表示将testField对象的strValue字段设置成puckasoft strField.set(testField, "puckasoft"); // 返回指定对象上此 Field 表示的字段的值。 //这里表示取出testField对象上的strValue的值 String str = (String) strField.get(testField); System.out.println(str); //对于基本数据类型,Field提供简便直接的方法来处理 Field intField = TestField.class.getField("intValue"); intField.setInt(testField, 2009); int value = intField.getInt(testField); System.out.println(value); } }
/
本文档为【Java反射机制】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑, 图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。 本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。 网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。

历史搜索

    清空历史搜索