【Java学习笔记】Day 4-2 Static 关键字及Java内存区域

Think In Java 关于Static的介绍
Copy From Think in Java

通常,我们创建类时会指出那个类的对象的外观与行为。除非用new创建那个类的一个对象,否则实际上并未得到任何东西。(注意,这里其实就是说的引用和真正的对象创建问题)只有执行了new后,才会正式生成数据存储空间,并可使用相应的方法。
但在两种特殊的情形下,上述方法并不堪用。一种情形是只想用一个存储区域来保存一个特定的数据——无论要创建多少个对象,甚至根本不创建对象。另一种情形是我们需要一个特殊的方法,它没有与这个类的任何对象关联。也就是说,即使没有创建对象,也需要一个能调用的方法。为满足这两方面的要求,可使用static(静态)关键字。一旦将什么东西设为static,数据或方法就不会同那个类的任何对象实例联系到一起。所以尽管从未创建那个类的一个对象,仍能调用一个static方法,或访问一些static数据。而在这之前,对于非static数据和方法,我们必须创建一个对象,并用那个对象访问数据或方法。这是由于非static数据和方法必须知道它们操作的具体对象。当然,在正式使用前,由于static方法不需要创建任何对象,所以它们不可简单地调用其他那些成员,同时不引用一个已命名的对象,从而直接访问非static成员或方法(因为非static成员和方法必须同一个特定的对象关联到一起)。
有些面向对象的语言使用了"类数据"和"类方法"这两个术语。它们意味着数据和方法只是为作为一个整体的类而存在的,并不是为那个类的任何特定对象。有时,您会在其他一些Java书刊里发现这样的称呼。
为了将数据成员或方法设为static,只需在定义前置和这个关键字即可。例如,下述代码能生成一个static数据成员,并对其初始化:

class StaticTest {
Static int i = 47;
}

现在,尽管我们制作了两个StaticTest对象,但它们仍然只占据StaticTest.i的一个存储空间。这两个对象都共享同样的i。请考察下述代码:
StaticTest st1 = new StaticTest();
StaticTest st2 = new StaticTest();
此时,无论st1.i还是st2.i都有同样的值47,因为它们引用的是同样的内存区域。
有两个办法可引用一个static变量。正如上面展示的那样,可通过一个对象命名它,如st2.i。亦可直接用它的类名引用,而这在非静态成员里是行不通的(最好用这个办法引用static变量,因为它强调了那个变量的"静态"本质)。
StaticTest.i++;
其中,++运算符会使变量增值。此时,无论st1.i还是st2.i的值都是48。
类似的逻辑也适用于静态方法。既可象对其他任何方法那样通过一个对象引用静态方法,亦可用特殊的语法格式"类名.方法()"加以引用。静态方法的定义是类似的:
class StaticFun {
static void incr() { StaticTest.i++; }
}
从中可看出,StaticFun的方法incr()使静态数据i增值。通过对象,可用典型的方法调用incr():
StaticFun sf = new StaticFun();
sf.incr();
或者,由于incr()是一种静态方法,所以可通过它的类直接调用:
StaticFun.incr();
尽管是"静态"的,但只要应用于一个数据成员,就会明确改变数据的创建方式(一个类一个成员,以及每个对象一个非静态成员)。若应用于一个方法,就没有那么戏剧化了。对方法来说,static一项重要的用途就是帮助我们在不必创建对象的前提下调用那个方法。正如以后会看到的那样,这一点是至关重要的——特别是在定义程序运行入口方法main()的时候。
和其他任何方法一样,static方法也能创建自己类型的命名对象。所以经常把static方法作为一个"领头羊"使用,用它生成一系列自己类型的"实例"。

以上是关于Static Think in Java给出的解释。感觉说的比较理性了。额,就是抽象。

打算动手试试,分别验证一下。

Example One
 1 public class TestStaticUnStaticClass {
 2     private static String staticStr = "Hello Java,I'm In UnStatic Class";
 3 
 4     public static void setStaticStr(String value) {
 5         System.out.println("设置函数--设置前" + staticStr);
 6         staticStr = value;
 7         System.out.println("设置函数--设置后" + staticStr);
 8     }
 9 
10     public TestStaticUnStaticClass() {
11         System.out.println("构造函数" + staticStr);
12     }
13 
14     public static void printStaticStr() {
15         System.out.println("打印函数" + staticStr);
16     }
17 }
18 
19 
20 public class TestStatic {
21     public static void main(String[] args) {
22         System.out.println("直接用类名调用输出方法");
23         TestStaticUnStaticClass.printStaticStr();
24         System.out.println("创建对象并设置信息再调用输出方法");
25         TestStaticUnStaticClass test = new TestStaticUnStaticClass();
26 
27         test.setStaticStr("Hello Java,I set value outClass with Object");
28 
29         test.printStaticStr();
30         System.out.println("再修改信息后重新用类名调用输出方法");
31         TestStaticUnStaticClass.printStaticStr();
32         System.out.println("利用类名访问方法修改内容并調用輸出方法");
33         TestStaticUnStaticClass
34                 .setStaticStr("Hello Java,I set value outClass with ClassName");
35         TestStaticUnStaticClass.printStaticStr();
36         System.out.println("再用类名修改内容之后,直接用之前声明的对象调用输出方法");
37         test.printStaticStr();
38 
39     }
40 }

显示结果

Example One 显示结果
直接用类名调用输出方法
打印函数Hello Java,I'm In UnStatic Class
创建对象并设置信息再调用输出方法
构造函数Hello Java,I'm In UnStatic Class
设置函数--设置前Hello Java,I'm In UnStatic Class
设置函数--设置后Hello Java,I set value outClass with Object
打印函数Hello Java,I set value outClass with Object
再修改信息后重新用类名调用输出方法
打印函数Hello Java,I set value outClass with Object
利用类名访问方法修改内容并調用輸出方法
设置函数--设置前Hello Java,I set value outClass with Object
设置函数--设置后Hello Java,I set value outClass with ClassName
打印函数Hello Java,I set value outClass with ClassName
再用类名修改内容之后,直接用之前声明的对象调用输出方法
打印函数Hello Java,I set value outClass with ClassName

这个就只实例化 了一个对象。

 

下面的代码创建了两个对象,用到了之EXAMPLE ONE的一个类方法

Example2
 1 public static void main(String[] args) {
 2 
 3         /*
 4          * System.out.println("直接用类名调用输出方法");
 5          * TestStaticUnStaticClass.printStaticStr();
 6          * System.out.println("创建对象并设置信息再调用输出方法"); TestStaticUnStaticClass test =
 7          * new TestStaticUnStaticClass();
 8          * 
 9          * test.setStaticStr("Hello Java,I set value outClass with Object");
10          * 
11          * test.printStaticStr(); System.out.println("再修改信息后重新用类名调用输出方法");
12          * TestStaticUnStaticClass.printStaticStr();
13          * System.out.println("利用类名访问方法修改内容并調用輸出方法"); TestStaticUnStaticClass
14          * .setStaticStr("Hello Java,I set value outClass with ClassName");
15          * TestStaticUnStaticClass.printStaticStr();
16          * System.out.println("再用类名修改内容之后,直接用之前声明的对象调用输出方法");
17          * test.printStaticStr();
18          */
19         System.out.println("实例化对象t1");
20         TestStaticUnStaticClass t1 = new TestStaticUnStaticClass();
21         System.out.println("实例化对象t2");
22         TestStaticUnStaticClass t2 = new TestStaticUnStaticClass();
23         System.out.println("对象t1设置内容并输出");
24         t1.setStaticStr("Hello Java,I set value outClass by t1");
25         t1.printStaticStr();
26         System.out.println("对象t2输出");
27         t2.printStaticStr();
28         System.out.println("实例化对象t3");
29         TestStaticUnStaticClass t3 = new TestStaticUnStaticClass();
30         System.out.println("类名设置内容");
31         TestStaticUnStaticClass
32                 .setStaticStr("Hello Java,I set value outClass by ClassName");
33         System.out.println("对象t3输入");
34         t3.printStaticStr();
35     }

显示结果如下

Example 2的显示结果
实例化对象t1
构造函数Hello Java,I'm In UnStatic Class
实例化对象t2
构造函数Hello Java,I'm In UnStatic Class
对象t1设置内容并输出
设置函数--设置前Hello Java,I'm In UnStatic Class
设置函数--设置后Hello Java,I set value outClass by t1
打印函数Hello Java,I set value outClass by t1
对象t2输出
打印函数Hello Java,I set value outClass by t1
实例化对象t3
构造函数Hello Java,I set value outClass by t1
类名设置内容
设置函数--设置前Hello Java,I set value outClass by t1
设置函数--设置后Hello Java,I set value outClass by ClassName
对象t3输入
打印函数Hello Java,I set value outClass by ClassName

 

静态块

Example 3
 1 public class TestStaticStaticClass {
 2     private static String mStr = "Hello Java,I'm In UnStatic Class";
 3     static {
 4         System.out.println("进入静态块" + mStr);
 5         mStr = "Hello Java,I set value in Static Square";
 6         System.out.println("静态块赋值并离开" + mStr);
 7     }
 8 
 9     public static void setStr(String value) {
10         System.out.println("设置函数--设置前" + mStr);
11         mStr = value;
12         System.out.println("设置函数--设置后" + mStr);
13     }
14 
15     public static void printStr() {
16         System.out.println("打印函数" + mStr);
17     }
18 }
19 
20 
21 public class TestStatic {
22     public static void main(String[] args) {
23 
24         /*
25          * System.out.println("直接用类名调用输出方法");
26          * TestStaticUnStaticClass.printStaticStr();
27          * System.out.println("创建对象并设置信息再调用输出方法"); TestStaticUnStaticClass test =
28          * new TestStaticUnStaticClass();
29          * 
30          * test.setStaticStr("Hello Java,I set value outClass with Object");
31          * 
32          * test.printStaticStr(); System.out.println("再修改信息后重新用类名调用输出方法");
33          * TestStaticUnStaticClass.printStaticStr();
34          * System.out.println("利用类名访问方法修改内容并調用輸出方法"); TestStaticUnStaticClass
35          * .setStaticStr("Hello Java,I set value outClass with ClassName");
36          * TestStaticUnStaticClass.printStaticStr();
37          * System.out.println("再用类名修改内容之后,直接用之前声明的对象调用输出方法");
38          * test.printStaticStr();
39          */
40 
41         /*
42          * System.out.println("实例化对象t1"); TestStaticUnStaticClass t1 = new
43          * TestStaticUnStaticClass(); System.out.println("实例化对象t2");
44          * TestStaticUnStaticClass t2 = new TestStaticUnStaticClass();
45          * System.out.println("对象t1设置内容并输出"); t1.setStaticStr("Hello Java,I set
46          * value outClass by t1"); t1.printStaticStr();
47          * System.out.println("对象t2输出"); t2.printStaticStr();
48          * System.out.println("实例化对象t3"); TestStaticUnStaticClass t3 = new
49          * TestStaticUnStaticClass(); System.out.println("类名设置内容");
50          * TestStaticUnStaticClass .setStaticStr("Hello Java,I set value
51          * outClass by ClassName"); System.out.println("对象t3输入");
52          * t3.printStaticStr();
53          */
54 
55         System.out.println("实例化对象a并打印,并设置值");
56         TestStaticStaticClass a = new TestStaticStaticClass();
57         a.printStr();
58         a.setStr("Hello Java,I set value out Static Square by Object");
59         System.out.println("类名调用打印,并设置值,分别打印");
60         TestStaticStaticClass.printStr();
61         TestStaticStaticClass
62                 .setStr("Hello Java,I set value out Static Square by ClassName");
63         TestStaticStaticClass.printStr();
64         a.printStr();
65         System.out.println("实例化对象b并打印验证Static块的加载时机");
66         TestStaticStaticClass b = new TestStaticStaticClass();
67         b.printStr();
68 
69     }
70 }

显示结果

Example 3的显示结果
实例化对象a并打印,并设置值
进入静态块Hello Java,I'm In UnStatic Class
静态块赋值并离开Hello Java,I set value in Static Square
打印函数Hello Java,I set value in Static Square
设置函数--设置前Hello Java,I set value in Static Square
设置函数--设置后Hello Java,I set value out Static Square by Object
类名调用打印,并设置值,分别打印
打印函数Hello Java,I set value out Static Square by Object
设置函数--设置前Hello Java,I set value out Static Square by Object
设置函数--设置后Hello Java,I set value out Static Square by ClassName
打印函数Hello Java,I set value out Static Square by ClassName
打印函数Hello Java,I set value out Static Square by ClassName
实例化对象b并打印验证Static块的加载时机
打印函数Hello Java,I set value out Static Square by ClassName

 

替换顺序

Example 4
 1 public class TestStatic {
 2     public static void main(String[] args) {
 3 
 4         /*
 5          * System.out.println("直接用类名调用输出方法");
 6          * TestStaticUnStaticClass.printStaticStr();
 7          * System.out.println("创建对象并设置信息再调用输出方法"); TestStaticUnStaticClass test =
 8          * new TestStaticUnStaticClass();
 9          * 
10          * test.setStaticStr("Hello Java,I set value outClass with Object");
11          * 
12          * test.printStaticStr(); System.out.println("再修改信息后重新用类名调用输出方法");
13          * TestStaticUnStaticClass.printStaticStr();
14          * System.out.println("利用类名访问方法修改内容并調用輸出方法"); TestStaticUnStaticClass
15          * .setStaticStr("Hello Java,I set value outClass with ClassName");
16          * TestStaticUnStaticClass.printStaticStr();
17          * System.out.println("再用类名修改内容之后,直接用之前声明的对象调用输出方法");
18          * test.printStaticStr();
19          */
20 
21         /*
22          * System.out.println("实例化对象t1"); TestStaticUnStaticClass t1 = new
23          * TestStaticUnStaticClass(); System.out.println("实例化对象t2");
24          * TestStaticUnStaticClass t2 = new TestStaticUnStaticClass();
25          * System.out.println("对象t1设置内容并输出"); t1.setStaticStr("Hello Java,I set
26          * value outClass by t1"); t1.printStaticStr();
27          * System.out.println("对象t2输出"); t2.printStaticStr();
28          * System.out.println("实例化对象t3"); TestStaticUnStaticClass t3 = new
29          * TestStaticUnStaticClass(); System.out.println("类名设置内容");
30          * TestStaticUnStaticClass .setStaticStr("Hello Java,I set value
31          * outClass by ClassName"); System.out.println("对象t3输入");
32          * t3.printStaticStr();
33          */
34         System.out.println("类名调用打印,并设置值");
35         TestStaticStaticClass.printStr();
36         TestStaticStaticClass
37                 .setStr("Hello Java,I set value out Static Square by ClassName");
38 
39         System.out.println("实例化对象a并打印");
40         TestStaticStaticClass a = new TestStaticStaticClass();
41         a.printStr();
42     }
43 }

显示结果

Example 4 的显示结果
类名调用打印,并设置值
进入静态块Hello Java,I'm In UnStatic Class
静态块赋值并离开Hello Java,I set value in Static Square
打印函数Hello Java,I set value in Static Square
设置函数--设置前Hello Java,I set value in Static Square
设置函数--设置后Hello Java,I set value out Static Square by ClassName
实例化对象a并打印
打印函数Hello Java,I set value out Static Square by ClassName

 

会发现,JVM加载类时会执行这些静态的代码块,如果static代码块有多个,JVM将按照它们在类中出现的先后顺序依次执行它们,每个代码块只会被执行一次。

其他的Static的规律,在显示结果和实例中都比较明显了。

 

 

这里引出一个问题,叫Java的内存区域。

栈内存:对象名称。(实际指的是对象对于堆的引用地址)

堆内存:属性

全局代码区:所有的操作方法

全局变量区:所有的Static属性

 

略微简陋,以后的学习中再扩展。

转载于:https://www.cnblogs.com/Xuhaiyang/archive/2012/04/19/2457445.html

你可能感兴趣的:(java)