Java 프로그래밍에서는 개인 키워드를 사용하여 회원이 수정됩니다. 이 회원이있는 클래스 와이 클래스의 방법을 사용할 수 있으며 다른 클래스는이 개인 회원에 액세스 할 수 없습니다.
상기는 개인 수정 자의 기본 기능을 설명합니다. 오늘, 개인 기능 실패 상황을 연구 해 봅시다.
자바 내부 수업
Java에서는 많은 사람들이 내부 수업을 사용했다고 생각합니다. Java는 한 클래스에서 다른 클래스를 정의 할 수 있습니다. 수업의 수업은 내부 수업이며 중첩 클래스라고도합니다. 간단한 내부 클래스 구현은 다음과 같습니다
클래스 외부 클래스 {클래스 내부 클래스 {}}오늘의 문제는 Java 내부 수업과 관련이 있으며이 기사의 연구와 관련된 일부 내부 수업 지식 만 포함됩니다. Java 내부 수업에 대한 다음 기사를 소개합니다.
처음 실패했을 때?
우리가 프로그래밍에 자주 사용하는 시나리오는 내부 클래스에서 개인 회원 변수 또는 외부 클래스 방법에 액세스하는 것입니다. 다음 코드에서 구현 된대로.
공개 클래스 OUTCLASS {private String Language = "en"; 개인 문자열 영역 = "우리"; 공개 클래스 내부 클래스 {public void printouterclassprivatefields () {문자열 fields = "ancegra =" + ancegry + "; region =" + region; System.out.println (필드); }} public static void main (String [] args) {Outerclass OUTER = new OUTCLASS (); auterclass.innerclass 내부 = outer.new innerclass (); Inner.printouterClassPrivateFields (); }}이게 왜? 개인 수정 된 회원은 회원이 설명한 클래스에서만 액세스 할 수 없습니까? 개인이 정말 유효하지 않습니까?
컴파일러가 엉망이되고 있습니까?
우리는 Javap 명령을 사용하여 생성 된 두 개의 클래스 파일을 봅니다.
외부 클래스의 분해 결과
15:30 $ Javap -C "Outerclass.java"에서 공개 클래스 OUTCLASS가 java.lang.object {public auterclass (); 코드 : 0 : aload_0 1 : invokescial #11; // 메소드 Java/Lang/Object. "<init>":() v 4 : aload_0 5 : ldc #13; // 문자열 EN 7 : Putfield #15; // 필드 언어 : ljava/lang/string; 10 : Aload_0 11 : LDC #17; // 13 번 문자열 : Putfield #19; // 필드 영역 : ljava/lang/string; 16 : returnPublic static void main (java.lang.string []); 코드 : 0 : 새로운 #1; // 클래스 외부 클래스 3 : DUP 4 : Invokescial #27; // 메소드 "<init>":() v 7 : Store_1 8 : 새로운 #28; // 클래스 OUTCLASS $ 내부 클래스 11 : DUP 12 : ALOAD_1 13 : DUP 14 : InvokeVirtual #30; // 메소드 java/lang/object.getClass :() ljava/lang/class; 17 : POP 18 : Invokescial #34; // 메소드 OUTCLASS $ 내부 클래스. "<init>":( louterClass;) v 21 : Store_2 22 : aload_2 23 : InvokeVirtual #37; // 메소드 OUTCLASS $ 내부 클래스 .printouterClassPrivateFields :() v 26 : ReturnStatic Java.Lang.String Access $ 0 (OUTERCLASS); 코드 : 0 : aload_0 1 : Getfield #15; // 필드 언어 : ljava/lang/string; 4 : areturnstatic java.lang.string Access $ 1 (OUTCLASS); 코드 : 0 : aload_0 1 : getfield #19; // 필드 영역 : ljava/lang/string; 4 : Areturn}뭐? 아니요, 우리는이 두 가지 방법을 외부에서 정의하지 않습니다.
정적 java.lang.String Access $ 0 (OUTCLASS); 코드 : 0 : aload_0 1 : Getfield #15; // 필드 언어 : ljava/lang/string; 4 : areturnstatic java.lang.string Access $ 1 (OUTCLASS); 코드 : 0 : aload_0 1 : getfield #19; // 필드 영역 : ljava/lang/string; 4 : Areturn}
주어진 의견으로 판단하면 Access $ 0는 외부의 언어 속성을 반환합니다. 액세스 $ 1은 외부의 영역 속성을 반환합니다. 두 방법 모두 외부 인스턴스를 매개 변수로 받아들입니다. 이 두 가지 방법이 생성되는 이유와 그 기능은 무엇입니까? 내부 클래스의 대결 결과를 살펴 보겠습니다.
OUTCLASS $ 내부 클래스의 분해 결과
15:37 $ javap -c outerclass/$ 내부 클래스는 "outerclass.java"공개 클래스 외부 클래스 $ java.lang.object {Final Outerclass이 $ 0; public auterclass $ innerclass (outerclass); 코드 : 0 : aload_0 1 : aload_1 2 : Putfield #10; //이 $ 0 : LouterClass; 5 : Aload_0 6 : invokescial #12; // 메소드 Java/Lang/Object. "<init>":() v 9 : returnpublic void printouterclassprivatefields (); 코드 : 0 : 새로운 #20; // 클래스 Java/Lang/StringBuilder 3 : DUP 4 : LDC #22; // 문자열 언어 = 6 : invokescial #24; // 메소드 java/lang/stringbuilder. "<init>":( ljava/lang/string;) v 9 : aload_0 10 : getfield #10; //이 $ 0 : LouterClass; 13 : Invokestatic #27; // 메소드 auterclass.access $ 0 : (louterClass;) ljava/lang/string; 16 : InvokeVirtual #33; // 메소드 java/lang/stringbuilder.append : (ljava/lang/string;) ljava/lang/stringbuilder; 19 : LDC #37; // String; region = 21 : InvokeVirtual #33; // 메소드 java/lang/stringbuilder.append : (ljava/lang/string;) ljava/lang/stringbuilder; 24 : Aload_0 25 : Getfield #10; //이 $ 0 : LouterClass; 28 : Invokestatic #39; // 메소드 auterclass.access $ 1 : (louterClass;) ljava/lang/string; 31 : InvokeVirtual #33; // 메소드 java/lang/stringbuilder.append : (ljava/lang/string;) ljava/lang/stringbuilder; 34 : InvokeVirtual #42; // 메소드 java/lang/stringbuilder.tostring :() ljava/lang/string; 37 : Store_1 38 : Getstatic #46; // 필드 java/lang/system.out : ljava/io/printstream; 41 : aload_1 42 : InvokeVirtual #52; // 메소드 java/io/printstream.println : (ljava/lang/string;) v 45 : return}다음 코드는 OUTCLASS의 언어 사유 재산을 얻기 위해 Access $ 0 코드를 호출합니다.
13 : Invokestatic #27; // 메소드 auterclass.access $ 0 : (louterClass;) ljava/lang/string;
다음 코드는 Access $ 1 코드를 호출하며 OUTCLASS의 지역 사유 재산을 얻기위한 것입니다.
28 : Invokestatic #39; // 메소드 auterclass.access $ 1 : (louterClass;) ljava/lang/string;
참고 : 내부 클래스를 구성 할 때 외부 클래스에 대한 참조가 내부 클래스의 속성으로 전달되어 사용되므로 내부 클래스는 외부 클래스에 대한 참조를 보유합니다.
이 $ 0은 내부 클래스가 보유한 외부 클래스 참조이며, 참조를 전달하고 생성자를 통해 값을 할당합니다.
Final Outerclass이 $ 0; public Outerclass $ 내부 클래스 (OUTCLASS); 코드 : 0 : aload_0 1 : aload_1 2 : Putfield #10; //이 $ 0 : LouterClass; 5 : Aload_0 6 : invokescial #12; // 메소드 Java/Lang/Object. "<init>":() v 9 : return
요약
개인 의이 부분은 유효하지 않은 것처럼 보이지만 내부 클래스가 외부 클래스의 개인 속성을 호출 할 때 실제 실행은 컴파일러가 생성 한 속성의 정적 메소드 (즉, Acess $ 0, Access $ 1 등)를 호출하는 것이 중요하지 않습니다. 이 모든 것은 컴파일러의 특별한 처리입니다.
이번에는 유효하지 않습니까?
위의 쓰기 방법이 매우 일반적으로 사용된다면,이 쓰기 방법은 거의 노출되지 않지만 실행할 수 있습니다.
public class onther class asherouterclass {public static void main (string [] args) {InnerClass Inner = new OtherouterClass (). New InnerClass (); System.out.println ( "Innerclass filed =" + inner.x); } 클래스 내부 클래스 {private int x = 10; }}위와 마찬가지로 Javap을 사용하여 디 컴파일하고 살펴보십시오. 하지만 이번에는 먼저 Innerclass의 결과를 봅니다.
16:03 $ javap -c "otherouterclass.java"클래스에서 aerva.lang.object {final other uterclass이 $ 0; 다른 OUTERCLASS $ InnerClass (OtherOuterClass); 코드 : 0 : aload_0 1 : aload_1 2 : Putfield #12; //이 $ 0 : LanotherouterClass; 5 : aload_0 6 : invokescial #14; // 메소드 Java/Lang/Object. "<init>":() v 9 : aload_0 10 : Bipush 10 12 : Putfield #17; // 필드 X : I 15 : returnStatic int Access $ 0 (OtherouterClass $ 내부 클래스); 코드 : 0 : aload_0 1 : getfield #17; // 필드 X : I 4 : Ireturn}다시 나타나고 컴파일러는 x의 값을 얻기 위해 개인 속성에 $ 0에 액세스 할 수있는 백도어 메소드를 자동으로 생성합니다.
다른 OUTERCLASS.CLASS 코 컴파일 결과
16:08 $ javap -c "aleysouterclass.java"에서 operouterclasscompiled 공개 클래스 java.lang.object {public otherouterclass (); 코드 : 0 : aload_0 1 : invokescial #8; // 메소드 Java/Lang/Object. "<init>":() v 4 : returnpublic static void main (java.lang.string []); 코드 : 0 : 새로운 #16; // 다른 OUTERCLASS $ CLASS 내부 클래스 3 : DUP 4 : 새로운 #1; // 클래스 다른 OUTERCLASS 7 : DUP 8 : invokescial #18; // 메소드 "<init>":() v 11 : dup 12 : InvokeVirtual #19; // 메소드 java/lang/object.getClass :() ljava/lang/class; 15 : POP 16 : Invokescial #23; // 방법 다른 OUTERCLASS $ 내부 클래스. "<init>":( lanotherouterClass;) v 19 : Store_1 20 : getstatic #26; // 필드 java/lang/system.out : ljava/io/printstream; 23 : 새로운 #32; // 클래스 Java/Lang/StringBuilder 26 : DUP 27 : LDC #34; // String InnerClass가 제출 된 = 29 : invokescial #36; // 메소드 java/lang/stringbuilder. "<init>":( ljava/lang/string;) v 32 : aload_1 33 : invokestatic #39; // 메소드 다른 OUTERCLASS $ InnerClass.Access $ 0 : (LanotherouterClass $ 내부 클래스;) i 36 : InvokeVirtual #43; // 메소드 java/lang/stringbuilder.append : (i) ljava/lang/stringbuilder; 39 : InvokeVirtual #47; // 메소드 java/lang/stringbuilder.tostring :() ljava/lang/string; 42 : InvokeVirtual #51; // 메소드 java/io/printstream.println : (ljava/lang/string;) v 45 : return}이 호출은 내부 클래스의 인스턴스를 통해 개인 속성 X를 얻기위한 외부 클래스의 작동입니다.
33 : Invokestatic #39; // 메소드 다른 OUTERCLASS $ innerclass.access $ 0 : (LanotherouterClass $ 내부 클래스;) i
다른 요약을하자
공식 Java 문서에는 문장이 있습니다
멤버 또는 생성자가 개인으로 선언 된 경우, 멤버 또는 생성자의 선언을 동봉하는 최상위 클래스 (§7.6)의 본문 내에서 발생하는 경우에만 액세스가 허용됩니다.
의미 IF (내부 클래스) 멤버 및 생성자는 개인 수정 자로 설정되며 외부 클래스에 액세스하는 경우에만 허용됩니다.
내부 클래스의 개인 구성원이 외부에서 액세스하는 것을 방지하는 방법
위의 두 부분을 읽은 후에는 내부 클래스의 개인 구성원이 외부 클래스에서 액세스하는 것을 피하기가 어렵다고 생각합니다. 컴파일러를 "Messing Nosy"로 만들 수있는 사람은 누구입니까? 실제로 수행 할 수 있습니다. 그것은 익명의 내부 클래스를 사용하는 것입니다.
mrunnable 객체의 유형은 익명의 내부 클래스의 유형이 아니라 (정상적으로 얻을 수 없음), runanble에는 x 속성이 없기 때문에 mrunnable.x는 허용되지 않습니다.
공개 클래스 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); // 허용되지 않음 p.mrunnable.run (); // 허용된 }}최종 요약
이 기사에서는 개인이 표면에 무효 인 것으로 보이지만 실제로는 그렇지 않습니다. 대신, 개인 속성은 호출 될 때 간접적 인 방법을 통해 얻습니다.
Java의 내부 클래스 구성은 외부 클래스에 응용 프로그램을 보유하고 있지만 C ++는 C ++와 다릅니다.
자바 세부 사항에 깊이 들어가는 책
자바 프로그래밍 아이디어
Sun Company 's Core Technology Series : 효과적인 Java 중국어 버전을 깊이 이해하는 Java Virtual Machine : JVM의 고급 기능 및 모범 사례
위는 Java 개인 수정 자에 대한 정보를 편집 한 것입니다. 우리는 향후 관련 정보를 계속 추가 할 것입니다. 이 사이트를 지원 해주셔서 감사합니다!