反射的作用

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. 将Excel数据导入Oracle中

    第一步:修改Excel 1.将Excel的表头修改为目标数据库中表的字段名 2.去重(如果有需要的话) 删除Excel表中的重复数据: 选择去重的列: 删除成功后提示: 第二步:将修改后的Excel另 ...

  2. [oracle] ORACLE_HOME_LISTNER is not SET, unable to auto-start Oracle Net Listener

    安装好Oracle数据库后: 执行 dbstart和dbshut会提示: [oracle@oracle11g ~]$ dbstartORACLE_HOME_LISTNER is not SET, un ...

  3. mongodb不同版本之间有很大的差异

    今天主要说下我为了给mongodb数据库添加authorization,大家应该知道,mongo默认是无auth运行的.这可能是方便小伙伴学习命令吧. 由于之前发布的一个项目,在亚马逊的云上,处于内部 ...

  4. 【jmter】JDBC进行mysql数据库测试

    1.添加线程组 2.添加需要的驱动jar包 使用不同的数据库,我们需要引入不同的jar包. 方式1:直接将jar包复制到jmeter的lib目录 mysql数据库:无需引入其他数据库驱动jar包. s ...

  5. Java-Thread

    1. 线程的创建和启动 1.1 继承Thread 在run方法里,通过this获取当前线程. 多个线程不能共享实例变量. 1.2 通过实现接口 1.2.1 实现Runable接口 在run方法里,只能 ...

  6. js常用方法收集

    JS获取地址栏制定参数值: //获取URL参数的值 function getUrlParam(name){ var reg = new RegExp("(^|&)"+ na ...

  7. 1. Netty解决Tcp粘包拆包

    一. TCP粘包问题 实际发送的消息, 可能会被TCP拆分成很多数据包发送, 也可能把很多消息组合成一个数据包发送 粘包拆包发生的原因 (1) 应用程序一次写的字节大小超过socket发送缓冲区大小 ...

  8. 内存修改console

    #include <stdio.h> #include <windows.h> #include <winuser.h> int main() { int cur_ ...

  9. U3d中实现A*寻路,附源文件

    图片看不清楚,请点击看大图 http://pan.baidu.com/s/1pKwmOYn   写了好多,没保存,哎哎哎 空格键开始移动

  10. JDK1.7新特性

    jdk1.7新特性 1 对集合类的语言支持: 2 自动资源管理: 3 改进的通用实例创建类型推断: 4 数字字面量下划线支持: 5 switch中使用string: 6 二进制字面量: 7 简化可变参 ...