- Date:2015-5-6
- Tag:java,反射
- Author:踏雪
- Email:[email protected]
一、What(是什么?)
反射就是将java类中的各种成分映射成相应的java类,分别是Field、Method、Constructor、Package等等。
(1)Java类是描述同一类事物的属性,包括方法、属性、包名、构造函数、类加载器、子类、父类等等。
而Java类的实例对象则是同一属性下的不同属性值的对象。
(2)Class类是描述java类的各个方面的信息,如属性、方法、包、构造函数等等。
代码实例:
/**
* 知识点1
* Class类是描述java类的各个方面的信息,如属性、方法、包、构造函数等等...
*/
String str = new String("wgc");
System.out.println(str.getClass().getName());
/**
* 知识点2
* 每个类对象对应的Class字节码是相同的(有相同的描述)
*/
System.out.println(int.class);
System.out.println(void.class);
Integer i1 = 3;
Integer i2 = 4;
System.out.println(i1.getClass() == i2.getClass());
int[] array1 = new int[]{1,2,3};
int[] array2 = new int[]{2,2,3};
System.out.println(array1.getClass() == array2.getClass());
Person p1 = new Person("wgc");
Person p2 = new Person("apple");
System.out.println(p1.getClass() == p2.getClass());
二、How(如何使用?)
1、获取Class的途径
(1)类名.class
例如:String.class;
(2)对象.getClass()
(3)Class.forName(“类名”)
例如:Class.forName(“java.lang.String”);
代码实例:
System.out.println(String.class);
ystem.out.println(str.getClass());
System.out.println(Class.forName("java.lang.String"));
2、构造方法的反射
(1)得到某个类的所有构造方法
Constructor[] | getConstructors() | Returns an array containing Constructor objects reflecting all the public constructors of the class represented by this Class object. |
---|
代码实例:
Constructor[] constructors = Class.forName("java.lang.String").getConstructors();
for(Constructor constructor : constructors) {
System.out.println(constructor);
}
(2)得到某一个构造方法
Constructor < T > | getConstructor(Class… parameterTypes) | Returns a Constructor object that reflects the specified public constructor of the class represented by this Class object. |
---|
代码实例:
//public java.lang.String()
Constructor constructor1 = Class.forName("java.lang.String").getConstructor();
//public java.lang.String(java.lang.StringBuffer)
Constructor constructor2 = Class.forName("java.lang.String").getConstructor(StringBuffer.class);
//public java.lang.String(char[])
Constructor constructor3 = Class.forName("java.lang.String").getConstructor(char[].class);
(3)创建一个实例对象
T | newInstance() | Creates a new instance of the class represented by this Class object |
---|
代码实例:
String str1 = (String)constructor1.newInstance();
String str2 = (String)constructor2.newInstance(new StringBuffer("wgc"));
String str3 = (String)constructor3.newInstance(new char[]{'w','g','c'});
System.out.println(str1);
System.out.println(str2);
System.out.println(str3);
3、成员变量的反射
类型 | 函数名 | 说明 |
---|---|---|
Field[] | getFields() | 获取所有public属性的field |
Field[] | getDeclaredFields() | 获取所有属性的field |
Field | getField(String name) | 获取指定public属性的field |
Field | getDeclaredField(String name) | 获取指定属性的field |
代码实例:
Student student = new Student("Hnu", "shuwoom");
Field[] fields1 = student.getClass().getFields();
for(Field field : fields1) {
System.out.println(field);
}
结果:
System.out.println("=======================================");
Field[] fields2 = student.getClass().getDeclaredFields();
for(Field field : fields2) {
System.out.println(field);
}
结果:
//getField是获取public field的方法
Field fieldSchool = student.getClass().getField("school");
// Field fieldSchool = student.getClass().getDeclaredField("school");
// Field fieldName = student.getClass().getField("name");
//getDeclaredField是获取各种权限field的方法,其中private field需要设置setAccessible
Field fieldName = student.getClass().getDeclaredField("name");
fieldName.setAccessible(true);
System.out.println(fieldSchool.get(student));
System.out.println(fieldName.get(student));
public class Student {
private String name;
public String school;
public Student(String school,String name) {
this.school = school;
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSchool() {
return school;
}
public void setSchool(String school) {
this.school = school;
}
private void test(){
System.out.println("This is private test function");
}
}
4、成员方法的反射
类型 | 函数名 | 说明 |
---|---|---|
Method[] | getMethods() | 获取所有public属性的method |
Method [] | getDeclaredMethods() | 获取所有属性的method |
Method | getDeclaredMethod(String name, Class… parameterTypes) | 获取指定public属性的method |
Method | getMethod(String name, Class… parameterTypes) | 获取指定属性的method |
(1)获取所有成员方法
代码实例:
System.out.println("=======================================");
Method[] methods1 = student.getClass().getMethods();//获取所有public方法
for(Method method : methods1) {
System.out.println(method);
}
结果:
System.out.println("=======================================");
Method[] methods2 = student.getClass().getDeclaredMethods();//获取所有方法
for(Method method : methods2) {
System.out.println(method);
}
结果:
(2)获取某一个成员方法
Student student2 = new Student("Hnu", "shuwoom");
Method setNameMethod = student.getClass().getMethod("setName", String.class);
setNameMethod.invoke(student2, "shuwoom2");
System.out.println(student2.getName());
Method getNameMethod = student.getClass().getMethod("getName", null);
System.out.println(getNameMethod.invoke(student2, null));
结果:
(3)对有数组的成员方法进行反射
如果Student类中有一个接收数组的方法,如下:
public int getScore(int[]scores) {
int sum = 0;
for(int score : scores) {
sum += score;
}
return sum;
}
则其调用方法如下:
Method getScoreMethod = student2.getClass().getMethod("getScore", int[].class);
System.out.println(getScoreMethod.invoke(student2, new int[]{90,80,90}));
5、JavaBean、PropertyDescriptor类、Introspector类和BeanInfo类
JavaBean是一种特殊的Java类,其成员属性都是私有的,并且只能通过set和get函数来设置和获取。
(1)PropertyDescriptor类
PropertyDescriptor是专门处理JavaBean的类,用于获取其属性的方法。
常用方法:
构造函数 |
---|
PropertyDescriptor (String propertyName, Class beanClass) |
返回类型 | 方法名 |
---|---|
Method | getReadMethod() |
Method | getWriteMethod() |
代码实例:
Student student5 = new Student("Hnu", "shuwoom5");
String propertyName = "name";
PropertyDescriptor nameProperty = new PropertyDescriptor(propertyName, student5.getClass());
Method getNameMethod2 = nameProperty.getReadMethod();
System.out.println(getNameMethod2.invoke(student5, null));
Method setNameMethod2 = nameProperty.getWriteMethod();
setNameMethod2.invoke(student5, "Walk");
System.out.println(getNameMethod2.invoke(student5, null));
(2) BeanInfo类
返回值类型 | 方法名 |
---|---|
PropertyDescriptor[] | getPropertyDescriptors() |
(3)Introspector类
返回值类型 | 方法名 |
---|---|
static BeanInfo | getBeanInfo(Class beanClass) |
代码实例:
BeanInfo beanInfo = Introspector.getBeanInfo(student5.getClass());
PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors();
Object retVal = null;
for(PropertyDescriptor pd : pds) {
if(pd.getName().equals(propertyName)) {
Method methodGetName = pd.getReadMethod();
retVal = methodGetName.invoke(student5);
break;
}
}
System.out.println(retVal);
三、When(何时使用?)
Java语言反射提供一种动态链接程序组件的多功能方法。它允许程序创建和控制任何类的对象(根据安全性限制),无需提前硬编码目标类。这些特性使得反射特别适用于创建以非常普通的方式与对象协作的库。例如,反射经常在持续存储对象为数据库、XML或其它外部格式的框架中使用。
代码实例:
config.properties文件:
InputStream ips = new FileInputStream("config.properties");
Properties props = new Properties();
props.load(ips);
ips.close();
String className = props.getProperty("className");
// Collection collection = new ArrayList();
// Collection collection = new HashSet();
Collection collection = (Collection) Class.forName(className).newInstance();
Student s1 = new Student("Hnu", "张三");
Student s2 = new Student("Hnu", "李四");
Student s3 = new Student("Hnu", "王五");
collection.add(s1);
collection.add(s2);
collection.add(s3);
collection.add(s1);
System.out.println(collection.size());
四、优缺点
优点:
反射是一种强大的工具。它使您能够创建灵活的代码,这些代码可以在运行时装配,无需在组件之间进行源代表链接。
缺点:
(1) 第一个是性能问题。当用于字段和方法接入时反射要远慢于直接代码。性能问题的程度取决于程序中是如何使用反射的。如果它作为程序运行中相对很少涉及的部分,缓慢的性能将不会是一个问题。即使测试中最坏情况下的计时图显示的反射操作只耗用几微秒。仅反射在性能关键的应用的核心逻辑中使用时性能问题才变得至关重要。
(2) 许多应用更严重的一个缺点是使用反射会模糊程序内部实际要发生的事情。程序人员希望在源代码中看到程序的逻辑,反射等绕过了源代码的技术会带来维护问题。反射代码比相应的直接代码更复杂,正如性能比较的代码实例中看到的一样。解决这些问题的最佳方案是保守地使用反射– 仅在它可以真正增加灵活性的地方 – 记录其在目标类中的使用。
代码实例:
//使用反射
Student student4 = new Student("Hnu", "shuwoom");
Method method = student4.getClass().getMethod("setName", String.class);
Long beginTime = System.currentTimeMillis();
for(int i = 0; i < 10000000; i++)
method.invoke(student4, "shuwoom2");
long endTime = System.currentTimeMillis();
System.out.println("使用反射:" + (endTime - beginTime));
//直接调用
beginTime = System.currentTimeMillis();
for(int i = 0; i < 10000000; i++)
student4.setName("shuwoom2");
endTime = System.currentTimeMillis();
System.out.println("直接调用:" + (endTime - beginTime));