Java反射详解

一,打破砂锅问到底

  1. 什么是反射以及反射存在的意义
  2. 反射的原理是什么
  3. 什么是Class,里面都描述了类的什么信息
  4. 如何使用反射获取类信息(实例,属性,方法等)
  5. 反射是如何在开发中被运用的


    Java反射详解.png

二,晓之以理,动之以码

反射机制测试类完整代码:Github

1. 反射定义与存在意义

Reflection(反射)是指程序在运行时才会知道要操作的类是什么,并且可以在运行时借助于反射API取得任何类的內部信息,并能直接操作任何对象的内部属性及方法。

反射的功能:

Java反射机制是Java被视为动态语言的关键,反射被广泛地用于那些需要在运行时检测或修改程序行为的程序中。它通过Class对象主要提供了以下功能:

  • 访问隐藏属性或者调用方法改变程序原来的逻辑
  • 在开发中动态加载类(组件化,插件化,Hook)
  • 在运行时操作任意一个类的对象;
  • 在运行时操作任意一个类的Constructer;
  • 在运行时操作任意一个类的Method;
  • 在运行时操作任意一个类的Field;
  • 在运行时操作任意一个类的Interface;
  • 在运行时操作任意一个类的ClassLoader;
  • 在运行时操作任意一个类的Annotation;

反射的缺点:

  • 性能第一 反射包括了一些动态类型,所以JVM无法对这些代码进行优化。因此,反射操作的效率要比那些非反射操作低得多。我们应该避免在经常被 执行的代码或对性能要求很高的程序中使用反射。

  • 安全限制 使用反射技术要求程序必须在一个没有安全限制的环境中运行。

  • 内部暴露 由于反射允许代码执行一些在正常情况下不被允许的操作(比如访问私有的属性和方法),所以使用反射可能会导致意料之外的副作用--代码有功能上的错误,降低可移植性。反射代码破坏了抽象性,因此当平台发生改变的时候,代码的行为就有可能也随着变化。

2. 描述类的类:Class

每个类的运行时的类型信息就是用Class对象表示的。它包含了与类有关的信息。其实我们的实例对象就通过Class对象来创建的。

每一个类都有一个Class对象,每当编译一个新类Jdk就产生一个Class对象,包括引用类型,基本类型,数组类型,甚至是关键字也有Class对象

验证所有的类都是Class类的实例对象

System.out.println("-----每一个类都有一个Class对象,每当编译一个新类就产生一个Class对象,基本类型,引用类型,数组以及关键字都有Class对象-----");
System.out.println(int.class.getName());
System.out.println(Integer.TYPE); //int
System.out.println(Integer.class.getName());
System.out.println(char.class.getName());
System.out.println(short.class.getName());
System.out.println(long.class.getName());
System.out.println(byte.class.getName());
System.out.println(float.class.getName());
System.out.println(double.class.getName());
System.out.println(boolean.class.getName());
System.out.println(void.class.getName());
System.out.println(char[].class.getName());//[C
System.out.println(char[][].class.getName());//[[C
System.out.println(void.class.getName());
System.out.println(Person.class.getName());

运行结果:

-----每一个类都有一个Class对象,每当编译一个新类就产生一个Class对象,基本类型,引用类型,数组以及关键字都有Class对象-----
int
int
java.lang.Integer
char
short
long
byte
float
double
boolean
void
[C
[[C
void
com.jay.java.反射.ReflectMainTest$Person

Java获取一个类的Class对象的四种方式

System.out.println("-----Java获取一个类的Class对象的四种方式-----");
//定义两个类型都未知的Class , 设置初值为null, 看看如何给它们赋值成Person类
Class<?> class1 = null;
Class<?> class2 = null;
Class<?> class3 = null;
Class<?> class4 = null;

//写法1, 可能抛出 ClassNotFoundException [多用这个写法]
System.out.println("-----写法1:Class.forName(class name)-----");
class1 = Class.forName(Person.CLASS_NAME);
System.out.println("Class1类的包名: " + class1.getClass().getPackage().getName());
System.out.println("Class1类的完整类名: " + class1.getClass().getName());

//写法1, 可能抛出 ClassNotFoundException [多用这个写法]
System.out.println("-----写法1:Class.forName(class name)-----");
class1 = Class.forName(Child.CLASS_NAME);
System.out.println("Class1类的包名: " + class1.getClass().getPackage().getName());
System.out.println("Class1类的完整类名: " + class1.getClass().getName());

//写法2
System.out.println("-----写法2:Person.class-----");
class2 = Person.class;
System.out.println("Class2类的包名: " + class2.getPackage().getName());
System.out.println("Class2类的完整类名: " + class2.getClass().getName());

//写法3
System.out.println("-----写法3: personInstance.getClass()-----");
Person personInstance = new Person();
class3 = personInstance.getClass();
System.out.println("Class3类的包名: " + class3.getPackage().getName());
System.out.println("Class3类的完整类名: " + class3.getClass().getName());

//写法4
//Classloader中loadClass()方法和Class.forName()区别?
//lass.forName(className)方法,内部实际调用的方法是  Class.forName(className,true,classloader);x
//第2个boolean参数表示类是否需要初始化,  Class.forName(className)默认是需要初始化。
//一旦初始化,就会触发目标对象的 static块代码执行,static参数也也会被再次初始化。
//
//ClassLoader.loadClass(className)方法,内部实际调用的方法是  ClassLoader.loadClass(className,false);
//第2个 boolean参数,表示目标对象是否进行链接,false表示不进行链接,由上面介绍可以,
//不进行链接意味着不进行包括初始化等一些列步骤,那么静态块和静态对象就不会得到执行
System.out.println("-----写法4: ClassLoader.getSystemClassLoader().loadClass(Person.CLASS_NAME)-----");
class4 = ClassLoader.getSystemClassLoader().loadClass(Person.CLASS_NAME);
System.out.println("Class4类的包名: " + class4.getPackage().getName());
System.out.println("Class4类的完整类名: " + class4.getClass().getName());

运行结果:

-----Java获取一个类的Class对象的四种方式-----
-----写法1:Class.forName(class name)-----
我是静态代码块
Class1类的包名: java.lang
Class1类的完整类名: java.lang.Class
-----写法1:Class.forName(class name)-----
Class1类的包名: java.lang
Class1类的完整类名: java.lang.Class
-----写法2:Person.class-----
Class2类的包名: com.jay.java.反射
Class2类的完整类名: java.lang.Class
-----写法3: personInstance.getClass()-----
我是无参数构造方法
Class3类的包名: com.jay.java.反射
Class3类的完整类名: java.lang.Class
-----写法4: ClassLoader.getSystemClassLoader().loadClass(Person.CLASS_NAME)-----
Class4类的包名: com.jay.java.反射
Class4类的完整类名: java.lang.Class

3. 通过Class获取类实例

System.out.println("-----Demo2-----\n\n");
Class<?> class1 = null;
Class<?> class2 = null;
Class<?> class3 = null;
//写法1
class1 = Class.forName(Person.CLASS_NAME);
//由于这里不能带参数,所以你要实例化的这个类Person,一定要有无参构造函数
Person person = (Person) class1.newInstance();
person.setAge(20);
person.setName("王五");
System.out.println("Person1: " + person.getName() + " : " + person.getAge());

//写法2
class2 = Person.class;
Person person2 = (Person) class2.newInstance();
person2.setAge(30);
person2.setName("赵六");
System.out.println("Person2: " + person.getName() + " : " + person.getAge());

//写法3
class3 = ClassLoader.getSystemClassLoader().loadClass(Person.CLASS_NAME);
Person person3 = (Person) class3.newInstance();
person3.setAge(50);
person3.setName("小七");
System.out.println("Person3: " + person.getName() + " : " + person.getAge());

运行结果

-----Demo2-----


-----写法1:Class.forName(class name)-----
我是静态代码块
我是无参数构造方法
我的年龄是:20
我的名字是:王五
Person1: 王五 : 20
-----写法2:Person.class-----
我是无参数构造方法
我的年龄是:30
我的名字是:赵六
Person2: 王五 : 20
-----写法3: ClassLoader.getSystemClassLoader().loadClass(Person.CLASS_NAME)-----
我是无参数构造方法
我的年龄是:50
我的名字是:小七
Person3: 王五 : 20

4. 通过Class获取Constructor

System.out.println("-----Demo3-----\n\n");
Class<?> class1 = Class.forName(Person.CLASS_NAME);
Person person1 = null;
Person person2 = null;

System.out.println("-----获取全部Constructor对象-----");
//得到一系列构造函数集合
Constructor<?>[] constructors = class1.getConstructors();
for (Constructor<?> constructor : constructors) {
    System.out.println(constructor);
}

System.out.println("-----从构造器集合中获取某一个Constructor 对象,----");
Constructor<?> constructor2 = constructors[0];
System.out.println(constructor2);

System.out.println("-----调用构造器的 newInstance() 方法创建对象-----");
//集合中构造器的顺序是按照类中的构造器的前后顺序
person1 = (Person) constructor2.newInstance();
person1.setAge(30);
person1.setName("Jay");
System.out.println("Demo4: person1: " + person1.getName() + " : " + person1.getAge());


System.out.println("-----获取某一个Constructor 对象,需要参数列表----");
Constructor<?> constructor
= class1.getConstructor(String.class, int.class);
System.out.println(constructor);

System.out.println("-----调用构造器的 newInstance() 方法创建对象-----");
person2 = (Person) constructor.newInstance("JayDroid", 20);
System.out.println("Demo4: person2: " + person2.getName() + " : " + person2.getAge());

运行结果

-----Demo3-----


我是静态代码块
-----获取全部Constructor对象-----
public com.jay.java.反射.ReflectMainTest$Person()
public com.jay.java.反射.ReflectMainTest$Person(java.lang.String,int)
-----从构造器集合中获取某一个Constructor 对象,----
public com.jay.java.反射.ReflectMainTest$Person()
-----调用构造器的 newInstance() 方法创建对象-----
我是无参数构造方法
我的年龄是:30
我的名字是:Jay
person1: Jay : 30
-----获取某一个Constructor 对象,需要参数列表----
public com.jay.java.反射.ReflectMainTest$Person(java.lang.String,int)
-----调用构造器的 newInstance() 方法创建对象-----
我是两个参数构造方法
我的名字是:JayDroid ,我的年龄是20
person2: JayDroid : 20

5. 通过Class获取Field

System.out.println("-----Demo4-----\n\n");
Class<?> class1 = Class.forName(Person.CLASS_NAME);
Class<?> class2 = Class.forName(Child.CLASS_NAME);
Person person = (Person) class1.newInstance();

System.out.println("-----获取公用和私有的所有字段,但不能获取父类字段-----");
//getDeclaredFields()返回Class中所有的字段,包括私有字段,不能获取父类的任何字段
//getFields()只返回公有字段,即有public修饰的字段,包括父类中的所有共有字段
Field[] fields = class1.getDeclaredFields();
for (Field field : fields) {
    System.out.print(" " + field.getName());
}
System.out.println();

System.out.println("-----获取指定字段-----");
Field field = class1.getDeclaredField("name");
System.out.println("字段名:" + field.getName());

System.out.println("-----获取指定字段的值-----");
person.setAge(30);
person.setName("赵六");
// 获取name字段的值
Object val = field.get(person);
System.out.println(field.getName() + "=" + val);

System.out.println("-----设置指定对象指定字段的值-----");
//设置name字段的值
field.set(person, "Jay");
System.out.println(field.getName() + "=" + person.getName());

System.out.println("-----字段是私有的,不管是读值还是写值,都必须先调用setAccessible(true)方法-----");
//比如Person类中,字段name字段是非私有的,age是私有的
field = class1.getDeclaredField("age");
field.setAccessible(true);
//获取私有属性的值
Object val2 = field.get(person);
System.out.println(field.getName() + "=" + val2);
//设置私有属性的值
field.set(person, 100);
System.out.println(field.getName() + "=" + person.getAge());

运行结果

-----Demo4-----


我是静态代码块
我是无参数构造方法
-----获取公用和私有的所有字段,但不能获取父类字段-----
 CLASS_NAME name age
-----获取指定字段-----
字段名:name
-----获取指定字段的值-----
我的年龄是:30
我的名字是:赵六
name=赵六
-----设置指定对象指定字段的值-----
name=Jay
-----字段是私有的,不管是读值还是写值,都必须先调用setAccessible(true)方法-----
age=30
age=100

6. 通过Class获取Method


System.out.println("-----Demo5-----\n\n");

Class<?> class1 = Class.forName(Person.CLASS_NAME);
Class<?> class2 = Class.forName(Child.CLASS_NAME);

System.out.println("-----获取clazz对应类中的所有方法,不能获取private方法,且获取从父类继承来的所有方法-----");
Method[] methods = class2.getMethods();
for (Method method : methods) {
    System.out.print(" " + method.getName() + "()");
}
System.out.println();

System.out.println("-----获取所有方法,包括私有方法,且只获取当前类的方法-----");
methods = class2.getDeclaredMethods();
for (Method method : methods) {
    System.out.print(" " + method.getName() + "()");
}
System.out.println();

System.out.println("-----获取指定的方法,需要参数名称和参数列表,无参则不需要写-----");
//  方法public void setName(String name) {  }
Method method = class1.getDeclaredMethod("setName", String.class);
System.out.println(method);

// public void setAge(int age) {  }---->int.class
// public void setAge(Integer age) {  }---->Integer.class
// 注意以上两种写法在反射时的区别
method = class1.getDeclaredMethod("setAge", int.class);
System.out.println(method);


System.out.println("-----执行方法,第一个参数表示执行哪个对象的方法,剩下的参数是执行方法时需要传入的实参-----");
Object obje = class1.newInstance();
method.invoke(obje, 18);

System.out.println("-----执行私有方法-----");
//私有方法的执行,必须在调用invoke之前加上一句method.setAccessible(true)
method = class1.getDeclaredMethod("privateMethod");
System.out.println(method);
method.setAccessible(true);
method.invoke(obje);

运行结果

-----Demo5-----


我是静态代码块
-----获取clazz对应类中的所有方法,不能获取private方法,且获取从父类继承来的所有方法-----
 sing() setToy() getToy() climb() walk() getName() setName() setAge() getAge() wait() wait() wait() equals() toString() hashCode() getClass() notify() notifyAll()
-----获取所有方法,包括私有方法,且只获取当前类的方法-----
 sing() setToy() getToy() climb() walk() childPrivateMethod()
-----获取指定的方法,需要参数名称和参数列表,无参则不需要写-----
public void com.jay.java.反射.ReflectMainTest$Person.setName(java.lang.String)
public void com.jay.java.反射.ReflectMainTest$Person.setAge(int)
-----执行方法,第一个参数表示执行哪个对象的方法,剩下的参数是执行方法时需要传入的实参-----
我是无参数构造方法
我的年龄是:18
-----执行私有方法-----
private void com.jay.java.反射.ReflectMainTest$Person.privateMethod()
我是私有构造方法

7. 通过Class获取类加载器

在java中有三种类类加载器:

  1. Bootstrap ClassLoader 引导类加载器:
    此加载器采用c++编写,一般开发中很少见

  2. Extension ClassLoader扩展类加载器:
    用来进行扩展类的加载,一般对应的是jre\lib\ext目录中的类

  3. App ClassLoader系统的类加载器:
    加载classpath指定的类,是最常用的加载器。同时也是java中默认的加载器。

   System.out.println("-----Demo6-----\n\n");

Class<?> class1 = Class.forName(Child.CLASS_NAME);

String nameString = class1.getClassLoader().getClass().getName();

System.out.println("Demo6: 类加载器类名: " + nameString);

System.out.println("-----获取一个系统的类加载器(系统的类加载器,可以获取,当前这个类就是它加载的)-----");
//1. 获取一个系统的类加载器(系统的类加载器 可以获取,当前这个类就是它加载的)
ClassLoader classLoader = ClassLoader.getSystemClassLoader();
System.out.println(classLoader);

System.out.println("-----获取系统类加载器的父类加载器(扩展类加载器,可以获取)-----");
//2. 获取系统类加载器的父类加载器(扩展类加载器,可以获取).
classLoader = classLoader.getParent();
System.out.println(classLoader);

System.out.println("-----获取扩展类加载器的父类加载器(引导类加载器,不可获取)-----");
//3. 获取扩展类加载器的父类加载器(引导类加载器,不可获取).
classLoader = classLoader.getParent();
System.out.println(classLoader);

System.out.println("-----测试当前类由哪个类加载器进行加载(系统类加载器)-----");
//4. 测试当前类由哪个类加载器进行加载(系统类加载器):
classLoader = Class.forName(CLASS_NAME).getClassLoader();
System.out.println(classLoader);

System.out.println("-----测试 JDK 提供的 Object 类由哪个类加载器负责加载(引导类加载器,不可获取)-----");
//5. 测试 JDK 提供的 Object 类由哪个类加载器负责加载(引导类加载器,不可获取)
classLoader = Class.forName("java.lang.Object").getClassLoader();
System.out.println(classLoader);

运行结果


-----Demo6-----


我是静态代码块
Demo6: 类加载器类名: sun.misc.Launcher$AppClassLoader
-----获取一个系统的类加载器(系统的类加载器,可以获取,当前这个类就是它加载的)-----
sun.misc.Launcher$AppClassLoader@18b4aac2
-----获取系统类加载器的父类加载器(扩展类加载器,可以获取)-----
sun.misc.Launcher$ExtClassLoader@5e2de80c
-----获取扩展类加载器的父类加载器(引导类加载器,不可获取)-----
null
-----测试当前类由哪个类加载器进行加载(系统类加载器)-----
sun.misc.Launcher$AppClassLoader@18b4aac2
-----测试 JDK 提供的 Object 类由哪个类加载器负责加载(引导类加载器,不可获取)-----
null

8. 通过Class获取类的其它信息(接口,注解,修饰符等)

System.out.println("-----Demo7-----\n\n");

Class<?> class1 = Class.forName(Child.CLASS_NAME);

Class<?> class2 = Class.forName(Person.CLASS_NAME);

System.out.println("-----取得类的包名和全类名-----");
System.out.println("类的包名: " + class1.getPackage().getName());
System.out.println("类的完整类名: " + class1.getName());

System.out.println("-----取得父类名称-----");
Class<?> superClass = class1.getSuperclass();
System.out.println("当前类的父类名: " + superClass.getName());

System.out.println("-----取得类中的属性----");
Field[] fields = class1.getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
    System.out.println("类中的成员: " + fields[i]);
}

System.out.println("-----取得类方法----");
Method[] methods = class1.getDeclaredMethods();
for (int i = 0; i < methods.length; i++) {
    System.out.println("函数名:" + methods[i].getName());
    System.out.println("函数返回类型:" + methods[i].getReturnType());
    System.out.println("函数访问修饰符:" + Modifier.toString(methods[i].getModifiers()));
    System.out.println("函数代码写法: " + methods[i]);
    System.out.println(" -----------------");
}

System.out.println("-----取得类构造方法----");
Constructor<?>[] constructors = class2.getConstructors();
for (Constructor<?> constructor : constructors) {
    System.out.println(constructor);
}

System.out.println("-----测试当前类由哪个类加载器进行加载(系统类加载器)-----");
ClassLoader classLoader = class1.getClassLoader();
System.out.println(classLoader);

System.out.println("-----取得类实现的接口----");
//取得类实现的接口,因为接口类也属于Class,所以得到接口中的方法也是一样的方法得到
Class<?> interfaces[] = class1.getInterfaces();
for (int i = 0; i < interfaces.length; i++) {
    System.out.println("实现的接口类名: " + interfaces[i].getName());
    for (int j = 0; j < interfaces[i].getDeclaredMethods().length; j++) {
System.out.print("函数代码写法: " + methods[i] + ",");
    }
}
System.out.println();


System.out.println("-----取得类注解----");
Annotation[] annotations = class2.getAnnotations();
for (int j = 0; j < annotations.length; j++) {
    System.out.print("所有注解信息:" + annotations[j] + ",");
}
System.out.println();
ClassAnnotation annotation = class2.getAnnotation(ClassAnnotation.class);
System.out.println("path=" + annotation.path() + "\tdesc=" + annotation.desc());

运行结果

-----Demo7-----


我是静态代码块
-----取得类的包名和全类名-----
类的包名: com.jay.java.反射
类的完整类名: com.jay.java.反射.ReflectMainTest$Child
-----取得父类名称-----
当前类的父类名: com.jay.java.反射.ReflectMainTest$Person
-----取得类中的属性----
类中的成员: public static final java.lang.String com.jay.java.反射.ReflectMainTest$Child.CLASS_NAME
类中的成员: private java.lang.String com.jay.java.反射.ReflectMainTest$Child.toy
-----取得类方法----
函数名:walk
函数返回类型:void
函数访问修饰符:public
函数代码写法: public void com.jay.java.反射.ReflectMainTest$Child.walk(int)
         -----------------
函数名:setToy
函数返回类型:void
函数访问修饰符:public
函数代码写法: public void com.jay.java.反射.ReflectMainTest$Child.setToy(java.lang.String)
         -----------------
函数名:climb
函数返回类型:void
函数访问修饰符:public
函数代码写法: public void com.jay.java.反射.ReflectMainTest$Child.climb()
         -----------------
函数名:getToy
函数返回类型:class java.lang.String
函数访问修饰符:public
函数代码写法: public java.lang.String com.jay.java.反射.ReflectMainTest$Child.getToy()
         -----------------
函数名:sing
函数返回类型:void
函数访问修饰符:public
函数代码写法: public void com.jay.java.反射.ReflectMainTest$Child.sing(java.lang.String)
         -----------------
函数名:childPrivateMethod
函数返回类型:void
函数访问修饰符:private
函数代码写法: private void com.jay.java.反射.ReflectMainTest$Child.childPrivateMethod()
         -----------------
-----取得类构造方法----
public com.jay.java.反射.ReflectMainTest$Person()
public com.jay.java.反射.ReflectMainTest$Person(java.lang.String,int)
-----测试当前类由哪个类加载器进行加载(系统类加载器)-----
sun.misc.Launcher$AppClassLoader@18b4aac2
-----取得类实现的接口----
实现的接口类名: com.jay.java.反射.ReflectMainTest$FunctionInterface
函数代码写法: public void com.jay.java.反射.ReflectMainTest$Child.walk(int),函数代码写法: public void com.jay.java.反射.ReflectMainTest$Child.walk(int),
-----取得类注解----
所有注解信息:@com.jay.java.反射.ReflectMainTest$ClassAnnotation(path=com.jay.java.反射.ReflectMainTest$Person, desc=我是描述类的注解信息),
path=com.jay.java.反射.ReflectMainTest$Person desc=我是描述类的注解信息

反射机制测试类完整代码:Github

三,实践出真知

反射机制实践类完整代码:Github

1. 反射与工厂设计模式的实践

工厂模式的特点:客户端的程序类不直接牵扯到对象的实例化管理,只与接口发生关联,通过工厂类获取接口的实例化对象

实现的效果为:富士康工厂可以采用不同的生产线生产不同种类的产品而无需修改工厂类

接口和产品类

  /**
     * 生产手机的接口
     */
    interface Phone {
        void phoneBrand();
    }

    /**
     * 小米手机生产类
     */
    public static class MiPhone implements Phone {

        public static final String CLASS_NAME = "com.jay.java.反射.practice.RefectionPractice$MiPhone";

        @Override
        public void phoneBrand() {
            System.out.println("我是富士康代生产的小米手机");
        }
    }

    /**
     * 华为手机生产类
     */
    public static class HuaWeiPhone implements Phone {

        public static final String CLASS_NAME = "com.jay.java.反射.practice.RefectionPractice$HuaWeiPhone";

        @Override
        public void phoneBrand() {
            System.out.println("我是富士康代生产的华为手机");
        }
    }

    /**
     * 生产电脑的接口
     */
    interface Computer {
        void computerBrand();
    }

    /**
     * 小米笔记本电脑生产类
     */
    public static class MiComputer implements Computer {

        public static final String CLASS_NAME = "com.jay.java.反射.practice.RefectionPractice$MiComputer";

        @Override
        public void computerBrand() {
            System.out.println("我是富士康代生产的小米笔记本电脑");
        }
    }

工厂类

/**
     * 富士康代加工工厂类
     */
    static class Factory {
        /**
         * 获取接口实例化对象,生产线分配系统
         *
         * @param className      接口的子类
         * @param interfaceClass 描述的是一个接口的类型
         * @return 如果子类存在则返回指定接口
         * @throws Exception
         */
        static <T> T getInstance(String className, Class<T> interfaceClass) throws Exception {
            //反射获取各个产品类的实例
            Object object = Class.forName(className).newInstance();
            //将各个产品类转为各自的接口类型
            return interfaceClass.cast(object);
        }
    }

测试类

 /**
     * demo1:反射与工厂设计模式的实践
     * 工厂模式的特点:客户端的程序类不直接牵扯到对象的实例化管理,只与接口发生关联,通过工厂类获取接口的实例化对象
     * 实现的效果为:富士康工厂可以采用不同的生产线生产不同种类的产品而无需修改工厂类
     *
     * @throws Exception
     */
    private static void demo1() throws Exception {
        System.out.println("-----Demo1-----\n\n");
        System.out.println("-----构建手机生产线-----");
        Phone miPhone = Factory.getInstance(MiPhone.CLASS_NAME, Phone.class);
        miPhone.phoneBrand();
        Phone huaWeiPhone = Factory.getInstance(HuaWeiPhone.CLASS_NAME, Phone.class);
        huaWeiPhone.phoneBrand();
        System.out.println("-----构建笔记本电脑生产线-----");
        Computer computer = Factory.getInstance(MiComputer.CLASS_NAME, Computer.class);
        computer.computerBrand();
    }

运行结果:

-----Demo1-----


-----构建手机生产线-----
我是富士康代生产的小米手机
我是富士康代生产的华为手机
-----构建笔记本电脑生产线-----
我是富士康代生产的小米笔记本电脑

2. 反射在Android框架层的应用

 /**
     * 应用启动状态跟踪
     * 一般写在application里面的attachBaseContext()方法里面,因为这个方法时机最早
     *
     * @param context context
     * @throws Exception
     */
    public static void hookHandler(Context context) throws Exception {
        //反射获取ActivityThread的Class对象
        Class<?> activityThreadClass = Class.forName("android.app.ActivityThread");
        //获取currentActivityThread私有方法
        Method currentActivityThreadMethod = activityThreadClass.getDeclaredMethod("currentActivityThread");
        currentActivityThreadMethod.setAccessible(true);
        //执行currentActivityThreadMethod获取主线程对象
        Object activityThread = currentActivityThreadMethod.invoke(null);
        //获取mH字段
        Field mH = activityThreadClass.getDeclaredField("mH");
        mH.setAccessible(true);
        //获取mH私有字段的值
        Handler handler = (Handler) mH.get(activityThread);
        //反射获取Handler中原始的mCallBack字段
        Field mCallBack = Handler.class.getDeclaredField("mCallback");
        mCallBack.setAccessible(true);
        //这里设置了我们自己实现了接口的CallBack对象
        mCallBack.set(handler, new CustomHandler(handler));
    }

    /**
     * 用于应用初始化异步通信Handler,可以截获发送的一系列事件
     */
    public static class CustomHandler implements Handler.Callback {
        private Handler origin;

        public CustomHandler(Handler mHandler) {
            this.origin = mHandler;
        }

        @Override
        public boolean handleMessage(Message msg) {
            Log.d(TAG, "CustomHandler-handleMessage-" + H.codeToString(msg.what));
            //这样每次启动的时候可以做些额外的事情
            origin.handleMessage(msg);
            return false;
        }
    }

Android 源码中的一些状态值

 public static class H {
        public static final int BIND_APPLICATION = 110;
        public static final int EXIT_APPLICATION = 111;
        public static final int RECEIVER = 113;
        public static final int CREATE_SERVICE = 114;
        public static final int SERVICE_ARGS = 115;
        public static final int STOP_SERVICE = 116;
        public static final int CONFIGURATION_CHANGED = 118;
        public static final int CLEAN_UP_CONTEXT = 119;
        public static final int GC_WHEN_IDLE = 120;
        public static final int BIND_SERVICE = 121;
        public static final int UNBIND_SERVICE = 122;
        public static final int DUMP_SERVICE = 123;
        public static final int LOW_MEMORY = 124;
        public static final int PROFILER_CONTROL = 127;
        public static final int CREATE_BACKUP_AGENT = 128;
        public static final int DESTROY_BACKUP_AGENT = 129;
        public static final int SUICIDE = 130;
        public static final int REMOVE_PROVIDER = 131;
        public static final int ENABLE_JIT = 132;
        public static final int DISPATCH_PACKAGE_BROADCAST = 133;
        public static final int SCHEDULE_CRASH = 134;
        public static final int DUMP_HEAP = 135;
        public static final int DUMP_ACTIVITY = 136;
        public static final int SLEEPING = 137;
        public static final int SET_CORE_SETTINGS = 138;
        public static final int UPDATE_PACKAGE_COMPATIBILITY_INFO = 139;
        public static final int DUMP_PROVIDER = 141;
        public static final int UNSTABLE_PROVIDER_DIED = 142;
        public static final int REQUEST_ASSIST_CONTEXT_EXTRAS = 143;
        public static final int TRANSLUCENT_CONVERSION_COMPLETE = 144;
        public static final int INSTALL_PROVIDER = 145;
        public static final int ON_NEW_ACTIVITY_OPTIONS = 146;
        public static final int ENTER_ANIMATION_COMPLETE = 149;
        public static final int START_BINDER_TRACKING = 150;
        public static final int STOP_BINDER_TRACKING_AND_DUMP = 151;
        public static final int LOCAL_VOICE_INTERACTION_STARTED = 154;
        public static final int ATTACH_AGENT = 155;
        public static final int APPLICATION_INFO_CHANGED = 156;
        public static final int RUN_ISOLATED_ENTRY_POINT = 158;
        public static final int EXECUTE_TRANSACTION = 159;
        public static final int RELAUNCH_ACTIVITY = 160;

        static String codeToString(int code) {
            switch (code) {
                case BIND_APPLICATION:
                    return "BIND_APPLICATION";
                case EXIT_APPLICATION:
                    return "EXIT_APPLICATION";
                case RECEIVER:
                    return "RECEIVER";
                case CREATE_SERVICE:
                    return "CREATE_SERVICE";
                case SERVICE_ARGS:
                    return "SERVICE_ARGS";
                case STOP_SERVICE:
                    return "STOP_SERVICE";
                case CONFIGURATION_CHANGED:
                    return "CONFIGURATION_CHANGED";
                case CLEAN_UP_CONTEXT:
                    return "CLEAN_UP_CONTEXT";
                case GC_WHEN_IDLE:
                    return "GC_WHEN_IDLE";
                case BIND_SERVICE:
                    return "BIND_SERVICE";
                case UNBIND_SERVICE:
                    return "UNBIND_SERVICE";
                case DUMP_SERVICE:
                    return "DUMP_SERVICE";
                case LOW_MEMORY:
                    return "LOW_MEMORY";
                case PROFILER_CONTROL:
                    return "PROFILER_CONTROL";
                case CREATE_BACKUP_AGENT:
                    return "CREATE_BACKUP_AGENT";
                case DESTROY_BACKUP_AGENT:
                    return "DESTROY_BACKUP_AGENT";
                case SUICIDE:
                    return "SUICIDE";
                case REMOVE_PROVIDER:
                    return "REMOVE_PROVIDER";
                case ENABLE_JIT:
                    return "ENABLE_JIT";
                case DISPATCH_PACKAGE_BROADCAST:
                    return "DISPATCH_PACKAGE_BROADCAST";
                case SCHEDULE_CRASH:
                    return "SCHEDULE_CRASH";
                case DUMP_HEAP:
                    return "DUMP_HEAP";
                case DUMP_ACTIVITY:
                    return "DUMP_ACTIVITY";
                case SLEEPING:
                    return "SLEEPING";
                case SET_CORE_SETTINGS:
                    return "SET_CORE_SETTINGS";
                case UPDATE_PACKAGE_COMPATIBILITY_INFO:
                    return "UPDATE_PACKAGE_COMPATIBILITY_INFO";
                case DUMP_PROVIDER:
                    return "DUMP_PROVIDER";
                case UNSTABLE_PROVIDER_DIED:
                    return "UNSTABLE_PROVIDER_DIED";
                case REQUEST_ASSIST_CONTEXT_EXTRAS:
                    return "REQUEST_ASSIST_CONTEXT_EXTRAS";
                case TRANSLUCENT_CONVERSION_COMPLETE:
                    return "TRANSLUCENT_CONVERSION_COMPLETE";
                case INSTALL_PROVIDER:
                    return "INSTALL_PROVIDER";
                case ON_NEW_ACTIVITY_OPTIONS:
                    return "ON_NEW_ACTIVITY_OPTIONS";
                case ENTER_ANIMATION_COMPLETE:
                    return "ENTER_ANIMATION_COMPLETE";
                case LOCAL_VOICE_INTERACTION_STARTED:
                    return "LOCAL_VOICE_INTERACTION_STARTED";
                case ATTACH_AGENT:
                    return "ATTACH_AGENT";
                case APPLICATION_INFO_CHANGED:
                    return "APPLICATION_INFO_CHANGED";
                case RUN_ISOLATED_ENTRY_POINT:
                    return "RUN_ISOLATED_ENTRY_POINT";
                case EXECUTE_TRANSACTION:
                    return "EXECUTE_TRANSACTION";
                case RELAUNCH_ACTIVITY:
                    return "RELAUNCH_ACTIVITY";
            }
            return Integer.toString(code);
        }

    }

测试

class App : Application() {

    override fun attachBaseContext(base: Context?) {
        super.attachBaseContext(base)
        //Activity的启动监控
        HockHelper.hookHandler(base)
        //Activity的创建的监控
        HockHelper.hookInstrumentation()
    }

运行结果:

D/HockHelper: CustomHandler-handleMessage-EXECUTE_TRANSACTION
D/HockHelper: CustomHandler-handleMessage-ENTER_ANIMATION_COMPLETE
D/HockHelper: CustomHandler-handleMessage-CREATE_SERVICE
D/HockHelper: CustomHandler-handleMessage-BIND_SERVICE
D/HockHelper: CustomHandler-handleMessage-UNBIND_SERVICE
D/HockHelper: CustomHandler-handleMessage-STOP_SERVICE
D/HockHelper: CustomHandler-handleMessage-CLEAN_UP_CONTEXT
D/HockHelper: CustomHandler-handleMessage-CREATE_SERVICE
D/HockHelper: CustomHandler-handleMessage-SERVICE_ARGS
D/HockHelper: CustomHandler-handleMessage-ENABLE_JIT
D/HockHelper: CustomHandler-handleMessage-CREATE_SERVICE
D/HockHelper: CustomHandler-handleMessage-BIND_SERVICE
D/HockHelper: CustomHandler-handleMessage-CREATE_SERVICE
D/HockHelper: CustomHandler-handleMessage-BIND_SERVICE
D/HockHelper: CustomHandler-handleMessage-BIND_SERVICE
D/HockHelper: CustomHandler-handleMessage-BIND_SERVICE
D/HockHelper: CustomHandler-handleMessage-UNBIND_SERVICE
D/HockHelper: CustomHandler-handleMessage-CREATE_SERVICE
D/HockHelper: CustomHandler-handleMessage-BIND_SERVICE
D/HockHelper: CustomHandler-handleMessage-UNBIND_SERVICE
D/HockHelper: CustomHandler-handleMessage-STOP_SERVICE
D/HockHelper: CustomHandler-handleMessage-CLEAN_UP_CONTEXT

Activity的创建的监控

   /**
     * Activity的创建的监控
     * 创建自定义的Instrumentation,然后反射替换,同时重写newActivity方法
     *
     * @throws Exception
     */
    public static void hookInstrumentation() throws Exception {
        Class<?> activityThread = Class.forName("android.app.ActivityThread");
        Method currentActivityThread = activityThread.getDeclaredMethod("currentActivityThread");
        currentActivityThread.setAccessible(true);
        //获取主线程对象
        Object activityThreadObject = currentActivityThread.invoke(null);
        //获取Instrumentation字段
        Field mInstrumentation = activityThread.getDeclaredField("mInstrumentation");
        mInstrumentation.setAccessible(true);
        //获取字段值
        Instrumentation instrumentation = (Instrumentation) mInstrumentation.get(activityThreadObject);
        //偷梁换柱,把系统的instrumentation替换为自己的Instrumentation对象
        CustomInstrumentation customInstrumentation = new CustomInstrumentation(instrumentation);
        //设置字段值
        mInstrumentation.set(activityThreadObject, customInstrumentation);
    }

    /**
     * 自定义一个Instrumentation类用于替换系统的
     */
    public static class CustomInstrumentation extends Instrumentation {
        private Instrumentation base;

        public CustomInstrumentation(Instrumentation base) {
            this.base = base;
        }

        //重写创建Activity的方法
        @Override
        public Activity newActivity(ClassLoader cl, String className, Intent intent) throws InstantiationException, IllegalAccessException, ClassNotFoundException {
            Log.d(TAG, "CustomInstrumentation-newActivity-className=" + className);
            Log.d(TAG, "CustomInstrumentation-newActivity-intent=" + intent);
            Log.d(TAG, "CustomInstrumentation-newActivity-ClassLoader=" + cl);
            return super.newActivity(cl, className, intent);
        }
    }

运行结果:

D/HockHelper: CustomInstrumentation-newActivity-className=com.jay.develop.java.reflection.ReflectionActivity
D/HockHelper: CustomInstrumentation-newActivity-intent=Intent { cmp=com.jay.develop/.java.reflection.ReflectionActivity }
D/HockHelper: CustomInstrumentation-newActivity-ClassLoader=dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/com.jay.develop-DXfsrv1lSMw1iZI5FStC4Q==/base.apk"],nativeLibraryDirectories=[/data/app/com.jay.develop-DXfsrv1lSMw1iZI5FStC4Q==/lib/arm64, /data/app/com.jay.develop-DXfsrv1lSMw1iZI5FStC4Q==/base.apk!/lib/arm64-v8a, /system/lib64, /system/vendor/lib64]]]
D/HockHelper: onCreate: 
D/HockHelper: onStart: 
D/HockHelper: onResume: 

3. 反射机制在jdk动态代理的实践

接口是真实类

  /**
     * 抽象主题接口
     */
    public interface Subject {

        void doSomething();
    }

    /**
     * 真是主题类
     */
    public static class RealSubject implements Subject {
        @Override
        public void doSomething() {
            System.out.println("RealSubject do something");
        }
    }

Jdk动态代理类

  /**
     * jdk动态代理
     */
    public static class JDKDynamicProxy implements InvocationHandler {

        private Object target;

        public JDKDynamicProxy(Object target) {
            this.target = target;
        }

        /**
         * 获取被代理接口实例对象
         */
        public <T> T getProxy() {
            return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
        }

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("Do something before");
            //实现代理对象调用到了真实对象的方法
            Object result = method.invoke(target, args);
            System.out.println("Do something after");
            return result;
        }
    }

测试类

 /**
     * 基于反射机制的动态代理实践
     */
    private static void demo3() {
        // jdk动态代理测试
        Subject subject = new JDKDynamicProxy(new RealSubject()).getProxy();
        subject.doSomething();
    }

运行结果:

-----Demo3-----


我是代理类,执行被代理对象的方法之前
我是真实对象的方法,我被代理类执行了
我是代理类,执行被代理对象的方法之后

关于动态代理的详解会在下一篇文章介绍

反射机制实践类完整代码:Github

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容

  • 转载注明出处:http://www.jianshu.com/p/2f488de72886 简介 Java在编译时候...
    王三的猫阿德阅读 1,037评论 0 2
  • 1、 什么是反射? JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个...
    北牧苍狼阅读 1,333评论 0 2
  • 一、什么是反射? “反射(Reflection)能够让运行于JVM中的程序检测和修改运行时的行为。反射用于在运行时...
    Q南南南Q阅读 470评论 0 1
  • 吾本虞舜后,四大聚为人。尔今逾廿岁,跎落飘零身。繁木将育荫,垂颔念前闻。无心在兹没,相与梳旧尘。回鸾飚千载,漫道聚...
    陈观南阅读 1,214评论 19 31
  • 感恩无上智者先驱,为我们洒下智慧甘霖,驱除一切无明业障,滋养吾身心。 感恩父母给予我今生暇满的人身,使我得以修行❤...
    涵涵_a55c阅读 128评论 0 0