java的反射机制:
我们都知道,一个java类中,有成员变量、成员方法、构造方法等等,反射机制,就是动态的获取这些类中的信息,并动态的调用对象的方法。通常只有要设计框架的过程中,才会使用java反射相关的api,但是了解java反射机制的基本原理与基本方法,可以帮忙我们在日后对框架的学习与应用提供很大的帮忙。
反射的使用,简单的讲,就是通过类的Class对象,获取对应的Field、Method 和 Constructor 对象,并进行相关操作。通常jdk中的关于反射的api我们一般使用与框架的编写。
1获得类的字节码文件的三种方法。
<span style="font-size:18px;">package com.reflect;
import com.reflect.bean.Person;
/**
* User: OF895
* Date: 14-11-11
* Time: 下午1:43
*/
public class GetClazzDemo {
public static void main(String[] args) {
//反射,加载类,获得类的字节码文件
try {
//第一种获得“类的字节码”文件的方法,将类的字节码文件加载到"内存中"
Class clazz = Class.forName("com.reflect.bean.Person");
System.out.println(clazz);
//第二种获得“类的字节码”文件的方法
Class clazz1 = new Person().getClass();
System.out.println(clazz1);
//第三种获得“类的字节码”文件的方法,将类的字节码文件加载到内存中
Class clazz2 = Person.class;
System.out.println(clazz2);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
</span>
2利用反射技术反射出类中的方法的构造函数。
Person类,用于被反射的类:
<span style="font-size:18px;">package com.reflect.bean;
import java.io.InputStream;
import java.util.List;
/**
* User: OF895
* Date: 14-11-11
* Time: 下午1:44
*/
public class Person {
public int age;
public String name = "小明";
public String height = "100";
private String gender = "男";
public static String weight = "300";
//私有的构造方法
private Person(List<String> list) {
System.out.println("这个一个私有的构造方法!");
}
public Person() {
System.out.println("new person!");
}
public Person(int age, String name) {
this.age = age;
this.name = name;
System.out.println("这是含有参数的构造方法!");
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void say() {
System.out.println("这是一个不带参数的say方法!");
}
public void say(String name, int age) {
System.out.println(name + ":" + age);
}
public Class[] say(String name, int[] password) {
return new Class[]{String.class, int.class};
}
private void say(InputStream in) {
System.out.println(in);
}
//静态方法的反射
public static void say(int num) {
System.out.println(num);
}
//如何反射main方法,注意一下main方法的参数是一个String类型的数组
public static void main(String[] args) {
System.out.println("main...................");
}
}
</span>
<span style="font-size:18px;">package com.reflect;
import com.reflect.bean.Person;
import org.junit.Test;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;
/**
* 利用反射技术反射出类中的方法的构造函数
* User: OF895
* Date: 14-11-11
* Time: 下午5:35
*/
public class GetConstructDemo {
//反射类中的无参数的构造方法
@Test
public void test1() {
try {
Class clazz = Class.forName("com.reflect.bean.Person");
//反射类中的无参数的构造方法
Constructor constructor = clazz.getConstructor(null);
//构造函数的主要作用是实例化一个对象,所以在这里我们拿到一个Constructor对象后,我们可以通过调用他的newInstance()方法,实例化一个对象!
Person person = (Person) constructor.newInstance();
System.out.println(person.height);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
//反射类的含有参数的构造方法
@Test
public void test2() throws Exception {
Class clazz = Class.forName("com.reflect.bean.Person");
//反射类中含有参数的构造方法,这里不要写成Integer.class,int.class
Constructor constructor = clazz.getConstructor(int.class, String.class);
Person person = (Person) constructor.newInstance(20, "xiaoming");
person.say();
}
//反射类中的私有的的构造方法
@Test
public void test3() throws Exception {
Class clazz = Class.forName("com.reflect.bean.Person");
//反射类中的私有的构造方法
Constructor constructor = clazz.getDeclaredConstructor(List.class);
//不管被反射的类的构造方法是什么样的访问权限,这里强制允许访问,如果这里不这样设置,那么在类外是无法访问Person类的“私有的”构造方法的。
constructor.setAccessible(true); //反射类的私有的构造函数,那么这个设置一定要加上!
Person person = (Person) constructor.newInstance(new ArrayList());
}
//反射类,创建类的对象的另外一种方法
@Test
public void test4() throws Exception {
Class clazz = Class.forName("com.reflect.bean.Person");
//通过clazz类的newInstance()方法我们也可以直接反射出类的对象
//与上面的例子区别开来,原理:其实这个类的源码也就是先反射出一个无参数的Constructor对象
//然后再通过这个Constructor的newInstance()方法得到
//这个就是sun公司给我们提供的一种简便的方法
Person person = (Person) clazz.newInstance();
}
}
</span>
<span style="font-size:18px;">package com.reflect;
import com.reflect.bean.Person;
import org.junit.Test;
import java.io.FileInputStream;
import java.io.InputStream;
import java.lang.reflect.Method;
/**
* 利用反射技术去反射类的“方法”
* User: OF895
* Date: 14-11-11
* Time: 下午10:09
*/
public class GetMethodDemo {
/**
* public void say() {
* System.out.println("这是一个不带参数的say方法!");
* }
*
* @throws Exception
*/
//反射“无参数”的方法
@Test
public void test1() throws Exception {
Class clazz = Class.forName("com.reflect.bean.Person");
//因为在下面使用invoke方法的时候,我们需要指定反射那个对象下面的那个方法,所以我们需要先“反射”出一个对象!
Person p = (Person) clazz.newInstance();
//查阅api可以知道第一个参数是“方法名”,第二个参数是方法的参数类型
Method method = clazz.getMethod("say", null);//得到无参数的方法的Method对象
//查阅api可以看到,在调用invoke方法的时候,我们必须要执行我们要
method.invoke(p, null);
}
//反射“带参数”的方法
/**
* public Class[] say(String name, int[] password) {
* return new Class[]{String.class, int.class};
* }
*
* @throws Exception
*/
@Test
public void test2() throws Exception {
Class clazz = Class.forName("com.reflect.bean.Person");
//因为在下面使用invoke方法的时候,我们需要指定反射那个对象下面的那个方法,所以我们需要先“反射”出一个对象!
Person p = (Person) clazz.newInstance();
Method method = clazz.getMethod("say", String.class, int[].class);
//这里注意一下“反射”的方法的返回类型是Class[]类型的,字节码类型的数组!
Class[] array = (Class[]) method.invoke(p, "小明", new int[]{1, 2, 3});
System.out.println(array.length);
}
/**
* 要反射的方法:
* private void say(InputStream in) {
* System.out.println(in);
* }
*
* @throws Exception
*/
@Test
public void test3() throws Exception {
Class clazz = Class.forName("com.reflect.bean.Person");
//因为在下面使用invoke方法的时候,我们需要指定反射那个对象下面的那个方法,所以我们需要先“反射”出一个对象!
Person p = (Person) clazz.newInstance();
//注意一下要“反射”方法的参数的类型是InoutStream类型的
Method method = clazz.getDeclaredMethod("say", InputStream.class);
//因为要反射的方法是“private”类型的,所以这里需要设置一下可访问性!
method.setAccessible(true);
//第一个参数是要反射的对象,第二个参数是要反射对象的方法的参数
method.invoke(p, new FileInputStream("d://test.txt"));
}
/**
* //静态方法的反射
* public static void say(int num) {
* System.out.println(num);
* }
*/
@Test
public void test4() throws Exception {
Class clazz = Class.forName("com.reflect.bean.Person");
Method method = clazz.getMethod("say", int.class);
//反射静态方法有个不同的地方就是,进行方法在调用的时候是不需要传入对象的,所以前面给null就可以了!
method.invoke(null, 20);
}
/**
*如何反射main方法?这个有点特殊,不能直接在invoke的时候传入String[]类型的参数
* 这里jdk1.5之后才出现了“可变参数”的概念,sun公司为了兼容以前的代码,这里做了一个折中的选择。
*/
@Test
public void test5() throws Exception {
Class clazz = Class.forName("com.reflect.bean.Person");
Method method = clazz.getMethod("main", String[].class);
//这个有点特殊,不能直接在invoke的时候传入String[]类型的参数,必须传入new Object[]{new String[]{"hello","world"}}
//如果直接传入new String["hello","world"],会在person中去寻找有两个String类型的static的main方法,它默认会将String["hello","world"]拆成"hello","world两个参数
method.invoke(null, new Object[]{new String[]{"hello","world"}});
}
}
</span>
4反射类的“字段”(这个仍然是是使用上面的Person类):
<span style="font-size:18px;">package com.reflect;
import com.reflect.bean.Person;
import org.junit.Test;
import java.lang.reflect.Field;
/**
* 反射类的“字段”
* User: OF895
* Date: 14-11-11
* Time: 下午11:26
*/
public class GetFieldDemo {
/**
* 反射Person类的name字段
* <p/>
* public String name = "小明";
*/
@Test
public void test1() throws Exception {
Class clazz = Class.forName("com.reflect.bean.Person");
//这里的参数是要“反射的”字段的“引用名”
Field field = clazz.getField("name");
//我们可以获取到“反射的”字段的“类型”
Class type = field.getType();
//获取到“反射的”字段的值,参数一定要记住,要从“反射那个对象”中的此字段,要传入“被反射字段所在的类的对象”
Person p = (Person) clazz.newInstance();
// Object value = field.get(p);
if (type.equals(String.class)) {
//我们还可以为“字段”赋值,先赋值,在取值
field.set(p,"科比");
//这里的字段P,指的是反射的“字段”,所在的类的"对象"
Object value = field.get(p);
//如果得到的“反射的字段”的类型是java.lang.String类型的,那么我们就将“反射的”字段的值,强制转换成String类型的
String str = (String) value;
System.out.println(str);
}
}
/**
* 反射私有的字段
* private String gender = "男";
*
*/
@Test
public void test2() throws Exception {
Class clazz = Class.forName("com.reflect.bean.Person");
Field field = clazz.getDeclaredField("gender");
field.setAccessible(true);
Object value = field.get(clazz.newInstance());
System.out.println(value);
}
/**
*
* 反射类的静态的字段
*
* public static String weight = "300";
*/
@Test
public void test3() throws Exception {
Class clazz = Class.forName("com.reflect.bean.Person");
Field field = clazz.getDeclaredField("weight");
//由于“反射的”是“静态的”字段,所以我们不需要指定反射的具体的类的对象,因为这个类的这个静态的“字段”在内存中只有一份,是通用的。
Object value = field.get(null);
System.out.println(value);
}
}</span>