Java反射机制

来源:互联网 发布:离婚率 知乎 编辑:程序博客网 时间:2024/05/22 15:52
一、什么是反射机制 
        简单的来说,反射机制指的是程序在运行时能够获取自身的信息。在java中,只要给定类的名字, 
    那么就可以通过反射机制来获得类的所有信息。 
二、哪里用到反射机制 
        有些时候,我们用过一些知识,但是并不知道它的专业术语是什么,在刚刚学jdbc时用过一行代码, 
    Class.forName("com.mysql.jdbc.Driver.class").newInstance();但是那时候只知道那行代码是生成 
    驱动对象实例,并不知道它的具体含义。听了反射机制这节课后,才知道,原来这就是反射,现在很多开 
    框架都用到反射机制,hibernate、struts都是用反射机制实现的。 
三、反射机制的优点与缺点 
        为什么要用反射机制?直接创建对象不就可以了吗,这就涉及到了动态与静态的概念, 
    静态编译:在编译时确定类型,绑定对象,即通过。 
    动态编译:运行时确定类型,绑定对象。动态编译最大限度发挥了java的灵活性,体现了多 
    态的应用,有以降低类之间的藕合性。 
    一句话,反射机制的优点就是可以实现动态创建对象和编译,体现出很大的灵活性,特别是在J2EE的开发中 
    它的灵活性就表现的十分明显。比如,一个大型的软件,不可能一次就把把它设计的很完美,当这个程序编 
    译后,发布了,当发现需要更新某些功能时,我们不可能要用户把以前的卸载,再重新安装新的版本,假如 
    这样的话,这个软件肯定是没有多少人用的。采用静态的话,需要把整个程序重新编译一次才可以实现功能 
    的更新,而采用反射机制的话,它就可以不用卸载,只需要在运行时才动态的创建和编译,就可以实现该功 
    能。 
       它的缺点是对性能有影响。使用反射基本上是一种解释操作,我们可以告诉JVM,我们希望做什么并且它 
    满足我们的要求。这类操作总是慢于只直接执行相同的操作。 
四、利用反射机制能获得什么信息 
         一句话,类中有什么信息,它就可以获得什么信息,不过前提是得知道类的名字,要不就没有后文了 
    首先得根据传入的类的全名来创建Class对象。 
    Class c=Class.forName("className");注明:className必须为全名,也就是得包含包名,比如,cn.netjava.pojo.UserInfo; 
    Object obj=c.newInstance();//创建对象的实例 
    OK,有了对象就什么都好办了,想要什么信息就有什么信息了。   
    获得构造函数的方法 
    Constructor getConstructor(Class[] params)//根据指定参数获得public构造器


    Constructor[] getConstructors()//获得public的所有构造器


    Constructor getDeclaredConstructor(Class[] params)//根据指定参数获得public和非public的构造器


    Constructor[] getDeclaredConstructors()//获得public和非public的所有构造器
    Class<?>[] getDeclaredClasses() 返回 Class 对象的一个数组,这些对象反映声明为此 Class 对象所表示的类的成员的所有类和接口。

    Method getMethod(String name, Class[] params) 根据参数类型获得方法


    Method[] getMethods()//获取的是类的所有共有方法,这就包括自身的所有public方法,和从基类继承的、从接口实现的所有public方法。


    Method getDeclaredMethod(String name, Class[] params)//根据方法名和参数类型,获得public和非public的方法


    Method[] getDeclaredMethods()//)获取的是类自身声明的所有方法,包含public、protected和private方法

    Field getField(String name)//根据变量名得到相应的public变量


    Field[] getFields()//获得类中所以public的方法


    Field getDeclaredField(String name)//根据方法名获得public和非public变量


    Field[] getDeclaredFields()//获得类中所有的public和非public方法 
    常用的就这些,知道这些,其他的都好办…… 
五、用反射机制能干什么事 
        刚开始在使用jdbc时侯,在编写访问数据库时写到想吐,有八个表,每个表都有增删改查中操作 
    那时候还不知道有反射机制这个概念,所以就对不同的表创建不同的dao类,这样不仅开发速率地,而且代码 
    冗余的厉害,最要命的是看着差不多的,然后直接复制修改,由于容易犯各种低级的错误(大小写啊,多一 
    个或少一个字母啊……),一个错误就可以让你找半天。 
        有了java反射机制,什么都好办了,只需要写一个dao类,四个方法,增删改查,传入不同的对象,就OK啦, 
    无需为每一个表都创建dao类,反射机制会自动帮我们完成剩下的事情,这就是它的好处。说白了,反射机制就是专门 
    帮我们做那些重复的有规则的事情,所以现在很多的自动生成代码的软件就是运用反射机制来完成的




                          具体方法详解
Method Class.getMethod(String name, Class<?>... parameterTypes)的作用是获得对象所声明的公开方法


该方法的第一个参数name是要获得方法的名字,第二个参数parameterTypes是按声明顺序标识该方法形参类型。
如:
person.getClass().getMethod("Speak", null);
//获得person对象的Speak方法,因为Speak方法没有形参,所以parameterTypes为null
person.getClass().getMethod("run", String.class);
//获得person对象的run方法,因为run方法的形参是String类型的,所以parameterTypes为String.class

 public void Speak(){
        System.out.println("Hello! "+"My name is "+name);
    }
public void run(String speed){
        System.out.println("I can run " + speed+" KM!!!");
    }


++++++++++++++++++++++++  调用方法  +++++++++++++++++++++
 Person person = new Person("小明",10001);
        person.Speak();
        person.run("10");
        Method m1 = person.getClass().getMethod("Speak", null);        
        Method m2 = person.getClass().getMethod("run", String.class);
        System.out.println(m1);
        System.out.println(m2);
++++++++++++++++++  如果方法有N个参数  ++++++++++++++++++++
Method method = this.getClass().getDeclaredMethod("方法名", new Class[]{String.class,int.class}); 


++++++++  method.invoke(Object obj,Object... args)  +++++++
obj--------类对象(简单的说就是调用谁的方法用谁的对象)
args-------得到方法里的参数
如:
public class InvokeObj 
    public String[] arrayShow (String[] arr) {  
        return arr;  
    }  
        Class<InvokeObj> clazz = InvokeObj.class; 
        Method method3 = clazz.getMethod("arrayShow", String[].class);  
        String[] strs = new String[]{"hello", "world", "!"};  
        //数组类型的参数必须包含在new Object[]{}中,否则会报IllegalArgumentException  
        String[] strings = (String[]) method3.invoke(new InvokeObj(), new Object[]{strs});  
        for (String str : strings) {  
            System.out.println("arrayShow的数组元素:" + str);  
        }  
        System.out.println("InvokeObj类的StringShow()方法: ");



++++++++++++  constructor.setAccessible(true) ++++++++++++++
值为 true 则指示反射的对象在使用时应该取消 Java 语言访问检查。值为 false 则指示反射的对象应该实施 Java 语言访问检查。
实际上setAccessible是启用和禁用访问安全检查的开关,并不是为true就能访问为false就不能访问。




+++++++++++++  constructor.newInstance  ++++++++++
Class<?> clazz = Class.forName("reflect.Person");
        // 获得构造器
        Constructor<?> constructor = clazz.getDeclaredConstructor(new Class[] {});
        // 根据类的默认构造器来获得一个对象
        Object instance = constructor.newInstance(new Object[] {});


Constructor<?> constructor2 = clazz
                .getDeclaredConstructor(new Class[] { Integer.class, String.class, Integer.class });
        Object instance2 = constructor2.newInstance(new Object[]{1,"Tom",21});
        System.out.println(instance2);


+++++++++++++ 三种获取class对象的方式 +++++++++++++
Student类
Student stu=new Student("tom",23);
Class c1=stu.getClass(); //class文件创建的
Class c2=Student.class;  //class文件创建的
Class c3=Class.forName("com.eduask.reflect.Student");//class文件创建的 


+++++++++++  Class.asSubclass +++++++++++
public <U> Class<? extends U> asSubclass(Class<U> clazz)  
这是java.lang.Class中的一个方法,作用是将调用这个方法的class对象转换成由clazz参数所表示的class对象的某个子类。
举例来说,
List<String> strList = new ArrayList<String>();  
Class<? extends List> strList_cast = strList.getClass().asSubclass(List.class);
上面的代码将strList.getClass()获取的class对象转换成Class<? extends List>,这么做似乎没有什么意义,因为我们很清楚strList.getClass()获取的class对象就是ArrayList,它当然是List.class的一个子类;但有些情况下,我们并不能确知一个class对象的类型,典型的情况是Class.forName()获取的class对象:Class.forName()的返回类型是Class<?>,但这显然太宽泛了,假设我们需要
List.class类型的class对象,但我们传递给Class.forName的参数是未知的(可能是"java.lang.String",也可能是"java.util.ArrayList"),
这时我们就可以用到asSubclass()这个方法了。
如下:
Class.forName("xxx.xxx.xxx").asSubclass(List.class).newInstance();  
当xxx.xxx.xxx是List的子类时,正常执行,当不是List的子类时,抛出ClassCastException,这时我们可以做些别的处理;如果我们查看Class.asSubclass()
在JDK中的中的引用的话,会发现这种用法有很多。
这里有必要说下 instanceof 关键字.
<<object reference>> instanceof <<class/interface name>> 
它的用法用于判断一个Object是否是某个超类或者接口的一个子类或者实现类(不一定是直接超类或者直接接口),
如下:
interface IFace {  
}  
class IFaceImpl implements IFace {  
}  
class IFaceImplExt extends IFaceImpl {  
}    
System.out.println(new IFaceImpl() instanceof IFace); // true  
System.out.println(new IFaceImplExt() instanceof IFace); // true 
asSubclass用于窄化未知的Class类型的范围,而instanceof用于判断一个对象引用是否是一个超类或者接口的子类/实现类,
如果试图将instanceof用于Class类型的判断会引起编译错误