1. 程式人生 > >案例分析 --構造方法,程式碼塊,重寫 的應用

案例分析 --構造方法,程式碼塊,重寫 的應用

案例分析 –構造方法,程式碼塊,重寫 的應用

參考資料:

掌握java中的三種程式碼塊的定義及使用

java中構造方法和方法全面解析

1. 分析下面程式碼 的結果

    public class HDemo {
        public static void main(String[] args) {
            Person son=new Son(7);
            son.show();
        }

    }
    class Son extends  Person {
        int i = 2
; { i=8; System.out.println(i); } public Son(int p) { super(p); super.show(); } @Override public void show() { System.out.println(i); } } public abstract class Person { int
i=4; { i=3; System.out.println(i); } public Person(int p){ show(); } public void show(){ System.out.println(i); } }

2.結果為 3 ,0 ,8,3,8

3. 分析:

一. Person son=new Son(7);

該方法先獲取 Person 的引用 son ,例項化 Son () 物件

new Son() 主要過程
1. 呼叫 super(p) 的實現


 會執行 Person 的構造方法   
     public Person(int p){
            show();

        }
 主要過程:
    在執行 super(),Object 的構造方法後執行:

    1. 初始化引數 int i=42. 執行 構造塊

     {
           i=3;
            System.out.println(i);------------------3
        }

    3. 執行 show();

    由於 子類對其進行重寫,呼叫子類的
    @Override
        public void show() {
            System.out.println(i);-------------0
        }

    而此時,子類還沒有 初始化,執行構造方法,所以 i=0;
  1. 執行 子類構造方法 初始化
  public Son(int p) {
            super(p); --已執行
            super.show();
        }

會執行

  1. 初始化引數 int i=22. 執行 構造塊

     {
           i=8;
            System.out.println(i);------------------8
        }

    3. 執行  super.show();

   呼叫 父類的方法 
  此時父類已完成初始化操作:
        super.i=3
        super.show();
        public void show() {
            System.out.println(i);-------------3
        }
  1. 執行 son.show();
此時呼叫 子類的引用 son ,son.show() ,執行

        @Override
        public void show() {
            System.out.println(i);------8
        }

    此時子類完成初始化操作 :i=8;
    所以。。

基本概念:

1. 程式碼塊的概念

程式碼塊本身並不是一個很難理解的概念,實際上之前也一直在使用。所謂程式碼塊是指使用“{}”括起來的一段程式碼,根據位置不同,程式碼塊可以分為四種:普通程式碼塊、構造塊、靜態程式碼塊、同步程式碼塊,其中同步程式碼塊本書將在多執行緒部分進行講解,本章先來觀察其他三種程式碼塊。

  1. 普通程式碼塊

直接定義在方法中的程式碼塊稱為普通程式碼塊。

public class CodeDemo01{
 public static void main(String args[]){
  {  // 普通程式碼塊
   int x = 30 ; // 就屬於一個區域性變數
   System.out.println("普通程式碼塊 --> x = " + x) ;
  }
  int x = 100 ;  // 與區域性變數名稱相同
  System.out.println("程式碼塊之外 --> x = " + x) ;
 }
};

執行結果:

C:\Documents and Settings\Administrator\桌面\java>java CodeDemo01
普通程式碼塊 --> x = 30
程式碼塊之外 --> x = 100
  1. 構造塊:

將程式碼塊直接定義在類中,則稱為構造程式碼塊。

==構造塊優先於構造方法執行,且執行多次,只要一有例項化物件產生,就執行構造塊中的內容。==

class Demo{
 { // 直接在類中編寫程式碼塊,稱為構造塊
  System.out.println("1、構造塊。") ;
 }
 public Demo(){ // 定義構造方法
  System.out.println("2、構造方法。") ;
 }
};
public class CodeDemo02{
 public static void main(String args[]){
  new Demo() ;  // 例項化物件
  new Demo() ;  // 例項化物件
  new Demo() ;  // 例項化物件
 }
};

執行結果:

C:\Documents and Settings\Administrator\桌面\java>java CodeDemo02
1、構造塊。
2、構造方法。
1、構造塊。
2、構造方法。
1、構造塊。
2、構造方法。
  1. 靜態程式碼塊:

直接使用static關鍵字宣告就稱為靜態程式碼塊.

==靜態塊優先於主方法執行,如果在普通類中定義的靜態塊,優先於構造塊執行,不管不多少個例項化物件產生,靜態程式碼塊只執行一次,靜態程式碼塊的主要功能就是為靜態發生初始化。==

class Demo{
 { // 直接在類中編寫程式碼塊,稱為構造塊
  System.out.println("1、構造塊。") ;
 }
 static{ // 使用static,稱為靜態程式碼塊
  System.out.println("0、靜態程式碼塊") ;
 }
 public Demo(){ // 定義構造方法
  System.out.println("2、構造方法。") ;
 }
};
public class CodeDemo03{
 static{  // 在主方法所在的類中定義靜態塊
  System.out.println("在主方法所在類中定義的程式碼塊") ;
 }
 public static void main(String args[]){
  new Demo() ;  // 例項化物件
  new Demo() ;  // 例項化物件
  new Demo() ;  // 例項化物件
 }
};

執行結果:

C:\Documents and Settings\Administrator\桌面\java>java CodeDemo03
在主方法所在類中定義的程式碼塊
0、靜態程式碼塊
1、構造塊。
2、構造方法。
1、構造塊。
2、構造方法。
1、構造塊。
2、構造方法。
  1. 同步程式碼塊
     同步程式碼塊主要出現在多執行緒中。

2. 重寫

方法的重寫:

1、在子類中可以根據需要對從基類中繼承來的方法進行重寫。

2、重寫的方法和被重寫的方法必須具有相同方法名稱、引數列表和返回型別。

3、重寫方法不能使用比被重寫的方法更嚴格的訪問許可權。

3.構造方法

個人理解: 呼叫 super 方法類似 呼叫 遞迴方法 ,有前進,有返回,到頂 為 object (遞迴頭–遞迴條件)

==構造方法能被呼叫,不能被繼承。==

初始化的順序包括構造方法呼叫的順序如下:

  1.主類的靜態成員首先初始化。
  2.主類的超類的構造方法按照從最高到最低的順序被呼叫。
  3.主類的非靜態物件(變數)初始化。
  4.呼叫主類的構造方法

特點:


1.構造器必須與類同名(如果一個原始檔中有多個類,那麼構造器必須與公共類同名)

2.每個類可以有一個以上的構造器

3.構造器可以有0個、1個或1個以上的引數

4.構造器沒有返回值

5.構造器總是伴隨著new操作一起呼叫

 ```

 ==構造方法和方法的區別:==

構造方法要與類名相同,無返回型別,在類初始化的時候呼叫。
方法最好與類名不同,物件呼叫,靜態方法可用類名.方法().

構造器和方法在下面三個方面區別:修飾符,返回值,命名:
   1。和方法一樣,構造器可以有任何訪問的修飾: public, protected, private或者沒有修飾(通常被package 和 friendly呼叫). 不同於方法的是,構造器不能有以下非訪問性質的修飾: abstract, final, native, static, 或者 synchronized。 
    2。返回型別也是非常重要的。方法能返回任何型別的值或者無返回值(void),構造器沒有返回值,也不需要void。 
    3。兩者的命名。構造器使用和類相同的名字,而方法則不同。按照習慣,方法通常用小寫字母開始,而構造器通常用大寫字母開始。構造器通常是一個名詞,因為它和類名相同;而方法通常更接近動詞,因為它說明一個操作。

 構造方法和方法中this和supper的用法區別: 
 > "this"的用法 
    構造器和方法使用關鍵字this有很大的區別。方法引用this指向正在執行方法的類的例項。靜態方法不能使用this關鍵字,因為靜態方法不屬於類的實  例,所以this也就沒有什麼東西去指向。構造器的this指向同一個類中,不同引數列表的另外一個構造器,我們看看下面的程式碼: 

package com.dr.gouzao;

public class Platypus {
String name;

Platypus(String input) {
    name = input;
}

Platypus() {
    this("John/Mary Doe");
}

public static void main(String args[]) {
    Platypus p1 = new Platypus("digger");
    Platypus p2 = new Platypus();
    System.out.println(p1.name + "----" + p2.name);
}

}
在上面的程式碼中,有2個不同引數列表的構造器。第一個構造器,給類的成員name賦值,第二個構造器,呼叫第一個構造器,給成員變數name一個初始值 “John/Mary Doe”.

在構造器中,如果要使用關鍵字this,那麼,必須放在第一行,如果不這樣,將導致一個編譯錯誤。
在一個構造方法中只能呼叫一次其它的構造方法,並且呼叫構造方法的語句必須是第一條語句。

>   "super"的用法 

   構造器和方法,都用關鍵字super指向超類,但是用的方法不一樣。方法用這個關鍵字去執行被過載的超類中的方法。看下面的例子:

   構造器使用super去呼叫超類中的構造器。而且這行程式碼必須放在第一行,否則編譯將出錯。看下面的例子:

public class SuperClassDemo {
SuperClassDemo() {
}
}

class Child extends SuperClassDemo {
Child() {
super();
}
}
在上面這個沒有什麼實際意義的例子中,構造器 Child()包含了 super,它的作用就是將超類中的構造器SuperClassDemo例項化,並加到 Child類中。

編譯器自動加入程式碼 ,當我們寫一個沒有構造器的類,編譯的時候,編譯器會自動加上一個不帶引數的構造器。



2. 介紹物件的初始化順序問題。

class One
{
One(String str)
{
System.out.println(str);
}
}
class Two
{
One one_1 = new One(“one-1”);
One one_2 = new One(“one-2”);
One one_3 = new One(“one-3”);
Two(String str)
{
System.out.println(str);
}
}
public class Test
{
public static void main(String[] args)
{
System.out.println(“Test main() start”);
Two two = new Two(“two”);
}
}

輸出結果:
Test main() start…
one-1
one-2
one-3
two

> 在main()方法中例項化了一個Two類的物件。但程式在初始化Two類的物件時,並非先呼叫Two類的構造方法,而是先初始化Two類的成員變數。這裡Two類有3個成員變數,它們都是One類的物件,所以要先呼叫3次One類的相應的構造方法。最後在初始化Two類的物件。
 即在建立物件時,物件所在類的所有資料成員會首先進行初始化,如果其中的成員變數有物件,那麼它們也會按照順序執行初始化工作。在所有類成員初始化完成後,才呼叫物件所在類的構造方法建立物件。構造方法作用就是初始化。

4. 靜態順序
    如果一個類中有靜態物件,那麼它會在非靜態物件前初始化,但只初始化一次。非靜態物件每次呼叫時都要初始化。

class One

{
One(String str)
{
System.out.println(str);
}
}
class Two
{
One one_1 = new One(“one-1”);
One one_2 = new One(“one-2”);
static One one_3 = new One(“one-3”);
Two(String str)
{
System.out.println(str);
}
}
public class Test
{
public static void main(String[] args)
{
System.out.println(“Test main() start”);
Two two_1 = new Two(“two-1”);
System.out.println(“————”);
Two two_2 = new Two(“two-2”);
}
}
輸出結果:
Test main() start…
one-3
one-1
one-2

two-1

one-1
one-2
two-2
  

5. 不僅第1次建立物件時,類中所有的靜態變數要初始化,第1次訪問類中的靜態變數(沒有建立物件)時,該類中所有的靜態變數也要按照它們在類中排列的順序初始化。

class One
{
One(String str)
{
System.out.println(str);
}
}
class Two
{
static int i = 0;
One one_1 = new One(“one-1”);
static One one_2 = new One(“one-2”);
static One one_3 = new One(“one-3”);
Two(String str)
{
System.out.println(str);
}
}
public class Test
{
public static void main(String[] args)
{
System.out.println(“Test main() start”);
System.out.println(“Two.i = ” Two.i);
}
}
“`