В программировании Java член изменяется с помощью частного ключевого слова. Только тот класс, где находится этот участник, и можно использовать метод этого класса, а другие классы не могут получить доступ к этому частному члену.
Приведенное выше описывается основные функции частного модификатора. Сегодня давайте изучим ситуацию с неудачей частной функции.
Java внутренние классы
В Java я считаю, что многие люди использовали внутренние классы. Java позволяет определять другой класс в одном классе. Класс в классе - это внутренний класс, также называемый вложенным классом. Простая внутренняя реализация класса может быть следующей
класс outterclass {class innerclass {}}Сегодняшняя проблема связана с внутренними классами Java и включает в себя лишь некоторые внутренние знания класса, связанные с исследованиями этой статьи. Мы представим следующие статьи о внутренних классах Java.
В первый раз это не удалось?
Сценарий, который мы часто используем в программировании, заключается в доступе к переменным частным членам или методам внешних классов во внутреннем классе, что в порядке. Как реализовано в следующем коде.
открытый класс outterclass {private String language = "en"; Private String Region = "US"; открытый класс innerclass {public void printouterclassprivatefields () {String fields = "language =" + language + "; region =" + region; System.out.println (Fields); }} public static void main (string [] args) {overclass over = new overclass (); Overclass.innerclass inner = over.new innerclass (); inner.printouterclassprivatefields (); }}Почему это? Разве частный модифицированный участник не доступен только по классу, описанному членом? Частный действительно ли недействителен?
Компилятор возится?
Мы используем команду Javap для просмотра сгенерированных двух файлов класса
Результаты декомпиляции OUTERCLASS
15:30. Код: 0: ALOAD_0 1: INLOKPECIAL #11; // метод java/lang/object. "<int>" :() V 4: Aload_0 5: LDC #13; // Строка EN 7: Putfield #15; // Полевой язык: Ljava/lang/String; 10: Aload_0 11: LDC #17; // String US 13: Putfield #19; // Полевая область: ljava/lang/string; 16: returnpublic static void main (java.lang.string []); Код: 0: новый #1; // класс Overclass 3: DUP 4: INLOKPECIAL #27; // Метод "<Itin>" :() V 7: Store_1 8: новый #28; // класс Overclass $ InnerClass 11: DUP 12: Aload_1 13: DUP 14: Invokevirtual #30; // метод java/lang/object.getClass :() ljava/lang/class; 17: POP 18: INLOKSECIAL #34; // Метод overclass $ innerclass. "<Itin>" :( LouterClass;) V 21: Store_2 22: Aload_2 23: Invokevirtual #37; // Метод outterclass $ innerclass.printouterClassPrivateFields :() V 26: returnstatic java.lang.string Access $ 0 (overclass); Код: 0: aload_0 1: getfield #15; // Полевой язык: Ljava/lang/String; 4: areturnstatic java.lang.string access $ 1 (overclass); Код: 0: Aload_0 1: Getfield #19; // Полевая область: ljava/lang/string; 4: Areturn}
Хм? Нет, мы не определяем эти два метода в Overclass
static java.lang.string access $ 0 (overclass); Код: 0: aload_0 1: getfield #15; // Полевой язык: Ljava/lang/String; 4: areturnstatic java.lang.string access $ 1 (overclass); Код: 0: Aload_0 1: Getfield #19; // Полевая область: ljava/lang/string; 4: Areturn}
Судя по приведенным комментариям, доступ к $ 0 возвращает языковой атрибут Overclass; Доступ $ 1 возвращает атрибут региона Overclass. И оба метода принимают экземпляр Overclass в качестве параметра. Почему создаются эти два метода и каковы их функции? Давайте посмотрим на результаты декомпиляции внутреннего класса.
Результат декомпиляции overclass $ innerclass
15:37. Код: 0: aload_0 1: aload_1 2: putfield #10; // поставьте это $ 0: LOUTERCLASS; 5: aload_0 6: infokpecial #12; // метод java/lang/object. "<int>" :() V 9: returnPublic void printouterClassPrivateFields (); Код: 0: новый #20; // класс Java/Lang/StringBuilder 3: DUP 4: LDC #22; // String Language = 6: Invokespecial #24; // метод java/lang/stringbuilder. "<Itin>" :( ljava/lang/string;) V 9: aload_0 10: getfield #10; // поставьте это $ 0: LOUTERCLASS; 13: Invokestatic #27; // метод outterclass.access $ 0: (louterclass;) ljava/lang/string; 16: Invokevirtual #33; // метод java/lang/stringbuilder.append: (ljava/lang/string;) ljava/lang/stringbuilder; 19: LDC #37; // string; область = 21: InvokeVirtual #33; // метод java/lang/stringbuilder.append: (ljava/lang/string;) ljava/lang/stringbuilder; 24: Aload_0 25: Getfield #10; // поставьте это $ 0: LOUTERCLASS; 28: Invokestatic #39; // метод outterclass.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}
Следующий код вызывает код доступа $ 0 с целью получения языковой частной собственности OuterClass.
13: Invokestatic #27; // метод outterclass.access $ 0: (louterclass;) ljava/lang/string;
Следующий код вызывает код доступа $ 1 с целью получения частной собственности региона OuterClass.
28: Invokestatic #39; // метод outterclass.access $ 1: (louterclass;) ljava/lang/string;
ПРИМЕЧАНИЕ. При построении внутреннего класса ссылка на внешний класс будет передаваться и использовать в качестве свойства внутреннего класса, поэтому внутренний класс будет иметь ссылку на свой внешний класс.
Этот $ 0 - это внешний класс ссылка, хранящийся внутренним классом, который передает ссылку и назначает значение через конструктор.
окончательный overclass этот $ 0; Public overclass $ innerclass (overclass); Код: 0: aload_0 1: aload_1 2: putfield #10; // поставьте это $ 0: LOUTERCLASS; 5: aload_0 6: infokpecial #12; // метод java/lang/obj
краткое содержание
Эта часть частного, кажется, является недействительной, но она не недействительна, потому что, когда внутренний класс вызывает частные свойства внешнего класса, его реальное исполнение - вызов статических методов атрибутов, сгенерированных компилятором (то есть Acess $ 0, доступ 1 доллар и т. Д.), Чтобы получить эти значения атрибутов. Все это является специальной обработкой компилятора.
На этот раз это недействительно?
Если приведенный выше метод написания очень часто используется, то этот метод написания редко разоблачается, но его можно запустить.
public class oneyouterclass {public static void main (string [] args) {innerclass inner = new inotherouterclass (). new innerclass (); System.out.println ("innerclass filed =" + inner.x); } класс innerclass {private int x = 10; }}Как и выше, используйте Javap, чтобы декомпилировать и посмотрите. Но на этот раз мы сначала посмотрим на результаты внутреннего класса
16:03 $ javap -c notherouterclass/$ innerclasscompilled из "notherouterclass.java" class oreightouterclass $ innerclass расширяет java.lang.object {final oreightclass this $ 0; notherouterclass $ innerclass (другой вучительский класс); Код: 0: aload_0 1: aload_1 2: putfield #12; // поставьте это $ 0: lanotherouterClass; 5: Aload_0 6: Allokpecial #14; // Метод java/lang/object. "<int>" :() V 9: Aload_0 10: Bipush 10 12: Putfield #17; // Поле X: I 15: returnstatic int access $ 0 (inotherouterclass $ innerclass); Код: 0: aload_0 1: getfield #17; // Поле X: I 4: Ireturn}Он появляется снова, и компилятор автоматически генерирует метод Backdoor для получения частных атрибутов доступа 0 долларов США один раз, чтобы получить значение x.
Sotherouterclass.class decroplation Результаты
16:08. Код: 0: ALOAD_0 1: INLOKPECIAL #8; // метод java/lang/object. "<int>" :() V 4: returnPublic static void main (java.lang.string []); Код: 0: новый #16; // Класс inetherouterClass $ InnerClass 3: DUP 4: новый #1; // Класс другой вроде класса 7: DUP 8: ENLOKPECIAL #18; // Метод "<Itin>" :() V 11: DUP 12: InvokeVirtual #19; // метод java/lang/object.getClass :() ljava/lang/class; 15: POP 16: INLOKPECIAL #23; // метод другого вроде класса $ innerclass. // поле java/lang/system.out: ljava/io/printstream; 23: новый #32; // класс Java/Lang/StringBuilder 26: DUP 27: LDC #34; // Строка InnerClass FILED = 29: ENLOKPECIAL #36; // метод java/lang/stringbuilder. "<int>" :( ljava/lang/string;) V 32: Aload_1 33: Invokestatic #39; // метод другого вроде класса $ innerclass.access $ 0: (lanotherouterClass $ innerclass;) 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; // Метод другого вроде $ innerclass.access $ 0: (lanotherouterClass $ innerclass;) i
Давайте получим еще одно резюме
В официальном документе Java есть предложение
Если член или конструктор объявлен частным, то доступ разрешается в то время как и только если он происходит в теле класса верхнего уровня (§7.6), который прилагает объявление члена или конструктора.
Значение, если члены и конструкторы (внутренний класс) устанавливаются как частные модификаторы, которые разрешены тогда и только тогда, когда их внешний класс обращаются.
Как предотвратить доступ к частным членам внутренних классов
Я полагаю, что после прочтения двух вышеупомянутых частей вы почувствуете, что частным членам внутренних классов трудно избежать доступа к внешним классам. Кто может сделать компилятор «путающим любопытным»? Это может быть сделано. То есть использовать анонимные внутренние классы.
Поскольку тип объекта Mrunnable запускается, а не тип анонимного внутреннего класса (мы не можем получить его обычно), и в Runanble, Mrunnable.x нет свойства 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 privateTooter (); //System.out.println("anonymous class private filed = "+ p.mrunnable.x); // не допускается p.mrunnable.run (); // допустимый }}Последнее резюме
В этой статье частная, кажется, недействительна на поверхности, но на самом деле это не так. Вместо этого частные свойства получаются с помощью косвенных методов при вызове.
Внутренняя конструкция класса Java содержит приложения для внешних классов, но C ++ нет, что отличается от C ++.
Книги, которые углубляются в Java Details
Идеи программирования Java
Серия основных технологий Sun Company: эффективная китайская версия Java глубоко понимание виртуальной машины Java: передовые функции и лучшие практики JVM
Выше приведено сборник информации о частных модификаторах Java. Мы будем продолжать добавлять соответствующую информацию в будущем. Спасибо за поддержку этого сайта!