Class

作者: sollian | 来源:发表于2018-06-11 18:08 被阅读93次

    在运行中的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方法仅仅加载类,不会初始化。这是forNameloadClass的一点区别。

    该方法不能用于获取原始类型或者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;
        }
    

    若该类是

    1. 普通类:返回其实现的所有接口,若没有则返回空数组。
    2. 接口:返回其扩展的所有接口,若没有则返回空数组。
    3. 数组:返回new Class<?>[] { Cloneable.class, Serializable.class }
    4. 原始类型或者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()

    返回当前类的所有注解。

    相关文章

      网友评论

        本文标题:Class

        本文链接:https://www.haomeiwen.com/subject/buiwsftx.html