- 论坛徽章:
- 0
|
static 的涵义
头脑里有了this关键字的概念,你就能更加充分地理解定义一个方法为static的意思。
static的意思是你不能将this用于那个特定的定义为static的方法。 你不可以在static方法里调用non-static方法2(尽管反过来是可以的),你可以在没有任何对象的情况下为类自身调用static方法。 实际上,这就是static方法的主要意图。 看上去这似乎是在创建全局方法。 不过,全局方法在Java里不允许,Java允许为类定义static方法从而允许该方法访问别的static方法和static fields。 一些人争论说 static 方法不属于 object-oriented 的范畴,因为这种方法带有全局方法的意思;使用 static 方法时,既然不能有 this 的概念,你就没有为对象发送消息。 这或许是个合理的意见,假如你发现自己使用了很多 static 方法,就应该重新思考一下你的策略。 不过,statics 是实用地,很多时候你确实需要它们,所以它们到底是不是“正确的面向对象的概念”就应该留给理论家来论证。
清理:终结处理与垃圾回收
finalize定义:Java 提供了一种称为 finalize()的方法,你可以为自己的类定义它。 这段话就描述了它应该是如何工作地: 当垃圾收集器准备释放你的对象使用的存贮空间时,它首先会调用 finalize(),并且只在下一轮回才收回对象占用的存贮空间。 所以如果你选择使用 finalize(),它使你能够在垃圾收集的时候执行一些重要的清理工作。
(1) 对象可能不会被垃圾站回收
(2) 垃圾站回收不等于析构
Java 没有 destructor 或者类似的概念,所以你必须创建一个普通的方法来执行这种清理工作。 举个例子,设想创建你的对象的过程中,对象把自己绘制在了屏幕上。 如果你不明确地从屏幕抹除对象的图形,这个图形可能永远都不会被清理。 如果你在 finalize()方法里加入了某种抹除的功能,再进一步假设对象被清理、finalize()被调用(无法保证垃圾回收器会启用),那么图形会首先被从屏幕上移除,但是如果 finalize()不被调用,图形将会在屏幕上保留下去。
(3) 垃圾站回收只与内存有关
finalize()主要用在使用本地方法的情况下。
垃圾回收站的工作机制
成员初始化
(1) 对于原始类型的数据成员会初始化为0,
(2) 对于未初始化的对象引用,会初始化为null关键字
(3) 对于方法中的局部变量,未初始化时Java会产生一个错误
指定初始化
Java可以在类中指定初始化,以后生成的对象具有相同成员初始值,c++中这样做是不可以的
public class InitialValues2 {
boolean bool = true;
char ch = 'x';
byte b = 47;
short s = 0xff;
int i = 999;
long lng = 1;
float f = 3.14f;
double d = 3.14159;
} ///:~
构造器初始化
construtor 可以用来执行初始化的任务,这种方式为你的程序提供了更大的灵活性,因
为你可以调用方法然后在运行时执行一些动作来决定初始值。 不过有一件事情需要记住: 你用 construtor 来初始化对象并不是在排除自动初始化。 所以,举个例子,假如你这样编写代码:
//: initialization/Counter.java
public class Counter { Counter() { i = 7; }
// ...
} ///:~
那么 i 将首先被赋予初始值 0,然后才改为 7。
初始化的顺序:先初始化变量,再调用构造函数进行初始化,而不管他们在类中的位置如何
静态数据的初始化:
class Bowl {
Bowl(int marker) {
print("Bowl(" + marker + ")");
}
void f1(int marker) {
print("f1(" + marker + ")");
}
}
class Table {
static Bowl bowl1 = new Bowl(1);
Table() {
print("Table()");
bowl2.f1(1);
}
void f2(int marker) {
print("f2(" + marker + ")");
}
static Bowl bowl2 = new Bowl(2);
}
class Cupboard {
Bowl bowl3 = new Bowl(3);
static Bowl bowl4 = new Bowl(4);
Cupboard() {
print("Cupboard()");
bowl4.f1(2);
}
void f3(int marker) {
print("f3(" + marker + ")");
}
static Bowl bowl5 = new Bowl(5);
}
public class StaticInitialization {
public static void main(String[] args) {
print("Creating new Cupboard() in main");
new Cupboard();
print("Creating new Cupboard() in main");
new Cupboard();
table.f2(1);
cupboard.f3(1);
}
static Table table = new Table();
static Cupboard cupboard = new Cupboard();
} /* Output:
Bowl(1)
Bowl(2)
Table()
f1(1)
Bowl(4)
Bowl(5)
Bowl(3)
Cupboard()
f1(2)
Creating new Cupboard() in main
Bowl(3)
Initialization & Cleanup
129 Cupboard()
f1(2)
Creating new Cupboard() in main
Bowl(3)
Cupboard()
f1(2)
f2(1)
f3(1)
*///:~
为了总结对象的创建过程,考虑一下名为 Dog 的类:
1、即使 Dog 类没有明确使用 static 关键字,constructor 实际上就一个 static 方法。 所以 Dog 类型的对象第一次被创建的时候,或者 Dog 类的 static 成员或方法第一次被访问的时候,Java 解释器必须通过查找类路径来得到 Dog.class 文件。
2、当 Dog.class 文件被加载之后,(你将在后面学习创建类对象的知识),它的所有statics 被初始化。 因此,当 Class 对象第一次被加载的时候,static 初始化只发生一次。
3、当你使用 new Dog()创建了一个对象时,Dog 对象首先在堆里分配到足够的存贮空间。
4、这块空间自动为 Dog 里的所有 primitives 设置默认值(numbers 类型为零,还有boolean 和 char 的相应默认值),为对象引用赋予值 null。
5、执行 field 定义时的初始化。
6、Constructor 执行。 正如你将在 Reusing Classes 一章里看到的,constructor 执行可能涉及到相当多的动作,尤其是当继承卷入其中的时候。
7初始化的顺序是先静态成员,再非静态成员,再是构造函数
明确进行静态成员的初始化
class Cup {
Cup(int marker) {
print("Cup(" + marker + ")");
}
void f(int marker) {
print("f(" + marker + ")");
}
}
class Cups {
static Cup cup1;
static Cup cup2;
static {
cup1 = new Cup(1);
cup2 = new Cup(2);
}
Cups() {
print("Cups()");
}
}
public class ExplicitStatic {
public static void main(String[] args) {
print("Inside main()");
Cups.cup1.f(99); // (1)
}
// static Cups cups1 = new Cups(); // (2)
// static Cups cups2 = new Cups(); // (2)
} /* Output:
Inside main()
Cup(1)
Cup(2)
f(99)
*///:~
如果将标签(2)的//去了,则结果为:
Cup(1)
Cup(2)
Cups()
Cups()
Inside main()
f(99)
It appears to be a method, but it’s just the static keyword followed by a block of code. This code, like other static initializations, is executed only once: the first time you make an object of that class or the first time you access a static member of that class (even if you never
make an object of that class).
数组初始化:
a2 = a1; Java中允许将一个数组赋给另外一个数组,因为这里a2,a1实际上都是引用
无法确定数组长度时采取的措施:
public class ArrayNew {
public static void main(String[] args) {
int[] a;
Random rand = new Random(47);
a = new int[rand.nextInt(20)];
print("length of a = " + a.length);
print(Arrays.toString(a));
}
} /* Output:
length of a = 18
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
我们可以看到数组这个类含有一个length成员,用来表示数组长度,对于不知道成都的数组可以用new来生成
数组创建的两种形式:
Integer[] a = {
new Integer(1),
new Integer(2),
3, // Autoboxing
};
Integer[] b = new Integer[]{
new Integer(1),
new Integer(2),
3, // Autoboxing
};
尽管第一种形式()是有用的,但是它的局限性较大,因为它只能在数组被定义的地方使
用。 你可以在任何地方使用第二种形式,甚至在方法调用的内部
第二种方法还能用来处理类型和容量都不确定的数组问题
//: initialization/VarArgs.java
// Using array syntax to create variable argument lists.
class A {}
public class VarArgs {
static void printArray(Object[] args) {
for(Object obj : args)
System.out.print(obj + " ");
System.out.println();
}
public static void main(String[] args) {
printArray(new Object[]{
new Integer(47), new Float(3.14), new Double(11.11)
});
printArray(new Object[]{"one", "two", "three" });
printArray(new Object[]{new A(), new A(), new A()});
}
} /* Output: (Sample)
47 3.14 11.11
one two three
A@1a46e30 A@3e25a5 A@19821f
*///:~
本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u2/69999/showart_2046489.html |
|