天天看點

【java基礎17:繼承】子類調用父類方法 何時使用繼承 Object中有哪些方法 println()方法的解釋 toString 方法的測試

繼承(extends)

  1. 什麼是繼承?繼承有什麼用?

    繼承:在現實世界中也存在,例如:父親有錢,兒子不用努力也很有錢

    繼承的作用:

    • 基本作用:子類繼承父類,代碼可以得到複用。
    • 主要/重要作用:有了繼承關系,才有了後期的方法覆寫和多态機制
  2. 繼承的相關特性
    1. B類繼承A類:A類為超類(superclass)、父類、基類。

      B類則稱為子類(subclass)、派生類、擴充類

      class A{}
      class B extends A{}
      //我們平時聊天說的比較多的是:父類和子類。
      suoperclass 父類
      subclass  子類
                 
    2. java中的繼承隻支援單繼承,不支援多繼承 ,C++中支援多繼承

      這也是java展現簡單性的一點,換句話說,java中不允許這樣寫代碼:

      class B extends A,C{}//這樣寫是錯誤的.
                 
    3. 雖然java不支援多繼承,但有的時候會産生間接繼承的效果,例如:
      calss C extends B{} 
      class B extends A{}
      //也就是說:c直接繼承B、其實C還間接繼承A.
                 
      public class ExtendsTest02 {public static void main(String[] args){}}
      
      class AA{}
      class BB{}
      class CC extends AA{}
      class DD extends BB{}
      
      //文法錯誤
      //java隻允許單繼承,不允許多繼承。java是簡單的,C++支援多繼承。
      //C++更接近現實一些。現實中:兒子同時繼承父母親的基因。
      //class EE extends AA,BB{}
      
      class XX{}
      class YY extends XX{}
      //其實這樣也說明了ZZ是繼承XX和YY的。
      //較長的描述:ZZ直接繼承了YY ,間接繼承了XX。
      class ZZ extends YY{}
                 
    4. java中規定:子類繼承父類,除了構造方法不能繼承外,剩下的都可以繼承,但是私有的屬性無法在子類中直接通路。(父類中private修飾的不能在子類中直接通路,可以通過間接的手段通路,如:使用set和get方法)
    5. java的類沒有顯示的繼承任何類,則預設繼承Object類,Object類是java語言提供的根類(老祖宗類),也就是說:類一旦建立,就有Object類型中所有的特征。
      //C繼承B,B繼承A,A繼承Object
      //C具有所有的Object對象的特征(基因)
      //Object是所有類的超類、老祖宗,是類體系結構中的根。
      //java這麼龐大的一個繼承結構,最頂點:Object
                 
    6. 繼承也有缺點: 如:CreditAccount類繼承Account類會導緻它們之間的耦合度非常高,Account類發生改變之後馬上影響到CreditAccount類。
      /*
          使用繼承解決
          繼承:除了構造方法其他的都繼承,私有化的屬性也繼承,但是在子類中不能直接通路
          繼承也是有缺點的:耦合度高,父類修改,字類受牽連。
       */
      
      public class ExtendsTest01 {
          public static void main(String[] args){
              //建立普通賬戶
              Account1 act = new Account1();
              act.setActNo("123456");
              act.setBalance(10000);
              System.out.println(act.getActNo()+"的餘額:"+act.getBalance());
      
              //建立信用賬戶
              CreditAccount ca = new CreditAccount();
              ca .setActNo("654321");
              ca.setBalance(-20000);
              ca.setCredit(0.99);
              System.out.println(ca.getActNo()+"的餘額:"+ca.getBalance()+" \t他的信譽為:"+ca.getCredit());
      
          }
      }
      //銀行賬戶類
      //賬戶屬性:賬戶、餘額
      class Account1{//父類
          //屬性
          private String actNo;
          private double balance;
          //構造方法
          public Account1(){}
          public Account1(String actNo,double balance){
              this.actNo = actNo;
              this.balance = balance;
          }
          //set 和 get 方法
          public String getActNo(){
              return actNo;
          }
          public void setActNo(String actNo){
              this.actNo = actNo;
          }
          public double getBalance(){
              return balance;
          }
          public void setBalance(double balance){
              this.balance = balance;
          }
      }
      //其他類型的賬戶:信用卡賬戶
      //賬号、餘額、信譽度
      class CreditAccount extends Account1{//子類
      
          private double credit;
      
          //構造方法
          public CreditAccount(){}
      
          public void doSome(){
              //錯誤: actNo 在 Account1 中是 private 通路控制
              //繼承的私有屬性無法直接通路。
              //System.out.println(actNo);
              //隻能間接通路
              System.out.println(getActNo());
          }
      
          //set 和 get 方法
      
          public double getCredit(){
              return credit;
          }
          public void setCredit(double credit){
              this.credit = credit;
          }
      
      }
      
      
      /*分析以下程式存在什麼問題?
            代碼臃腫,代碼沒有得到複用性。
      
       */
      
      /*
      public class ExtendsTest01 {
          public static void main(String[] args){
              //建立普通賬戶
              Account1 act = new Account1();
              act.setActNo("123456");
              act.setBalance(10000);
              System.out.println(act.getActNo()+"的餘額:"+act.getBalance());
      
              //建立信用賬戶
              CreditAccount ca = new CreditAccount();
              ca .setActNo("654321");
              ca.setBalance(-20000);
              ca.setCredit(0.99);
              System.out.println(ca.getActNo()+"的餘額:"+ca.getBalance()+" \t他的信譽為:"+ca.getCredit());
      
          }
      }
      //銀行賬戶類
      //賬戶屬性:賬戶、餘額
      class Account1{
          //屬性
          private String actNo;
          private double balance;
          //構造方法
          public Account1(){}
          public Account1(String actNo,double balance){
              this.actNo = actNo;
              this.balance = balance;
          }
          //set 和 get 方法
          public String getActNo(){
              return actNo;
          }
          public void setActNo(String actNo){
              this.actNo = actNo;
          }
          public double getBalance(){
              return balance;
          }
          public void setBalance(double balance){
              this.balance = balance;
          }
      }
      //其他類型的賬戶:信用卡賬戶
      //賬号、餘額、信譽度
      class CreditAccount{
          private String actNo;
          private double balance;
          private double credit;
      
          //構造方法
          public CreditAccount(){}
          public CreditAccount(String actNo,double balance,double credit){
              this.actNo = actNo;
              this.balance = balance;
              this.credit = credit;
          }
      
          //set 和 get 方法
          public String getActNo(){
              return actNo;
          }
          public void setActNo(String actNo){
              this.actNo = actNo;
          }
          public double getBalance(){
              return balance;
          }
          public void setBalance(double balance){
              this.balance = balance;
          }
          public double getCredit(){
              return credit;
          }
          public void setCredit(double credit){
              this.credit = credit;
          }
      }
       */
                 
  3. 測試: 字類繼承父類之後,能使用字類調用父類方法嗎?
    /*
        測試:  子類繼承父類之後,能使用子類調用父類方法嗎?
            本質上,子類繼承父類之後,父類繼承過來的方法歸自己所有。
            繼承:把父類的東西複制一份挪過來。
            實際上調用的也不是父類的方法,是子類自己的方法(因為已經繼承過來了,就屬于自己的。)
     */
    public class ExtendsTest03 {
        public static void main(String[] args){
            Cat c = new Cat();
            //調用父類中方法
            c.move();
    
            //子類可以通路name嗎
            //父類屬性如果沒有封裝,子類可以通路。封裝後使用get以及set方法讀改。
            System.out.println(c.name);//可以
    
        }
    }
    class Animal{//先不封裝
        //名字
        String name = "xiaohua";
    
        //提供一個動物移動的方法
        public void move(){
            System.out.println(name +"正在疾跑");
        }
    }
    //Cat類繼承Animal類,會将Animal中除構造方法外的東西都繼承過來。
    class Cat extends Animal{
    
    }
    
               
  4. 在實際開發中,滿足什麼條件時才可以使用繼承?
    /*
    	凡是采用“is a” 能描述的,都可以繼承。
    	例如:Cat is a Animal :貓是一個動物
    	例如:Dog is a Animal :狗是一個動物
    	CreditAccount is a Account :信用卡是一個銀行賬戶
    	......
    	假設以後開發中有一個A類,有一個B類,A類和B類确實也有重複的代碼,那麼他們兩個之間就可以繼承嗎?	 不一定,還是要看他們之間是不是可以使用is a來描述
    	
    */
    class Customer{
    	String name;//名字
    	//set以及get 方法
    }
    class Product{
    	String name //名字
    	//set以及get 方法
    }
    //class Product extends Customer{}
    //這種繼承就是錯誤的,因為Product is a Customer 是不符現實的。
    //雖然他們都有名字這個屬性,但一個是人,一個是東西。是以繼承主要還是要兩個類之間存在關系。
               
  5. 任何一個類,沒有顯示繼承任何類,預設繼承Object,那麼Object類當中有哪些方法呢?老祖宗為我們提供了哪些方法?

    println()方法的解釋

    /*
    	out後面沒有小括号,說明out是變量名。System是一個類名,類名.out,說明out是一個靜态變量。
    	System.out傳回一個對象,然後采用“對象.”的方式通路println()方法。
    */
    //以下代碼中:System out println都是辨別符
    public class Test3 {
        //靜态變量
        static Student6 stu = new Student6();
        //入口
        public static void main(String[] args){
    
            //拆分為兩行
            Student6 s = Test3.stu;//把靜态變量的值指派給一個變量
            s.exam();  //通過這個變量調用其中的方法。
            //合并
            Test3.stu.exam();
            System.out.println("Hello World");
        }
    }
    class Student6{
        //執行個體方法
        public void exam(){
            System.out.println("考試中。。");
        }
    }
    
               
    Object中有一個方法toString(),測試後發現:
    Sysetm.out.println(引用);
    //當我們直接輸出一個“引用”的時候,println()方法會自動調用“引用.toString()”,然後輸出toString()的執行結果。
               
    /*
        //預設繼承Object,Object中有哪些方法呢?
    
        public class Object {
    
        //注意:當源碼中一個方法以“;”結尾,并且修飾符清單中有“native”關鍵字時
        //表示底層調用C++寫的dll程式(dll動态連結庫檔案)
        private static native void registerNatives();
    
        //靜态代碼塊
        static {
            //調用registerNatives方法
            registerNatives();
        }
    
        //無參數構造方法
        @HotSpotIntrinsicCandidate
        public Object() {}
    
        //底層也是調用C++
        @HotSpotIntrinsicCandidate
        public final native Class<?> getClass();
    
        //底層也是調用C++
        @HotSpotIntrinsicCandidate
        public native int hashCode();
    
        //equals方法應該看懂
        //public是公開的、boolean是方法的傳回值類型、equals是一個方法名,意思是:相等。
        //(Object obj) 形參
        //隻不過目前還不知道這個方法存在的意義。
        public boolean equals(java.lang.Object obj) {
            //方法體
            return (this == obj);
        }
    
        //已有對象a,想建立一個和a一模一樣的對象,你可以調用這個克隆方法。
        //底層也是調用C++
        @HotSpotIntrinsicCandidate
        protected native java.lang.Object clone() throws CloneNotSupportedException;
    
    
        //一會可以測試一下toString()方法
        //public 表示公共的、String是傳回值類型、toString()方法執行結束之後傳回一個字元串。
        //toString是方法名,()表示形參個數為0。
        public String toString() {
            return getClass().getName() + "@" + Integer.toHexString(hashCode());
        }
    
        @HotSpotIntrinsicCandidate
        public final native void notify();
    
    
        @HotSpotIntrinsicCandidate
        public final native void notifyAll();
    
    
        public final void wait() throws InterruptedException {
            wait(0L);
        }
    
        public final native void wait(long timeoutMillis) throws InterruptedException;
    
        public final void wait(long timeoutMillis, int nanos) throws InterruptedException {
            if (timeoutMillis < 0) {
                throw new IllegalArgumentException("timeoutMillis value is negative");
            }
    
            if (nanos < 0 || nanos > 999999) {
                throw new IllegalArgumentException(
                        "nanosecond timeout value out of range");
            }
    
            if (nanos > 0) {
                timeoutMillis++;
            }
    
            wait(timeoutMillis);
        }
    
        @Deprecated(since="9")
        protected void finalize() throws Throwable { }
    }
    
    
     */
    
    //
    public class ExtendsTest04 {
    
    //    ExtendsTest04中預設繼承Object
    //    ExtendsTest04類當中是有toString()方法
    //    不過toString()方法是一個執行個體方法,需要建立對象才能調用。
        public String toString() {
            return getClass().getName() + "@" + Integer.toHexString(hashCode());
        }
    
        public static void main(String[] args){
            //分析這個代碼可以執行嗎?
            //ExtendsTest04.toStirng();   //報錯
    
            //先new對象
            ExtendsTest04 et = new ExtendsTest04();
            String retValue = et.toString();//傳回String類型的值,定義一個變量接收
            System.out.println(retValue);//[email protected]        
            //1b6d3586  可以“等同”看做對象在堆記憶體中的記憶體位址
            //實際上是記憶體位址經過“雜湊演算法”得出的十六進制結果
    
            //建立對象
            Product1 p = new Product1();
            System.out.println(p.toString());//[email protected]
    
            System.out.println(100);
            System.out.println(true);
            //如果直接輸出“引用”呢?
            //直接輸出引用,會自動調用這個引用的toString()方法
            System.out.println(p);//[email protected]
            //println方法會自動調用p的toString()方法
        }
    }
    class Product1{
        /*
        public String toString() {
            return getClass().getName() + "@" + Integer.toHexString(hashCode());
        }
         */
        }