反射的作用

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. 【shell】sort命令

    [root@andon ~]# sort 1 ##常用正序自动排序 101 paul 18 100 102 suan 11 99 103 peter 18 98 id name age score [ ...

  2. visual studio 声明数组太大,导致栈溢出

    在解释原因前我们先看一下一个由C/C++编译的程序占用的内存分为几个部分: 1.栈区(stack segment):由编译器自动分配释放,存放函数的参数的值,局部变量的值等.在Windows下,栈是向 ...

  3. 黄聪:WordPress 多站点建站教程(六):使用WP_Query、switch_to_blog函数实现获取子站点分类中的文章

    首先在你使用主题的funtions.php里面添加下代码: //根据时间显示最新的分类文章内容,每个站点显示一篇内容 //$blog_id 子站点ID //$catid 分类ID wp_reset_q ...

  4. [Bug-IOS] - linker command failed with exit code 1 (use -v to see invocation)

    Ld /Users/Rubert/Library/Developer/Xcode/DerivedData/OC_Language-emftyzftyvhdpuaxipddjmpnpvox/Build/ ...

  5. UVa 10801 - Lift Hopping(dijkstra最短路)

    根据题意,以每一层楼为顶点,每个电梯可以到达的两层楼之间的秒数为每一条边的权值,以此构建一个无向图.然后利用dijkstra求出最短的时间,注意每次换乘电梯需要等待60s(因为同一个电梯上的楼层是相互 ...

  6. [实变函数]5.1 Riemann 积分的局限性, Lebesgue 积分简介

    1 Riemann 积分的局限性 (1) Riemann 积分与极限的条件太严:    $$\bex    f_k\rightrightarrows f\ra \lim \int_a^b f_k   ...

  7. 关于htmlspecialchars实体字符转码的问题

    php对post过来的数据进行实体字符转码,我的页面编码是gb2312,刚开始是这样: $post = htmlspecialchars ( $post); 取到的$post值为空,但是有时候是好的( ...

  8. SteamVR Unity工具包(VRTK)之控制器交互

    可交互对象(VRTK_InteractableObject) 可交互对象脚本被添加到需要用(如控制器)来交互的任何游戏对象上.   可用脚本参数如下   Touch Interactions 触摸交互 ...

  9. studio adb连接不上手机 ADB server didn't ACK

    问题描述:在eclipse的Logcat出现错误 [2014-01-08 14:00:07 - adb] ADB server didn't ACK [2014-01-08 14:00:07 - ad ...

  10. memcpy

    函数原型 void *memcpy(void*dest, const void *src, size_t n); 功能 由src指向地址为起始地址的连续n个字节的数据复制到以destin指向地址为起始 ...