通过 Class 对象获取类型信息

  |  

摘要: 本文主要是关于如何用 Class 对象获取类型的各种信息。

【对算法,数学,计算机感兴趣的同学,欢迎关注我哈,阅读更多原创文章】
我的网站:潮汐朝夕的生活实验室
我的公众号:算法题刷刷
我的知乎:潮汐朝夕
我的github:FennelDumplings
我的leetcode:FennelDumplings


3 种方式获取类的 Class 对象

  1. .class 获取 Class 实例,对于基本数据类型的封装类,可以用 .TYPE 获取相应的 Class 实例。
  2. 调用 getClass 方法获取 Class 实例。
  3. 调用 Class 类的静态方法 forName,获取 Class 实例。
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
class Student {
static {
System.out.println("加载 Student 类");
}

public Student() {
System.out.println("Construct Student");
}
}

public class ClassTest {
public static void main(String[] args) throws Exception {
Integer in = 5;

Class c1 = int.class;
System.out.println("c1 = " + c1);

Class c2 = Integer.class;
System.out.println("c2 = " + c2);

Class c3 = Integer.TYPE;
System.out.println("c3 = " + c3);

Class c4 = in.getClass();
System.out.println("c4 = " + c4);

Class<?> c5 = Class.forName("java.lang.String");
System.out.println("c5 = " + c5);

Class c6 = Student.class;
System.out.println("c6 = " + c6);

Class<?> c7 = Class.forName("Student");
System.out.println("c7 = " + c7);
}
}

结果如下:

1
2
3
4
5
6
7
8
c1 = int
c2 = class java.lang.Integer
c3 = int
c4 = class java.lang.Integer
c5 = class java.lang.String
c6 = class Student
加载 Student 类
c7 = class Student

一些要点如下:

  • 当使用 Student.class 获取 Class 对象时,在 Student 类中没有任何代码被执行。
  • 在使用 Class.forName 获取 Student 类的 Class 对象时,Student 类中的静态代码块被执行了,因为在类加载的时候,静态代码块中的语句就会被执行。Student 类的构造方法并没有被调用,说明这个时候并没有 Student 类对象的产生。

用 Class 对象获取类型信息

(1) 方法和字段信息

方法和字段信息都是通过类表示的,这些类位于 java.lang.reflect 包中,方法又分为构造方法和普通方法。

  • 构造方法(也称为构造器)的类是 Constructor
  • 对应方法的类是 Method
  • 对应字段的类是 Field
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
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

class MyClass {
public int pubField;
private int priField;
protected int proField;

public MyClass() {}
public MyClass(int a) {}
protected MyClass(int a, int b) {}
private MyClass(int a, int b, int c) {}

public void pub_method() {}
protected void pro_method() {}
void defMethod() {}
private void priMethod() {}

public static void staticMethod() {}
}

interface MyInterface {
float pi = 3.14f;
void fun();
default void defFun() {}
static void staticFun() {}
private void priFun() {}
}

public class ClassInfo {
public static void main(String[] args) {
Class cls = MyClass.class;

System.out.println("Fields: ");
// 只获取公共字段
for(Field f: cls.getFields()) {
System.out.println(f);
}
System.out.println("-------------------");

System.out.println("Constructors: ");
// 获取所有声明的构造器
for(Constructor c: cls.getDeclaredConstructors()) {
System.out.println(c);
}
System.out.println("-------------------");

System.out.println("Methods: ");
// 只获取公共方法,报错从 Object 继承的公共方法
for(Method m: cls.getMethods()) {
System.out.println(m);
}
System.out.println("-------------------");

Class clz = MyInterface.class;
System.out.println("Interface's Methods: ");
// 只获取接口中的公共方法
for(Method m: clz.getMethods()) {
System.out.println(m);
}
System.out.println("-------------------");
}
}

结果如下:

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
Fields: 
public int MyClass.pubField
-------------------
Constructors:
private MyClass(int,int,int)
protected MyClass(int,int)
public MyClass(int)
public MyClass()
-------------------
Methods:
public void MyClass.pub_method()
public static void MyClass.staticMethod()
public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
public final void java.lang.Object.wait() throws java.lang.InterruptedException
public boolean java.lang.Object.equals(java.lang.Object)
public java.lang.String java.lang.Object.toString()
public native int java.lang.Object.hashCode()
public final native java.lang.Class java.lang.Object.getClass()
public final native void java.lang.Object.notify()
public final native void java.lang.Object.notifyAll()
-------------------
Interface's Methods:
public abstract void MyInterface.fun()
public default void MyInterface.defFun()
public static void MyInterface.staticFun()
-------------------

(2) 基类与接口信息

了解一个类的基类或者实现的接口,可以用于判断某个对象是否可以进行安全的类型转换。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
interface A {}
interface B {}
class Base {}

class Derived extends Base implements A, B {}

public class SuperClassAndInterface {
public static void main(String[] args) {
Class cls = Derived.class;
Class baseCls = cls.getSuperclass();
System.out.println("基类: ");
System.out.println(baseCls);

System.out.println("实现的接口: ");
Class[] interfaces = cls.getInterfaces();
for(Class c: interfaces) {
System.out.println(c);
}
}
}

结果如下:

1
2
3
4
5
基类: 
class Base
实现的接口:
interface A
interface B

(3) 枚举信息

Class 对象表示的是枚举类型,那么可以调用 getEnumConstants 方法来得到所有的枚举值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
enum Week {
Monday, Tuesday, Wednesday, Thursday,
Friday, Saturday, Sunday;
}

public class EnumInfo {
public static void main(String[] args) {
Class<Week> cls = Week.class;

Week[] weeks = cls.getEnumConstants();
for(Week w: weeks) {
System.out.println(w);
}
}
}

结果如下:

1
2
3
4
5
6
7
Monday
Tuesday
Wednesday
Thursday
Friday
Saturday
Sunday

(4) 获取泛型信息

获取泛型信息的代码如下,可以对照着注释和输出结果来看。

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
import java.util.ArrayList;
import java.util.Arrays;
import java.lang.reflect.Type;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.WildcardType;
import java.lang.reflect.Method;

interface Functor<T> {
void call(T args);
}

class MyCallBack implements Functor<Object> {
public void call(Object args) {
System.out.println(args);
}
}

class CallbackTest {
public static <T> T callback(ArrayList<T> list, Functor<? super T> fun) {
for(T each: list) {
fun.call(each);
}
return list.get(0);
}
}

public class GenericInfo {
public static void main(String[] args) {
System.out.println("[MyCallBack 类的泛型信息]");
Class cls = MyCallBack.class;
Type baseType = cls.getGenericSuperclass();
System.out.println("基类: ");
System.out.println(baseType);

System.out.println("实现的接口: ");
Type[] interfaces = cls.getGenericInterfaces();
for(Type t: interfaces) {
System.out.println(t);
// 如果接口是参数化类型
if(t instanceof ParameterizedType) {
ParameterizedType pt = (ParameterizedType) t;
// 得到实际的类型参数
Type[] typeArgs = pt.getActualTypeArguments();
for(Type ta: typeArgs) {
System.out.println("-- 实际的类型参数: " + ta);
}
}
}

System.out.println("------------------");

System.out.println("CallbackTest 类中泛型方法的泛型信息");
Class cl = CallbackTest.class;
Method method = cl.getMethods()[0];
System.out.println("方法参数的类型: ");

Type[] paramTypes = method.getGenericParameterTypes();
for(Type t: paramTypes) {
System.out.println(t);
// 如果形参是参数化类型
if(t instanceof ParameterizedType) {
ParameterizedType pt = (ParameterizedType) t;
// 得到实际的参数类型
Type[] typeArgs = pt.getActualTypeArguments();
for(Type ta: typeArgs) {
System.out.println("-- 实际的类型参数: " + ta);
// 如果是通配符类型
if(ta instanceof WildcardType) {
WildcardType wt = (WildcardType) ta;
// 输出类型变量的下限
System.out.println("-------" + Arrays.toString(wt.getLowerBounds()));
// 输出类型变量的上限
System.out.println("-------" + Arrays.toString(wt.getUpperBounds()));
}
}
}
}
System.out.println("方法的返回类型: ");
Type returnType = method.getGenericReturnType();
System.out.println(returnType);
}
}

结果如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
[MyCallBack 类的泛型信息]
基类:
class java.lang.Object
实现的接口:
Functor<java.lang.Object>
-- 实际的类型参数: class java.lang.Object
------------------
CallbackTest 类中泛型方法的泛型信息
方法参数的类型:
java.util.ArrayList<T>
-- 实际的类型参数: T
Functor<? super T>
-- 实际的类型参数: ? super T
-------[T]
-------[class java.lang.Object]
方法的返回类型:
T

检测类型

所有类型都有 Class 对象,当得到一个 Class 对象后,若想知道它对应的是哪一种类型,那么可以调用 Class 类中的 isXxx 方法。

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
interface A {}

class X {
class B {}
public static A getA() {
class C implements A {}
return new C();
}
}

enum D {}

public class DetectType {
public static void main(String[] args) {
Class c1 = int.class;
System.out.printf("c1 是否是基本数据类型: %b%n", c1.isPrimitive());

Integer in = 2;
Class c2 = in.getClass();
System.out.printf("c2 是否是基本数据类型: %b%n", c2.isPrimitive());

int[] arr = new int[3];
Class c3 = arr.getClass();
System.out.printf("c3 是否是数组类型: %b%n", c3.isArray());

Class c4 = D.class;
System.out.printf("c4 是否是枚举类型: %b%n", c4.isEnum());

Class c5 = A.class;
System.out.printf("c5 是否是接口类型: %b%n", c5.isInterface());

Class c6 = X.B.class;
System.out.printf("c6 是否是内部类: %b%n", c6.isMemberClass());

Class c7 = X.getA().getClass();
System.out.printf("c7 是否是内部类: %b%n", c7.isLocalClass());

A a = new A() {};
Class c8 = a.getClass();
System.out.printf("c8 是否是匿名类: %b%n", c8.isAnonymousClass());
}
}

结果如下:

1
2
3
4
5
6
7
8
c1 是否是基本数据类型: true
c2 是否是基本数据类型: false
c3 是否是数组类型: true
c4 是否是枚举类型: true
c5 是否是接口类型: true
c6 是否是内部类: true
c7 是否是内部类: true
c8 是否是匿名类: true

Share