亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > Java > 正文

Java中的private修飾符失效了?

2019-11-26 15:19:18
字體:
來源:轉載
供稿:網友

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

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

Java內部類

在Java中相信很多人都用過內部類,Java允許在一個類里面定義另一個類,類里面的類就是內部類,也叫做嵌套類。一個簡單的內部類實現可以如下

復制代碼 代碼如下:

class OuterClass {
    class InnerClass{
    }
}

今天的問題和Java內部類相關,只涉及到部分和本文研究相關的內部類知識,具體關于Java內部類后續的文章會介紹。

第一次失效?

一個我們在編程中經常用到的場景,就是在一個內部類里面訪問外部類的private成員變量或者方法,這是可以的。如下面的代碼實現。

復制代碼 代碼如下:

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修飾的成員只能被成員所述的類才能訪問么?難道private真的失效了么?

編譯器在搗鬼?

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

OuterClass的反編譯結果

復制代碼 代碼如下:

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

}
咦?不對,在OuterClass中我們并沒有定義這兩個方法

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

}


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

OuterClass$InnerClass的反編譯結果

復制代碼 代碼如下:

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
}


下面代碼調用access$0的代碼,其目的是得到OuterClass的language 私有屬性。
復制代碼 代碼如下:

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

下面代碼調用了access$1的代碼,其目的是得到OutherClass的region 私有屬性。
復制代碼 代碼如下:

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

注意:在內部類構造的時候,會將外部類的引用傳遞進來,并且作為內部類的一個屬性,所以內部類會持有一個其外部類的引用。

this$0就是內部類持有的外部類引用,通過構造方法傳遞引用并賦值。

復制代碼 代碼如下:

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

小結

這部分private看上去失效可,實際上并沒有失效,因為當內部類調用外部類的私有屬性時,其真正的執行是調用了編譯器生成的屬性的靜態方法(即acess$0,access$1等)來獲取這些屬性值。這一切都是編譯器的特殊處理。

這次也失效?

如果說上面的寫法很常用,那么這樣的寫法是不是很少接觸,但是卻可以運行。

復制代碼 代碼如下:

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反編譯看一下。不過這次我們先看一下InnerClass的結果
復制代碼 代碼如下:

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

}


又出現了,編譯器又自動生成了一個獲取私有屬性的后門方法access$0一次來獲取x的值。

AnotherOuterClass.class的反編譯結果

復制代碼 代碼如下:

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

}


其中這句調用就是外部類通過內部類的實例獲取私有屬性x的操作
復制代碼 代碼如下:

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

再來個總結

其中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.

意思是 如果(內部類的)成員和構造方法設定成了私有修飾符,當且僅當其外部類訪問時是允許的。

如何讓內部類私有成員不被外部訪問

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

由于mRunnable對象的類型為Runnable,而不是匿名內部類的類型(我們無法正常拿到),而Runanble中沒有x這個屬性,所以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
  }
}

最后總結

在本文中,private表面上看上去失效了,但實際上是沒有的,而是在調用時通過間接的方法來獲取私有的屬性。
Java的內部類構造時持有對外部類的應用,C++不會,這一點和C++不一樣。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
国产日韩精品综合网站| 日韩美女中文字幕| 综合欧美国产视频二区| 狠狠躁夜夜躁久久躁别揉| 欧美孕妇毛茸茸xxxx| 日本国产欧美一区二区三区| 欧美激情一级精品国产| www.xxxx精品| 国产精品美女免费视频| 国产免费观看久久黄| 久久99精品国产99久久6尤物| 亚洲高清色综合| 欧美裸体xxxx极品少妇软件| 久久久久久一区二区三区| 欧美极品欧美精品欧美视频| 精品呦交小u女在线| 欧美日韩中文在线观看| 亚洲片在线观看| 亚洲美女av网站| 日韩美女视频在线观看| 国产美女扒开尿口久久久| 久热精品在线视频| 亚洲人成伊人成综合网久久久| 奇米成人av国产一区二区三区| 国产一区二区三区高清在线观看| 国产有码在线一区二区视频| 精品一区二区电影| 国产精品视频网| 久久人人爽人人爽爽久久| 永久免费看mv网站入口亚洲| 中文字幕日韩精品在线| 成人国产精品一区二区| 日韩a**站在线观看| 2021国产精品视频| 97视频在线播放| 国产成人精品久久亚洲高清不卡| 欧美性极品xxxx做受| 欧美专区中文字幕| 欧美体内谢she精2性欧美| 亚洲欧洲av一区二区| 国产精品久久久久久久久影视| 久久精品小视频| 深夜福利国产精品| 亚洲国产欧美一区二区三区同亚洲| 69久久夜色精品国产69| 亚洲第一男人av| 日韩电视剧免费观看网站| 欧美在线视频网站| 欧美激情中文字幕在线| 91精品免费久久久久久久久| 欧美肥老妇视频| 国产视频精品一区二区三区| 午夜精品久久17c| 黑人巨大精品欧美一区二区三区| 亚洲风情亚aⅴ在线发布| 亚洲精品色婷婷福利天堂| 91po在线观看91精品国产性色| 精品美女久久久久久免费| 日韩人在线观看| 欧美刺激性大交免费视频| 日韩欧美在线国产| 国产一区二区三区在线观看网站| 欧美一区二区三区四区在线| 久久精品国产欧美亚洲人人爽| 欧美性猛交99久久久久99按摩| 69视频在线播放| 亚洲偷欧美偷国内偷| 91在线精品视频| 欧美日韩国产精品一区二区不卡中文| 国产69久久精品成人看| 欧美极品美女视频网站在线观看免费| 欧美成aaa人片免费看| 狠狠久久五月精品中文字幕| 欧美激情图片区| 亚洲影院高清在线| 欧美—级a级欧美特级ar全黄| 日韩成人xxxx| 国产99视频在线观看| 亚洲国产欧美日韩精品| 欧美老女人性视频| 狠狠操狠狠色综合网| 久久理论片午夜琪琪电影网| 亚洲欧美制服综合另类| 国产日韩中文字幕在线| 精品国产乱码久久久久久婷婷| 国产香蕉97碰碰久久人人| 亚洲第一福利在线观看| 55夜色66夜色国产精品视频| 欧美成人精品一区| 51视频国产精品一区二区| 91av在线视频观看| 疯狂做受xxxx高潮欧美日本| 亚洲精品国产精品久久清纯直播| 日韩欧美在线视频日韩欧美在线视频| 久久精品色欧美aⅴ一区二区| 亚洲精品国产精品久久清纯直播| 91久久精品久久国产性色也91| 超碰97人人做人人爱少妇| 色偷偷偷亚洲综合网另类| 亚洲精品在线看| 久久人人爽人人爽人人片av高请| 成人写真福利网| 国产精品视频一区二区高潮| 成人在线一区二区| 欧美丝袜第一区| 久久精品国产久精国产思思| 91九色单男在线观看| 国产精品午夜一区二区欲梦| 亚洲精品一区av在线播放| 成人高清视频观看www| 国产精品视频成人| 国产视频自拍一区| 亚洲人成电影网站| 亚洲在线免费观看| 欧美国产日韩一区二区在线观看| 正在播放欧美一区| 亚洲精品黄网在线观看| 欧美性猛交xxxx免费看久久久| 久久韩剧网电视剧| 欧美日韩精品在线视频| 国产亚洲一区精品| 91免费的视频在线播放| 黄色一区二区在线观看| 精品美女久久久久久免费| 日本最新高清不卡中文字幕| 中文字幕日韩在线视频| 欧美精品生活片| 国产综合久久久久久| 成人性教育视频在线观看| 午夜精品一区二区三区视频免费看| 亚洲欧洲第一视频| 亚洲欧美中文日韩在线| 国产91色在线|免| 欧美日韩国产第一页| 中文字幕亚洲欧美一区二区三区| 57pao国产成人免费| 57pao成人永久免费视频| 欧美最猛性xxxxx(亚洲精品)| 国产精品欧美日韩一区二区| 精品欧美一区二区三区| 日韩免费电影在线观看| 亚洲欧美成人精品| 日韩国产在线播放| 亚洲国产91色在线| 久久成人18免费网站| 狠狠操狠狠色综合网| 国产精品第二页| 一区二区三区黄色| 日本精品久久中文字幕佐佐木| 亚洲福利在线播放| 美女黄色丝袜一区| 综合136福利视频在线| 久久这里有精品| 91夜夜未满十八勿入爽爽影院| 精品国产美女在线| 国产一区二区av| 欧洲午夜精品久久久| 久久国产精品久久久久久久久久| 国产精品香蕉av| 国产精品视频1区| 欧美肥臀大乳一区二区免费视频| 青青久久av北条麻妃黑人| 久久久久国产精品免费| 亚洲人成网站色ww在线|