Java反射探索研究(转)
林炳文Evankaka原创作品。转载请注明出处http://blog.csdn.net/evankakay
摘要:本文详细深入讲解是Java中反射的机制,并介绍了如何通过反射来生成对象、调用函数、取得字段、设置字段的方法。最后,给出了一些反射常用到的实例。
一、反射
(1)概念
反射含义:可以获取正在运行的Java对象。
(2)功能
1)在运行时判断任意一个对象所属的类
2)在运行时构造任意一个类的对象
3) 在运行时判断任意一个类所具有的成员变量和方法
4)在运行时调用任意一个对象的方法
(3)实现Java反射的类
1)Class:它表示正在运行的Java应用程序中的类和接口
2)Field:提供有关类或接口的属性信息,以及对它的动态访问权限
3)Constructor:提供关于类的单个构造方法的信息以及对它的访问权限
4)Method:提供关于类或接口中某个方法信息
注意:Class类是Java反射中最重要的一个功能类,所有获取对象的信息(包括:方法/属性/构造方法/访问权限)都需要它来实现
(4)取得class的三种方法
- Dog dog = new Dog();
- Class<?> dogClass = dog.getClass();
- Class<?> dogClass1 = Dog.class;
- Class<?> dogClass2 = Class.forName("com.lin.Dog");//注意要添加异常抛出
(5)关键方法
方法关键字 |
含义 |
getDeclaredMethods() |
获取所有的方法 |
getReturnType() |
获得方法的放回类型 |
getParameterTypes() |
获得方法的传入参数类型 |
getDeclaredMethod("方法名",参数类型.class,……) |
获得特定的方法 |
构造方法关键字 |
含义 |
getDeclaredConstructors() |
获取所有的构造方法 |
getDeclaredConstructor(参数类型.class,……) |
获取特定的构造方法 |
父类和父接口 |
含义 |
getSuperclass() |
获取某类的父类 |
getInterfaces() |
获取某类实现的接口 |
(6)一些区别函数
public Method[] getMethods()返回某个类的所有公用(public)方法包括其继承类的公用方法,当然也包括它所实现接口的方法。
public Method[] getDeclaredMethods()对象表示的类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。当然也包括它所实现接口的方法。
getFields()获得某个类的所有的公共(public)的字段,包括父类。
getDeclaredFields()获得某个类的所有申明的字段,即包括public、private和proteced,
但是不包括父类的申明字段。
下面来看一个例子说明:
动物接口
- package com.lin;
- public interface Aminal {
- public String eat(String obj);
- public int run(int obj);
- }
实现类:
- <pre name="code" class="java">package com.lin;
- import java.util.jar.Attributes.Name;
- public class Dog implements Aminal {
- private String name;
- private int age;
- public Dog() {
- // TODO 自动生成的构造函数存根
- }
- public Dog(String name,int age) {
- this.name = name;
- this.age = age;
- }
- public Dog(String name) {
- this.name = name;
- this.age = 10;
- }
- private void sleep(int x) {
- System.out.println(name + "睡觉" + x + "分钟");
- }
- 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;
- }
- @Override
- public String eat(String obj) {
- System.out.println(name + "吃"+ obj);
- return null;
- }
- @Override
- public int run(int obj) {
- System.out.println("跑,速度:"+ obj);
- return 0;
- }
- @Override
- public String toString() {
- return "狗名:" + name + " 狗的年纪:" + age;
- }
- private static void play() {
- System.out.println("狗狗自己玩啊玩");
- }
- }
- </pre><br>
来看看各自的调用:
- package com.lin;
- import java.lang.reflect.Method;
- public class ReflectLearning {
- public static void main(String[] args) throws ClassNotFoundException {
- Dog dog = new Dog();
- System.out.println(dog.getClass());
- System.out.println(dog.getClass().getName());
- Class<?> dogClass = dog.getClass();
- Class<?> dogClass1 = Dog.class;
- Class<?> dogClass2 = Class.forName("com.lin.Dog");
- Method[] methods1 = dogClass.getMethods();
- System.out.println("====================通过getMethods取得方法开始====================");
- for (Method method : methods1) {
- System.out.println(method);
- }
- System.out.println("====================通过getMethods取得方法结束====================");
- Method[] methods2 = dogClass.getDeclaredMethods();
- System.out.println("====================通过getDeclaredMethods取得方法开始====================");
- for (Method method : methods2) {
- System.out.println(method);
- }
- System.out.println("====================通过getDeclaredMethods取得方法结束====================");
- }
- }
来看下结果:
getMethods方法
getDeclareMethos方法:
从上面可以看出getMethods()返回某个类的所有公用(public)方法包括其继承类的公用方法,当然也包括它所实现接口的方法。getDeclaredMethods()对象表示的类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。当然也包括它所实现接口的方法。
二、通过反射调用构造函数
(1)、列出所有的构造函数:
- Constructor<?>[] constructors = dogClass.getConstructors();
- System.out.println("====================列出所有的构造函数结束====================");
- for (Constructor<?> constructor : constructors) {
- System.out.println(constructor);
- }
- System.out.println("====================列出所有的构造函数结束====================");
输出结果:
(2)、通过反射生成对象
- System.out.println("====================通过newInstance()来生成对象,一定在有默认构造函数====================");
- Dog dog1 = (Dog) dogClass.newInstance();
- dog1.setName("狗狗1号");
- dog1.setAge(7);
- System.out.println(dog1);
- System.out.println("====================通过newInstance(参数)方法一来生成对象====================");
- Dog dog2 = (Dog)constructors[0].newInstance("狗狗2号");
- System.out.println(dog2);
- System.out.println("====================通过newInstance(参数)方法二来生成对象====================");
- Constructor con1 = dogClass.getConstructor(new Class[]{String.class,int.class}); //主要就是这句了
- Dog dog3 = (Dog) con1.newInstance(new Object[]{"狗狗3号",14});
- System.out.println(dog3);
输出结果:
从上面可以看出,先通过getConstructor(new Class[]{xxxx.class,yyy.class}),再通过con1.newInstance(new Object[]{"xxxxx",...});的方式是最灵活的,可以自动根据输入的参数类型和个数,找到对应的构造函数来调用。第二种方法需要得到构造函数的数组,并且需要知道对应哪一个构造函数。第一种就只能调用无参构造函数。
三、通过反射调用普通函数、静态函数
(1)取得函数的一些基本信息
- Class<?> dogClass = Dog.class;
- Method[] methods = dogClass.getDeclaredMethods();
- for (Method method : methods) {
- System.out.println("函数名:"+method.getName() +" 函数类型:"+ method.getModifiers() + " 函数返回: "+ method.getReturnType() + " 函数参数个数:" + method.getParameterCount());
- }
输出结果:
其中函数类型对应表如下:
PUBLIC: 1
PRIVATE: 2
PROTECTED: 4
STATIC: 8
FINAL: 16
SYNCHRONIZED: 32
VOLATILE: 64
TRANSIENT: 128
NATIVE: 256
INTERFACE: 512
ABSTRACT: 1024
STRICT: 2048
(2)方法调用
这是当前狗类的方法:
- package com.lin;
- import java.util.jar.Attributes.Name;
- public class Dog implements Aminal {
- private String name;
- private int age;
- public Dog() {
- // TODO 自动生成的构造函数存根
- }
- public Dog(String name,int age) {
- this.name = name;
- this.age = age;
- }
- public Dog(String name) {
- this.name = name;
- this.age = 10;
- }
- private void sleep(int x) {
- System.out.println(name + "睡觉" + x + "分钟");
- }
- 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;
- }
- @Override
- public String eat(String obj) {
- System.out.println(name + "吃"+ obj);
- return null;
- }
- @Override
- public int run(int obj) {
- System.out.println("跑,速度:"+ obj);
- return 0;
- }
- @Override
- public String toString() {
- return "狗名:" + name + " 狗的年纪:" + age;
- }
- private static void play() {
- System.out.println("狗狗自己玩啊玩");
- }
- }
不同方法的调用过程:
- //调用私有方法
- Method method1 = dogClass.getDeclaredMethod("sleep", int.class);//不要用getMethod,它只能取到public方法
- Dog dog1 = (Dog) dogClass.getConstructor(new Class[] {String.class}).newInstance(new Object[]{"狗狗1号"});
- method1.setAccessible(true);//私有方法一定要加这句
- method1.invoke(dog1, 12);
- //调用私有静态方法
- Method method2 = dogClass.getDeclaredMethod("play");//不要用getMethod,它只能取到public方法
- method2.setAccessible(true);//私有方法一定要加这句
- method2.invoke(dogClass.newInstance());
- //调用公共方法
- Method method3 = dogClass.getMethod("eat", String.class);//这里也可以用getDeclaredMethod
- Dog dog3 = new Dog("狗狗3号", 45);
- method3.invoke(dog3, "苹果~");
输出结果:
方法调用这里一定要记住getMethod和getDeclaredMethod的区别,并且在调用私有的方法之前一定要加setAccessible(true)这一句,要不会报错!
四、通过反射取得字段、设置字段值
(1)怎么通过反射获取类的属性
a)Class.getDeclaredField(String name);
返回一个 Field 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明字段。
b)Class.getDeclaredFields();
返回 Field 对象的一个数组,这些对象反映此 Class 对象所表示的类或接口所声明的所有字段。
c)Class.getField(String name);
返回一个 Field 对象,它反映此 Class 对象所表示的类或接口的指定公共成员字段。
d)Class.getField();
返回一个包含某些 Field 对象的数组,这些对象反映此 Class 对象所表示的类或接口的所有可访问公共字段。
(2)进行属性获取更改
- Dog dog1 = new Dog("狗狗1号", 12);
- System.out.println(dog1);
- Class<?> dogClass = dog1.getClass();
- Field field1 = dogClass.getDeclaredField("name");//注意,getField只能取得public的字段
- field1.setAccessible(true);//私有变量必须先设置Accessible为true
- System.out.println("原本狗名:" + field1.get(dog1));
- field1.set(dog1,"狗狗2号");
- System.out.println(dog1);
输出结果:
值得注意的是获取私有属性的时候必须先设置Accessible为true,然后才能获取。
五、反射常用工具类
(1)bean复制工具
这里可以使用commons-beanutils中的copyProperties()方法,自己写是为了加深对反射的理解。
1、toString的基类
- package com.lin;
- import java.lang.reflect.Field;
- import java.text.SimpleDateFormat;
- import java.util.Date;
- /**
- * bean基類
- * @author lin
- *
- */
- public class BaseBean {
- public String toString() {
- StringBuffer sb = new StringBuffer();
- SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
- Class<?> cls = this.getClass();
- Field[] fields = cls.getDeclaredFields();
- sb.append(cls.getName() + "{");
- for (Field field : fields) {
- try {
- field.setAccessible(true);
- sb.append(field.getName());
- sb.append("=");
- sb.append(field.get(this));
- sb.append(" ");
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- sb.append("}");
- return sb.toString();
- }
- }
2、bean复制工具
- package com.lin;
- import java.lang.reflect.Field;
- import java.lang.reflect.InvocationTargetException;
- import java.lang.reflect.Method;
- /**
- * 将一个JavaBean风格对象的属性值拷贝到另一个对象的同名属性中 (如果不存在同名属性的就不拷贝)
- **/
- public class BeanCopy {
- private static String GET = "get";
- private static String SET = "set";
- /**
- *
- * @param source
- * @param target
- * @throws Exception
- */
- public static void copy(Object source,Object target){
- Class<?> sourceClz = source.getClass();
- Class<?> targetClz = target.getClass();
- // 得到Class对象所表征的类的所有属性(包括私有属性)
- Field[] sourceFields = sourceClz.getDeclaredFields();
- if (sourceFields.length == 0) {
- sourceFields = sourceClz.getSuperclass().getDeclaredFields();
- }
- int len = sourceFields.length;
- for (int i = 0; i < len; i++) {
- String fieldName = sourceFields[i].getName();
- Field targetField = null;
- // 得到targetClz对象所表征的类的名为fieldName的属性,不存在就进入下次循环
- try {
- targetField = targetClz.getDeclaredField(fieldName);
- } catch (NoSuchFieldException e) {
- try {
- targetField = targetClz.getSuperclass().getDeclaredField(fieldName);
- } catch (NoSuchFieldException e1) {
- e1.printStackTrace();
- } catch (SecurityException e1) {
- e1.printStackTrace();
- }
- }
- if (targetField == null) {
- continue;
- }
- // 判断sourceClz字段类型和targetClz同名字段类型是否相同
- if (sourceFields[i].getType() == targetField.getType()) {
- // 由属性名字得到对应get和set方法的名字
- String getMethodName = GET + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
- String setMethodName = SET + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
- // 由方法的名字得到get和set方法的Method对象
- Method getMethod;
- Method setMethod;
- try {
- try {
- getMethod = sourceClz.getDeclaredMethod(getMethodName,new Class[] {});//get方法入參為空
- } catch (NoSuchMethodException e) {
- getMethod = sourceClz.getSuperclass().getDeclaredMethod(getMethodName,new Class[] {});
- }
- try {
- setMethod = targetClz.getDeclaredMethod(setMethodName,sourceFields[i].getType());//set方法入參不為空
- } catch (NoSuchMethodException e) {
- setMethod = targetClz.getSuperclass().getDeclaredMethod(setMethodName,sourceFields[i].getType());
- }
- // 调用source对象的getMethod方法
- Object result = getMethod.invoke(source, new Object[] {});
- // 调用target对象的setMethod方法
- setMethod.invoke(target, result);
- } catch (SecurityException e) {
- e.printStackTrace();
- } catch (NoSuchMethodException e) {
- e.printStackTrace();
- } catch (IllegalArgumentException e) {
- e.printStackTrace();
- } catch (IllegalAccessException e) {
- e.printStackTrace();
- } catch (InvocationTargetException e) {
- e.printStackTrace();
- }
- } else {
- continue;
- }
- }
- }
- }
使用:
新建两个类:
- package com.lin;
- import java.util.Date;
- public class Car extends BaseBean{
- private String name;
- private String id;
- private Boolean sellFlag;
- private int age;
- private double maxSpeed;
- private double minSpeed;
- private int driverPeople;
- private Date date;
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public String getId() {
- return id;
- }
- public void setId(String id) {
- this.id = id;
- }
- public Boolean getSellFlag() {
- return sellFlag;
- }
- public void setSellFlag(Boolean sellFlag) {
- this.sellFlag = sellFlag;
- }
- public int getAge() {
- return age;
- }
- public void setAge(int age) {
- this.age = age;
- }
- public double getMaxSpeed() {
- return maxSpeed;
- }
- public void setMaxSpeed(double maxSpeed) {
- this.maxSpeed = maxSpeed;
- }
- public double getMinSpeed() {
- return minSpeed;
- }
- public void setMinSpeed(double minSpeed) {
- this.minSpeed = minSpeed;
- }
- public int getDriverPeople() {
- return driverPeople;
- }
- public void setDriverPeople(int driverPeople) {
- this.driverPeople = driverPeople;
- }
- public Date getDate() {
- return date;
- }
- public void setDate(Date date) {
- this.date = date;
- }
- }
另一个:
- package com.lin;
- import java.util.Date;
- public class Bus extends BaseBean{
- private String name;
- private String id;
- private Boolean sellFlag;
- private int age;
- private double maxSpeed;
- private double minSpeed;
- private long driverPeople;//和car類型不同
- private int driverYear;//car沒有這個
- private Date date;
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public String getId() {
- return id;
- }
- public void setId(String id) {
- this.id = id;
- }
- public Boolean getSellFlag() {
- return sellFlag;
- }
- public void setSellFlag(Boolean sellFlag) {
- this.sellFlag = sellFlag;
- }
- public int getAge() {
- return age;
- }
- public void setAge(int age) {
- this.age = age;
- }
- public double getMaxSpeed() {
- return maxSpeed;
- }
- public void setMaxSpeed(double maxSpeed) {
- this.maxSpeed = maxSpeed;
- }
- public double getMinSpeed() {
- return minSpeed;
- }
- public void setMinSpeed(double minSpeed) {
- this.minSpeed = minSpeed;
- }
- public long getDriverPeople() {
- return driverPeople;
- }
- public void setDriverPeople(long driverPeople) {
- this.driverPeople = driverPeople;
- }
- public int getDriverYear() {
- return driverYear;
- }
- public void setDriverYear(int driverYear) {
- this.driverYear = driverYear;
- }
- public Date getDate() {
- return date;
- }
- public void setDate(Date date) {
- this.date = date;
- }
- }
调用:
- public static void test5() {
- Car car = new Car();
- car.setAge(12);
- car.setDriverPeople(4);
- car.setId("YU1234");
- car.setMaxSpeed(13.66);
- car.setMinSpeed(1.09);
- car.setName("小车");
- car.setSellFlag(false);
- car.setDate(new Date());
- Bus bus = new Bus();
- BeanCopy.copy(car,bus);
- System.out.println(car);
- System.out.println(bus);
- }
http://blog.csdn.net/evankaka/article/details/49978481
Java反射探索研究(转)的更多相关文章
- 第28章 java反射机制
java反射机制 1.类加载机制 1.1.jvm和类 运行Java程序:java 带有main方法的类名 之后java会启动jvm,并加载字节码(字节码就是一个类在内存空间的状态) 当调用java命令 ...
- Java反射机制
Java反射机制 一:什么事反射机制 简单地说,就是程序运行时能够通过反射的到类的所有信息,只需要获得类名,方法名,属性名. 二:为什么要用反射: 静态编译:在编译时确定类型,绑定对象,即通过 ...
- java反射(基础了解)
package cn.itcast_01; /** *Person类 */ public class Person { /** 姓名 */ private String name; ...
- java基础知识(十一)java反射机制(上)
java.lang.Class类详解 java Class类详解 一.class类 Class类是java语言定义的特定类的实现,在java中每个类都有一个相应的Class对象,以便java程序运行时 ...
- java基础知识(十一)java反射机制(下)
1.什么是反射机制? java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法,对于任意一个对象都能够调用他的属性和方法,这种动态获取属性和方法的功能称为java的反射机制. ...
- java反射学习之二万能EXCEL导出
一.EXCEL导出的实现过程 假设有一个对象的集合,现在需要将此集合内的所有对象导出到EXCEL中,对象有N个属性:那么我们实现的方式是这样的: 循环这个集合,在循环集合中某个对象的所有属性,将这个对 ...
- java反射学习之一反射机制概述
一.反射机制背景概述 1.反射(reflection)是java被视为动态语言的一个关键性质 2.反射机制指的是程序在运行时能获取任何类的内部所有信息 二.反射机制实现功能概述 1.只要给定类的全名, ...
- java反射 之 反射基础
一.反射 反射:JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:这种动态获取的信息以及动态调用对象的方法的功能称为 ...
- java反射 cglib asm相关资料
有篇文章对java反射的调用的效率做了测试,写的比较好.猛击下面地址 http://www.blogjava.net/stone2083/archive/2010/09/15/332065.html ...
随机推荐
- android在Canvas使用drawBitmap画一幅画
1.画图的主要方法 //Bitmap:图片对象,left:向左偏移.top: 顶部偏移 drawBitmap(Bitmap bitmap, float left, float top, Pai ...
- 程序缩小到托盘后系统就无法关机(解决方案)——处理WM_QUERYENDSESSION消息,并把它标识为处理过了
程序缩小到托盘后系统就无法关机(解决方案) 老帅 程序最小化到托盘后,会出现系统无法关闭的问题,常见于WinXP系统中,这里提供一个解决方案!一.解决 ...
- 在Ubuntu上录制视频和编辑(很全)
Linux多媒体三剑客:GIMP,Inkscape,Blender3D Blender基金会制作的开源微电影Sintel:http://www.sintel.org/about电影采用Creative ...
- Spring MVC的异步模式
高性能的关键:Spring MVC的异步模式 我承认有些标题党了,不过话说这样其实也没错,关于“异步”处理的文章已经不少,代码例子也能找到很多,但我还是打算发表这篇我写了好长一段时间,却一直没发表 ...
- JavaScript 中的事件流和事件处理程序(读书笔记思维导图)
JavaScript 程序采用了异步事件驱动编程模型.在这种程序设计风格下,当文档.浏览器.元素或与之相关的对象发生某些有趣的事情时,Web 浏览器就会产生事件(event). JavaScript ...
- filter与servlet对照
最近在开java物自,还记得刚开始使用servlet这是一个调试ajax什么时候,然后,我不知道怎么用,你知道写的路径来调用,总是提示404错,,到最后自己一点点的调通了,知道servlet是须要se ...
- WPF案例(-)模拟Windows7 Win+Tab切换
原文:WPF案例(-)模拟Windows7 Win+Tab切换 一个使用Wpf模拟Windows7 Win+Tab页面切换的小程序,使用快捷键Ctrl+Down或Ctrl+Up在示例程序各个页面元素之 ...
- Java对象序列化/反序列化的注意事项
Java对象序列化 对于一个存在Java虚拟机中的对象来说,其内部的状态只是保存在内存中.JVM退出之后,内存资源也就被释放,Java对象的内部状态也就丢失了.而在很多情况下,对象内部状态是需要被持久 ...
- xml(3)--dom4j实现crud操作
1.XML解析技术概述 (1)XML解析方式分为两种:dom和sax dom:(Document Object Model, 即文档对象模型) 是 W3C 组织推荐的处理 XML 的一种标准方 ...
- unity中的MonoBehaviour.OnMouseDown()
在官网的api文档中仅说明了 Description OnMouseDown is called when the user has pressed the mouse button while ov ...