黑马程序员—高新技术:Reflect反射

来源:互联网 发布:淘宝新店铺转让价格表 编辑:程序博客网 时间:2024/04/29 04:48

<---------------------- 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 {// 方式1Person p = new Person();Person p2 = new Person();Class c = p.getClass();Class c2 = p2.getClass();System.out.println(p == p2);// falseSystem.out.println(c == c2);// true// 方式2Class 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.PersonSystem.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字段赋值为20System.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";@Overridepublic String toString() {return str1+"***"+str2+"***"+str3+"***";}}

---------------------- ASP.Net+Android+IOS开发、.Net培训、期待与您交流! ----------------------详细请查看:http://edu.csdn.net




0 0
原创粉丝点击