java学习笔记:反射

时间:2021-07-20 12:01:50

1.什么是反射?

  Reflection(反射)是被视为动态语言的关键,反射机制允许程序做执行期间借助于ReflectionAPI取得任何类的内部信息,并能直接操作任意对象内部属性及方法

2.反射相关的主要API

java.lang.Class:代表一个类

  java.lang.reflect.Method:代表类的方法

  java.lang.reflect.Field:代表类的成员变量

  java.lang.reflect.Constructor:代表类的构造方法

3.简单入门示例代码

package day01.code;

import java.lang.reflect.Field;
import java.lang.reflect.Method; import org.junit.Test; public class TestReflection { // 有了反射,可以通过反射创建一个类的对象,并调用其中的结构
@Test
public void test2() throws Exception{
Class clazz=Person.class;
// 1.创建clazz对应的运行时类Person类的对象
Person person= (Person)clazz.newInstance();
System.out.println(person);
// 2.通过反射调用运行时类的指定的属性
// 2.1 调用public的属性
Field f1=clazz.getField("name");
f1.set(person, "lisi");
System.out.println(person);
// 2.2 调用非public的属性
Field f2= clazz.getDeclaredField("age");
f2.setAccessible(true);
f2.set(person, 20);
System.out.println(person);
// 3.通过反射调用运行时类的指定的方法
// 3.1 调用无参方法
Method m1=clazz.getMethod("show");
m1.invoke(person);
// 3.2 调用有参方法
Method m2=clazz.getMethod("display",String.class);
m2.invoke(person, "CHN");
} // 在有反射以前,如何创建一个类的对象,并调用其中的方法,属性
@Test
public void test1(){
Person person=new Person();
person.setAge(10);
person.setName("zhangsan");
System.out.println(person);
person.show();
person.display("CN");
}
}

4.反射的源头Class

  4.1 getClass()详解,此方法中Object类中被定义,会被所有的子类继承,调用此方法返回值的类型是一个Class类,此类的反射的源头,实际上所谓反射从程序的运行结果来看也很好理解,即:可以通过对象反射出类的名称

  @Test
public void test3(){
Person person=new Person();
Class calzz= person.getClass(); // 通过运行时类的对象,调用其getClass(),返回其运行时类
System.out.println(calzz);
}

  4.2 反射原理解析

    我们创建了一个类,通过编译(javac.exe),生成对应的.class文件,之后我们使用java.exe加载(JVM的类加载器完成的)此.class文件,此.class文件加载到内存以后,就是一个运行时类,存放在缓存区。那么这个运行时类本身就是一个Class的实例!

    4.2.1 每一个运行时类只加载一次

    4.2.2 有了Class的实例以后,我们才可以进行如下操作

        1)创建对应的运行时类的对象

        2)获取对应的运行时类的完整结构(属性,方法,构造器,内部类,父类,所在的包,异常,注解........)

        3) 调用对应的运行时类的指定的结构(属性,方法,构造器)

        4)反射的应用,动态代理

    正常方式:引入需要的“包类”名称->通过new实例化->取得实例化对象

    反射方式:实例化对象->getClass()方法->得到完整的“包类”名称

  4.3 获取Class的实例

    4.3.1 调用运行时类本身的.class属性

    @Test
public void test4(){
// 1.调用运行时类本身的.class属性
Class clazz=Person.class;
System.out.println(clazz.getName());
}

    4.3.2 通过运行时类的对象获取

  @Test
public void test5(){
// 通过运行时类的对象获取
Person person=new Person();
Class clazz= person.getClass();
System.out.println(clazz.getName());
}

    4.3.3 通过Class的静态方法获取

  @Test
public void Test6() throws Exception{
// 通过Class的静态方法获取
String className="day01.code.Person";
Class clazz= Class.forName(className);
System.out.println(clazz.getName());
}

    4.3.4 通过类的加载器

  @Test
public void test7() throws Exception{
// 通过类的加载器
String className="day01.code.Person";
ClassLoader classLoader=this.getClass().getClassLoader();
Class clazz= classLoader.loadClass(className);
System.out.println(clazz.getName());
}

  4.4 什么是类的加载器?(ClassLoader)

     解释:类加载器是用来把类(class)装载进内存的。JVM 规范定义了两种类型的类加载器:启动类加载器(bootstrap)和用户自定义加载器(user-defined class loader)

    4.4.1 Bootstap Classloader 引导类加载器:用C++编写的,是JVM自带的类加载器,负责Java平台核心库,用来加载核心类库,该加载器无法直接获取

    4.4.2 Extension Classloader 扩展类加载器:负责jre/lib/ext目录下的jar包或 –D java.ext.dirs 指定目录下的jar包装入工作库 .

    4.4.3 System Classloader 系统类加载器:负责java –classpath 或 –D java.class.path所指的目录下的类与jar包装入工作 ,是最常用的加载器

  4.5 有了Class对象,能做什么?

    4.5.1 newInstance() 作用: 创建对应的运行时类的对象,实际上就是调用类运行时类的空参的构造器。注:要想创建成功,1.要求对应的运行时类要有空参的构造器 2.构造器的权限修饰符的权限要足够(经验证同一个包下大于 private 即可)

  @Test
public void test1() throws Exception{
String className="day01.code.Person";
Class clazz= Class.forName(className);
// 创建运行时对象
Object obj=clazz.newInstance();
Person person=(Person)obj;
System.out.println(person);
}

    4.5.2 通过反射调用类的完整结构(实现的全部接口,所继承的父类,全部的构造器,全部的方法,全部的Field)

      4.5.2.1 Field

  // 获取对应的运行时类的属性
@Test
public void test1(){
Class clazz= Person.class;
// 1.getFields():只能获取到运行时类及其父类中声明为public的属性
Field[] fields=clazz.getFields();
for(int i=0;i<fields.length;i++){
System.out.println(fields[i]);
}
System.out.println();
// 2.getDeclaredFields():获取到运行时类本身声明的所有的属性
Field[] fields1=clazz.getDeclaredFields();
for (Field field : fields1) {
System.out.println(field.getName());
}
} // 权限修饰符 变量类型 变量名,获取属性的各个部分的内容
@Test
public void test2(){
Class clazz= Person.class;
Field[] fields1=clazz.getDeclaredFields();
for (Field field : fields1) {
// 1.获取每个属性的权限修饰符
int i= field.getModifiers();
String modifier= Modifier.toString(i);
System.out.print(modifier+" ");
// 2.获取属性的变量类型
Class type=field.getType();
System.out.print(type.getName()+" ");
// 3.获取属性名
System.out.println(field.getName());
}
}

      4.5.2.2 Method

  // 1.获取运行时类的方法
@Test
public void test1(){
Class clazz=Person.class;
// 1.getMethods():获取运行时类及其父类中所有声明为public的方法
Method[]m1=clazz.getMethods();
for (Method method : m1) {
System.out.println(method);
}
System.out.println();
// 2.getDeclaredMethods():获取运行时类本身声明的所有的方法
Method[]m2=clazz.getDeclaredMethods();
for (Method method : m2) {
System.out.println(method);
}
} // 注解 权限修饰符 返回值类型 方法名 形参列表 异常
@Test
public void test2(){
Class clazz=Person.class;
Method[]m2=clazz.getDeclaredMethods();
for (Method method : m2) {
// 1.注解
Annotation[] ann= method.getAnnotations();
for (Annotation annotation : ann) {
System.out.print(annotation+" ");
}
// 2.权限修饰符
String str= Modifier.toString(method.getModifiers());
System.out.print(str+" ");
// 3.返回值类型
Class returnType=method.getReturnType();
System.out.print(returnType.getName()+" ");
// 4.方法名
System.out.print(method.getName()+" ");
// 5.形参列表
System.out.print("(");
Class[]params=method.getParameterTypes();
for (Class p : params) {
System.out.print(p.getName());
}
System.out.print(")");
// 6.异常类型
Class[]exps= method.getExceptionTypes();
for (Class exp : exps) {
System.out.print(exp.getName()+" ");
}
System.out.println();
}
}

       4.5.2.3 构造器

  // 获取运行时类的构造器
@Test
public void test2()throws Exception{
String className="day01.code.Person";
Class clazz= Class.forName(className);
Constructor[]cons=clazz.getDeclaredConstructors();
for (Constructor constructor : cons) {
System.out.println(constructor);
}
}

        4.5.2.4 其他结构

  // 6.获取注解
@Test
public void test6(){
Class clazz=Person.class;
Annotation[]anns=clazz.getAnnotations();
for (Annotation annotation : anns) {
System.out.println(annotation);
}
} // 5.获取所在的包
@Test
public void test5(){
Class clazz=Person.class;
Package package1=clazz.getPackage();
System.out.println(package1);
} // 4.获取实现的接口
@Test
public void test4(){
Class clazz=Person.class;
Class[] interfaces=clazz.getInterfaces();
for (Class class1 : interfaces) {
System.out.println(class1);
}
} // 3.获取父类的泛型
@Test
public void test3(){
Class clazz=Person.class;
Type type=clazz.getGenericSuperclass();
ParameterizedType param=(ParameterizedType) type;
Type[]ars=param.getActualTypeArguments();
System.out.println(((Class)ars[0]).getName());
} // 2.获取带泛型的父类
@Test
public void test2(){
Class clazz=Person.class;
Type type=clazz.getGenericSuperclass();
System.out.println(type);
} // 1.获取运行时类的父类
@Test
public void test1(){
Class clazz= Person.class;
Class superClass=clazz.getSuperclass();
System.out.println(superClass);
}

    4.5.3 反射的各种操作

      4.5.3.1 调用运行时类指定的属性

  // 调用运行时类中指定的属性
@Test
public void test3() throws Exception{
Class clazz=Person.class;
// 1.获取指定的属性,属性权限是public的
Field name=clazz.getField("name");
// 2.创建运行时类的对象
Person p=(Person)clazz.newInstance();
System.out.println(p);
// 3.将运行时类的指定的属性赋值
name.set(p, "Jerry");
System.out.println(p);
System.out.println();
Field age= clazz.getDeclaredField("age");
// 由于属性权限修饰符的限制,为了保证可以给属性赋值,需要在操作前使得此属性值可以被操作
age.setAccessible(true);
age.set(p, 10);
System.out.println(p);
}

      4.5.3.2 调用运行时类指定的方法

  // 调用运行时类中指定的方法
@Test
public void test3() throws Exception{
Class clazz=Person.class;
// getMethod(String methodName,Class...params):获取运行时类中声明为public的方法
Method m1=clazz.getMethod("show");
Person person=(Person)clazz.newInstance();
// 可以获取返回值
Object returnVal=m1.invoke(person);
System.out.println(returnVal); Method m2=clazz.getMethod("toString");
Object returnVal2=m2.invoke(person);
System.out.println(returnVal2); // 获取运行时类的静态方法
Method m3=clazz.getMethod("info");
m3.invoke(Person.class);
// getDeclaredMethod(String methodName,Class...params):获取运行时类中定义的方法
Method m4=clazz.getDeclaredMethod("display",String.class,Integer.class);
m4.setAccessible(true);
Object value= m4.invoke(person,"中国",10);
System.out.println(value);
}

      4.5.3.3 调用指定的构造器

  // 调用指定的构造器,创建运行时类的对象
@Test
public void test() throws Exception{
String className="day01.code.Person";
Class clazz= Class.forName(className);
Constructor cons= clazz.getDeclaredConstructor(String.class,int.class);
cons.setAccessible(true);
Person person=(Person)cons.newInstance("陆虎",10);
System.out.println(person);
}

    4.5.4 动态代理vs静态代理

      4.5.4.1 静态代理

package day01.code1;

// 静态代理
// 接口
interface ClothFactory{ void productCloth();
} // 被代理类
class NikeClothFactory implements ClothFactory{ @Override
public void productCloth() {
System.out.println("Nike工厂生成一批衣服");
} } // 代理类
class ProxyFactory implements ClothFactory{ ClothFactory cf; public ProxyFactory(ClothFactory cf) {
this.cf=cf;
} @Override
public void productCloth() {
System.out.println("代理类开始执行。。。");
this.cf.productCloth();
} } public class TestClothProduct { public static void main(String[]args){
NikeClothFactory nikeClothFactory=new NikeClothFactory();
ProxyFactory proxyFactory=new ProxyFactory(nikeClothFactory);
proxyFactory.productCloth();
}
}

     4.5.4.2 动态代理

package day01.code1;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy; interface Subject{
void action();
}
// 被代理类
class RealSubject implements Subject{ @Override
public void action() {
System.out.println("被代理类方法开始执行");
} }
class MyInvocationHandler implements InvocationHandler{ Object obj;// 实现了接口的被代理类的对象的声明 // 1.给被代理的对象实例化 2.返回一个代理类的对象
public Object blind(Object obj){
this.obj=obj;
return Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(), this);
}
// 当通过代理类的对象发起对被重写的方法的调用时,都会转换为对如下的invoke方法的调用
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// method方法的返回值是returnVal
Object returnVal=method.invoke(obj, args);
return returnVal;
} } public class TestProxy { public static void main(String[]args){
// 1.被代理类的对象
RealSubject real=new RealSubject();
// 2.创建一个实现了InvacationHandler接口的类的对象
MyInvocationHandler handler=new MyInvocationHandler();
// 3.调用blind()方法,动态的返回一个同样实现了real所在类实现的接口Subject的代理类的对象
Object object=handler.blind(real);
// 4.此时subject就是代理类的对象
Subject subject=(Subject)object;
// 5.转到对InvocationHandler接口对实现类对invoke()方法的调用
subject.action(); // 再举一例
NikeClothFactory nikeClothFactory=new NikeClothFactory();
// proxyCloth即为代理类的对象
ClothFactory proxyCloth=(ClothFactory)handler.blind(nikeClothFactory);
proxyCloth.productCloth(); }
}