[置顶] java反射,让代码充满活力(一)

         在java编程的行当中,IT攻城狮们想必对反射这个字眼并不陌生,无论是我们想要在运行状态中获取任意一个类的所有属性或者方法,还是调用任意一个对象的方法和属性,甚至是修改它的某个属性和方法,我们都可以找java的反射机制来帮忙,让我们可以动态获取新和动态调用对象的方法,而这就是我们所熟悉的java的反射机制;

         在本篇博文中,主要分为java反射概述,反射的常用方法,反射的静态和动态代理,反射的实例应用和反射的总结这几部分,那小编先来给大家概述一下反射的功能:

♚  反射概述

         反射是用来获取正在运行的java对象,

♚  反射机制的功能

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

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

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

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

   生成动态代理。

♚    实现java反射的类

     1)Class:它表示正在运行的Java应用程序中的类和接口 

     2)Field:提供有关类或接口的属性信息,以及对它的动态访问权限

     3)Constructor:提供关于类的单个构造方法的信息以及对它的访问权限 

     4)Method:提供关于类或接口中某个方法信息

♚   常用方法的案例

          

【案例一获取完整的包名和类名====》getName()

<span style="font-size:18px;">package Reflect;
 
/**
 * 通过一个对象获得完整的包名和类名
 * */
class Demo{
    //other codes...
}
 
class hello{
    public static void main(String[] args) {
        Demo demo=new Demo();
        System.out.println(demo.getClass().getName());
    }
}</span>

  【案例二】实例化class对象 ===》forName()

<span style="font-size:18px;">package Reflect;
class Demo{
    //other codes...
}
 
class hello{
    public static void main(String[] args) {
        Class<?> demo1=null;
        Class<?> demo2=null;
        Class<?> demo3=null;
        try{
            //一般尽量采用这种形式
            demo1=Class.forName("Reflect.Demo");
        }catch(Exception e){
            e.printStackTrace();
        }
        demo2=new Demo().getClass();
        demo3=Demo.class;
         
        System.out.println("类名称   "+demo1.getName());
        System.out.println("类名称   "+demo2.getName());
        System.out.println("类名称   "+demo3.getName());
         
    }
}</span>

  【案例三】通过class调用其他类的构造函数 ===》getConstructors

<span style="font-size:18px;">package Reflect;
 
import java.lang.reflect.Constructor;
 
class Person{
     //无参数的构造函数
    public Person() {
         
    }
  //构造函数的重载
    public Person(String name){
        this.name=name;
    }
    public Person(int age){
        this.age=age;
    }
    public Person(String name, int age) {
        this.age=age;
        this.name=name;
    }
  //实体中各个属性的get
    public String getName() {
        return name;
    }
    public int getAge() {
        return age;
    }

  //重写toString方法
    @Override
    public String toString(){
        return "["+this.name+"  "+this.age+"]";
    }
    private String name;
    private int age;
}
 
//重新定义一个类,用来获取Person类中的构造函数
class hello{
    public static void main(String[] args) {
        Class<?> demo=null;
        try{
            demo=Class.forName("Reflect.Person");
        }catch (Exception e) {
            e.printStackTrace();
        }
        Person per1=null;
        Person per2=null;
        Person per3=null;
        Person per4=null;
        //取得全部的构造函数
        Constructor<?> cons[]=demo.getConstructors();
        try{
            per1=(Person)cons[0].newInstance();
            per2=(Person)cons[1].newInstance("Rollen");
            per3=(Person)cons[2].newInstance(20);
            per4=(Person)cons[3].newInstance("Rollen",20);
        }catch(Exception e){
            e.printStackTrace();
        }
        System.out.println(per1);
        System.out.println(per2);
        System.out.println(per3);
        System.out.println(per4);
    }
}</span>

 【案例四】 获取其他类的父类

<span style="font-size:18px;">class  Person{
	代码同上
}

class hello{
    public static void main(String[] args) {
        Class<?> demo=null;
        try{
            demo=Class.forName("Reflect.Person");
        }catch (Exception e) {
            e.printStackTrace();
        }
        //取得父类
        Class<?> temp=demo.getSuperclass();
        System.out.println("继承的父类为:   "+temp.getName());
    }
}</span>

   【案例五】获取其他类的全部属性 ===》getDeclaredFields()

<span style="font-size:18px;">class hello {
    public static void main(String[] args) {
        Class<?> demo = null;
        try {
            demo = Class.forName("Reflect.Person");
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("===============本类属性========================");
        // 取得本类的全部属性
        Field[] field = demo.getDeclaredFields();
        for (int i = 0; i < field.length; i++) {
            // 权限修饰符
            int mo = field[i].getModifiers();
            String priv = Modifier.toString(mo);
            // 属性类型
            Class<?> type = field[i].getType();
            System.out.println(priv + " " + type.getName() + " "
                    + field[i].getName() + ";");
        }
        System.out.println("===============实现的接口或者父类的属性========================");
        // 取得实现的接口或者父类的属性
        Field[] filed1 = demo.getFields();
        for (int j = 0; j < filed1.length; j++) {
            // 权限修饰符
            int mo = filed1[j].getModifiers();
            String priv = Modifier.toString(mo);
            // 属性类型
            Class<?> type = filed1[j].getType();
            System.out.println(priv + " " + type.getName() + " "
                    + filed1[j].getName() + ";");
        }
    }
}<strong>
</strong></span>

  【案例六】 获取类的指定属性并修改 

<span style="font-size:18px;">public static void main(String[] args) throws Exception{
	
           //以前的方式:
	//User u = new User();
	//u.age = 12; //set
	//System.out.println(u.age); //get
	
		
	//获取类
	Class c = Class.forName("User");
	//获取id属性
	Field idF = c.getDeclaredField("id");
	//实例化这个类赋给o
	Object o = c.newInstance();
	//打破封装
	idF.setAccessible(true); //使用反射机制可以打破封装性,导致了java对象的属性不安全。
	//给o对象的id属性赋值"110"
	idF.set(o, "110"); //set
	//get
	System.out.println(idF.get(o));
}
</span>

       可能大家比较疑惑,反射不是用来获取的嘛,但是反射还有修改制定属性的一个功能,就是上述代码中的setAccessible(true) ,这样我们就通过反射机制打破原有的封装性,但是这个方法的应用会导致java对象的属性不安全,所以我们需要慎重使用;

  【案例七】获取并修改数组的信息

<span style="font-size:18px;">import java.lang.reflect.*;
class hello{
    public static void main(String[] args) {
        int[] temp={1,2,3,4,5};
        Class<?>demo=temp.getClass().getComponentType();
        System.out.println("数组类型: "+demo.getName());
        System.out.println("数组长度  "+Array.getLength(temp));
        System.out.println("数组的第一个元素: "+Array.get(temp, 0));
        Array.set(temp, 0, 100);
        System.out.println("修改之后数组第一个元素为: "+Array.get(temp, 0));
    }
}</span>

  【案例八】修改数组的大小

<span style="font-size:18px;">class hello{
    public static void main(String[] args) {
        int[] temp={1,2,3,4,5,6,7,8,9};
        int[] newTemp=(int[])arrayInc(temp,15);
        print(newTemp);
        System.out.println("=====================");
        String[] atr={"a","b","c"};
        String[] str1=(String[])arrayInc(atr,8);
        print(str1);
    }
     
    /**
     * 修改数组大小
     * */
    public static Object arrayInc(Object obj,int len){
        Class<?>arr=obj.getClass().getComponentType();
        Object newArr=Array.newInstance(arr, len);
        int co=Array.getLength(obj);
        System.arraycopy(obj, 0, newArr, 0, co);
        return newArr;
    }
    /**
     * 打印
     * */
    public static void print(Object obj){
        Class<?>c=obj.getClass();
        if(!c.isArray()){
            return;
        }
        System.out.println("数组长度为: "+Array.getLength(obj));
        for (int i = 0; i < Array.getLength(obj); i++) {
            System.out.print(Array.get(obj, i)+" ");
        }
    }
}</span>
      这里由于篇幅原因,反射+工厂来操作数据库的例子将在下篇博文中进行分享; 

♚   总结

          每一个事物都有优点和缺点两面,那么在java中动态获取信息的反射又有怎么样的优缺点呢,咱们一起来看:

  ✎  优点:

        一句话概括:反射机制的优点是可以实现动态创建对象和编译,体现出很大的灵活性,特别是在j2ee的开发中,它的灵活性体现的十分明显。比如,一个大型的软件,不可能一次就把它设计的很完美,当这个程序编译后,发布了,当发现需要更新某些功能时,我们不可能将原有版本卸载,再安装新版本。
        静态编译:在编译时确定类型,绑定对象,即通过;
        动态编译:运行时确定类型,绑定对象,最大限度的发挥了java的灵活性,体现了多态的应用,用于降低类之间的耦合性;
       但是采取静态的话,我们就需要将整个程序重新编译一次,才可以实现功能的更新,但是如果采用反射机制的话,程序就不需要卸载,只需要在运行时菜动态的创建和编译,我们就可以实现功能的更新;

  ✎   缺点

       对性能有影响;使用反射是一种解释操作,我们可以告诉jvm:我们希望它帮我们做什么,并且它会满足我们的需求,但是这类操作总会慢于我们直接执行操作;
  
      虽然反射会对性能有影响,但是总的来说,java反射是一个好东西,我们用它可以解决很多写死的东西,因为反射机制的灵活性很大,有了它我们就不用花太多的时间来写操作数据库的代码了,而是花更多的时间在项目的逻辑功能上,这样就可以很大程度的减少开发时间,而且代码的可读性会提高很多; 
     

你可能感兴趣的:(java,java基础,反射)