14.1 Java 反射机制概述
- Reflection(反射)是被视为动态语言的关键,反射机制允许程序在执行期借助于 Reflection API 取得任何类的内部信息,并能直接操作任意对象的内部属性及方法
- 加载完类之后,在堆内存的方法区中就产生了一个 Class 类型的对象(一个类只有一个 Class 对象),这个对象就包含了完整的类的结构信息。我们可以通过这个对象看到类的结构
14.1.1 反射相关的主要 API
-
java.lang.Class:代表一个类
-
java.lang.reflect.Method:代表类的方法
-
java.lang.reflect.Field:代表类的成员变量
-
java.lang.reflect.Constructor:代表类的构造器
14.2 获取 Class 实例
关于 java.lang.Class 类的理解
1.类的加载过程
程序经过 javac.exe 命令以后,会生成一个或多个字节码文件(.class),接着我们
使用 java.exe 命令对莫格字节码文件进行解释运行。相当于将某个字节码文件加载到内存中,
此过程就称为类的加载。加载到内存中的类,我们就称为运行时类,此运行时类,
就作为 Class 的一个实例2.换句话说,Class 的实例就对应着加载到内存中的一个运行时类
3.加载到内存中的运行时类,会缓存一定的时间。在此时间之内,我们可以通过不同的方式来获取
此运行时类
public final Class getClass()
:返回一个Class类,此类是Java反射的源头
14.2.1 Class 类常用的方法
static Class forName(String name)
:返回指定类名 name 的 Class 对象Object newInstance()
:调用缺省构造函数,返回该 Class 对象的一个实例getName()
:返回此Class对象所表示的实体(类、接口、数组类、基本类型 或 void)名称Class getSuperClass()
:返回当前 Class 对象的父类的 Class 对象Class[] getInterfaces()
:获取当前 Class 对象的接口ClassLoader getClassLoader()
:返回该类的类加载器Class getSuperclass()
:返回表示此 Class 所表示的实体的超类的 ClassConstructor[] getConstructors()
:返回一个包含某些 Constructor 对象的数组Field[] getDeclaredFields():
返回 Field 对象的一个数组Method getMethod(String name,Class … paramTypes)
:返回一个 Method 对象,此对象的形参类型为 paramType
14.2.2 获取 Class 的实例的方式
@Test
public void test3() throws ClassNotFoundException {
//方式一:调用运行时类的属性:.class
Class<Person> clazz1 = Person.class;
System.out.println(clazz1);//class top.shiyiri.reflection.Person
//方式二:通过运行时类的对象,调用 getClass()
Person p1 = new Person();
Class<? extends Person> clazz2 = p1.getClass();
System.out.println(clazz2);
//方式三:调用 Class 的静态方法:forName(String classPath)
Class<?> clazz3 = Class.forName("top.shiyiri.reflection.Person");
//clazz3 = Class.forName("java.lang.String");
System.out.println(clazz3);
System.out.println(clazz1 == clazz2);//true
System.out.println(clazz1 == clazz3);//true
//方式四:使用类的加载器:ClassLoader
ClassLoader classLoader = ReflectionTest.class.getClassLoader();
Class clazz4 = classLoader.loadClass("top.shiyiri.reflection.Person");
System.out.println(clazz4);
System.out.println(clazz1 == clazz4);//true
}
-
Class 实例可以是哪些结构的说明
@Test public void test4() { Class c1 = Object.class; Class c2 = Comparable.class; Class c3 = String[].class; Class c4 = int[][].class; Class c5 = ElementType.class; Class c6 = Override.class; Class c7 = int.class; Class c8 = void.class; Class c9 = Class.class; int[] a = new int[10]; int[] b = new int[100]; Class c10 = a.getClass(); Class c11 = b.getClass(); // 只要元素类型与维度一样,就是同一个Class System.out.println(c10 == c11);//true }
14.3 类的加载和 ClassLoader
14.3.1 类的加载过程
- 类加载器作用:用来把类(class)装载进内存的
@Test
public void test1() {
//对于自定义类,使用系统类加载器进行加载
ClassLoader classLoader = ClassLoaderTest.class.getClassLoader();
System.out.println(classLoader);
//调用系统类加载器的getParent():获取扩展类加载器
ClassLoader classLoader1 = classLoader.getParent();
System.out.println(classLoader1);
//调用扩展类加载器的getParent():无法获取引导类加载器
//引导类加载器主要负责Java的核心类库,无法加载自定义类
ClassLoader classLoader2 = classLoader1.getParent();
System.out.println(classLoader2);
}
14.4 创建运行时类的对象
@Test
public void test() throws Exception {
Class<Person> clazz = Person.class;
/*
newInstance():调用此方法,创建对应的运行时类的对象。内部调用运行时类的空参构造器
要想此方法正常的创建运行时类的对象,要求:
1.运行时类必须提供空参的构造器
2.空参的构造器的访问权限能够在其他类中进行访问
在 JavaBean 中要求提供一个 public 的空参构造器。原因:
1.便于通过反射,创建运行时类的对象
2.便于子类继承此运行时类,默认调用 super(),保证父类由此构造器
*/
Person person = clazz.newInstance();
System.out.println(person);//Person(name=null, age=0)
}
14.5 获取运行时类的完整结构
14.5.1 接口
public Class<?>[] getInterfaces()
:确定此对象所表示的类或接口实现的接口
@Test
public void test5() {
Class clazz = Person.class;
Class[] interfaces = clazz.getInterfaces();
for (Class c: interfaces) {
System.out.println(c);
/*
interface java.lang.Comparable
interface top.shiyiri.reflection2.MyInterface
*/
}
System.out.println();
//获取运行时类父类实现的接口
Class[] interfaces1 = clazz.getSuperclass().getInterfaces();
for (Class in: interfaces1) {
System.out.println(in);
//interface java.io.Serializable
}
}
14.5.2 继承的父类
public Class<? Super T> getSuperclass()
:返回表示此 Class 所表示的实体(类、接口、基本类型)的父类的 Class
@Test
public void test2() {
Class<Person> clazz = Person.class;
Class<? super Person> superclass = clazz.getSuperclass();
//class top.shiyiri.reflection2.Creature
System.out.println(superclass);
}
14.5.3 构造器
public Constructor<T>[] getConstructors()
:返回此 Class 对象所表示的类的所有 public 构造方法public Constructor<T>[] getDeclaredConstructors()
:返回此 Class 对象表示的类声明的所有构造方法public int getModifiers()
:取得修饰符public String getName()
:取得方法名称public Class<?>[] getParameterTypes()
:取得参数的类型
@Test
public void test1() {
Class<Person> clazz = Person.class;
//getConstructors():获取当前运行时类中声明为public的构造器
Constructor<?>[] constructors1 = clazz.getConstructors();
for (Constructor constructor: constructors1) {
System.out.println(constructor);
//public top.shiyiri.reflection2.Person()
}
System.out.println("******************************");
//getConstructors():获取当前运行时类中声明的所有构造器
Constructor<?>[] constructors = clazz.getDeclaredConstructors();
for (Constructor<?> constructor: constructors) {
System.out.println(constructor);
/*
top.shiyiri.reflection2.Person(java.lang.String,int)
private top.shiyiri.reflection2.Person(java.lang.String)
public top.shiyiri.reflection2.Person()
*/
}
}
14.5.4 方法
public Method[] getDeclaredMethods()
:返回此 Class 对象所表示的类或接口的全部方法public Method[] getMethods()
:返回此 Class 对象所表示的类或接口的 public 的方法public Class<?> getReturnType()
:取得全部的返回值public Class<?>[] getParameterTypes()
:取得全部的参数public int getModifiers()
:取得修饰符public Class<?>[] getExceptionTypes()
:取得异常信息
@Test
public void test1() {
Class<Person> clazz = Person.class;
//getMethods():获取当前运行时类及其父类中声明为public权限的方法
Method[] methods = clazz.getMethods();
for (Method method: methods) {
System.out.println(method);
}
System.out.println("**********************************");
//getDeclaredMethods():获取当前运行时类中声明的所有方法(不包含父类中的方法)
Method[] declaredMethods = clazz.getDeclaredMethods();
for (Method method: declaredMethods) {
System.out.println(method);
}
}
/*
@Xxx
权限修饰符 返回值类型 方法名(参数名1, 参数名2) throws xxxException{}
*/
@Test
public void test2() {
Class<Person> clazz = Person.class;
Method[] declaredMethods = clazz.getDeclaredMethods();
for (Method method: declaredMethods) {
//1.获取方法声明的注解
Annotation[] annotations = method.getAnnotations();
for (Annotation annotation: annotations) {
System.out.println(annotation);
}
//2.权限修饰符
System.out.print(Modifier.toString(method.getModifiers())+"\t");
//3.返回值类型
System.out.print(method.getReturnType().getName() + "\t");
//4.方法名
System.out.print(method.getName());
System.out.print("(");
//5.形参列表
Class<?>[] parameterTypes = method.getParameterTypes();
if (!(parameterTypes == null && parameterTypes.length == 0)) {
for (int i = 0; i < parameterTypes.length; i++) {
if (i == parameterTypes.length - 1) {
System.out.print(parameterTypes[i].getName() + " args_" + i);
break;
}
System.out.print(parameterTypes[i].getName() + " args_" + i + ",");
}
}
System.out.print(")");
//6.抛出的异常
Class<?>[] exceptionTypes = method.getExceptionTypes();
if (exceptionTypes != null && exceptionTypes.length > 0) {
System.out.print("throws ");
for (int i = 0; i < exceptionTypes.length; i++) {
if (i == exceptionTypes.length -1) {
System.out.print(exceptionTypes[i].getName());
break;
}
System.out.print(exceptionTypes[i].getName() + ", ");
}
}
System.out.println();
}
}
14.5.5 Field
-
public Field[] getFields()
:返回此 Class 对象所表示的类或接口的 public 的 Field -
public Field[] getDeclaredFields()
:返回此 Class 对象所表示的类或接口的全部 Field -
public int getModifiers()
:以整数形式返回此Field的修饰符 -
public Class<?> getType()
:得到Field的属性类型 -
public String getName()
:返回Field的名称
@Test
public void test1() {
Class<Person> clazz = Person.class;
//获取属性结构
//getFields():获取当前运行时类及其父类中声明为public访问权限的属性
Field[] fields = clazz.getFields();
for (Field field: fields) {
System.out.println(field);
/*
public int top.shiyiri.reflection2.Person.id
public double top.shiyiri.reflection2.Creature.weight
*/
}
System.out.println("***********************");
//getDeclaredFields():获取当前运行时类中声明的所有属性(不包含父类中声明的属性)
Field[] declaredFields = clazz.getDeclaredFields();
for (Field de: declaredFields) {
System.out.println(de);
/*
private java.lang.String top.shiyiri.reflection2.Person.name
int top.shiyiri.reflection2.Person.age
public int top.shiyiri.reflection2.Person.id
*/
}
}
//权限修饰符 数据类型 变量名
@Test
public void test2() {
Class<Person> clazz = Person.class;
Field[] declaredFields = clazz.getDeclaredFields();
for (Field de: declaredFields) {
//1.权限修饰符
int modifiers = de.getModifiers();
System.out.print(Modifier.toString(modifiers)+"\t---");
//2.数据类型
Class<?> type = de.getType();
System.out.print(type+"\t---");
//3.变量名
System.out.println(de.getName());
/*
private ---class java.lang.String ---name
---int ---age
public ---int ---id
*/
}
}
14.6 调用运行时类的指定结构
14.6.1 调用指定方法
-
getMethod(String name,Class…parameterTypes)
:取得一个 Method 对象 -
Object invoke(Object obj, Object[] args)
:-
Object 对应原方法的返回值,若原方法无返回值,此时返回 null
-
若原方法若为静态方法,此时形参 Object obj 可为 null
-
若原方法形参列表为空,则 Object[] args 为 null
-
若原方法声明为 private,则需要在调用此invoke()方法前,显式调用方法对象的 setAccessible(true) 方法,将可访问 private 的方法
-
@Test
public void testMethod() throws Exception {
Class clazz = Person.class;
//创建运行时类的对象
Person p = (Person) clazz.newInstance();
//1.获取指定的某个方法
//getDeclaredMethod():参数一:指明获取的方法的名称。参数二:指明获取的方法的形参列表
Method show = clazz.getDeclaredMethod("show", String.class);
//2.保证当前方法是可访问的
//setAccessible(true)
show.setAccessible(true);
/*
3.
invoke():参数一:方法的调用者。参数二:给方法形参赋值的形参
invoke()的返回值即为对应类中调用的方法的返回值
*/
Object invoke = show.invoke(p, "中国");
System.out.println(invoke);
System.out.println("*************如何调用静态方法******************");
Method showDesc = clazz.getDeclaredMethod("showDesc");
showDesc.setAccessible(true);
//Object invoke1 = showDesc.invoke(p);
//静态方法可以不用设置对象,用null值即可
Object invoke1 = showDesc.invoke(null);
//Object invoke1 = showDesc.invoke(Person.class);
System.out.println(invoke1);//null
}
14.6.2 调用指定属性
@Test
public void testField1() throws Exception {
Class clazz = Person.class;
//创建运行时类的对象
Person p = (Person) clazz.newInstance();
//getDeclaredField(String fieldName):获取运行时类中指定变量名的属性
Field name = clazz.getDeclaredField("name");
//setAccessible(true):保证当前属性是可访问的
name.setAccessible(true);
//set():参数一:指明设置哪个对象的属性,参数二:将此属性值设置为多少
name.set(p, "张三");
/*
获取当前属性的值
get():参数一:获取哪个对象的额当前属性值
*/
System.out.println(name.get(p));
}
14.6.3 调用指定构造器
@Test
public void testConstructor() throws Exception {
Class clazz = Person.class;
/*
1.获取指定的构造器
getDeclaredConstructor(Class ...parameterTypes):参数:指明构造器的参数列表
*/
Constructor constructor = clazz.getDeclaredConstructor(String.class);
/*
2.保证此构造器可访问
*/
constructor.setAccessible(true);
//3.调用此构造器创建运行时类的对象
Object tom = constructor.newInstance("Tom");
System.out.println(tom.toString());
}
14.7 动态代理
14.7.1 静态代理
/*
静态代理举例
特点:代理类和被代理类在编译期间,就确定下来了
*/
interface ClothFactory {
void produceCloth();
}
//代理类
class ProxyClothFactory implements ClothFactory {
private ClothFactory factory;//被代理类对象进行实例化
public ProxyClothFactory(ClothFactory factory) {
this.factory = factory;
}
@Override
public void produceCloth() {
System.out.println("代理工厂做一些准备工作");
factory.produceCloth();
System.out.println("代理工作做一些后续的收尾工作");
}
}
//被代理类
class NickClothFactory implements ClothFactory {
@Override
public void produceCloth() {
System.out.println("Nick工厂生产一批运动服");
}
}
public class StaticProxyTest {
public static void main(String[] args) {
//创建被代理类的对象
NickClothFactory nickClothFactory = new NickClothFactory();
//创建代理类的对象
ProxyClothFactory clothFactory = new ProxyClothFactory(nickClothFactory);
clothFactory.produceCloth();
}
}
14.7.2 动态代理
/*
动态代理的举例
*/
interface Human {
String getBelief();
void eat(String food);
}
//被代理类
class SuperMan implements Human {
@Override
public String getBelief() {
return "I believe I can fly!";
}
@Override
public void eat(String food) {
System.out.println("我喜欢吃" + food);
}
}
class HumanUtil {
public void method1() {
System.out.println("************************通用方法一************************");
}
public void method2() {
System.out.println("************************通用方法二************************");
}
}
/*
要想实现动态代理,需要解决的问题?
问题一:如何根据加载到内存中的被代理类,动态的创建一个代理类及其对象
问题二:当通过代理类的对象调用方法时,如何动态的去调用被代理类中的同名方法
*/
class ProxyFactory {
//调用此方法,返回一个代理类的对象。解决问题一
public static Object getProxyInstance(Object obj) {//obj:被代理类的对象
MyInvocationHandler handler = new MyInvocationHandler();
handler.bind(obj);
return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), handler);
}
}
class MyInvocationHandler implements InvocationHandler {
private Object obj;//需要使用被代理类的对象进行赋值
public void bind(Object obj) {
this.obj = obj;
}
//当我们通过代理类的对象调用方法 a 时,就会自动的调用如下的方法 invoke()
//将被代理类要执行的方法 a 的功能就声明在 invoke() 中
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
HumanUtil humanUtil = new HumanUtil();
humanUtil.method1();
/*
method:即为代理类对象调用的方法,此方法也就作为了被代理类对象要调用的方法
obj:被代理类的对象
*/
Object value = method.invoke(obj, args);
//上述方法的返回值就作为当前类中的invoke()的返回值
humanUtil.method2();
return value;
}
}
public class ProxyTest {
public static void main(String[] args) {
SuperMan superMan = new SuperMan();
//proxyInstance:代理类的对象
Human proxyInstance = (Human) ProxyFactory.getProxyInstance(superMan);
//当通过代理类对象调用方法时,会自动的调用被代理类中同名的方法
String belief = proxyInstance.getBelief();
System.out.println(belief);
proxyInstance.eat("四川麻辣烫");
System.out.println("******************************");
NickClothFactory nickClothFactory = new NickClothFactory();
ClothFactory instance = (ClothFactory)ProxyFactory.getProxyInstance(nickClothFactory);
instance.produceCloth();
}
}