Java获取一个类的Class对象的四种方式

博客介绍了Java中获取Class对象的四种方式。包括ClassLoader对象的loadClass()方法,此方法不会对类进行连接和初始化;类名.class也不会初始化类;Class.forName()可进行初始化,常用于加载数据库驱动;object.getClass()通过对象获取对应类的Class对象,此时类已在虚拟机中。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.通过ClassLoader对象的loadClass()方法

比如以下方式:

  ClassLoader.getSystemClassLoader().loadClass("com.my.test.Hello")

去看一下loadClass的源码:

public Class<?> loadClass(String name) throws ClassNotFoundException {
        return loadClass(name, false);
    }

最终调用:

//可以看到参数resolve的解释,如果为true才会对这个类进行resolve
 /* @param  resolve
     *         If <tt>true</tt> then resolve the class
     * */
 protected Class<?> loadClass(String name, boolean resolve)
        throws ClassNotFoundException
    {
        synchronized (getClassLoadingLock(name)) {
            // First, check if the class has already been loaded
            Class<?> c = findLoadedClass(name);
            if (c == null) {
                long t0 = System.nanoTime();
                try {
                    if (parent != null) {
                        c = parent.loadClass(name, false);
                    } else {
                        c = findBootstrapClassOrNull(name);
                    }
                } catch (ClassNotFoundException e) {
                    // ClassNotFoundException thrown if class not found
                    // from the non-null parent class loader
                }

                if (c == null) {
                    // If still not found, then invoke findClass in order
                    // to find the class.
                    long t1 = System.nanoTime();
                    c = findClass(name);

                    // this is the defining class loader; record the stats
                    sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
                    sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                    sun.misc.PerfCounter.getFindClasses().increment();
                }
            }
            if (resolve) {
                resolveClass(c);
            }
            return c;
        }
    }

resolve其实是连接过程(验证verification,准备preparation,解析resolution),具体代码如下:

 /**
     * Links the specified class.  This (misleadingly named) method may be
     * used by a class loader to link a class.  If the class <tt>c</tt> has
     * already been linked, then this method simply returns. Otherwise, the
     * class is linked as described in the "Execution" chapter of
     * <cite>The Java&trade; Language Specification</cite>.
     *
     * @param  c
     *         The class to link
     *
     * @throws  NullPointerException
     *          If <tt>c</tt> is <tt>null</tt>.
     *
     * @see  #defineClass(String, byte[], int, int)
     */
    protected final void resolveClass(Class<?> c) {
        resolveClass0(c);
    }

    private native void resolveClass0(Class<?> c);

可以看到,ClassLoader对象的loadClass()方法传入的resolve值为false,因此它不会对类进行连接这一过程,根据类的生命周期我们知道,如果一个类没有进行验证和准备的话,是无法进行初始化过程的,也就是说该方法的调用不会导致初始化<cinit>的执行。

2. 类名.class

Class a=Test.class

该种方式同样不会对类进行初始化。

3. Class.forName()

Class test = Class.forName("com.my.Test");

forName函数的源码如下:

 public static Class<?> forName(String className)
                throws ClassNotFoundException {
        Class<?> caller = Reflection.getCallerClass();
        return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
    }

forName0是一个native方法。调用forName(string)方法等同于调用Class.forName(className, true, currentLoader)方法。源码如下:

 public static Class<?> forName(String name, boolean initialize,
                                   ClassLoader loader)
        throws ClassNotFoundException
    {
        Class<?> caller = null;
        SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            // Reflective call to get caller class is only needed if a security manager
            // is present.  Avoid the overhead of making this call otherwise.
            caller = Reflection.getCallerClass();
            if (sun.misc.VM.isSystemDomainLoader(loader)) {
                ClassLoader ccl = ClassLoader.getClassLoader(caller);
                if (!sun.misc.VM.isSystemDomainLoader(ccl)) {
                    sm.checkPermission(
                        SecurityConstants.GET_CLASSLOADER_PERMISSION);
                }
            }
        }
        return forName0(name, initialize, loader, caller);
    }

initialize为true表示会进行初始化initialization步骤,即静态初始化(会初始化类变量,静态代码块)。

这也就是为什么加载MySQL等一些数据库驱动程序的时候要使用这个方法的原因。比如MySQL的数据库驱动中有如下代码:

static {
    try {
        java.sql.DriverManager.registerDriver(new Driver());
    } catch (SQLException E) {
        throw new RuntimeException("Can't register driver!");
    }
}

需要使用forName方式加载使得静态代码块得以初始化。

4.object.getClass()

这个方法没什么好说的了,你通过一个对象调用其getClass()方法能获得其对应类的Class对象,既然对象已经存在了,那么说明这个类已经被装载到了虚拟机中。

public final native Class<?> getClass();
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值