鲁春利的工作笔记,好记性不如烂笔头
反射机制
为了更好的理解java的反射机制,最好先对java的泛型有所了解。java泛型就是参数化类型,即为所操作的数据类型指定一个参数。如果只指定了<?>,而没有extends,则默认是允许Object及其下的任何Java类。
List<? extends Map<String, String>> list = null;
{
// 具体实现时限定了List所能add的数据类型
list = new ArrayList<Map<String, String>>();
}
{
// 具体实现时限定了List所能add的数据类型
list = new ArrayList<HashMap<String, String>>();
}
("list is {}", list);Java运行时,对任意一个类,想知道它有哪些属性和方法,对于任意一个对象,想调用它的任意一个方法,都是可以实现的,这来自JAVA的反射机制。
1、JAVA的反射机制主要功能:
a、在运行时判断任意一个对象所属的类。
b、在运行时构造任意一个类的对象。
c、在运行时判断任意一个类所具有的成员变量和方法。
d、在运行时调用任意一个对象的方法
前提是在运行时,不是编译时,也就是在运行前并不知道调用哪一个类,通过反射就可以做到这些。
2、在JDK中,主要由以下类来实现JAVA反射机制,这些类位于java.lang.reflect包中:
3、Class类是Reflection API 中的核心类
Class类是Reflection API 中的核心类。在类加载时,java虚拟机会自动创建相应的Class对象。
在java.lang.Object 类中定义了getClass()方法,因此对于任意一个Java对象,都可以通过此方法获得对象的类。
Class类的实例用于表示运行时的java数据类型,包括类、接口、数组、枚举、注解、基本数据类型甚至void等。
获得你想操作的类的 java.lang.Class 对象
针对引用数据类型:
调用静态方法:Class.forName();
Class.forName("p1.Person");
Class.forName("com.mysql.jdbc.Driver");调用Object类中定义的getClass()方法
Person person = new Person(); Class cs = p.getClass(); Class strClass = "Hello World".getClass();
使用.class表达式
Class strClass = String.class; Class personClass = p1.Person.class; Class jdbcClass = com.mysql.jdbc.Driver.class;
针对基本数据类型及void
使用.class表达式
Class intClass = int.class; Class dobClass = double.class; Class voidClass = void.class;
调用相应封装类的Type属性
Class IntegerClass = Integer.TYPE; Class voicClass = Void.TYPE;
【实例1】
读取命令行参数指定的类名,然后打印这个类所具有的方法信息。即JAVA的反射机制功能中的“在运行时判断任意一个类所具有的方法”
package com.invicme.tools.reflect;
import java.lang.reflect.Method;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.invicme.tools.utils.StringUtils;
/**
*
* @author lucl
* @version 2017-01-19
*
* 测试运行时获取类的实例及参数
*/
public class ReflectTest001 {
//
private static Logger logger = LoggerFactory.getLogger(ReflectTest001.class);
public static void main(String[] args) throws Exception {
if (null == args || args.length <= 0 || StringUtils.isBlank(args[0])) {
return;
}
// 加载并初始化命令行参数指定的类
Class<?> clazz = Class.forName(args[0]);
String className = clazz.getName();
("class name is {}", className);
// 获得类的所有方法
Method[] methods = clazz.getDeclaredMethods();
for (Method method : methods) {
("\tmethod is {}", method.toString());
}
}
}在命令行里输入参数,此处参数必须为类的全限定名
(1). Class.forName(args[0]) 传入的是类的全称,返回的是与这个类所对应的一个Class类的实例;
(2). Method methods[] = classType.getDeclaredMethods() 获得该类所有的方法,包括private的。
【实例2】
这个例子只能复制简单的JavaBean,假定JavaBean 的每个属性都有public 类型的getXXX()和setXXX()方法。体现了JAVA的反射机制中的“在运行时判断任意一个类所具有的属性”、“在运行时调用任意一个对象的方法”和“在运行时构造任意一个类的对象”
package com.invicme.tools.reflect;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.invicme.common.model.test.TestUserInfo;
import com.invicme.tools.utils.GUIDUtils;
/**
*
* @author lucl
* @version 2017-01-19
*
* 测试运行时获取对象的拷贝
*/
public class ReflectTest002 {
//
private static Logger logger = LoggerFactory.getLogger(ReflectTest002.class);
public Object copy (Object userInfo) throws Exception {
// 获得对象的类的类型
Class<? extends Object> clazz = userInfo.getClass();
("class name is {}", clazz.getName());
// {
// // 先调用Class类的getConstructor()方法获得一个Constructor对象
// Constructor<? extends Object> constructor = clazz.getConstructor(new Class[]{});
// // 它代表默认的构造方法,然后调用Constructor对象的newInstance()方法构造一个实例。
// Object newInstance = constructor.newInstance(new Object[]{});
// }
// 或者直接通过Class类的newInstance方法
Object newInstance = clazz.newInstance();
// 获得对象的所有属性
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
String fieldName = field.getName();
if ("serialVersionUID".equals(fieldName)) {
continue;
}
if (fieldName.startsWith("is")) {
continue;
}
String firstLetter = fieldName.substring(0, 1).toUpperCase();
// 获得和属性对应的getXXX()方法的名字
String getMethodName = "get" + firstLetter + fieldName.substring(1);
// 获得和属性对应的setXXX()方法的名字
String setMethodName = "set" + firstLetter + fieldName.substring(1);
// 获取源实例的数据
Object invoke = null;
{
Method method = clazz.getMethod(getMethodName, new Class[]{});
// 调用原对象的getXXX()方法
invoke = method.invoke(userInfo, new Object[]{});
("field name is {}, field value is {}, get method name is {}, set method name is {}", fieldName, invoke, getMethodName, setMethodName);
}
// 设置为新复制出来的实例
{
Method method = clazz.getMethod(setMethodName, new Class[]{field.getType()});
// 调用拷贝对象的setXXX()方法
method.invoke(newInstance, new Object[]{invoke});
}
}
return newInstance ;
}
public static void main(String[] args) throws Exception {
//
ReflectTest002 reflect = new ReflectTest002();
//
TestUserInfo userInfo = new TestUserInfo();
userInfo.setPkid(GUIDUtils.getGUID());
userInfo.setUserName("");
userInfo.setUserPwd("123456");
userInfo.setRealName("鲁春利");
("source user info is {}", userInfo);
//
Object objectCopy = reflect.copy(userInfo);
("copy user info is {}", objectCopy);
}
}打印该对象所属的类的名字 后打印出原对象中所有属性及对应值 最后打印出新建对象复制原对象后的属性及对应值
(1). 获得对象的类的类型 Class<?> classType = object.getClass();与Class.forName()是一样的结果,返回一个对象运行时的Class,这个Class描述了当前这个对象所具有的一些属性和方法,也就是内部的构造。getClass方法定义在Object类里面,也就是JAVA中任何一个类都有这个方法
(2). Object objectCopy = classType.getConstructor(new Class[] {}).newInstance(new Object[] {});这句话主要的目的是通过默认的构造方法创建一个该Class类的实例。通过Class实例调用getConstructor方法,可以获得当前对象的构造方法。参数是用来辨别返回哪个构造方法的,所以是Class类型数组,无参数表示返回默认构造方法。
newInstance方法,通过当前构造方法生成当前类的一个实例。
【实例3】
该类的main()方法中,运用反射机制调用一个ReflectTest003对象的add()和echo()方法。add()方法的两个参数为int 类型,获得表示add()方法的Method对象的代码如下:
Method method = clazz.getMethod("add", new Class[]{int.class, int.class});Method类的invoke(Object obj,Object args[])方法接收的参数必须为对象,如果参数为基本类型数据,必须转换为相应的包装类型的对象。
Method类的invoke()方法的返回值总是对象,如果实际被调用的方法的返回类型是基本类型数据,那么invoke()方法会把它转换为相应的包装类型的对象,再将其返回。
体现了JAVA的反射机制功能中的“在运行时获得任意一个类的方法”、“在运行时调用任意一个对象的方法”
package com.invicme.tools.reflect;
import java.lang.reflect.Method;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*
* @author lucl
* @version 2017-01-19
*
* 通过反射获取类的方法并调用
*
*/
public class ReflectTest003 {
//
private static Logger logger = LoggerFactory.getLogger(ReflectTest003.class);
public int add (int param1, int param2) {
return param1 + param2;
}
public String echo (String msg) {
return "echo : " + msg;
}
public static void main(String[] args) throws Exception {
// 获得类的类型
Class<? extends ReflectTest003> clazz = ReflectTest003.class;
// 生成实例
ReflectTest003 newInstance = clazz.newInstance();
// 调用ReflectTest003对象的add()方法
{
Method method = clazz.getMethod("add", new Class[]{int.class, int.class});
Object invoke = method.invoke(newInstance, new Object[]{1, 2});
("the add method result is {}", invoke);
}
// 调用ReflectTest003对象的echo()方法
{
Method method = clazz.getMethod("echo", new Class[]{String.class});
Object invoke = method.invoke(newInstance, new Object[]{"Hello"});
("the echo method result is \"{}\"", invoke);
}
}
}【实例4】
通过反射机制获取类的注解。
com.invicme.common.persistence.annotation.MyBatisDao
package com.invicme.common.persistence.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.stereotype.Component;
/**
* @author lucl
* @version 2013-8-28
*
* 标识MyBatis的DAO,方便{@link org.mybatis.spring.mapper.MapperScannerConfigurer}的扫描。
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Component
public @interface MyBatisDao {
/**
* The value may indicate a suggestion for a logical component name,
* to be turned into a Spring bean in case of an autodetected component.
* @return the suggested component name, if any
*/
String value() default "";
}com.invicme.tools.reflect.ReflectTest004
package com.invicme.tools.reflect;
import java.lang.annotation.Annotation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.invicme.common.persistence.annotation.MyBatisDao;
/**
*
* @author lucl
* @version 2017-01-19
*
* 获取类的注解
*
*/
@MyBatisDao(value="@MyBatisDao")
public class ReflectTest004 {
//
private static Logger logger = LoggerFactory.getLogger(ReflectTest004.class);
public static void main(String[] args) {
//
Class<? extends ReflectTest004> clazz = ReflectTest004.class;
MyBatisDao myBatisDao = clazz.getAnnotation(MyBatisDao.class);
String value = myBatisDao.value();
("annotation value is {}", value);
Class<? extends Annotation> annotationType = myBatisDao.annotationType();
("annotation type is {}", annotationType.getName());
Annotation[] annotations = annotationType.getAnnotations();
for (Annotation annotation : annotations) {
("sub annotation is {}", annotation.annotationType());
}
//
Class<?>[] interfaces = clazz.getInterfaces();
for (Class<?> interfacz : interfaces) {
("interface name is {}", interfacz.getName());
}
//
if (null != clazz.getComponentType()) {
("component type is {}", clazz.getComponentType().getName());
}
}
}【实例4】
通过Array操作数组
package com.invicme.tools.reflect;
import java.lang.reflect.Array;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.invicme.common.model.test.TestUserInfo;
/**
*
* @author lucl
* @version 2017-01-20
*
* 动态数组
*
*/
public class ReflectTest005 {
//
private static Logger logger = LoggerFactory.getLogger(ReflectTest005.class);
public static void main(String[] args) {
// 初始化数组
int[] records = { 1, 2, 3 };
TestUserInfo[] ps = {
new TestUserInfo("张三", "123456"),
new TestUserInfo("李四", "123456"),
new TestUserInfo("王五", "123456")
};
// 使用Array类来操作数组对象
records = (int[]) incrementArray(records);
ps = (TestUserInfo[]) incrementArray(ps);
// 打印扩容之后的数组内容
list(records);
list(ps);
}
/**
*
* @param array
* @return
*/
public static Object incrementArray(Object array) {
// 返回表示数组组件类型的 Class
Class<?> componentType = array.getClass().getComponentType();
// component type is int
// component type is class com.invicme.common.model.test.TestUserInfo
("component type is {}", componentType);
// 返回指定数组对象的长度
int size = Array.getLength(array);
// 新数组
Object newArray = Array.newInstance(componentType, size * 2);
// 创建一个具有指定的组件类型和长度的新数组。
for (int i = 0; i < size; i++) {
Object o = Array.get(array, i);// 返回指定数组对象中索引组件的值
Array.set(newArray, i, o);
// 将指定数组对象中索引组件的值设置为指定的新值。newArray中i位置的值设为o指定的值
}
// System.arraycopy(array, 0, newArray, 0, size);
return newArray;
}
/**
*
* @param array
*/
public static void list(Object array) {
int size = Array.getLength(array);
for (int i = 0; i < size; i++) {
("{} [ {} ]的 值是 {}", array.getClass().getName(), i, Array.get(array, i));
}
}
}























