Java-反射
Tags
#Java
JAVA反射机制
简单的来说,反射机制指的是程序在运行时能够获取自身的信息。在java中,只要给定类的名字, 那么就可以通过反射机制来获得类的所有信息。
一、Class是什么?
Java程序在运行时,Java运行时系统一直对所有的对象进行所谓的运行时类型标识。这项信息纪录了每个对象所属的类。虚拟机通常使用运行时类型信息选择正确方法去执行,用来保存这些类型信息的类是Class类。
Class类封装一个对象和接口运行时的状态,当装载类时,Class类型的对象自动创建。 Class 没有公共构造方法。Class 对象是在加载类时由 Java 虚拟机以及通过调用类加载器中的 defineClass 方法自动构造的,因此不能显式地声明一个Class对象。
虚拟机为每种类型管理一个独一无二的Class对象。也就是说,每个类(型)都有一个Class对象。运行程序时,Java虚拟机(JVM)首先检查是否所要加载的类对应的Class对象是否已经加载。如果没有加载,JVM就会根据类名查找.class文件,并将其Class对象载入。
基本的 Java 类型(boolean、byte、char、short、int、long、float 和 double)和关键字 void 也都对应一个 Class 对象。 每个数组属于被映射为 Class 对象的一个类,所有具有相同元素类型和维数的数组都共享该 Class 对象。一般某个类的Class对象被载入内存,它就用来创建这个类的所有对象。
二、Class类的常用方法
在java.lang.Object 类中定义了getClass()方法,因此对于任意一个Java对象,都可以通过此方法获得对象的类型。Class类是Reflection API 中的核心类,它有以下方法
- getName():获得类的完整名字。
- getFields():获得类的public类型的属性。
- getDeclaredFields():获得类的所有属性。
- getMethods():获得类的public类型的方法。
- getDeclaredMethods():获得类的所有方法。
- getMethod(String name, Class[] parameterTypes):获得类的特定方法,name参数指定方法的名字,parameterTypes 参数指定方法的参数类型。
- getConstructors():获得类的public类型的构造方法。
- getConstructor(Class[] parameterTypes):获得类的特定构造方法,parameterTypes 参数指定构造方法的参数类型。
- newInstance():通过类的不带参数的构造方法创建这个类的一个对象。
提醒:
- 大家在使用Class实例化其他类的对象的时候,一定要自己定义无参的构造函数
- 所有类的对象其实都是Class的实例。
三、获取Class对象的三种方式
1.通过Object类的getClass()方法。
例如:Class c1 = new String("").getClass();
2.通过Class类的静态方法——forName()来实现:
Class c2 = Class.forName("MyObject");
3.如果T是一个已定义的类型的话,在java中,它的.class文件名:T.class就代表了与其匹配的Class对象
例如:Class c3 = Manager.class;
Class c4 = int.class;
Class c5 = Double[].class;
四、几个反射用例
先介绍2个很牛逼的方法:
- getClass().getDeclaredField("x");//获取类的属性x,无视权限(获取方法类似)
- setAccessible(true);//设置属性可编辑
实体类
package reflection;
/**
* yutianran 16/8/1 下午3:45
*/
public class Point {
private int x;
public int y;
public Point() {
}
public Point(int x) {
this.x = x;
}
public Point(int x, int y) {
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
private void draw(String msg){
System.out.println("msg="+msg);
}
@Override
public String toString() {
return "Point{" +
"x=" + x +
", y=" + y +
'}';
}
}
1. 修改私有属性
//修改私有属性
private static void modifyFiled() throws Exception {
Point pt1 = new Point(3, 5);
Class<?> clazz = pt1.getClass();//通过Ponit对象获取Class实例
//得到一个字段
Field fieldY = clazz.getField("y"); //y 是变量名
//fieldY的值是5么?? 大错特错
//fieldY和pt1根本没有什么关系,你看,是pt1.getClass(),是 字节码 啊
//不是pt1对象身上的变量,而是类上的,要用它取某个对象上对应的值
//要这样
System.out.println(fieldY.get(pt1)); //这才是5
//现在要x了
/*
Field fieldX = pt1.getClass().getField("x"); //x 是变量名
System.out.println(fieldX.get(pt1));
*/
//运行 报错 私有的,找不到
//NoSuchFieldException
//说明getField 只可以得到 公有的
//怎么得到私有的呢??
/*
Field fieldX = pt1.getClass().getDeclaredField("x"); //这个管你公的私的,都拿来
//然后轮到这里错了
// java.lang.IllegalAccessException:
//Class com.ncs.ReflectTest can not access a member of class com.ncs.Point with modifiers "private"
System.out.println(fieldX.get(pt1));
*/
//三步曲 一是不让你知道我有钱 二是把钱晃一下,不给用 三是暴力抢了
//暴力反射
Field fieldX = pt1.getClass().getDeclaredField("x"); //这个管你公的私的,都拿来
fieldX.setAccessible(true);//上面的代码已经看见钱了,开始抢了
fieldX.set(pt1, 2);//抢到手自己改一下
System.out.println(pt1.getX());
//out 2 OK!!
}
2.调用私有方法
//调用私有方法
private static void invokeMethod() throws Exception {
Class<?> clazz = Point.class;//通过Ponit类获取Class实例
//调用Point类中的draw方法
Method method = clazz.getDeclaredMethod("draw", String.class);
method.setAccessible(true);
method.invoke(clazz.newInstance(), "HelloWorld");
}
3.调用构造方法
//调用构造方法
private static void invokeConstructor() throws Exception {
Class<?> clazz = Class.forName("reflection.Point");//通过类名获取Class实例
Point pt1 = null;
Point pt2 = null;
Point pt3 = null;
//取得全部的构造函数
Constructor<?> cons[] = clazz.getConstructors();
for (int i = 0; i < cons.length; i++) {
System.out.println("构造方法: " + cons[i]);
}
//这里构造方法的顺序倒过来了,有点诡异
pt1 = (Point) cons[2].newInstance();
pt2 = (Point) cons[1].newInstance(20);
pt3 = (Point) cons[0].newInstance(49, 81);
System.out.println(pt1);
System.out.println(pt2);
System.out.println(pt3);
}