反射的作用

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. Linux环境下MySQL使用入门

    1 安装 1.1 yum安装 yum install mysql-server yum remove mysql service mysqld restart // 服务重新启动 chkconfig ...

  2. C# WinForm开发系列 - ComboBox

    5.一个带CheckBox,分组,颜色标记等功能的下拉框  PowerComboBoxCSharp.rar 包含自动完成下拉框,字体下拉框,电脑盘符,多列下拉框,带CheckBox,树型下拉框等.代码 ...

  3. 剑指offer系列43---判断平衡二叉树

    [题目]判断一颗二叉树是不是平衡二叉树. * 平衡二叉树定义:任意子节点深度相差不超过1.[思路]由上题,利用递归得到二叉树每个结点的深度同时比较. package com.exe9.offer; i ...

  4. Hadoop学习5--配置本地开发环境(Windows+Eclipse)

    一.导入hadoop插件到eclipse 插件名称:hadoop-eclipse-plugin-2.7.0.jar 我是从网上下载的,还可以自己编译. 放到eclipse安装目录下的plugins文件 ...

  5. Java事务处理全解析(三)——丑陋的案例

    在本系列的上一篇文章中,我们看到了一个典型的事务处理失败的案例,其主要原因在于,service层和各个DAO所使用的Connection是不一样的,而JDBC中事务处理的作用对象正是Connectio ...

  6. [MySQL] 同步一张表、复制过滤设置

    一.缘由 据测试要求,需要把线上一张股票信息的表实时同步到测试环境,那么干吧,这次不复制库,单独复制表. 二.解决办法 可以按照同步(复制)库的方法来,在salve端设置 my.cnf,replica ...

  7. 用socket操作redis

    代码: $cmd = "*3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$3\r\nbar\r\n"; // set foo bar $socket = socke ...

  8. python(19)编码问题

    转载链接:http://blog.csdn.net/lxdcyh/article/details/4018054 python的编码问题,一直都让人很头疼,今天就整理下python的编码知识. 首先: ...

  9. [复变函数]第15堂课 4.3 解析函数的 Taylor 展式

    1.  Taylor 定理: 设 $f(z)$ 在 $K:|z-a|<R$ 内解析, 则 $$\bee\label{15:taylor} f(z)=\sum_{n=0}^\infty c_n(z ...

  10. WindowsForm通过字符串名称实例化控件

    private Control FindControl(Control control, string controlName) { Control c1; foreach (Control c in ...