1、先看一下反射的概念:java
主要是指程序能够访问,检测和修改它自己状态或行为的一种能力,并能根据自身行为的状态和结果,调整或修改应用所描述行为的状态和相关的语义。数据库
反射是java中一种强大的工具,可以使咱们很方便的建立灵活的代码,这些代码能够再运行时装配,无需在组件之间进行源代码连接。可是反射使用不当会成本很高!数组
2、反射机制的做用:安全
1,反编译:.class-->.javaapp
2,经过反射机制访问java对象的属性,方法,构造方法等;工具
3、在这里先看一下sun为咱们提供了那些反射机制中的类:性能
java.lang.Class; 学习
java.lang.reflect.Constructor; java.lang.reflect.Field; this
java.lang.reflect.Method;spa
java.lang.reflect.Modifier;
4、具体功能实现:
一、反射机制获取类有三种方法,咱们来获取Employee类型
//第一种方式: Classc1 = Class.forName("Employee"); //第二种方式: //java中每一个类型都有class 属性. Classc2 = Employee.class; //第三种方式: //java语言中任何一个java对象都有getClass 方法 Employeee = new Employee(); Classc3 = e.getClass(); //c3是运行时类 (e的运行时类是Employee)
二、建立对象:获取类之后咱们来建立它的对象,利用newInstance:
Class c =Class.forName("Employee"); //建立此Class 对象所表示的类的一个新实例 Objecto = c.newInstance(); //调用了Employee的无参数构造方法.
3,获取属性:分为全部的属性和指定的属性:
a,先看获取全部的属性的写法:
//获取整个类 Class c = Class.forName("java.lang.Integer"); //获取全部的属性? //定义可变长的字符串,用来存储属性 StringBuffer sb = new StringBuffer(); //经过追加的方法,将每一个属性拼接到此字符串中 //最外边的public定义 sb.append(Modifier.toString(c.getModifiers()) + " class " + c.getSimpleName() +"{\n"); //里边的每个属性 for(Field field:fs){ sb.append("\t");//空格 sb.append(Modifier.toString(field.getModifiers())+" ");//得到属性的修饰符,例如public,static等等 sb.append(field.getType().getSimpleName() + " ");//属性的类型的名字 sb.append(field.getName()+";\n");//属性的名字+回车 } sb.append("}"); System.out.println(sb);
b,获取特定的属性,对比着传统的方法来学习:
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)); }
4,获取方法,和构造方法,再也不详细描述,只来看一下关键字:
getDeclaredMethods() | 获取全部的方法 |
getReturnType() | 得到方法的返回类型 |
getParameterTypes() | 得到方法的传入参数类型 |
getDeclaredMethod("方法名",参数类型.class,……) | 得到特定的方法 |
getDeclaredConstructors() | 获取全部的构造方法 |
getDeclaredConstructor(参数类型.class,……) | 获取特定的构造方法 |
getSuperclass() | 获取某类的父类 |
getInterfaces() | 获取某类实现的接口 |
这样咱们就能够得到类的各类内容,进行了反编译。对于JAVA这种先编译再运行的语言来讲,反射机制可使代码更加灵活,更加容易实现面向对象。
五,反射加配置文件,使咱们的程序更加灵活:
assembly.load("当前程序集的名称").CreateInstance("当前命名空间名称".要实例化的类名);
这样的好处是很容易的方便咱们变换数据库,例如咱们将系统的数据库从SQL Server升级到Oracle,那么咱们写两份D层,在配置文件的内容改一下,或者加条件选择一下便可,带来了很大的方便。
固然了,JAVA中其实也是同样,只不过这里的配置文件为.properties,称做属性文件。经过反射读取里边的内容。这样代码是固定的,可是配置文件的内容咱们能够改,这样使咱们的代码灵活了不少!
综上为,JAVA反射的再次学习,灵活的运用它,可以使咱们的代码更加灵活,可是它也有它的缺点,就是运用它会使咱们的软件的性能下降,复杂度增长,因此还要咱们慎重的使用它。
下面是引用的一篇文章:
Java反射在咱们Java学习的过程当中是很是重要的知识点。可能有些同窗认为这个学习起来不容易理解,其实就我我的而言仍是比较简单,学习起来也比较容易理解。下面我给你们总结一下Java反射学习的要点,同时给出几个比较好的例子。
一、Java反射的概念
反射含义:能够获取正在运行的Java对象。
二、Java反射的功能
1)能够判断运行时对象所属的类
2)能够判断运行时对象所具备的成员变量和方法
3)经过反射甚至能够调用到private的方法
4)生成动态代理
三、实现Java反射的类
1)Class:它表示正在运行的Java应用程序中的类和接口
2)Field:提供有关类或接口的属性信息,以及对它的动态访问权限
3)Constructor:提供关于类的单个构造方法的信息以及对它的访问权限
4)Method:提供关于类或接口中某个方法信息
注意:Class类是Java反射中最重要的一个功能类,全部获取对象的信息(包括:方法/属性/构造方法/访问权限)都须要它来实现
四、编写Java反射程序的步骤:
1)必须首先获取一个类的Class对象
例如:
Class c1 = Test.class;
Class c2 = Class.forName(“com.reflection.Test”);
Class c3 = new Test().getClass();
2)而后分别调用Class对象中的方法来获取一个类的属性/方法/构造方法的结构
注意:若是要可以正常的获取类中方法/属性/构造方法应该重点掌握以下的反射类
Field
Constructor
Method
示例:此程序例子告诉你们如何操做Class/Field/Constructor/Method等与Java反射相关的类
package com.reflection; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; public class TestReflection { private String username; private String password; private int[] age; public TestReflection(String username, String password, int[] age) { super(); this.username = username; this.password = password; this.age = age; } public TestReflection() { username = "李白"; password = "123"; age = new int[]{10,11,12}; } public void setUserName(String username) { this.username = username; } private void setPassWord(String password) { this.password = password; } public static void test01() throws ClassNotFoundException { //使用三种方法均可以经过反射来获取类对象Class Class c1 = TestReflection.class; Class c2 = Class.forName("com.reflection.TestReflection"); Class c3 = new TestReflection().getClass(); // 获取指定的包名 String package01 = c1.getPackage().getName(); String package02 = c2.getPackage().getName(); String package03 = c3.getPackage().getName(); System.out.println("package01 = " + package01); System.out.println("package02 = " + package02); System.out.println("package03 = " + package03); // 获取类的修饰符 int mod = c1.getModifiers(); String modifier = Modifier.toString(mod); System.out.println("modifier = " + modifier); // 获取指定类的彻底限定名 String className = c1.getName(); System.out.println("className = " + className); // 获取指定类的父类 Class superClazz = c1.getSuperclass(); String superClazzName = superClazz.getName(); System.out.println("superClazzName = " + superClazzName); // 获取实现的接口 Class[] interfaces = c1.getInterfaces(); for (Class t : interfaces) { System.out.println("interfacesName = " + t.getName()); } // 获取指定类的成员变量 Field[] fields = c1.getDeclaredFields(); for (Field field : fields) { modifier = Modifier.toString(field.getModifiers()); // 获取每一个字段的访问修饰符 Class type = field.getType(); // 获取字段的数据类型所对应的Class对象 String name = field.getName(); // 获取字段名 if (type.isArray()) { // 若是是数组类型则须要特别处理 Class tt = type.getComponentType(); //getComponentType()方法返回一个Class对象,表示数组的成员类型。若是该类不表示数组类,方法返回null.而后经过getName方法获取数组元素类型 String arrType = type.getComponentType().getName() + "[]";//arrType 为 int[] System.out.println("" + modifier + " " + arrType + " " + name + ";"); } else { System.out.println("" + modifier + " " + type + " " + name + ";"); } } // 获取类的构造方法 Constructor[] constructors = c1.getDeclaredConstructors(); for (Constructor constructor : constructors) { String name = constructor.getName(); // 构造方法名 modifier = Modifier.toString(constructor.getModifiers()); // 获取访问修饰符 System.out.println("" + modifier + " " + name + "("); Class[] paramTypes = constructor.getParameterTypes(); // 获取构造方法中的参数 for (int i = 0; i < paramTypes.length; i++) { if (i > 0) { System.out.print(","); } if (paramTypes[i].isArray()) { System.out.println(paramTypes[i].getComponentType().getName() + "[]"); } else { System.out.print(paramTypes[i].getName()); } } System.out.println(");"); } // 获取成员方法 Method[] methods = c1.getDeclaredMethods(); for (Method method : methods) { modifier = Modifier.toString(method.getModifiers()); Class returnType = method.getReturnType(); // 获取方法的返回类型 if (returnType.isArray()) { String arrType = returnType.getComponentType().getName() + "[]"; System.out.print("" + modifier + " " + arrType + " " + method.getName() + "("); } else { System.out.print("" + modifier + " " + returnType.getName() + " " + method.getName() + "("); } Class[] paramTypes = method.getParameterTypes(); for (int i = 0; i < paramTypes.length; i++) { if (i > 0) { System.out.print(","); } if (paramTypes[i].isArray()) { System.out.println(paramTypes[i].getComponentType() .getName() + "[]"); } else { System.out.print(paramTypes[i].getName()); } } System.out.println(");"); } } public static void test02() throws InstantiationException, IllegalAccessException, SecurityException, NoSuchMethodException, IllegalArgumentException, InvocationTargetException { // 反射调用方法,能够经过Method类的invoke方法实现动态方法的调用 // public Object invoke(Object obj, Object... args) //该方法中有多个参数:method.invoke(o, new Object[] {参数1,参数2...}); // 第一个参数表明对象 // 第二个参数表明执行方法上的参数 // 若反射要调用类的某个私有方法,能够在这个私有方法对应的Mehtod对象上先调用setAccessible(true) Class c1 = TestReflection.class; TestReflection t1 = (TestReflection) c1.newInstance(); // 利用反射调用无参的构造方法来建立类的对象 System.out.println("username == " + t1.username); System.out.println("password == " + t1.password); //得到名称setUserName的方法public void com.reflection.TestReflection.setUserName(java.lang.String),参数为String类型 Method method = c1.getDeclaredMethod("setUserName", String.class); method.invoke(t1, "Java反射的学习");//传入参数为字符串("Java反射的学习"),来调用类中的setUserName方法,此时已经改变实例t1的username的属性值 System.out.println("username == " + t1.username); //调用私有方法private void com.reflection.TestReflection.setPassWord(java.lang.String),参数为String类型 method = c1.getDeclaredMethod("setPassWord", String.class); //设置对私有方法的可操做权限 method.setAccessible(true); method.invoke(t1, "反射执行某个Private修饰的方法"); System.out.println("password == " + t1.password); } public static void main(String[] args) throws ClassNotFoundException, SecurityException, IllegalArgumentException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException { // test01(); test02(); } } class Sum{ public static void main(String[] args) { int vec[] = new int[]{1, 5, 3}; // 第一种方法 int vec1[] = {37,47,23} ; // 第二种方法 int vec2[] = new int [3];//指定数组的元素个数 for(int i=0;i<3;i++){ vec[i]=i+1; //第三种方法 } } }
再给与个实例:
package org.cqut.java.reflection; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; public class CopyObject { public Object copyObject(Object object) throws Exception { // 1.获取待操做类的一个Class对象 Class<?> classType = object.getClass(); // 2.获取待操做类的一个实例 Constructor<?> constructor = classType .getConstructor(new Class<?>[] {}); Object copyObj = constructor.newInstance(new Object[] {}); // 3.获取被拷贝类的成员变量 Field[] fields = classType.getDeclaredFields(); for (Field field : fields) { // 4.遍历数组获取各个成员变量名字 String name = field.getName();// 获取成员变量名字; // 5.操做字符串获取成员变量的set和get方法名字; String firstLetter = name.substring(0, 1).toUpperCase(); String getMethodName = "get" + firstLetter + name.substring(1); String setMethodName = "set" + firstLetter + name.substring(1); Method getMethod = classType.getMethod(getMethodName, new Class<?>[] {}); Method seMethod = classType.getMethod(setMethodName, new Class<?>[] { field.getType() }); /*最开始认为如下两个invoke方法的第一和参数都应该调用copyObj, * 可是最终的结果为输出为默认的空值。 * copyObj:程序前面经过Constructor类的newInstance方法 * 获取待操做类的一个实例; //Object value = getMethod.invoke(copyObj, new Object[] {}); //seMethod.invoke(copyObj, new Object[] { value }); /*如今改用以下方式了,输出就正常了 * 因此产生疑惑:为何第一个方法调用的object对象而不是copyObj呢? * */ Object value = getMethod.invoke(object, new Object[] {}); seMethod.invoke(copyObj, new Object[] { value }); } return copyObj; } public static void main(String[] args) throws Exception { Student student = new Student("Tom", 21); student.setId(111030805); CopyObject copy = new CopyObject(); Student student2 = (Student) copy.copyObject(student); System.out.println(student2.getId() + " " + student2.getName() + " " + student2.getAge()); } } // 一个被反射的JavaBean class Student { private long id; private String name; private int age; public Student() { } public Student(String name, int age) { this.name = name; this.age = age; } 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 long getId() { return id; } public void setId(long id) { this.id = id; } }
对于利用object给copyObj赋值的invoke的解惑:
Object value = getMethod.invoke(object, new Object[] {}); seMethod.invoke(copyObj, new Object[] { value }); 这两句代码的做用以下, 第一句,获取object中的值。 第二句,将该值设置到copyObj中。 这样才能完成赋值。 若是按你所说 //Object value = getMethod.invoke(copyObj, new Object[] {}); //seMethod.invoke(copyObj, new Object[] { value }); 那就是讲从copyObj获取的值,赋值给copyObj,这样作根本毫无心义。 for (Field field : fields) { String name = field.getName(); field.setAccessible(true); Object value = field.get(object); field.set(copyObj, value); } for循环里这样写,就成功的将object中的值赋值到了copyObj中。