JAVA基礎知識1——堆棧、引用傳遞、static、多態、繼承、接口

1.JVM(java虛擬機):
    Java 編譯器會將java程序(高級語言)經過編譯會形成hello.class文件(字節碼文件),類加載到JVM裏面後,JVM讀取並處理class文件,執行引擎把字節碼轉爲可執行代碼(機器碼),執行的過程,再把可執行代碼轉爲機器碼,由底層的操作系統完成執行。

針對於不同的操作系統平臺,有不同版本的Java虛擬機,一個Java虛擬機實例在運行過程中有三個子系統來保障它的正常運行,分別是類加載器子系統, 執行引擎子系統和垃圾收集子系統。 如下圖所示:

  1. 類加載器的子系統用來在運行時根據需要加載類。注意上面一句話中的“根據需要”四個字。在Java虛擬機執行過程中,只有他需要一個類的時候,纔會調用類加載器來加載這個類,並不會在開始運行時加載所有的類。就像一個人,只有餓的時候纔去喫飯,而不是一次把一年的飯都喫到肚子裏。一般來說,虛擬機加載類的時機,在第一次使用一個新的類的時候。
  2. 由虛擬機加載的類,被加載到Java虛擬機內存中之後,虛擬機會讀取並執行它裏面存在的字節碼指令。虛擬機中執行字節碼指令的部分叫做執行引擎。就像一個人,不是把飯喫下去就完事了,還要進行消化,執行引擎就相當於人的腸胃系統。在執行的過程中還會把各個class文件動態的連接起來。
  3. Java虛擬機會進行自動內存管理。具體說來就是自動釋放沒有用的對象,而不需要程序員編寫代碼來釋放分配的內存。這部分工作由垃圾收集子系統負責。

最後做一個總結:

  1. 虛擬機並不神祕,在操作系統的角度看來,它只是一個普通進程。
  2. 這個叫做虛擬機的進程比較特殊,它能夠加載我們編寫的class文件。如果把JVM比作一個人,那麼class文件就是我們喫的食物。
  3. 加載class文件的是一個叫做類加載器的子系統。就好比我們的嘴巴,把食物喫到肚子裏。
  4. 虛擬機中的執行引擎用來執行class文件中的字節碼指令。就好比我們的腸胃,對喫進去的食物進行消化。
  5. 虛擬機在執行過程中,要分配內存創建對象。當這些對象過時無用了,必須要自動清理這些無用的對象。清理對象回收內存的任務由垃圾收集器負責。就好比人喫進去的食物,在消化之後,必須把廢物排出體外,騰出空間可以在下次餓的時候喫飯並消化食物。

3.PATH:是操作系統的環境屬性,指的是可以執行命令的程序路徑;
   CLASSPATH:是所有*.class文件的執行路徑,java命令執行的時候將利用此路徑加載所需要的*.class文件 。使用public class定義的類,要求文件名稱和類名稱保持一致,在一個*.java文件之中只能存在一個public class;使用class定義的類,文件名稱可以和類名稱不一致,在一個*.java文件之中可以同時存在多個class定義,編譯之後會產生多個*.class文件


4.   堆棧:    
    堆內存(heap):保存每一個對象的屬性內容,堆內存需要用關鍵字new來開闢,對象沒有對應的堆內存指向,將無法使用。
    棧內存(stack):保存的是一塊堆內存的地址數值
    堆內存保存的是對象的真正數據,棧內存可以理解爲保存對象的名稱(Book bk)
    每一次使用關鍵字new都會開闢新的堆內存空間
    類屬於引用數據類型,進行引用傳遞時,傳遞的是堆內存的使用權 
        
5.Java避免了C/C++之中複雜的指針關係,而使用了更爲簡單的引用方式來進行內存傳遞
   Java的數據類型:分爲基本數據類型和引用數據類型
        基本數據類型:byte、short、int、long、float、double、char、boolean等
        引用數據類型:類(class)、接口(interface)、數組
        基本數據類型在被創建時,在棧上給其劃分一塊內存,將數值直接存儲在棧上
        引用數據類型在被創建時,首先要在棧上給其引用(句柄)分配一塊內存,而對象的具體信息都存儲在堆內存上,然後由棧上面的引用指向堆中對象的地址。
        基本數據不牽扯內存分配問題,引用數據類型必須要進行內存的開闢

6.引用傳遞(java精髓) :一塊堆內存空間(保存對象的屬性信息)可以同時被多個棧內存空間共同指向, 則每一個棧內存都可 以修改同一塊堆內存空間的屬性值。值傳遞和引用傳遞的區別(https://blog.csdn.net/zhzhao999/article/details/53449504?tdsourcetag=s_pcqq_aiomsg)(https://blog.csdn.net/bjweimengshu/article/details/79799485 

https://github.com/Snailclimb/JavaGuide/blob/master/docs/essential-content-for-interview/MostCommonJavaInterviewQuestions/%E7%AC%AC%E4%B8%80%E5%91%A8%EF%BC%882018-8-7%EF%BC%89.md關於java的值傳遞和引用傳遞,這2篇文章講解的清楚

  • 值傳遞的時候,將實參的copy一份給形參。
  • 引用傳遞的時候,將實參的地址值copy一份給形參,傳遞的是地址的拷貝

也就是說,不管是值傳遞還是引用傳遞,形參拿到的僅僅是實參的副本,而不是實參本身。

 

第三個例子:提供了改變自身方法的引用類型

StringBuilder sb = new StringBuilder("iphone");
void foo(StringBuilder builder) {
    builder.append("4");
}
foo(sb); // sb 被改變了,變成了"iphone4"。

第四個例子:提供了改變自身方法的引用類型,但是不使用,而是使用賦值運算符。

StringBuilder sb = new StringBuilder("iphone");
void foo(StringBuilder builder) {
    builder = new StringBuilder("ipad");
}
foo(sb); // sb 沒有被改變,還是 "iphone"。

重點理解爲什麼,第三個例子和第四個例子結果不同?

下面是第三個例子的圖解:
圖片說明 
builder.append("4")之後
圖片說明 
下面是第四個例子的圖解:
圖片說明 
builder = new StringBuilder("ipad"); 之後
圖片說明

7.封裝: 將類的某些信息隱藏在類內部,不允許外部程序直接訪問,而是通過該類提供的方法來實現對隱藏信息的操作和訪問。
        使用private關鍵字進行封裝
        使用setter和getter方法來對屬性進行讀寫
   使用封裝有四大好處:
        良好的封裝能夠減少耦合。
        類內部的結構可以自由修改。
        可以對成員進行更精確的控制。
        隱藏信息,實現細節。
        
8.package:定義本java文件中定義的類所在的包(文件夾)“."表示子目錄
        import關鍵字用來導包,導入的時候包名後面加.*  表示引入這個包裏面所有的類
        所有的類都應該放在包中,類名稱是“包.類”
        通常一個*.java文件只定義一個類,且用public class來聲明    
        
9.命名規則:類名的首字母大寫;變量名和方法名的首字母小寫,駝峯標識

10.重載:  指方法名相同,參數的類型或個數不同, 調用的時候將會按照傳遞的參數類型和個數來完成不同方法的重載
 
11.構造方法:構造方法可以爲類中的屬性初始化,構造方法的類名稱相同,無返回值類型聲明。
     如果類中沒有明確的定義出構造方法,則系統自動生成一個無參的什麼都不做的構造方法。構造方法可以重載
    
12.static: static屬性、方法=公共屬性、方法 全局變量       

  1. 從語法形式上看:成員變量是屬於類的,而局部變量是在方法中定義的變量或是方法的參數;成員變量可以被 public,private,static 等修飾符所修飾,而局部變量不能被訪問控制修飾符及 static 所修飾;但是,成員變量和局部變量都能被 final 所修飾。
  2. 從變量在內存中的存儲方式來看:如果成員變量是使用static修飾的,那麼這個成員變量是屬於類的,如果沒有使用static修飾,這個成員變量是屬於實例的。而對象存在於堆內存,局部變量則存在於棧內存。
  3. 從變量在內存中的生存時間上看:成員變量是對象的一部分,它隨着對象的創建而存在,而局部變量隨着方法的調用而自動消失。
  4. 成員變量如果沒有被賦初值:則會自動以類型的默認值而賦值(一種情況例外被 final 修飾的成員變量也必須顯示地賦值),而局部變量則不會自動賦值。

    static修飾的方法稱爲類方法,無this指針。其他的就是實例方法。
        類方法可以使用類名稱或實例化對象調用,而非static方法只能依靠實例化對象纔可以調用    
        類方法內部不能直接調用非static屬性、方法,只能調用static方法、屬性
        非static方法可以直接訪問static屬性、方法
        當一個類中不需要保存屬性時,可以將這個類中的方法全部定義爲static,這樣做可以節約內存空間
        類方法是屬於整個類的,而實例方法是屬於類的某個對象的。        
    由於類方法是屬於整個類的,並不屬於類的哪個對象,所以類方法的方法體中不能有與類的對象有關的內容。即類方法體有如下限制:
            類方法中不能引用對象變量;
            類方法中不能調用類的對象方法;
            在類方法中不能使用super、this關鍵字。(this表示當前類的對象,由static修飾的方法是類直接調用,不需要創建對象,所以不能用this)
            類方法不能被覆蓋。
            
13.繼承:通過繼承子類擁有了父類的所有成員(成員變量和方法)    
        一個子類只能有一個父類,一個父類可以派生出多個子類
        使用extends關鍵字來進行繼承

14.子類對象的實例化:
        當通過關鍵字new實例化子類對象時,會默認調用父類的無參構造方法,爲父類對象實例化,
        而後纔會調用子類的構造方法,爲子類對象實例化。
           
15.訪問權限:private  類內部
        :default  類內部  同一個包
        :protected類內部  同一個包  子類
        :public   類內部  同一個包  子類  任何地方
        對於class的權限修飾只可以用public和default
        
16.重寫:在子類中可以根據需要對從基類中繼承的方法進行重寫
        重寫方法必須和被寫方法具有相同的方法名稱、參數列表和返回類型
        重寫方法不能使用比被寫方法更嚴格的訪問權限
        父類方法前加final關鍵字,則無法被複寫
        
17.this:  代表使用該方法的對象的引用,可以看作是一個變量,他的值是當前對象的引用
        this可以調用本類屬性和本類方法,如果本類(子類)沒有指定的方法或屬性,則去父類中查找是否存在
        調用本類中的構造方法時,放在程序首行
        
18.super: 使用super表示當前子類的父類對象,表示子類直接調用父類的屬性的方法,不會查找本類定義
        super可以用來引用直接父類的實例變量。
        super可以用來調用直接父類方法。
        super()可以用於調用直接父類構造函數。
        
19.繼承中的構造方法:
        子類的構造的過程中必須調用起父類的構造方法(來保證父類對象先實例化,子類對象後實例化)
        子類可以在自己的構造方法中使用super(aegument_list)調用父類的構造方法
            使用this(aegument_list)調用本類的另外的構造方法
            如果調用super,必須寫在子類構造方法的第一行
        如果子類的構造方法中沒有顯示地調用父類的構造方法,則系統默認調用父類無參的構造方法
        this和super均必須編寫在構造方法內的第一行,所以兩者無法同時存在於同一個構造方法之內
        
       除非兩個類之間是“is - a”的關係,否則不要輕易地使用繼承。過多的使用繼承會破壞代碼的可維護性,當父類修改時,會影響所有繼承他的子類,增加了程序維護的難度和成本。
      不要僅僅爲實現多態而使用繼承,如果類之間沒有“is - a”關係,可以通過實現接口與組合的方式來達到相同的目的

23.對象轉型(casting):
            一個基類的引用類型變量可以“指向”其子類對象
            一個基類的引用不可以訪問其子類對象新增加的成員(屬性和方法)
            可以使用引用變量instanceof類名來判斷該引用型變量所“指向”的對象是否屬於該類或該類的子類
            子類的對象可以當作基類的對象來使用稱作向上轉型(upcasting),反之向下轉型(downcasting)
            例:Object obja = new Book(); //upcasting
                Object objb = "hello";    //upcasting
                Book b = (Book) obja;      //向下轉型
                String s = (String)objb;  //向下轉型
            向上轉型:目的是參數的統一
        抽象類和接口的對象都是利用對象多態性的向上轉型,進行接口或抽象類的實例化操作

24.多態: 
    方法的多態性:重載與覆寫
    對象的多態性:父子類對象的轉換
        在程序執行期間判斷所引用對象的實際類型,根據其實際類型調用其相應的方法
        繼承是子類使用父類的方法,而多態則是父類使用子類的方法
        要求:  1.要有繼承
                2.要有重寫
                3.父類引用指向子類對象

對象多態性核心概念:
        如果抽象類或接口中的抽象方法被子類覆寫了,那麼實例化這個子類時,所調用的方法一定是被覆寫過的方法
        即方法名稱以父類爲標準,而具體的實現需要依靠子類實現

25.抽象類/方法:   抽象類專門用來當父類,其作用類似一個“模板”
                使用abstract關鍵字定義
                利用抽象類可以使用abstract關鍵字明確定義子類需要重寫的方法,即抽象方法
                含有抽象方法的類必須被聲明爲抽象類,抽象類必須被繼承,抽象方法必須被重寫
                在定義抽象類時,類中可以不定義抽象方法
                抽象類不能被實例化,必須通過對象的多態性進行實例化操作
                抽象方法只需聲明(不需要加{}),而不需實現(不需要定義方法體)

26.final: 可以定義類、方法、變量
        使用final定義的類不能被繼承,不能有子類
        使用final定義的方法不能被重寫(就是說子類的方法中不能用和父類相同名稱的方法,但如果這個final方法被private修飾,則此方法對子類不可見,子類不能覆蓋。所以可以有同名方法,因爲子類方法和父類方法是兩個方法。)
        使用final定義的變量不能被修改,是常量
            
27.接口:    接口是抽象方法和常量值的定義的集合   
        使用interface關鍵字來定義        interface Singer
        接口是一種特殊的抽象類,這種抽象類中只包含常量和抽象方法
        “實現”類似於繼承,用implemenst關鍵字來實現,接口必須被子類實現
        如果一個類實現了某個接口,那麼這個類必須重寫這個接口中的所有方法,否則就必須聲明爲抽象類
        class Student implement Singer   //Singer是一個接口
        如果父類實現了某個接口,那麼子類自然也就實現了該接口,子類不必再顯式地使用關鍵字implements聲明實現這個接口
        多個無關的類可以實現同一個接口
        一個類可以實現多個無關的接口,接口主要用於解決單繼承侷限問題
        接口和接口之間可以繼承
        接口具有多態性
        接口中的方法只有public一種訪問權限
        接口可以多重實現

28.使用instanceof關鍵字,可以判斷對象屬於哪個類    

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