java反射详解
来源:互联网 发布:溺水 该去救人吗 知乎 编辑:程序博客网 时间:2024/05/22 16:02
反射是JDK5.0提供的java新特性,反射的出现打破了java一些常规的规则,如,私有变量不可访问。
反射机制指的是程序在运行时能够获取自身的信息。
在java中,只要给定类的名字, 那么就可以通过反射机制来获得类的所有信息。
一般而言,开发者社群说到动态语言,大致认同的一个定义是:“程序运行时,允许改变程序结构或变量类型,这种语言称为动态语言”尽管在这样的定义与分类下Java不是动态语言,它却有着一个非常突出的动态相关机制:Reflection。这个字的意思是“反射、映象、倒影”,用在Java身上指的是我们可以于运行时加载、探知、使用编译期间完全未知的classes。换句话说,Java程序可以加载一个运行时才得知名称的class,获悉其完整构造(但不包括methods定义),并生成其对象实体、或对其fields设值、或唤起其methods。这种“看透class”的能力(the ability of the program to examine itself)被称为introspection(内省、内观、反省)。Reflection和introspection是常被并提的两个术语
API简介
在JDK中,主要由以下类来实现Java反射机制,这些类都位于java.lang.reflect包中
–Class类:代表一个类。
–Field 类:代表类的成员变量(成员变量也称为类的属性)。
–Method类:代表类的方法。
–Constructor 类:代表类的构造方法。
–Array类:提供了动态创建数组,以及访问数组的元素的静态方法
在java.lang.Object类中定义了getClass()方法,因此对于任意一个Java对象,都可以通过此方法获得对象的类型。
Class类是Reflection API 中的核心类,它有以下方法
–getName():获得类的完整名字。
–getFields():获得类的public类型的属性。
–getDeclaredFields():获得类的所有属性。
–getMethods():获得类的public类型的方法。
–getDeclaredMethods():获得类的所有方法。
-getMethod(String name, Class[] parameterTypes):获得类的特定方法,name参数指定方法的名字,parameterTypes参数指定方法的参数类型。
-getConstructors():获得类的public类型的构造方法。
-getConstructor(Class[] parameterTypes):获得类的特定构造方法,parameterTypes参数指定构造方法的参数类型。
通过类的不带参数的构造方法创建这个类的一个对象
-newInstance():通过类的不带参数的构造方法创建这个类的一个对象。
通过默认构造方法创建一个新对象:
-Object objectCopy=classType.getConstructor(new Class[]{}).newInstance(new Object[]{});
以上代码先调用Class类的getConstructor()方法获得一个Constructor 对象,它代表默认的构造方法,然后调用Constructor对象的newInstance()方法构造一个实例。
获得对象的所有属性:
-Field fields[]=classType.getDeclaredFields();
-Class 类的getDeclaredFields()方法返回类的所有属性,包括public、protected、默认和private访问级别的属性
Method类的invoke(Object obj,Object args[])方法接收的参数必须为对象:
如果参数为基本类型数据,必须转换为相应的包装类型的对象。invoke()方法的返回值总是对象,如果实际被调用的方法的返回类型是基本类型数据,那么invoke()方法会把它转换为相应的包装类型的对象,再将其返回
Java中,无论生成某个类的多少个对象,这些对象都会对应于同一个Class对象:
要想使用反射,首先需要获得待处理类或对象所对应的Class对象。
获取某个类或某个对象所对应的Class对象的常用的3种方式:
a) 使用Class类的静态方法forName:Class.forName(“java.lang.String”);
b) 使用类的.class语法:String.class;
c) 使用对象的getClass()方法:String s = “aa”; Class<?> clazz = s.getClass();
下面写一个程序来用一下这些API吧:
//获得MethodInvoke类对应的一个clas对象
Class<?> MethodInvok=MethodInvoke.class;
//获得一个MethodInvoke类对应的对象实例
Object MethodInvo=MethodInvok.newInstance();
//获得MethodInvo对象对应的add方法对应的一个对象实例
1):Method method=MethodInvok.getMethod("add", int.class,int.class);
//调用MethodInvo对象对应的add方法对应的一个对象(MethodInvo)实例所代表的方法,并获得结果
2)Object result= method.invoke(MethodInvo, 1,2);
System.out.println(result);
System.out.println("--------------------------------------");
Method method1=MethodInvok.getMethod("print",String.class);
Object Result1=method1.invoke(MethodInvo, "tom");
System.out.println(Result1);
注:1)处的int.class,int.class可以写为new Class[]{int.class,int.class}
原因在于getMethod方法的第二个参数是一个可变参数。
2)处的1,2可以写为new int【】{1,2},原因如1);
4.若想通过类的不带参数的构造方法来生成对象,我们有两种方式:
a) 先获得Class对象,然后通过该Class对象的newInstance()方法直接生成即可:
Class<?> classType = String.class;
Object obj = classType.newInstance();
b) 先获得Class对象,然后通过该对象获得对应的Constructor对象,再通过该Constructor对象的newInstance()方法生成:
Class<?> classType = Customer.class;
Constructor cons = classType.getConstructor(new Class[]{});
Object obj = cons.newInstance(new Object[]{});
注:
4. 若想通过类的带参数的构造方法生成对象,只能使用下面这一种通过构造器对象的方式:
Class<?> classType = Customer.class;
Constructor cons = classType.getConstructor(new Class[]{String.class, int.class});
Object obj = cons.newInstance(new Object[]{“hello”, 3});
代码示例:
// 该方法实现对Customer对象的拷贝操作
public Object copy(Object object) throws Exception
{
Class<?> classType = object.getClass();
//先调用Class类的getConstructor()方法获得一个Constructor 对象,它代表默认的构造方法,然后调用
Constructor对象的newInstance()方法构造一个实例。
Object objectCopy = classType.getConstructor(new Class[] {})
.newInstance(new Object[] {});
// Class 类的getDeclaredFields()方法返回类的所有属性,包括public、protected、默
认和private访问级别的属性
Field[] fields = classType.getDeclaredFields();
for (Field field : fields)
{
String name = field.getName();
// 将属性的首字母转换为大写
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 setMethod = classType.getMethod(setMethodName,
new Class[] { field.getType() });
Object value = getMethod.invoke(object, new Object[] {});
setMethod.invoke(objectCopy, new Object[] { value });
}
// 以上两行代码等价于下面一行
// Object obj2 = classType.newInstance();
// System.out.println(obj);
return objectCopy;
}
5.Integer.TYPE返回的是int,而Integer.class返回的是Integer类所对应的Class对象。
java.lang.Array 类提供了动态创建和访问数组元素的各种静态方法
一维数组的简单创建,设值,取值
Object array = Array.newInstance(classType, 10);
Array.set(array, 5, "hello");
String str = (String)Array.get(array, 5);
二维数组的简单创建,设值,取值
//创建一个设值数组维度的数组
int[] dims = new int[] { 5, 10, 15 };
//利用Array.newInstance创建一个数组对象,第一个参数指定数组的类型,第
二个参数设值数组的维度,下面是创建一个长宽高为:5,10,15的三维数组
Object array = Array.newInstance(Integer.TYPE, dims);
System.out.println(array instanceof int[][][]);
//获取三维数组的索引为3的一个二维数组
Object arrayObj = Array.get(array, 3);
//获取二维数组的索引为5的一个一维数组
arrayObj = Array.get(arrayObj, 5);
//设值一维数组arrayObj下标为10的值设为37
Array.setInt(arrayObj, 10, 37);
int[][][] arrayCast = (int[][][]) array;
System.out.println(arrayCast[3][5][10]);
利用反射访问类的私有方法:
代码示例:
Private p = new Private();
Class<?> classType = p.getClass();
Method method = classType.getDeclaredMethod("sayHello",
new Class[] { String.class });
method.setAccessible(true);//压制Java的访问控制检查,使允许访问private方法
String str = (String)method.invoke(p, new Object[]{"zhangsan"});
System.out.println(str);
利用反射访问类的私有变量:
Private2 p = new Private2();
Class<?> classType = p.getClass();
Field field = classType.getDeclaredField("name");
field.setAccessible(true);//压制Java对访问修饰符的检查
field.set(p, "lisi");
System.out.println(p.getName());
---------------------------------------
反射的使用:
1.获得一个类的类模版
Class c = 对象名.getClass();
Class c = Class.forName(包名+类名); ---常用
我们也可以根据模版来获取其对应的类对象:
c.newInstance();
2.根据类模版获取类的信息:
获取类的属性:
Filed类----c.getFiled(String pname) 获得指定属
性(公共字段)
Filed类----c.getDeclearedFiled(String pname)
获得指定属性(所有权限字段)
Filed[]----c.getFileds(String pname) 获得所有属
性(公共字段)
Filed[]----c.getDeclearedFileds(String pname)
获得所有属性(所有权限字段)
获取类的方法:
Method类----c.getMethod(String
methodName,class[] params) 获得指定方法(公共方法)
Method类----c.getDeclearedMethod(String
methodName,class[] params) 获得指定方法(所有方法)
Method[]----c.getMethods(String
methodName,class[] params) 获得所有方法(公共方法)
Method[]----c.getDeclearedMethods(String
methodName,class[] params) 获得所有方法(所有权限方法)
反射的优点:
其实就一句话:高类聚低耦合。把代码动态化,提高了代码的灵活度减少了代码量!Java 反射是Java语言的一个很重要的特征,它使得Java具体了“动态性”。
反射的缺点:
代码灵活度增大了,自然会带来效率的问题,因此,大量使用反射会带来效率低的问题!
那些地方用到反射:
可以在配置文件里配置类名,然后在程序中动态的加载加载配置文件中指定的类并调用其方法,调方法之前还可以先检查这个人有没有这个权限,在Spring Hibernate transaction的处理以及面向切面的编程AOP中都大量用到了反射机制,hibernate、struts都是用反射机制实现的。
反射提供的主要功能:
Java 反射机制主要提供了以下功能:
在运行时判断任意一个对象所属的类。
在运行时构造任意一个类的对象。
在运行时判断任意一个类所具有的成员变量和方法。
在运行时调用任意一个对象的方法。
用反射机制实现对数据库数据的增、查例子 :
http://www.cnblogs.com/jqyp/archive/2012/03/29/2423112.html
- java反射机制详解!
- java 反射机制详解
- JAVA反射详解
- JAVA反射机制详解
- java反射机制详解
- java反射详解
- Java反射机制详解
- Java反射机制详解
- java反射机制详解
- java反射详解
- Java反射机制详解
- java反射详解
- Java反射机制详解
- JAVA反射详解
- java反射详解
- java反射详解
- java反射详解
- java反射详解
- JAVA中常用英文单词简写释义)
- 增强型for循环的优点与缺点
- Java对象排序的3种实现方法
- java中Collection与Collections的区别
- volatile关键字的用法
- java反射详解
- 【转载】logic标签使用
- Java动态代理的实现详解
- Java设计模式(一)设计模式遵循的七大原则
- java设计模式(二)设计模式分类和三种工厂模式
- Java设计模式(四)策略模式
- java设计模式(五)创建者模式和原型模式
- java设计模式(六)观察者模式
- java设计模式(七)代理模式和java动态代理机制