根据需求引出反射
要是说半天反射是什么怎么做,新手看完还是一头雾水,我们先来看看什么时候会使用到反射
现有一个配置文件re.properties的配置信息和定义好的Cat类如下:
re.properties
classFullPath=com.npc.Cat
method=hi
Cat.class
public class Cat {
private String name = "招财猫";
public int age = 10;
public Cat() {}
public void hi() {
System.out.println("hi, " + name);
}
public void cry() { //常用方法
System.out.println(name + " 喵喵叫..");
}
}
如何根据配置文件的指定信息创建Cat对象和调用hi方法?
首先理所当然想到的是
Cat cat = new Cat();
cat.hi();
但是这又引发了一个问题那就是我们将配置文件中method修改为cry, 这时又要改动已经写好的代码调用cry方法
method=cry
这时,反射的作用就出来了,接下来看看如何使用反射创建对象并调用method的指定方法
//1. 使用Properties 类, 可以读写配置文件
Properties properties = new Properties();
properties.load(new FileInputStream("src//re.properties"));
String classFullPath = properties.getProperty("classFullPath");
String methodName = properties.getProperty("method");
// 使用反射机制解决
// (1) 加载类, 返回Class类型的对象cls
Class cls = Class.forName(classFullPath);
// (2) 通过 cls 得到你加载的类 com.npc.Cat 的对象实例
Object object = cls.newInstance();
// (3) 通过 cls 得到你加载的类 com.npc.Cat 的 methodName"cry" 的方法对象
Method method1 = cls.getMethod(methodName);
method1.invoke(object);
这种通过外部文件配置,在不修改源码的情况下控制程序的方式,符合设计模式的开闭原则
反射
概述
反射即Reflection,指程序在运行期可以拿到一个对象的所有信息。
类加载之后会在堆中产生一个java.lang.Class对象,一个类有且只有一个Class对象。这个Class对象包含了类的完整结构信息,Class对象就像一面镜子,通过这个镜子能看到类的结构,所以形象的称之为反射。
Java反射机制原理示意图
反射能做什么
- 在运行时判断任意一个对象所属的类
- 在运行时构造任意一个类的对象
- 在运行时得到任意一个类的成员变量和方法
- 在运行时调用任意一个对象的成员变量和方法
- 生成动态代理
反射相关的主要类
- java.lang.Class 代表一个类,表示一个类加载后在堆中的对象
- java.lang.reflect.Constructor 代表类的构造器,
- java.lang.reflect.Field 代表类的成员变量
- java.lang.reflect.Method 代表类的方法
快速入门
public class ReflectionUtils {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException {
api_01();
api_02();
}
public static void api_01() throws ClassNotFoundException, NoSuchMethodException {
//得到Class对象
Class<?> personCls = Class.forName("com.hspedu.reflection.Person");
//getName:获取全类名
System.out.println(personCls.getName());//com.hspedu.reflection.Person
//getSimpleName:获取简单类名
System.out.println(personCls.getSimpleName());//Person
//getFields:获取所有public修饰的属性,包含本类以及父类的
Field[] fields = personCls.getFields();
for (Field field : fields) {
System.out.println("本类以及父类的属性=" + field.getName());
}
//getDeclaredFields:获取本类中所有属性
Field[] declaredFields = personCls.getDeclaredFields();
for (Field declaredField : declaredFields) {
System.out.println("本类中所有属性=" + declaredField.getName());
}
//getMethods:获取所有public修饰的方法,包含本类以及父类的
Method[] methods = personCls.getMethods();
for (Method method : methods) {
System.out.println("本类以及父类的方法=" + method.getName());
}
//getDeclaredMethods:获取本类中所有方法
Method[] declaredMethods = personCls.getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
System.out.println("本类中所有方法=" + declaredMethod.getName());
}
//getConstructors: 获取所有public修饰的构造器,包含本类
Constructor<?>[] constructors = personCls.getConstructors();
for (Constructor<?> constructor : constructors) {
System.out.println("本类的构造器=" + constructor.getName());
}
//getDeclaredConstructors:获取本类中所有构造器
Constructor<?>[] declaredConstructors = personCls.getDeclaredConstructors();
for (Constructor<?> declaredConstructor : declaredConstructors) {
System.out.println("本类中所有构造器=" + declaredConstructor.getName());//这里老师只是输出名
}
//getPackage:以Package形式返回 包信息
System.out.println(personCls.getPackage());//com.hspedu.reflection
//getSuperClass:以Class形式返回父类信息
Class<?> superclass = personCls.getSuperclass();
System.out.println("父类的class对象=" + superclass);
//getInterfaces:以Class[]形式返回接口信息
Class<?>[] interfaces = personCls.getInterfaces();
for (Class<?> anInterface : interfaces) {
System.out.println("接口信息=" + anInterface);
}
//getAnnotations:以Annotation[] 形式返回注解信息
Annotation[] annotations = personCls.getAnnotations();
for (Annotation annotation : annotations) {
System.out.println("注解信息=" + annotation);//注解
}
}
public static void api_02() throws ClassNotFoundException, NoSuchMethodException {
//得到Class对象
Class<?> personCls = Class.forName("com.hspedu.reflection.Person");
//getDeclaredFields:获取本类中所有属性
//规定 说明: 默认修饰符 是0 , public 是1 ,private 是 2 ,protected 是 4 , static 是 8 ,final 是 16
Field[] declaredFields = personCls.getDeclaredFields();
for (Field declaredField : declaredFields) {
System.out.println("本类中所有属性=" + declaredField.getName()
+ " 该属性的修饰符值=" + declaredField.getModifiers()
+ " 该属性的类型=" + declaredField.getType());
}
//getDeclaredMethods:获取本类中所有方法
Method[] declaredMethods = personCls.getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
System.out.println("本类中所有方法=" + declaredMethod.getName()
+ " 该方法的访问修饰符值=" + declaredMethod.getModifiers()
+ " 该方法返回类型" + declaredMethod.getReturnType());
//输出当前这个方法的形参数组情况
Class<?>[] parameterTypes = declaredMethod.getParameterTypes();
for (Class<?> parameterType : parameterTypes) {
System.out.println("该方法的形参类型=" + parameterType);
}
}
//getDeclaredConstructors:获取本类中所有构造器
Constructor<?>[] declaredConstructors = personCls.getDeclaredConstructors();
for (Constructor<?> declaredConstructor : declaredConstructors) {
System.out.println("====================");
System.out.println("本类中所有构造器=" + declaredConstructor.getName());//这里只是输出名
Class<?>[] parameterTypes = declaredConstructor.getParameterTypes();
for (Class<?> parameterType : parameterTypes) {
System.out.println("该构造器的形参类型=" + parameterType);
}
}
}
}
class A {
public String hobby;
public void hi() {
}
public A() {
}
public A(String name) {
}
}
interface IA {
}
interface IB {
}
@Deprecated
class Person extends A implements IA, IB {
//属性
public String name;
protected static int age; // 4 + 8 = 12
String job;
private double sal;
//构造器
public Person() {
}
public Person(String name) {
}
//私有的
private Person(String name, int age) {
}
//方法
public void m1(String name, int age, double sal) {
}
protected String m2() {
return null;
}
void m3() {
}
private void m4() {
}
}
Class类
概述
Class类图
-
Class也是类,因此也继承自Object类。
-
通过Class对象可以完整地得到一个类的结构。
-
Class对象是类加载时在加载阶段自动创建的,因为一个类只加载一次所以某个类的java.lang.Class类对象有且只有一个。
-
Class对象是存放在堆中的,同样在加载阶段的创建的类元信息放在方法区(二进制字节流),。
常用方法
获取Class对象方式
-
Class.forName()
-
Cat.class
-
cat.getClass()
-
cat.getClass().getClassLoader().loadClass()
-
基本数据类型.class
-
包装类.TYPE
哪些类型有Class对象
- 外部类,成员内部类,静态内部类,局部内部类,匿名内部类
- interface:接口
- 数组
- enum:枚举类
- annotation:注解
- 基本数据类型
- void
Constructor
public class ReflectCreateInstance {
public static void main(String[] args) throws Exception{
Class<?> userCls = Class.forName("npc.create.User");
Object o = userCls.newInstance();
System.out.println(o);
Constructor<?> constructor = userCls.getConstructor(int.class);
Object o1 = constructor.newInstance(12);
System.out.println(o1);
Constructor<?> declaredConstructor = userCls.getDeclaredConstructor(int.class, String.class, int.class);
declaredConstructor.setAccessible(true);
Object npc = declaredConstructor.newInstance(3, "NPC", 3);
System.out.println(npc);
}
}
class User {
int id;
String name;
int age;
public User() {
}
public User(int id) {
this.id = id;
}
private User(int id, String name, int age) {
this.id = id;
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "id:" + id +" name:" + name + " age: " + age;
}
}
Field
public class ReflectAccessProperty {
public static void main(String[] args) throws Exception{
Class<?> userCls = Class.forName("npc.field.User");
Object o = userCls.newInstance();
for (Field field : userCls.getFields()) {
System.out.println(field);
}
Field f1 = userCls.getField("f1");
System.out.println(f1);
System.out.println(f1.get(o));
f1.set(o, 100);
System.out.println(f1.get(o));
Field f2 = userCls.getDeclaredField("f2");
System.out.println(f2);
System.out.println(f2.getModifiers());
f2.setAccessible(true);
System.out.println(f2.get(o));
f2.set(o, 100);
System.out.println(f2.get(o));
Field f3 = userCls.getDeclaredField("f3");
System.out.println(f3);
System.out.println(f3.get(o));
f3.set(null, 100);
System.out.println(f3.get(o));
}
}
class User{
public int f1;
private int f2;
static int f3 = 6;
@Override
public String toString() {
return f1 + " " + f2 + " static:" + f3;
}
}
Method
public class ReflectAccessMethod {
public static void main(String[] args) throws Exception {
Class<?> cls = Class.forName("npc.method.Boss");
Object o = cls.newInstance();
Method m1 = cls.getMethod("m1");
Object invoke = m1.invoke(o);
System.out.println(invoke);
Method hi = cls.getMethod("hi", String.class);
Object npc = hi.invoke(o, "npc");
System.out.println(npc);
Method say = cls.getDeclaredMethod("say", int.class, String.class, char.class);
say.setAccessible(true);
Object invoke1 = say.invoke(null, 1, "1", 'c');
System.out.println(invoke1);
}
}
class Monster {
@Override
public String toString() {
return "monster";
}
}
class Boss {//类
public int age;
private static String name;
public Boss() {//构造器
}
public Monster m1() {
return new Monster();
}
private static String say(int n, String s, char c) {//静态方法
return n + " " + s + " " + c;
}
public void hi(String s) {//普通 public 方法
System.out.println("hi " + s);
}
}