反射定义
官方解释:反射通常用来检测和改变java在虚拟机中的表现。
通俗来讲反射就是通过非常规手段在程序运行时修改程序的行为。
反射入口
Class
反射其实就是为一个类提供通用说明书Class,
注意的是 Class 是首字母大写,不同于 class 小写,class 是定义类的关键字,而 Class 的本质也是一个类,因为在 Java 中一切都是对象。
把 Java 虚拟机类似于高速公路,那么 Class 就是用来描述公路上飞驰的汽车,也就是我前面提到的规格说明书。
Class的获取
反射的入口是 Class,但是反射中 Class 是没有公开的构造方法的,所以就没有办法像创建一个类一样通过 new 关键字来获取一个 Class 对象。获取方式如下:
1.通过Object.getClass()。
对于一个对象而言,如果这个对象可以访问,那么调用
getClass()
方法就可以获取到了它的相应的 Class 对象。public class Reflect {
public static void get(){
System.out.println("hello");
}
public static void main(String[] args) {
Reflect reflect=new Reflect();
Class clazz=reflect.getClass();
}
}
值得注意的是,这种方法不适合基本类型如 int、float 等等。
2.通过.class获取
public class Reflect {
public static void get(){
System.out.println("hello");
}
public static void main(String[] args) {
Class clazz2=Reflect.class;
Class a=int.class;
Class b=String.class;
}
}
3.通过Class.forname()
public class Reflect {
public static void get(){
System.out.println("hello");
}
@SneakyThrows
public static void main(String[] args) {
Class c=Class.forName("com.ssm.study.Reflect");
}
}
Class的名字
涉及到Api
Class.getName();
Class是一个入口,代表引用,基本数据类型,对象数组。
1.当Class代表一个引用时,getName()返回的是二进制字符串。eg:"com.ssm.study.Reflect"
2.当Class代表一个基本类型时,getName()返回的是它们的关键字。eg:int.class->int
3.当Class代表一个基本类型的数组时,getName()返回 [[[I 这样的字符串
public class Reflect {
public static void get(){
System.out.println("hello");
}
@SneakyThrows
public static void main(String[] args) {
Class c=Class.forName("com.ssm.study.Reflect");
c.getName();
c.getCanonicalName();
c.getSimpleName();
Class a=int.class;
Class b=new int[]{}.getClass();
System.out.println(a.getName());
System.out.println(b.getName());
System.out.println(c.getName());
}
}
效果:
Class获取修饰符
Class的修饰符主要有:
- 用来限制作用域,如 public、protected、priviate。
- 用来提示子类复写,abstract。
- 用来标记为静态类 static。
- 注解。
System.out.println(Modifier.toString(Reflect.class.getModifiers()));
效果:
获取Class的成员
class的成员包括Field、Method、Constructor。
getDeclaredField() 获取的是 Class 中被 private 修饰的属性。
getField() 方法获取的是非私有属性,并且 getField() 在当前 Class 获取不到时会向祖先类获取。
//获取所有的属性,但不包括从父类继承下来的属性
public Field[] getDeclaredFields() throws SecurityException {}
//获取自身的所有的 public 属性,包括从父类继承下来的。
public Field[] getFields() throws SecurityException {}
eg:
public class Father {
private int a;
int b;
public int d;
}
public class Son extends Father {
private int c;
public int e;
}
public class Reflect {
@SneakyThrows
public static void main(String[] args) {
System.out.println(Modifier.toString(Reflect.class.getModifiers()));
Class son=Son.class;
System.out.println(son.getDeclaredField("b"));
}
}
public class Father { private int a; int b; public int d; }
public class Son extends Father {
private int c; public int e; }
public class Reflect { @SneakyThrows public static void main(String[] args) { System.out.println(Modifier.toString(Reflect.class.getModifiers())); Class son=Son.class; System.out.println(son.getDeclaredField("b")); } }
public class Reflect {
@SneakyThrows
public static void main(String[] args) {
System.out.println(Modifier.toString(Reflect.class.getModifiers()));
Class son=Son.class;
/* System.out.println(son.getDeclaredField("b"));*/
Field[] fields=son.getDeclaredFields();
for (Field filed:
fields ) {
System.out.println("getDeclaredFields():"+filed.getName());
}
Field[] fields1=son.getFields();
for (Field filed:
fields1 ) {
System.out.println("getFields():"+filed.getName());
}
}
}
tips:如何获取父类中的非public的属性
public class Reflect { public void say() { System.out.println("hello"); } @SneakyThrows public static void main(String[] args) { Field[] declaredFields = Son.class.getSuperclass().getDeclaredFields(); for (Field field:declaredFields ) { System.out.println("Son父类的属性"+field.getName()); } } }效果:
两张图对比说明:
获取Constructor
代码1:
public class Father { private int a; int b; public int d; public Father() { super(); } }
public class Son extends Father { private int c; public int e; private Son() { super(); } public Son(int c, int e) { super(); this.c = c; this.e = e; } }
public class Reflect { @SneakyThrows public static void main(String[] args) { System.out.println(Modifier.toString(Reflect.class.getModifiers())); Class son=Son.class; /* System.out.println(son.getDeclaredField("b"));*/ Field[] fields1=son.getDeclaredFields(); for (Field filed: fields1 ) { System.out.println("getDeclaredFields():"+filed.getName()); } Field[] fields2=son.getFields(); for (Field filed: fields2 ) { System.out.println("getFields():"+filed.getName()); } Constructor[] constructors1=son.getDeclaredConstructors(); for (Constructor constructor: constructors1) { System.out.println("getDeclaredConstructors:"+constructor.toString()); } Constructor[] constructors2=son.getConstructors(); for (Constructor constructor: constructors2) { System.out.println("getConstructors:"+constructor.toString()); } } }效果:
通过invoke调用方法
public class Reflect { public void say(String...args) { for (String s:args ) { System.out.println(s); } } @SneakyThrows public static void main(String[] args) { //获取字节码对象 Class clazz=Class.forName("com.ssm.study.Reflect"); //获取一个对象 Constructor constructor = clazz.getConstructor(); Reflect r= (Reflect) constructor.newInstance(); String[] s=new String[]{"aa","bb"}; //获取method对象 Method getA = clazz.getMethod("say", String[].class); //调用invoke方法来调用 //将传递进去的s强转为Object类型 getA.invoke(r, new Object[]{s}); //将s重新包装成一个Object数组 getA.invoke(r,(Object) s); } }
效果: