关于Java的反射
2015-10-10 10:57
393 查看
I. 前言:
1> 反射相关的主要API:
java.lang.Class:代表一个类
java.lang.reflect.Method:代表类的方法
java.lang.reflect.Field:代表类的成员变量
java.lang.reflect.Constructor:代表类的构造方法
2> 对于Class类的理解:
Class本身也是一个类Class 对象只能由系统建立对象
一个类在 JVM 中只会有一个Class实例
一个Class对象对应的是一个加载到JVM中的一个.class文件
每个类的实例都会记得自己是由哪个 Class 实例所生成
通过Class可以完整地得到一个类中的完整结构
3> 实例化Class类对象(四种方法)
1)前提:若已知具体的类,通过类的class属性获取,该方法
最为安全可靠,程序性能最高
实例:Class clazz = String.class;
2)前提:已知某个类的实例,调用该实例的getClass()方法获
取Class对象
实例:Class clazz = “www.atguigu.com”.getClass();
3)前提:已知一个类的全类名,且该类在类路径下,可通过
Class类的静态方法forName()获取,可能抛出ClassNotFoundException
实例:Class clazz = Class.forName(“java.lang.String”);
4)其他方式(不做要求)
ClassLoader cl = this.getClass().getClassLoader();
Class clazz4 = cl.loadClass(“类的全类名”);
4> 创建类对象并获取类的完整结构
4.1>调用Class对象的newInstance()方法
要 求:1)类必须有一个无参数的构造器。
2)类的构造器的访问权限需要足够。
4.2> 指定形参类型的构造器,步骤如下:
1)通过Class类的getDeclaredConstructor(Class … parameterTypes)取得本类的指定形参类型的构造器
2)向构造器的形参中传递一个对象数组进去,里面包含了构造器中所需的各个参数。
3)通过Constructor实例化对象。
5> 全部的构造器
public Constructor<T>[] getConstructors()
返回此 Class 对象所表示的类的所有public构造方法,并不能获取父类的构造器。
public Constructor<T>[] getDeclaredConstructors()
返回此 Class 对象表示的类声明的所有构造方法,并不能获取父类的构造器。
Constructor类中:
取得修饰符: public int getModifiers();
取得方法名称: public String getName();
取得参数的类型:public Class<?>[] getParameterTypes();
6> 全部的方法
public Method[] getDeclaredMethods()
可以获取运行时类及其父类的所有声明为public的方法
public Method[] getMethods()
可以获取运行时类本身声明的所有的方法
Method类中:
public Class<?> getReturnType()取得全部的返回值
public Class<?>[] getParameterTypes()取得全部的参数
public int getModifiers()取得修饰符
public Class<?>[] getExceptionTypes()取得异常信息
7> 全部的Field
public Field[] getFields()
只能获取到运行时类的所有的声明为public的属性,包括其父类的public的属性
public Field[] getDeclaredFields()
只能获取到运行时类本身的所有的属性,而不能得到父类的属性
Field方法中:
public int getModifiers() 以整数形式返回此Field的修饰符
public Class<?> getType() 得到Field的属性类型
public String getName() 返回Field的名称。
8> 调用指定方法
通过反射,调用类中的方法,通过Method类完成。步骤:
8.1>通过Class类的getMethod(String name,Class…parameterTypes)方法取得一个Method对象,并设置此方法操作时所需要的参数类型。
8.2>之后使用Object invoke(Object obj, Object[] args)进行调用,并向方法中传递要设置的obj对象的参数信息。
8.2.1> Object 对应原方法的返回值,若原方法无返回值,此时返回null
8.2.2> 若原方法若为静态方法,此时形参Object obj可为null
8.2.3> 若原方法形参列表为空,则Object[] args为null
8.2.4> 若原方法声明为private,则需要在调用此invoke()方法前,显式调用方法对象的setAccessible(true)方法,将可访问private的方法。
9> 调用指定属性
在反射机制中,可以直接通过Field类操作类中的属性,通过Field类提供的set()和get()方法就可以完成设置和取得属性内容的操作。
public Field getField(String name)
只能获取到运行时类的所有的声明为public的属性,包括其父类的
public Field getDeclaredField(String name)只能获取到运行时类本身的所有的属性,而不能得到父类的属性
在Field中:
public Object get(Object obj) 取得指定对象obj上此Field的属性内容
public void set(Object obj,Object value) 设置指定对象obj上此Field的属性内容
注:在类中属性都设置为private的前提下,在使用set()和get()方法时,首先要使用Field类中的setAccessible(true)方法将需要操作的属性设置为可以被外部访问。
public void setAccessible(true)访问私有属性时,让这个属性可见。
II. 代码示例如下:
1> 实例化Class类对象(四种方法)
代码示例如下:
2> 有了Class实例之后,我们可以做如下事情:
2.1> 创建对应的类的对象
代码示例一如下:
注://不管是对于不带参还是不带参的,若想要对应的对象能够创建成功,首先需要有对应的构造器,
//然后还需要构造器的权限修饰符要足够,足够其意思是:在本类中可以访问得到对应类的构造器
2.2> 获取及调用属性
代码示例如下:
2.3> 获取及调用方法
代码示例如下:
2.4> 获取及调用构造器
代码示例如下:
2.5>获取其他信息
代码示例如下:
Person类的代码如下:
Creator的代码示例如下:
1> 反射相关的主要API:
java.lang.Class:代表一个类
java.lang.reflect.Method:代表类的方法
java.lang.reflect.Field:代表类的成员变量
java.lang.reflect.Constructor:代表类的构造方法
2> 对于Class类的理解:
Class本身也是一个类Class 对象只能由系统建立对象
一个类在 JVM 中只会有一个Class实例
一个Class对象对应的是一个加载到JVM中的一个.class文件
每个类的实例都会记得自己是由哪个 Class 实例所生成
通过Class可以完整地得到一个类中的完整结构
3> 实例化Class类对象(四种方法)
1)前提:若已知具体的类,通过类的class属性获取,该方法
最为安全可靠,程序性能最高
实例:Class clazz = String.class;
2)前提:已知某个类的实例,调用该实例的getClass()方法获
取Class对象
实例:Class clazz = “www.atguigu.com”.getClass();
3)前提:已知一个类的全类名,且该类在类路径下,可通过
Class类的静态方法forName()获取,可能抛出ClassNotFoundException
实例:Class clazz = Class.forName(“java.lang.String”);
4)其他方式(不做要求)
ClassLoader cl = this.getClass().getClassLoader();
Class clazz4 = cl.loadClass(“类的全类名”);
4> 创建类对象并获取类的完整结构
4.1>调用Class对象的newInstance()方法
要 求:1)类必须有一个无参数的构造器。
2)类的构造器的访问权限需要足够。
4.2> 指定形参类型的构造器,步骤如下:
1)通过Class类的getDeclaredConstructor(Class … parameterTypes)取得本类的指定形参类型的构造器
2)向构造器的形参中传递一个对象数组进去,里面包含了构造器中所需的各个参数。
3)通过Constructor实例化对象。
5> 全部的构造器
public Constructor<T>[] getConstructors()
返回此 Class 对象所表示的类的所有public构造方法,并不能获取父类的构造器。
public Constructor<T>[] getDeclaredConstructors()
返回此 Class 对象表示的类声明的所有构造方法,并不能获取父类的构造器。
Constructor类中:
取得修饰符: public int getModifiers();
取得方法名称: public String getName();
取得参数的类型:public Class<?>[] getParameterTypes();
6> 全部的方法
public Method[] getDeclaredMethods()
可以获取运行时类及其父类的所有声明为public的方法
public Method[] getMethods()
可以获取运行时类本身声明的所有的方法
Method类中:
public Class<?> getReturnType()取得全部的返回值
public Class<?>[] getParameterTypes()取得全部的参数
public int getModifiers()取得修饰符
public Class<?>[] getExceptionTypes()取得异常信息
7> 全部的Field
public Field[] getFields()
只能获取到运行时类的所有的声明为public的属性,包括其父类的public的属性
public Field[] getDeclaredFields()
只能获取到运行时类本身的所有的属性,而不能得到父类的属性
Field方法中:
public int getModifiers() 以整数形式返回此Field的修饰符
public Class<?> getType() 得到Field的属性类型
public String getName() 返回Field的名称。
8> 调用指定方法
通过反射,调用类中的方法,通过Method类完成。步骤:
8.1>通过Class类的getMethod(String name,Class…parameterTypes)方法取得一个Method对象,并设置此方法操作时所需要的参数类型。
8.2>之后使用Object invoke(Object obj, Object[] args)进行调用,并向方法中传递要设置的obj对象的参数信息。
8.2.1> Object 对应原方法的返回值,若原方法无返回值,此时返回null
8.2.2> 若原方法若为静态方法,此时形参Object obj可为null
8.2.3> 若原方法形参列表为空,则Object[] args为null
8.2.4> 若原方法声明为private,则需要在调用此invoke()方法前,显式调用方法对象的setAccessible(true)方法,将可访问private的方法。
9> 调用指定属性
在反射机制中,可以直接通过Field类操作类中的属性,通过Field类提供的set()和get()方法就可以完成设置和取得属性内容的操作。
public Field getField(String name)
只能获取到运行时类的所有的声明为public的属性,包括其父类的
public Field getDeclaredField(String name)只能获取到运行时类本身的所有的属性,而不能得到父类的属性
在Field中:
public Object get(Object obj) 取得指定对象obj上此Field的属性内容
public void set(Object obj,Object value) 设置指定对象obj上此Field的属性内容
注:在类中属性都设置为private的前提下,在使用set()和get()方法时,首先要使用Field类中的setAccessible(true)方法将需要操作的属性设置为可以被外部访问。
public void setAccessible(true)访问私有属性时,让这个属性可见。
II. 代码示例如下:
1> 实例化Class类对象(四种方法)
代码示例如下:
package com.atguigu.java; /* * 1.如何创建Class的实例(掌握) * 2.如何获取Class对象对应的运行时类的完整的结构(理解) * 3.如何调用Class对象对应的运行时类的指定的属性、方法(掌握) * 4.动态代理(反射的一个应用) */ import java.io.File; import java.io.FileInputStream; import java.io.InputStream; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.Properties; import org.junit.Test; public class TestReflection { // 创建Class实例的方法(四种方法)(重点) @Test public void test4() throws ClassNotFoundException { // 1.调用运行时类的.class属性 Class clazz1 = Person.class; System.out.println(clazz1); Class clazz2 = Creator.class; System.out.println(clazz2); // 2.通过运行时类的对象,调用其getClass()方法 Person p = new Person(); Class clazz3 = p.getClass(); System.out.println(clazz3); // 3.调用Class的静态方法forName(String className)。此方法报ClassNotFoundException String className = "com.atguigu.java.Person"; Class clazz4 = Class.forName(className); System.out.println(clazz4); // 4.了解:通过类的加载器 ClassLoader loader = this.getClass().getClassLoader(); Class clazz5 = loader.loadClass(className); System.out.println(clazz5); } /* * java.lang.Class类 1.Class类是反射的源头! * 2.Class的一个对象,对应着一个运行时类。相当于一个运行时类本身充当了Class的一个实例。 * 3.过程:源文件经过编译(javac.exe)以后,得到一个或多个.class文件。 * .class文件经过运行(java.exe)这步,就需要进行类的加载(通过JVM的类的加载器), * 记载到内存中的缓存。每一个放入缓存中的.class文件就是一个Class的实例! */ @Test public void test3() { Person p = new Person(); Class clazz = p.getClass();// 获取p对应对应的类:Person类。相当于Person类本身充当了Class的实例 } // 有了反射以后 // 看成是关于反射的一个应用 @Test public void test2() throws Exception { Class clazz = Person.class; // 使用反射可以创建一个类的对象 Object obj = clazz.newInstance(); Person p = (Person) obj; System.out.println(p); // 可以通过反射,获取对应的运行时类的结构:属性、方法、。。。 Field name = clazz.getField("name"); name.set(p, "李雷"); Field age = clazz.getField("age"); age.set(p, 24); System.out.println(p); Method show = clazz.getMethod("show"); show.invoke(p); } // 反射以前,如何创建一个类的对象 @Test public void test1() { Person p = new Person(); p.setName("韩梅梅"); p.setAge(23); System.out.println(p); } }
2> 有了Class实例之后,我们可以做如下事情:
2.1> 创建对应的类的对象
代码示例一如下:
package com.atguigu.java; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import org.junit.Test; public class TestClass{ //不带参的 @Test public void test1() throws Exception{ //1.根据全类名获取对应的Class对象 String className = "com.atguigu.java.Person"; Class clazz = Class.forName(className); //2.通过Class的实例创建对应类的对象 Object obj = clazz.newInstance(); //创建对应类的对象,在本例中,newInstance()调用的就是空参的person构造器 Person p1 = (Person)obj; System.out.println(p1); } //带参的 @Test public void test2() throws Exception{ //1.根据全类名获取对应的Class对象 String name = "com.atguigu.java.Person"; Class clazz = null; clazz = Class.forName(name); //2.调用指定参数结构的构造器,生成Constructor的实例 Constructor con = clazz.getConstructor(String.class,Integer.class); //3.通过Constructor的实例创建对应类的对象,并初始化类属性 Person p2 = (Person)con.newInstance("Peter",20); ////创建对应类的对象,在本例中,newInstance("Peter","20")调用的就是带参的person构造器 System.out.println(p2); } }
注://不管是对于不带参还是不带参的,若想要对应的对象能够创建成功,首先需要有对应的构造器,
//然后还需要构造器的权限修饰符要足够,足够其意思是:在本类中可以访问得到对应类的构造器
2.2> 获取及调用属性
代码示例如下:
package com.atguigu.java; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import org.junit.Test; public class TestFields { //获取运行时类的属性 @Test public void test1(){ Class clazz = Person.class; //getFields():只能获取到运行时类的所有的声明为public的属性,包括其父类的 Field[] fields = clazz.getFields(); for(int i = 0;i < fields.length;i++){ System.out.println(fields[i].getName()); } //getDeclaredFields():可以获取到运行时类本身的所有的属性 System.out.println(); Field[] fields1 = clazz.getDeclaredFields(); for(int i = 0;i < fields1.length;i++){ System.out.println(fields1[i].getName()); } } //权限修饰符 数据类型 变量名 @Test public void test2(){ Class clazz = Person.class; Field[] fields = clazz.getDeclaredFields(); for(int i = 0;i < fields.length;i++){ //属性的权限修饰符 int m = fields[i].getModifiers(); String mm = Modifier.toString(m); System.out.print(mm + "\t"); //数据类型 Class type = fields[i].getType(); System.out.print(type.getName() + "\t"); //变量名 System.out.print(fields[i].getName()); System.out.println(); } } //调用对应运行时类的指定的属性(掌握) @Test public void test3() throws Exception{ Class clazz = Person.class; Person p = (Person)clazz.newInstance(); System.out.println(p); //1.getField(String fieldName):获取指定属性名的属性(仅限于public声明的) Field name = clazz.getField("name"); //set(Object obj,fieldVal):将obj对象的当前属性指定值为fieldVal name.set(p, "高鹏"); System.out.println(p); //get(Object obj):获取obj对象的当前属性的值 System.out.println(name.get(p)); //*************** //getDeclaredField(String fieldName):获取对应的运行时类的名为fieldName的属性(不用考虑权限修饰符) Field age = clazz.getDeclaredField("age"); //setAccessible():要想操作声明为非public的属性,需要在调用前执行此方法,操作为true age.setAccessible(true); age.set(p, 23); System.out.println(p); } }
2.3> 获取及调用方法
代码示例如下:
package com.atguigu.java; import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import org.junit.Test; public class TestMethods { //获取运行时类的所有的方法 @Test public void test1(){ Class clazz = Person.class; //getMethods():可以获取运行时类及其父类的所有声明为public的方法 Method[] m1 = clazz.getMethods(); for(int i = 0;i < m1.length;i++){ System.out.println(m1[i].getName()); } System.out.println(); //getDeclaredMethods():可以获取运行时类本身声明的所有的方法 Method[] m2 = clazz.getDeclaredMethods(); for(int i = 0;i < m2.length;i++){ System.out.println(m2[i]); } } //注解 权限修饰符 返回值类型 方法名 (参数类型1 参数名1,参数类型2 参数名2 ,。。。)异常 @Test public void test2(){ Class clazz = Person.class; Method[] methods = clazz.getDeclaredMethods(); for(int i = 0;i < methods.length;i++){ //0.注解 Annotation[] annos = methods[i].getAnnotations(); for(int j = 0;j < annos.length;j++){ System.out.println(annos[j]); } //1.权限修饰符 System.out.print(Modifier.toString(methods[i].getModifiers()) + "\t"); //2.返回值类型 Class returnType = methods[i].getReturnType(); System.out.print(returnType.getName() + "\t"); //3.方法名 System.out.print(methods[i].getName() + "("); //4.参数列表 Class[] paras = methods[i].getParameterTypes(); for(int j = 0;j < paras.length;j++){ System.out.print(paras[j].getName() + " args-" + j); } System.out.print(")"); //5.抛出的异常 Class[] excep = methods[i].getExceptionTypes(); for(int j = 0;j < excep.length;j++){ System.out.print(excep[j].getName()); } System.out.println(); } } //调用指定的方法(掌握) @Test public void test3() throws Exception{ Class clazz = Person.class; Person p = (Person)clazz.newInstance(); //getMethod(String methodName,ParaType...t):获取运行时类指定名为methodName,参数列表为t的方法(仅限于public) Method m1 = clazz.getMethod("display", String.class); //Object invoke(Object obj,RealVal... r):调用obj对象的当前方法,并且传入实参:r //此invoke()方法的返回值即为当前名为methodName的返回值。 Object returnVal = m1.invoke(p,"中华人民共和国");//类似于:对象.方法(实参) System.out.println(returnVal); Method m2 = clazz.getMethod("getAge"); Object obj = m2.invoke(p); System.out.println(obj); //*********** //getDeclaredMethod(String methodName,ParaType...t):可以获取运行时类任何权限修饰符修饰的方法 Method m3 = clazz.getDeclaredMethod("info"); //setAccessible(true):对于非public的方法,如果想调用,需要进行此步骤 m3.setAccessible(true); Object returnVal1 = m3.invoke(p); System.out.println(returnVal1); } } <strong> </strong>
2.4> 获取及调用构造器
代码示例如下:
package com.atguigu.java; import java.lang.reflect.Constructor; import org.junit.Test; public class getConstructors { //获取运行时类所有的构造器 @Test public void test1() throws Exception{ Class clazz = Class.forName("com.atguigu.java.Person"); //getConstructors():只能获取本类中声明为public的构造器 Constructor[] cons1 = clazz.getConstructors(); for(int i = 0;i < cons1.length;i++){ System.out.println(cons1[i]); } //getDeclaredConstructors():获取本类中声明的所有的构造器 System.out.println(); Constructor[] cons2 = clazz.getDeclaredConstructors(); for(int i = 0;i < cons2.length;i++){ System.out.println(cons2[i]); } } //调用运行时类的构造器 @Test public void test2() throws Exception{ String className = "com.atguigu.java.Person"; Class clazz = Class.forName(className); //1.根据全类名获取对应的Class对象 String name = "com.atguigu.java.Person"; Class clazz = null; clazz = Class.forName(name); //2.调用指定参数结构的构造器,生成Constructor的实例 Constructor con = clazz.getConstructor(String.class,Integer.class); con.setAccessible(true); // //3.通过Constructor的实例创建对应类的对象,并初始化类属性 Person p2 = (Person)con.newInstance("Peter",20); ////创建对应类的对象,在本例中,newInstance("Peter","20")调用的就是带参的person构造器 System.out.println(p2); } }
2.5>获取其他信息
代码示例如下:
package com.atguigu.java; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.lang.annotation.Annotation; import org.junit.Test; public class TestOther { //获取运行时类的内部类 @Test public void test7() throws Exception{ Class clazz = Class.forName("com.atguigu.java.Person"); Class[] innerClass = clazz.getDeclaredClasses(); for(int i = 0;i < innerClass.length;i++){ System.out.println(innerClass[i]); } } //获取运行时类的接口 @Test public void test6() throws Exception{ Class clazz = Class.forName("com.atguigu.java.Person"); Class[] interfaces = clazz.getInterfaces(); for(int i = 0;i < interfaces.length;i++){ System.out.println(interfaces[i].getName()); } } //获取类的注解 @Test public void test5(){ Class clazz = Person.class; Annotation[] anns = clazz.getAnnotations(); for(int i = 0;i < anns.length;i++){ System.out.println(anns[i]); } } //获取运行时类所在的包 @Test public void test4(){ Class clazz = Person.class; Package pack = clazz.getPackage(); System.out.println(pack); } //获取运行时类的父类的泛型 @Test public void test3(){ Class clazz = Person.class; Type t = clazz.getGenericSuperclass(); ParameterizedType p = (ParameterizedType)t; Type[] t1 = p.getActualTypeArguments(); System.out.println(((Class)t1[0]).getName()); } //获取带泛型的父类 @Test public void test2(){ Class clazz = Person.class; Type t = clazz.getGenericSuperclass(); System.out.println(t); } //获取运行时类的父类 @Test public void test1(){ Class clazz = Person.class; Class clazz1 = clazz.getSuperclass(); System.out.println(clazz1); } }
Person类的代码如下:
package com.atguigu.java; @MyAnnotation(values = "atguigu") public class Person extends Creator<String> implements Comparable,MyInterface{ public String name; private int age = 12; int id; private Person(String name){ this.name = name; } public Person(String name, int age) { super(); this.name = name; this.age = age; } public Person() { super(); } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "Person [name=" + name + ", age=" + age + "]"; } @MyAnnotation(values = "hello") public void show() throws Exception{ System.out.println("我是一个人"); } public void display(String nation){ System.out.println("我的国籍是:" + nation); } @Override public int compareTo(Object o) { // TODO Auto-generated method stub return 0; } private String info(){ return "今天北京天气不错!"; } //内部类 class Bird{ } }
Creator的代码示例如下:
package com.atguigu.java; public class Creator<T> { public int legs; public void breath(){ System.out.println("呼吸。。。"); } }
相关文章推荐
- 关于Java的访问控制修饰符
- 关于Java的继承
- 在Java中,关于final关键字
- 在Java中,关于static关键字
- 在Java中,关于abstract关键字
- 在Java中,关于接口的概念
- 在Java中,关于this和super
- 在Java中,关于package和import
- Struts在控制器内的三种基本接收参数的方式
- 集合 Properties 的 简单例子(Spring)
- 关于Java的异常处理
- 在Java中,关于线程的通信
- 在Java中,关于线程的同步
- 在Java中,关于线程的创建,方法及生命周期
- java集合的体系
- Java的JUnit
- Java的包装类,基本数据类型和String类之间的转化
- 在eclipse下如何查找某一个类的源码
- Java中this与super,构造器执行顺序
- Eclipse常用快捷键