什么是反射?
在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性
这种动态获取的信息以及动态调用对象的方法的功能称为反射机制。
反射的前提:
需要获取代表每个类的java.lang.class对象,对于HotSpot来说,这个class对象保存在在方法区,作为这个类的各种数据的访问入口
获取class对象的方式:
public static void main(String[] args) throws Exception{ //第一种,通过对象获取class对象 A a = new A(); Class aClass = a.getClass(); System.out.println(aClass.getName()); //第二种,通过类直接获取class对象 Class aClass1 = A.class; System.out.println(aClass == aClass1); //第三种,通过类的全限定名获取class对象(包名+类名) Class aClass2 = Class.forName("com.it.exception.A"); System.out.println(aClass == aClass2); }
PS: 一般使用第三种方式来获取
构造函数相关方法:
public class A { public A(int i) { System.out.println("A Constructor " + i); } public A() { System.out.println("A Constructor No Parameter"); } protected A(String name) { System.out.println("A Constructor " + name); } private A(int i, String name) { System.out.println("A Constructor " + i + " name " + name); } }
public static void main(String[] args) throws Exception{ Class aClass = Class.forName("com.it.exception.A"); //返回所有public构造函数 Constructor[] constructors1 = aClass.getConstructors(); for (Constructor constructor : constructors1) { System.out.println(constructor); } System.out.println("----getConstructors---------"); //返回具体某种参数类型的public构造函数,参数也可以是null,表示无参构造器 Constructor constructor = aClass.getConstructor(int.class); System.out.println(constructor); System.out.println("----get int Constructors---------"); //返回所有构造函数,无论什么修饰符修饰 Constructor[] constructors2 = aClass.getDeclaredConstructors(); for (Constructor constructor1 : constructors2) { System.out.println(constructor1); } System.out.println("----getDeclaredConstructors---------"); //返回具体某种参数类型的构造函数,无论什么修饰符修饰 Constructor constructor2 = aClass.getDeclaredConstructor(String.class); System.out.println(constructor2); System.out.println("----String getDeclaredConstructor---------"); }
结果:
public com.it.exception.A() public com.it.exception.A(int) ----getConstructors--------- public com.it.exception.A(int) ----get int Constructors--------- private com.it.exception.A(int,java.lang.String) protected com.it.exception.A(java.lang.String) public com.it.exception.A() public com.it.exception.A(int) ----getDeclaredConstructors--------- protected com.it.exception.A(java.lang.String)
getEnclosingConstructor:
public class Outter { public void destination(String s) { class Inner1 { private String label; public Inner1() { System.out.println("abc"); } public Inner1(String whereTo) { this.label = whereTo; } } Class aClass = new Inner1().getClass(); //获取局部或匿名内部类在定义时所在的构造器 System.out.println(aClass.getEnclosingConstructor()); } public static void main(String[] args) { Outter outter = new Outter(); outter.destination("aaa"); } }
这里实验类局部内部类一直得到的是null,大家可以试一下
调用构造器:
constructor.newInstance(); //默认无参构造器
字段相关方法:
public class A {
private int id;
private String name;
public int sex;
}
public static void main(String[] args) throws Exception{
Class aClass = Class.forName("com.it.exception.A");
//获取所有public字段
Field[] fields = aClass.getFields();
for (Field field : fields) {
System.out.println(field);
}
//获取某个具体字段,这个字段必须是public修饰,否则会报错
Field field = aClass.getField("sex");
System.out.println(field);
//获取所有字段,无论修饰符
Field[] fields1 = aClass.getDeclaredFields();
for (Field field1 : fields1) {
System.out.println(field1);
}
//获取某个具体字段
Field field1 = aClass.getDeclaredField("id");
System.out.println(field1);
}
结果:
public int com.it.exception.A.sex public int com.it.exception.A.sex private int com.it.exception.A.id private java.lang.String com.it.exception.A.name public int com.it.exception.A.sex private int com.it.exception.A.id
其余操作:
public static void main(String[] args) throws Exception{ Class aClass = Class.forName("com.it.exception.A"); Field field = aClass.getDeclaredField("name"); Object object = aClass.getDeclaredConstructor(null).newInstance(); field.setAccessible(true); //设置为true,private字段可以修改,私有字段必须设置为true,否则set字段会发生异常 field.set(object, "sam");//设置具体字段value A a = (A)object; System.out.println(a.toString()); }
结果:
A(id=0, name=sam, sex=0)
方法相关操作:
public class A { private int id; private String name; public int sex; public void add() { System.out.println("add()"); } private void del() { System.out.println("del()"); } public static void update() { System.out.println("static update()"); } } public static void main(String[] args) throws Exception{ Class aClass = Class.forName("com.it.exception.A"); Method[] methods = aClass.getMethods(); //获取所有public字段 for (Method method : methods) { System.out.println(method); } //获取某个具体方法,这个method必须是public修饰,否则会报错 Method method = aClass.getMethod("add", null); System.out.println(method); //获取所有字段,无论修饰符 Method[] methods1 = aClass.getDeclaredMethods(); for (Method method1 : methods1) { System.out.println(method1); } //获取某个具体字段 Method method1 = aClass.getDeclaredMethod("del", null); System.out.println(method1); }
结果:已经省略默认继承object的相关方法
public void com.it.exception.A.add() public static void com.it.exception.A.update() public void com.it.exception.A.add() public void com.it.exception.A.add() public static void com.it.exception.A.update() private void com.it.exception.A.del() private void com.it.exception.A.del()
其余操作:
private int del(int i) { System.out.println("del(): " + i); return i + 3; } public static void main(String[] args) throws Exception{ Class aClass = Class.forName("com.it.exception.A"); Object object = aClass.getDeclaredConstructor(null).newInstance(); Method method = aClass.getDeclaredMethod("del", int.class); method.setAccessible(true); Object object1 = method.invoke(object, 20); System.out.println(object1); }
结果:
del(): 20 23
其他:
public class A extends B implements C{ @Override public void f() throws IOException { System.out.println("f()"); } } public static void main(String[] args) throws Exception{ Class aClass = Class.forName("com.it.exception.A"); System.out.println(aClass.getSuperclass());// 获取父类Class对象 System.out.println(aClass.getClassLoader());// 获取类的加载器 System.out.println(aClass.getInterfaces()[0]);// 获取类的接口数组列表 A[] as = new A[1]; System.out.println(as.getClass().getComponentType());// 获取该数组的Class对象 System.out.println(aClass.getPackage().getName());// 获取包 }
结果:
class com.it.exception.B sun.misc.Launcher$AppClassLoader@18b4aac2 interface com.it.exception.C class com.it.exception.A com.it.exception
通过反射越过泛型检查
public static void main(String[] args) throws Exception{ ArrayList<String> list = new ArrayList<>(); list.add("a"); list.add("b"); // List<String> list = Arrays.asList("a", "b"); Class aClass = list.getClass(); Method method = aClass.getMethod("add", Object.class); method.invoke(list, 20); System.out.println(list); // list.forEach(s -> { // System.out.println(s); // }); }
结果:List<String> list = Arrays.asList("a", "b");然后执行invoke()会报错的,也不要使用foreach也会报错(ClassCastException)