概念:
百度百科:JAVA反射机制是在运行状态中,对于任意一个实体类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。
java中的类在编译之后都会生成一个.class结尾的字节码文件,这些字节码文件统称为字节码文件类型的对象。也就是说这些文件最终会加载到内存中每一个字节码文件对应一个字节码文件对象(Class类对象)
相关的方法:
得到某个类的Class对象之后,就可以使用该对象的getConstructors(),getFields(),getMethods()等方法得到这个类的构造函数,属性,方法等。这个类中的构造函数,属性,方法等单独拿出来之后会被封装成Constructor,Field,Method等类型的对象。反射就是把java类中的各种成分映射成一个个的Java对象。
获取字节码文件对象:
注意:字节码文件对象只能通过Java虚拟机去创建,不可以用关键字new去创建字节码文件对象。并且一个类在内存中有且只有一个字节码文件对象。
public class reflect {
public static void main(String[] args) throws Exception {
/**
* 方式一
* 通过class属性获取
*/
//基本数据类型
Class<Integer> c1 = int.class;
//引用数据类型
Class<Double> c2 = Double.class;
//自定义数据类型
Class<reflect> c3 = reflect.class;
//接口
Class<reflect_interface> c4 = reflect_interface.class;
/**
* 方式二
* 通过Object定义的getClass方法获取
* 注意:这里调用的getClass方法不能重写,因为在定义的时候已经被final关键字修饰
*/
//对象
ArrayList<String> list = new ArrayList<String>();
Class<? extends ArrayList> c5 = list.getClass();
//数组(讲道理这也是对象)
int[] intarry = new int[]{1,2,3};
Class<? extends int[]> c6 = intarry.getClass();
String[] strarry = {"1","2","3"};
Class<? extends String[]> c7 = strarry.getClass();
/**
* 方式三
* 通过Class类的静态方法forName(类的全路径)
*/
Class<?> c8 = Class.forName("Reflect.reflect");
Class<?> c9 = Class.forName("java.lang.Double");
System.out.println(c1);
System.out.println(c2);
System.out.println(c3);
System.out.println(c4);
System.out.println(c5);
System.out.println(c6);
System.out.println(c7);
//不管用哪一种方法得到的Class对象都是一样的
//哪种方法方便就选取哪种方法
System.out.println(c8 == c3);
System.out.println(c9 == c2);
}
}
结果
int
class java.lang.Double
class Reflect.reflect
interface Reflect.reflect_interface
class java.util.ArrayList
class [I
class [Ljava.lang.String;
true
true
用反射得到方法并调用:
public class reflect {
public void public_show(String name) {
System.out.println("public " + name + " ShowTime");
}
private void private_show(String name) {
System.out.println("private " + name + " ShowTime");
}
protected void protected_show(String name) {
System.out.println("protected " + name + " ShowTime");
}
public static void main(String[] args) throws Exception {
/**
* 得到public方法
*/
//得到reflect的字节码对象
Class c = reflect.class;
//用该对象的getMethod方法得到reflect类中的show方法
//getMethod
//参数一:要得到的方法名
//参数二:该方法参数列表的参数类型的字节码对象(没有参数则不写)
Method show = c.getMethod("public_show", String.class);
//用Method类中的invoke方法使用show方法
//invoke
//参数一:reflect的一个普通对象
//参数二:show方法的参数
show.invoke(new reflect(), "zzf");
//还可以用字节码对象中的newInstance方法来获取一个普通对象
//不过前提是这个类必须有无参构造方法
Object obj = c.newInstance();
show.invoke(obj, "ZZF");
//或者先得到构造方法然后用Constructor对象newInstance这样适用于所有构造方法
Constructor cons = c.getConstructor();
Object obj2 = cons.newInstance();
show.invoke(obj2, "Zzf");
/**
* 得到private方法
* getMethod方法只能得到public的方法
* getDeclaredMethod方法来得到private或protected方法
*/
show = c.getDeclaredMethod("private_show", String.class);
//对私有方法设置可允许访问
show.setAccessible(true);
show.invoke(c.newInstance(), "zzf");
/**
* 得到protected方法
*/
show = c.getDeclaredMethod("protected_show", String.class);
show.invoke(c.newInstance(), "zzf");
/**
* 当然也可以得到全部的public方法
* 用getMethods()
* 用getDeclaredMethods()得到所有的方法包括public,protected,private以及默认
* 还可以通过反射获取main方法逻辑一样
*/
}
}
结果
public zzf ShowTime
public ZZF ShowTime
public Zzf ShowTime
private zzf ShowTime
protected zzf ShowTime
用反射得到构造方法并创建对象:
public class refConstructor {
refConstructor() {
System.out.println("默认 ");
}
public refConstructor(String s) {
System.out.println("public " + s);
}
private refConstructor(String a, String b) {
System.out.println("private " + a + " " + b);
}
protected refConstructor(int a, int b) {
System.out.println("protected " + a + " " + b);
}
public static void main(String[] args) throws Exception {
//获取public有一个参数的构造方法
Class c = refConstructor.class;
//getConstruct有参数就传参数类型没有就不传或者传null
Constructor cons = c.getConstructor(String.class);
//用构造方法创建对象
Object obj = cons.newInstance("zzf");
//获取private有两个参数的构造方法
cons = c.getDeclaredConstructor(String.class, String.class);
//设置可访问
cons.setAccessible(true);
obj = cons.newInstance("zzf","zjz");
//获取protected有两个参数的构造方法
cons = c.getDeclaredConstructor(int.class, int.class);
obj = cons.newInstance(1, 2);
//获取默认没有参数的构造方法
cons = c.getDeclaredConstructor();
obj = cons.newInstance();
/**
* 同样也可以获取所有public的构造方法
* getConstructors()
* 获取所有构造方法包括默认,public,private,protected
* getDeclaredConstructors()
*/
}
}
结果
public zzf
private zzf zjz
protected 1 2
默认
用反射得到属性并赋值:
public class refField {
private String pri = "init";
protected String pro = "init";
public String pub = "init";
String mr = "init";
public static void main(String[] args) throws Exception {
Class c = refField.class;
//用getDeclaredField方法得到private成员变量
Field field = c.getDeclaredField("pri");
//设置可访问
field.setAccessible(true);
//进行赋值
//参数一:一个普通的refField对象
//参数二:需要赋的值
refField obj = new refField();
field.set(obj, "private field");
System.out.println(obj.pri);
//用getDeclaredField方法得到protected成员变量
field = c.getDeclaredField("pro");
//进行赋值
field.set(obj, "protected field");
System.out.println(obj.pro);
//用getDeclaredField方法得到默认成员变量
field = c.getDeclaredField("mr");
//进行赋值
field.set(obj, "默认 field");
System.out.println(obj.mr);
//用getField方法得到public成员变量
field = c.getField("pub");
//进行赋值
field.set(obj, "public field");
System.out.println(obj.pub);
/**
* 同样也可以获取所有public的字段
* getFields()
* 获取所有字段包括默认,public,private,protected
* getDeclaredFields()
*/
}
}
结果
private field
protected field
默认 field
public field
用反射获取父类属性,方法,构造方法:
public class refFather {
private String name = "init";
public refFather(String name) {
this.name = name;
System.out.println(name + " : here is father's constructor.");
}
public void show() {
System.out.println(name + ":I am a father.");
}
}
public class refSon extends refFather{
public refSon(String name) {
super(name);
System.out.println(name + "here is son's constructor.");
}
public static void main(String[] args) throws Exception {
//得到refSon的字节码对象
Class c = Class.forName("Reflect.refSon");
//通过refSon的字节码对象的getSuperclass方法得到父类的字节码对象
Class fc = c.getSuperclass();
Field ffield = fc.getDeclaredField("name");
//设置为可访问
ffield.setAccessible(true);
//通过反射得到父类的构造方法
Constructor fons = fc.getConstructor(String.class);
//通过构造方法创建refFather对象
Object obj = fons.newInstance("ref_zjz");
refFather father = (refFather) obj;
//赋值通过反射得到的变量,赋值为zjz,这时候name的值为zjz
ffield.set(father, "zjz");
//调用普通对象的show方法
System.out.println("*普通show方法*");
father.show();
//通过反射得到父类的show方法
Method fshow = fc.getMethod("show");
//调用反射得到的show方法
System.out.println("*反射得到的show方法*");
fshow.invoke(father);
}
}
结果
ref_zjz : here is father's constructor.
*普通show方法*
zjz:I am a father.
*反射得到的show方法*
zjz:I am a father.
反射的简单应用举例:
用于JavaWeb中servlet做同意拦截,通过反射调用方法做一些验证等处理
用于Android开发中得到一些控件中的private属性或方法并修改得到自己想要的效果
用反射越过泛型检查
public class refGeneric {
public static void main(String[] args) throws Exception {
ArrayList<Integer> list = new ArrayList<Integer>();
list.add(1);
list.add(2);
//这里如果list传入了泛型,那么就有限制,只能添加Integer类型的数据
//list.add("3");
System.out.println(list);
//我们得到list字节码对象
Class c = list.getClass();
//然后得到其中的add方法
Method add = c.getDeclaredMethod("add", Object.class);
//调用方法,传入字符串a
add.invoke(list, "a");
//输出
System.out.println(list);
}
}
结果
[1, 2]
[1, 2, a]