《靜態、單例、繼承》
1. 靜態變量
1.1成員變量和內存示例
成員變量,因爲都在成員中,是對象的成員。
成員變量,隨對象創建在堆中,多份(每生成一個成員就生成一份)。
1.2靜態變量和內存示例
靜態變量在變量的類型前,用關鍵字static聲明。
靜態變量是類的變量,隨類的生成而生成在方法區的靜態區中,一個類生成一個,與對象的多少無關。
1.3成員變和靜態變量的區別(局部變量和成員變量的區別)
靜態變量和成員變量的區別?
區別一:生命週期不同。
靜態變量隨着類的加載而加載,隨着類的消失而消失。
成員變量隨着對象的創建而創建,隨着對象的消失而消失。
區別二:存儲空間不同。
靜態變量存儲在靜態區。
成員變量存儲在對象所在的堆內存。
區別三:創建個數不同。
靜態變量只有一份,被所有該類的對象共享。一改全改。
成員變量有很多分,每個對象都獨享自己的成員變量。改動相互不影響。
區別四:所屬元素不同。
靜態變量屬於定義它的類,又叫類變量。
成員變量屬於它所在的對象,又叫實例變量。
區別五:訪問方式不同。
靜態變量有兩種訪問形式 classname.xxx(Student.country)和objectname.xxx(stu.country)
成員變量有一種訪問形式 objectname.xxx(stu.name)。。。。objectname(對象)
成員變量和局部變量的區別?
區別一:定義位置不同。
成員變量定義在類中和對象相關。
局部變量定義在方法中以及語句裏,和方法相關。
區別二:存儲位置不同。
成員變量存儲在堆內存的對象中。
局部變量存儲在棧內存的方法中。
區別三:存生命週期不同。
成員變量隨着對象的創建而創建,隨着對象的消失而消失。
局部變量隨着的方法的進棧而創建,隨着方法的彈棧而消失。
區別四:作用範圍不同。
成員變量因爲定義在類中,所以在類的{}內都有效。
局部變量因爲定義在方法或代碼塊中,所以只在方法或代碼塊的{}內有效。
區別五:初始化不同。
成員變量因爲在堆內存中,所以有默認初始化值。
局部變量因爲在棧內存中,所以沒有默認初始值,必須初始化後纔可以使用。
2. 靜態方法
2.1成員方法和靜態方法
靜態方法只能訪問靜態方法和靜態變量,不能訪問成員方法和成員變量,因爲這個時候成員方法還沒有生成呢
成員方法既能訪問靜態變量和靜態方法,又能訪問成員方法和成員變量
因爲:
靜態方法,隨着類的加載而加載,隨着類的消失而消失。
靜態方法加載進內存的時候堆中的對象可能還不存在,
因此不能訪問和對象相關的成員變量和成員方法。
成員方法是和對象相關的,對象的創建要比靜態方法晚,
成員方法訪問已經存在的靜態方法是沒有問題的。
2.2靜態方法main方法
public static void main(String[] args)
public:訪問修飾符,爲了jvm到處都能找到入口,所有給main最大的權限
static:jvm啓動的時候還沒有對象,那它咋執行代碼捏?只好將方法聲明爲static,
爲了不用對象通過類名來調用。
void:無返回值。異常處理(暫時沒學)可以幫我們解決程序執行正確與否的問題,不需要返回值來判斷。
main:歷史傳統都叫main
String[]:字符串數組,要求調用main方法時候輸入信息。以前爲了用鍵盤輸入信息而設計,現在不用。
args:arguments的簡寫。
2.3靜態方法應用—數組工具類
工具類,靜態方法可以製作工具類,不需要工具類對象而直接使用工具類的功能。
例子:
class ArraysTool {
//遍歷數組
public static void printArray(int [] arr){
for (int i=0;i<arr.length ;i++ ){
System.out.println(arr[i]);
}
}
//得到最大值
public static int getMax(int [] arr){
int max=arr[0];
for (int i=1;i<arr.length ;i++ ){
if (arr[i]>max){
max=arr[i];
}
}
return max;
}
//得到最小值
public static int getMin(int [] arr){
int min=arr[0];
for (int i=1;i<arr.length ;i++ ){
if (arr[i]<min){
min=arr[i];
}
}
return min;
}
}
3. 靜態代碼塊
3.1靜態代碼塊
靜態代碼塊,和類相關,類加載的時候執行一次,工具類使用時需要條件,怎麼滿足呢?在靜態代碼塊中處理。
作用
1.加載類的時候處理一些條件。
2.給靜態變量初始化值。
靜態代碼塊在類加載的時候執行一次,多用於給類初始化。
1.靜態代碼塊,就是在類中用static關鍵字修飾的代碼塊!
2.它在類加載的時候,只執行一次,並不是每次構建對象都執行的。
3.它可以用於給初始靜態變量,和做一些類加載時期的準備工作
4.類加載->靜態變量初始化->靜態代碼塊->構造方法
5.靜態代碼塊和靜態變量,靜態方法一樣是和類相關的,不能直接訪問成員變量和成員方法,
爲此時可能對象還不存在。
例子:
static{
country="中國";
System.out.println("static block is run");
}
3.2構造代碼塊
構造代碼塊,和對象相關,每次創建對象都要執行。
作用
1.創建對象的時候可以處理一些條件
2.給成員變量初始化值
構造代碼塊
構造代碼塊隨着對象的創建而執行,多用於給對象初始化。
1.構造代碼塊就是類中的一段獨立的代碼執行體,在每次構造對象的時候都會被執行。
2.它可以用於給成員變量初始,和執行一些創建對象前的準備工作。
3.它的地位和成員變量、成員方法類似,屬於對象相關的東西。
4.成員變量初始-->構造代碼塊->構造方法
例子:
{
name="張三丰";
System.out.println("construct block is run");
}
3.3局部代碼塊
局部代碼塊,和方法相關
作用:
1.組織方法中一個功能
2.控制局部變量的作用範圍,生命週期
例子:
{
int i=1;
while(i<=10){
System.out.println(i);
i++;
}
}
4. 對象的創建過程
(如果有父類就先處理父類)類加載-->靜態變量初始化-->靜態代碼塊-->靜態方法-->成員變量的初始化-->構造代碼塊-->構造方法
對象的創建順序。
1.Person.class文件被加載進內存(如果有父類,將其父類的.class文件加載進內存)
2.靜態變量默認初始化
3.靜態變量顯示初始化
4.靜態代碼塊執行
5.成員變量默認初始化
6.成員變量顯示初始化
7.構造代碼塊執行
8.構造方法初始化。
9.對象創建完畢。
注意:
靜態元素是和類相關的,只有在第一次使用該類的時候執行一次,並且只執行一次。
成員元素是和對象相關的,在每次創建對象的時候都要執行一次,可能執行很多次。
構造方法和構造代碼塊
1.構造方法是初始化特定對象的特定方式(new Person("張三",18))
2.構造代碼塊是初始化所有對象的共同方式(new Person("張三",18) new Person())
3.特定的初始化方式寫到構造方法中,共同的初始化方式寫到構造代碼塊中。
5. 單例模式
5.1單例模式的引入
設計模式:
模式:練武套路。少林拳,鐵砂掌。太極拳。
建築學:窗口朝南,通風,寬敞明亮。豪華裝修
軟件工程學,也有一些解決問題的特定套路。設計的時候就應該考慮。
設計模式:23種經典設計模式,不侷限與23種。
單例設計模式:要求一個只可以創建一個對象的類
5.2單例模式的代碼體現(餓漢式)
//餓漢式(開發)。不會有多線程問題。
class Student{
private static Student stu=new Student();//類加載的時候初始化一次,創建一個對象
private Student(){
//外面不能new對象
}
public static Student getInstance(){
//可以得到這個唯一的對象
return stu;
}
}
5.3單例模式的代碼體現(懶漢式)
思想:
問題:如果類外面能new Student()那將無法控制對象的個數。咋辦?
答案:將學生類的構造方法私有化。
問題:一個對象都無法在類外面創建了。咋辦?
答案:在類內new 對象。對象有叫實例 instance
問題:類和對象對無法訪問 getInstance(),咋辦?
答案:將getInstance()聲明爲static
問題:我多次調用getInstance()方法依然可以創建多個對象。咋辦?
答案:將學生對象搞成靜態。
問題:搞成靜態依然沒控制住。原因,對象不爲空你依然new對象造成的。
答案:判定一下,對象爲空就new對象,不爲空就不new對象。
問題:數據對外暴露不安全,
答案:對數據private
單線程有效,多線程無效。
懶漢式(面試)
class Student{
private static /*final*/ Student stu;
private Student(){
}
public static Student getInstance(){
// 此時線程1要new沒new被叫停 線程2殺過來,創建一個對象,線程1醒來以後直接創建對象,導致對象不唯一。
if (stu==null){
stu=new Student();;
}
return stu;
}
}
6. 繼承
6.1繼承概述
一、繼承定義:
繼承就是子類從父類當中繼承下來成員變量和成員方法。
如果有重名的成員變量和成員方法,將保留兩份,
使用時,按先己後父原則查找。
二、什麼時候能繼承?
1.子類是父類的一種特殊類型的時候可以繼承。
比如:蘋果是一種水果 ,梨子是一種水果,蘋果和梨子都可以繼承水果。
學生是一種人,司機是一種人,學生和司機都可以繼承人。
2.apple is a kind of fruit. 子類和父類存在is a關係。
父類更加通用,子類更加具體。 子類和父類是一種更加具體的關係。
3.父類中存放,從多個子類中抽取出來的共同的屬性和方法,子類中可以存儲,
和子類自己相關的特有的屬性和方法。並不是所有的動物都和狗一樣能看家。
子類和父類,子類是一種個性的體現,父類是一種共性的體現。
三、Java中的繼承體系(單繼承)
1.一個父類可以有多個直接子類。Animal有Cat和Dog兩個子類。
2.一個子類有且只有一個直接父類。
3.所有類的父類是Object類。
4.單根(一個object根類)、多層(注意不要循環繼承)、一顆樹
四、Java爲啥不能多繼承(爲啥不能有多個父類)
會出現菱形問題,不知道用哪個方法。
6.2繼承中子父類的同名變量
/*
繼承中的特殊
*/
class Fu{
int i=2;
}
class Zi extends Fu{
int i=3;
public void show(){
System.out.println(i);
}
}
class BianliangDemo
{
public static void main(String[] args)
{
//Zi zi=new Zi();
//zi.show();
Zi zi=new Zi();
zi.i=5;
zi.show();
}
}
6.3子父類中同名方法
先己後父,皆無報錯!