一.学java基础中有时候会对class对象不太理解,做java的作业时遇到要对对象进行排序的问题,发现要对class对象有真正的理解。
二.于是我就去看《java 编程思想》这本书,它对class对象有较详细的说明,但是这本书对讲解的顺序有点混乱,不便于记忆,以下是我对这本书讲解class对象的重新整理,下面的2个例子也是《java 编程思想》中摘录的。
三.下面的讲解可以对初学者来说有许多概念,但还是要记住概念,概念记住了会对进一步学习提供很大的帮助。
class对象
----------
目的:class对象究竟是什么?
首先要了解
------------------------------
类的加载 |
------------------------------
1)类加载的概念:
所有的类都是在对其第一次使用时,动态加载到JVM中的。java的程序在它开始运行之前并非是被完全加载的,其各部分是在必需时才加载的,这称为动态加载,而传统语言如C++是静态加载的。
2)什么情况会加载一个类?
当程序创建第一个对类的静态成员的引用时,就会加载这个类。这个证明构造器也是类的静态方法,即使构造器并没有使用static关键字,我们称构造器是隐式静态的。因此,使用new操作符创建类的新对象也会被当做对类的静态成员的引用。
2.1)怎么才算是对静态成员的引用?
有2种情况是对静态成员的引用
一.对静态方法的引用(构造器是隐式静态的)
二.对非常熟静态域进行的域进的引用
2.2)什么是非常数静态域
对于static成员变量加了final关键的字的成员变量称为常数静态域,编译器会把常数静态域当做一个编译常量来对待。
如:static final i=47; i会被当做编译常量来对待,所谓编译期常量,就是他和47这个数没什么区别,我没必要去加载类去确定i的值。
除了常量静态域,其他的static成员变量就就是非常数静态域。
3)类加载的过程
一.加载。这是由类的加载器执行的。类加载器查找类的.class文件来创建一个Class对象。注意,这个时候就创建了Class对象。
二.链接。在链接阶段将验证类中的字节码,为静态域分配存储空间,就是为成员变量和成员方法分配存储空间。而且,如果必须的话,将解析这个类创建的对其他类的所有引用。
三.初始化。执行初始化器和静态初始化块,执行后就是对类的成员变量赋值和执行静态块中的语句,静态块就是类中的static{语句...},要注意的一点是静态成员函数没有什么所谓的初始化,只需要为静态成员函数分配存储空间就可以了。如果该类具有超类,则先对超类初始化化。
4)类加载完成后,会产生什么效果?
类加载完成后,我们就可以创建类的普通对象了。
-----------------------------
class对象 |
-----------------------------
1.Class对象的概念:
对类的加载过程了解后,我们发现Class对象是在类的加载过程中产生的,而完成类的加载过程才可以创建类的普通对象.其实一旦某个类的Class对象被载入内存,它就被用来创建这个类的所有对象。
注意:Class对象的创建和Class对象的初始化是分开来的。也就是说,创建了一个Class对象,不一定是对Class对象初始化了。
2.什么情况下会创建class对象
1.使用类字面常量(类名.class)
---------------------------------------------------------------
类字面常量(类名.class)和Class.forName()方法 |
---------------------------------------------------------------
类字面常量的格式是
类名.class
这个语法会创建一个类的Class对象。注意,这仅仅是创建一个类的Class对象,并没有完成类的加载的全部的3个过程。如
Dog.class 表示创建一个Dog的class对象。
Class.forName()的格式是
Class.forName("类的全限定名")
如果上面的Dog类在com.guo包下,则
Class.forName("com.guo.Dog");
Class.forName()方法会执行类的加载的全部过程,即类加载过程的3个步骤都会执行。类加载重要的第3步会对Class对象初始化化。即创建Dog类的Class对象,对Dog类的静态域分配空间,初始化Dog类的Class对象。
------------------------------------------------
下面2个例子来说明上面的概念 |
------------------------------------------------
//: typeinfo/SweetShop.java
// Examination of the way the class loader works.
import static net.mindview.util.Print.*;
class Candy {
static { print("Loading Candy"); }
}
class Gum {
static { print("Loading Gum"); }
}
class Cookie {
static { print("Loading Cookie"); }
}
public class SweetShop {
public static void main(String[] args) {
print("inside main");
new Candy();
print("After creating Candy");
try {
Class.forName("Gum");
} catch(ClassNotFoundException e) {
print("Couldn't find Gum");
}
print("After Class.forName(\"Gum\")");
new Cookie();
print("After creating Cookie");
}
}
输出信息为:
inside main
Loading Candy
After creating Candy
Loading Gum
After Class.forName("Gum")
Loading Cookie
After creating Cookie
我们发现,你要创建一个类的普通对象必须要在创建普通对象之前创建这个类的Class对象。说明Class对象被用来创建这个类的所有对象
-------------------------------------------------------------
//: typeinfo/ClassInitialization.java
import java.util.*;
class Initable {
static final int staticFinal = 47;
static final int staticFinal2 =
ClassInitialization.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 ClassInitialization {
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");
// Does not trigger initialization:
System.out.println(Initable.staticFinal);
// Does trigger initialization:
System.out.println(Initable.staticFinal2);
// Does trigger initialization:
System.out.println(Initable2.staticNonFinal);
Class initable3 = Class.forName("Initable3");
System.out.println("After creating Initable3 ref");
System.out.println(Initable3.staticNonFinal);
}
}
输出信息为:
After creating Initable ref
47
Initializing Initable
258
Initializing Initable2
147
Initializing Initable3
After creating Initable3 ref
74
我们发现static final值是编译期常量,如Initable.staticFinal不会引起Class对象的初始化,同时它也不能产生Class对象。
但是static final并不足以保证成员变量是是编译期常量,例如Initable.staticFinal2的访问会触发类的初始化,因为它不是一个编译期常量。
其他的static域都会触发类加载的全部过程,即会对Class对象进行初始化。
--------------------------------------------------------------------------------
初始化Class对象究竟是怎么样的?函数怎么进行初始化? |
---------------------------------------------------------------------------------
答:请看上面的类加载的过程,我们发现函数没有什么初始化,只需要为函数分配空间就可以了。