最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java:"失效"的private修飾符

 更新時(shí)間:2016年08月31日 15:38:50   作者:技術(shù)小黑屋  
本文主要介紹Java 失效的private修飾符,這里整理了相關(guān)資料說(shuō)明private 修飾符的作用,如何使用并與C++ 做比較,有興趣的小伙伴可以參考下

在Java編程中,使用private關(guān)鍵字修飾了某個(gè)成員,只有這個(gè)成員所在的類和這個(gè)類的方法可以使用,其他的類都無(wú)法訪問(wèn)到這個(gè)private成員。

上面描述了private修飾符的基本職能,今天來(lái)研究一下private功能失效的情況。

Java內(nèi)部類

在Java中相信很多人都用過(guò)內(nèi)部類,Java允許在一個(gè)類里面定義另一個(gè)類,類里面的類就是內(nèi)部類,也叫做嵌套類。一個(gè)簡(jiǎn)單的內(nèi)部類實(shí)現(xiàn)可以如下

class OuterClass {
  class InnerClass{
  }
}

今天的問(wèn)題和Java內(nèi)部類相關(guān),只涉及到部分和本文研究相關(guān)的內(nèi)部類知識(shí),具體關(guān)于Java內(nèi)部類后續(xù)的文章會(huì)介紹。

第一次失效?

一個(gè)我們?cè)诰幊讨薪?jīng)常用到的場(chǎng)景,就是在一個(gè)內(nèi)部類里面訪問(wèn)外部類的private成員變量或者方法,這是可以的。如下面的代碼實(shí)現(xiàn)。

public class OuterClass {
 private String language = "en";
 private String region = "US";
 
 
 public class InnerClass {
   public void printOuterClassPrivateFields() {
     String fields = "language=" + language + ";region=" + region;
     System.out.println(fields);
   }
 }
 
 public static void main(String[] args) {
   OuterClass outer = new OuterClass();
   OuterClass.InnerClass inner = outer.new InnerClass();
   inner.printOuterClassPrivateFields();
 }
}

這是為什么呢,不是private修飾的成員只能被成員所述的類才能訪問(wèn)么?難道private真的失效了么?

編譯器在搗鬼?

我們使用javap命令查看一下生成的兩個(gè)class文件

OuterClass的反編譯結(jié)果

15:30 $ javap -c OuterClass
Compiled from "OuterClass.java"
public class OuterClass extends java.lang.Object{
public OuterClass();
 Code:
  0: aload_0
  1: invokespecial  #11; //Method java/lang/Object."<init>":()V
  4: aload_0
  5: ldc #13; //String en
  7: putfield #15; //Field language:Ljava/lang/String;
  10: aload_0
  11: ldc #17; //String US
  13: putfield #19; //Field region:Ljava/lang/String;
  16: return

public static void main(java.lang.String[]);
 Code:
  0: new #1; //class OuterClass
  3: dup
  4: invokespecial  #27; //Method "<init>":()V
  7: astore_1
  8: new #28; //class OuterClass$InnerClass
  11: dup
  12: aload_1
  13: dup
  14: invokevirtual  #30; //Method java/lang/Object.getClass:()Ljava/lang/Class;
  17: pop
  18: invokespecial  #34; //Method OuterClass$InnerClass."<init>":(LOuterClass;)V
  21: astore_2
  22: aload_2
  23: invokevirtual  #37; //Method OuterClass$InnerClass.printOuterClassPrivateFields:()V
  26: return

static java.lang.String access$0(OuterClass);
 Code:
  0: aload_0
  1: getfield #15; //Field language:Ljava/lang/String;
  4: areturn

static java.lang.String access$1(OuterClass);
 Code:
  0: aload_0
  1: getfield #19; //Field region:Ljava/lang/String;
  4: areturn

}

咦?不對(duì),在OuterClass中我們并沒(méi)有定義這兩個(gè)方法

static java.lang.String access$0(OuterClass);
 Code:
  0: aload_0
  1: getfield #15; //Field language:Ljava/lang/String;
  4: areturn

static java.lang.String access$1(OuterClass);
 Code:
  0: aload_0
  1: getfield #19; //Field region:Ljava/lang/String;
  4: areturn

}

從給出來(lái)的注釋來(lái)看,access$0返回outerClass的language屬性;access$1返回outerClass的region屬性。并且這兩個(gè)方法都接受OuterClass的實(shí)例作為參數(shù)。這兩個(gè)方法為什么生成呢,有什么作用呢?我們看一下內(nèi)部類的反編譯結(jié)果就知道了。

OuterClass$InnerClass的反編譯結(jié)果

15:37 $ javap -c OuterClass\$InnerClass
Compiled from "OuterClass.java"
public class OuterClass$InnerClass extends java.lang.Object{
final OuterClass this$0;

public OuterClass$InnerClass(OuterClass);
 Code:
  0: aload_0
  1: aload_1
  2: putfield #10; //Field this$0:LOuterClass;
  5: aload_0
  6: invokespecial  #12; //Method java/lang/Object."<init>":()V
  9: return

public void printOuterClassPrivateFields();
 Code:
  0: new #20; //class java/lang/StringBuilder
  3: dup
  4: ldc #22; //String language=
  6: invokespecial  #24; //Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
  9: aload_0
  10: getfield #10; //Field this$0:LOuterClass;
  13: invokestatic #27; //Method OuterClass.access$0:(LOuterClass;)Ljava/lang/String;
  16: invokevirtual  #33; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
  19: ldc #37; //String ;region=
  21: invokevirtual  #33; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
  24: aload_0
  25: getfield #10; //Field this$0:LOuterClass;
  28: invokestatic #39; //Method OuterClass.access$1:(LOuterClass;)Ljava/lang/String;
  31: invokevirtual  #33; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
  34: invokevirtual  #42; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
  37: astore_1
  38: getstatic  #46; //Field java/lang/System.out:Ljava/io/PrintStream;
  41: aload_1
  42: invokevirtual  #52; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
  45: return
}

下面代碼調(diào)用access$0的代碼,其目的是得到OuterClass的language 私有屬性。

13:   invokestatic #27; //Method OuterClass.access$0:(LOuterClass;)Ljava/lang/String;

下面代碼調(diào)用了access$1的代碼,其目的是得到OutherClass的region 私有屬性。

28:   invokestatic #39; //Method OuterClass.access$1:(LOuterClass;)Ljava/lang/String;

注意:在內(nèi)部類構(gòu)造的時(shí)候,會(huì)將外部類的引用傳遞進(jìn)來(lái),并且作為內(nèi)部類的一個(gè)屬性,所以內(nèi)部類會(huì)持有一個(gè)其外部類的引用。

this$0就是內(nèi)部類持有的外部類引用,通過(guò)構(gòu)造方法傳遞引用并賦值。

final OuterClass this$0;

public OuterClass$InnerClass(OuterClass);
 Code:
  0: aload_0
  1: aload_1
  2: putfield #10; //Field this$0:LOuterClass;
  5: aload_0
  6: invokespecial  #12; //Method java/lang/Object."<init>":()V
  9: return

小結(jié)

這部分private看上去失效可,實(shí)際上并沒(méi)有失效,因?yàn)楫?dāng)內(nèi)部類調(diào)用外部類的私有屬性時(shí),其真正的執(zhí)行是調(diào)用了編譯器生成的屬性的靜態(tài)方法(即acess$0,access$1等)來(lái)獲取這些屬性值。這一切都是編譯器的特殊處理。

這次也失效?

如果說(shuō)上面的寫(xiě)法很常用,那么這樣的寫(xiě)法是不是很少接觸,但是卻可以運(yùn)行。

public class AnotherOuterClass {
 public static void main(String[] args) {
   InnerClass inner = new AnotherOuterClass().new InnerClass();
   System.out.println("InnerClass Filed = " + inner.x);
 }

 class InnerClass {
   private int x = 10;
 }

}

和上面一樣,使用javap反編譯看一下。不過(guò)這次我們先看一下InnerClass的結(jié)果

16:03 $ javap -c AnotherOuterClass\$InnerClass
Compiled from "AnotherOuterClass.java"
class AnotherOuterClass$InnerClass extends java.lang.Object{
final AnotherOuterClass this$0;

AnotherOuterClass$InnerClass(AnotherOuterClass);
 Code:
  0: aload_0
  1: aload_1
  2: putfield #12; //Field this$0:LAnotherOuterClass;
  5: aload_0
  6: invokespecial  #14; //Method java/lang/Object."<init>":()V
  9: aload_0
  10: bipush  10
  12: putfield #17; //Field x:I
  15: return

static int access$0(AnotherOuterClass$InnerClass);
 Code:
  0: aload_0
  1: getfield #17; //Field x:I
  4: ireturn

}

又出現(xiàn)了,編譯器又自動(dòng)生成了一個(gè)獲取私有屬性的后門方法access$0一次來(lái)獲取x的值。

AnotherOuterClass.class的反編譯結(jié)果

16:08 $ javap -c AnotherOuterClass
Compiled from "AnotherOuterClass.java"
public class AnotherOuterClass extends java.lang.Object{
public AnotherOuterClass();
 Code:
  0: aload_0
  1: invokespecial  #8; //Method java/lang/Object."<init>":()V
  4: return

public static void main(java.lang.String[]);
 Code:
  0: new #16; //class AnotherOuterClass$InnerClass
  3: dup
  4: new #1; //class AnotherOuterClass
  7: dup
  8: invokespecial  #18; //Method "<init>":()V
  11: dup
  12: invokevirtual  #19; //Method java/lang/Object.getClass:()Ljava/lang/Class;
  15: pop
  16: invokespecial  #23; //Method AnotherOuterClass$InnerClass."<init>":(LAnotherOuterClass;)V
  19: astore_1
  20: getstatic  #26; //Field java/lang/System.out:Ljava/io/PrintStream;
  23: new #32; //class java/lang/StringBuilder
  26: dup
  27: ldc #34; //String InnerClass Filed =
  29: invokespecial  #36; //Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
  32: aload_1
  33: invokestatic #39; //Method AnotherOuterClass$InnerClass.access$0:(LAnotherOuterClass$InnerClass;)I
  36: invokevirtual  #43; //Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
  39: invokevirtual  #47; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
  42: invokevirtual  #51; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
  45: return

}

其中這句調(diào)用就是外部類通過(guò)內(nèi)部類的實(shí)例獲取私有屬性x的操作

33:   invokestatic #39; //Method AnotherOuterClass$InnerClass.access$0:(LAnotherOuterClass$InnerClass;)I

再來(lái)個(gè)總結(jié)

其中java官方文檔 有這樣一句話

if the member or constructor is declared private, then access is permitted if and only if it occurs within the body of the top level class (§7.6) that encloses the declaration of the member or constructor.

意思是 如果(內(nèi)部類的)成員和構(gòu)造方法設(shè)定成了私有修飾符,當(dāng)且僅當(dāng)其外部類訪問(wèn)時(shí)是允許的。

如何讓內(nèi)部類私有成員不被外部訪問(wèn)

相信看完上面兩部分,你會(huì)覺(jué)得,內(nèi)部類的私有成員想不被外部類訪問(wèn)都很困難吧,誰(shuí)讓編譯器“愛(ài)管閑事”呢,其實(shí)也是可以做到的。那就是使用匿名內(nèi)部類。

由于mRunnable對(duì)象的類型為Runnable,而不是匿名內(nèi)部類的類型(我們無(wú)法正常拿到),而Runanble中沒(méi)有x這個(gè)屬性,所以mRunnable.x是不被允許的。

public class PrivateToOuter {
 Runnable mRunnable = new Runnable(){
   private int x=10;
   @Override
   public void run() {
     System.out.println(x);
   }
 };

 public static void main(String[] args){
   PrivateToOuter p = new PrivateToOuter();
   //System.out.println("anonymous class private filed= "+ p.mRunnable.x); //not allowed
   p.mRunnable.run(); // allowed
 }
}

最后總結(jié)

在本文中,private表面上看上去失效了,但實(shí)際上是沒(méi)有的,而是在調(diào)用時(shí)通過(guò)間接的方法來(lái)獲取私有的屬性。

Java的內(nèi)部類構(gòu)造時(shí)持有對(duì)外部類的應(yīng)用,C++不會(huì),這一點(diǎn)和C++不一樣。

深入Java細(xì)節(jié)的書(shū)籍

Java編程思想
Sun 公司核心技術(shù)叢書(shū):Effective Java中文版
深入理解Java虛擬機(jī):JVM高級(jí)特性與最佳實(shí)踐

以上就是對(duì)Java private 修飾符的資料整理,后續(xù)繼續(xù)補(bǔ)充相關(guān)資料,謝謝大家對(duì)本站的支持!

相關(guān)文章

  • feign的ribbon超時(shí)配置和hystrix的超時(shí)配置說(shuō)明

    feign的ribbon超時(shí)配置和hystrix的超時(shí)配置說(shuō)明

    這篇文章主要介紹了feign的ribbon超時(shí)配置和hystrix的超時(shí)配置說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-09-09
  • java中List集合及其遍歷詳解

    java中List集合及其遍歷詳解

    這篇文章主要介紹了java中List集合及其遍歷詳解的相關(guān)資料,需要的朋友可以參考下
    2015-07-07
  • Java 多線程實(shí)例講解(一)

    Java 多線程實(shí)例講解(一)

    本文主要介紹Java 多線程的知識(shí),這里整理了詳細(xì)的資料及簡(jiǎn)單示例代碼有需要的小伙伴可以參考下
    2016-09-09
  • Java編程 多態(tài)

    Java編程 多態(tài)

    這篇文章主要介紹了關(guān)于Java編程的多態(tài),多態(tài)通過(guò)分離做什么和怎么做,從另一個(gè)角度將接口和實(shí)現(xiàn)分離開(kāi)來(lái)。構(gòu)建可擴(kuò)展的程序,需要的朋友可以參考下
    2021-10-10
  • 擴(kuò)展tk.mybatis的流式查詢功能實(shí)現(xiàn)

    擴(kuò)展tk.mybatis的流式查詢功能實(shí)現(xiàn)

    mybatis查詢默認(rèn)是一次獲取全部,如果數(shù)據(jù)過(guò)于龐大,就會(huì)導(dǎo)致OOM問(wèn)題,本文就介紹了tk.mybatis 流式查詢,具有一定的參考價(jià)值,感興趣的可以了解一下
    2021-12-12
  • Spring MVC的國(guó)際化實(shí)現(xiàn)代碼

    Spring MVC的國(guó)際化實(shí)現(xiàn)代碼

    本篇文章主要介紹了Spring MVC的國(guó)際化實(shí)現(xiàn)代碼,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-08-08
  • 輕松掌握J(rèn)ava迭代器模式

    輕松掌握J(rèn)ava迭代器模式

    這篇文章主要幫助大家輕松掌握J(rèn)ava迭代器模式,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-09-09
  • Java讓泛型實(shí)例化的方法

    Java讓泛型實(shí)例化的方法

    這篇文章主要介紹了Java讓泛型實(shí)例化的方法,文中示例代碼非常詳細(xì),幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下
    2020-07-07
  • 基于Java和GeoTools的Shapefile矢量數(shù)據(jù)縮略圖生成實(shí)踐

    基于Java和GeoTools的Shapefile矢量數(shù)據(jù)縮略圖生成實(shí)踐

    這篇文章主要介紹了基于Java和GeoTools的Shapefile矢量數(shù)據(jù)縮略圖生成實(shí)踐,需要的朋友可以參考下
    2024-08-08
  • SpringMVC項(xiàng)目異常處理機(jī)制詳解

    SpringMVC項(xiàng)目異常處理機(jī)制詳解

    SpringMVC是一種基于Java,實(shí)現(xiàn)了Web MVC設(shè)計(jì)模式,請(qǐng)求驅(qū)動(dòng)類型的輕量級(jí)Web框架,即使用了MVC架構(gòu)模式的思想,將Web層進(jìn)行職責(zé)解耦?;谡?qǐng)求驅(qū)動(dòng)指的就是使用請(qǐng)求-響應(yīng)模型,框架的目的就是幫助我們簡(jiǎn)化開(kāi)發(fā),SpringMVC也是要簡(jiǎn)化我們?nèi)粘eb開(kāi)發(fā)
    2022-08-08

最新評(píng)論

雷州市| 上饶县| 通渭县| 靖西县| 武穴市| 华池县| 雷州市| 无棣县| 嘉兴市| 沧源| 蒙自县| 纳雍县| 手游| 特克斯县| 高邑县| 江川县| 隆安县| 漳平市| 广昌县| 手游| 筠连县| 池州市| 行唐县| 湖口县| 延寿县| 盈江县| 余江县| 桂林市| 图木舒克市| 阿克苏市| 漳州市| 肃北| 凌源市| 郸城县| 三原县| 扬州市| 江陵县| 宣汉县| 定日县| 塔河县| 邓州市|