国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看av不卡

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術(shù)|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務(wù)器之家 - 編程語言 - Java教程 - java對象初始化代碼詳解

java對象初始化代碼詳解

2021-02-05 11:19hapjin Java教程

這篇文章主要介紹了java對象初始化代碼詳解,涉及實例變量的初始化,類變量的初始化等相關(guān)介紹幾代碼示例,具有一定參考價值,需要的朋友可以了解下。

本文主要記錄JAVA中對象初始化過程,包括實例變量的初始化和類變量的初始化以及final關(guān)鍵字對初始化的影響。另外,還討論了由于繼承原因,探討了引用變量的編譯時類型和運行時類型

一,實例變量的初始化

這里首先介紹下創(chuàng)建對象的過程:

類型為Dog的一個對象首次創(chuàng)建時,或者Dog類的static字段或static方法首次訪問時,Java解釋器必須找到Dog.class(在事先設(shè)定好的路徑里面搜索); 
找到Dog.class后(它會創(chuàng)建一個Class對象),它的所有static初始化模塊都會運行。因此,static初始化僅發(fā)生一次——在Class對象首次載入的時候; 
創(chuàng)建一個newDog()時,Dog對象的構(gòu)建進程首先會在內(nèi)存堆(Heap)里為一個Dog對象分配足夠多的存儲空間; 
這種存儲空間會清為零,將Dog中的所有基本類型(Primitive)設(shè)為它們的默認值(0用于數(shù)字,以及boolean和char的等價設(shè)定); 
進行成員字段定義時發(fā)生的所有初始化都會執(zhí)行; 
執(zhí)行構(gòu)造函數(shù)。

然后,開始對實例變量進行初始化。一共有三種方式對實例變量進行初始化:

①定義實例變量時指定初始值

②非靜態(tài)初始化塊中對實例變量進行初始化

③構(gòu)造器中對實例變量進行初始化

當new對象初始化時,①②要先于③執(zhí)行。而①②的順序則按照它們在源代碼中定義的順序來執(zhí)行。

當實例變量使用了final關(guān)鍵字修飾時,如果是在定義該final實例變量時直接指定初始值進行的初始化(第①種方式),則:該變量的初始值在編譯時就被確定下來,那么該final變量就類似于“宏變量”,相當于JAVA中的直接常量。

java" id="highlighter_124877">
?
1
2
3
4
5
6
7
8
9
10
public class Test {
  public static void main(String[] args) {
    final String str1 = "HelloWorld";
    final String str2 = "Hello" + "World";
    System.out.println(str1 == str2);//true
    
    final String str3 = "Hello" + String.valueOf("World");
    System.out.println(str1 == str3);//false
  }
}

第8行輸出false,是因為:第7行中str3需要通過valueOf方法調(diào)用之后才能確定。而不是在編譯時確定。

再來看一個示例:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class Test {
  
  final String str1 = "HelloWorld";
  final String str2 = "Hello" + "World";
  final String str3;
  final String str4;
  {
    str3 = "HelloWorld";
  }
  {
    System.out.println(str1 == str2);//true
    System.out.println(str1 == str3);//true
//    System.out.println(str1 == str4);//compile error
  }
  public Test() {
    str4 = "HelloWorld";
    System.out.println(str1 == str4);//true
  }
  
  public static void main(String[] args) {
    new Test();
  }
}

把第13行的注釋去掉,會報編譯錯誤“Theblankfinalfieldstr4maynothavebeeninitialized”

因為變量str4是在構(gòu)造器中進行初始化的。而前面提到:①定義實例變量時直接指定初始值(str1和str2的初始化)、②非靜態(tài)初始化塊中對實例變量進行初始化(str3的初始化)要先于③構(gòu)造器中對實例變量進行初始化。

另外,對于final修飾的實例變量必須顯示地對它進行初始化,而不是通過構(gòu)造器(<clinit>)對之進行默認初始化。

?
1
2
3
4
public class Test {
   final String str1;//compile error---沒有顯示的使用①②③中的方式進行初始化
   String str2;
 }

str2可以通過構(gòu)造器對之進行默認的初始化,初始化為null。而對于final修飾的變量 str1,必須顯示地使用 上面提到的三種方式進行初始化。如下面的這個Test.java(一共有22行的這個Test類)

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class Test {
  final String str1 = "Hello";//定義實例變量時指定初始值
  
  final String str2;//非靜態(tài)初始化塊中對實例變量進行初始化
  final String str3;//構(gòu)造器中對實例變量進行初始化
  
  {
    str2 = "Hello";
  }
  public Test() {
    str3 = "Hello";
  }
  
  public void show(){
    System.out.println(str1 + str1 == "HelloHello");//true
    System.out.println(str2 + str2 == "HelloHello");//false
    System.out.println(str3 + str3 == "HelloHello");//false
  }
  public static void main(String[] args) {
    new Test().show();
  }
}

由于str1采用的是第①種方式進行的初始化,故在執(zhí)行15行:str1+str1連接操作時,str1其實相當于“宏變量”

而str2和str3并不是“宏變量”,故16-17行輸出false

在非靜態(tài)初始化代碼塊中初始化變量和在構(gòu)造器中初始化變量的一點小區(qū)別:因為構(gòu)造器是可以重寫的,比如你把某個實例變量放在無參的構(gòu)造器中進行初始化,但是在new對象時卻調(diào)用的是有參數(shù)的構(gòu)造器,那就得注意該實例變量有沒有正確得到初始化了。

而放在非靜態(tài)初始化代碼塊中初始化變量時,不管是調(diào)用有參的構(gòu)造器還是無參的構(gòu)造器,非靜態(tài)初始化代碼塊都會執(zhí)行。

二,類變量的初始化

類變量一共有兩個地方對之進行初始化:

?定義類變量時指定初始值

?靜態(tài)初始化代碼塊中進行初始化

不管new多少個對象,類變量的初始化只執(zhí)行一次。

三,繼承對初始化的影響

主要是理解編譯時類型和運行時類型的不同,從這個不同中可以看出this關(guān)鍵字和super關(guān)鍵字的一些本質(zhì)區(qū)別。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
class Fruit{
  String color = "unknow";
  public Fruit getThis(){
    return this;
  }
  public void info(){
    System.out.println("fruit's method");
  }
}
 
public class Apple extends Fruit{
 
  String color = "red";//與父類同名的實例變量
  
  @Override
  public void info() {
    System.out.println("apple's method");
  }
  
  public void accessFruitInfo(){
    super.info();
  }
  public Fruit getSuper(){
    return super.getThis();
  }
  
  //for test purpose
  public static void main(String[] args) {
    Apple a = new Apple();
    Fruit f = a.getSuper();
    
    //Fruit f2 = a.getThis();
    //System.out.println(f == f2);//true
    
    System.out.println(a == f);//true
    System.out.println(a.color);//red
    System.out.println(f.color);//unknow
    
    a.info();//"apple's method"
    f.info();//"apple's method"
    
    a.accessFruitInfo();//"fruit's method"
  }
}

值得注意的地方有以下幾個:

⒈第35行引用變量a和f都指向內(nèi)存中的同一個對象,36-37行調(diào)用它們的屬性時,a.color是red,而f.color是unknow

因為,f變量的聲明類型(編譯時類型)為Fruit,當訪問屬性時是由聲明該變量的類型來決定的。

⒉第39-40行,a.info()和f.info()都輸出“apple'smethod”

因為,f變量的運行時類型為Apple,info()是Apple重載的父類的一個方法。調(diào)用方法時由變量的運行時類型來決定。

⒊關(guān)于this關(guān)鍵字

當在29行new一個Apple對象,在30行調(diào)用getSuper()方法時,最終是執(zhí)行到第4行的returnthis

this的解釋是:返回調(diào)用本方法的對象。它返回的類型是Fruit類型(見getThis方法的返回值類型),但實際上是Apple對象導致的getThis方法的調(diào)用。故,這里的this的聲明類型是Fruit,而運行時類型是Apple

⒋關(guān)于super關(guān)鍵字

super與this是有區(qū)別的。this可以用來代表“當前對象”,可用return返回。而對于super而言,沒有returnsuper;這樣的語句。

super主要是為了:在子類中訪問父類中的屬性或者在子類中調(diào)用父類中的方法而引入的一個關(guān)鍵字。比如第24行。

⒌在父類的構(gòu)造器中不要去調(diào)用被子類覆蓋的方法(Override),或者說在構(gòu)造父類對象時,不要依賴于子類覆蓋了父類的那些方法。這樣很可能會導致初始化的失敗(沒有正確地初始化對象)

因為:前面第1點和第2點談到了,對象(變量)有聲明時類型(編譯時類型)和運行時類型。而方法的調(diào)用取決于運行時類型。

當new子類對象時,會首先去初始化父類的屬性,而此時對象的運行時類型是子類,因此父類的屬性的賦值若依賴于子類中重載的方法,會導致父類屬性得不到正確的初始化值。示例如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
class Fruit{
    String color;
    
    public Fruit() {
      color = this.getColor();//父類color屬性初始化依賴于重載的方法getColor
//      color = getColor();
    }
    public String getColor(){
      return "unkonw";
    }
    
    @Override
    public String toString() {
      return color;
    }
  }
  
  public class Apple extends Fruit{
  
    @Override
    public String getColor() {
      return "color: " + color;
    }
    
//    public Apple() {
//      color = "red";
//    }
    
    public static void main(String[] args) {
      System.out.println(new Apple());//color: null
    }
  }

Fruit類的color屬性 沒有正確地被初始化為"unknow",而是為 null

主要是因為第5行 this.getColor()調(diào)用的是Apple類的getColor方法,而此時Apple類的color屬性是直接從Fruit類繼承的。

四,參考資料

瘋狂Java 突破程序員基本功的16課  第二章

Effective Java中文版 第2版 中文 PDF版    第二版第17條

原文鏈接:https://www.cnblogs.com/hapjin/p/5931220.html

延伸 · 閱讀

精彩推薦
Weibo Article 1 Weibo Article 2 Weibo Article 3 Weibo Article 4 Weibo Article 5 Weibo Article 6 Weibo Article 7 Weibo Article 8 Weibo Article 9 Weibo Article 10 Weibo Article 11 Weibo Article 12 Weibo Article 13 Weibo Article 14 Weibo Article 15 Weibo Article 16 Weibo Article 17 Weibo Article 18 Weibo Article 19 Weibo Article 20 Weibo Article 21 Weibo Article 22 Weibo Article 23 Weibo Article 24 Weibo Article 25 Weibo Article 26 Weibo Article 27 Weibo Article 28 Weibo Article 29 Weibo Article 30 Weibo Article 31 Weibo Article 32 Weibo Article 33 Weibo Article 34 Weibo Article 35 Weibo Article 36 Weibo Article 37 Weibo Article 38 Weibo Article 39 Weibo Article 40
主站蜘蛛池模板: 国产成人精品一区二区三区视频 | 午夜精品在线 | 欧美乱大交xxxxx春色视频 | 俺去操| 亚洲精品自拍 | 日韩欧美一级 | 欧美一区二区在线 | 成人免费视频网址 | 久久精品网 | 国产亚洲精品精品国产亚洲综合 | 狠狠躁夜夜躁人人爽天天天天97 | 中文字幕在线永久在线视频 | 欧美精品一区二区三区蜜桃视频 | 精品福利视频网站 | 色中色综合 | 国产成年人视频 | 亚洲成av人片一区二区梦乃 | 一区二区三区亚洲 | 午夜成人免费电影 | 美国理论 | 成人小视频在线观看 | 精品一级 | 国产精品久久嫩一区二区免费 | 久久久久国产一区二区三区 | 91在线看片 | 一级片少妇 | 欧美日韩一区二区三区在线电影 | 日本一区二区视频免费观看 | 日韩在线视屏 | 免费成人在线观看视频 | 国产色毛片 | 成人精品国产一区二区4080 | 日日操夜夜操天天操 | 午夜精品 | 成人午夜网| 视频在线一区 | 日本一区二区精品 | 久久精品综合 | 日韩一区二区三区福利视频 | 亚洲人视频在线 | 久久合 |