一、如果沒有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
關鍵字是代表了一個函數 的調用者對象,這時候產生了衝突。
靜態的數據的生命週期:
靜態的成員變量數據是優先於對象存在的。