Java反射Reflect中java.lang.Class类源码阅读讲解

Class类的实例对象代表的是正在运行的类或者接口的class对象;enum枚举是一种类class,注解是一种接口;每个数组也属于一个类class对象,该对象是通过反射Reflect生成的对象,该对象由具有相同元素类型和维数的所有数组共享;原生的Java类型boolean、byte、char、short、int、long、float、double和关键字void也可以表示为Class实例对象。

1.Class类的声明
public final
    class Class<T> implements java.io.Serializable,
                              java.lang.reflect.GenericDeclaration,
                              java.lang.reflect.Type,
                              java.lang.reflect.AnnotatedElement {

构造函数:

    /*
     * Constructor. Only the Java Virtual Machine creates Class
     * objects.
     */
    private Class() {}

Class类没有public公共构造函数,只有一个私有的无参构造函数,相反的,class对象是由Java虚拟机在类加载的时候自动生成的,并在类加载器中调用defineClass方法生成。

下面的例子使用class对象打印对象的class类名:

    void printClassName(Object obj) {
        System.out.println("The class of " + obj + " is " + obj.getClass().getName());
    }

也可以通过类名的方式获取类的class对象:

System.out.println("The name of class Foo is: "+Foo.class.getName());
2.Class类中forName方法讲解

方法声明如下:

    @CallerSensitive
    public static Class<?> forName(String name, boolean initialize,
                                   ClassLoader loader) throws ClassNotFoundException

name:指定的类、接口的全路径;
initialize:指定类加载的时候是否记载静态代码块;
loader:加载类的类加载器;
返回:方法会返回使用给定的类加载器、指定类或接口名name对应的class实例对象;指定的类加载器loader被用做加载类或者接口,如果参数loader是null,类的加载将会由启动类加载器加载;类只会在参数initialize是true并且之前未被初始化的时候才会初始化。

如果name被声明为原生类型或void类型,将会在未被命名的包中查找名为name的类,然而,这个方法不能被用做任何包含原生类型或void类型的class对象。

如果name表示一个数组类,数组类将会被加载,但是不会被初始化。

如下的方法是等价的:

Class.forName("Foo")
Class.forName("Foo", true, this.getClass().getClassLoader())

注意:这个方法将会在加载(loading)、关联(linking)、初始化(initializing)抛出异常;

  • linkageError:如果关联失败;
  • ExceptionInInitializerError:如果此方法引发的初始化失败;
  • ClassNotFoundException:如果指定的类加载器不能加载指定的类;

接下来我们验证一下initialize参数是否初始化静态代码块,首先声明一个包含静态代码块的类:

package com.test.Application;

public class StaticTest {
    static {
        System.out.println("loading...");
    }
}

加载测试类的客户端类:

    public static void main(String[] args) throws Exception {
        Class clazz = Class.forName("com.test.Application.StaticTest", false, Thread.currentThread().getContextClassLoader());
        System.out.println(clazz.getName());
    }

如果参数initialize是true,将会输出loading…,证明静态代码块被加载了;如果为false,则未被加载,但是在调用newInstance方法后会加载静态代码块;

3.newInstance方法
  • 方法不需要任何参数
  • 返回Class对象代表的类的实例对象,返回值是Object类型,需要进行强制转换为需要的类型;
  • 将会抛出IllegalAccessException、InstantiationException、ExceptionInInitializerError、SecurityException异常;
    public static void main(String[] args) throws Exception {
        Class clazz = Class.forName("com.test.Application.StaticTest", false, Thread.currentThread().getContextClassLoader());
        StaticTest obj = (StaticTest)clazz.newInstance();
        System.out.println();
    }
4.asSubclass判断类是否是指定类的一个子类

判断一个类是否是另外一个类的子类,如果是就返回当前类的Class对象,否则就会抛出ClassCastException异常,

package com.test.Application;

public class Test {

    public static void main(String[] args)  throws ClassCastException{
        Class<?> p = Student.class.asSubclass(People.class);
        System.out.println(p);
    }
}
5.Class类中有很多的方法,下面就介绍一些常用的方法
            //获取类对应方法的Method对象,包括继承类的方法
            Method method = Student.class.getMethod("teachStudent", String.class);
            //获取类对应的所有方法,包括继承的方法
            Method[] method1 = Student.class.getMethods();
            //返回类的所有方法,不包括继承的方法
            Method[] method2 = Student.class.getDeclaredMethods();
            //返回类指定的方法,不包括继承的方法
            Method method3 = Student.class.getDeclaredMethod("work", String.class);

            String[] s = {"1","2","3"};
            //如果当前调用对象是数组,就返回代表数组的class对象,否则返回null
            Class c = s.getClass().getComponentType();
                    //返回类的名称,包含包名
        System.out.println("====>>"+Student.class.getName());
        //如果class对象对应的是原始数据类型将会返回类型名称
        System.out.println("====>>"+int.class.getName());
        //如果是void修饰符,将会返回void
        System.out.println("====>>"+void.class.getName());
        //返回源代码中的简单名称(类名),如果是匿名内部类则返回空,
        System.out.println("====>>"+Student.class.getSimpleName());
        //返回类的规范名称
        System.out.println("====>>"+Student.class.getCanonicalName());
        //返回类的修饰符编码
        System.out.println("====>>"+Student.class.getModifiers());
        //如果调用方法的类或者接口是参数对象的父类或父接口或者是它自己就返回true,否则返回false;
        System.out.println("====>>"+People.class.isAssignableFrom(Student.class));
        //如果是原始数据类型就返回true
        System.out.println("====>>"+int.class.equals(int.class));
        //参数是一个对象,调用者是一个class实例对象,如果对象是调用者的一个对象就返回true
        System.out.println("====>>"+Student.class.isInstance(new Student()));
        //将一个类的对象转换成,调用class实例对应的对象
        System.out.println("====>>"+Student.class.cast(new Student()));
        System.out.println("====>>"+Student.class.getPackage().getName());
        //判断当前类是否是注解类型
        System.out.println("====>>"+Student.class.isAnnotation());
        //判断指定的注解是否存在于此元素上
//      System.out.println("====>>"+Student.class.isAnnotationPresent(Student.class));
        //判断是否是一个匿名类
        System.out.println("====>>"+Student.class.isAnonymousClass());
        //判断是否是一个数组类
        System.out.println("====>>"+Student.class.isArray());
        //判断是否是枚举类
        System.out.println("====>>"+Student.class.isEnum());
        //判断是否是一个接口类型
        System.out.println("====>>"+Student.class.isInterface());
        //判断是否是一个本地类
        System.out.println("====>>"+Student.class.isLocalClass());
        //判断是否是一个成员类
        System.out.println("====>>"+Student.class.isMemberClass());
        //判断是否是原始类型
        System.out.println("====>>"+Integer.class.isPrimitive());
        System.out.println("====>>"+int.class.isPrimitive());
        //判断是否是合成类
        System.out.println("====>>"+Student.class.isSynthetic());

猜你喜欢

转载自blog.csdn.net/yaomingyang/article/details/81143300