Thinking in java: 14类型信息

1.  java识别对象和类的信息的两种方式:

   (1)RTTI,她假定我们在编译时已经知道了所有类型;名字含义:在运行时,识别一个对象的类型。

   (2)反射机制,他允许我们运行时发现和使用类的信息。

2. 类是程序的一部分,每个类都有一个Class对象。换言之,每当编写并且编译了一个新类,就会产生一个Class对象(更恰当的说是被保存在一个同名的.class文件中)。为了生成这个类的对象,java虚拟机将运行“类加载器”的子系统。

类加载器首先检查这个类的Class对象是否已经加载。如果尚未加载,类加载器就会根据类名查找.class文件。在这个类的字节码被加载时,他们会接收验证,以确保其没有被破坏,且不包含不良代码。一旦某个类的Class对象被载入内存,他就被用来创建这个类的所有对象。

所有的类都是在对其第一次使用时,动态加载到JVM中的。当程序创建第一个对类的静态成员的引用时,就会加载这个类。这证明构造器也是类的静态方法,即使没有static关键字。因此,java程序在它开始运行之前并非完全加载,其各个部分是在必需时才加载的。

class Candy{
    static {
        System.out.println("Loading Candy");}
}
class Gum{
    static {
        System.out.println("Loading Gum");
    }
}
class Cookie{
    static {
        System.out.println("Loading Cookie");
    }
}

public class Niuke {
    public static void main(String[] args) {
        System.out.println("inside main");
        new Candy();
        System.out.println("After creating Candy");
        try {
            Class.forName("Gum");
        } catch (ClassNotFoundException e) {
            System.out.println("Couldn't find Gum");
        }
        System.out.println("After Class.forName(\"Gum\")");
        new Cookie();
        System.out.println("After creating Cookie");
    }
}
/*
inside main
Loading Candy
After creating Candy
Loading Gum
After Class.forName("Gum")
Loading Cookie
After creating Cookie
 */

3.只要你想在运行时使用类型信息,就必须首先获得对恰当的Class对象的引用。有两种方式获得对对象的引用:

     方式一:  使用Class  a = Class.forName("全限定名(包含包名的)"),返回一个Class对象的引用

     方式二:使用类字面常量。例如:类名.class    (FancyToy.class),更简单更安全

  两者区别:.class对类的引用不会引发类的初始化,但是Class.forName()会立即对类进行初始化.需要注意的是:这里是类的初始化(static{}函数),不是类的构造函数。static{}是伴随类加载执行的,且只会执行一次。

另外:如果类的域里面含有编译期常量(static final值),那么这个值不需要对类进行初始化就可以被读取。如果一个static域不是final的,那么在对它访问时,总是要求先进行链接(为域分配存储空间)和初始化(初始化该存储空间)

import java.util.Random;

class Initable{
    static final int staticFinal = 47;                        
    static final int staticFinal2 = Niuke.rand.nextInt(1000);
    static {
        System.out.println("Initializing Initable");
    }
}
class Initable2{
    static int staticNonFinal = 147;
    static {
        System.out.println("Initializing Initable2");
    }
}

class Initable3 {
    static int staticNonFinal = 74;
    static {
        System.out.println("Initializing Initable3");
    }
}

public class Niuke {
    public static Random rand = new Random(47);
    public static void main(String[] args) throws Exception {
        Class initable = Initable.class;                       //不会对类初始化
        System.out.println("After creating Initable ref");    
        System.out.println(Initable.staticFinal);              //编译期常量,调用它不用首先对Initable进行初始化
        System.out.println(Initable.staticFinal2);             //非编译期常量,调用时需要首先强制对Initable初始化
        System.out.println(Initable2.staticNonFinal);          //非final的,需首先进行链接和初始化

        Class initable3 = Class.forName("Initable3");
        System.out.println("After creating Initable3 ref");
        System.out.println(Initable3.staticNonFinal);
    }
}

     为了使用类而做的准备工作包含:

       1. 加载。这是由类加载器执行的。该步骤将查找字节码,并从这些字节码中创建一个Class对象。

       2.链接。验证类中的字节码,并未静态域分配存储空间

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

4. instanceof与==来判断类型,instanceof保持了类型的概念,它指的是“你是这个类吗,或者你是这个类的派生类吗?”而如果用==比较实际的Class对象,就没有考虑继承,换句话说,它是这个类型或者不是。

5.反射:运行时的类信息




  



猜你喜欢

转载自blog.csdn.net/oyeyuanxinzhizhu1/article/details/79749776