在运行中的Java应用中,Class类的实例代表类或者接口。
enum、数组是一种类,annotation是一种接口。
Java原始类型(boolean,byte,char,short,int,log,float,double)以及void关键字也是类。
public final class Class<T> implements java.io.Serializable,
GenericDeclaration,
Type,
AnnotatedElement {...}
AnnotatedElement是注解相关接口,可以用来获取Class的注解。
GenericDeclaration是泛型声明接口。
toString
public String toString() {
return (isInterface() ? "interface " : (isPrimitive() ? "" : "class "))
+ getName();
}
toString方法对于原始类型(int.class等)只打印类名。对于接口,类名前带有“interface”前缀;对于普通类则带有“class”前缀。
toGenericString
/*与`toString`的不同在于:
1. 带有可见性修饰符。
2. 对不同类型区分的更细。如annotation、interface、enum、class、原始类型。
3. 若是泛型,会带有泛型类型名。
*/
public String toGenericString() {
if (isPrimitive()) {
return toString();
} else {
StringBuilder sb = new StringBuilder();
// Class modifiers are a superset of interface modifiers
int modifiers = getModifiers() & Modifier.classModifiers();
if (modifiers != 0) {
sb.append(Modifier.toString(modifiers));
sb.append(' ');
}
if (isAnnotation()) {
sb.append('@');
}
if (isInterface()) { // Note: all annotation types are interfaces
sb.append("interface");
} else {
if (isEnum())
sb.append("enum");
else
sb.append("class");
}
sb.append(' ');
sb.append(getName());
TypeVariable<?>[] typeparms = getTypeParameters();//获取泛型参数列表
if (typeparms.length > 0) {
boolean first = true;
sb.append('<');
for(TypeVariable<?> typeparm: typeparms) {
if (!first)
sb.append(',');
sb.append(typeparm.getTypeName());
first = false;
}
sb.append('>');
}
return sb.toString();
}
}
public class JavaDemo<T extends Number, K> {
public static void main(String[] args) {
System.out.println(JavaDemo.class.toString());
System.out.println(JavaDemo.class.toGenericString());
}
}
输出如下:
class demo.sollian.com.demo.JavaDemo
public class demo.sollian.com.demo.JavaDemo<T,K>
forName
该函数与ClassLoader.loadClass相似,也是用来加载类。有两个重载方法:
public static Class<?> forName(String className)
throws ClassNotFoundException {
return forName(className, true, VMStack.getCallingClassLoader());
}
public static Class<?> forName(String name, boolean initialize,
ClassLoader loader)
throws ClassNotFoundException
{
if (loader == null) {
loader = BootClassLoader.getInstance();
}
Class<?> result;
try {
result = classForName(name, initialize, loader);
} catch (ClassNotFoundException e) {
Throwable cause = e.getCause();
if (cause instanceof LinkageError) {
throw (LinkageError) cause;
}
throw e;
}
return result;
}
第二个方法需要三个参数:类名称、是否初始化以及ClassLoader。第一个函数默认使用当前类的ClassLoader。
initialize为true时,会对类进行初始化,即执行类的静态代码块,初始化静态成员等。否则在对加载的类对象调用
newInstance
方法时进行类初始化。ClassLoader.load
方法仅仅加载类,不会初始化。这是forName
和loadClass
的一点区别。
该方法不能用于获取原始类型或者void。比如int.class.getName()
返回int,但若使用Class.forName("int")
则会抛出ClassNotFoundException。
如果name表示一个数组类,那么数组的元素类对象会自动加载,但不会初始化。比如:
public class Data {
static {
System.out.println("我来了");
}
}
上面是Data类。如下代码加载Data类,会执行静态代码块:
public static void main(String[] args) {
try {
Class<?> clazz = Class.forName("demo.sollian.com.demo.clazz.Data", true, ClassLoader.getSystemClassLoader());
} catch (Exception e) {
e.printStackTrace();
}
}
通过System.out.println(Car[].class.getName())
打印其数组类如下:
[Ldemo.sollian.com.demo.Car;
加载其数组类:
public static void main(String[] args) {
try {
Class<?> clazz = Class.forName("[Ldemo.sollian.com.demo.clazz.Data;", true, getSystemClassLoader());
// if (clazz != null) {
// Object obj = clazz.getComponentType().newInstance();
// }
} catch (Exception e) {
e.printStackTrace();
}
}
不会执行Data类的静态代码块,去掉注释,则会执行Data类的静态代码块。
需要注意的是,该方法并不会检查要加载的类对调用者是否可见。
public native T newInstance() throws InstantiationException, IllegalAccessException
创建一个类的实例,与调用该类的无参构造函数相似。如果该类未初始化,将进行初始化。
该方法会传递无参构造函数抛出的任何异常。
isInstance
public boolean isInstance(Object obj) {
if (obj == null) {
return false;
}
return isAssignableFrom(obj.getClass());
}
与instanceof
运算符等价。判断obj是否是调用类或其子类的实例。
若obj为null,则始终返回false。
若调用类是原始类型,则始终返回false,如:
System.out.println(int.class.isInstance(2));
System.out.println(Integer.class.isInstance(2));
返回false true
。
若调用类是数组类型,如:
System.out.println(List[].class.isInstance(new List[2]));
System.out.println(List[].class.isInstance(new ArrayList[2]));
System.out.println(int[].class.isInstance(new Integer[2]));
System.out.println(Integer[].class.isInstance(new int[2]));
返回true true false false
。
isAssignableFrom
isInstance最终调用了该方法来实现,从该方法可以学习其判断逻辑。
public boolean isAssignableFrom(Class<?> cls) {
if (this == cls) {//同一个类类型
return true; // Can always assign to things of the same type.
} else if (this == Object.class) {//调用类为Object类型,则当cls为原始类型时返回false。
return !cls.isPrimitive(); // Can assign any reference to java.lang.Object.
} else if (isArray()) {//同是数组时,比较其元素的类型
return cls.isArray() && componentType.isAssignableFrom(cls.componentType);
} else if (isInterface()) {//若调用类是接口,则当cls是该接口的实现类时,返回true。
// Search iftable which has a flattened and uniqued list of interfaces.
Object[] iftable = cls.ifTable;
if (iftable != null) {
for (int i = 0; i < iftable.length; i += 2) {
if (iftable[i] == this) {
return true;
}
}
}
return false;
} else {//否则判断调用类是否是cls的父类。
if (!cls.isInterface()) {
for (cls = cls.superClass; cls != null; cls = cls.superClass) {
if (cls == this) {
return true;
}
}
}
return false;
}
}
isInterface
判断是否是接口类型。
isArray
public boolean isArray() {
return getComponentType() != null;
}
判断是否是数组。
isPrimitive
判断是否是原始类型。除boolean byte char short int long float double
外,以下值也表示原始类型:
java.lang.Boolean#TYPE
java.lang.Character#TYPE
java.lang.Byte#TYPE
java.lang.Short#TYPE
java.lang.Integer#TYPE
java.lang.Long#TYPE
java.lang.Float#TYPE
java.lang.Double#TYPE
java.lang.Void#TYPE
isAnnotation
判断是否是注解类型。若该方法返回true,则isInterface
也返回true。
isSynthetic
判断是否是合成类。可以参考synthetic Java合成类型
getName
返回名称,包括类/接口/数组类型/原始类型/void。
若是数组类型,则“[”的个数表示数组的维度,元素类型表示如下:
元素类型 | 表示符号 |
---|---|
boolean | Z |
byte | B |
char | C |
double | D |
float | F |
int | I |
long | J |
short | S |
class or interface | Lclassname |
如:
System.out.println(void.class.getName());
System.out.println(int[].class.getName());
System.out.println(boolean[][][].class.getName());
System.out.println(TestAnnotation[].class.getName());//注解
System.out.println(Car[].class.getName());
结果如下:
void
[I
[[[Z
[Ldemo.sollian.com.demo.TestAnnotation;
[Ldemo.sollian.com.demo.Car;
getClassLoader
返回加载这个类的ClassLoader。返回null来表示bootstrap class loader。如果该类表示原始类型或者void,则返回null。
public synchronized TypeVariable<Class<T>>[] getTypeParameters()
该方法是GenericDeclaration
接口的方法,返回类型的泛型参数。如:
public class JavaDemo<T extends Number, K> {
public static void main(String[] args) {
for (TypeVariable<Class<JavaDemo>> var : JavaDemo.class.getTypeParameters()) {
System.out.print(var.getName() + ",");
for (Type type : var.getBounds()) {
System.out.print(type);
}
System.out.println();
}
}
}
输出如下:
T,class java.lang.Number
K,class java.lang.Object
getSuperclass
public Class<? super T> getSuperclass() {
// For interfaces superClass is Object (which agrees with the JNI spec)
// but not with the expected behavior here.
if (isInterface()) {
return null;
} else {
return superClass;
}
}
返回当前类的父类。
注:
如果当前类是Object、接口、原始类型或者void,则返回null。
如果当前类是数组类型,则返回Object。
getGenericSuperclass
public Type getGenericSuperclass() {
Type genericSuperclass = getSuperclass();
// This method is specified to return null for all cases where getSuperclass
// returns null, i.e, for primitives, interfaces, void and java.lang.Object.
if (genericSuperclass == null) {
return null;
}
String annotationSignature = getSignatureAttribute();
if (annotationSignature != null) {
GenericSignatureParser parser = new GenericSignatureParser(getClassLoader());
parser.parseForClass(this, annotationSignature);
genericSuperclass = parser.superclassType;
}
return Types.getType(genericSuperclass);
}
返回带有参数类型的父类。getSuperclass
的“注”同样适用于该方法。另外两个方法的返回值是不同的。
public class JavaDemo {
public static void main(String[] args) {
System.out.println(Child.class.getSuperclass());
System.out.println(Child.class.getGenericSuperclass());
}
private static class Parent<T> {
}
private static class Child extends Parent<String> {
}
}
结果为:
//前者返回值为Class类型,后者返回值为ParameterizedType类型
class demo.sollian.com.demo.JavaDemo$Parent
demo.sollian.com.demo.JavaDemo$Parent<java.lang.String>
public Package getPackage
返回类所在的包的信息。
getInterfaces
public Class<?>[] getInterfaces() {
if (isArray()) {
return new Class<?>[] { Cloneable.class, Serializable.class };
}
final Class<?>[] ifaces = getInterfacesInternal();
if (ifaces == null) {
return EmptyArray.CLASS;
}
return ifaces;
}
若该类是
- 普通类:返回其实现的所有接口,若没有则返回空数组。
- 接口:返回其扩展的所有接口,若没有则返回空数组。
- 数组:返回
new Class<?>[] { Cloneable.class, Serializable.class }
。 - 原始类型或者void:返回空数组。
数组中接口的顺序,与类或接口文件中实现或扩展的接口顺序相同。
getGenericInterfaces
参考getGenericSuperclass
public Class<?> getComponentType
若该类是数组类型,则返回该数组的元素类型;否则返回null。
getModifiers
返回类的修饰符,包括public, protected, private, final, static, abstract和interface,用一个int值表示。
如果是一个数组类型,它的访问修饰符(public, protected, private)和其元素一样。
如果是原始类型或者void,则访问修饰符是public(返回的int值中代表public的位等于1)
如果是数组类型或者原始类型或者void,则final位为1,interface位为0。
public native Class<?> getDeclaringClass()
如果该类是一个内部类(匿名内部类除外),则返回它的外部类;否则返回null。
对于枚举,可以参见java 枚举类 getClass和getDeclaringClass的区别
getSimpleName
public String getSimpleName() {
if (isArray())//数组类型,如int数组,返回“int[]”
return getComponentType().getSimpleName()+"[]";
if (isAnonymousClass()) {//匿名类
return "";
}
if (isMemberClass() || isLocalClass()) {//内部类或者局部类
// Note that we obtain this information from getInnerClassName(), which uses
// dex system annotations to obtain the name. It is possible for this information
// to disagree with the actual enclosing class name. For example, if dex
// manipulation tools have renamed the enclosing class without adjusting
// the system annotation to match. See http://b/28800927.
return getInnerClassName();
}
String simpleName = getName();
final int dot = simpleName.lastIndexOf(".");
if (dot > 0) {
return simpleName.substring(simpleName.lastIndexOf(".")+1); // strip the package name
}
return simpleName;
}
public native boolean isAnonymousClass()
是否是匿名类。如:
System.out.println(new ArrayList(){}.getClass().isAnonymousClass());//true
isLocalClass
判断是否是局部类。如:
public class JavaDemo implements Cloneable {
public static void main(String[] args) {
new JavaDemo().test();
}
public void test() {
class B extends ArrayList{
}
System.out.println(B.class.isLocalClass());
}
}
结果为true。
isMemberClass
判断是否是内部类。如:
public class JavaDemo implements Cloneable {
public static void main(String[] args) {
System.out.println(A.class.isMemberClass());
}
private static class A{
}
}
结果为true。
isLocalOrAnonymousClass
private boolean isLocalOrAnonymousClass() {
// JVM Spec 4.8.6: A class must have an EnclosingMethod
// attribute if and only if it is a local class or an
// anonymous class.
return isLocalClass() || isAnonymousClass();
}
getClasses
public Class<?>[] getClasses() {
List<Class<?>> result = new ArrayList<Class<?>>();
for (Class<?> c = this; c != null; c = c.superClass) {
for (Class<?> member : c.getDeclaredClasses()) {
if (Modifier.isPublic(member.getModifiers())) {
result.add(member);
}
}
}
return result.toArray(new Class[result.size()]);
}
返回该类及其所有父类中所有的访问修饰符为public的内部类和接口。如果该类型是原始类型、数组或者void,则返回一个空数组。
public native Class<?>[] getDeclaredClasses()
返回当前类的所有内部类和接口。
public Field[] getFields() throws SecurityException
返回该类及其所有父类的所有访问修饰符为public的字段。如果该类型是原始类型、数组或者void,则返回一个空数组。
public native Field[] getDeclaredFields()
返回当前类的所有字段。
public Method[] getMethods() throws SecurityException
返回该类及其所有父类及实现的接口中所有的访问修饰符为public的方法。如果该类型是原始类型或者void,则返回一个空数组。
不包括构造函数。
若有方法覆写的情况,则返回子类的方法。
public Method[] getDeclaredMethods() throws SecurityException
返回当前类的所有方法,不含构造方法。
public Constructor<?>[] getConstructors() throws SecurityException
返回该类所有的访问修饰符为public的构造方法。如果该类型是原始类型、数组或者void,则返回一个空数组。
public Constructor<?>[] getDeclaredConstructors() throws SecurityException
返回当前类的所有构造方法。
public Field getField(String name) throws NoSuchFieldException
返回该类或其所有父类、父接口中名称为name且访问修饰符为public的字段。找不到则抛出NoSuchFieldException异常。
public native Field getDeclaredField(String name) throws NoSuchFieldException
返回当前类名称为name的字段。找不到则抛出NoSuchFieldException异常。
不能用来获取数组的
length
字段。
public Method getMethod(String name, Class<?>... parameterTypes) throws NoSuchMethodException, SecurityException
返回该类或其所有父类、父接口中名称为name且访问修饰符为public的方法。找不到则抛出NoSuchMethodException异常。
parameterTypes为所要查找的方法的参数列表,顺序一致。需要注意的是,若方法的参数为int,则需要传入int.class;若是Integer,则需要传入Integer.class。其他原始类型及其包装类型以此类推。
该方法无法获取到构造方法。
public Method getDeclaredMethod(String name, Class<?>... parameterTypes) throws NoSuchMethodException, SecurityException
返回当前类的名称为name,参数列表为parameterTypes的方法。
public Constructor<T> getConstructor(Class<?>... parameterTypes) throws NoSuchMethodException, SecurityException
返回该类访问修饰符为public,且参数类型为parameterTypes的构造方法。
若该类是一个非静态内部类,需要将其外部类作为第一个参数。如下:
public class JavaDemo extends JavaDemo2 implements Cloneable {
public static void main(String[] args) {
try {
Constructor method = A.class.getConstructor(JavaDemo.class, //传入外部类
int.class);
if (method != null) {
System.out.println(method);
}
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
private class A {
public A(int a) {
}
}
}
输出为:
public demo.sollian.com.demo.JavaDemo$A(demo.sollian.com.demo.JavaDemo,int)
public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) throws NoSuchMethodException, SecurityException
返回该类参数类型为parameterTypes的构造方法。
getResourceAsStream
public InputStream getResourceAsStream(String name) {
name = resolveName(name);
ClassLoader cl = getClassLoader();
if (cl==null) {
// A system class.
return ClassLoader.getSystemResourceAsStream(name);
}
return cl.getResourceAsStream(name);
}
private String resolveName(String name) {
if (name == null) {
return name;
}
if (!name.startsWith("/")) {
Class<?> c = this;
while (c.isArray()) {
c = c.getComponentType();
}
String baseName = c.getName();
int index = baseName.lastIndexOf('.');
if (index != -1) {
name = baseName.substring(0, index).replace('.', '/')
+"/"+name;
}
} else {
name = name.substring(1);
}
return name;
}
getResource
public java.net.URL getResource(String name) {
name = resolveName(name);
ClassLoader cl = getClassLoader();
if (cl==null) {
// A system class.
return ClassLoader.getSystemResource(name);
}
return cl.getResource(name);
}
isEnum
判断该类是否是枚举类型
getEnumConstants
如果该类是枚举类型,则返回所有元素的数组,否则返回null。
cast
public T cast(Object obj) {
if (obj != null && !isInstance(obj))
throw new ClassCastException(cannotCastMsg(obj));
return (T) obj;
}
将obj强转成该类的类型。
getAnnotation
public <A extends Annotation> A getAnnotation(Class<A> annotationClass) {
Objects.requireNonNull(annotationClass);
A annotation = getDeclaredAnnotation(annotationClass);
if (annotation != null) {
return annotation;
}
if (annotationClass.isDeclaredAnnotationPresent(Inherited.class)) {
for (Class<?> sup = getSuperclass(); sup != null; sup = sup.getSuperclass()) {
annotation = sup.getDeclaredAnnotation(annotationClass);
if (annotation != null) {
return annotation;
}
}
}
return null;
}
返回该类或所有父类中带Inherited
注解的类型为annotationClass
的注解,如果没有则返回null。
有时候拿不到,是因为注解的RetentionPolicy的问题。
- SOURCE:仅在源码中保留,编译时会被丢弃。
- CLASS:编译时保留,运行时被丢弃。
- RUNTIME:一直保留。
public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass)
判断该类或所有父类中带Inherited
注解的注解中,是否包含指定类型的注解。
getAnnotations
public Annotation[] getAnnotations() {
/*
* We need to get the annotations declared on this class, plus the
* annotations from superclasses that have the "@Inherited" annotation
* set. We create a temporary map to use while we accumulate the
* annotations and convert it to an array at the end.
*
* It's possible to have duplicates when annotations are inherited.
* We use a Map to filter those out.
*
* HashMap might be overkill here.
*/
HashMap<Class<?>, Annotation> map = new HashMap<Class<?>, Annotation>();
for (Annotation declaredAnnotation : getDeclaredAnnotations()) {
map.put(declaredAnnotation.annotationType(), declaredAnnotation);
}
for (Class<?> sup = getSuperclass(); sup != null; sup = sup.getSuperclass()) {
for (Annotation declaredAnnotation : sup.getDeclaredAnnotations()) {
Class<? extends Annotation> clazz = declaredAnnotation.annotationType();
if (!map.containsKey(clazz) && clazz.isDeclaredAnnotationPresent(Inherited.class)) {
map.put(clazz, declaredAnnotation);
}
}
}
/* Convert annotation values from HashMap to array. */
Collection<Annotation> coll = map.values();
return coll.toArray(new Annotation[coll.size()]);
}
返回该类或所有父类中带Inherited
注解的所有注解。
public native <A extends Annotation> A getDeclaredAnnotation(Class<A> annotationClass)
返回当前类中类型为annotationClass
的注解。
public native Annotation[] getDeclaredAnnotations()
返回当前类的所有注解。
网友评论