在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反射是一个好东西,我们用它可以解决很多写死的东西,因为反射机制的灵活性很大,有了它我们就不用花太多的时间来写操作数据库的代码了,而是花更多的时间在项目的逻辑功能上,这样就可以很大程度的减少开发时间,而且代码的可读性会提高很多;