第十九、Java面向對象之static


一、如果沒有static會怎樣?

    1:定義Person類

       1)姓名、年齡、國籍,說話行爲

       2)多個構造,重載形式體現

    2:中國人的國籍都是確定的

       1)國籍可以進行顯示初始化

class Person {
	String name;
	int age;
	String gender;
	String country = "CN";

	Person() {

	}

	Person(String name, int age, String gender, String country) {
		this.name = name;
		this.age = age;
		this.gender = gender;
		this.country = country;
	}

	void speak() {
		System.out.println("國籍:" + country + " 姓名:" + name + " 性別:" + gender + " 年齡:" + age + " 哈哈!!!");
	}

}

    3:new Person 對象

       1)分析內存

       2)每個對象都維護實例變量國籍。

public class PersonDemo {
	public static void main(String[] args) {
		Person p1 = new Person("jack", 20, "男");
		p1.speak();

		Person p2 = new Person("rose", 18, "女");
		p2.speak();
	}
}

    4:內存分析

       1)棧,堆、共享區

       2)Demo.class加載進共享區

           2.1:Demo類的main方法進棧

           2.2:Person p1=new Person();

              *** Person.class 加載進方法區

              *** 堆內存開闢空間,實例變量進行默認初始化,顯示初始化。

              *** 內存地址傳給變量p1,棧和堆建立連接

           3)person p2=new Person();

              1:堆內存開闢空間,實例變量進行默認初始化,顯示初始化。

              2:內存地址傳給變量p2,棧和堆建立連接

           4)如果建立多個Person對象發現問題

              目前存在的問題:每個對象都維護有國籍,有n個Person對象就會有n份中國的 數據存內存中,這樣子會浪費內存。

              目前方案: 把“country”這個數據 移動到數據共享區中,共享這個數據給所有的Person對象使用即可。

    5:解決問題,內存優化

            1)爲了讓所有Person對象都共享一個country ,可以嘗試將country放入共享區。

            2)country變量如何放入共享區?對象如何訪問?

                 解決方案:只需要使用static修飾該數據即可            

                 static的目的:爲了實現對象之間重複屬性的數據共享


static使用

             1:主要用於修飾類的成員(包括成員變量和成員函數)

                        成員變量

                             static修飾成員變量 :如果有數據需要被共享給所有對象使用時,那麼就可以使用static修飾。(static修飾成員變量的應用場景)

                             *** 非靜態成員變量:需要創建對象來訪問

                             *** 靜態成員變量:使用類名直接調用,也可以通過對象訪問

                            靜態成員變量的訪問方式:

                                   方式1: 可以使用對象進行訪問。
                                     格式: 對象.變量名。

                                  方式2: 可以使用類名進行訪問。
                                    格式: 類名.變量名;

注意: 
                1. 非靜態的成員變量只能使用對象進行訪問,不能使用類名進行訪問。
                2. 千萬不要爲了方便訪問數據而使用static修飾成員變量,只有成員變量的數據是真正需要被共享的時候才使用static修飾。
                3. 靜態的成員變量只會在數據共享區中維護一份,而非靜態成員變量的數據會在每個對象中都維護一份的。



public static void main(String[] args) {
		
		//訪問靜態成員
		//直接通過類名來調用
		String country=Person.country;
		System.out.println(country);
		
		//通過對象.成員的形式訪問
		Person p1 = new Person("jack", 20, "男");
		p1.country="US";
		p1.speak();

}
class Person {
	String name;
	int age;
	String gender;
	//static 修飾成員變量
	static String country = "CN";

	Person() {

	}

	Person(String name, int age, String gender) {
		this.name = name;
		this.age = age;
		this.gender = gender;

	}

	void speak() {

		System.out.println("國籍:" + country + " 姓名:" + name + " 性別:" + gender
				+ " 年齡:" + age + " 哈哈!!!");
	}

}


        成員方法

                 可以使用類名直接調用

        1:靜態函數:

               1)靜態函數中不能訪問非靜態成員變量,只能訪問靜態變量。

               2)靜態方法不可以定義this,super關鍵字.

               3)因爲靜態優先於對象存在.靜態方法中更不可以出現this

       2:非靜態函數:非靜態函數中可以訪問靜態成員變量


static修飾方法(靜態的成員方法):

訪問方式:
方式一:可以使用對象進行訪問。
對象.靜態的函數名();


方式二:可以使用類名進行訪問。
類名.靜態函數名字。

推薦使用是類名直接訪問靜態的成員。

      1、代碼實現如下

class Person {
	String name;
	int age;
	String gender;
	//static 修飾成員變量
	static String country = "CN";

	Person() {

	}

	Person(String name, int age, String gender) {
		this.name = name;
		this.age = age;
		this.gender = gender;

	}
	//非靜態方法
	void speak() {
		//非靜態方法可以訪問靜態成員
		System.out.println("國籍:" + country );
		
		System.out.println("國籍:" + country + " 姓名:" + name + " 性別:" + gender
				+ " 年齡:" + age + " 哈哈!!!");
		
	}
	//靜態方法
	static void run(){
		//靜態方法只能訪問靜態成員變量。
		System.out.println("國籍:"+country);
		
		//靜態方法訪問非靜態成員變量,編譯報錯。
		System.out.println(" 姓名:" + name);
		
		//靜態方法中不可以出現this,編譯報錯
		this.speak();
	}
}

         2、細節:

                1)靜態函數中不能使用非靜態變量

                2)非靜態函數可以訪問靜態變量

         3、爲什麼靜態函數中不能訪問非靜態成員

               1)static修飾的成員在共享區中。優先於對象存在

               2)驗證

                  *** 使用靜態代碼塊驗證

                      靜態代碼塊

                      static{

                            靜態代碼塊執行語句;

                      }

               *** 靜態代碼塊特點

                    隨着類的加載而加載。只執行一次,優先於主函數。用於給類進行初始化。

public class PersonDemo {
	public static void main(String[] args) {

		// 訪問靜態成員
		// 直接通過類名來調用
		String country = Person.country;
		System.out.println(country);

		// 通過對象.成員的形式訪問
		Person p1 = new Person("jack", 20, "男");
		p1.country = "US";
		p1.speak();

	}
}


class Person {
	String name;
	int age;
	String gender;
	// static 修飾成員變量
	static String country = "CN";
	static {
		System.out.println("這是靜態代碼塊");//靜態代碼塊是在Person.class文件加載到內存的時候就馬上執行的。
	}

	{
		System.out.println("這是構造代碼塊");
	}

	Person() {
		System.out.println("無參數構造");
	}

	Person(String name, int age, String gender) {
		this.name = name;
		this.age = age;
		this.gender = gender;
		System.out.println(" 有參數構造");

	}

	// 非靜態方法
	void speak() {
		// 非靜態方法可以訪問靜態成員
		System.out.println("國籍:" + country);

		System.out.println("國籍:" + country + " 姓名:" + name + " 性別:" + gender
				+ " 年齡:" + age + " 哈哈!!!");
		// 非靜態方法可以調用靜態方法。
		run();
	}

	// 靜態方法與非靜態方法的字節碼文件是同時存在內存中的。 只是靜態的成員變量數據是優先於對象存在而已。
	static void run() {
		// 靜態方法只能訪問靜態成員變量。
		System.out.println("國籍:" + country);
	}
}


4、static特點

        1 隨着類的加載而加載,靜態會隨着類的加載而加載,隨着類的消失而消失。說明它的生命週期很長。

        2 優先於對象存在。-->靜態是先存在,對象是後存在。

        3 被所有實例(對象)所共享。

        4 可以直接被類名調用

5、靜態的成員變量與非靜態的成員變量的區別:

1. 作用上的區別:
1. 靜態的成員變量的作用共享一個 數據給所有的對象使用。
2. 非 靜態的成員變量的作用是描述一類事物的公共屬性。
2. 數量與存儲位置上的區別:
1. 靜態成員變量是存儲 方法區內存中,而且只會存在一份數據。
2. 非靜態的成員變量是存儲在堆內存中,有n個對象就有n份數據。
3. 生命週期的區別:
1. 靜態的成員變量數據是隨着類的加載而存在,隨着類文件的消失而消失。
2.非靜態的成員數據是隨着對象的創建而存在,隨着對象被垃圾回收器回收而消失。


6、靜態優缺點

      優點:   對對象的共享數據進行單獨空間的存儲,節省空間例如Person 都有國籍。該數據可以共享可以被類名調

      缺點:生命週期過長

                 訪問出現侷限性。(靜態只能訪問靜態)

7、什麼時候定義靜態變量

       靜態變量(類變量)當對象中出現共享數據

              例如:學生的學校名稱。學校名稱可以共享

              對象的數據要定義爲非靜態的存放在對內存中(學生的姓名,學生的年齡)

8、什麼時候定義靜態函數

        如果功能內部沒有訪問到非靜態數據(對象的特有數據。那麼該功能就可以定義爲靜態), 一般用於工具類型的方法         

9、靜態的應用

        自定義數組工具類


靜態函數要注意的事項:

1. 靜態函數是可以調用類名或者對象進行調用的,而非靜態函數只能使用對象進行調用。
2. 靜態的函數可以直接訪問靜態的成員,但是不能直接訪問非靜態的成員。
原因:靜態函數是可以使用類名直接調用的,這時候可能還沒有存在對象,
而非靜態的 成員數據是隨着對象 的存在而存在的。


3. 非靜態的函數是可以直接訪問靜態與非靜態的成員。
原因:非靜態函數只能由對象調用,當對象存在的時候,靜態數據老早就已經存在了,而非靜態
數據也隨着對象的創建而存在了。


4. 靜態函數不能出現this或者super關鍵字。
原因:因爲靜態的函數是可以使用類名調用的,一旦使用類名調用這時候不存在對象,而this
關鍵字是代表了一個函數 的調用者對象,這時候產生了衝突。


靜態的數據的生命週期:

               靜態的成員變量數據是優先於對象存在的。

靜態函數不能訪問非靜態的成員?

靜態函數只要存在有對象,那麼也可以訪問非靜態的數據。只是不能直接訪問而已。



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