`
devil587
  • 浏览: 5116 次
  • 性别: Icon_minigender_2
  • 来自: 杭州
最近访客 更多访客>>
社区版块
存档分类
最新评论

理解java.lang.Class类

    博客分类:
  • Java
 
阅读更多
Java Class类理解:

首先,Class是一个java类,跟Java API中定义的诸如Thread、Integer类、我们自己定义的类是一样,也继承了Object(Class是Object的直接子类)。总之,必须明确一点,它其实只是个类,只不过名字比较特殊。更进一步说,Class是一个java中的泛型类型。



对于我们自己定义的类,我们用类来抽象现实中的某些事物,比如我们定义一个名称为Car的类来抽象现实生活中的车,然后可以实例化这个类,用这些实例来表示我的车、你的车、黄的车、红的车等等。

好了,现在回到Class 类上来,这个类它抽象什么了?它的实例又表示什么呢?

在一个运行的程序中,会有许多类和接口存在。我们就用Class这个来来表示对这些类和接口的抽象,而Class类的每个实例则代表运行中的一个类。例如,运行的程序有A、B、C三个类,那么Class类就是对A、B、C三个类的抽象。所谓抽象,就是提取这些类的一些共同特征,比如说这些类都有类名,都有对应的hashcode,可以判断类型属于class、interface、enum还是annotation。这些可以封装成Class类的域,另外可以定义一些方法,比如获取某个方法、获取类型名等等。这样就封装了一个表示类型(type)的类。


需要注意的是,这个特殊的Class类没有公开的构造函数,那怎么获取Class类的实例呢?有几个途径。

1.      当Java虚拟机载入一个类的时候,它就会自动创建一个Class类的实例来表示这个类。例如,虚拟机载入Car这个来的时候,它就会创建一个Class类的实例。然后可以通过以下方法获得这个Class对象:

java.lang.Class classObj = ClassName.class;

2. 可以通过调用类加载器(ClassLoader)的defineClass()方法来得到一个实例。这个方法接受一个byte数组,载入这个byte数组否成的class类,同时实例化一个Class对象。

3. ClassName.class( )   ClassName.getClass( )

现在来分析一下Class类的源码(java.lang.Class):

public final

    class Class<T>implementsjava.io.Serializable,

                            java.lang.reflect.GenericDeclaration,

                             java.lang.reflect.Type,

                             java.lang.reflect.AnnotatedElement {…



ClassClass<T>,前一个Class表示这是一个类的声明,第二个Class是类的名称,<T>表示这是一个泛型类,带有参数T.同时,Class类实现了许多接口。



紧接着定义了几个静态变量:

private static final int ANNOTATION= 0x00002000;

private static final int ENUM      = 0x00004000;

private static final int SYNTHETIC = 0x00001000;



接着定义一个本地方法registerNatives(),并在静态块中调用:

private static native void registerNatives();

    static {

        registerNatives();

}



私有的构造函数:

private Class() {}

访问修饰符是private,程序员是无法直接调用这个构造函数,只能通过JVM来调用它,构造一个Class实例。

  public String toString() {

        return (isInterface() ?"interface " : (isPrimitive() ? "" : "class"))

            + getName();

}

这是Class对象实例的字符串表示方法,应该不陌生。那么,它返回什么东西呢?

>如果这个Class对象实例所表示的是一个Java类,则返回class full_classname.

例如java.lang.Math.java这个类,它所对应的Class实例的toString方法返回的就是class java.lang.Math

>如果是接口,将class改成interface。还有一种特殊情况,如果Class实例表示的是void类型,则发挥void。如果是基本类型,一样的返回基本类型的名称。



静态方法forName:

public static Class<?> forName(String className)

                throws ClassNotFoundException{

        returnforName0(className,true, ClassLoader.getCallerClassLoader());

}

根据给定的类名参数className,查找与className相对应的Class实例,然后加载、连接该实例对象,之后返回这个Class实例。其中例如以下代码段将输出:

class java.lang.Thread

public class ClassTest {



    /**

     * @param args

     */

    public static void main(String[] args) {

     

       try {

           System.out.println( Class.forName("java.lang.Thread") );

       } catch (ClassNotFoundException e) {

           e.printStackTrace();

           System.out.println("No ClassNamed java.lang.Thread");

       }



    }



}



forName方法重载:

    public static Class<?> forName(String name, boolean initialize,

                                   ClassLoaderloader)

        throws ClassNotFoundException

    {

        if (loader ==null) {

            SecurityManager sm = System.getSecurityManager();

            if (sm !=null) {

                ClassLoader ccl = ClassLoader.getCallerClassLoader();

                if (ccl !=null) {

                    sm.checkPermission(

                        SecurityConstants.GET_CLASSLOADER_PERMISSION);

                }

            }

        }

        returnforName0(name, initialize,loader);

    }

注意到这个forName重载方法中多了两个方法参数,其中initialize这个boolean类型指定是否要初始化对应的Class实例,loader指定加载Class实例的加载器。留意这个方法可能抛出的异常还是比较多的,比如连接失败、找不到对应的类等等。



forName0本地方法:

private static native Class<?> forName0(String name,boolean initialize,

                                            ClassLoaderloader)

        throws ClassNotFoundException;

这是一个本地方法,在前面的静态方法forName的两个版本中都调用了这个本地方法。



newInstance()方法:

public T newInstance()          // T是个泛型参数,是Class实例所表示的Java类

        throws InstantiationException,IllegalAccessException

    {

        if (System.getSecurityManager()!=null) {

            checkMemberAccess(Member.PUBLIC, ClassLoader.getCallerClassLoader());

        }

        return newInstance0();     //这是一个本地方法,也在Class类中定义

}

注意这是一个实例方法,必须由Class类的实例对象调用。例如,有一个代表java.lang.Thread类的Class实例对象objec1,也就是说,泛型参数T此时就是Thread,object1这个实例代表Thread这个类。好了,现在调用object1的newInstance方法,即object1.newInstance(),此时这个调用将返回一个Thread类的对象。简单验证:

public class ForName {



    /**

     * @paramargs

     * @throwsIllegalAccessException

     * @throwsInstantiationException

     */

    public static void main(String[] args) throws InstantiationException, IllegalAccessException {

       Class<?> c = null ;

       try {

           c = Class.forName("java.lang.Thread");

       } catch (ClassNotFoundException e) {

           e.printStackTrace();

       }

       Thread thread = (Thread) c.newInstance(); //类型转化一下

       System.out.println(thread.getId());



    }



}

在我机子中,上述代码输出 8 。即c.newInstance产生一个ID为8的新线程。



getClassLoader:

public ClassLoader getClassLoader() {

        ClassLoader cl = getClassLoader0();

        if (cl ==null)

            return null;   // Bootstrap

        SecurityManager sm = System.getSecurityManager();

        if (sm !=null) {

            ClassLoader ccl = ClassLoader.getCallerClassLoader();

            if (ccl !=null && ccl != cl&& !cl.isAncestor(ccl)) {

               sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION);

            }

        }

        return cl;

    }



    //Package-private to allow ClassLoader access

    native ClassLoadergetClassLoader0();   // 本地方法

这个方法返回该Class对象代表的类的类加载器。如果类的加载器是Bootstrap,则返回null。下面的代码输出:The ClassLoader of Thread Class is Bootstrap



Class<?> classObj= Thread.class;

       ClassLoader loader = classObj.getClassLoader();

       if (loader ==null) {

           System.out.println("TheClassLoader of Thread Class is Bootstrap");

       } else {

           System.out.println(loader);

       }



获取父类方法:getSuperclass()

public native Class<? super T> getSuperclass();

这是一个本地方法,这里的逻辑有点饶,方法返回的是这个Class对象所代表的Java类的父类对应的的Class 对象。

例如: Thread.class.getSuperclass()将返回一个代表Thread类的Class对象,Thread.class.getSuperclass().toString()则输出这个Class对象的字符串表示:classjava.lang.Object。其实这里的关系无非就是说Thread的超类是Object。只是饶了Class对象这个弯子,至于这么绕有什么好处,还没有深刻体会。

分享到:
评论

相关推荐

    java.lang.IllegalArgumentException: Class not found: org.apache.Struts2.validato

    在Java编程中,`java.lang.IllegalArgumentException` 是一个运行时异常,通常会在方法接收到非法或不合适的参数时抛出。这个错误信息 "Class not found: org.apache.struts2.validator" 指示程序在尝试加载名为 `...

    java.lang.NoSuchMethodError异常处理要点.doc

    在Java编程中,`java.lang.NoSuchMethodError`异常是一个运行时异常,通常发生在程序试图执行一个不存在的方法时。这个异常的出现通常意味着编译时和运行时的类版本不匹配,或者是在编译期间存在而运行时不存在的...

    Java.lang.reflect 包下常用的类及方法简介

    每个类在内存中都有一个唯一的`Class`实例,可以通过`Class.forName()`方法获取,或者通过`Object.getClass()`方法从对象中获取。 - `getConstructors()`:返回类的所有公共构造函数。 - `getDeclaredConstructors...

    java.lang包介绍

    `java.lang`包中最基本的类是`Object`,它是所有类层次结构的根,而`Class`类的实例则代表运行时的类。 `java.lang`包包括以下关键类: 1. **Boolean**: 表示布尔值`true`和`false`。 2. **Long, Short, Byte, ...

    java.lang.Class类

    Java.lang.Class类 Java.lang.Class类是Java语言中一个非常重要的类,它封装了对象和接口的运行时状态。...通过掌握Class类,可以更好地理解Java语言的机制和原理,并且可以更好地应用Java语言来开发各种应用程序。

    出现Exception in threadmain java.lang.NoClassDefFoundError的各种可能情况.doc

    解决这类问题的关键在于理解Java的类加载机制,确保类路径、文件名、类名以及包结构等元素的正确性。在复杂的项目中,使用IDE(如Eclipse、IntelliJ IDEA或VisualAge for Java)可以避免许多常见的配置错误,使开发...

    java.lang包

    Java语言的核心库之一就是`java...通过理解并熟练使用`java.lang`包中的类和接口,开发者能够更好地进行异常处理、数据类型转换、字符串操作、数学计算以及对类和对象的基本操作,从而编写出更加健壮和高效的Java程序。

    Struts的java.lang.ClassNotFoundException: org.apache.commons.dbcp.BasicDataSource异常的解决方法

    总的来说,理解并解决"java.lang.ClassNotFoundException: org.apache.commons.dbcp.BasicDataSource"这一异常,不仅需要对Struts框架有一定了解,还需要掌握Java类加载机制以及数据库连接池的基本原理。通过正确...

    java.lang.ClassNotFoundException: org.apache.commons.dbcp.BasicDataSource

    在Java编程中,`java.lang.ClassNotFoundException`是一个常见的运行时异常,它表示JVM尝试加载一个类时,找不到对应的.class文件。在这个特定的错误中,我们看到的是`org.apache.commons.dbcp.BasicDataSource`,这...

    java.lang.NoClassDefFoundError: org/jboss/logging/

    Java编程中的`java.lang.NoClassDefFoundError: org/jboss/logging/`是一个常见的运行时错误,通常发生在尝试执行一个类时,JVM无法找到在编译时已经存在的类定义。这个错误并不意味着类在编译期间不存在,而是表明...

    在Java中异常分析

    - 使用`Class.forName(String className)`时,确保类确实存在于类路径中。 ##### 3. `java.lang.ArithmeticException` - **异常路径**:`java.lang.Object -&gt; java.lang.Throwable -&gt; java.lang.Exception -&gt; ...

    java.lang.class源码-datanucleus-cache:修复java.lang.IncompatibleClassChange

    当我们使用`Class.forName()`加载类时,Java虚拟机(JVM)会解析类的字节码,生成对应的`Class`对象。这个过程涉及到类加载器(ClassLoader),它是JVM的一部分,负责查找和加载类。 在`java.lang.Class`中,`new...

    java.lang研究

    《深入解析java.lang》 Java语言的核心库之一就是`java.lang`包,它包含了Java程序设计中最基础的类和接口,...通过深入研究`java.lang`,我们可以更好地理解Java的内在机制,并能更熟练地运用这些工具来解决问题。

    java.lang.NoSuchMethodError异常解决

    可以使用`java -verbose:class`命令来查看类加载过程。 5. **查看编译和运行配置**:检查IDE或构建脚本的配置,确保它们指向正确的源代码和目标目录。 6. **混淆或优化代码的反向操作**:如果你使用了混淆或代码...

    Android 出现:java.lang.NoClassDefFoundError...错误解决办法

    在Android开发过程中,有时会遇到一个常见的运行时异常——`java.lang.NoClassDefFoundError`。这个错误通常意味着在编译期间能够找到类的定义,但在运行时却无法加载该类。本文将深入探讨这个问题,特别是在Android...

    java.lang.IllegalArgumentException: Path search.page does not start with a \"/\" c

    3. 使用Java的 `File` 类或 `Class.getResource()` 方法来验证路径是否有效,这些方法在路径格式不正确时会抛出异常。 4. 在IDE或日志中打印出实际使用的路径,以帮助定位问题所在。 5. 如果问题涉及框架配置(如...

    java_lang包详解.pdf

    总之,java.lang包是Java编程的基础,它的类和接口构成了Java语言的核心,理解并熟练运用这些元素是成为一名合格的Java开发者的前提。在编写Java程序时,无论何时何地,你都有可能需要用到java.lang包中的类和接口,...

    org.apache.commons.lang包

    Apache Commons Lang是一个非常重要的Java库,它为Java标准类库提供了许多实用的工具类和扩展。这个资源包包含了丰富的功能,极大地增强了Java开发者的生产力。标题中的"org.apache.commons.lang包"指的是该库的主要...

    class.getMethods()

    在Java编程语言中,`Class.getMethods()`是一个非常重要的方法,它属于`java.lang.Class`类。这个方法用于获取指定类或接口的所有公共方法,包括继承自超类和实现的接口的方法。`getMethods()`返回一个`Method`对象...

    java.lang.NoClassDefFoundError:

    ### Java.lang.NoClassDefFoundError: org/apache/commons/logging/LogFactory #### 错误概述 ...对于初学者来说,这类问题可能显得较为复杂,但随着对Java生态系统的深入理解,处理起来会越来越得心应手。

Global site tag (gtag.js) - Google Analytics