jdk的反射机制
反射的作用
1)在运行时判断任意一个对象所属的类;
2)在运行时构造任意一个类的对象;
3)在运行时判断任意一个类所具有的成员变量和方法;
4)在运行时调用任意一个对象的方法。
5)反射API可以获取程序在运行时刻的内部结构。
6)使用反射的一个最大的弊端是性能比较差。相同的操作,用反射API所需的时间大概比直接的使用要慢一两个数量级。
Class类
可以通过以下三种方式获得Class对象:
1)使用Class类的静态方法forName:Class.forName(“java.lang.String”);
2)使用类的.class语法:String.class;
3)使用对象的getClass()方法:String s = "aa"; Class<?> clazz = s.getClass();
4)对于包装类(8个)可以通过.TYPE语法方式
public class ReflectDemo01 {
public static void main(String[] args) throws Exception {
// Class<?> clazz = Class.forName(args[0]);
Class<?> clazz = Class.forName("java.lang.Object");
Method[] methods = clazz.getDeclaredMethods();
for (Method method : methods) {
System.out.println(method);
}
System.out.println("-------------");
methods = clazz.getMethods();
for (Method method : methods) {
System.out.println(method);
}
}
}
注意:
getDeclaredMethods()和getMethods()方法的区别
Integer.TYPE返回的是int;
Integer.class返回的是Integer类所对应的Class对象;
Integer.TYPE返回的是基本类型 int的Class实例;
Integer age = 10;
System.out.println(age.TYPE);
结果是:int
getSuperclass()方法的使用
public class ReflectDemo08 {
public static void main(String[] args) {
Class<?> classType = Child.class;
System.out.println(classType); //class Child
classType = classType.getSuperclass();
System.out.println(classType); //class Parent
classType = classType.getSuperclass();
System.out.println(classType); //class java.lang.Object
classType = classType.getSuperclass();
System.out.println(classType);//null
}
}
class Parent {
}
class Child extends Parent {
}
通过Class的方法来获取到该类中的构造方法、属性和方法。对应的方法分别是getConstructor、getField和getMethod。
Class对象封装了一个java类中定义的成员变量、成员方法、构造方法、类名、包名等。
Constructor类
Constructor类代表某个类中的一个构造方法。
得到某个类所有的构造方法:
Constructor [] constructors= Class.forName("java.lang.String").getConstructors();
得到某一个构造方法:
Constructor constructor = Class.forName("java.lang.String").getConstructor(StringBuffer.class);
创建实例对象:
方法一:通常方式
String str = new String(new StringBuffer("abc"));
方法二:反射方式
String str = (String)constructor.newInstance(new StringBuffer("abc"));
方法三:Class.newInstance()方法
String obj = (String)Class.forName("java.lang.String").newInstance();
该方法内部先得到默认的构造方法,然后用该构造方法创建实例对象。
Field类
Field类代表某个类中的一个成员变量;
问题:得到的Field对象是对应到类上面的成员变量,还是对应到对象上的成员变量?
类只有一个,而该类的实例对象有多个,如果是与对象关联,哪关联的是哪个对象呢?所以字段fieldX 代表的是x的定义,而不是具体的x变量。(注意访问权限的问题)
示例代码:
ReflectPoint point = new ReflectPoint(1,7);
Field y = Class.forName("cn.itcast.corejava.ReflectPoint").getField("y");
System.out.println(y.get(point));
//Field x = Class.forName("cn.itcast.corejava.ReflectPoint").getField("x");
Field x = Class.forName("cn.itcast.corejava.ReflectPoint").getDeclaredField("x");
x.setAccessible(true);
System.out.println(x.get(point));
Method类
Method类代表某个类中的一个成员方法;
得到类中的某一个方法:
Method charAt = Class.forName("java.lang.String").getMethod("charAt", int.class);
调用方法:
方式一:通常方式
System.out.println(str.charAt(1));
方式二:反射方式
System.out.println(charAt.invoke(str, 1));
如果传递给Method对象的invoke()方法的第一个参数为null,这有着什么样的意义呢?说明该Method对象对应的是一个静态方法!
jdk1.4和jdk1.5的invoke方法的区别:
Jdk1.5:public Object invoke(Object obj,Object... args)
Jdk1.4:public Object invoke(Object obj,Object[] args),即按jdk1.4的语法,需要将一个数组作为参数传递给invoke方法时,数组中的每个元素分别对应被调用方法中的一个参数,所以,调用charAt方法的代码也可以用Jdk1.4改写为 charAt.invoke("str", new Object[]{1})形式。
通过Class类实例化对象
方法一:实例化无参构造的类并调用方法
先获得Class对象,然后通过该Class对象的newInstance()方法直接生成即可:
Class<?> classType = String.class;
Object obj = classType.newInstance();
先获得Class对象,然后通过该对象获得对应的Constructor对象,再通过该Constructor对象的newInstance()方法生成:
Class<?> classType = Customer.class;
Constructor cons = classType.getConstructor(new Class[]{});
Object obj = cons.newInstance(new Object[]{});
public class ReflectDemo02 {
public int add(int param1, int param2) {
return param1 + param2;
}
public String echo(String message) {
return "hello: " + message;
}
public static void main(String[] args) throws Exception {
Class<?> clazz = ReflectDemo02.class;
Object obj = clazz.newInstance();
Method addMethod = clazz.getMethod("add", int.class, int.class);
Object result = addMethod.invoke(obj, 1, 2);
System.out.println(result);
System.out.println("----------------华丽的分割线------------------");
Method echoMethod = clazz.getMethod("echo", String.class);
result = echoMethod.invoke(obj, "luogankun");
System.out.println(result);
}
}
getMethod()的定义:
public Method getMethod(String name, Class<?>... parameterTypes)
第二个参数是可变参数。
方法二:实例化有参构造的类并调用方法
若想通过类的带参数的构造方法生成对象,只能使用下面这一种方式:
Class<?> classType = Customer.class;
Constructor cons = classType.getConstructor(new Class[]{String.class, int.class});
Object obj = cons.newInstance(new Object[]{"hello", 3});
Class<?> clazz = Dog.class;
Constructor<?> constructor = clazz.getConstructor(Integer.class,String.class);
Dog dog = (Dog) constructor.newInstance(2, "aaad");
利用反射完成对象的拷贝
public class ReflectDemo03 {
public static void main(String[] args) throws Exception {
Customer customer = new Customer("Tom", 20);
customer.setId(1L);
ReflectDemo03 demo = new ReflectDemo03();
Customer customer2 = (Customer) demo.copy(customer);
System.out.println(customer2.getId() + "," + customer2.getName() + ","
+ customer2.getAge());
}
// 该方法实现对Customer对象的拷贝操作
@SuppressWarnings("rawtypes")
public Object copy(Object object) throws Exception {
Class<?> clazz = object.getClass();
System.out.println("clazz " + clazz);
Constructor constructor = clazz.getConstructor();
Object objectCopy = constructor.newInstance();
// 以上两行代码等价于clazz.newInstance();
Field[] fields = clazz.getDeclaredFields(); //获得属性
for (Field field : fields) {
// System.out.println(field.getName());
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 = clazz.getDeclaredMethod(getMethodName);
Method setMethod = clazz.getDeclaredMethod(setMethodName,sfield.getType());
Object value = getMethod.invoke(object);
setMethod.invoke(objectCopy, value);
}
return objectCopy;
}
}
public class Customer {
private Long id;
private String name;
private int age;
public Customer() {
}
public Customer(String name, int age) {
this.name = name;
this.age = age;
}
setter/getter
}
如果要通过反射调用类的静态方法时,只需要将要反射的对象设置成null即可。 setMethod.invoke(null, value);
使用Java反射API的时候可以绕过Java默认的访问控制检查
1)利用反射调用对象的私有方法
public class ReflectDemo06 {
public static void main(String[] args) throws Exception {
Class<?> clazz = Private.class;
Object object = clazz.newInstance();
Method method = clazz.getDeclaredMethod("sayHello", String.class);
method.setAccessible(true);
Object result = method.invoke(object, "luogankun");
System.out.println(result);
}
}
public class Private {
private String name = "zhangsan";
private String sayHello(String name) {
return "hello: " + name;
}
public String getName() {
return name;
}
}
2)利用反射完成对私有成员变量的重新赋值
面试题:私有变量能被外界访问吗? 正常情况下不行,但是可以通过反射来调用
public class ReflectDemo07 {
public static void main(String[] args) throws Exception {
Class<?> clazz = Private.class;
Private object = (Private) clazz.newInstance();
Field field = clazz.getDeclaredField("name");
field.setAccessible(true);
field.set(object, "luogankun");
System.err.println(object.getName());
}
}
总结:使用Java反射API的时候可以绕过Java默认的访问控制检查,比如可以直接获取到对象的私有域的值或是调用私有方法。
只需要在获取到Constructor、Field和Method类的对象之后,调用setAccessible方法并设为true即可。有了这种机制,就可以很方便的在运行时刻获取到程序的内部状态。
Array类提供了一系列的静态方法用来创建数组和对数组中的元素进行访问和操作
public class ReflectDemo04 {
public static void main(String[] args) throws Exception {
Class<?> clazz = Class.forName("java.lang.String");
Object array = Array.newInstance(clazz, 10); //等价于 new String[10]
Array.set(array, 5, "hello"); //等价于array[5] = "Hello"
String string = (String) Array.get(array, 5); //等价于array[5]
System.out.println(string);
}
}
jdk的反射机制的更多相关文章
- 利用JAVA反射机制将JSON数据转换成JAVA对象
net.sf.json.JSONObject为我们提供了toBean方法用来转换为JAVA对象, 功能更为强大, 这里借鉴采用JDK的反射机制, 作为简单的辅助工具使用, 有些数据类型需要进行转 ...
- 第28章 java反射机制
java反射机制 1.类加载机制 1.1.jvm和类 运行Java程序:java 带有main方法的类名 之后java会启动jvm,并加载字节码(字节码就是一个类在内存空间的状态) 当调用java命令 ...
- java基础知识(十一)java反射机制(下)
1.什么是反射机制? java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法,对于任意一个对象都能够调用他的属性和方法,这种动态获取属性和方法的功能称为java的反射机制. ...
- Java系列笔记(2) - Java RTTI和反射机制
目录 前言 传统的RTTI 反射 反射的实现方式 反射的性能 反射与设计模式 前言 并不是所有的Class都能在编译时明确,因此在某些情况下需要在运行时再发现和确定类型信息(比如:基于构建编程,),这 ...
- Java反射机制专题
·Java Reflection Reflection(反射)是被视为动态语言的关键,反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方 ...
- java反射机制初探
最近和一位师兄交流了一下Java,真可谓是大有收获,让我好好的学习了一下javad的反射机制,同终于明白了spring等框架的一个基本实现的思想,那么今天就和大家分享一下java的反射机制. 反射,r ...
- Java基础复习笔记系列 十三 反射机制
主题:Java反射机制 学习资料参考网址: 1.http://www.icoolxue.com 1.Java反射机制. 各种框架中都使用到了Java的反射机制. 两个类:java.lang.Class ...
- Java反射机制详解
Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的反 ...
- Java反射机制(Reflection)
Java反射机制(Reflection) 一.反射机制是什么 Java反射机制是程序在运行过程中,对于任意一个类都能够知道这个类的所有属性和方法;对于任意一个对象都能够调用它的任意一个方法和属性,这种 ...
随机推荐
- HTML页面上获取鼠标的位置(备忘)
<html> <head> <meta http-equiv="Content-Type" content="text/html; char ...
- Python基础教程【读书笔记】 - 2016/7/18
希望通过博客园持续的更新,分享和记录Python基础知识到高级应用的点点滴滴! 第七波:第3章 字符串 介绍如何使用字符串格式化其他的值,并简单了解一下利用字符串的分割.联接.搜索等方法能做些什么. ...
- 【Spring-AOP-1】AOP相关概念
Advice (好多中文书籍翻译为:增强处理,比如前向增强.后向增强等) 描述了Aspect类执行的具体动作.the job of an aspect. 定义了如下两个方面: what:即Aspect ...
- 目前已经知道的乐视所有产品各个型号的强刷方法!更新X50
http://ui.letv.com/thread-43668-1-1.html 很多网友买来电视/盒子仅仅要看,还要折腾这个电视,有时候不小心把系统折腾死了,肿么办?危难之中显身手,我的神帖来了,敬 ...
- 216. Combination Sum III
Find all possible combinations of k numbers that add up to a number n, given that only numbers from ...
- 如何缩短SQL Server 的启动时间
将/nosplash添加到SQLServer Manageement Studio的快捷方式可以缩短启动时间.为此,右击SSMS快捷方式(位于你的桌面上.start菜单中或任务栏中)并选择Proper ...
- 黄聪:WordPress 多站点建站教程(五):获取子站点用户信息(通过输入站点ID号来获取该站点的所有用户)
得到站点ID为1的用户 <ul> <?php $blogusers = get_users('blog_id=1'); foreach ($blogusers as $user) { ...
- HDU 2516 取石子游戏(斐波那契博弈)
取石子游戏 Time Limit: 2000/1000 MS(Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Submissi ...
- 对CSS中的Position属性的一些深入探讨
转:http://www.cnblogs.com/coffeedeveloper/p/3145790.html Position属性 Position的属性值共有四个static.relative.a ...
- 时间c#
无论Time.timeScale 等于多说Update和LateUpdate都会去执行 Time.timeScale会影响FixedUpdate的速度. Time.timeScale还会影响Time ...