Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1611650
  • 博文数量: 695
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 4027
  • 用 户 组: 普通用户
  • 注册时间: 2013-11-20 21:22
文章分类

全部博文(695)

文章存档

2018年(18)

2017年(74)

2016年(170)

2015年(102)

2014年(276)

2013年(55)

分类: Java

2016-04-06 21:49:49

   http://blog.csdn.net/elfylin/article/details/7422610

http://blog.csdn.net/ff313976/article/details/7931491


java惰性初始化 P319

初始化有效地实现了尽可能的惰性。仅使用.class语法来获得对类的引用不会引发初始化。使用Class.forName()方法时立即就进行了初始化


如果一个static final值是编译期常量,那么这个值就不需要对类进行初始化就能获取,但是如果将一个域设置成static和final的,还不足以确保这种行为,对它的访问就会强制进行类的初始化,因为他不是一个编译期常量


如果一个static域不是final的,那么在对他访问时,总是要求她在被读取之前,要先进行链接(为这个域分配存储空间)和初始化(初始化该存储空间)


 一个类的运行,JVM做会以下几件事情

1.加载,这是由类加载器执行的。该步骤将查找字节码(通常在classpath所指定的路径中查找,但这并非必须的),并从这些字节码中创建一个Class对象。


2.链接,在链接阶段将验证类的字节码,为静态域分配存储空间,并且如果必须的话,将解析这个类创建的对其他类的所有引用。


3.初始化,如果该类具有超类,则对其进行初始化,初始化静态域和静态初始化块。


初始化被延迟到对静态方法(构造器隐式地是静态的)或者非常数静态域进行首次引用时才执行。


创建对象成员的初始化过程:

创建实例对象时在堆内存中为类的成员变量分配内存,并将其初始化为各数据类型的默认值(java各类型都有默认值);接着进行显式初始化(类定义时的初始 化值);最后调用构造方法,为成员变量赋值。返回堆内存中对象的引用(相当于首地址)给引用变量,以后就可以通过来引用堆内存中的对象了。


运行时类型识别(RTTI, Run-Time Type Identification)是Java中非常有用的机制,在Java运行时,RTTI维护类的相关信息。RTTI形式有传统的类型转换(String) obj; Class对象;instanceof 三种.

 

RTTI与反射真正的区别只在于:对RTTI来说,编译期是在编译时打开和检查.class文件; 而对反射来说.class文件在编译时是不可获取的,所以在运行是打开和检查.class文件文件.

        JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。

Java反射机制主要提供了以下功能: 在运行时判断任意一个对象所属的类;在运行时构造任意一个类的对象;在运行时判断任意一个类所具有的成员变量和方法;在运行时调用任意一个对象的方法;生成动态代理。p335.

反射机制具体实现可以通过类方法提取器getMethods、字段提取器getFields、构造方法提取器getConstructors实现.

      

    多态(polymorphism)是基于RTTI实现的。RTTI的功能主要是由Class类实现的;反射和RTTI的区别就在于对RTTI来说,编译器是在编译时打开和检查.class文件, 而对反射机制来说, .class文件在编译时是不可获取的,所以是在运行是打开和检查.class文件的.


Class类

       Class类是"类的类"(class of classes)。如果说类是对象的抽象和集合的话,那么Class类就是对类的抽象和集合,每个类都有一个Class的对象。

     每一个Class类的对象代表一个其他的类。比如下面的程序中,Class类的对象c1代表了Human类,c2代表了Woman类。

     Class对象产生时刻:每当编译一个新类时就产生一个Class对象,被保存在同名的.Class文件中.

     Class对象加载的时刻:使用构造方法创建新对象时; 使用类的static变量时(但不属于编译常量的那种编译期常量:final static修饰并且在定义时就赋值); 应用Class.forName()方法   p315 类加载时会首先检查Class对象是否已被加载,如果尚未加载才进行加载工作.


复制代码
public class Test
{ public static void main(String[] args)
    {  Human aPerson = new Human();
        Class c1 = aPerson.getClass();
        System.out.println(c1.getName()); 
 Human anotherPerson = new Woman();
        Class c2 = anotherPerson.getClass();
        System.out.println(c2.getName());  

    }
} class Human
{   public int getHeight()
    { return this.height;
    }  public void growHeight(int h)
    { this.height = this.height + h;
    } private int height; 
} class Woman extends Human
{  public Human giveBirth()
    {
        System.out.println("Give birth"); return (new Human());
    }  } 
复制代码

当我们调用对象的getClass()方法时,就得到对应Class对象的引用。

在c2中,即使我们将Women对象的引用向上转换为Human对象的引用,对象所指向的Class类对象依然是Woman。

Java中每个对象都有相应的Class类对象,因此,我们随时能通过Class对象知道某个对象“真正”所属的类。无论我们对引用进行怎样的类型转换,对象本身所对应的Class对象都是同一个。当我们通过某个引用调用方法时,Java总能找到正确的Class类中所定义的方法,并执行该Class类中的代码。由于Class对象的存在,Java不会因为类型的向上转换而迷失。这就是多态的原理。

getClass: 我是谁?

 

除了getClass()方法外,我们还有其他方式调用Class类的对象。

复制代码
public class Test
{ public static void main(String[] args)
    {
        Class c3 = Class.forName("Human");
        System.out.println(c1.getName());

        Class c4 = Woman.class System.out.println(c2.getName());  
    }
} 
复制代码

上面显示了两种方式:

  • forName()方法接收一个字符串作为参数,该字符串是类的名字。这将返回相应的Class类对象。
  • Woman.class方法是直接调用类的class成员。这将返回相应的Class类对象。

 

Class类的方法

Class对象记录了相应类的信息,比如类的名字,类所在的包等等。我们可以调用相应的方法,比如:

getName()         返回类的名字

getPackage()      返回类所在的包

 

可以利用Class对象的newInstance()方法来创建相应类的对象,比如:

Human newPerson = c1.newInstance();   

newInstance()调用默认的不含参数的构建方法

 

我们可以获得类定义的成员:

getFields()       返回所有的public数据成员

getMethods()      返回所有的public方法

可以进一步使用Reflection分析类。这里不再深入。

 

Class类更多的方法可查询官方文档:

 

Class类的加载

当Java创建某个类的对象,比如Human类对象时,Java会检查内存中是否有相应的Class对象。

如果内存中没有相应的Class对象,那么Java会在.class文件中寻找Human类的定义,并加载Human类的Class对象。

 

在Class对象加载成功后,其他Human对象的创建和相关操作都将参照该Class对象。

阅读(1328) | 评论(0) | 转发(0) |
0

上一篇:java快速学习

下一篇:Linux多线程与同步

给主人留下些什么吧!~~