主頁 > 後端開發 > Java面向物件(知識點整理)

Java面向物件(知識點整理)

2021-02-23 12:17:57 後端開發

文章目錄

    • 面向物件
      • 類與物件
      • 匿名物件
      • 創建物件的記憶體分析
        • 堆疊(stack)
        • 堆(heap)
        • 方法區
        • PC暫存器
        • 本地方法堆疊
      • 內部類
        • 成員內部類
        • 區域內部類
        • 匿名內部類
        • 靜態內部類
      • 包裝類
        • 拆箱和裝箱操作
        • 字串轉換
        • 基本資料型別和包裝型別的區別
        • Integer型別的重點
      • 抽象類
        • 抽象方法
        • 不能被實體化
        • 常見問題
        • 抽象類和普通類的區別
      • 介面
        • 面向介面編程思想
        • 全域常量和抽象方法的簡寫
        • 介面的實作 implements
        • 介面的繼承 extends
        • 介面與抽象類的區別
      • 多型
        • 多型的體現
        • 多型的使用:物件的型別轉換
      • Instanceof
      • Object類
        • Object的多型
        • toString()
        • equals()
      • 可變引數
      • 遞回
      • 例外處理
        • try+catch的處理流程
        • finally
        • 例外體系結構
        • throws關鍵字
        • throw關鍵字
        • RuntimeExcepion與Exception的區別
        • 自定義例外類
        • try-with-resources
      • 構造方法(構造器)
      • 多載(Overload)
      • 重寫(Override)
      • 重寫與多載的區別
      • Java兩種核心機制
      • JAVA跨平臺原理
      • 識別符號
      • 關鍵字
        • this
        • static
        • final
      • 權限修飾符
        • 封裝private
      • 代碼塊

面向物件

要理解面向物件思想,我們先要知道什么是物件?

《Java編程思想》中提到“萬物皆為物件”的概念,它將物件視為一種奇特的變數,它除了可以存盤資料之外還可以對它自身進行操作,它能夠直接反映現實生活中的事物,例如人、車、小鳥等,將其表示為程式中的物件,每個物件都具有各自的狀態特征(也可以稱為屬性)及行為特征(方法),java就是通過物件之間行為的互動來解決問題的,

面向物件就是把構成問題的事物分解成一個個物件,建立物件不是為了實作一個步驟,而是為了描述某個事物在解決問題中的行為,

類是面向物件中的一個很重要的概念,因為類是很多個具有相同屬性和行為特征的物件所抽象出來的,物件是類的一個實體,

類具有三個特性:封裝、繼承和多型,

三大特征

  • 封裝:核心思想就是“隱藏細節”、“資料安全”,將物件不需要讓外界訪問的成員變數和方法私有化,只提供符合開發者意愿的公有方法來訪問這些資料和邏輯,保證了資料的安全和程式的穩定,所有的內容對外部不可見,
  • 繼承:子類可以繼承父類的屬性和方法,并對其進行拓展,將其他的功能繼承下來繼續發展 ,
  • 多型:同一種型別的物件執行同一個方法時可以表現出不同的行為特征,通過繼承的上下轉型、介面的回呼以及方法的重寫和多載可以實作多型,方法的多載本身就是一個多型性的體現,

三大思想

面向物件思想從概念上講分為以下三種:OOA、OOD、OOP

OOA:面向物件分析(Object Oriented Analysis)

OOD:面向物件設計(Object Oriented Design)

OOP:面向物件程式(Object Oriented Programming )

類與物件

類表示一個共性的產物,是一個綜合的特征,而物件,是一個個性的產物,是一個個體的特征, (類似生活中的圖紙與實物的概念,)

類必須通過物件才可以使用,物件的所有操作都在類中定義,

類由屬性和方法組成:

  • 屬性:就相當于人的一個個的特征

  • 方法:就相當于人的一個個的行為,例如:說話、吃飯、唱歌、睡覺

一個類要想真正的進行操作,則必須依靠物件,物件的定義格式如下:

類名稱 物件名稱 = new 類名稱() ;

如果要想訪問類中的屬性或方法(方法的定義),則可以依靠以下的語法形式:

訪問類中的屬性: 物件.屬性 ;

呼叫類中的方法: 物件.方法(實際引數串列) ;

  • 類必須撰寫在.java檔案中;
  • 一個.java檔案中,可以存在N個類,但是只能存在一個public修飾的類;
  • .java檔案的檔案名必須與public修飾的類名完全一直;
  • 同一個包中不能有重名的類;

匿名物件

  • 沒有物件名稱的物件就是匿名物件, 即堆疊記憶體中沒有名字,而堆記憶體中有物件,
  • 匿名物件只能使用一次,因為沒有任何的物件參考,所以將稱為垃圾,等待被GC回收,
  • 只使用一次的物件可以通過匿名物件的方式完成,這一點在以后的開發中將經常使用到,
public static void main(String[] args){
	//Math2 m=new Math2();
	//int num=m.sum(100,200);
	//不通過創建物件名,直接實體物件呼叫,這就是匿名物件,因為沒有物件名指向物件,所以只能呼叫一次,然后被GC回收,
	int num = new Math().sum(100,200);
	System.out.println(num);
}
class Math2{
	int sum(int x,int y){
		return x+y;
	}
}

物件記憶體分析如下圖所示:
在這里插入圖片描述

創建物件的記憶體分析

堆疊(stack)

Java堆疊的區域很小 , 大概2m左右 , 特點是存取的速度特別快

堆疊存盤的特點是:先進后出

存盤速度快的原因:

堆疊記憶體, 通過 ‘堆疊指標’ 來創建空間與釋放空間 !

指標向下移動, 會創建新的記憶體, 向上移動, 會釋放這些記憶體 !

這種方式速度特別快 , 僅次于PC暫存器 !

但是這種移動的方式, 必須要明確移動的大小與范圍 ,

明確大小與范圍是為了方便指標的移動 , 這是一個對于資料存盤的限制, 存盤的資料大小是固定的 , 影響了程式 的靈活性 ~

所以我們把更大部分的資料存盤到了堆記憶體中

堆存盤的是:

基本資料型別的資料以及參考資料型別的參考!

例如:

int a =10; 
Person p = new Person(); 

10存盤在堆疊記憶體中 , 第二句代碼創建的物件的參考§存在堆疊記憶體中

堆(heap)

存放的是類的物件 ;

Java是一個純面向物件語言, 限制了物件的創建方式 :

所有類的物件都是通過new關鍵字創建

new關鍵字, 是指告訴JVM , 需要明確的去創建一個新的物件 , 去開辟一塊新的堆記憶體空間:

堆記憶體與堆疊記憶體不同, 優點在于我們創建物件時 , 不必關注堆記憶體中需要開辟多少存盤空間 , 也不需要關注記憶體占用

時長 !

堆記憶體中記憶體的釋放是由GC(垃圾回收器)完成的

垃圾回收器回收堆記憶體的規則 :

當堆疊記憶體中不存在此物件的參考時,則視其為垃圾 , 等待垃圾回收器回收 !

例如:

Person p0 = new Person(); 
Person p1 = p0; 
Person p2 = new Person(); 

堆在邏輯上分為三部分:

新生代(Young Generation,常稱為YoungGen)

老年代(Old Generation,常稱為OldGen、TenuringGen)

永久代(Permanent Generation,常稱為PermGen)

新生區(New/Young Generation):

新生代(Young Generation),常稱為YoungGen,位于堆空間,

新生區又分為Eden區和Survior(幸存區),

Eden:新創建的物件

Survior 0、1:經過垃圾回收,但是垃圾回收次數小于15次的物件,

養老區(Old Generation):

老年代常稱為OldGen,位于堆空間

Old:垃圾回收次數超過15次,依然存活的物件,

永久區(Permanent Generation):

永久代常稱為PermGen,位于非堆空間,

永久區是一個常駐記憶體區域,用于存放JDK自身所攜帶的Class,Interface的元資料,也就是說它存盤的是運行環境必須的類資訊,被裝載進此區域的資料是不會被垃圾回收器回收掉的,關閉JVM才會釋放此區域所占用的空間,

public static void main(String[] args){
    String s1 = "123456";
    String s2 = "123456";
    System.out.println(s1==s2)//結果:true-----------第一次定義s1存放在堆中的永久區,所以第二次屬于呼叫
}

方法區

方法區(Method Area),又稱永久代,又稱非堆區(Non-Heap space)

方法區是被所有執行緒共享:

  1. 所有的欄位和方法位元組碼,以及一些特殊方法如建構式,介面代碼也再此定義,
  2. 簡單說,所有定義的方法的資訊都保存在該區域,此區屬于共享區間,
  3. 這些區域儲存的是:靜態變數+常量+類資訊(構造方法/介面定義)+運行時常量池,
  4. 但是,實體變數存在堆記憶體中,和方法區無關,

以上,只是邏輯上的定義,在HotSpot中,方法區僅僅只是邏輯上的獨立,實際上還是包含在java堆中,也就是說,方法區在物理上屬于java堆區中的一部分,而永久區(Permanent Generation)就是方法區的實作,

存放的是

- 類資訊

- 靜態的變數

- 常量

- 成員方法

方法區中包含了一個特殊的區域 ( 常量池 )(存盤的是使用static修飾的成員)

方法區的實作的演變

jdk1.7之前:hotspot虛擬機對方法區的實作為永久代,

jdk1.8及之后:hotspot移除了永久代用元空間(Metaspace),

運行時 常量池字串常量池的變化

jdk1.7之前:運行時常量池(包含字串常量池)存放在方法區,此時hotspot虛擬機對方法區的實作為永久代,

jdk1.7:字串常量池被方法區拿到了堆中;運行時常量池剩下的東西還在方法區,也就是hotspot中的永久代,

jdk1.8:hotspot移除了永久代,用元空間(Metaspace)取而代之,這時候,字串常量池還在堆中,運行時常量池還在方法區,只不過方法區的實作從永久代變成元空間(Metaspace),

代碼使用記憶體情況如下圖所示:

在這里插入圖片描述

上圖描述了程式運行時記憶體的情況,當程式運行完畢,堆疊內的會清空b2、b1,這樣堆記憶體中的Book物件就沒有一個參考指向他,即堆疊記憶體中沒有指向他的,則滿足了GC的清理原則,GC會自動清理掉堆記憶體中的Book物件,

在這里插入圖片描述

上圖描述了兩個物件b1、b2的在堆疊和堆中記憶體的使用情況,當b2=b1時,b1指向的地址就覆寫了b2的指向地址,這樣原來b2物件在堆中的記憶體就沒東西指向他的地址了,這就滿足了GC的自動清理原則,

public static void main(String[] args){
    String s1 = "鋤禾日當午";
    String s2 = "汗滴禾下土";
    String s3 = "窗前明月光";
    text1 = text1+text2+text3;//先計算text1+text2,產生地址為0x126的物件,接著再計算0x126物件+text3,產生0x127物件
    System.out.println(text1);//輸出:鋤禾日當午汗滴禾下土窗前明月光
}

在這里插入圖片描述

上圖描述了三個字串拼接成一個新的字串的記憶體使用情況,可以看到堆疊中text1指向的地址被改變,但是堆中產生兩個沒有指向的物件垃圾,這是非常耗費記憶體的,所以平常應該避免字串拼接,

PC暫存器

PC暫存器保存的是當前正在執行的 JVM指令的 地址 ;

在Java程式中, 每個執行緒啟動時, 都會創建一個PC暫存器 ;

本地方法堆疊

保存本地(native)方法的地址

內部類

在Java中,可以將一個類定義在另一個類里面或者一個方法里面,這樣的類稱為內部類,

廣泛意義上的內部類一般來說包括這四種:

1、成員內部類

2、區域內部類

3、匿名內部類

4、靜態內部類

成員內部類

成員內部類是最普通的內部類,它的定義為位于另一個類的內部,形如下面的形式:

public class Demo{
    public static void main(String[] args){
        //外部使用成員內部類 
		Outer outter = new Outer(100); 
		Outer.Inner inner = outter.new Inner();
        inner.say();       //輸出:200    
        				   //     100
    }
}
class Outer { 
    private double x = 0; 
    public Outer(double x) { 
        this.x = x; 
    }
    class Inner { 
        private double x=200;
        //內部類 
        public void say() { 
            System.out.println(x); 
            System.out.println(Outer.this.x);
        }
    }
}

特點: 成員內部類可以無條件訪問外部類的所有成員屬性和成員方法(包括private成員和靜態成員), 不過要注意的是,當成員內部類擁有和外部類同名的成員變數或者方法時,會發生隱藏現象,即默認情況下訪問的是成員內部類的成員,

如果要訪問外部類的同名成員,需要以下面的形式進行訪問:

外部類.this.成員變數

外部類.this.成員方法

區域內部類

區域內部類是定義在一個方法或者一個作用域里面的類,它和成員內部類的區別在于區域內部類的訪問僅限于方法內或者該作用域內,

例如:

interface Person{ 
    public void say();
}
public class Demo{
    public static void main(String[] args){
        //區域內部類
        class PersonImp implements Person{
            @Override
            public void say(){
                System.out.prinln("新撰寫的區域內部類的say方法內容");
            }
        }
        PersonImp p=new PersonImp();
        //這里像呼叫haha()方法,但是需要一個Person類,為此專門創建一個class檔案類很浪費時間,所以使用區域內部類
        haha(p);
    }
    public static void haha(Person p){ }
}

//視窗關閉
public static void main(String[] args){
    Frame f=new Frame("QQ登陸器");
    f.setVisible(true);
    f.setSize(300,200);
    class MyWindowListener implements WindowListener{
        @Override
        public void windowClosing(WindowEvent e){
            System.out.println("哈哈哈");
        }
    }
    MyWindowListener l=new MyWindowListener();
    //想要添加一個視窗關閉的事件,可以使用區域類
    f.addWindowListener(l);
}

注意:區域內部類就像是方法里面的一個區域變數一樣,是不能有public、protected、private以及static修飾符的,區域內部類也是只能訪問final型別變數,

匿名內部類

匿名內部類由于沒有名字,所以它的創建方式有點兒奇怪,匿名內部類創建出來只能使用一次,和匿名物件類似,創建格式如下:

new 父類構造器(引數串列)|實作介面() {
    //匿名內部類的類體部分 
}

interface Person{ 
    public void say();
}
public class Demo{
    public static void main(String[] args){
        //匿名內部類
        Person p=new Person(){
            public void say(){
                System.out.println("鋤禾日當午");
            }
        }
        haha(p);
    }
    public static void haha(Person p){ }
}

在這里我們看到使用匿名內部類我們必須要繼承一個父類或者實作一個介面,當然也僅能只繼承一個父類或者實作一個介面,同時它也是沒有class關鍵字,這是因為匿名內部類是直接使用new來生成一個物件的參考,當然這個參考是隱式的,

在使用匿名內部類的程序中,我們需要注意如下幾點:

1、使用匿名內部類時,我們必須是繼承一個類或者實作一個介面,但是兩者不可兼得,同時也只能繼承一個類或 者實作一個介面,

2、匿名內部類中是不能定義建構式的,

3、匿名內部類中不能存在任何的靜態成員變數和靜態方法,

4、匿名內部類為區域內部類,所以區域內部類的所有限制同樣對匿名內部類生效,

5、匿名內部類不能是抽象的,它必須要實作繼承的類或者實作的介面的所有抽象方法,

6、只能訪問final型的區域變數,JDK1.8之后變數默認為final型別,但是只要第二次賦值,就不再是final型別的了,

只能訪問final型別的區域變數的原因,因為區域類編譯的時候是單獨編譯成一個檔案,所以在檔案中有final變數的備份,

靜態內部類

靜態內部類也是定義在另一個類里面的類,只不過在類的前面多了一個關鍵字static,

靜態內部類是不需要依賴于外部類物件的,這點和類的靜態成員屬性有點類似,并且它不能使用外部類的非static成員變數或者方法,

格式:

public class Demo { 
    public static void main(String[] args) { 
        Book.Info info = new Book.Info(); 
        info.say();
    }
}
class Book { 
    static class Info { 
        public void say(){
            System.out.println("這是一本書");
        }
    } 
}

包裝類

在Java中有一個設計的原則“一切皆物件”,那么這樣一來Java中的一些基本的資料型別,就完全不符合于這種設計思想,因為Java中的八種基本資料型別并不是參考資料型別,所以Java中為了解決這樣的問題,引入了八種基本資料型別的包裝類,

在這里插入圖片描述

以上的八種包裝類,可以將基本資料型別按照類的形式進行操作,

但是,以上的八種包裝類也是分為兩種大的型別的:

  • Number:Integer、Short、Long、Double、Float、Byte都是Number的子類表示是一個數字,
  • Object:Character、Boolean都是Object的直接子類,

在這里插入圖片描述

拆箱和裝箱操作

以下以Integer和Float為例進行操作

將一個基本資料型別變為包裝類,那么這樣的操作稱為裝箱操作,

將一個包裝類變為一個基本資料型別,這樣的操作稱為拆箱操作,

因為所有的數值型的包裝類都是Number的子類,Number的類中定義了如下的操作方法,以下的全部方法都是進行拆箱的操

作,

在這里插入圖片描述

裝箱操作:

在JDK1.4之前 ,如果要想裝箱,直接使用各個包裝類的構造方法即可,例如:

int temp = 10 ; 				// 基本資料型別 
Integer x = new Integer(temp) ; // 將基本資料型別變為包裝類

在JDK1.5,Java新增了自動裝箱和自動拆箱,而且可以直接通過包裝類進行四則運算和自增自建操作,例如: 

Float f = 10.3f ; 			// 自動裝箱 
float x = f ; 				// 自動拆箱 
System.out.println(f * f) ; // 直接利用包裝類完成 
System.out.println(x * x) ; // 直接利用包裝類完成

字串轉換

使用包裝類還有一個很優秀的地方在于:可以將一個字串變為指定的基本資料型別,此點一般在接收輸入資料上使用較多,

在Integer類中提供了以下的操作方法:

public static int parseInt(String s);//將String變為int型資料

在Float類中提供了以下的操作方法:

public static float parseFloat(String s);//將String變為Float

在Boolean 類中提供了以下操作方法:

public static boolean parseBoolean(String s);//將String變為boolean

基本資料型別和包裝型別的區別

1、包裝類是物件,擁有方法和欄位,物件的呼叫都是通過參考物件的地址,基本型別不是
2、包裝型別是參考的傳遞,基本型別是值的傳遞
3、宣告方式不同,基本資料型別不需要new關鍵字,而包裝型別需要new在堆記憶體中進行new來分配記憶體空間
4、存盤位置不同,基本資料型別直接將值保存在值堆疊中,而包裝型別是把物件放在堆中,然后通過物件的參考來呼叫他們
5、初始值不同,eg: int的初始值為 0 、 boolean的初始值為false 而包裝型別的初始值為null
6、使用方式不同,基本資料型別直接賦值使用就好 ,而包裝型別是在集合如 coolection Map時會使用

Integer型別的重點

Integer a=1000,b=1000;
System.out.println(a==b);
/**
上述代碼回傳false,因為
IntegerCache.low = -128
IntegerCache.high = 127
    所以上面`Integer a = 1000,b = 1000;`其實都是`new Integer(1000);`所以分配的記憶體地址肯定不一樣,所以`==`比較就成`false`了
    */

抽象類

抽象類必須使用abstract class宣告

一個抽象類中可以沒有抽象方法,抽象方法必須寫在抽象類或者介面中,

格式:

abstract class 類名{ // 抽象類 
} 

抽象方法

只宣告而未實作的方法稱為抽象方法(未實作指的是:沒有“{}”方法體),抽象方法必須使用abstract關鍵字宣告,

格式:

// 抽象類 
abstract class 類名{ 
	public abstract void 方法名() ; // 抽象方法,只宣告而未實作
}

不能被實體化

在抽象類的使用中有幾個原則:

  • 抽象類本身是不能直接進行實體化操作的,即:不能直接使用關鍵字new完成, 不能被我們創建,但是jvm虛擬器可以創建,

  • 一個抽象類必須被子類所繼承,被繼承的子類(如果不是抽象類)則必須覆寫(重寫)抽象類中的全部抽象方法,

常見問題

1、 抽象類能否使用final宣告?

不能,因為final屬修飾的類是不能有子類的 , 而抽象類必須有子類才有意義,所以不能,

2、 抽象類能否有構造方法?

能有構造方法,而且子類物件實體化的時候的流程與普通類的繼承是一樣的,都是要先呼叫父類中的構造方法(默認是無參的),之后再呼叫子類自己的構造方法,

抽象類和普通類的區別

1、抽象類必須用public或protected修飾(如果為private修飾,那么子類則無法繼承,也就無法實作其抽象方法), 默認預設為 public ;

2、抽象類不可以使用new關鍵字創建物件, 但是在子類創建物件時, 抽象父類也會被JVM實體化 ;

3、如果一個子類繼承抽象類,那么必須實作其所有的抽象方法,如果有未實作的抽象方法,那么子類也必須定義為 abstract類 ;

介面

如果一個類中的全部方法都是抽象方法,全部屬性都是全域常量,那么此時就可以將這個類定義成一個介面,

定義格式:

interface 介面名稱{ 
    全域常量 ; 
    抽象方法 ; 
}

面向介面編程思想

這種思想是介面是定義(規范,約束)與實作(名實分離的原則)的分離,

優點:

1、 降低程式的耦合性

2、 易于程式的擴展

3、 有利于程式的維護

全域常量和抽象方法的簡寫

因為介面本身都是由全域常量和抽象方法組成 , 所以介面中的成員定義可以簡寫:

1、全域常量撰寫時, 可以省略public static final 關鍵字,例如:

public static final String INFO = "內容" ; 
//簡寫后: 
String INFO = "內容" ; 

2、抽象方法撰寫時, 可以省略 public abstract 關鍵字, 例如:

public abstract void print() ; 
//簡寫后: 
void print() ; 

介面的實作 implements

介面可以多實作:

格式:

class 子類 implements 父介面1,父介面2...{ } 
//以上的代碼稱為介面的實作,那么如果一個類即要實作介面,又要繼承抽象類的話,則按照以下的格式撰寫即可: 
class 子類 extends 父類 implements 父介面1,父介面2...{ }

注意:如果一個介面要想使用,必須依靠子類, 子類(如果不是抽象類的話)要實作介面中的所有抽象方法,

介面的繼承 extends

繼承是java面向物件編程技術的一塊基石,因為它允許創建分等級層次的類,

繼承就是子類繼承父類的特征和行為,使得子類物件(實體)具有父類的實力域和方法,或子類從父類繼承方法,使得子類具有父類相同的行為,

繼承的限制:Java中只有單繼承,多重繼承,沒有多繼承(即一個子類只能有一個父類),多重繼承通俗來講就是爺爺、爸爸、孫子,

介面因為都是抽象部分, 不存在具體的實作, 所以允許多繼承,例如:

interface C extends A,B{ }

在這里插入圖片描述

student類實體化時先實體化person,默認呼叫的person的無參構造方法

public class Demo{
    public static void main(String[] args){
        Student student = new Student();
        student.say();
    }
}
class Person{
    private String name;
    private int age;
    public Person(){
        supper();//平時supper()可以省略,作用時默認呼叫父類的無參構造方法
    }
    public Person(String name,int age){
        this.name=name;
        this.age=age;
    }
    public void say(){
        System.out.println("姓名:"+name+",年齡:"+age);
    }
}
class Student extends Person{
    Student(){
        supper("張三",1);
    }
}
//結果為:
//姓名:張三,年齡:1

supper

  • 通過supper可以訪問父類的構造方法、屬性、方法,

  • 通過supper呼叫父類構造方法的代碼,必須寫在第一行,

  • supper和this呼叫建構式時都需要放在第一行,但是兩者不會同時使用,因為不可能呼叫自身建構式的同時還呼叫父類的構造方法

介面與抽象類的區別

1、抽象類要被子類繼承,介面要被類實作,

2、介面只能宣告抽象方法,抽象類中可以宣告抽象方法,也可以寫非抽象方法,

3、介面里定義的變數只能是公共的靜態的常量,抽象類中的變數是普通變數,

4、抽象類使用繼承來使用, 無法多繼承, 介面使用實作來使用, 可以多實作

5、抽象類中可以包含static方法 ,但是介面中不允許(靜態方法不能被子類重寫,因此介面中不能宣告靜態方法)

6、介面不能有構造方法,但是抽象類可以有

7、1.8后介面允許出現有方法體的方法

多型

多型:就是物件的多種表現形式,(多種體現形態)

多型的體現

物件的多型性,從概念上非常好理解,在類中有子類和父類之分,子類就是父類的一種形態 ,物件多型性就從此而來,

ps: 方法的多載 和 重寫 也是多型的一種, 不過是方法的多型(相同方法名的多種形態),

多載: 一個類中方法的多型性體現 ,

重寫: 子父類中方法的多型性體現,

多型的使用:物件的型別轉換

類似于基本資料型別的轉換:

  • 向上轉型:將子類實體變為父類實體 |- 格式:父類 父類物件 = 子類實體 ;

  • 向下轉型:將父類實體變為子類實體 |- 格式:子類 子類物件 = (子類)父類實體 ;

public class Demo{
    public static void main(String[] args){
    	Student student1=new Student();
        Nurse nurse1=new Nurse();
        //向上轉型,父類參考指向子類物件
    	Person person1=student1;
    	person1.say();		//輸出:我是學生
        Person person2=nurse1;
        person2.say();		//輸出:我是護士
        //向下轉型
        Student student2=(Student)person1;
        student2.say();		//輸出:我是學生
        //向下轉型需要注意的是不能把原來是護士的張三轉成學生   例如:
        Student student3=(Student)person2;
        student3.say();		//此處會報錯     
        
        //向上轉型比較高級的用法
        Student student4=new Student();
        say(student4);		//輸出:我是學生
    }
    public static void say(Person person){
        person.say();
    }
}
abstract class Person{
    public abstract void say();
}
class Student extends Person{
    @Override
    public void say(){
        System.out.println("我是學生");
    }
}
class Nurse extends Person{
    @Override
    public void say(){
        System.out.println("我是護士")
    }
}

注意:向上轉型的物件,是通過父類呼叫子類覆寫或繼承父類的方法,不是父類的方法,而且此時父類物件不能呼叫子類特有的方法,

Instanceof

作用:

判斷某個物件是否是指定類的實體,則可以使用instanceof關鍵字

格式:

實體化物件 instanceof 類 //此操作回傳boolean型別的資料

Object類

Object類是所有類的父類(基類),如果一個類沒有明確的繼承某一個具體的類,則將默認繼承Object類,

//例如我們定義一個類: 
public class Person{ }
//其實它被使用時 是這樣的: 
public class Person extends Object{ }

Object的多型

使用Object可以接收任意的參考資料型別

public static void main(String[] args){
	String text="123";
    say(text);
    int a=10;
    say(a);
}
public static void say(Object o){
    System.out.println(o)
}

toString()

  • 建議重寫Object中的toString方法, 此方法的作用:回傳物件的字串表示形式 ;

  • Object的toString方法, 回傳物件的記憶體地址 ;

  • System.out.println(物件名)一般輸出時呼叫的時物件的toString方法 ;

equals()

建議重寫Object中的equals(Object obj)方法,此方法的作用:指示某個其他物件是否“等于”此物件,

***Object的 equals方法:***實作了物件上最具區別的可能等價關系; 也就是說,對于任何非空參考值x和y ,當且僅當 x和y參考同一物件

( x == y具有值true )時,此方法回傳true ,

equals方法重寫時的五個特性:

自反性 :對于任何非空的參考值x , x.equals(x)應該回傳true ,

對稱性 :對于任何非空參考值x和y , x.equals(y)應該回傳true當且僅當y.equals(x)回報true ,

傳遞性 :對于任何非空參考值x , y和z ,如果x.equals(y)回報true個y.equals(z)回報true ,然后 x.equals(z)應該回傳true ,

一致性 :對于任何非空參考值x和y ,多次呼叫x.equals(y)始侄訓傳true或始侄訓傳false ,前提是未修改物件上的equals比較中使用的資訊,

非空性 :對于任何非空的參考值x , x.equals(null)應該回傳false ,

class Person{
    private String name;
    private int age;
    public boolean equals(Object o){
        //判斷記憶體地址是否相同
        if(this==o){
            return true;
        }
        //非空性
        if(o==null){
            return false;
        }
        //判斷是否是同一個類
        if(o instanceof Person){
            //向下轉型
            Person p2=(Person)o;
            //此處呼叫的是String里的equals()方法,和Object不同
            if(this.name.equals(p2.name)&&this.age==p2.age){
                return true;
            }
        }
        return false;
    }
}

equals和==的區別

前者是比較兩個數是否等價,后者是比較地址

可變引數

一個方法中定義完了引數,則在呼叫的時候必須傳入與其一一對應的引數,但是在JDK 1.5之后提供了新的功能,可以根據需要自動傳入任意個數的引數,

語法:

回傳值型別 方法名稱(資料型別…引數名稱){
	//引數在方法內部 , 以陣列的形式來接收 
} 

public class Demo{
    public static void main(String[] args){
        System.out.println(sum(1));				//輸出:1
        System.out.println(sum(1,2));			//輸出:3
        System.out.println(sum(1,2,3));			//輸出:6
        System.out.println(sum(1,2,3,4));		//輸出:10
    }
    public static int sum(int... nums){
        int n=0;
        for(int i=0;i<nums.length;i++){
            n+=num[i];
        }
        return n;
    }
}

注意: 可變引數只能出現在引數串列的最后,

遞回

遞回,在數學與計算機科學中,是指在方法的定義中使用方法自身,也就是說,遞回演算法是一種直接或者間接呼叫自身方

法的演算法,

遞回流程圖如下:

在這里插入圖片描述

//5的階乘
public class Demo{
    public static void main(String[] args){
        int n=fact(5);		
        System.out.println(n); //結果:120
    }
    public static int fact(int n){
        if(n==1){
            return 1;
        }else{
            n*fact(n-1);
        }
    }
}

注意:能用回圈完成的作業,盡量不要使用遞回,因為太消耗記憶體,

例外處理

例外是在程式中導致程式中斷運行的一種指令流,

例如,現在有如下的操作代碼:

public class ExceptionDemo01{ 
	public static void main(String argsp[]){ 
		int i = 10 ; 
		int j = 0 ; 
		System.out.println("============= 計算開始 =============") ; 
		int temp = i / j ; // 進行除法運算 
		System.out.println("temp = " + temp) ; 
		System.out.println("============= 計算結束 =============") ; 
	} 
};
//運行結果: 
//============= 計算開始 ============= 
Exception in thread "main" java.lang.ArithmeticException: / by zero at ExceptionDemo01.main(ExceptionDemo01.java:6) 

以上的代碼在“int temp = i / j ;”位置處產生了例外,一旦產生例外之后,例外之后的陳述句將不再執行了,所以現在的程式并沒有正確的執行完畢之后就退出了,

那么,為了保證程式出現例外之后仍然可以正確的執行完畢,所以要采用例外的處理機制,

如果要想對例外進行處理,則必須采用標準的處理格式,處理格式語法如下:

try{
	// 有可能發生例外的代碼段 
}catch(例外型別1 物件名1){ 
	// 例外的處理操作 
}catch(例外型別2 物件名2){
    // 例外的處理操作 
} ... 
finally{ 
    // 例外的統一出口 
}

public class ExceptionDemo01{ 
	public static void main(String argsp[]){ 
		int i = 10 ; 
		int j = 0 ; 
		System.out.println("============= 計算開始 =============") ;
        try{
            int temp = i / j ; // 進行除法運算 
            System.out.println("temp = " + temp) ; 
			System.out.println("============= 計算結束 =============") ; 
        }catch(ArithmeticException e){
            System.out.println("除數不能為零") ; 
        }
	} 
};

try+catch的處理流程

1、 一旦產生例外,則系統會自動產生一個例外類的實體化物件,

2、 那么,此時如果例外發生在try陳述句,則會自動找到匹配的catch陳述句執行,如果沒有在try陳述句中,則會將例外拋出.

3、 所有的catch根據方法的引數匹配例外類的實體化物件,如果匹配成功,則表示由此catch進行處理

在這里插入圖片描述

注意:使用try…catch捕獲例外不是簡單的提示就行了,那樣意義很小,我們應該想辦法解決例外,

finally

在進行例外的處理之后,在例外的處理格式中還有一個finally陳述句,那么此陳述句將作為例外的統一出口,不管是否產生了例外,最終都要執行此段代碼,

注意:finally在一些情況是不會被執行的,比如電腦被關機了(方法強制中斷),

唯一會使finally不執行的代碼:

public class Demo{
    public static void main(String[] args){
        haha();
    }
    public static void haha(){
        try{
            int a = 10;
            int b = 0;
            System.out.println(a/b);
        }catch(Exception e){
            System.out.println("出現了例外");
            //退出JVM
            System.exit(0);
        }finally{
            System.out.println("鋤禾日當午,汗滴禾下土");
        }
    }
}
//結果:出現了例外

finally兩種執行情況:

//案例一
public class Demo1{
    public static void main(String[] args){
        Person p=haha();
        System.out.println(p.age);	//輸出:28
    }
    public static Person haha(){
        Person p=new Person();
        try{
            p.age=18;
            return p;
        }catch(Exception e){
            return null;
        }finally{
            p.age=28;
        }
    }
    static class Person{
        int age;
    }
}
//finally會再return 準備資料回傳的階段執行,所以,無論是否return,finally都是執行,

//案例二
public class Demo2{
    public static void main(String[] args){
        int a = haha();
        System.out.println(a);	//輸出:10
    }
    public static int haha(){
        int a = 10;
        try{
            return a;
        }catch(Exception e){
            return null;
        }finally{
            a = 20;
        }
    }
}
//結果和案例一不一樣,是因為兩者回傳的資料型別不一樣,
//案例一回傳的是參考資料型別,在return的準備資料回傳的階段,備份的是堆記憶體地址,所以堆記憶體里的Person物件的age改變,return備份的值都會改變,
//案例二回傳的是基本資料型別,在return的準備資料回傳階段,備份的是值,即10,所以無論堆疊記憶體中的a如何改變,都不會影響return備份的10,

案例一記憶體使用情況如下圖所示:

在這里插入圖片描述

案例二記憶體使用情況如下圖所示:

在這里插入圖片描述

例外體系結構

例外指的是Exception , Exception類, 在Java中存在一個父類Throwable(可能的拋出)

Throwable存在兩個子類:

  1. Error:表示的是錯誤,是JVM發出的錯誤操作,只能盡量避免,無法用代碼處理,

  2. Exception:一般表示所有程式中的錯誤,所以一般在程式中將進行try…catch的處理,

在這里插入圖片描述

受檢例外代碼會飄紅,不受檢例外不會,

多例外捕獲的注意點:

1、 捕獲更粗的例外不能放在捕獲更細的例外之前,

2、 如果為了方便,則可以將所有的例外都使用Exception進行捕獲,

特殊的多例外捕獲寫法:

catch(例外型別1 |例外型別2 物件名){ 
	//表示此塊用于處理例外型別1 和 例外型別2 的例外資訊 
}
//還有可以直接使用Exception類捕獲例外,這樣所有的例外都能捕獲,缺點是針對性差

throws關鍵字

在程式中例外的基本處理已經掌握了,但是隨例外一起的還有一個稱為throws關鍵字,此關鍵字主要在方法的宣告上使用,表示方法中不處理例外,而交給呼叫處處理,

格式:

回傳值 方法名稱()throws Exception{ 
}

如果是傳參導致的例外,應該通過throws將例外拋出去:

public class Demo{
    public static void main(String[] args){
        shutDown("0");//此處也是受檢例外(飄紅),因為shutDown()方法把例外拋給了呼叫者,所以需要捕獲或者拋出例外,
    }
    public static void shutDown(String text) throws IOException{
    	Runtime.getRuntime().exec(text);//此處為受檢例外(飄紅),需要捕獲或者拋出例外
    }									//通俗點來講,拋出例外就是告訴呼叫者,我這個方法有例外,你需要處理,
}

throw關鍵字

throw關鍵字表示在程式中人為的拋出一個例外,因為從例外處理機制來看,所有的例外一旦產生之后,實際上拋出的就是一個例外類的實體化物件,那么此物件也可以由throw直接拋出,

代碼:

throw new Exception("拋著玩的,") ; 

示例:

public class Demo{
    public static void main(String[] args){
        Person person = new Person();
        person.setAge(-1);
    }
}
class Person{
    private int age;
    public void setAge(int age){
        if(age<0 || age>180){
            RuntimeException e = new RuntimeException("年齡不合理");
            throw e;
        }else{
            this.age = age;
        }
    }
}

上述代碼運行結果如下圖所示:

在這里插入圖片描述

RuntimeExcepion與Exception的區別

注意觀察如下方法的原始碼:

Integer類:

 public static int parseInt(String text)throws NumberFormatException 

此方法拋出了例外, 但是使用時卻不需要進行try…catch捕獲處理,原因:

因為NumberFormatException并不是Exception的直接子類,而是RuntimeException的子類,只要是RuntimeException的子類,則表示程式在操作的時候可以不必使用try…catch進行處理,如果有例外發生,則由JVM進行處理,當然,也可以通過try catch處理,

自定義例外類

撰寫一個類, 繼承Exception,并重寫一參構造方法 即可完成自定義受檢例外型別,

撰寫一個類, 繼承RuntimeException,并重寫一參構造方法 即可完成自定義運行時例外型別,

例如:

class MyException extends Exception{ // 繼承Exception,表示一個自定義例外類 
	public MyException(String msg){ 
		super(msg) ; // 呼叫Exception中有一個引數的構造 
	} 
} 
public class Demo{
    public static void main(String[] args){
        Person person = new Person();
        person.setAge(-1);
    }
}
class Person{
    private int age;
    public void setAge(int age) throws MyException{
        if(age<0 || age>180){
            MyException e = new MyException("年齡不合理");
            throw e;//此處會飄紅,因為屬于受檢例外,所以必須得拋出例外;不要捕獲例外,因為自己生成例外又自己捕獲例外,很腦殘
        }else{
            this.age = age;
        }
    }
}

自定義例外可以做很多事情, 例如:

class MyException extends RuntimeException{
	public MyException(String msg){ 
		super(msg) ; //在這里給維護人員發短信或郵件, 告知程式出現了BUG, 
	} 
}

try-with-resources

//jdk1.7之前
public static void main(String[] args){
     FileReader fr = null;
    try{
        fr = new FileReader("d://book.txt");
        int c = fr.read();//讀取一個位元組
        System.out.prinyln((char)c);
    } catch(IOException e){
        e.printStackTrace();
    } finally {
        try{
            fr.close();
        } catch (Exception e){
            e.printStackTrace();
        }
    }
}
//jdk1.7時
public static void main(String[] args){
    try(FileReader fr = new FileReader("d://book.txt")){//try小括號里的物件必須是實作了AutoCloseable,這樣才會自動關閉物件
        int c = fr.read();//讀取一個位元組
        System.out.prinyln((char)c);
    } catch(IOException e){
        e.printStackTrace();
    }
}
//jdk9進行了優化
public static void main(String[] args){
    FileReader fr = new FileReader("d://book.txt");
    PrintWriter pw = new PrintWriter("d://book.txt");
    try(fr;pw){//try小括號里可以放置多個物件,物件之間用分號分隔
        int c = fr.read();//讀取一個位元組
        System.out.prinyln((char)c);
    } catch(IOException e){
        e.printStackTrace();
    }
}
//自定義實作了Closeable的物件
public static void main(String[] args){
    CloseDemo d = new CloseDemo();
    try(d){
        
    } catch(Exception e){
        
    }
}
static class CloseDemo implements Closeable{
    @Override
    public void close() throws IOException{
		Sytem.out.println("close方法被呼叫了");
    }
}//輸出:close方法被呼叫了

構造方法(構造器)

Person p = new Person();

在右側Person后面出現的小括號, 其實就是在呼叫構造方法

作用:

用于物件初始化,

執行時機:

在創建物件時,自動呼叫

特點:

所有的Java類中都會至少存在一個構造方法

如果一個類中沒有明確的撰寫構造方法, 則編譯器會自動生成一個無參的構造方法, 構造方法中沒有任何的代

碼!

如果自行撰寫了任意一個構造器, 則編譯器不會再自動生成無參的構造方法,

定義的格式 :

與普通方法基本相同, 區別在于: 方法名稱必須與類名相同, 沒有回傳值型別的宣告 ;

  • 建議自定義無參構造方法,不要對編譯器形成依賴,避免錯誤發生,

  • 當類中有非常量成員變數時,建議提供兩個版本的構造方法,一個是無參構造方法,一個是全屬性做引數的構造方法,

  • 當類中所有成員變數都是常量或者沒有成員變數時,建議不提供任何版本的構造,

多載(Overload)

方法的多載

  • 方法名稱相同, 引數型別或引數長度不同或順序不同, 可以完成方法的多載 ;
  • 方法的多載與回傳值無關;
  • 方法的多載 ,可以讓我們在不同的需求下, 通過傳遞不同的引數呼叫方法來完成具體的功能,
int sum(int x, int y){
	int z = x + y;
	return z;
}
double sum(double x, double y){
	double z = x + y;
	return z;
}

構造方法的多載

  • 一個類, 可以存在多個構造方法 ;
  • 引數串列的長度或型別不同即可完成構造方法的多載 ;
  • 構造方法的多載 ,可以讓我們在不同的創建物件的需求下, 呼叫不同的方法來完成物件的初始化 ;

重寫(Override)

  1. 引數串列必須完全與被重寫的方法相同;
  2. 回傳型別必須完全與被重寫的回傳型別相同;
  3. 訪問權限不能比父類被重寫的方法的訪問權限更低,例如父類方法為public,子類就不能為protected;
  4. 父類的成員方法只能被它的子類繼承;
  5. 宣告為static和private的方法不能被重寫,但是能夠被再次宣告;
public class Demo{
    public static void main(String[] args){
        Student student=new Student();
        student.say();
    }
}
class Person{
    public void say(){
        System.out.println("鋤禾日當午,汗滴禾下土,");
    }
}
class Student extends Person{
    public void say(){
        System.out.println("鋤禾日當午,玻璃好上霜,要不及時擦,整不好得臟,");
    }
}
//結果為:
//鋤禾日當午,玻璃好上霜,要不及時擦,整不好得臟,

重寫與多載的區別

  • 重寫方法名回傳值相同引數相同;

  • 多載方法名相同回傳值相同引數可以不同,個數可以不同;

  • 重寫發生在父子類中,多載發生在一個類中;

  • 多載與訪問權限無關 ;

  • 例外處理:多載與例外無關 ; 重寫例外范圍可以更小,但是不能拋出新的例外 ;

Java兩種核心機制

Java 虛擬機(Java Virtual Machine) JVM

在這里插入圖片描述

JVM 可以理解成一個可運行 Java 位元組碼的虛擬計算機系統

  • 它有一個解釋器組件,可以實作 Java 位元組碼和計算機作業系統之間的通信

  • 對于不同的運行平臺,有不同 的 JVM,

  • JVM 屏蔽了底層運行平臺的差別,實作了“一次編譯,隨處運行”,

垃圾回收器(Garbage Collection) GC

  • 不再使用的記憶體空間應當進行回收-垃圾回收,

  • 在 C/C++等語言中,由程式員負責回收無用記憶體,

  • Java 語言消除了程式員回收無用記憶體空間的責任:

  • JVM 提供了一種系統執行緒跟蹤存盤空間的分配情況,并在 JVM 的空閑時,檢查并釋放那些可以被釋放的存盤空間,

  • 垃圾回收器在 Java 程式運行程序中自動啟用,程式員無法精確控制和干預,

JAVA跨平臺原理

在這里插入圖片描述

識別符號

Java 對包、類、方法、引數和變數等要素命名時使用的字符序列稱為識別符號,

規則如下:

  • 由字母、數字、下劃線(_)和美元符號($)組成,

  • 不能以數字開頭,

  • 區分大小,

  • 長度無限制,

  • 不能是 Java 中的保留關鍵字,

識別符號命名習慣:見名知意,

關鍵字

Java 中有一些賦予特定的含義,有專門用途的字串稱為關鍵字(keyword),全部是小寫,

在這里插入圖片描述

this

在Java基礎中,this關鍵字是一個最重要的概念,使用this關鍵字可以完成以下的操作:

  • 呼叫類中的屬性
  • 呼叫類中的方法或構造方法 ,注意:在一個構造方法中,呼叫另一個構造方法時,呼叫的代碼必須撰寫在構造方法的第一行,
  • 表示當前物件
class Person{
	private String name;
    private int age;
	Person(){
        //呼叫下面的構造方法,如果下面還有代碼,必須寫在第一行
		this("張三",12);
	}
	Person(String name,int age){
        //呼叫類中的屬性
		this.name=name;
        this.age=age;
	}
}

static

概述

static表示“靜態”的意思,可以用來修飾成員變數和成員方法(后續還會學習 靜態代碼塊 和 靜態內部類), static的主要作用在于創建獨立于具體物件的域變數或者方法 ,

簡單理解:

被static關鍵字修飾的方法或者變數不需要依賴于物件來進行訪問,只要類被加載了,就可以通過類名去進行訪問, 并且不會因為物件的多次創建 而在記憶體中建立多份資料 ,

重點 :

  1. 靜態成員 在類加載時加載并初始化 ;
  2. 無論一個類存在多少個物件 , 靜態的屬性, 永遠在記憶體中只有一份( 可以理解為所有物件公用 ) ;
  3. 在訪問時: 靜態不能訪問非靜態 , 非靜態可以訪問靜態 ;
  4. 靜態修飾的方法,被呼叫時,有可能物件還未創建 ;

在這里插入圖片描述

//示例一
class Demo{
    public static void main(String[] args){
        /**
        Emp e1 = new Emp("張三","北京");
        Emp e2 = new Emp("李四","北京");
        Emp e3 = new Emp("王二","北京");
        Emp e4 = new Emp("麻子","北京");
        //假設公司遷址到天津
        e1.setRegion("天津");
        e2.setRegion("天津");
        e3.setRegion("天津");
        e4.setRegion("天津");
        *///上述代碼替換地址工作量非常大,所以可以把地址定義成靜態變數
        Emp.region="北京";
        Emp e1 = new Emp("張三");
        Emp e2 = new Emp("李四");
        Emp e3 = new Emp("王二");
        Emp e4 = new Emp("麻子");
        Emp.region="天津";
    }
}
class Emp{
    private String name;
    //private String region;
    static String region;
    Emp(String name,String region){
    	this.name=name;
        this.region=region;
    }
    Emp(String name){
    	this.name=name;
    }
    Emp(){}
    public String getName(){
        return name;
    }
    public void setName(String name){
        this.name=name;
    }
    public String getRegion(){
        return region;
    }
    public void setRegion(String region){
        this.region=region;
    }
}


//示例二
public class Demo {
    public static void main(String[] args) {
        Clothes clothes1 = new Clothes();
        Clothes clothes2 = new Clothes();
        Clothes clothes3 = new Clothes();
    }
}
class Clothes{
    static int count;
    Clothes(){
        count++;
        System.out.println("序號:"+count);
    }
}
//輸出:
//序號:1
//序號:2
//序號:3

final

final用于修飾屬性(類里定義的識別符號稱為屬性)和變數(方法體里定義的識別符號成為變數:

  • 通過final修飾的屬性和變數都是常量,就是不能再次賦值的變數或屬性 ;
  • final修飾的區域變數,只能賦值一次(可以先宣告后賦值);
  • final修飾的成員屬性,必須在宣告時賦值 ;
  • 全域常量(public static final)可以在任何位置被訪問 ;
  • 常量的命名規范:由一個或多個單詞組成,單詞之間必須使用下劃線隔開,所有字母大寫,例如:SQL_INSERT ;
//如果常量定義時沒有賦值初始值,那么可以賦值一次
final int a;
a=10;

final用于修飾類:

final修飾的類,不能被繼承,

final用于修飾方法:

final修飾的方法,不能被子類重寫,

權限修飾符

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-971NLHBM-1613955209061)(java%E5%9F%BA%E6%9C%AC%E7%9F%A5%E8%AF%86.assets/image-20210121165006550.png)]

封裝private

//我們觀察如下代碼:
class Person{ 
    private String name ; // 表示姓名 
    private int age ;     // 表示年齡 
    void tell(){ 
        System.out.println("姓名:" + name + ";年齡:" + age) ;
    } 
};
public class Demo{ 
    public static void main(String args[]){ 
        Person per = new Person() ;
        per.name = "張三" ;
        per.age = -30 ;
        per.tell() ;
    } 
}; 
//以上的操作代碼并沒有出現了語法錯誤,但是出現了邏輯錯誤 (年齡-30歲) 在開發中, 為了避免出現邏輯錯誤, 我們建議對所有屬性進行封裝,并為其提供setter及getter方法進行設定和取得 操作, 修改代碼如下:
class Person{ 
    private String name ; // 表示姓名 
    private int age ;     // 表示年齡 
    void tell(){ 
        System.out.println("姓名:" + getName() + ";年齡:" + getAge()) ;
    }
    public void setName(String str){ 
        name = str ; 
    }
    public void setAge(int a){ 
        if(a>0&&a<150) age = a ; 
    }
    public String getName(){ 
        return name ;
    }
    public int getAge(){ 
        return age ; 
    } 
};
public class OODemo10{ 
    public static void main(String args[]){ 
        Person per = new Person() ;
        per.setName("張三") ; 
        per.setAge(-30) ; 
        per.tell() ;
    }
};

代碼塊

普通代碼塊

在執行的流程中 出現的 代碼塊, 我們稱其為普通代碼塊,

構造代碼塊

在類中的成員代碼塊, 我們稱其為構造代碼塊, 在每次物件創建時執行, 執行在構造方法之前,

靜態代碼塊

在類中使用static修飾的成員代碼塊, 我們稱其為靜態代碼塊, 在類加載時執行, 每次程式啟動到關閉 ,只會 執行一次的代碼塊,

同步代碼塊

在后續多執行緒技術中學習,

面試題:

構造方法 與 構造代碼塊 以及 靜態代碼塊的執行順序:

靜態代碼塊 --> 構造代碼塊 --> 構造方法

public static void main(String[] args){
    //普通代碼塊,就是{}的范圍
    {
        
    }
    Person p1 = new Person();
    Person p2 = new Person();
}
class Person{
    //構造代碼塊
    //區別于構造方法,無論用戶呼叫哪一個構造方法來創建物件,構造代碼塊都必然執行,
    {
        System.out.println("物件創建時執行1");
    }
    //靜態代碼塊
    //隨著類的加載(第一次使用),靜態代碼執行,
    //因為類只加載一次,所以靜態代碼只執行一次,
    static{
        System.out.println("靜態代碼塊執行")
    }
    //構造方法
    //構造方法不一定會執行,因為構造方法存在多載,這就取決于用戶創建物件時采用哪個多載,
    public Person(){
        System.out.println("物件創建時執行2");
    }
}
//輸出: 靜態代碼塊執行		        只執行一次
//      物件創建時執行1
//		物件創建時執行2
//      物件創建時執行1
//		物件創建時執行2

  1. 把功能相似或相關的類或介面組織在同一個包中,方便類的查找和使用,
  2. 包如同檔案夾一樣,不同的包中的類的名字是可以相同的,當同時呼叫兩個不同包中相同類名的類時,應該加上包名加以區別,因此,包可以避免名字沖突,
  3. 包也限定了訪問權限,擁有包訪問權限的類才能訪問某個包中的類,

包的使用規則

- 包中java檔案的定義:

在.java檔案的首部, 必須撰寫類所屬哪個包, 格式:

package 包名;

- 包的定義:

通常由多個單詞組成, 所有單詞的字母小寫, 單詞與單詞之間使用.隔開 ,一般命名為“com.公司名.專案名.模塊名…”,

規范由來:

由于Java面向物件的特性,每名Java開發人員都可以撰寫屬于自己的Java Package,為了保障每個Java Package命名的唯一性,在最新的Java編程規范中,要求開發人員在自己定義的包名前加上唯一的前綴,由于互聯網上的域名稱是不會重復的,所以多數開發人員采用自己公司在互聯網上的域名稱作為自己程式包的唯一前綴,例如:

com.java.xxx

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/262547.html

標籤:java

上一篇:JAVA常用類別庫超重點——集合

下一篇:由淺入深了解JVM-虛擬機堆疊

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【C++】Microsoft C++、C 和匯編程式檔案

    ......

    uj5u.com 2020-09-10 00:57:23 more
  • 例外宣告

    相比于斷言適用于排除邏輯上不可能存在的狀態,例外通常是用于邏輯上可能發生的錯誤。 例外宣告 Item 1:當函式不可能拋出例外或不能接受拋出例外時,使用noexcept 理由 如果不打算拋出例外的話,程式就會認為無法處理這種錯誤,并且應當盡早終止,如此可以有效地阻止例外的傳播與擴散。 示例 //不可 ......

    uj5u.com 2020-09-10 00:57:27 more
  • Codeforces 1400E Clear the Multiset(貪心 + 分治)

    鏈接:https://codeforces.com/problemset/problem/1400/E 來源:Codeforces 思路:給你一個陣列,現在你可以進行兩種操作,操作1:將一段沒有 0 的區間進行減一的操作,操作2:將 i 位置上的元素歸零。最終問:將這個陣列的全部元素歸零后操作的最少 ......

    uj5u.com 2020-09-10 00:57:30 more
  • UVA11610 【Reverse Prime】

    本人看到此題沒有翻譯,就附帶了一個自己的翻譯版本 思考 這一題,它的第一個要求是找出所有 $7$ 位反向質數及其質因數的個數。 我們應該需要質數篩篩選1~$10^{7}$的所有數,這里就不慢慢介紹了。但是,重讀題,我們突然發現反向質數都是 $7$ 位,而將它反過來后的數字卻是 $6$ 位數,這就說明 ......

    uj5u.com 2020-09-10 00:57:36 more
  • 統計區間素數數量

    1 #pragma GCC optimize(2) 2 #include <bits/stdc++.h> 3 using namespace std; 4 bool isprime[1000000010]; 5 vector<int> prime; 6 inline int getlist(int ......

    uj5u.com 2020-09-10 00:57:47 more
  • C/C++編程筆記:C++中的 const 變數詳解,教你正確認識const用法

    1、C中的const 1、區域const變數存放在堆疊區中,會分配記憶體(也就是說可以通過地址間接修改變數的值)。測驗代碼如下: 運行結果: 2、全域const變數存放在只讀資料段(不能通過地址修改,會發生寫入錯誤), 默認為外部聯編,可以給其他源檔案使用(需要用extern關鍵字修飾) 運行結果: ......

    uj5u.com 2020-09-10 00:58:04 more
  • 【C++犯錯記錄】VS2019 MFC添加資源不懂如何修改資源宏ID

    1. 首先在資源視圖中,添加資源 2. 點擊新添加的資源,復制自動生成的ID 3. 在解決方案資源管理器中找到Resource.h檔案,編輯,使用整個專案搜索和替換的方式快速替換 宏宣告 4. Ctrl+Shift+F 全域搜索,點擊查找全部,然后逐個替換 5. 為什么使用搜索替換而不使用屬性視窗直 ......

    uj5u.com 2020-09-10 00:59:11 more
  • 【C++犯錯記錄】VS2019 MFC不懂的批量添加資源

    1. 打開資源頭檔案Resource.h,在其中預先定義好宏 ID(不清楚其實ID值應該設定多少,可以先新建一個相同的資源項,再在這個資源的ID值的基礎上遞增即可) 2. 在資源視圖中選中專案資源,按F7編輯資源檔案,按 ID 型別 相對路徑的形式添加 資源。(別忘了先把檔案拷貝到專案中的res檔案 ......

    uj5u.com 2020-09-10 01:00:19 more
  • C/C++編程筆記:關于C++的參考型別,專供新手入門使用

    今天要講的是C++中我最喜歡的一個用法——參考,也叫別名。 參考就是給一個變數名取一個變數名,方便我們間接地使用這個變數。我們可以給一個變數創建N個參考,這N + 1個變數共享了同一塊記憶體區域。(參考型別的變數會占用記憶體空間,占用的記憶體空間的大小和指標型別的大小是相同的。雖然參考是一個物件的別名,但 ......

    uj5u.com 2020-09-10 01:00:22 more
  • 【C/C++編程筆記】從頭開始學習C ++:初學者完整指南

    眾所周知,C ++的學習曲線陡峭,但是花時間學習這種語言將為您的職業帶來奇跡,并使您與其他開發人員區分開。您會更輕松地學習新語言,形成真正的解決問題的技能,并在編程的基礎上打下堅實的基礎。 C ++將幫助您養成良好的編程習慣(即清晰一致的編碼風格,在撰寫代碼時注釋代碼,并限制類內部的可見性),并且由 ......

    uj5u.com 2020-09-10 01:00:41 more
最新发布
  • Rust中的智能指標:Box<T> Rc<T> Arc<T> Cell<T> RefCell<T> Weak

    Rust中的智能指標是什么 智能指標(smart pointers)是一類資料結構,是擁有資料所有權和額外功能的指標。是指標的進一步發展 指標(pointer)是一個包含記憶體地址的變數的通用概念。這個地址參考,或 ” 指向”(points at)一些其 他資料 。參考以 & 符號為標志并借用了他們所 ......

    uj5u.com 2023-04-20 07:24:10 more
  • Java的值傳遞和參考傳遞

    值傳遞不會改變本身,參考傳遞(如果傳遞的值需要實體化到堆里)如果發生修改了會改變本身。 1.基本資料型別都是值傳遞 package com.example.basic; public class Test { public static void main(String[] args) { int ......

    uj5u.com 2023-04-20 07:24:04 more
  • [2]SpinalHDL教程——Scala簡單入門

    第一個 Scala 程式 shell里面輸入 $ scala scala> 1 + 1 res0: Int = 2 scala> println("Hello World!") Hello World! 檔案形式 object HelloWorld { /* 這是我的第一個 Scala 程式 * 以 ......

    uj5u.com 2023-04-20 07:23:58 more
  • 理解函式指標和回呼函式

    理解 函式指標 指向函式的指標。比如: 理解函式指標的偽代碼 void (*p)(int type, char *data); // 定義一個函式指標p void func(int type, char *data); // 宣告一個函式func p = func; // 將指標p指向函式func ......

    uj5u.com 2023-04-20 07:23:52 more
  • Django筆記二十五之資料庫函式之日期函式

    本文首發于公眾號:Hunter后端 原文鏈接:Django筆記二十五之資料庫函式之日期函式 日期函式主要介紹兩個大類,Extract() 和 Trunc() Extract() 函式作用是提取日期,比如我們可以提取一個日期欄位的年份,月份,日等資料 Trunc() 的作用則是截取,比如 2022-0 ......

    uj5u.com 2023-04-20 07:23:45 more
  • 一天吃透JVM面試八股文

    什么是JVM? JVM,全稱Java Virtual Machine(Java虛擬機),是通過在實際的計算機上仿真模擬各種計算機功能來實作的。由一套位元組碼指令集、一組暫存器、一個堆疊、一個垃圾回收堆和一個存盤方法域等組成。JVM屏蔽了與作業系統平臺相關的資訊,使得Java程式只需要生成在Java虛擬機 ......

    uj5u.com 2023-04-20 07:23:31 more
  • 使用Java接入小程式訂閱訊息!

    更新完微信服務號的模板訊息之后,我又趕緊把微信小程式的訂閱訊息給實作了!之前我一直以為微信小程式也是要企業才能申請,沒想到小程式個人就能申請。 訊息推送平臺🔥推送下發【郵件】【短信】【微信服務號】【微信小程式】【企業微信】【釘釘】等訊息型別。 https://gitee.com/zhongfuch ......

    uj5u.com 2023-04-20 07:22:59 more
  • java -- 緩沖流、轉換流、序列化流

    緩沖流 緩沖流, 也叫高效流, 按照資料型別分類: 位元組緩沖流:BufferedInputStream,BufferedOutputStream 字符緩沖流:BufferedReader,BufferedWriter 緩沖流的基本原理,是在創建流物件時,會創建一個內置的默認大小的緩沖區陣列,通過緩沖 ......

    uj5u.com 2023-04-20 07:22:49 more
  • Java-SpringBoot-Range請求頭設定實作視頻分段傳輸

    老實說,人太懶了,現在基本都不喜歡寫筆記了,但是網上有關Range請求頭的文章都太水了 下面是抄的一段StackOverflow的代碼...自己大修改過的,寫的注釋挺全的,應該直接看得懂,就不解釋了 寫的不好...只是希望能給視頻網站開發的新手一點點幫助吧. 業務場景:視頻分段傳輸、視頻多段傳輸(理 ......

    uj5u.com 2023-04-20 07:22:42 more
  • Windows 10開發教程_編程入門自學教程_菜鳥教程-免費教程分享

    教程簡介 Windows 10開發入門教程 - 從簡單的步驟了解Windows 10開發,從基本到高級概念,包括簡介,UWP,第一個應用程式,商店,XAML控制元件,資料系結,XAML性能,自適應設計,自適應UI,自適應代碼,檔案管理,SQLite資料庫,應用程式到應用程式通信,應用程式本地化,應用程式 ......

    uj5u.com 2023-04-20 07:22:35 more