反射的作用

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的反射机制的更多相关文章

  1. 利用JAVA反射机制将JSON数据转换成JAVA对象

    net.sf.json.JSONObject为我们提供了toBean方法用来转换为JAVA对象, 功能更为强大,  这里借鉴采用JDK的反射机制, 作为简单的辅助工具使用,   有些数据类型需要进行转 ...

  2. 第28章 java反射机制

    java反射机制 1.类加载机制 1.1.jvm和类 运行Java程序:java 带有main方法的类名 之后java会启动jvm,并加载字节码(字节码就是一个类在内存空间的状态) 当调用java命令 ...

  3. java基础知识(十一)java反射机制(下)

    1.什么是反射机制? java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法,对于任意一个对象都能够调用他的属性和方法,这种动态获取属性和方法的功能称为java的反射机制. ...

  4. Java系列笔记(2) - Java RTTI和反射机制

    目录 前言 传统的RTTI 反射 反射的实现方式 反射的性能 反射与设计模式 前言 并不是所有的Class都能在编译时明确,因此在某些情况下需要在运行时再发现和确定类型信息(比如:基于构建编程,),这 ...

  5. Java反射机制专题

    ·Java Reflection Reflection(反射)是被视为动态语言的关键,反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方 ...

  6. java反射机制初探

    最近和一位师兄交流了一下Java,真可谓是大有收获,让我好好的学习了一下javad的反射机制,同终于明白了spring等框架的一个基本实现的思想,那么今天就和大家分享一下java的反射机制. 反射,r ...

  7. Java基础复习笔记系列 十三 反射机制

    主题:Java反射机制 学习资料参考网址: 1.http://www.icoolxue.com 1.Java反射机制. 各种框架中都使用到了Java的反射机制. 两个类:java.lang.Class ...

  8. Java反射机制详解

    Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的反 ...

  9. Java反射机制(Reflection)

    Java反射机制(Reflection) 一.反射机制是什么 Java反射机制是程序在运行过程中,对于任意一个类都能够知道这个类的所有属性和方法;对于任意一个对象都能够调用它的任意一个方法和属性,这种 ...

随机推荐

  1. Android 打包签名 从生成keystore到完成签名 -- 转

    首先,我们需要一个keystore,当然已经有了的话就不用这一步了:cmd下:进入到jdk的bin目录,这样的话,android.keystore文件就会生成在这个目录下,签名的时候我们需要这个文件C ...

  2. 【linux】chmod命令详细用法

    功能说明: 变更文件或目录的权限 u:User,即文件或目录的拥有者. g:Group,即文件或目录的所属群组. o:Other,除了文件或目录拥有者或所属群组之外,其他用户皆属于这个范围. a:Al ...

  3. 加了GO后报 'GO' 附近有语法错误

    单独运行SQL无问题,了加GO就报错. 是你的SQL语句中,有些行的结尾处只有Char(13)没有Char(10),即:只有回车符没有换行符,这种状态在视觉上是没办法区分的. 参考:http://ww ...

  4. 剑指offer系列30-----删除链表中重复的节点

    [题目]在一个排序的链表中,存在重复的结点, * 请删除该链表中重复的结点,重复的结点不保留,返回链表头指针. * 例如,链表1->2->3->3->4->4->5 ...

  5. Avant Browser

    Avant Browser Avant 浏览器友好的用户界面为你的网络冲浪带来全新的效率和透明性.软件版本的不断升级使产品的可靠性稳步提高. 没有广告.没有恶意软件! Avant 浏览器是免费的.10 ...

  6. SQL常用方法整理

    去除字符串重复项: declare @str varchar(8000) declare @ret varchar(8000),@return varchar(8000) select @str = ...

  7. c++随机数生成

    算机的随机数都是由伪随机数,即是由小M多项式序列生成的,其中产生每个小序列都有一个初始值,即随机种子.(注意: 小M多项式序列的周期是65535,即每次利用一个随机种子生成的随机数的周期是65535, ...

  8. 最小费用最大流 POJ2195-Going Home

    网络流相关知识参考: http://www.cnblogs.com/luweiseu/archive/2012/07/14/2591573.html 出处:優YoU http://blog.csdn. ...

  9. 黄聪:Dsicuz x2.5、X3、X3.2如何去掉域名后面的/forum.php

    Dsicuz x2.5去掉域名后面的/forum.php 1, 后台--全局--域名设置--应用域名--设置默认域名为访问域名就可以,如:www.xxxxx.com 上面2种方法都可以去掉域名后面的/ ...

  10. VS 开发工具中的Remote Debug 功能远程调试程序经验分享

    前言: 有时候我们Dev(开发人员)需要debug tester(测试人员)或者customer(客户)的环境,可tester的机器上没有Code,是不是有点着急? 而且是多版本应用且tester 发 ...