Java学习笔记——Java反射机制

2022-06-23 12:29:27 浏览数 (1)

文章目录

代码语言:txt复制
- [1 简介](https://cloud.tencent.com/developer)
- [2 Class 类](https://cloud.tencent.com/developer)
    - [2.1 获取Class类的实例](https://cloud.tencent.com/developer)
    - [2.2 创建类对象](https://cloud.tencent.com/developer)
- [3 获取运行时类的完整结构](https://cloud.tencent.com/developer)
    - [3.1 类的属性](https://cloud.tencent.com/developer)
    - [3.2 类的方法](https://cloud.tencent.com/developer)
    - [3.3 构造器](https://cloud.tencent.com/developer)
    - [3.4 其他](https://cloud.tencent.com/developer)
- [4 调用类中的指定属性、方法和构造器](https://cloud.tencent.com/developer)
- [5 动态代理与AOP](https://cloud.tencent.com/developer)

1 简介

  • Java Reflection ​ Reflection(反射)是被视为动态语言的关键,反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法。
  • Java反射机制提供的功能
    • 在运行时判断任意一个对象所属的类
    • 在运行时构造任意一个类的对象
    • 在运行时判断任意一个类所具有的成员变量和方法
    • 在运行时调用任意一个对象的成员变量和方法
    • 生成动态代理
  • 反射相关的主要API java.lang.Class:代表一个类 java.lang.reflect.Method:代表类的方法 java.lang.reflect.Field:代表类的成员变量 java.lang.reflect.Constructor:代表类的构造方法 …

2 Class 类

在Object类中定义了以下的方法,此方法将被所有子类继承:

  • public final Class getClass()

以上的方法返回值的类型是一个Class类,此类是Java反射的源头,实际上所谓反射从程序的运行结果来看也很好理解,即:可以通过对象反射求出类的名称。

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

2.1 获取Class类的实例

代码语言:javascript复制
// 1.调用运行时类本身的.class属性
Class class1 = String.class;
System.out.println(class1.getName());

// 2.通过运行时类的对象获取
String string = new String();
Class class2 = string.getClass();
System.out.println(class2.getName());

// 3.通过Class的静态方法获取(通过此方式体会反射的动态性)
String className = "java.lang.String";
Class class3 = null;
try {
    class3 = Class.forName(className);
} catch (ClassNotFoundException e) {
    e.printStackTrace();
}
System.out.println(class3.getName());

// 4.通过类的加载器(了解)
ClassLoader classLoader = this.getClass().getClassLoader();
Class class4 = null;
try {
    class4 = classLoader.loadClass(className);
} catch (ClassNotFoundException e) {
    e.printStackTrace();
}
System.out.println(class4.getName());


System.out.println(class1 == class2); // true
System.out.println(class2 == class3); // true
System.out.println(class3 == class4); // true

类加载器:

代码语言:javascript复制
@Test
public void test4() throws ClassNotFoundException, IOException {
    ClassLoader loader1 = ClassLoader.getSystemClassLoader();
    ClassLoader loader2 = loader1.getParent();
    ClassLoader loader3 = loader2.getParent();
    System.out.println(loader1); // jdk.internal.loader.ClassLoaders$AppClassLoader@28c97a5
    System.out.println(loader2); // jdk.internal.loader.ClassLoaders$PlatformClassLoader@24269709
    System.out.println(loader3); // null

    Class class1 = Person.class;
    ClassLoader loader4 = class1.getClassLoader();
    System.out.println(loader4); // jdk.internal.loader.ClassLoaders$AppClassLoader@28c97a5

    // 测试某个类由哪个类加载器进行加载
    String className = "java.lang.Object";
    Class class2 = Class.forName(className);
    ClassLoader loader5 = class2.getClassLoader();
    System.out.println(loader5); // null 

    // 关于类加载器的一个主要方法
    // 获取包下的配置文件
    ClassLoader loader6 = this.getClass().getClassLoader();
    InputStream is = loader6.getResourceAsStream("day20\jdbc.properties"); // 获取类路径下的指定文件的输入流

    // 获取工程目录下的配置文件
    // FileInputStream is = new FileInputStream(new File("jdbc.properties"));

    Properties pros = new Properties();
    pros.load(is);
    String name = pros.getProperty("user"); 
    System.out.println(name); // runner
    System.out.println(pros.getProperty("password")); // 123456
}

2.2 创建类对象

代码语言:javascript复制
String className = "day20.Person";
Class class1 = Class.forName(className);
代码语言:javascript复制
// 方法一:
Object obj = class1.newInstance(); // 已弃用
Person person = (Person) obj;
代码语言:javascript复制
// 方法二:
Constructor constructor = class1.getConstructor(String.class);
Person person2 = (Person) constructor.newInstance("hello");

3 获取运行时类的完整结构

3.1 类的属性

代码语言:javascript复制
Class class1 = Person.class;

// 1.getFields(): 只能获取到运行时类中及其父类中声明为public的属性
Field[] fields = class1.getFields();
for (int i = 0; i < fields.length; i  ) {
    System.out.println(fields[i]);
}

// 2.getDeclaredFields(): 获取运行时类本身声明的所有的属性
Field[] fields1 = class1.getDeclaredFields();
for(Field field : fields1) {
    //			System.out.println(field);
    // 1.获取每个属性的权限修饰符
    int i = field.getModifiers();
    System.out.print(Modifier.toString(i)   " ");
    // 2.获取属性的类型
    Class type = field.getType();
    System.out.print(type.getName()   " ");
    // 3.获取属性名
    System.out.println(field.getName());
}

3.2 类的方法

代码语言:javascript复制
// 1.getMethods():获取运行时类及其父类中所有的声明为public的方法
Method[] methods = class1.getMethods();
// 2.getDeclaredMethods():获取运行时类本身声明的所有的方法
Method[] methods2 = class1.getDeclaredMethods(); 

// 获取注解 权限修饰符 返回值类型 方法名 形参列表 异常
for(Method method : methods2) {
    // 1.注解
    Annotation[] anns = method.getAnnotations();
    for(Annotation ann : anns) {
        System.out.println(ann);
    }
    // 2.权限修饰符
    System.out.print(Modifier.toString(method.getModifiers())   " ");
    // 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 (int i = 0; i < params.length; i  ) {
        System.out.print(params[i].getName()   " args-"   i   " ");
    }
    System.out.print(")");
    // 6.异常类型
    Class[] exps = method.getExceptionTypes();
    if (exps.length != 0) {
        System.out.print(" throws ");
    }
    for (int i = 0; i < exps.length; i  ) {
        System.out.print(exps[i].getName()   " ");
    }
    System.out.println();
}

3.3 构造器

代码语言:javascript复制
Constructor[] cons = class1.getConstructors();
Constructor[] cons1 = class1.getDeclaredConstructors();

3.4 其他

代码语言:javascript复制
// 1.获取运行时类的父类
Class superClass = clazz.getSuperclass();
// 2.获取带泛型的父类
Type type = class1.getGenericSuperclass();
// 获取父类的泛型
ParameterizedType param = (ParameterizedType) type;
Type[] ars = param.getActualTypeArguments();
// 3.获取实现的接口
Class[] interfaces = class1.getInterfaces();
// 4.获取所在的包
Package package1 = class1.getPackage();
// 5.获取注解
Annotation[] anns = class1.getAnnotations();
// 6.获取内部类
Class[] classes = class1.getDeclaredClasses();

4 调用类中的指定属性、方法和构造器

  • 属性
代码语言:javascript复制
Class class1 = Person.class;
//1.获取指定的属性
//getField(String fieldName):获取运行时类中声明为public的指定属性名为fieldName的属性
Field name = class1.getField("name");
//2.创建运行时类的对象 
Person person = (Person) class1.newInstance();
//3.将运行时类的指定的属性赋值
name.set(person, "hello");
name.get(person); // 获取该属性值
// getDeclaredField(String fieldName):获取运行时类中指定的名为fieldName的属性
Field age = class1.getDeclaredField("age");
age.setAccessible(true); // 由于属性权限修饰符的限制,为了保证可以给属性赋值,需要在操作前使得此属性可被操作。
age.set(person, 20);
  • 方法
代码语言:javascript复制
Class class1 = Person.class;
//getMethod(String methodName,Class ... params):获取运行时类中声明为public的指定的方法
Method method = class1.getMethod("show");
Person person = new Person();
// 调用指定的方法:Object invoke(Object obj,Object ... obj)
Object returnVal = method.invoke(person);

Method method2 = class1.getMethod("toString");
Object returnVal1 = method2.invoke(person);

// 对于运行时类中静态方法的调用
Method method3 = class1.getMethod("Info");
method3.invoke(Person.class);
method3.invoke(null);

// getDeclaredMethod(String methodName,Class ... params):获取运行时类中声明了的指定的方法
Method method4 = class1.getDeclaredMethod("display", String.class, Integer.class);
method4.setAccessible(true);
Object returnVal2 = method4.invoke(person, "hhhh", 3);
  • 构造器
代码语言:javascript复制
Class class1 = Person.class;
Constructor constructor = class1.getDeclaredConstructor(String.class, int.class);
constructor.setAccessible(true);
Person person = (Person) constructor.newInstance("xixi", 20);

5 动态代理与AOP

Java学习笔记——设计模式:动态代理

注:以上笔记参考自尚硅谷

0 人点赞