Topic: [转载]Static的意义与实作方式

  Print this page

1.[转载]Static的意义与实作方式 Copy to clipboard
Posted by: 阿熊
Posted on: 2002-09-21 20:21

「将某class产生出一个instance之后,此class所有的instance field都会新增一份,那么所有的instance method是否也会新增一份?」我常常看到网络上有人在讨论此问题,所以写了这篇文章,以为解释。

Member的种类
类别(class)的内部组成统称为成员(member),如果依据成员是「资料」还是「程序」来区分,可以分成:

资料,被称为field
程序,被称为method
如果再依据有无使用static修饰而细分,则成员可细分成四种:

class field:有用static修饰的field
class method:有用static修饰的method
instance field:没有用static修饰的field
instance method:没有用static修饰的method
顾名思义,class field/method和class本身有密切的关系,而instance field/method则与instance(也就是对象)有密切的关系。请看下面的范例程序。

public class Class1 {

 public static int classField;

 public static void classMethod1() {

  // ...

 }

 public static void classMethod2() {

  // ...

 }

 public int instanceField;

 public void instanceMethod1() {

  // ...

 }

 public void instanceMethod2() {

  // ...

 }

}

public class Class2 {

 public static void classMethod () {

  // ...

 }

 public void instanceMethod() {

  // ...

 }

}

Field
宣告field时,如果前面加上static的修饰字,就会使得此field变成是class field。一个class field永远只占用一块内存,而且此内存空间是在此class一被加载(load)内存之后就立刻配置的(allocate),感觉就如同此field与该class本身相关,而不是与该class的instance相关。class field可以被同一个class的class method内部所直接使用,举例来说,上述的classMethod1()内部可以出现classField。如果Class1的class method或instance method欲使用到Class2的class field,就必须在前面冠上Class2,例如:Class2.classField。

宣告field时,如果前面「不」加上static的修饰字,就会使得此field变成是instance field。对instance field而言,每产生一个instance(对象)就多一块instance field的内存,每少一个instance就少一块instance field的内存。instance field可以被同一个instance的instance method内部所直接使用,举例来说,上述的instanceMethod1()内部可以出现instanceField。如果某class的class method或instance method欲使用到某instance的instance field,就必须在前面冠上instance名称,例如:obj.classField。

Method
宣告method时,如果前面加上static的修饰字,就会使得此method变成是class method。对class method而言,永远只占用一块内存,而且此内存空间是在此class一被加载进内存之后就立刻配置的,就如同此method是与该class本身相关,而不是与该class的instance相关。class method可以被同一个class的任何class method内部所直接使用,举例来说,上述的classMethod1()内部可以出现classMethod2()。如果Class1的class method或instance method欲使用到Class2的classMethod(),就必须在前面冠上Class2,也就是Class2.classMethod()。

宣告method时,如果前面「不」加上static的修饰字,就会使得此method变成是instance method。对instance method而言,每产生一个instance「并不会」多一块instance method的内存。同一个method不管被调用(invoke)几次,也不管被调用时的instance是何者,每次的程序代码完全都一样,差别只在每次执行时资料不同,而资料是存放在call stack中,所以不会混淆。在instance method内,资料的来源包括了参数和instance field。参数被传进来变成call stack内的entry,所以不会混淆,这很容易理解,但是instance field是如何区隔开来的(前面刚提过:instance field会随着instance数目增加而增加),这是透过隐匿(implicit)的this参数来达到了,稍后会有说明。instance method可以被同一个instance的instance method内部所直接使用,举例来说,上述的instanceMethod1()内部可以出现instanceMethod2()。如果某class的class method或instance method欲使用到某instance的某instance method,就必须在前面冠上此instance名称,例如:obj.classMethod()。

隐匿的this参数
综合上面的叙述来看:

class field:共享一块内存
class method:共享一块内存
instance field:随着每个instance各有一块内存
instance method:共享一块内存
instance method为什么不是随着每个instance占有一块内存,反倒是共享一块内存?其实,让每个instance method如同instance field一样,随着每个instance占有一块内存,这么做当然是可以的,只是Java编译器和JVM都不这么做,因为太浪费内存空间了。一个field少则占用一个byte,多则占用数百Byte,但是method少则数个byte,多则数百Kilo Byte。Mehtod耗费的内存是field的数百倍,甚至数千倍,当然是能共享就尽量共享,比较不会消耗内存。既然JVM让一个class的所有instance共享相同的instance method,下面两行程序代码在instanceMethod()内部时,如何区分是instance1或instance2?

instance1.instanceMethod();

instance2.instanceMethod();

因为编译器会帮我们在把instance1和instance2个别传入instanceMethod()中当作第一个参数。也就是说,任何instance method参数的实际个数都会比表面上多一个,这个多出来的参数是由Java编译器帮我们加上去的,用来代表对应的instance。此参数的变量名称为this,也是Java的一个关键词(keyword)。

当调用某个instance method或使用某个instance field时,你必须在前面加上该instance的名称,如果该instance method/field相关的instance和当时程序代码所在的instance method的instance指的是同一个instance时,该instance的名称就是this,这种情况下,你也可以选择不在前面加上「this.」。

然而,在某些状况下,非得在前面加上「this.」不可。例如,当method中的参数或区域变量和instance field名称完全相同时,如果不在前面冠上「this.」,那么指的是参数或区域变量;如果在前面冠上「this.」,那么指的才是instance field。

本文作者:蔡学镛


   Powered by Jute Powerful Forum® Version Jute 1.5.6 Ent
Copyright © 2002-2021 Cjsdn Team. All Righits Reserved. 闽ICP备05005120号-1
客服电话 18559299278    客服信箱 714923@qq.com    客服QQ 714923