zoukankan      html  css  js  c++  java
  • java中Class对象详解和类名.class, class.forName(), getClass()区别

    一直在想.class和.getClass()的区别,思索良久,有点思绪,然后有网上搜了搜,找到了如下的一篇文章,与大家分享。

     

    原来为就是涉及到Java的反射~~~~~

    Java反射学习

    所谓反射,可以理解为在运行时期获取对象类型信息的操作。传统的编程方法要求程序员在编译阶段决定使用的类型,但是在反射的帮助下,编程人员可以动态获取这些信息,从而编写更加具有可移植性的代码。严格地说,反射并非编程语言的特性,因为在任何一种语言都可以实现反射机制,但是如果编程语言本身支持反射,那么反射的实现就会方便很多。

    1,获得类型类

    我们知道在Java中一切都是对象,我们一般所使用的对象都直接或间接继承自Object类。Object类中包含一个方法名叫getClass,利用这个方法就可以获得一个实例的类型类。类型类指的是代表一个类型的类,因为一切皆是对象,类型也不例外,在Java使用类型类来表示一个类型。所有的类型类都是Class类的实例。例如,有如下一段代码
    1. A a = new A();  
    2.   
    3. if(a.getClass()==A.class) {  
    4.   
    5.       System.out.println("equal");  
    6.   
    7. else {  
    8.   
    9.       System.out.println("unequal");  
    10.   
    11. }  
    12. 输出equal;  

    可以看到,对象a是A的一个实例,A是某一个类,在if语句中使用a.getClass()返回的结果正是类A的类型类,在Java中表示一个特定类型的类型类可以用“类型.class”的方式获得,因为a.getClass()获得是A的类型类,也就是A.class,因此上面的代码执行的结果就是打印出“equal”。特别注意的是,类型类是一一对应的,父类的类型类和子类的类型类是不同的,因此,假设A是B的子类,那么如下的代码将得到“unequal”的输出: 

    1. A a = new A();  
    2.   
    3. if(a.getClass()==B.class) {  
    4.   
    5.         System.out.println("equal");  
    6.   
    7. }  else {  
    8.           
    9.           System.out.println("unequal");  
    10. }  
    11. 输出unequal; 

    因此,如果你知道一个实例,那么你可以通过实例的“getClass()”方法获得该对象的类型类,如果你知道一个类型,那么你可以使用“.class”的方法获得该类型的类型类。

    2,获得类型的信息

    在获得类型类之后,你就可以调用其中的一些方法获得类型的信息了,主要的方法有:

    getName():String:获得该类型的全称名称。

    getSuperClass():Class:获得该类型的直接父类,如果该类型没有直接父类,那么返回null。

    getInterfaces():Class[]:获得该类型实现的所有接口。

    isArray():boolean:判断该类型是否是数组。

    isEnum():boolean:判断该类型是否是枚举类型。

    isInterface():boolean:判断该类型是否是接口。

    isPrimitive():boolean:判断该类型是否是基本类型,即是否是int,boolean,double等等。

    isAssignableFrom(Classcls):boolean:判断这个类型是否是类型cls的父(祖先)类或父(祖先)接口。

    getComponentType():Class:如果该类型是一个数组,那么返回该数组的组件类型。

    此外还可以进行类型转换这类的操作,主要方法有:

    asSubclass(Class clazz):Class:将这个类型

    -----------------------------------------------------------------------------------

    在学习反射时想到了这个问题,.getClass()和.class有没有什么区别?
           当然,最明显的区别就是.getClass()是一个对象实例的方法,只有对象实例才有这个方法,具体的类是没有的。类的Class类实例是通过.class获得的,显然,类没有.getClass()方法。
           从网上还找到一些其他资料:
           1、出现的时期不同:Class.forName()在运行时加载;Class.class和getClass()是在编译时加载.

    这里有些个疑问?Class.forName("XXX")这方法是动态加载class,先把类文件加载进来,再使用.newInstance()时创建了一个对象。


    new ClassName(),就是所谓的静态加载,
    Class.forName("ClassName"),就是所谓的动态加载。
    区别在于“静态加载”的类在编译的时候就要提供,而动态加载的类在源程序编译时可以缺席,在运行时按需提供。

    Class.forName(xxx.xx.xx) 返回的是一个类, .newInstance() 后才创建一个对象 Class.forName(xxx.xx.xx);的作用是要求JVM查找并加载指定的类,也就是说JVM会执行该类的静态代码段
          2、 举个例子,Iterator it = s.iterator();得到的it的真正类型是KeyIterator,是Iterator的子类,按常理来说应该可以执行next()方法,但是值 得注意的是,KeyIterator是hashmap的内部类,JAVA给的提示是cannot access a member of class java.util.HashMap$KeyIterator withmodifiers "public"
           从上面的那些例子上也能看出,除内部类外的其他类的应用上.class功能完全等于.getClass()!只是一个是用类直接获得的,一个是用实例获得的。

    -------------------------------------------------------------------------------------------------------------------------------------------

    Class对象的生成方式如下:

    1.类名.class           说明: JVM将使用类装载器, 将类装入内存(前提是:类还没有装入内存),不做类的初始化工作.返回Class的对象

    2.Class.forName("类名字符串")  (注:类名字符串是包名+类名)  说明:装入类,并做类的静态初始化,返回Class的对象

    3.实例对象.getClass()  说明:对类进行静态初始化、非静态初始化;返回引用运行时真正所指的对象(因为:子对象的引用可能会赋给父对象的引用变量中)所属的类的Class的对象

    通过下面的程序,来观察一下Class对象的生成的原理。

    1. package ClassTest;  
    2.   
    3. public class TestClass {  
    4.     public static void main(String[] args) {  
    5.   
    6.         try {  
    7.             // 测试.class  
    8.             @SuppressWarnings("rawtypes")  
    9.             Class testTypeClass = TestClassType.class;  
    10.             System.out.println("testTypeClass---" + testTypeClass);  
    11.   
    12.             // 测试Class.forName()  
    13.             @SuppressWarnings("rawtypes")  
    14.             Class testTypeForName = Class.forName("ClassTest.TestClassType");  
    15.             System.out.println("testTypeForName---" + testTypeForName);  
    16.   
    17.             // 测试Object.getClass()  
    18.             TestClassType testTypeGetClass = new TestClassType();  
    19.             System.out.println("testTypeGetClass---"  
    20.                     + testTypeGetClass.getClass());  
    21.   
    22.         } catch (ClassNotFoundException e) {  
    23.             // TODO Auto-generated catch block  
    24.             e.printStackTrace();  
    25.         }  
    26.     }  
    27.   
    28. }  

    1. package ClassTest;  
    2.   
    3. public class  TestClassType {  
    4.   
    5.     // 构造函数  
    6.     public TestClassType() {  
    7.         System.out.println("----构造函数---");  
    8.     }  
    9.   
    10.     // 静态的参数初始化  
    11.     static {  
    12.         System.out.println("---静态的参数初始化---");  
    13.     }  
    14.   
    15.     // 非静态的参数初始化  
    16.     {  
    17.         System.out.println("----非静态的参数初始化---");  
    18.     }  
    19.   
    20. }  


     运行结果如下

    1. testTypeClass---class ClassTest.TestClassType  
    2. ---静态的参数初始化---  
    3. testTypeForName---class ClassTest.TestClassType  
    4. ----非静态的参数初始化---  
    5. ----构造函数---  
    6. testTypeGetClass---class ClassTest.TestClassType  

     然而单独执行  测试Class.forName() 时结果为

    ---静态的参数初始化e---
    testTypeForName---测试Class.forName()/class ClassTest.TestClassType

    单独执行测试Object.getClass() 结果为

    ---静态的参数初始化e---
    ----非静态的参数初始化e---
    ----构造函数e---
    testTypeGetClass---测试Object.getClass()/class ClassTest.TestClassType

    所以根据结果可以发现,三种生成的Class对象一样的。并且程序只打印一次“静态的参数初始化”,但时拆分单独执行时class.forName(),Object.getClass()时

    都执行了“静态的参数初始化”。

    我们知道,静态的方法属性初始化,是在加载类的时候初始化。而非静态方法属性初始化,是new 类实例对象的时候加载。

    因此,这段程序说明,三种方式生成Class对象,其实只有一个Class对象。在生成Class对象的时候,首先判断内存中是否已经加载。

    所以,生成Class对象的过程其实是如此的:

    当我们编写一个新的java类时,JVM就会帮我们编译成class对象,存放在同名的.class文件中。在运行时,当需要生成这个类的对象,JVM就会检查此类是否已经装载内存中。若是没有装载,则把.class文件装入到内存中。若是装载,则根据class文件生成实例对象。

  • 相关阅读:
    mysql日期默认值格式('0000-00-00')错误解决
    休闲一下-精华-IMDB评分8分左右影片400多部!
    开机动画流程
    SystemServer启动服务
    理解Android进程创建流程
    android开机动画启动流程
    Android系统的启动优化
    Android 系统启动(init,zygote)
    Zygote
    init
  • 原文地址:https://www.cnblogs.com/Seachal/p/5371733.html
Copyright © 2011-2022 走看看