1. 程式人生 > >【小家java】類中靜態程式碼塊、構造程式碼塊、靜態變數執行順序和繼承邏輯

【小家java】類中靜態程式碼塊、構造程式碼塊、靜態變數執行順序和繼承邏輯

相關閱讀

每篇一句

上帝給每個人都安排了幸福的一生,我們的任務就是把它走完

1、概述

誠如各位所知,java的三大特性:封裝、繼承、多型。其中繼承,是java中最有學問的一點也是最相對來說最難理解的一些東西,本文針對於此,做一些例項分析,希望能夠幫助大家理解java中的繼承機制

2、栗子

情況一:當父類和子類有同名同類型的屬性時,使用時需要注意

public class Main {
    public static void main(String[] args) {
        Parent chidParent = new Child();
        System.out.
println("Parent:" + chidParent.getAge()); //40 System.out.println("Parent:" + chidParent.age); //18 這個結果你能接受嗎?哈哈 Child child = Child.class.cast(chidParent); System.out.println("Child:" + child.getAge()); //40 System.out.println("Child:" + child.age); //40 } } @Getter @Setter
class Child extends Parent { Integer age = 40; //名稱和父類的同名 } @Getter @Setter class Parent { Integer age = 18; }

我們發現,那個18為什麼會輸出出來呢?父類和子類的變數是同時存在的,即使是同名。子類中看到的是子類的變數,父類中看到的是父類中的變數,它們互相隱藏,而同名的方法則是實實在在的覆蓋(重寫),屬性不存在重寫喲。有了這個解釋,就好理解了吧
情況二:當父類和子類有同名***不同型別***的屬性時,使用時需要注意

public class Main {
    public
static void main(String[] args) { // 報錯Error:(20, 12) java: com.sayabc.boot2demo1.main.Child中的getAge() // 無法覆蓋com.sayabc.boot2demo1.main.Parent中的getAge() // 返回型別java.lang.String與java.lang.Integer不相容 Parent chidParent = new Child(); } } @Getter class Child extends Parent { String age = "40"; //名稱和父類的同名 public void setAge(String age) { this.age = age; } } @Getter class Parent { Integer age = 18; public void setAge(Integer age) { this.age = age; } }

我們高興的發現,如果型別不同,編譯器還發現不了,但是一執行,就報錯啦。這算編譯器的bug嗎?哈哈
情況三:繼承中最基本的類載入順序,不做過多解釋。靜態程式碼塊只執行一次,並且優先於mai方法先執行

public class Main {
    public static void main(String[] args) {
        Parent chidParent = new Child();
    }
}

@Getter
class Child extends Parent {

    static {
        System.out.println("Child的靜態塊");
    }

    {
        System.out.println("Child的構造塊");
    }

    Child() {
        System.out.println("Child的構造方法");
    }
}

@Getter
class Parent {
    Integer age = 18;

    static {
        System.out.println("Parent的靜態塊");
    }

    {
        System.out.println("Parent的構造塊");
    }

    Parent() {
        System.out.println("Parent的構造方法");
    }
}

結果如下:

Parent的靜態塊
Child的靜態塊
Parent的構造塊
Parent的構造方法
Child的構造塊
Child的構造方法

備註:此處需要注意,此處子類沒有顯示呼叫super(),但父類的構造還是執行了的。但是,但是,但是,如果構造快為有參構造,請記得顯示呼叫super方法,否則父類是不能被初始化的。如果子類的構造器沒有顯示地呼叫超類的構造器,則將自動呼叫超類預設(沒有引數) 的構造器。如果超類沒有不帶引數的構造器,並且在子類的構造器又沒有顯式地呼叫超類的其他構造器,則 java 編譯器將報告錯誤

情況四:子類和父類有同名同類型的靜態常量的時候

public class Main {
    public static void main(String[] args) {
        Parent parent = new Child();
        System.out.println(parent.name); //fangshixiangParent
        Child child = new Child();
        System.out.println(child.name); //fangshixiangChild
    }
}

@Getter
@Setter
class Child extends Parent {
    static String name = "fangshixiangChild";
}

@Getter
@Setter
class Parent {
    static String name = "fangshixiangParent";
}

有了前面的基礎,這個現象就很好解釋了。同理:當有同名不同型別的屬性時,直接獲取屬性還是會各自獲取到自己的,但get方法就不行,就會報錯了。
情況五:靜態程式碼塊屬於類的,並且優先於main方法執行

public class StaticDemo1 {                             

    public static void main(String[] args) {
        StaticDemo1 t1=new StaticDemo1();    //第2步,初始化建構函式,i=9
        System.out.println(t1.i);            //第3步,按順序執行,9
        speak();                            //第4步,按順序執行,呼叫靜態函式
        
    }    
    static int i=1;                            //靜態變數存到靜態區域。    
    static void speak()                        //靜態函式存到靜態區域。呼叫時執行。
    {
        System.out.println("a");;
    }
    static {                                //第1步,靜態程式碼塊隨著類的載入,優先執行且只執行一次。i=3,i+3列印結果是4。
        i=i+3;
        System.out.println(i);
    }
    
    public StaticDemo1(){                    //構造方法,初始化時執行。
        i=i+5;                                //i=9
        System.out.println(i);    
    }
}

但是,但是,但是。如果StaticDemo1沒有new或者靜態方法沒有呼叫,靜態程式碼塊是不會被執行的哦,只有載入了才會執行,並且只執行一次
static塊真正的執行時機。如果瞭解JVM原理,我們知道,一個類的執行分為以下步驟:static程式碼塊真正執行時機
下面我們看看執行static塊的幾種情況:
1、第一次new A()的過程會列印"";因為這個過程包括了初始化
2、第一次Class.forName(“A”)的過程會列印"";因為這個過程相當於Class.forName(“A”,true,this.getClass().getClassLoader());
3、第一次Class.forName(“A”,false,this.getClass().getClassLoader())的過程則不會列印""。因為false指明瞭裝載類的過程中,不進行初始化。不初始化則不會執行static塊。

最後,附上兩張圖,大家可以明顯發發現一些端倪,希望對大家能有記憶作用哈:

圖一:構造程式碼塊是在初始化物件屬性(成員變數)之前執行的
這裡寫圖片描述
圖二:@PostConstruct是物件的屬性都初始化ok了才去執行的。
這裡寫圖片描述
特別的,這裡我介紹一下各種註解影響的執行順序,如下程式碼:

@Component  
public class InitBeanTest implements InitializingBean,ApplicationListener<ContextRefreshedEvent> {  
  
    @Resource  
    DemoService demoService;  
      
    public InitBeanTest() {     
           System.err.println("----> InitSequenceBean: constructor: "+demoService);     
        }  
  
    @PostConstruct  
    public void postConstruct() {  
        System.err.println("----> InitSequenceBean: postConstruct: "+demoService);  
    }  
  
    @Override  
    public void afterPropertiesSet() throws Exception {  
        System.err.println("----> InitSequenceBean: afterPropertiesSet: "+demoService);  
    }  
  
    @Override  
    public void onApplicationEvent(ContextRefreshedEvent arg0) {  
        System.err.println("----> InitSequenceBean: onApplicationEvent");  
    }  
  
}  

執行結果:

----> InitSequenceBean: constructor: null
----> InitSequenceBean: postConstruct: com.yiniu.kdp.service.impl.DemoServiceImpl@40fe544
----> InitSequenceBean: afterPropertiesSet: com.yiniu.kdp.service.impl.DemoServiceImpl@40fe544
----> InitSequenceBean: onApplicationEvent
----> InitSequenceBean: onApplicationEvent

根據執行結果,我們很容易的總結出來執行的順序。至於是什麼原因呢,下面給出一個簡單分析:

建構函式是每個類最先執行的,這個時候,bean屬性還沒有被注入。
postConstruct優先於afterPropertiesSet執行,這時屬性竟然也被注入了,這個時候需要記住啦
spring很多組建的初始化都放在afterPropertiesSet做。我們在做一些中介軟體想和spring一起啟動,可以放在這裡啟動。比如獲取到ApplicationContext上下文
onApplicationEvent屬於應用層的事件,最後被執行,很容易理解。注意,它出現了兩次,為什麼?因為bean注入了DemoService,spring容器會被重新整理。這個很容易被當作高階面試題的喲。換言之onApplicationEvent會被頻繁執行,需要使用它監聽,需要考慮效能問題以及重複執行的問題。很顯然,這是觀察者模式的經典應用。至於spring中觀察者模式的使用,我在後續文章中會重點分享,請持續關注

3、使用場景

各種設計模式,都會以此為依託,才能有更好的設計

4、最後

java的三大特性都非常的重要,如果不理解虛擬機器對類的一些處理,有時候會犯迷糊,影響邏輯的設計,所以此文用簡單用例希望能幫助大家理解。日後也許會持續更新

知識交流

在這裡插入圖片描述

若群二維碼失效,請加微訊號(或者掃描下方二維碼):fsx641385712。
並且備註:“java入群” 字樣,會手動邀請入群

在這裡插入圖片描述

相關推薦

java靜態程式碼構造程式碼靜態變數執行順序繼承邏輯

相關閱讀 每篇一句 上帝給每個人都安排了幸福的一生,我們的任務就是把它走完 1、概述 誠如各位所知,java的三大特性:封裝、繼承、多型。其中繼承,是java中最有學問的一點也是最相對來說最難理解的一些東西,本文針對於此,做一些例項分析,希望能夠幫助大家

javajava維護常量使用常量?介面?還是列舉呢?

相關閱讀 每篇一句 只要學不死,就往死裡學。我們離過勞死都還遠著呢 1、概述 在編碼過程中,避免不了維護一些常量。而通過這麼多的專案中發現,使用方式都不盡相同。有用常量類的、有用介面的、有用列舉的,因此本文針對於常量的管理做一些討論 2、栗子 第一種使用

javaJava對時間戳相加減的問題(向前推100天,答案卻讓我匪夷所思)

相關閱讀 【小家java】java5新特性(簡述十大新特性) 重要一躍 【小家java】java6新特性(簡述十大新特性) 雞肋升級 【小家java】java7新特性(簡述八大新特性) 不溫不火 【小家java】java8新特性(簡述十大新特性) 飽受讚譽 【小家java】java9

JavaFutureFutureTaskCompletionServiceCompletableFuture解決多執行緒併發歸集問題的效率對比

相關閱讀 【小家java】java5新特性(簡述十大新特性) 重要一躍 【小家java】java6新特性(簡述十大新特性) 雞肋升級 【小家java】java7新特性(簡述八大新特性) 不溫不火 【小家java】java8新特性(簡述十大新特性) 飽受讚譽 【小家java】java9

javaJava執行緒(父執行緒)與子執行緒的通訊聯絡

相關閱讀 【小家java】java5新特性(簡述十大新特性) 重要一躍 【小家java】java6新特性(簡述十大新特性) 雞肋升級 【小家java】java7新特性(簡述八大新特性) 不溫不火 【小家java】java8新特性(簡述十大新特性) 飽受讚譽 【小家java】java9

javaJava執行緒池,你真的用對了嗎?(教你用正確的姿勢使用執行緒池)

相關閱讀 【小家java】java5新特性(簡述十大新特性) 重要一躍 【小家java】java6新特性(簡述十大新特性) 雞肋升級 【小家java】java7新特性(簡述八大新特性) 不溫不火 【小家java】java8新特性(簡述十大新特性) 飽受讚譽 【小家java】java9

javaJavaApache Commons-Collections4使用精講(對JDK集合功能的強有力擴充套件)

相關閱讀 前言 雖然JDK提供給我們的集合框架已經足夠強大,基本能解決我們平時的絕大所述問題,並且效率還挺高。 本文針對於Apache提供的Collections4元件提供的一些特殊資料結構,通過例子解決一些實際問題的講解。 ® bag介面 ® 固定大小的m

Javacommon-lang3StringUtils的使用詳解

相關閱讀 前言 上一篇博文已經講解了lang3下面的很多的API,但是StringUtils留在本文專門講解。因為這個工具類在日常使用中實在太多了。 本文的講解方式為:直接看例項,而不做過多的文字描述解釋 例項 public static boolean i

java一個基於POI的Excel的匯入匯出工具處理(支援xls,xlsx格式),另有SpringMVC的匯入匯出案例講解

相關閱讀 前言 表格的匯入、匯出可謂開發過程中經常會碰到的功能。然後這種模版化的東西並不需要每次都去編碼一次,因此我就整理了一個Excel的萬能處理類。能夠實現相容2003、2007的各種Excel格式的匯入匯出功能,使用起來也非常的方面,適用於所有業務場景

java Restful風格的API設計,怎麼實現批量刪除?

相關閱讀 每篇一句 面試高大上,面試造飛機,工作擰螺絲 因此不能以為自己工作覺得還OK,就覺得自己技術還不錯了 如題,指的是在restful風格的url設計中,怎麼實現批量刪除呢? 這裡指的刪除是真刪除,不是邏輯刪除。如果是邏輯刪除,其實就是upd

javaString為什麼要設計成final?不可變有什麼優點?

相關閱讀 原始碼解釋: 先貼一下String類的申明程式碼: public final class String implements java.io.Serializable, Comparable<String>, CharSeque

javaJava二進位制與位運算(“^,&,>>,>>>”),使用移位演算法寫一個流水號生成器(訂單號生成器)

相關閱讀 每篇一句 高樓大廈,都是平地起的。 整個java體系,其實就是一本祕籍,那就是:java基礎! (基礎如果打的紮實,在實際開發工作中會帶來極大的助益) 二進位制 二進位制是計算技術中廣泛採用的一種數制。二進位制資料是用0和1兩個數碼來表示的

JavaFuture與FutureTask的區別與聯絡

相關閱讀 【小家java】java5新特性(簡述十大新特性) 重要一躍 【小家java】java6新特性(簡述十大新特性) 雞肋升級 【小家java】java7新特性(簡述八大新特性) 不溫不火 【小家java】java8新特性(簡述十大新特性) 飽受讚譽 【小家java】java9

javaPOP(面向過程程式設計)OOP(面向物件程式設計)AOP(面向切面程式設計)三種程式設計思想的區別聯絡

相關閱讀 【小家java】java5新特性(簡述十大新特性) 重要一躍 【小家java】java6新特性(簡述十大新特性) 雞肋升級 【小家java】java7新特性(簡述八大新特性) 不溫不火 【小家java】java8新特性(簡述十大新特性) 飽受讚譽 【小家java】java9

javaSessionCookie的區別聯絡分散式session的幾種實現方式

相關閱讀 【小家java】java5新特性(簡述十大新特性) 重要一躍 【小家java】java6新特性(簡述十大新特性) 雞肋升級 【小家java】java7新特性(簡述八大新特性) 不溫不火 【小家java】java8新特性(簡述十大新特性) 飽受讚譽 【小家java】java9

javaJava8新特性之---CompletableFuture的系統講解例項演示(使用CompletableFuture構建非同步應用)

相關閱讀 【小家java】java5新特性(簡述十大新特性) 重要一躍 【小家java】java6新特性(簡述十大新特性) 雞肋升級 【小家java】java7新特性(簡述八大新特性) 不溫不火 【小家java】java8新特性(簡述十大新特性) 飽受讚譽 【小家java】java9

javaJava之Apache Commons-Collections4使用精講(含有BagMapListSet全覆蓋)

相關閱讀 【小家java】java5新特性(簡述十大新特性) 重要一躍 【小家java】java6新特性(簡述十大新特性) 雞肋升級 【小家java】java7新特性(簡述八大新特性) 不溫不火 【小家java】java8新特性(簡述十大新特性) 飽受讚譽 【小家java】java9

javaBlockingQueue阻塞佇列詳解以及5大實現(ArrayBlockingQueueDelayQueueLinkedBlockingQueue...)

相關閱讀 【小家java】java5新特性(簡述十大新特性) 重要一躍 【小家java】java6新特性(簡述十大新特性) 雞肋升級 【小家java】java7新特性(簡述八大新特性) 不溫不火 【小家java】java8新特性(簡述十大新特性) 飽受讚譽 【小家java】java9

Java深入理解Java列舉型別(enum)及7種常見的用法(含EnumMapEnumSet)

相關閱讀 【小家java】java5新特性(簡述十大新特性) 重要一躍 【小家java】java6新特性(簡述十大新特性) 雞肋升級 【小家java】java7新特性(簡述八大新特性) 不溫不火 【小家java】java8新特性(簡述十大新特性) 飽受讚譽 【小家java】java9

Java一次Java執行緒池誤用(newFixedThreadPool)引發的線上血案總結

相關閱讀 【小家java】java5新特性(簡述十大新特性) 重要一躍 【小家java】java6新特性(簡述十大新特性) 雞肋升級 【小家java】java7新特性(簡述八大新特性) 不溫不火 【小家java】java8新特性(簡述十大新特性) 飽受讚譽 【小家java】java9