您的位置:首页 > 编程语言 > Java开发

【框架基础】java反射详解

2017-04-19 22:05 183 查看
在学习框架设计之前,先来了解一下框架基础——Java反射机制。

        一、什么是反射机制

        反射机制是在程序运行状态时,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都

能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的反射机制。

主要是指程序可以访问,检测和修改它本身状态或行为的一种能力,并能根据自身行为的状态和结果,调整或修改应

用所描述行为的状态和相关的语义。

       反射是Java语言中一种强大的工具,能够使我们很方便的创建灵活的代码,这些代码可以在运行时装配,无需在

组件之间进行源代码链接。

       要让Java程序能够运行,就得让Java类被Java虚拟机加载。Java类如果不被Java虚拟机加载就不能正常运行。正

常情况下,我们运行的所有的程序在编译期时候就已经把那个类被加载了。

       Java的反射机制是在编译时并不确定是哪个类被加载了,而是在程序运行的时候才加载、探知、自审。使用的是

在编译期并不知道的类。这样的编译特点就是Java反射。

       简单的来说,反射机制指的是程序在运行时能够获取自身的信息。在Java中,只要给定类的名字, 那么就可以通

过反射机制来获得类的所有信息。

       二、反射机制能做什么

       反射机制主要提供了以下功能: 

       1.在运行时判断任意一个对象所属的类;

       2.在运行时构造任意一个类的对象;

       3.在运行时判断任意一个类所具有的成员变量和方法;

       4.在运行时调用任意一个对象的方法;

       5.生成动态代理;

       6.进行反编译:.class(字节码文件)-->.java(源代码文件);

       三、Java反射的作用

       假如有两个程序员,一个程序员在写程序的时需要使用第二个程序员所写的类,但第二个程序员并没完成他所写

的类。那么第一个程序员的代码是不能通过编译的。此时,利用Java反射的机制,就可以让第一个程序员在没有得到

第二个程序员所写的类的时候,来完成自身代码的编译。

      Java的反射机制它知道类的基本结构,这种对Java类结构探知的能力,我们称为Java类的“自审”。如Eclipse

中,一按点,编译工具就会自动的把该对象能够使用的所有的方法和属性全部都列出来,供用户进行选择。这就是利

用了Java反射的原理,是对我们创建对象的探知、自审。   

       四、反射机制的优点与缺点 

       为什么要用反射机制?直接创建对象不就可以了吗,这就涉及到了动态与静态的概念。

       静态编译:在编译时确定类型,绑定对象,即通过。 

       动态编译:运行时确定类型,绑定对象。动态编译最大限度发挥了Java的灵活性,体现了多态的应用,有以降低

类之间的藕合性。 

       一句话,反射机制的优点就是可以实现动态创建对象和编译,体现出很大的灵活性,特别是在JavaEE的开发中。

它的灵活性就表现的十分明显。比如,一个大型的软件,不可能一次就把把它设计的很完美,当这个程序编译后,发

布了,当发现需要更新某些功能时,我们不可能要用户把以前的卸载,再重新安装新的版本,假如这样的话,这个软

件肯定是没有多少人用的。采用静态的话,需要把整个程序重新编译一次才可以实现功能 的更新,而采用反射机制的

话,它就可以不用卸载,只需要在运行时才动态的创建和编译,就可以实现该功能。 

       它的缺点是对性能有影响。使用反射基本上是一种解释操作,我们可以告诉JVM,我们希望做什么并且它 满足我们的要求。这类操作总是慢于只直接执行相同的操作。   

1:获取类的三种方式

(1):任何Class都有一个隐含的静态成员变量  Class<?>  c1=p.Class;

(2):已知该类的对象 通过getClass方法获得

(3):根据一个类的全名字符串来获取一个类的类对象  Class<?> clazz=Class.getforName("java.lang.String");

2:根据获取的类的类对象 获取对象的所有方法:Method[] methods=clazz.getMethods();

3:获取所有类的属性以上面clazz为例  Field [] field=clazz.getDeclaredFields();  循环输出如下

private final char[] java.lang.String.value

private int java.lang.String.hash

private static final long java.lang.String.serialVersionUID

private static final java.io.ObjectStreamField[] java.lang.String.serialPersistentFields

public static final java.util.Comparator java.lang.String.CASE_INSENSITIVE_ORDER

private static final int java.lang.String.HASHING_SEED

private transient int java.lang.String.hash32

获取类的构造器

Constructor<?> [] constructor=clazz.getDeclaredConstructors();

获取Clazz属性方法和构造器

Class<?> clazz=Class.forName("com.czmec.reflect.persion");

//获取指定属性属性

Field field=clazz.getDeclaredField("adress");

System.out.printf(field);

//获取类的一个具体的方法
Method method =clazz.getDeclaredMethod("getName",new Class[]{});  /*注意 new Class[]{}是具体方法的参数   比如setName方法
 带有参数String age  那么应该写成new Class[]{String.Class}*/

//获取一个带有参数的方法
Method method1=clazz.getDeclaredMethod("setName",new
Class[]{String.Class});

//获取默认构造器(无参数)

Constructor<?> constructor
=clazz.getDeclaredConstructor(new Class[]{});

//获取有参构造器

Constructor<?>
constructor1=clazz.getDeclaredConstructor(new Class[]{Integer.class,String.class,String.class});

反射赋值

Class<?>
clazz=Class.froName("com.czmec.reflect.persion");

//获取构造器

Constructor<?>
constructor=clazz.getDeclaredConstructor(new Class[]{});

//根据类的默认构造器来获取一个对象
 api对newInstance的解释  使用此
Constructor
对象表示的构造方法来创建该构造方法的声明类的新实例,并用指定的初始化参数初始化该实例。

Object
instence =constructor.newInstance(new Obeject[]{});

//给对象属性赋值

//获取方法名称
Method[]
methods=clazz.getDeclaredMethods();

for(Method
m:methods){

 
//获取方法名称

 
            String name=m.getName();

 
            boolean startWith=name.startsWith("set");

               if(startWith){

                //获取set字符串的后面的值

                String fieldName=name.substring(3);

                //获取属性的名字

                fieldName=fieldName.substring(0,1).toLowerCase()+fieldName.substring(1);

                Field field=clazz.getDeclaredField(fieldName);//Field 提供有关类或接口的单个字段的信息,以及对它的动态访问权限。反射的字段可能是一个类(静态)字段或实例字段。

                Class<?> type=field.getType();

                if(type==Integer.class){

 
             //对带有指定参数的指定对象调用由此
Method
对象表示的底层方法对带有指定参数的指定对象调用由此
Method
对象表示的底层方法

                    m.invoke(instence,new Object[]{20});

                }

                if(type==String.class&&"address".equals(fieldName)){

                    m.invoke(instence,new Object[]{"常州"});

                }

                if(type==String.class&&"name".equals(fieldName)){

                    m.invoke(instence,new Object[]{"dcg"});

                }

            }

}


通过反射方式拷贝对象

public class CopyObject {

    public static void main(String args[]) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {

        persion p=new persion();

        p.setAddress("常州");

        p.setId(20);

        p.setName("dcg");

        Object object=copyObject(p);

        System.out.println(object);

    }

    public static Object copyObject(Object object) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {

        //获得传递过来的对象和构造器

        Class<? extends Object> clazz=object.getClass();

        //获取属性

        Field[] fields=clazz.getDeclaredFields();

        //获取默认构造器

        Constructor<? extends Object> constructor=clazz.getConstructor( new Class[]{});

        //创建一个对象

        Object instence=constructor.newInstance(new Object[]{});

        //遍历属性

        for(Field f:fields){

            //获取属性的name

            String fname=f.getName();

            //获取属性的类型

            //获取属性的类型

            Class<?>type=f.getType();

            //根据属性获取对象的set方法

            String setMthodName="set"+fname.substring(0,1).toUpperCase()+fname.substring(1);

            String getMethodName="get"+fname.substring(0,1).toUpperCase()+fname.substring(1);

            //获取get方法 并获得返回值

            Method gmethod=clazz.getDeclaredMethod(getMethodName,null);

            //调用get方法 获得被拷贝对象的一个属性值

            Object gresult=gmethod.invoke(object,null);

            //获得set方法

            Method smetnod=clazz.getDeclaredMethod(setMthodName,new Class[]{type});

            smetnod.invoke(instence,new Object[]{gresult});

        }

        return instence;

    }

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息