1. 程式人生 > >對java中public、static的理解

對java中public、static的理解

首先是public 

在說明這四個關鍵字之前,我想就class之間的關係做一個簡單的定義,對於繼承自己的classbase class可以認為他們都是自己的子女,而對於和自己一個目錄下的classes,認為都是自己的朋友。

1publicpublic表明該資料成員、成員函式是對所有使用者開放的,所有使用者都可以直接進行呼叫

2privateprivate表示私有,私有的意思就是除了class自己之外,任何人都不可以直接使用,私有財產神聖不可侵犯嘛,即便是子女,朋友,都不可以使用。

3protectedprotected對於子女、朋友來說,就是public的,可以自由使用,沒有任何限制,而對於其他的外部

classprotected就變成private

作用域 當前類 同一package 子孫類 其他package 

public       √             √                √               √ 

protected √√ √× 

friendly     √ √ ×× 

private     √ × × ×

不寫時預設為friendly

然後是static

static在java中表示靜態

但是這個靜態又是什麼意思呢?

最開始接觸static的時候看書上的概念根本沒弄懂!

接觸有一段時間java了,在這裡面要總結一下我對static的理解:

(概念)static表示“全域性”或者“靜態”的意思,用來修飾成員變數和成員方法,也可以形成靜態static程式碼塊,但是Java語言中沒有全域性變數的概念。

這句話是說,你會用到static修飾一些個變數、方法、方法塊什麼的,這是你用到static的地方;“但是,java中沒有全域性變數的概念,怎麼理解這句話?你時刻要記住java是一個面向物件的語言,萬事萬物皆物件,無論你做什麼都需要建立一個物件,然後再呼叫這個物件的方法,java怎麼能允許存在一個在全域性都通用的“全域性變數”的概念存在呢?所以java中壓根就沒有所謂的“全域性變數”,但是沒有這個概念,不代表你不可以實現這個功能,java存在的目的就是讓人們使用它去達到人們想要的效果,所以static value就可以達到全域性變數的作用,所以,你現在應該可以理解下面這句話了吧。

(概念)用public修飾的static成員變數和成員方法本質是全域性變數和全域性方法,當宣告它類的物件市,不生成static變數的副本,而是類的所有例項共享同一個static變數。

現在進一步理解下面兩段概念:

(概念)只要這個類被載入,Java虛擬機器就能根據類名在執行時資料區的方法區內找到他們。因此,static物件可以在它的任何物件建立之前訪問,無需引用任何物件。

根據實際例子來理解這段概念,現在有兩個類,Demo1和Demo2。

此例項還包含對靜態方的操作

public class Demo1 {
    public static int i = 1;
    public int j = 2;
    
    public static int getNumber(){
        return i;
//        這個return返回的是全域性變數的i,即前面多建立的i
    }
    
    public int getDealNumber(int j){
        return j;
//        這個return返回的是所傳進來的引數,是(int j)這個東西
    }

}

public class Demo2 {
    public static void main(String args[]){
//        想要得到Demo1中的靜態的(即全域性的)變數i,直接用類名引用就可以了
        int i = Demo1.i;
//        但是想要得到Demo1中的例項的變數j,我需要怎麼做呢?(此刻牢記java面向物件的思想!)
//        首先我要先new一個Demo1的物件,然後才可以通過new出來的物件得到Demo1中的j
        Demo1 demo1 = new Demo1();
        int j = demo1.j;
//        同理,java中的static方法和非static方法都是一樣的區別
//        下面一行的方法是靜態的,我可以直接根據類名呼叫方法
        int ii = Demo1.getNumber();
//        但是想要呼叫例項的方法,就需要利用前面所new出來的Demo1的物件來呼叫了
        int jj = demo1.getDealNumber(1);
//        所以現在你可以理解上文紫色的定義了麼?
    }
}

(概念)用public修飾的static成員變數和成員方法本質是全域性變數和全域性方法,當宣告它類的物件市,不生成static變數的副本,而是類的所有例項共享同一個static變數。

弄懂了上面的程式碼,這句定義是不是迎刃而解了呢?這裡面涉及到堆疊的問題,我現在還沒有整理,我會整理的,寫完這篇我馬上就要鞏固一下堆疊的知識,我認為堆疊的知識很重要,如果你也是初學者,關注我吧,嘿嘿~

這裡說一下靜態變數和例項變數的區別:

兩者的區別是:
 對於靜態變數在記憶體中只有一個拷貝(節省記憶體),JVM只為靜態分配一次記憶體,在載入類的過程中完成靜態變數的記憶體分配,可用類名直接訪問(方便),當然也可以通過物件來訪問(但是這是不推薦的)。
 對於例項變數,沒建立一個例項,就會為例項變數分配一次記憶體,例項變數可以在記憶體中有多個拷貝,互不影響(靈活)。

所以一般在需要實現以下兩個功能時使用靜態變數:
在物件之間共享值時
 方便訪問變數時

現在理解一下靜態方法

2、靜態方法
靜態方法可以直接通過類名呼叫,任何的例項也都可以呼叫靜態方法。前面的程式碼中有直接通過類名呼叫的例子
靜態方法中不能用this和super關鍵字,不能直接訪問所屬類的例項變數和例項方法(就是不帶static的成員變數和成員成員方法),只能訪問所屬類的靜態成員變數和成員方法。因為例項成員與特定的物件關聯!就是java面向物件的思想,例項是你這個類本身的屬性,你會用這個本身的屬性去做一些事情,而這些事情不是固定的,不能像靜態方法一樣一成不變。換位思考,人是一個java類,手是類的例項方法,而人身上有手機,這個手機就是靜態方法;人只會用手去玩手機,你見過人用手機玩手麼?哈哈
因為static方法獨立於任何例項,因此static方法必須被實現,而不能是抽象的abstract。靜態方法是類內部的一類特殊方法,只有在需要時才將對應的方法宣告成靜態的,一個類內部的方法一般都是非靜態的

怎麼理解上面這句定義呢?記住得了,哈哈。

3、static程式碼塊

 static程式碼塊也叫靜態程式碼塊,是在類中獨立於類成員的static語句塊,可以有多個,位置可以隨便放,它不在任何的方法體內,JVM載入類時會執行這些靜態的程式碼塊,如果static程式碼塊有多個,JVM將按照它們在類中出現的先後順序依次執行它們,每個程式碼塊只會被執行一次。例如:

public class Test5 {
private static int a;
private int b;

static{
Test5.a=3;
System.out.println(a);
Test5 t=new Test5();
t.f();
t.b=1000;
System.out.println(t.b);
}
static{
Test5.a=4;
System.out.println(a);
}
public static void main(String[] args) {
// TODO 自動生成方法存根
}
static{
Test5.a=5;
System.out.println(a);
}
public void f(){
System.out.println("hhahhahah");
}
}  

執行結果:
3
hhahhahah
1000
4
5

 利用靜態程式碼塊可以對一些static變數進行賦值,最後再看一眼這些例子,都一個static的main方法,這樣JVM在執行main方法的時候可以直接呼叫而不用建立例項。

還用我再說什麼麼?

有時你希望定義一個類成員,使它的使用完全獨立於該類的任何物件。通常情況下,類成員必須通過它的類的物件訪問,但是可以建立這樣一個成員,它能夠被它自己使用,而不必引用特定的例項。在成員的宣告前面加上關鍵字static(靜態的)就能建立這樣的成員。如果一個成員被宣告為static,它就能夠在它的類的任何物件建立之前被訪問,而不必引用任何物件。你可以將方法和變數都宣告為static。static 成員的最常見的例子是main( ) 。因為在程式開始執行時必須呼叫main() ,所以它被宣告為static。
如果讀不懂這句話就倒著念,就明白個大概了。

注意一下幾點

宣告為static的變數實質上就是全域性變數。當宣告一個物件時,並不產生static變數的拷貝,而是該類所有的例項變數共用同一個static變數。宣告為static的方法有以下幾條限制:

它們僅能呼叫其他的static 方法。

它們只能訪問static資料。

它們不能以任何方式引用this 或super(關鍵字super 與繼承有關,在下一章中描述)。
如果你需要通過計算來初始化你的static變數,你可以宣告一個static塊,Static 塊僅在該類被載入時執行一次。

下面的例子顯示的類有一個static方法,一些static變數,以及一個static 初始化塊:
// Demonstrate static variables,methods,and blocks.

class UseStatic {
static int a = 3;
static int b;

static void meth(int x) {
System.out.println("x = " + x);
System.out.println("a = " + a);
System.out.println("b = " + b);
}

static {
System.out.println("Static block initialized.");
b = a * 4;
}

public static void main(String args[]) {
meth(42);
}
}

一旦UseStatic 類被裝載,所有的static語句被執行。首先,a被設定為3,接著static 塊執行(列印一條訊息),最後,b被初始化為a*4 或12。然後呼叫main(),main() 呼叫meth() ,把值42傳遞給x。3個println ( ) 語句引用兩個static變數a和b,以及區域性變數x 。

注意:在一個static 方法中引用任何例項變數都是非法的。