This outer class java

Class.this и object.new для внутренних классов в Java

В проекте по исследованию ИВП мы используем Java. Не так давно проводя рефакторинг уже написанного кода, я столкнулся с ситуацией, когда из внутреннего класса нужно было вызвать метод, в параметр которого нужно было передать ссылку на объект внешнего класса. Я набрал в гугле «java inner class access outer object» и..

Погуглив, я обнаружил две новые для себя конструкции Java, возможно для вас они также покажутся интересными:

1. Class.this

class Outer < int x = 5; class Inner < int x = 10; public void test() < System.out.println( Outer.this.x ); >> public void test() < new Inner().test(); >>

Т.е. с помощью такой конструкции вы можете сделать именно то, что мне было нужно — получить из внутреннего класса ссылку на объект внешнего класса. Это часто бывает нужно, когда вы работаете с EventListener’ами.

2. object.new

Попробуйте скомпилировать вот этот невинный на первый взгляд код:

public class Test < static void main() < innerTest inner=new innerTest(); // тут ошибка >public class innerTest < >>

И вы получите следующую ошибку компиляции: Error: java: non-static variable this cannot be referenced from a static context . Все дело в том, что при создании объектов внутренних классов Java необходимо иметь ссылку на объект внешнего класса (см. п. 1 выше 🙂 ). Поэтому, чтобы код мог быть скомпилирован строчку с ошибкой нужно переписать так:

innerTest inner=new Test().new innerTest();
Test test=new Test(); innerTest inner=test.new innerTest();

Последнее выглядит достаточно необычно, согласитесь 😉

Читайте также:  Java как сформировать json

Источник

Внутренние и вложенные классы java. Часть 1

Цель статьи: Рассказать о внутренних, вложенных, локальных, анонимных классах. Показать примеры их использования. Написать и протестировать классы в коде на java. Рассказать о свойствах этих классов. Материал предназначен для лучшего понимания безымянных классов, лямбда выражений, адаптеров и многопоточности. То есть перед их изучением.

Небольшое вступление. Предлагаю вашему вниманию цикл из трех статей.
В них я рассказываю о внутренних, вложенных, локальных, анонимных классах. Речь идет о терминологии и применении. Для этих статей я написал довольно много кода.
Это учебный код, а не руководство к действию. То есть сам код я написал для лучшего понимания. Также я постарался объяснить работу учебного кода. На написание данной публикации, ушло довольно много времени. Публикация состоит из трех частей. Прошу отнестись с пониманием.

Для лучшего изучения материала у вас должна быть некоторая подготовка.
То есть вам нужно знать: синтаксис языка java, область видимости переменных, классы, статические и нестатические члены класса, создание экземпляров класса, наследование, модификаторы доступа.

Начнем с того, что же такое внутренние и вложенные классы. Посмотрим терминологию, встречающуюся в документации и литературе:

В Java существуют 4 типа вложенных (nested) классов:

  1. Статические вложенные классы
  2. Внутренние классы
  3. Локальные классы
  4. Анонимные (безымянные) классы

Существуют четыре категории вложенных классов:

  • статический класс-член (static member class),
  • не статический класс-член (nonstatic member class),
  • анонимный класс (anonymous class)
  • и локальный класс (local class).

Попытаемся разобраться, что же это такое.

Начнем немного отдаленно, так как всё это имеет непосредственное отношение к нашим вопросам. Вспомним объектно-ориентированное программирование. Отношения композиции и наследования.

В своей книге «Java 2 Руководство разработчика» Майкл Морган очень хорошо и подробно описывает взаимосвязи классов и объектов. Мы рассмотрим некоторые из них. Взаимосвязь «это — есть — то» выражается наследованием, а взаимосвязь «имеет часть» описывается композицией.

В наших примерах мы в основном рассматриваем композицию. Так как вложенные классы — это и есть часть чего-то. То есть у нас есть класс оболочка и вложенный класс определенный внутри класса оболочки. Пример композиции: машина имеет двигатель, двери, 4 колеса, корпус. И мы можем описать машину с помощью внутренних (Inner) классов.

Пример такого использования вы можете найти в книге Брюса Эккеля «Философия Java»

/* Пример №1 */ //: c06:Car.java // композиция с использованием открытых объектов // двигатель class Engine < public void start()<>public void rev()<> public void stop()<> > class Wheel< public void inflare(int psi)<>// накачать > // окно class Window< public void rollup()<>// приоткрыть public void rolldown()<>// опустить > // дверь class Door< public Window window=new Window(); public void open()<>//открыть public void close()<>// закрыть > // машина public class Car < public Engine engine = new Engine(); public Wheel[] wheel = new Wheel[4]; public Door left = new Door(), right = new Door();//две двери public Car()< for(int i = 0; ipublic static void main(String[] args) < Car car= new Car(); car.left.window.rollup(); car.wheel[0].inflare(72); >> 

Так как композиция объекта является частью проведенного анализа задачи (а не
просто частью реализации класса), объявление членов класса открытыми, помогает программисту-клиенту понять, как использовать класс, и упрощает создателю написание кода. Однако нужно помнить, что описанный случай является особым, и в основном поля класса нужно объявлять как private.

Выше я не случайно упомянул наследование и композицию. Это напрямую относится к дальнейшему материалу.

Статические вложенные классы

Определение вложенных классов:

То есть класс просто определен внутри другого, даже не важно статически определен или не статически. Вложенный класс создается для того, чтобы обслуживать окружающий его класс. Если вложенный класс оказывается полезен в каком-либо ином контексте, он должен стать классом верхнего уровня.

Вложенные классы применяются в тех случаях, когда нужно написать небольшой вспомогательный код для другого класса. Вложенный класс создают также, чтобы скрыть его переменные и методы от внешнего мира. Таким образом, вложенный класс еще один элегантный способ ограничения области видимости. Внутренние классы также есть смысл использовать, если предполагается, что они будут использовать элементы родителя, чтобы не передавать лишнего в конструкторах.

Пример вложенного класса вы можете увидеть в документации Оракле:

/* Пример №2 */ // class OuterClass < . class NestedClass < . >> 

У нас нет, пока что, никакого контекста использования данной конструкции. С таким же успехом вложенный класс мы можем назвать вместо: «Вложенный класс» (NestedClass) — «Внутренний класс» InnerClass. Далее будем разбираться, в чем же отличия, и в каких контекстах используются классы. Брюс Эккель пишет в книге «Философия Java» так:

Документацию Oracle вы можете посмотреть по этой ссылке: >>>

Существует четыре категории вложенных классов:

  1. Статические вложенные классы и не статические вложенные классы. Вложенные классы, объявленные статически, называются вложенными статическими классами.
  2. Внутренние классы — когда объект внутреннего класса связан с объектом обрамляющего класса. Не статические вложенные классы называются внутренними классами, если они связанны с внешним классом.
  3. Локальные классы — объявленные внутри блока кода и не являющиеся членом обрамляющего класса. В этом случае можно рассматривать класс как локальную переменную типа класс.
  4. Анонимные классы – наследуемые, от какого либо класса, классы в которых при объявлении не задано имя класса.

Причины использования вложенных классов такие. Если класс полезен только для одного другого класса, то вполне логично встроить его в этот класс и хранить их вместе. Использование вложенных классов увеличивает инкапсуляцию. Рассмотрим два класса верхнего уровня, A и B, где B нужен доступ к членам, которые иначе были бы объявлены закрытыми.

Скрывая класс «B» в пределах класса «А», члены класса «А» могут быть объявлены закрытыми, и «B» может получить доступ к ним. Кроме того, сам «B» может быть скрыт от внешнего мира.

Продемонстрируем это в коде:

/* Учебный пример №4 */ package innernested; /** * * @author Ar20L80 */ public class A < private static int iPrivVar; class B < void setPrivateOfA(int var) < A.iPrivVar = var; >> > 

Использование вложенных классов приводит к более читабельному и поддерживаемому коду: Размещение класса ближе к тому месту, где он будет использован, делает код более читабельным.

Статические Вложенные Классы
Static Nested Classes

Причины использования статических вложенных классов такие.

Для случая, когда связь между объектом вложенного класса и объектом внешнего класса не нужна, можно сделать вложенный класс статическим(static).

Так как внутренний класс связан с экземпляром, он не может определить в себе любые статические члены.

Статические вложенные классы не имеют ограничений по объявлению своих данных и полей как static.

Из вложенного статического класса мы не имеем доступа к внешней не статической переменной внешнего класса.

Приведенный ниже код демонстрирует это:

 /* Учебный пример №5 Статические вложенные классы Попытка доступа к не статической переменной внешнего класса Outer2 через обращение из вложенного статического класса Nested2 */ package nested; /** * * @author Ar20L80 * 20.03.2016 */ public class Outer2 < public int pubOutVar; // переменная не статическая и мы не имеем к ней доступа // из внутреннего статического класса private int prOutVar; public Outer2()<>// конструктор внешнего класса static class Nested2 < public static int pub_innVar; // тут все в порядке public Nested2() <>// конструктор вложенного класса int getOuterPublicVariable() < return Outer2.this.pubOutVar; // ошибка return Outer2.pubOutVar; // ошибка >int getOuterPrivateVariable() < return Outer2.this.prOutVar; // ошибка return Outer2.prOutVar; // ошибка >> > /* вывод программы: программа не компилируется */ 

Вывод: Мы не имеем доступа к не статическому полю внешнего класса, через статический контекст вложенного класса. Это подобно тому, как мы не имеем доступа из статического метода к нестатическим переменным класса. Точно также из статического вложенного класса мы не имеем доступа к нестатическим переменным внешнего класса.

Но мы имеем доступ к приватным статическим полям внешнего класса из вложенного статичного класса.

Приведенный ниже фрагмент кода демонстрирует это:

Все вопросы, комментарии, дополнения, критика приветствуются.

Продолжение следует…
Часть 2 >>>

Если у вас есть возможность, вам пригодилось, и вы можете помочь, то нажмите кнопку поддержать автора материально.

Источник

Разница между ключевыми словами this и super в Java

Java-университет

Разница между ключевыми словами this и super в Java - 1

this и super — это два специальных ключевых слова в Java, которые представляют соответственно текущий экземпляр класса и его суперкласса. Java-программисты часто путают эти слова и обнаруживают слабую осведомленность об их специальных свойствах, о которых нередко спрашивают на интервью по Java Сore. Вот, например, пара вопросов, из того, что сразу приходит на ум, о this и super , Можно ли присвоить другое значение ключевому слову this в Java? и какая разница между ключевыми словами this и super в Java. Не знаете? Ну что ж, здесь я ответа не даю — его можно найти в конце статьи. Так вот, как я уже сказал в начале, главное отличие между this и super в Java в том, что this представляет текущий экземпляр класса, в то время как super — текущий экземпляр родительского класса. Вот один из примеров использования переменных this и super — вы наверняка уже видели примеры вызовов конструкторов одного из другого, т.н. вызовы конструкторов по цепочке, это возможно благодаря использованию ключевых слов this и super . Внутри класса для вызова своего конструктора без аргументов используется this() , тогда как super() используется для вызова конструктора без аргументов, или как его ещё называют, конструктора по умолчанию родительского класса. Между прочим, таким способом вызывать можно не только конструктор без аргументов, а и вообще любой другой конструктор, передав ему соответствующие параметры. Скоро мы увидим пример такого использования this и super . Ещё this и super в Java используются для обращения к переменным экземпляра класса и его родителя. Вообще-то, к ним можно обращаться и без префиксов super и this , но только если в текущем блоке такие переменные не перекрываются другими переменными, т.е. если в нем нет локальных переменных с такими же именами, в противном же случае использовать имена с префиксами придется обязательно, но это не беда, т.к. в таком виде они даже более читабельны. Классическим примером такого подхода является использование this внутри конструктора, который принимает параметр с таким же именем, как и у переменной экземпляра. Дальше в статье мы узнаем, какие ещё есть отличия между super и this , и рассмотрим некоторые примеры их использования.

Чем this и super похожи

  1. И this , и super — это нестатические переменные, соответственно их нельзя использовать в статическом контексте, а это означает, что их нельзя использовать в методе main. Это приведет к ошибке во время компиляции «на нестатическую переменную this нельзя ссылаться из статического контекста». То же самое произойдет, если в методе main воспользоваться ключевым словом super .
  2. И this , и super могут использоваться внутри конструкторов для вызова других конструкторов по цепочке, нпр., this () и super () вызывают конструктор без аргументов наследующего и родительского классов соответственно.
 class A < A()< System.out.println("Конструктор без аргументов класса A"); >A(String args) < System.out.println("Конструктор с одним аргументом класса A"); >> class B extends A < B()< this(""); // вызов конструктора с одним аргументом класса B System.out.println("Конструктор без аргументов класса B"); >B(String args) < super(""); // вызов конструктора с одним аргументом класса A System.out.println("Конструктор с одним аргументом класса B"); >> // Тест-класс и вывод public class Test < public static void main(String args[]) < B b = new B(); >> 
  1. Внутри конструктора this и super должны стоять выше всех других выражений, в самом начале, иначе компилятор выдаст сообщение об ошибке. Из чего следует, что в одном конструкторе не может быть одновременно и this() , и super() .

Различия в super и this

  1. переменная this ссылается на текущий экземпляр класса, в котором она используется, тогда как super — на текущий экземпляр родительского класса.
  2. Каждый конструктор при отсутствии явных вызовов других конструкторов неявно вызывает с помощью super() конструктор без аргументов родительского класса, при этом у вас всегда остается возможность явно вызвать любой другой конструктор с помощью либо this() , либо super() .

Источник

Оцените статью