1. 程式人生 > 資訊 >俄羅斯成功發射聯盟 2.1b 火箭,將“碼頭”號節點艙及貨運飛船送入軌道

俄羅斯成功發射聯盟 2.1b 火箭,將“碼頭”號節點艙及貨運飛船送入軌道

物件

概述

Java是一種面向物件的高階程式語言。

三大特徵:封裝,繼承,多型

面向物件最重要的兩個概念:類和物件

  • 類:相同事物共同特徵的描述。類只是學術上的一個概念並非真實存在的,只能描述一類事物
  • 物件:是真實存在的例項, 例項==物件,物件是類的例項化
  • 結論:有了類和物件就可以描述萬千世界所有的事物。 必須先有類才能有物件

定義

定義格式

修飾符 class 類名{
}
  1. 類名的首字母建議大寫,滿足駝峰模式,比如 StudentNameCode
  2. 一個 Java 程式碼中可以定義多個類,按照規範一個 Java 檔案一個類
  3. 一個 Java 程式碼檔案中,只能有一個類是 public 修飾,public修飾的類名必須成為當前Java程式碼的檔名稱
類中的成分:有且僅有五大成分
修飾符 class 類名{
		1.成員變數(Field):  	描述類或者物件的屬性資訊的。
        2.成員方法(Method):		描述類或者物件的行為資訊的。
		3.構造器(Constructor):	 初始化一個物件返回。
		4.程式碼塊
		5.內部類
	  }
類中有且僅有這五種成分,否則程式碼報錯!
public class ClassDemo {
    System.out.println(1);//報錯
}

構造器

構造器格式:

修飾符 類名(形參列表){

}

作用:初始化類的一個物件返回

分類:無引數構造器,有引數構造器

注意:一個類預設自帶一個無引數構造器,寫了有引數構造器預設的無引數構造器就消失,還需要用無引數構造器就要重新寫

構造器初始化物件的格式:類名 物件名稱 = new 構造器

  • 無引數構造器的作用:初始化一個類的物件(使用物件的預設值初始化)返回
  • 有引數構造器的作用:初始化一個類的物件(可以在初始化物件的時候為物件賦值)返回

包:分門別類的管理各種不同的技術,便於管理技術,擴充套件技術,閱讀技術

定義包的格式:package 包名,必須放在類名的最上面

導包格式:import 包名.類名

相同包下的類可以直接訪問;不同包下的類必須導包才可以使用


封裝

封裝的哲學思維:合理隱藏,合理暴露
封裝最初的目的:提高程式碼的安全性和複用性,元件化

封裝的步驟:

  1. 成員變數應該私有,用 private 修飾,只能在本類中直接訪問
  2. 提供成套的 getter 和 setter 方法暴露成員變數的取值和賦值

使用 private 修飾成員變數的原因:實現資料封裝,不想讓別人使用修改你的資料,比較安全


this

this 關鍵字的作用:

  • this 關鍵字代表了當前物件的引用
  • this 出現在方法中:哪個物件呼叫這個方法 this 就代表誰
  • this 可以出現在構造器中:代表構造器正在初始化的那個物件
  • this 可以區分變數是訪問的成員變數還是區域性變數

static

基本介紹

Java 是通過成員變數是否有 static 修飾來區分是類的還是屬於物件的。

static 靜態修飾的成員(方法和成員變數)屬於類本身的。

按照有無 static 修飾,成員變數和方法可以分為:

  • 成員變數:

    • 靜態成員變數(類變數):static 修飾的成員變數,屬於類本身,與類一起載入一次,只有一個,直接用類名訪問即可
    • 例項成員變數:無 static 修飾的成員變數,屬於類的每個物件的,與類的物件一起載入,物件有多少個,例項成員變數就載入多少個,必須用類的物件來訪問
  • 成員方法:

    • 靜態方法:有 static 修飾的成員方法稱為靜態方法也叫類方法,屬於類本身的,直接用類名訪問即可
    • 例項方法:無 static 修飾的成員方法稱為例項方法,屬於類的每個物件的,必須用類的物件來訪問

static用法

成員變數的訪問語法:

  • 靜態成員變數:只有一份可以被類和類的物件共享訪問

    • 類名.靜態成員變數(同一個類中訪問靜態成員變數可以省略類名不寫)
    • 物件.靜態成員變數(不推薦)
  • 例項成員變數:

    • 物件.例項成員變數(先建立物件)

成員方法的訪問語法:

  • 靜態方法:有 static 修飾,屬於類

    • 類名.靜態方法(同一個類中訪問靜態成員可以省略類名不寫)
    • 物件.靜態方法(不推薦,參考 JVM → 執行機制 → 方法呼叫)
  • 例項方法:無 static 修飾,屬於物件

    • 物件.例項方法
    public class Student {
        // 1.靜態方法:有static修飾,屬於類,直接用類名訪問即可!
        public static void inAddr(){ }
        // 2.例項方法:無static修飾,屬於物件,必須用物件訪問!
        public void eat(){}
        
        public static void main(String[] args) {
            // a.類名.靜態方法
            Student.inAddr();
            inAddr();
            // b.物件.例項方法
            // Student.eat(); // 報錯了!
            Student zbj = new Student();
            zbj.eat();
        }
    }
    

兩個問題

記憶體問題:

  • 棧記憶體存放 main 方法和地址

  • 堆記憶體存放物件和變數

  • 方法區存放 class 和靜態變數(jdk8 以後移入堆)

訪問問題:

  • 例項方法是否可以直接訪問例項成員變數?可以的,因為它們都屬於物件
  • 例項方法是否可以直接訪問靜態成員變數?可以的,靜態成員變數可以被共享訪問
  • 例項方法是否可以直接訪問例項方法? 可以的,例項方法和例項方法都屬於物件
  • 例項方法是否可以直接訪問靜態方法?可以的,靜態方法可以被共享訪問
  • 靜態方法是否可以直接訪問例項變數? 不可以的,例項變數必須用物件訪問!!
  • 靜態方法是否可以直接訪問靜態變數? 可以的,靜態成員變數可以被共享訪問。
  • 靜態方法是否可以直接訪問例項方法? 不可以的,例項方法必須用物件訪問!!
  • 靜態方法是否可以直接訪問靜態方法?可以的,靜態方法可以被共享訪問!!

繼承

基本介紹

繼承是 Java 中一般到特殊的關係,是一種子類到父類的關係

  • 被繼承的類稱為:父類/超類。
  • 繼承父類的類稱為:子類。

繼承的作用:

  • 提高程式碼的複用,相同程式碼可以定義在父類中
  • 子類繼承父類,可以直接使用父類這些程式碼(相同程式碼重複利用)
  • 子類得到父類的屬性(成員變數)和行為(方法),還可以定義自己的功能,子類更強大

繼承的特點:

  1. 子類的全部構造器預設先訪問父類的無引數構造器,再執行自己的構造器
  2. 單繼承:一個類只能繼承一個直接父類
  3. 多層繼承:一個類可以間接繼承多個父類(家譜)
  4. 一個類可以有多個子類
  5. 一個類要麼預設繼承了 Object 類,要麼間接繼承了 Object 類,Object 類是 Java 中的祖宗類

繼承的格式:

子類 extends 父類{

}

子類不能繼承父類的東西:

  • 子類不能繼承父類的構造器,子類有自己的構造器
  • 子類是不能可以繼承父類的私有成員的,可以反射暴力去訪問繼承自父類的私有成員
  • 子類是不能繼承父類的靜態成員的,子類只是可以訪問父類的靜態成員,父類靜態成員只有一份可以被子類共享訪問,共享並非繼承
public class ExtendsDemo {
    public static void main(String[] args) {
        Cat c = new Cat();
        // c.run();
        Cat.test();
        System.out.println(Cat.schoolName);
    }
}
class Cat extends Animal{
}
class Animal{
    public static String schoolName ="seazean";
    public static void test(){}
    private void run(){}
}

變數訪問

繼承後成員變數的訪問特點:就近原則,子類有找子類,子類沒有找父類,父類沒有就報錯

如果要申明訪問父類的成員變數可以使用:super.父類成員變數,super指父類引用

public class ExtendsDemo {
    public static void wmain(String[] args) {
        Wolf w = new Wolf();w
        w.showName();
    }
}
class Wolf extends Animal{
    private String name = "子類狼";
    public void showName(){
        String name = "區域性名稱";
        System.out.println(name); // 區域性name
        System.out.println(this.name); // 子類物件的name
        System.out.println(super.name); // 父類的
        System.out.println(name1); // 父類的
        //System.out.println(name2); // 報錯。子類父類都沒有
    }
}

class Animal{
    public String name = "父類動物名稱";
    public String name1 = "父類";
}

方法訪問

子類繼承了父類就得到了父類的方法,可以直接呼叫,受許可權修飾符的限制,也可以重寫方法

方法重寫:子類重寫一個與父類申明一樣的方法來覆蓋父類的該方法

方法重寫的校驗註解:@Override

  • 方法加了這個註解,那就必須是成功重寫父類的方法,否則報錯
  • @Override 優勢:可讀性好,安全,優雅

子類可以擴充套件父類的功能,但不能改變父類原有的功能,重寫有以下三個限制:

  • 子類方法的訪問許可權必須大於等於父類方法
  • 子類方法的返回型別必須是父類方法返回型別或為其子型別
  • 子類方法丟擲的異常型別必須是父類丟擲異常型別或為其子型別

繼承中的隱藏問題:

  • 子類和父類方法都是靜態的,那麼子類中的方法會隱藏父類中的方法
  • 在子類中可以定義和父類成員變數同名的成員變數,此時子類的成員變數隱藏了父類的成員變數,在建立物件為物件分配記憶體的過程中,隱藏變數依然會被分配記憶體
public class ExtendsDemo {
    public static void main(String[] args) {
        Wolf w = new Wolf();
        w.run();
    }
}
class Wolf extends Animal{
    @Override
    public void run(){}//
}
class Animal{
    public void run(){}
}

面試問題

  • 為什麼子類構造器會先呼叫父類構造器?

    1. 子類的構造器的第一行預設 super() 呼叫父類的無引數構造器,寫不寫都存在
    2. 子類繼承父類,子類就得到了父類的屬性和行為。呼叫子類構造器初始化子類物件資料時,必須先呼叫父類構造器初始化繼承自父類的屬性和行為
    3. 參考 JVM → 類載入 → 物件建立
    class Animal{
        public Animal(){
            System.out.println("==父類Animal的無引數構造器==");
        }
    }
    class Tiger extends Animal{
        public Tiger(){
            super(); // 預設存在的,根據引數去匹配呼叫父類的構造器。
            System.out.println("==子類Tiger的無引數構造器==");
        }
        public Tiger(String name){
            //super();  預設存在的,根據引數去匹配呼叫父類的構造器。
            System.out.println("==子類Tiger的有引數構造器==");
        }
    }
    
  • 為什麼 Java 是單繼承的?

    答:反證法,假如 Java 可以多繼承,請看如下程式碼:

    class A{
    	public void test(){
    		System.out.println("A");
    	}
    }
    class B{
    	public void test(){
    		System.out.println("B");
    	}
    }
    class C extends A , B {
    	public static void main(String[] args){
    		C c = new C();
            c.test(); 
            // 出現了類的二義性!所以Java不能多繼承!!
    	}
    }
    

super

繼承後 super 呼叫父類構造器,父類構造器初始化繼承自父類的資料。

總結與拓展:

  • this 代表了當前物件的引用(繼承中指代子類物件):this.子類成員變數、this.子類成員方法、this(...)可以根據引數匹配訪問本類其他構造器。
  • super 代表了父類物件的引用(繼承中指代了父類物件空間):super.父類成員變數、super.父類的成員方法、super(...)可以根據引數匹配訪問父類的構造器

注意:

  • this(...) 借用本類其他構造器,super(...) 呼叫父類的構造器。
  • this(...) 或 super(...) 必須放在構造器的第一行,否則報錯!
  • this(...) 和 super(...) 不能同時出現在構造器中,因為建構函式必須出現在第一行上,只能選擇一個。
public class ThisDemo {
    public static void main(String[] args) {
        // 需求:希望如果不寫學校預設就是”張三“!
        Student s1 = new Student("天蓬元帥", 1000 );
        Student s2 = new Student("齊天大聖", 2000, "清華大學" );
    }
}
class Study extends Student {
   public Study(String name, int age, String schoolName) {
        super(name , age , schoolName) ; 
       // 根據引數匹配呼叫父類構造器
   }
}

class Student{
    private String name ;
    private int age ;
    private String schoolName ;

    public Student() {
    }
    public Student(String name , int age){
        // 借用兄弟構造器的功能!
        this(name , age , "張三");
    }
	public Student(String name, int age, String schoolName) {
        this.name = name;
        this.age = age;
        this.schoolName = schoolName;
    }
// .......get + set
}

final

基本介紹

final 用於修飾:類,方法,變數

  • final 修飾類,類不能被繼承了,類中的方法和變數可以使用
  • final 可以修飾方法,方法就不能被重寫
  • final 修飾變數總規則:變數有且僅能被賦值一次

面試題:final 和 abstract 的關係是互斥關係,不能同時修飾類或者同時修飾方法!


修飾變數

靜態變數

final 修飾靜態成員變數,變數變成了常量

常量:有 public static final 修飾,名稱字母全部大寫,多個單詞用下劃線連線。

final 修飾靜態成員變數可以在哪些地方賦值:

  1. 定義的時候賦值一次

  2. 可以在靜態程式碼塊中賦值一次

public class FinalDemo {
//常量:public static final修飾,名稱字母全部大寫,下劃線連線。
    public static final String SCHOOL_NAME = "張三" ;
    public static final String SCHOOL_NAME1;

    static{
        //SCHOOL_NAME = "java";//報錯
        SCHOOL_NAME1 = "張三1";
        //SCHOOL_NAME1 = "張三2"; // 報錯,第二次賦值!
    }
}
例項變數

final 修飾變數的總規則:有且僅能被賦值一次

final 修飾例項成員變數可以在哪些地方賦值 1 次:

  1. 定義的時候賦值一次
  2. 可以在例項程式碼塊中賦值一次
  3. 可以在每個構造器中賦值一次
public class FinalDemo {
    private final String name = "張三" ;
    private final String name1;
    private final String name2;
    {
        // 可以在例項程式碼塊中賦值一次。
        name1 = "張三1";
    }
	//構造器賦值一次
    public FinalDemo(){
        name2 = "張三2";
    }
    public FinalDemo(String a){
        name2 = "張三2";
    }

    public static void main(String[] args) {
        FinalDemo f1 = new FinalDemo();
        //f1.name = "張三1"; // 第二次賦值 報錯!
    }
}