在 Class
类中有众多方法用来判断当前 Class
的类型
方法名 | 描述 |
---|---|
isPrimitive() | 是否基本数据类型,如:int、long、double |
isInterface() | 是否是接口 |
isEnum() | 是否是枚举 |
isAnnotation() | 是否是注解 |
isArray() | 是否是数组 |
isAnonymousClass() | 是否匿名类 |
isSynthetic() | 是否合成类,由 JVM 编译生成 |
isMemberClass() | 是否内部类,包括静态内部类 |
isLocalClass() | 是否局部类,方法内部定义的类 |
isAssignableFrom(Class) | ClassA.isAssignableFrom(ClassB),A 是否 B 的父类或者相同类 |
isInstance(Object) | ClassA.isAssignableFrom(obj),相当于 obj instanceof ClassA |
基本数据类型 & 数组
JAVA
提供了八种基本数据类型:byte
、short
、int
、long
、float
、double
、boolean
、char
。
// 基本数据类型
System.out.println(long.class.isPrimitive());
// 数组
System.out.println(String[].class.isArray());
接口 & 枚举 & 注解
// 接口
System.out.println(Cloneable.class.isInterface());
// 枚举
System.out.println(ElementType.class.isEnum());
// 注解
System.out.println(Override.class.isAnnotation());
匿名类 & 内部类 & 局部类
- 匿名类:直接实现接口,没有类名的类
- 内部类:定义在其它类内部的类
- 局部类:在方法中定义的类,生命周期就是方法的生命周期
public class Test {
public static void main(String[] args) {
Cloneable anonymous = new Cloneable() {
};
print(anonymous.getClass());
print(Member.class);
print(StaticMember.class);
class LocalClass {
}
print(LocalClass.class);
Object proxy = Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class[]{Cloneable.class}, (p, m, a) -> null);
print(proxy.getClass());
}
public static void print(Class<?> clazz) {
System.out.println("----------------------------------------------------------------");
System.out.println(clazz.getName() + " isAnonymousClass:" + clazz.isAnonymousClass());
System.out.println(clazz.getName() + " isMemberClass:" + clazz.isMemberClass());
System.out.println(clazz.getName() + " isLocalClass:" + clazz.isLocalClass());
System.out.println(clazz.getName() + " isSynthetic:" + clazz.isSynthetic());
}
public class Member {
}
public static class StaticMember {
}
}
输出结果
-----------------------------------------------------------
com.Test$1 isAnonymousClass:true
com.Test$1 isMemberClass:false
com.Test$1 isLocalClass:false
com.Test$1 isSynthetic:false
-----------------------------------------------------------
com.Test$Member isAnonymousClass:false
com.Test$Member isMemberClass:true
com.Test$Member isLocalClass:false
com.Test$Member isSynthetic:false
-----------------------------------------------------------
com.Test$StaticMember isAnonymousClass:false
com.Test$StaticMember isMemberClass:true
com.Test$StaticMember isLocalClass:false
com.Test$StaticMember isSynthetic:false
-----------------------------------------------------------
com.Test$1LocalClass isAnonymousClass:false
com.Test$1LocalClass isMemberClass:false
com.Test$1LocalClass isLocalClass:true
com.Test$1LocalClass isSynthetic:false
-----------------------------------------------------------
com.sun.proxy.$Proxy0 isAnonymousClass:false
com.sun.proxy.$Proxy0 isMemberClass:false
com.sun.proxy.$Proxy0 isLocalClass:false
com.sun.proxy.$Proxy0 isSynthetic:false
isSynthetic
是否合成,其实在 Method
、Field
等反射类中也有这个方法,表示这个类、方法、字段是否是由 JVM
编译期额外生成。
桥接方法
桥接方法用于处理引入泛型带来的方法继承问题。
声明一个泛型接口
public interface A<T> {
void test(T t);
}
使用 String
类型实现一个具体的实现类
public class B implements A<String> {
public void test(String s) {
System.out.println(s);
}
}
泛型经过编译会被擦除,所以接口 A
在编译后,test
方法的入参会被转换为 Object
public interface A {
void test(Object t);
}
而实现类中的入参却是具体的 String
类型,并没有实现 void test(Object t)
方法。但是这个代码是正确的,可以正常运行,因为 JVM
在编译过程中对我们的实现类做了一点手脚
public class B implements A {
public void test(String s) {
System.out.println(s);
}
public void test(Object s) {
this.test((String) s);
}
}
编译后的类 B
也擦除了泛型,但是增加了一个方法同名的 test
方法,这个方法由 JVM
在编译期生成,解决了泛型带来的继承问题,这个方法就是桥接方法,同时也是合成方法。
通过反射验证一下
public class Test {
public static void main(String[] args) {
Class<B> classB = B.class;
Method[] methods = classB.getDeclaredMethods();
System.out.println("方法总数量:" + methods.length);
for (Method method : methods) {
System.out.println(method.getReturnType().getSimpleName() + " "
+ method.getName() +
"(" + method.getParameters()[0].getType().getSimpleName() + ")"
+ " isBridge" + method.isBridge()
+ " isSynthetic" + method.isSynthetic()
);
}
}
}
输出如下
方法总数量:2
void test(String) isBridge false isSynthetic false
void test(Object) isBridge true isSynthetic true
内部类
内部类之所以能够直接访问外部类中的属性,是因为编译器自动为内部类添加一个成员变量,这个成员变量指向外部类对象的引用,同时 JVM
在编译时会为内部类的构造方法添加一个外部类的入参,在创建内部类实例时,会传入外部类实例并设置到 JVM
生成的成员变量。
但是静态内部类就没有,因为静态内部与外部类是同等地位,而普通的内部类依赖于外部类
public class Test {
public static void main(String[] args) {
printField(Member.class);
System.out.println("------------------------------------");
printField(StaticMember.class);
}
public static void printField(Class<?> clazz) {
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
System.out.println(field.getType() + " " + field.getName() + " isSynthetic:" + field.isSynthetic());
}
}
public class Member {
}
public static class StaticMember {
}
}
输出如下
class com.Test this$0 isSynthetic:true
-------------------------------------------
继承关系判断
instanceof
如果你有一个对象实例,需要判断该实例是否属于某个类型,就可以使用 instanceof
进行判断。instanceof
是 JAVA
的关键字。
String s = "Hello World";
System.out.println(s instanceof String); // true
isInstance
Class
类中提供了一个 isInstance(Object)
方法,该方法与 instanceof
动态等价。
String s = "Hello World";
System.out.println(String.class.isInstance(s)); // true
isAssignableFrom
如果没有对象实例,单纯判断两个类的继承关系,则可以使用 父类.class.isAssignableFrom(子类.class)
来进行判断。
System.out.println(ArrayList.class.isAssignableFrom(List.class)); //false
System.out.println(List.class.isAssignableFrom(ArrayList.class)); //true
如果是同一个类,isAssignableFrom 也返回 true