Java--类反射(一)

来源:互联网 发布:python做网页 编辑:程序博客网 时间:2024/06/07 00:24

什么是类反射 ?

☆什么是反射:

1)JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的反射机制。

2)反射(Reflection)是Java程序开发语言的特征之一,它允许运行中的Java程序对自身进行检查, 也称自审,并能直接操作程序的内部属性。例如,使用它能获得Java类中各成员的名称并显示出来。
3)Java的这一能力在实际应用中应用得很多,在其它的程序语言中根本就不存在这一特性。例如,Pascal、C或者C++中就没有办法在程序中获得函数定义相关的信息。
4)JavaBean是类反射的实际应用之一,它能让一些工具可视化的操作软件组件。这些工具通过类反射动态的载入并取得Java组件(类)的属性。后面学习的各种框架,基本上都会有反射的使用。

☆反射引例(HelloWorld)

引例类:Person类

class Person{private String name;public static final int age = 20;public void aa(){System.out.println("aaaa.......");}public void bb(){System.out.println("bbbbb.......");}public int aa(int a ,int b){System.out.println("a+b="+(a+b));return a+b;}}
@Testpublic void demo1(){Class c = Person.class;Field flds[] = c.getDeclaredFields();System.out.println("!!!!"+flds);for(Field fld:flds){System.out.println("name:"+fld.getName());System.out.println("modifiers:"+fld.getModifiers());System.out.println("type:"+fld.getType());System.out.println("declaringClass");}}

测试结果如下:

!!!![Ljava.lang.reflect.Field;@3603820ename:namemodifiers:2type:class java.lang.StringdeclaringClassname:agemodifiers:25type:intdeclaringClass


反射使用的三个步骤

用于反射的类,如Method,可以在java.lang.reflect包中找到。使用这些类的时候必须要遵循三个步骤:

第一步:获得你想操作的类的java.lang.Class对象。在运行中的Java程序中,用java.lang.Class类来描述类和接口等。

第二步:调用诸如getDeclaredMethods的方法,取得该类中定义的所有方法的列表。
第三步:使用反射的API来操作这些信息。

如下面这段代码:

Class c = Class.forName("java.lang.String");Method ms[] = c.getDeclaredMethods();System.out.println(ms[0].toString());

☆反射示例(模拟instanceof的功能)

        @Test //进行类反射的3个步骤---以方法调用为例public  void demo2() throws Exception{//1获取Class对象 ----类模板对象(山寨叫法), 字节码对象(官方叫法), 蓝本Class c = Class.forName("cn.hucu.reflect.hello.Person");    //2获取要调用的方法--Method对象Method m = c.getDeclaredMethod("aa", null);//aa()方法  是 一个Method对象//3执行方法--m.invoke() //Person p = new Person();Object p = c.newInstance();m.invoke(p, null);    }@Testpublic void demo3() throws  Exception{//获取Class对象Class c = Class.forName("cn.hucu.reflect.hello.Person");//2获取要调用的方法--Method对象    Class parameterTypes[] = {int.class,int.class};    Method m = c.getDeclaredMethod("aa", parameterTypes);        //3执行方法--m.invoke()    Object p = c.newInstance();    Object objs[] = {10,20};    Object returnValue = m.invoke(p, objs);    System.out.println(returnValue);}@Testpublic void simulateInstanceOf() throws Exception{Person p = new Person();Class c = Class.forName("cn.hucu.reflect.hello.Person");boolean boo = c.isInstance(p); //判断对象p是否属于c模板System.out.println(boo);}


获取Class对象的三种方式

★ 方式一:通过对象的getClass方法进行获取。这种方式需要具体的类和该类的对象,以及调用getClass方法。

        @Test// 通过对象的getClass方法进行获取,, 依赖: 类+对象public void demo1() {Person p = new Person();Class c = p.getClass();System.out.println(c);}

Person类:

class Person {private String name;public static final int age = 20;public void aa() {System.out.println("aaaa......");}}

测试结果如下:

class cn.hucu.reflect.fetchClass.Person

★ 方式二:任何数据类型(包括基本数据类型)都具备着一个静态的属性class,通过它可直接获取到该类型对应的Class对象。这种方式要使用具体的类,然后调用类中的静态属性class完成,无需调用方法,性能更好。

        @Test //任何数据类型(包括基本数据类型)都具备着一个静态的属性class,直接获取, 依赖: 类public void demo2(){Class c1 = Person.class;System.out.println(c1);Class c2 = int.class;System.out.println(c2);Class clazz = Double.class;System.out.println();}

测试结果如下:

class cn.hucu.reflect.fetchClass.Personintclass java.lang.Double

★ 方式三:通过Class.forName()方法获取。这种方式仅需使用类名,就可以获取该类的Class对象,更有利于扩展。
        @Test//通过Class.forName()方法获取, 依赖: java.lang.String  ---这种一般不断依赖(因为java的语言包通常离不开)public void demo3() throws Exception{Class c =Class.forName("cn.hucu.reflect.fetchClass.Person");System.out.println(c);}

测试结果如下:
class cn.hucu.reflect.fetchClass.Person

类的解剖(获取类的定义信息)
★ 获取类的方法,★ 获取类的构造器,★ 获取类的属性字段
        @Testpublic void FetchMethods() throws Exception {Class c = Class.forName("cn.hucu.reflect.decompose.Person");// (1)获取所有方法Method ms[] = c.getDeclaredMethods(); // 获取当前类中声明的所有方法,包括私有的// Method ms[] = c.getMethods();//获取当前类及其父类中声明的public方法// (2)获取指定名称和参数类型列表的某一个方法// Method oneM = c.getDeclaredMethod(name, parameterTypes);// Method oneM = c.getMethod(name, parameterTypes);for (Method m : ms) {System.out.println("name:" + m.getName());System.out.println("declaringClass:" + m.getDeclaringClass());int modifiers = m.getModifiers();System.out.println("modifiers:" + Modifier.toString(modifiers));Class exceps[] = m.getExceptionTypes();for (int i = 1; i < exceps.length; i++) {Class cls = exceps[i - 1];System.out.println(i + "-exceptionTypes:" + cls.getName());}Class params[] = m.getParameterTypes();for (int i = 0; i < params.length; i++) {System.out.println((i + 1) + "--parameterTypes:" + params[i]);}System.out.println("returnTypeame:" + m.getReturnType());System.out.println("annotation:" + m.getAnnotation(Test.class));System.out.println("-----------------");}}
测试类:Person类
package cn.hucu.reflect.decompose;import java.io.File;import org.junit.Test;public class Person {private String name;@MyAnnoprivate String pwd;public static final int age = 20;public Person(String name, String pwd) {super();this.name = name;this.pwd = pwd;}public Person() {super();}public Person(String name) {this.name = name;}@Testpublic void aa(){System.out.println("aaa....");}synchronized static double sum(int a,int b){return b+a;}private File fl(Object obj){File f = new File("aa.txt");return f;}}

测试结果:
name:aadeclaringClass:class cn.hucu.reflect.decompose.Personmodifiers:publicreturnTypeame:voidannotation:@org.junit.Test(expected=class org.junit.Test$None, timeout=0)-----------------name:sumdeclaringClass:class cn.hucu.reflect.decompose.Personmodifiers:static synchronized1--parameterTypes:int2--parameterTypes:intreturnTypeame:doubleannotation:null-----------------name:fldeclaringClass:class cn.hucu.reflect.decompose.Personmodifiers:private1--parameterTypes:class java.lang.ObjectreturnTypeame:class java.io.Fileannotation:null-----------------

类的调用(调用类中的成员)
★ 构造类对象 :使用构造器新建对象。根据指定的参数类型找到相应的构造函数,传入相应参数调用执行,以创建一个新的对象实例。
package cn.hucu.reflect.operateObj;public class Person {private String name;private int age;public double score;public Person(String name, int age) {this.name = name;this.age = age;}public Person(String name) {this.name = name;}public Person() {}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;}public double sum(int a, int b) {return a + b;}public void sum() {System.out.println("不加.....");}public static void aa() {System.out.println("aaa.........");}@Overridepublic String toString() {return  name + ", " + age ;}// 该方法用于演示暴力访问private void set(int n) {age = n;}}


// //一、使用构造器来创建对象////@Test// 空参构造public void operateConstructor() throws Exception {Class c = Class.forName("cn.hucu.reflect.operateObj.Person");Object obj = c.newInstance();System.out.println("空参构造>>>" + obj);}@Test// 使用指定参数列表的构造器来创建对象public void operateConstructor2() throws Exception {// 步1Class c = Class.forName("cn.hucu.reflect.operateObj.Person");// 步2 获得指定的构造器对象con---通过形参(类型列表)// Class paramTypes[] = {String.class,int.class};// Constructor con =c.getDeclaredConstructor(paramTypes);// 步3// Object params[] = {"Jack",22};// Object obj = con.newInstance(params);// 一步到位Object obj = c.getDeclaredConstructor(String.class, int.class).newInstance("Jack", 22);System.out.println(obj);}


★ 调用方法
根据方法名称执行方法。根据方法名与参数类型匹配指定的方法,传入相应参数与对象进行调用执行。若是静态方法,则不需传入具体对象。

       // /二、使用Method对象来执行指定方法---函数调用//@Test// 调用空参方法public void callMethod() throws Exception {// 步1Class clazz = Class.forName("cn.hucu.reflect.operateObj.Person");// 步2Method m = clazz.getDeclaredMethod("toString", null);Class Class[] = { String.class, int.class };// 步3Object obj = clazz.getConstructor(Class).newInstance("Rose", 25);Object returnValue = m.invoke(obj, null);System.out.println(returnValue);}// 调用指定形参类型列表的方法 ---public double sum(int a, int b)@Testpublic void callMethod2() throws Exception {// 步1Class clazz = Class.forName("cn.hucu.reflect.operateObj.Person");// 步2 获得指定的Method对象mClass paramTypes[] = { int.class, int.class };// AC以后我们就用这种简单保险的写法,参数是什么类型就用该类型中的class静态属性// Class paramTypes[] = {Integer.class,int.class}; //WA,// 这里是精确匹配(要求类模板一样),没有装箱拆箱功能,是严格匹配sum(Integer,int)的方法// Class paramTypes[] = {Integer.TYPE,int.class}; //AC,// Integer.TYPE指的是Integer数据的类型,可以匹配intMethod m = clazz.getDeclaredMethod("sum", paramTypes);// 步3 方法调用---让m对象去调用它的invoke()方法Object obj = clazz.newInstance();Object params[] = { 100, 50 };Object returnValue = m.invoke(obj, params);System.out.println(returnValue);}@Test// 调用静态方法 ---public static void aa()public void callMethod3() throws Exception {// 步1Class clazz = Class.forName("cn.hucu.reflect.operateObj.Person");// 步2 获得指定的Method对象mMethod m = clazz.getDeclaredMethod("aa", null);// 空参方法// 步3 方法调用---让m对象去调用它的invoke()方法m.invoke(null, null); // 对象为空,实参为空}


★ 获取与设置属性值

根据属性名称读取与修改属性的值,访问非静态属性需传入对象为参数。

     // 三、使用Field对象来访问类(对象)中的属性变量---读取或设置属性值///public void fieldDemo() throws Exception {// 步1Class clazz = Class.forName("cn.hucu.reflect.operateObj.Person");// 步2 获得指定的Field对象Field fld = clazz.getDeclaredField("score");// 步3 给fld属性设置值和读取值Object obj = clazz.newInstance();fld.setDouble(obj, 88.66);// fld.set(obj, new Double(2.12)); //把数据值当成Objectdouble v1 = fld.getDouble(obj);System.out.println("1::" + v1);Object v2 = fld.get(obj);System.out.println("2::" + v2);}/* * setAccessible()是AccessibleObject类中的方法, * 该类是Constructor、Method和Field三者的公共父类, 因此都可以调用---都可打开开关进行暴力访问 */@Test //暴力访问public void AccessibleDemo() throws Exception {// 步1Class clazz = Class.forName("cn.hucu.reflect.operateObj.Person");Object obj = clazz.newInstance();// 访问私有属性Field fld = clazz.getDeclaredField("name");fld.setAccessible(true); // 打开访问开关,就可以暴力访问了fld.set(obj, "张三");// 访问私有方法Method m = clazz.getDeclaredMethod("set", int.class);// 方法名和参数类型(int)m.setAccessible(true);// 打开访问开关,就可以暴力访问了m.invoke(obj, 24);System.out.println(obj);}// ※暴力访问一般只在特殊场合如做框架功能时使用,平时开发不能使用,否则会违反设计原则

类反射功能很强大,那就是"神仙"!!!!









原创粉丝点击