案例分析 --構造方法,程式碼塊,重寫 的應用
案例分析 –構造方法,程式碼塊,重寫 的應用
參考資料:
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=4;
2. 執行 構造塊
{
i=3;
System.out.println(i);------------------3
}
3. 執行 show();
由於 子類對其進行重寫,呼叫子類的
@Override
public void show() {
System.out.println(i);-------------0
}
而此時,子類還沒有 初始化,執行構造方法,所以 i=0;
- 執行 子類構造方法 初始化
public Son(int p) {
super(p); --已執行
super.show();
}
會執行
1. 初始化引數 int i=2;
2. 執行 構造塊
{
i=8;
System.out.println(i);------------------8
}
3. 執行 super.show();
呼叫 父類的方法
此時父類已完成初始化操作:
super.i=3
super.show();
public void show() {
System.out.println(i);-------------3
}
- 執行 son.show();
此時呼叫 子類的引用 son ,son.show() ,執行
@Override
public void show() {
System.out.println(i);------8
}
此時子類完成初始化操作 :i=8;
所以。。
基本概念:
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
- 構造塊:
將程式碼塊直接定義在類中,則稱為構造程式碼塊。
==構造塊優先於構造方法執行,且執行多次,只要一有例項化物件產生,就執行構造塊中的內容。==
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、構造方法。
- 靜態程式碼塊:
直接使用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、構造方法。
- 同步程式碼塊
同步程式碼塊主要出現在多執行緒中。
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);
}
}
“`