首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java Class 類深度解析:反射入口、泛型語法與運行時類型識別

     編輯:Java 相關知識

Class 類:Java 反射的核心入口

java.lang.Class<T> 是 Java 反射機制的核心,JVM 為每個載入的類、介面、枚舉、註解、基本類型、陣列類型創建唯一的 Class 實例。它封裝了類的完整元數據:修飾符、父類、介面、構造器、方法、欄位、註解等。理解 Class 是掌握反射、依賴注入框架、序列化庫的基石。

三種獲取 Class 對象的方式

public class ClassDemo {
    public static void main(String[] args) throws ClassNotFoundException {
        // 方式 1: 類字面常量 (編譯期已知類型,不觸發類初始化)
        Class<String> c1 = String.class;
        Class<int> c2 = int.class;        // 基本類型也有 Class 對象
        Class<String[]> c3 = String[].class; // 陣列類型

        // 方式 2: 對象 getClass() (運行期獲取實際類型)
        String str = "Hello";
        Class<? extends String> c4 = str.getClass(); // 返回 String.class

        // 方式 3: Class.forName() (字串名稱動態載入,會觸發類初始化)
        Class<?> c5 = Class.forName("java.lang.String");
        
        System.out.println(c1 == c4); // true: JVM 保證同一類載入器下 Class 實例唯一
        System.out.println(c1 == c5); // true
    }
}

關鍵差異對照表

方式觸發類初始化適用場景異常處理
.class否編譯期已知類型、註解處理器編譯期檢查
obj.getClass()否運行期獲取實例真實類型無拋出檢查異常
Class.forName()是配置驅動、SPI 機制、動態代理拋出 ClassNotFoundException

泛型 Class 語法:類型安全的反射

JDK 5 引入 Class<T> 泛型參數,讓反射操作獲得編譯期類型檢查:

// 1. 精確類型綁定
Class<String> stringClass = String.class;
String instance = stringClass.getDeclaredConstructor().newInstance(); // 返回 String,無需轉型

// 2. 通配符上界: 接受 Number 及其子類
Class<? extends Number> numClass = Integer.class;
numClass = Double.class; // 合法
// numClass = String.class; // 編譯錯誤

// 3. 通配符下界: 接受 Integer 及其父類
Class<? super Integer> intSuper = Integer.class;
intSuper = Number.class; // 合法
intSuper = Object.class; // 合法

// 4. 無界通配符: 接受任意類型 (相當於 Class<?>)
Class<?> anyClass = String.class;
anyClass = int[].class; // 合法

實戰場景:獲取父類泛型參數 (如 MyBatis Mapper 解析)

利用 Type 體系 (ParameterizedType) 可提取泛型實際類型參數:

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

class BaseDao<T> {
    private Class<T> entityClass;

    @SuppressWarnings("unchecked")
    public BaseDao() {
        Type genericSuperclass = getClass().getGenericSuperclass();
        if (genericSuperclass instanceof ParameterizedType) {
            Type[] actualTypeArgs = ((ParameterizedType) genericSuperclass).getActualTypeArguments();
            this.entityClass = (Class<T>) actualTypeArgs[0];
        }
    }
    public Class<T> getEntityClass() { return entityClass; }
}

class UserDao extends BaseDao<User> {} // User 為實體類

public class GenericTypeDemo {
    public static void main(String[] args) {
        UserDao dao = new UserDao();
        System.out.println("實體類型: " + dao.getEntityClass().getName()); // 輸出: com.example.User
    }
}
class User {}

Class 對象創建實例的兩種路徑

Class<User> clazz = User.class;

// 方式 1: newInstance() (已棄用 JDK 9+, 僅能調用 public 無參構造器)
User u1 = clazz.newInstance(); 

// 方式 2: Constructor.newInstance() (推薦,支援私有構造器、帶參構造器)
User u2 = clazz.getDeclaredConstructor(String.class, int.class).newInstance("Tom", 18);

總結

Class 類不僅是反射的入口,更是 Java 類型系統在運行時的鏡像。掌握 Class<T> 泛型語法、三種獲取方式的語義差異、以及 Type 體系對泛型擦除的補完,能讓你在框架開發、動態代理、序列化等進階場景中遊刃有餘。記住:.class 不初始化類,forName() 會初始化,這在靜態塊有副作用時至關重要。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved