Static 關鍵字
靜态:static是一個修飾符,用于修飾成員(成員變量,成員函數)。
當成員被靜态修飾後,就多了一個調用方式,除了可以被對象調用外,還可以直接被類名調用。(類名.靜态成員)System.out.println(Person.country); 直接被調用
static特點:
1.随着類的加載而加載(也就是說,靜态會随着類的消失而消失。說明它的生命周期最長)
2.優先于對象存在
明确一點:靜态是先存在的。對象是後存在的
3.被所有的對象所共享
4.可以直接被類名所調用
String name;成員變量,執行個體變量
static String country = “cn”;靜态的成員變量,類變量。
執行個體變量和類變量的差別:
1.存放位置: 類變量随着類的加在而存在于方法區中 執行個體變量随着對象的建立而存在于堆記憶體中
2.生命周期: 類變量生命周期最長,随着類的消失而消失
執行個體變量的生命周期随着對象的消失而消失
靜态的使用注意事項:
1.靜态方法隻能通路靜态成員 非靜态方法既可以通路靜态也可以通路非靜态
2.靜态方法中不可以定義this,super關鍵字。因為靜态優先于對象存在,是以靜态方法中不可以出現this。
3.主函數是靜态的
靜态有利有弊
利處:對對象的共享資料進行單獨空間的存儲,節省空間。沒有必要每個對象中都存儲一份。
可以直接被類名調用
弊端:生命周期過長。
通路出現局限性。(靜态雖好,隻能通路靜态)
主函數:是一個特殊的函數,作為程式的入口可以被jvm調用。
主函數的定義:
public :代表着該函數的通路權限是最大的。
static:代表着主函數随着類的加載就已經存在了。
void:主函數沒有具體的傳回值。
main:不是關鍵字。但是是一個特殊的單詞,可以被jvm識别。
函數的參數(String[ ] args):函數的參數,參數類型是一個數組,該數組中的元素是字元串,字元串的類型是數組。
主函數是固定格式的:jvm識别。Jvm在調用主函數時,傳入的是new String[0];
什麼時候使用靜态:
要從兩方面下手:因為靜态修飾的内用有成員變量和成員函數。
class Day6_1
{
public static void main(String[] args)
{
System.out.println(Person.country);
//Person p = new Person(20);
//p.test();
Person.show();//可以直接調用靜态方法
}
}
class Person
{
int age;
static String country = "CN";
Person(int age)
{
this.age = age;
System.out.println(age+" .. "+country);
}
public static void show()
{
//test(); 錯誤是因為靜态中調用非靜态的方法 導緻找不到test方法
System.out.println("show()中的:"+country);
}
public void test()
{
System.out.println("it just a test");
}
}
什麼時候定義靜态變量(類變量)呢?
當對象中出現共享資料時,該資料被靜态所修飾。
對象中的特有資料要定義成非靜态,存在于堆記憶體中。
什麼時候定有靜态函數呢?
當功能内部沒有通路到非靜态資料(對象的特有資料),那麼該功能可以定義成靜态的。
靜态的應用:
每一個應用程式中都有共性的功能,可以将這些功能進行抽取,獨立封裝。
以便複用。
靜态代碼塊
格式:
static
{
靜态代碼塊中執行的語句。
}
特點:随着類的執行而執行,隻執行一次。用于給類進行初始化。并優先于主函數
(構造代碼塊
格式
{
System.out.println(“a”);
}
靜态代碼塊
static
{
System.out.println(“v”);
}
)
//靜态代碼塊
class Day6_3
{
public static void main(String[] args)
{
new StaticDemo(10);
}
}
class StaticDemo
{
int a = 10;
{
System.out.println("b"+ this.a);//構造代碼塊
}
StaticDemo()
{
System.out.println("c");//空param的構造函數
}
static
{
System.out.println("a" );//靜态代碼塊,最先執行
}
StaticDemo(int a)
{
System.out.println("d");//帶參數的構造函數
}
}
非靜态前面省略this.(this.method();) 靜态前面省略類名.(Person.method();)
設計模式:解決某一類為題最行之有效的方法。
java中23種設計模式:
單例設計模式:解決一個類在類存隻存在一個對象。
想要保證對象唯一。
1.為了避免其他程式過多建立該類對象。先禁止其他程式建立該類對象
2.還為了讓其他程式可以通路到該類對象,隻好在本類中,自定義一個對象。
3.為了友善其他程式對自定義對象的通路,可以對外提供一些通路方式。
//單例模式 設計方式
class Day6_4
{
public static void main(String[] args)
{
System.out.println("Hello World!");
Student a = Student.getInstance();
a.setAge(20);
Student b = Student.getInstance();
System.out.println(b.getAge());//20個對象公用一個函數
}
}
class Student
{
private int age;
public void setAge(int age)
{
this.age = age;
}
public int getAge()
{
return age;
}
private Student(){}//單例模式的3步
private static Student s = new Student();//
public static Student getInstance()//
{
return s;
}
}
class Car
{
private Car(){}
private static Car c = new Car();
public static Car getInstance()
{
return c;
}
}
class Man//餓漢式
{
private Man(){}
private Man m = new Man();
public static Man getInstance()
{
return m;
}
}
class Woman//懶漢式 單例模式的延遲加載
{
private Woman(){}
private Woman w = null;
public static Woman getInstance()
{
if(w == null)
w = new Woman();
return w;
}
}
這三步怎麼用代碼展現呢?
1.講構造函數私有化
2.在類中建立一個本類對象
3.提供一個方法可以擷取到該對象
繼承:
1.提高了代碼的複用性
2.繼承讓類與類之間産生了關系,有了這個關系,才有了多态的特性。
注意:千萬不要為了擷取其他類的功能,簡化代碼而繼承。
必須是類于類之間有所屬關系才可以繼承。所屬關系 is a。
java語言中:java隻支援單繼承,不支援多繼承。因為多繼承容易帶來安全隐患
當多個父類中定義了相同功能,但功能内容不同時,子類對象不确定運作哪一個
但是java保留了這種機制。并用另一種展現形式來完成表示。多實作。
java支援多層繼承。也就是一個繼承體系
如何使用一個繼承體系中的功能呢?
想要使用體系,先查閱體系父類的描述,因為父類中定義的是該體系中的共性功能。
通過了解共性功能,就可以知道該體系的基本功能。
那麼這個體系已經可以基本使用了
那麼在具體調用是,要建立最子對象,為什麼呢?
一是因為有可能父類不能建立對象,二是建立子類對象可以使用更多功能,包括基本的也包括特有的
簡單一句話:查閱父類功能,建立子類對象使用功能
另外一種關系
聚集:has a
聚合:
組合
子父類中的函數
當子類出現和父類一模一樣的函數時,當子類對象調用該函數,會運作子類函數的内容,如同父類的函數被覆寫一樣,這種情況是函數的另一個特征:重寫(覆寫)
當子類繼承父類,沿襲了父類的功能到子類中,但是子類雖有該功能,但是功能的内容卻和父類不一緻,這時,沒有必要定義新功能,而是使用覆寫特性,保留父類的功能定義,重寫父類内容。
覆寫:1.子類覆寫父類,必須保證子類權限大于等于父類權限,才可以覆寫,否則,編譯失敗。(public>空白>private)
2.靜态隻能覆寫靜态
重載:隻看同名函數的參數清單。
重寫:子夫類方法要一模一樣。
子父類中的構造函數
在對子類對象進行初始化時,父類的構造函數也會運作,那是因為子類的構造函數預設第一行有一條隐的語句 super();
super():會通路父類中控參數的構造函數,而且子類中所有構造函數的預設第一行都是super();
為什麼子類一定要通路父類中的構造函數?
因為父類中的資料子類可以直接擷取,是以子類對象在建立時,需要先需要先檢視父類是如何對這些資料進行初始化的。是以子類對象初始化時,要先通路一下父類中的構造函數,如果要通路父類中指定的構造函數,可以通過手動定義速super語句的方式來指定。
注意:super語句一定放在子類構造函數的第一行。
//構造函數的繼承
class Day7_2
{
public static void main(String[] args)
{
Student s = new Student();
new Student (20);
}
}
class Person
{
Person(int a)
{
System.out.println("zou jibu "+a);
}
}
class Student extends Person
{
Student()
{
//super(); 自動調用父類中空參數的構造函數
super(10);
System.out.println("我是學生啊 ");
}
Student(int a)
{
this();
System.out.println("ccacacacaca"+a);
}
}
子類的的執行個體化過程:
結論:
子類的所有構造函數,預設都會通路父類中空參數的構造函數,因為子類每一個構造函數内的第一行都有一句隐式super();
當父類中沒有空參數的構造函數時,子類必須手動通過super語句形式來通路父類 中的構造函數,當然:子類的構造函數第一行也可以手動指定this語句來通路本類中的構造函數,子類中至少會有一個構造函數會通路父類中的構造函數。