大数据知识体系
首页
数据结构与算法
  • JVM
  • Java
  • Scala
  • Python
设计模式
  • MySQL
  • Redis
  • HDFS
  • HBase
  • ClickHouse
  • ElasticSearch
  • Iceberg
  • Hudi
  • Spark
  • Flink
  • Hive
  • Yarn
  • Zookeeper
  • Maven
  • Git
  • 数据仓库
  • 用户画像
  • 指标体系
数据治理
关于
首页
数据结构与算法
  • JVM
  • Java
  • Scala
  • Python
设计模式
  • MySQL
  • Redis
  • HDFS
  • HBase
  • ClickHouse
  • ElasticSearch
  • Iceberg
  • Hudi
  • Spark
  • Flink
  • Hive
  • Yarn
  • Zookeeper
  • Maven
  • Git
  • 数据仓库
  • 用户画像
  • 指标体系
数据治理
关于
  • JVM

    • JVM 架构
    • JVM 类加载机制
    • JVM 运行时数据区
    • JVM 垃圾回收机制
    • JVM 性能监控与调优
    • JVM 常见错误
  • Java

    • Java基础

      • Java 基础知识
      • Java 基础 - 枚举类
      • Java 基础 - 异常处理
      • Java 基础 - 泛型
      • Java 基础 - 反射
        • 什么是反射
        • 核心类库
          • Class 类
          • Constructor 类
          • Field 类
          • Method 类
        • 综合案例
      • Java 基础 - 代理模式
      • Java 基础 - 注解
    • Java集合

    • Java并发编程

    • Java 开发规范
  • Scala

    • Scala 概述
  • Python

    • Numpy

      • 初识 Numpy
      • ndarray 的创建方式
      • NumPy 的数据类型
      • NumPy 数组计算
      • 拷贝
      • 索引和切片
      • 数学和统计方法
      • 数组形状变换
      • 通用函数
      • 排序
      • 搜索和计数
      • 线性代数
      • 伪随机数生成
      • 广播
      • 文件输入和输出
    • Pandas

      • 初识 Pandas
      • 认识 Series 和 DataFrame
      • Series 和 DataFrame 增删改查
      • Index对象增删改查
      • 普通列和行Index相互转化
      • 快速查看整体信息
      • 数值运算
      • 合并数据集
      • 数值统计与聚合
      • 分组聚合
      • 分类类型
      • 排序和排名
      • 时间序列
      • 文件输入与输出
      • 缺失值处理
      • 字符串处理
      • pandas sql
      • 其它
  • 语言基础
  • Java
  • Java基础
Will
2022-07-31
目录

Java 基础 - 反射

# 什么是反射

当虚拟机加载完类信息之后,就会在堆内存的方法区中针对每个类产生唯一一个 Class 类型的对象,该对象包含了其它类的结构信息。正常来说可以通过 new 的方式去创建一个类的对象,但是也可以通过记录类完整信息的 Class 对象去反向分析类的结构,这种能够分析类的结构和能力的程序称为反射(reflective),是一种功能强大且复杂的机制。反射机制可以用来:

  1. 在运行时分析类的成员变量和方法;
  2. 在运行时调用一个对象的成员变量和方法;
  3. 在运行时构造一个类的对象;
  4. 在运行时获取一个对象的类信息;
  5. 在运行时检查对象。

反射机制主要应用在开发工具(如框架)方面,在应用开发中使用较少。

# 核心类库

和反射相关的有 4 个核心类:

  1. java.lang.Class:用以表示类信息。
  2. java.lang.reflect.Constructor:用以表示类的构造器。
  3. java.lang.reflect.Field:用以表示类的成员变量。
  4. java.lang.reflect.Method:用以表示类的方法。

# Class 类

java.lang.Class 类是一个特殊的类(实际上是一个泛型类),它在程序运行期间始终为所有对象维护一个运行时的类型标识,其中记录了各个类的完整结构信息,包括构造器、成员变量和方法的属性及结果。Class 类是反射的根源,任何想通过反射动态加载、运行的行为都必须从 Class 对象开始。

Class 类的主要方法:

  • static Class forName(String name):返回指定类名 name 的 Class 对象。
  • Object newInstance():调用缺省构造函数,返回该 Class 对象的一个实例。
  • String getName():返回此 Class 对象所表示的实体(类、接口、数组类、基本类型或 void)名称。
  • Class getSuperClass():返回当前 Class 对象的父类的 Class 对象。
  • Class[] getInterfaces():返回当前 Class 对象的所有接口。
  • ClassLoader getClassLoader():返回该类的类加载器。
  • Constructor<T>[] getConstructors():返回此 Class 对象所表示的类的所有 public 构造方法。
  • Constructor<T>[] getDeclaredConstructors():返回此 Class 对象表示的类声明的所有构造方法。
  • Field[] getFields():返回此 Class 对象所表示的类或接口的 public 的 Field。
  • Field[] getDeclaredFields():返回此 Class 对象所表示的类或接口的全部 Field。
  • Method getMethod():返回此 Class 对象所表示的类或接口的 public 的方法。
  • Method[] getDeclaredMethods():返回此 Class 对象所表示的类或接口的全部方法。

获取 Class 对象的三种方式:

  1. 通过对象的getClasss()方法
Student s;

Class clazz = s.getClass();
1
2
3
  1. 使用 Class 类的静态方法forName()
Class clazz = Class.forName("com.sqlboy.Student");
1
  1. 通过T.class获取
Class clazz = Student.class;
1

提示

由于虚拟机为每个类型都管理了一个唯一的 Class 对象,所以在比较两个类是否相等时可以使用==。

if (Student.class == Class.forName("com.sqlboy.Student")){
    // pass
}
1
2
3

# Constructor 类

Constructor 类用以描述类的构造器信息。主要方法:

  • int getModifiers():获取构造器的修饰符。
  • String getName():获取方法名称。
  • Class<?>[] getParameterTypes():获取参数类型。

# Field 类

Field 类用以描述类的成员变量信息。主要方法:

  • Field[] getFields():获取 Class 对象表示的类或接口的 pubic 的 Field。
  • Field[] getDeclaredFields():获取 Class 对象所表示的类或接口的全部 Field。

# Method 类

Method 类用以描述类的方法信息。主要方法:

  • Class<?> getReturnType():获取返回值类型。
  • Class<?>[] getParameterTypes():获取所有参数。
  • int getModifiers():获取修饰符。
  • Class<?>[] getExceptionTypes()获取异常信息。
  • Object invoke(Object obj, Object... args):执行类对象的方法。

对于 invoke 方法的使用说明:

  1. invoke 方法的返回值 Object 对应原方法的返回值,若原方法无返回值,则 Object 为 null。
  2. 若原方法为静态方法,此时形参 obj 为 null。
  3. 若原方法形参列表为空,则形参 args 为 null。
  4. 若原方法声明为 private,则需要在调用 invoke 方法前显式调用方法对象的 setAccessible(true) 方法。

示例:

package com.sqlboy.reflect;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

/**
 * 在运行时创建类对象
 */
public class ClassTest {
    public static void main(String[] args) throws Exception {
        System.out.println("程序已经开始执行");
        Class clazz = Person.class;

        Constructor constructor = clazz.getDeclaredConstructor(String.class, Integer.class);
        Object person = constructor.newInstance("张三", 18);
        System.out.println(person);
        Method say = clazz.getDeclaredMethod("say");
        say.setAccessible(true);
        say.invoke(person);
    }
}

class Person {

    private String name;
    private Integer age;

    Person() {
    }

    Person(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    public String toString() {
        return "name: " + name + ",age: " + age;
    }

    private void say() {
        System.out.println("我的名字是:" + name + ", 我今年 " + age + " 岁");
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43

输出:

程序已经开始执行
name: 张三,age: 18
我的名字是:张三, 我今年 18 岁
1
2
3

# 综合案例

下面的代码是一个关于反射的综合应用,输入任意类,将会打印该类的全部信息:

import java.lang.reflect.*;
import java.util.*;

public class ReflectionTest {
    public static void main(String[] args) {
        // 从命令行参数或用户输入读取类名
        String name;
        if (args.length > 0) name = args[0];
        else {
            Scanner in  = new Scanner(System.in);
            System.out.println("Enter a class name (e.g. java.util.Date): ");
            name = in.next();
        }

        try{
            //打印类名和父类名(if != Object)
            Class cl = Class.forName(name);
            Class supercl = cl.getSuperclass();
            String modifiers = Modifier.toString(cl.getModifiers());
            if (modifiers.length() > 0) System.out.print(modifiers + " ");
            System.out.print("class " + name);
            if (supercl != null && supercl != Object.class ){
                System.out.print(" extends " + supercl.getName());
            }
            System.out.print("\n{\n");
            printConstructors(cl);
            System.out.println();
            printMethods(cl);
            System.out.println();
            printFields(cl);
            System.out.println("}");

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        System.exit(0);
    }

    /**
     * 打印类的所有构造函数
     * @param cl
     */
    public static void printConstructors(Class cl) {
        Constructor[] constructors = cl.getConstructors();
        for (Constructor c : constructors){
            String name = c.getName();
            System.out.print("  ");
            String modifiers = Modifier.toString(cl.getModifiers());//修饰符字符串
            if (modifiers.length() > 0){
                System.out.print(modifiers + " ");
            }
            System.out.print(name + "(");

            //打印参数类型
            Class[] parameterType = c.getParameterTypes();
            for (int j = 0; j < parameterType.length; j++) {
                if (j > 0) System.out.print(", ");
                System.out.print(parameterType[j].getName());
            }
            System.out.println(");");
        }
    }

    /**
     * 打印一个类的所有方法
     * @param cl
     */
    public static void printMethods(Class cl) {
        Method[] methods = cl.getDeclaredMethods();
        for (Method m : methods){
            Class returnType = m.getReturnType();
            String name = m.getName();
            System.out.print("  ");
            //打印修饰符,返回类型,以及方法名
            String modifiers = Modifier.toString(cl.getModifiers());
            if (modifiers.length() > 0) System.out.print(modifiers + " ");
            System.out.print(returnType.getName() + " " + name + "(");
            //打印参数类型
            Class[] parameterTypes = m.getParameterTypes();
            for (int j = 0; j < parameterTypes.length; j++) {
                if (j > 0) System.out.print(", ");
                System.out.print(parameterTypes[j].getName());
            }
            System.out.println(");");
        }
    }

    /**
     * 打印类的所有字段
     * @param cl
     */
    public static void printFields(Class cl) {
        Field[] declaredFields = cl.getDeclaredFields();
        for (Field f : declaredFields){
            Class type = f.getType();
            String name = f.getName();
            System.out.print("  ");
            //打印 修饰符 类型名 变量名
            String modifiers = Modifier.toString(f.getModifiers());
            if (modifiers.length() > 0) System.out.print(modifiers + " ");
            System.out.println(type.getName() + " " + name + ";");
        }
    }

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105

使用示例:

$ javac ReflectionTest.java
$ java ReflectionTest
Enter a class name (e.g. java.util.Date):
java.lang.String
public final class java.lang.String
{
  public final java.lang.String([B, int, int);
  public final java.lang.String([B, java.nio.charset.Charset);
  public final java.lang.String([B, java.lang.String);
  public final java.lang.String([B, int, int, java.nio.charset.Charset);
  public final java.lang.String([B, int, int, java.lang.String);
  public final java.lang.String(java.lang.StringBuilder);
  public final java.lang.String(java.lang.StringBuffer);
  public final java.lang.String([B);
  public final java.lang.String([I, int, int);
  public final java.lang.String();
  public final java.lang.String([C);
  public final java.lang.String(java.lang.String);
  public final java.lang.String([C, int, int);
  public final java.lang.String([B, int);
  public final java.lang.String([B, int, int, int);

  public final boolean equals(java.lang.Object);
  public final java.lang.String toString();
  public final int hashCode();
  public final int compareTo(java.lang.Object);
  public final int compareTo(java.lang.String);
  public final int indexOf(java.lang.String, int);
  public final int indexOf([C, int, int, java.lang.String, int);
  public final int indexOf([C, int, int, [C, int, int, int);
  public final int indexOf(int);
  public final int indexOf(java.lang.String);
  public final int indexOf(int, int);
  public final java.lang.String valueOf(char);
  public final java.lang.String valueOf(java.lang.Object);
  public final java.lang.String valueOf(boolean);
  public final java.lang.String valueOf([C, int, int);
  public final java.lang.String valueOf([C);
  public final java.lang.String valueOf(double);
  public final java.lang.String valueOf(float);
  public final java.lang.String valueOf(long);
  public final java.lang.String valueOf(int);
  public final void checkBounds([B, int, int);
  public final int length();
  public final boolean isEmpty();
  public final char charAt(int);
  public final int codePointAt(int);
  public final int codePointBefore(int);
  public final int codePointCount(int, int);
  public final int offsetByCodePoints(int, int);
  public final void getChars(int, int, [C, int);
  public final void getChars([C, int);
  public final [B getBytes();
  public final [B getBytes(java.lang.String);
  public final void getBytes(int, int, [B, int);
  public final [B getBytes(java.nio.charset.Charset);
  public final boolean contentEquals(java.lang.StringBuffer);
  public final boolean contentEquals(java.lang.CharSequence);
  public final boolean nonSyncContentEquals(java.lang.AbstractStringBuilder);
  public final boolean equalsIgnoreCase(java.lang.String);
  public final int compareToIgnoreCase(java.lang.String);
  public final boolean regionMatches(int, java.lang.String, int, int);
  public final boolean regionMatches(boolean, int, java.lang.String, int, int);
  public final boolean startsWith(java.lang.String);
  public final boolean startsWith(java.lang.String, int);
  public final boolean endsWith(java.lang.String);
  public final int indexOfSupplementary(int, int);
  public final int lastIndexOf(int, int);
  public final int lastIndexOf([C, int, int, [C, int, int, int);
  public final int lastIndexOf([C, int, int, java.lang.String, int);
  public final int lastIndexOf(java.lang.String, int);
  public final int lastIndexOf(int);
  public final int lastIndexOf(java.lang.String);
  public final int lastIndexOfSupplementary(int, int);
  public final java.lang.String substring(int);
  public final java.lang.String substring(int, int);
  public final java.lang.CharSequence subSequence(int, int);
  public final java.lang.String concat(java.lang.String);
  public final java.lang.String replace(char, char);
  public final java.lang.String replace(java.lang.CharSequence, java.lang.CharSequence);
  public final boolean matches(java.lang.String);
  public final boolean contains(java.lang.CharSequence);
  public final java.lang.String replaceFirst(java.lang.String, java.lang.String);
  public final java.lang.String replaceAll(java.lang.String, java.lang.String);
  public final [Ljava.lang.String; split(java.lang.String, int);
  public final [Ljava.lang.String; split(java.lang.String);
  public final java.lang.String join(java.lang.CharSequence, [Ljava.lang.CharSequence;);
  public final java.lang.String join(java.lang.CharSequence, java.lang.Iterable);
  public final java.lang.String toLowerCase(java.util.Locale);
  public final java.lang.String toLowerCase();
  public final java.lang.String toUpperCase();
  public final java.lang.String toUpperCase(java.util.Locale);
  public final java.lang.String trim();
  public final [C toCharArray();
  public final java.lang.String format(java.util.Locale, java.lang.String, [Ljava.lang.Object;);
  public final java.lang.String format(java.lang.String, [Ljava.lang.Object;);
  public final java.lang.String copyValueOf([C, int, int);
  public final java.lang.String copyValueOf([C);
  public final java.lang.String intern();

  private final [C value;
  private int hash;
  private static final long serialVersionUID;
  private static final [Ljava.io.ObjectStreamField; serialPersistentFields;
  public static final java.util.Comparator CASE_INSENSITIVE_ORDER;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
上次更新: 2023/11/01, 03:11:44

← Java 基础 - 泛型 Java 基础 - 代理模式→

Theme by Vdoing | Copyright © 2022-2023 Will 蜀ICP备2022002285号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式