<---------------------- ASP.Net+Android+IOS开发、.Net培训、期待与您交流! ----------------------/p>
一 反射的基石,class类。
Java程序中各个Java类属于同一类事物,描述这一类事物的Java类名就是Class。
例如我们将人定义为person类,将动物定义为Anime类,而众多诸如此类该如何通过Java描述呢,我们称其为class类。
这个特性自Java1.2开始出现,非常强大。将来我们所用的很多框架,都要用到反射技术。
一般我们在定义一个类的时候,class这个单词是小写的。而当我们对类进行描述的时候,类类型Class要采取大写。
class:Java中的类用于描述一类事物的共性,该类事物有什么属性,没有什么属性,至于这个属性的值是什么,则由此类的实例对象确定,不同的实例对象有不同的属性值。
Class:指的是Java程序中的各个Java类是属于同一类事物,都是Java程序的类,这些类称为Class。例如人对应的是Person类,Java类对应的就是Class。
一个Java类有它的各种属性和方法,有它的父类等等。而通过Class,我们可以得到它方方面面的信息。这个类似逆推的过程就叫做反射。
Class类中的常用方法:
getName() 获取类的名字。
getPakage() 得到自己所属的包。
getMethod() 得到自己所有的方法。
getInterface() 得到自己实现的多个接口。
等等这些方法,我们可以通过它们得到所需的信息。
反射是什么?
反射是个动词,就是通过字节码文件对象,来使用构造方法,成员变量,成员方法。这个过程叫做反射。
反射的一切都是建立在Class字节码文件之上,首先要考虑的是该如何得到一份字节码文件。
获取字节码文件对象有三种方式:
A:使用Object类的getClass()方法
B:使用数据类型.class静态属性
C:使用Class类的forName()静态方法
推荐使用:第三种,因为第三种可以结合配置文件使用。
/*
*
* 你想使用这些内容,那么首先要做的事情,就是你能够获取到字节码文件对象。
* 如何获取Class的对象呢?
* A:使用Object类的getClass()方法。
* B:使用数据类型.class这个静态的成员变量。
* C:使用的是Class类的forName()静态方法。
* public static Class<?> forName(String className)
*/
public class ReflectDemo {
public static void main(String[] args) throws ClassNotFoundException {
// 方式1
Person p = new Person();
Person p2 = new Person();
Class c = p.getClass();
Class c2 = p2.getClass();
System.out.println(p == p2);// false
System.out.println(c == c2);// true
// 方式2
Class c3 = Person.class;
System.out.println(c == c3);
// 方式3
// public static Class<?> forName(String className)
Class c4 = Class.forName("cn.itcast_01.Person");
// cn.itcast_01.Person
// cn.itcast_01.Person
System.out.println(c == c4);
}
}
class Person {
private String name;
public int age;
public Person() {
}
Person(String name) {
this.name = name;
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public void show() {
System.out.println("show");
}
public void method(String name) {
System.out.println("method " + name);
}
public String function() {
return "hello";
}
public String sum(int a, String b) {
return String.valueOf(a).concat(b);
}
private void print() {
System.out.println("print");
}
public String toString() {
return "name:" + name + ",age:" + age;
}
}
以上的代码实现了获取Class字节码文件的三种方式。反射纠结能做哪些比较具体的应用呢?
简单说有三种:
A:通过反射获取构造方法并使用
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
/*
* 通过反射获取带参构造器并创建对象。
*/
public class ReflectDemo2 {
public static void main(String[] args) throws ClassNotFoundException,
NoSuchMethodException, SecurityException, InstantiationException,
IllegalAccessException, IllegalArgumentException,
InvocationTargetException {
// 获取字节码文件对象
Class c = Class.forName("Person");
// 获取带参构造器对象
Constructor con = c.getConstructor(String.class, int.class);
// Person(String name,int age);
// 创建对象
// public T newInstance(Object... initargs)
Object obj = con.newInstance("奶茶", 22);
System.out.println(obj);
}
}
B:通过反射获取成员变量并使用
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
/*
* 通过反射获取成员变量对象并使用。
*
* 需求:
* Person p = new Person();
* p.name = "奶茶";
* p.age = 22;
*/
public class ReflectDemo {
public static void main(String[] args) throws ClassNotFoundException,
NoSuchMethodException, SecurityException, InstantiationException,
IllegalAccessException, IllegalArgumentException,
InvocationTargetException, NoSuchFieldException {
// 获取字节码文件对象
Class c = Class.forName("Person");
// 创建一个对象
Constructor con = c.getConstructor();
Object obj = con.newInstance();
// 获取单个成员变量对象
Field field = c.getField("age");
//给obj对象的指定的字段赋值为指定的值
field.set(obj, 20);//给obj对象的field字段赋值为20
System.out.println(obj);
}
}
C:通过反射获取成员方法并使用
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
/*
* 通过反射获取成员方法对象并使用。
*/
public class ReflectDemo {
public static void main(String[] args) throws Exception {
// 获取字节码文件对象
Class c = Class.forName("Person");
// 通过无参构造创建对象
Constructor con = c.getConstructor();
Object obj = con.newInstance();
// 单个方法的获取
// 无参,无返回值;
Method m = c.getMethod("show");
m.invoke(obj);
System.out.println("*********");
// 带参,无返回值
Method m2 = c.getMethod("method", String.class);
m2.invoke(obj, "hello");
System.out.println("*********");
// 无参,有返回值
Method m3 = c.getMethod("function");
Object m3Obj = m3.invoke(obj);
System.out.println(m3Obj);
System.out.println("*********");
// 带多个参数,有返回值
Method m4 = c.getMethod("sum", int.class, String.class);
Object m4Obj = m4.invoke(obj, 100, "abc");
System.out.println(m4Obj);
System.out.println("*********");
//私有方法的使用
Method m5 = c.getDeclaredMethod("print");
m5.setAccessible(true);
m5.invoke(obj);
}
}
案例:改变任意对象中所有STRING类型成员变量所对应的字符串内容;
import java.lang.reflect.Field;
//题目:将任意一个对象中的所有string类型的成员变量所对应的字符串内容的“b”改成“a”.
/*
* 思路要对对象进行扫描,得到它所有的成员变量,也就是字段。再做修改
* 步骤1,写一个方法,传入对象。
* 2,通过对象,可以反射得到他的所有字段,并 传入数组
* 3,迭代每一个字段,然后再得出每个字段的类型。(这个时候类型并不明确),如何确认类型呢?则通过比较完成。
* 然后对获得的每一个字段进行修改。注意,在判断迭代条件的时候,由于同属一个字节码,==号的语义比equals来的准确。
* */
public class ReflectTest {
/**
* @param args
*/
public static void main(String[] args)throws Exception {
//先得有个类的实例对象
ReflectExample re =new ReflectExample();
changeStringValue(re);
System.out.println(re);
}
private static void changeStringValue(Object obj) throws Exception{//方法
//获得所有字段
Field[] fields =obj.getClass().getFields();
//这里要注意,获得指定字段的方法是getField(指定名称); 获得所有字段的方法是getFields();
for (Field field : fields) {
//getType()能获得字段的类型。
if(field.getType()==(String.class)){
//这里先要获得具体的值再作修改;返回值是String类型。经过判断,知道这里得出的也是String类型。
String oldValue=(String)field.get(obj);
//得到具体的字段值之后呢,可以对值进行改变。
String newValue=oldValue.replace("b", "a");
//这里输入换完了值,但是对象本身的值没有被改变。目前只是将值取出而已。只get还没有set.下面的方法是对对象的值进行设置。
field.set(obj, newValue);
//为了得到我们的结果,还要重写toString方法。
}
}
}
}
class ReflectExample {
public String str1 ="ball";
public String str2 ="baskeball";
public String str3 ="itcast";
@Override
public String toString() {
return str1+"***"+str2+"***"+str3+"***";
}
}
---------------------- ASP.Net+Android+IOS开发、 .Net培训、期待与您交流! ----------------------详细请查看: http://edu.youkuaiyun.com