Java基礎知識回顧

面向對象三大特性

封裝

隱藏對象的屬性和實現細節,僅對外公開接口,控制在程序中屬性的讀取和修改的訪問級別。

繼承

繼承就是子類繼承父類的特徵和行爲,使得子類對象(實例)具有父類的實例域和方法
子類擁有父類的非private屬性,方法
子類可以擁有自己的屬性和方法,即子類可以對父類進行擴展
子類可以用自己的方式實現父類的方法
java的繼承是單繼承
關鍵字:extends

多態

多態是同一個行爲具有多個不同表現實行或形態的能力
多態存在的三個必要條件:

  • 繼承
  • 重寫
  • 父類引用指向子類對象
class Animal{
    public int month = 2;
    public void eat(){
        System.out.println("動物吃東西");
    }
    
}
class Dog extends Animal{
    public int month = 3;
    
    public void eat() {
        System.out.println("小狗吃肉");
    }
    
    public void sleep() {
        System.out.println("小狗睡午覺");
    }
}
class Cat extends Animal{
    public int month = 4;
    
    public void eat() {
        System.out.println("小貓吃魚");
    }
}
public class Test {
    public static void main(String[] args){
        Animal a = new Dog();
        Animal b = new Cat();
        a.eat();
        a.sleep();//指定了父對象沒有的函數,會報錯,因爲在編譯的時候a爲Animal對象
        System.out.println(a.month);
        b.eat();
        System.out.println(b.month);
    }
}

這一段表示創建父對象動物,狗和貓繼承自動物,那麼變量a和變量b分別表現爲狗,貓,這就是多態。
多態中成員的特點:

  • 多態成員變量:編譯運行看左邊
  • 多態成員方法:編譯看左邊,運行看右邊
    instanceof關鍵字用於判斷某個對象是否屬於某種數據類型,使用方法如下:
Animal f1=new Dog();
Animal f2=new Cat();
if(f1 instanceof Animal)//用這個關鍵字檢測父子對象都是對的
{
    System.out.println("f1是Animal的類型");
}
else{
    System.out.println("f1是Dog的類型");
}

多態的方法執行是覆蓋的,如果被調用的子類有這個方法則調用子類的方法,如果子類沒有該方法會去父類裏面找。
對於屬性,使用的是同名屬性隱藏機制來實現多態的,同名屬性隱藏機制是指:在具有父子關係的兩個類中,類中相同名字的屬性會使得從父類中繼承過來的同名屬性變得不可見,

重載和重寫的區別

  • 重寫(Override):重寫是子類對父類的允許訪問的方法進行重新編寫,返回值和形參都不能改變,子類根據需要實現自己的方法
  • 重載(Overload):是在一個類裏面,方法名相同,而參數不同(個數和類型不同),返回類型可以相同也可以不同。
    方法重載是一個類的多態性表現,而方法重寫是子類與父類的一種多態性的表現。
    重寫發生在子類和父類之間,重寫要求子類被重寫方法與父類被重寫方法有相同的返回類型,比父類被重寫方法更好的訪問,不能比父類被重寫方法聲明更多的異常。—運行時多態
    重寫原則:
    參數列表必須完全與被重寫方法的一致,返回類型必須完全與被重寫的方法的返回類型一致
    構造方法不能被重寫,聲明爲final的方法不能被重寫,聲明爲static的方法不能被重寫,但是能夠被再次申明
    訪問權限不能比父類中被重寫的方法的訪問權限更低。
    重寫的父類方法能夠拋出任何非強制異常(也叫非運行異常),無論被重寫的方法是否拋出異常,但是,重寫的方法不能拋出新的強制性異常,或者比被重寫方法聲明更廣泛的強制性異常,反之則可以。

Java是否可以繼承String類:

  • String是final類型的,所以不能被繼承

Java類支持多繼承嗎?可以實現多個接口嗎?

java不支持多繼承,但是類可以實現多個接口,間接的實現多繼承,也可以通過內部類。

接口和抽象的區別:

  • 接口和抽象類都是繼承樹的上層,他們的共同點如下:
  1. 都是上層的抽象層
  2. 都不能夠被實例化
  3. 都能包含抽象的方法,這些抽象的方法用於描述類具備的功能
  • 兩者的區別:
  1. 在抽象類中可以寫非抽象的方法,從而避免在子類中重複書寫,提高代碼複用性–抽象類的優勢,而接口當中只能有抽象的方法(jdk8之後也可以有實現方法)
  2. 一個類只能繼承一個直接父類,這個父類可以是具體的類也可以是抽象類,但是一個類可以實現多個接口,接口的設計具有更大的擴展性,而抽象類的設計必須十分謹慎。
  3. 抽象級別:接口 大於 抽象類 大於 實現類
  4. 接口的設計目的:是針對類的行爲進行約束,側重於動作,而抽象類的設計目的是代碼複用。
  5. 抽象類是 is a的關係,接口是has a的關係。

Java中的修飾符的作用域以及可見性

  • public :當前類、子類,同一包、其他包都可以訪問
  • protected:當前類,子類以及同一包可以訪問,其它包不可以
  • default:當前類和同一包可以訪問,子類和其他包不可以
  • private:當前類可以訪問,同一包、子類、其它包都不可以訪問
    控制的範圍是逐級減少的,public > protected > default > private

Java中== 與equals的區別:

  • ==比較的是變量(棧)內存中存放的對象(堆)的內存地址,用來判斷兩個對象的地址是否相同,即是否是指相同一個對象。比較的是真正意義上的指針操作。
  • equals來比較的是兩個對象的內容是否相等,由於所有的類都是繼承自java.lang.Object類的,所以適用於所有對象,如果沒有對該方法進行覆蓋的話,調用的仍然是Object類中的方法,而Object中的equals方法返回的卻是==的判斷。
    如果想自己定義什麼是相等,可以重寫equals方法。用於判斷是否是自己定義的相等

靜態變量和實例變量的區別?

  • 一個static方法內不可以調用非static方法
    因爲非靜態方法是與對象關聯起來的,必須創建一個對象纔可以進行方法的調用,而非靜態的方法是不需要創建對象的,所以兩者之間相互矛盾,不能在靜態方法使用調用非靜態的方法。
  • static方法是靜態方法,是屬於類的方法;非static方法是屬於對象的方法,所以要想在static方法中調用非static方法要先創建一個對象,再由這個對象來調用。
    本質是JVM加載順序決定的,加載static方法的時候非靜態方法還沒有初始化,當然不能調用了

Integer和int的類型

Integer是int的封裝類,從java5以後引入了自動裝箱和拆箱機制,兩個可以互相轉換,int是基本的數據類型不能是null,但是Integer可以是null。爲空值。
Integer是對象,用一個引用指向這個對象,而int是基本類型,直接存儲數據。
Integer提供了好多與整數相關的操作方法,例如:將一個字符串轉換成整數等.

Integer的緩存問題


public class IntTest {
 
    public static void main(String[] args) {
        Integer a = 100, b = 100, c = 150, d = 150;
        System.out.println(a == b);
        System.out.println(c == d);
    }

請問輸出結果如何?
答案是:第一個是true,第二個是false
爲什麼會這樣呢? 是因爲Integer緩存了-128到127之間的整數對象,如果是-128到127之間的整數,則會使用整數緩存對象,否則就new一個整形對象。所以a和b是緩存好的對象,但是C和d是new出來的,所以在比較的時候就會出現現在的結果啦

String、StringBuilder、StringBuffer的優缺點

  • String是字符串常量,StringBuilder和StringBuffer都是字符串變量,

Java字符串駐留池

String a = "aa";
Stirng b = "aa";
System.out.priont(a == b);

輸出結果爲trye,因爲==比較的引用地址,String被放在了常量池之中,第一次出現"aa"的時候,JVM吧他放在了常量池裏面,當第二次出現"aa"的時候,JVM就會把引用引到之前的地方,所以這兩比較的時候會出現true

String a = new String("aa");
String b = new String("aa");
System.out.print(a==b);

這裏輸出結果是false,因爲new會強制的分配空間。

String str1 = "java";
String str2 = "blog";
String s = str1+str2;
System.out.print(s=="javablog");

這裏是false,JVM確實會對型如String str1 = “java”; 的String對象放在字符串常量池裏,但是它是在編譯時刻那麼做的,而String s = str1+str2; 是在運行時刻才能知道(我們當然一眼就看穿了,可是Java必須在運行時才知道的,人腦和電腦的結構不同),也就是說str1+str2是在堆裏創建的, s引用當然不可能指向字符串常量池裏的對象。

String str1 = "java";
String str2 = new String("java");
System.out.print(str1.equals(str2));

是true,無論在常量池還是堆中的對象,用equals()方法比較的就是內容


public class StringCompare {
  public static void A() {
    String str1 = "java";
    String str2 = "java";
    System.out.println(str1 == str2);  //true
  }
  public static void B() {
    String str1 = new String("java");
    String str2 = new String("java");
    System.out.println(str1 == str2);  //false
  }
  public static void C() {
    String str1 = "java";
    String str2 = "blog";
    String s = str1 + str2;
    System.out.println(s == "javablog");  //false
  }
  public static void C2() {
    String str1 = "javablog";
    String str2 = "java"+"blog";    //在編譯時被優化成String str2 = "javablog";
    System.out.println(str1 == str2);  //true
  }
  public static void D() {
    String s1 = "java";
    String s2 = new String("java");
    System.out.println(s1.intern() == s2.intern());  //true
  }
 
  public static void E() {
    String str1 = "java";
    String str2 = new String("java");
    System.out.println(str1.equals(str2));  //true
  }
 
  public static void main(String[] args){
    A();
    B();
    C();
    C2();
    D();
    E();
  }
}
 
輸出============
 
true
false
false
true
true
true

線程安全性

StringBuilder是線程不安全的,而StringBuffer是線程安全的(StringBuffer中很多方法帶有synchronized關鍵字)

總結

String:適用於少量字符串操作的情況;
StringBuilder:適用於在單線程下在字符緩衝區進行大量操作的情況;
StringBuffer:適用於在多線程下在字符緩衝區進行大量操作的情況

java程序初始化的順序是什麼樣子的?

一般遵循三個原則:

  • 1.靜態變量優先於非靜態變量初始化,其中靜態變量只初始化一次,而非靜態變量可能會初始化很多次
  • 2.父類優先子類進行初始化
  • 3.按照成員變量定義順序進行初始化,即使變量定義散佈於方法之中,它們依然在方法調用之前(包括構造函數)先初始化。
    父類靜態字段初始化
    父類靜態代碼塊
    子類靜態字段初始化
    子類靜態代碼塊
    父類普通字段初始化
    父類構造代碼塊({//代碼}) –優先於構造函數執行
    父類構造函數
    子類普通字段初始化
    子類構造代碼塊
    子類構造函數

Java中的反射:

轉看另一篇專門講反射機制 Java中的反射機制

Java中的Try catch finally的問題

  • 1.不管有沒有異常,finally中的代碼都會執行
  • 2.當try、catch中有return語句時,finally中的代碼依然會繼續執行
  • 3.finally是在return後面的表達式運算之後執行的,此時並沒有返回運算後的值,而是把值保存起來,不管finally對該值做了任何改變,返回的值都不會改變,依然返回保存起來的值,也就是說方法的返回值是在finally運算之前就確定了的。
  • 4.如果return的數據是引用數據類型,而在finally中對該引用數據類型的屬性值的改變起作用,try 中return返回的就是finally中改變後的屬性值
  • 5.finally代碼最好不要包含return,程序會提前退出,也就是說返回的值不是try catch中的值
    先執行try中的語句,包括return後面的表達式
    有異常時,先執行catch中的語句,包括return 後面的表達式;
    然後執行fianlly中的語句,如果finally裏面有return語句,會提前退出
    最後執行try 中的return,有異常執行catch中return;

歡迎關注我的個人博客zenshin’blog

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