Java中的一些小問題

只是記錄幾個在學習Java的過程中思考的一些問題,以及自己的理解。

1.Java 局部變量、實例變量、類變量(靜態變量)區別?

2.爲什麼“類方法中不能訪問非靜態變量”?

3.如何準確記憶Java中各個訪問修飾符的訪問範圍?

4.如何理解“重載”與“覆蓋”?


1.Java 局部變量、成員變量、類變量(靜態變量)區別?


局部變量:在Java方法中的變量。其作用域只在本方法內。

成員變量:是獨立於方法之外的,不會有static修飾,也稱作“實例變量”,它就是對象的私有變量。

類變量:類變量獨立於方法之外,也稱作“靜態變量”。用static修飾。static 表示“全局的”“靜態的”,用來修飾成員變量,成員方法,或者靜態代碼塊。

成員變量和類變量的區別?

其根本區別在於,類變量是類所實例化的所有對象的公有變量,任何一個對象對該變量進行修改以後,其他對象得到的都是被修改之後的數據;成員變量是對象私有的變量,某一對象對成員變量進行修改,隻影響該對象成員變量的數據,不影響其他對象。


Code 說明:

class  Student{
	int age;                  //成員變量,“實例變量”
	static int totalAge;       //類變量,“靜態變量”
	public void getTime()
	{
		float time=2016;         //局部變量,作用域在本方法以內
		System.out.println("time="+time);
	}
}
public class Test6 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Student s1=new Student();
		Student s2=new Student();
		
		s1.age=1;         
		s1.totalAge=1;
		
		System.out.println("s2.age="+s2.age);  //結果是 0
		//成員變量s1.age改變,只會影響其s1.age,對象s2的成員變量s2.age不會有任何改變
		System.out.println("s2.total="+s2.totalAge);  //結果是1
		//s1改變類變量,其他對象會得到改變之後的數據
	}
}


2.爲什麼“類方法中不能訪問非靜態變量”?

本來自己準備寫寫理解,加上代碼來做解釋。但是看到別的大神對此解釋的非常清楚,所以準備搬過來。
爲什麼不能從靜態的方法裏面調用非靜態方法,或變量?   (沒有找到原作者,對作者抱歉)

程序都將在內存中執行,變量只有在內存中佔有一席之地時才能被訪問。
類的靜態成員(類變量、類方法)屬於類本身,在類加載時就會被分配內存,可以通過類名直接訪問;非靜態成員(成員變量,成員方法)屬於類實例化的對象,只有在類產生對象時(類進行實例化時)時纔會產生,然後通過類的對象去訪問。
在一個類的靜態成員中去訪問非靜態成員會出錯的原因是:靜態成員在類加載時就已經創建了,而非靜態成員要等到類進行實例化、創建對象的時候纔會產生。簡單的說,非靜態成員不存在的時候靜態成員就已經存在了。訪問一個不存在的東西當然會出錯。

而類是在什麼時候加載的呢?

引導類加載器負責加載的核心類比如 String 類在 JVM 啓動時(main 方法開始執行前)就會被加載,其它類在使用前(new 它對象或調用其靜態方法訪問靜態域等等前)會被動態加載,要注意的是子類被加載前它的所有類要根據由父到子的順序被逐一加載。

class A1
{
    public static int a=5;
}
class B1 extends A1
{
    public static int a=8;
    void print(){
        System.out.println(super.a);
        System.out.println(a);
    }
}
public class TestStatic
{
    public static void main(String args[])
    {
        System.out.println("b.a="+B1.a);
        System.out.println("b.a="+A1.a);
        new B1().print();
    }
}

說明如下:

在doc環境下,

Java TestStatic時, 
虛擬機會先加載TestStatic類,此時虛擬機會先看看TestStatic類有沒有靜態的字段,

沒有。JVM直接執行main 方法,

main方法中第一句代碼是打印B1.a, 

虛擬機便會去找類B1,找到類B1時,虛擬機發現B1的父親是A1, 
於是父親優先,先加載A1, 
同樣,在加載A1時,會看看A1中有什麼靜態的東西,有, 
static int a = 5; 
a是靜態的,先加載,當把靜態的字段加載完後,一個類就算加載完了, 
所以A1已經加載完畢,以後不用在加載了。 
父親加載完了,輪到B1了,同樣先看看裏面有什麼靜態的字段,有, 
static int a = 8; 
此時B1也加載完畢了。 
第一條打印語句到此時也執行完畢了, 
輪到第二條打印語句了。 
當執行new B1().print();這句時, 
會發生動態綁定, 
此時會有一個代表B1對象的this對象傳遞給print()方法, 
所以print()方法中的 
System.out.println(a); 
其實是, 
System.out.println(this.a); 
會打印出一個8出來。 
至於super.a就簡單了, 
打印父類中的a, 
結果是5. 
到此,main()方法執行完,整個程序退出。

再加一句:super關鍵字有兩種意義:–調用父類的方法–調用父類的構造器。但是super並不表示一個指向對象的引用,它只是一個特殊的關鍵字,用來告訴編譯器,現在要調用的是父類的方法。

3.如何準確記憶Java中各個訪問修飾符的訪問範圍?

雖然學習了修飾符的訪問範圍,但是總是記憶不清楚。所以想小小總結一下,加深一下印象。

Java 裏的控制訪問範圍的修飾符總共有四個,從控制範圍從小到大依次是private,默認,protected,public。但是比如protected 其訪問範圍到底是多大,同類?同包?不同包?還是記憶不清楚

總結了一個表,如下:


做個說明:

其實對於private,default,protected,public控制範圍由小到大早已爛熟於心,但對於同類,同包,子類,不同包還沒有達到那個地步。

將“同類,同包,子類,不同包”形象比作四種關係:自己和“自己,夫妻,子女,自己的朋友”,其親密程度是由近到遠,但是範圍在擴大。

1.private 私有的,就自己能訪問,別人誰都不行。訪問範圍最小,只能是同類之間訪問。

2.default  默認的,就像親密付,只有跟自己非常親密的人才行,比如妻子。訪問範圍比private稍擴大,在同類同包都可以訪問。

3.protected 受到保護的,就像自己家的東西只有家人(自己老婆還有孩子)纔可以分享。訪問範圍比default 更大,在同類同包子類可訪問。

4.public 公有的,除了自己和家人以外,認識自己的朋友都可以看。訪問範圍比default再大一點,在同類,同包,子類,不同包可以訪問。


4.如何理解“重載”與“覆蓋”?

重載(Overloading 

簡單來講,就是類的同一種功能的多種實現形式,具體採用哪一種,取決於調用者傳遞的參數。

再具體一點:

百度百科給出的定義方法重載是指在一個類中定義多個同名的方法,但要求每個方法具有不同的參數的類型或參數的個數。調用重載方法時,Java編譯器能通過檢查調用的方法的參數類型和個數選擇一個恰當的方法。

歸納幾個要點:

1.重載要求,在同一個類中,定義多個同名方法。

2.同名方法具有不同的參數類型/個數。

3.返回類型,可以相同也可以不同。不能以返回類型來區分重載函數。

public class Test8 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		A a = new A();
		System.out.println("得到較大的數字:"+a.getMax(11, 12.5f));;
	}
}
class A{
	//返回較大的整數
	int getMax(int a,int b){
		if(a>b){
			return a;
		}else{
			return b;
		}
	}
	//返回較大的小數
	float getMax(float a,float b){
		if(a>b){
			return a;
		}else{
			return b;
		}
	}
}
覆蓋(Overriding

簡單的講,就是如果子類中的某個方法和父類中的名稱、返回類型、參數都一樣。那麼我們就說子類的這個方法覆蓋了父類的那個方法。

PS:覆蓋是爲了解決,子類在繼承父類以後,雖然有了父類的所有方法,但是希望對該方法做一定的修改而產生的。覆蓋也稱作“重寫”。

要點總結如下:

1.子類中的方法和父類的某一個方法名稱、返回類型、參數都一樣,則新方法會覆蓋父類中的方法。

2.如需父類中原有的方法,可使用super關鍵字,該關鍵字引用了當前類的父類。

3.子類中方法的修飾符訪問範圍>=父類中該方法的訪問範圍。

public class Test9 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Cat c=new Cat();
		c.speak();
	}
}
class Animal{
	protected void speak(){
		System.out.println("作爲動物,我不知道怎麼叫!");
	}
}
class Cat extends Animal{
	public void speak(){           //注意:public>protected 子類方法可以擴大,但不能縮小訪問範圍
		System.out.println("我是小貓,喵喵!");
	}
}
class Dog extends Animal{
	protected void speak(){
		System.out.println("我是小狗,汪汪!");
	}
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章