У чому головна відмінність внутрішнього класу від статичного вкладеного класу на Java? Чи грає дизайн / реалізація роль у виборі одного з них?
У чому головна відмінність внутрішнього класу від статичного вкладеного класу на Java? Чи грає дизайн / реалізація роль у виборі одного з них?
Відповіді:
З навчального посібника Java :
Вкладені класи поділяються на дві категорії: статичні та нестатичні. Вкладені класи, які оголошені статичними, просто називаються статичними вкладеними класами. Нестатичні вкладені класи називають внутрішніми класами.
До статичних вкладених класів можна отримати доступ, використовуючи назву класу, що додається:
OuterClass.StaticNestedClass
Наприклад, щоб створити об’єкт для статичного вкладеного класу, використовуйте цей синтаксис:
OuterClass.StaticNestedClass nestedObject = new OuterClass.StaticNestedClass();
Об'єкти, що є екземплярами внутрішнього класу, існують в екземплярі зовнішнього класу. Розглянемо наступні класи:
class OuterClass {
...
class InnerClass {
...
}
}
Екземпляр InnerClass може існувати лише в екземплярі OuterClass і має прямий доступ до методів і полів його екземпляра, що додається.
Щоб створити внутрішній клас, потрібно спочатку інстанціювати зовнішній клас. Потім створіть внутрішній об’єкт у зовнішньому об'єкті за допомогою цього синтаксису:
OuterClass outerObject = new OuterClass()
OuterClass.InnerClass innerObject = outerObject.new InnerClass();
див .: Підручник Java - Вкладені класи
Для повноти зауважте, що існує також таке поняття, як внутрішній клас без прикладного екземпляра :
class A {
int t() { return 1; }
static A a = new A() { int t() { return 2; } };
}
Тут new A() { ... }
є внутрішній клас, визначений у статичному контексті і не має примірника, що обгороджує.
import OuterClass.StaticNestedClass;
тоді посилайтеся на клас так само, як на OuterClass.
OuterClass.InnerClass innerObject = outerObject.new InnerClass();
?
Підручник Java говорить :
Термінологія: Вкладені класи поділяються на дві категорії: статичні та нестатичні. Вкладені класи, які оголошені статичними, просто називаються статичними вкладеними класами. Нестатичні вкладені класи називають внутрішніми класами.
Зазвичай кажучи, терміни "вкладений" та "внутрішній" вживаються взаємозамінно більшістю програмістів, але я буду використовувати правильний термін "вкладений клас", який охоплює як внутрішній, так і статичний.
Класи можуть бути вкладені ad infinitum , наприклад, клас A може містити клас B, який містить клас C, який містить клас D тощо. Однак більш ніж один рівень вкладання класу рідко, оскільки це, як правило, погана конструкція.
Ви можете створити вкладений клас з трьох причин:
На Яві є чотири види вкладеного класу . Якщо коротко, це:
Дозвольте детальніше розказати.
Статичні класи - це найпростіший вид для розуміння, оскільки вони не мають нічого спільного з екземплярами класу, що містить.
Статичний клас - це клас, оголошений статичним членом іншого класу. Як і інші статичні члени, такий клас насправді є просто вішальником, який використовує клас, що містить, як простір імен, наприклад, клас Коза, оголошений статичним членом класу Rhino в пакеті піци , відомий під назвою pizza.Rhino.Goat .
package pizza;
public class Rhino {
...
public static class Goat {
...
}
}
Відверто кажучи, статичні класи - це досить нікчемна особливість, оскільки класи вже розділені на простори імен за пакетами. Єдиною реальною можливою причиною створення статичного класу є те, що такий клас має доступ до приватних статичних членів класу, але я вважаю це досить кульгавим обґрунтуванням існування функції статичного класу.
Внутрішній клас - це клас, оголошений нестатичним членом іншого класу:
package pizza;
public class Rhino {
public class Goat {
...
}
private void jerry() {
Goat g = new Goat();
}
}
Як і у випадку зі статичним класом, внутрішній клас відомий як кваліфікований за своїм ім'ям, що містить клас pizza.Rhino.Goat , але всередині класу, що містить його, він може бути відомий за його простою назвою. Однак кожен екземпляр внутрішнього класу прив’язаний до певного екземпляра класу, що містить його: вище, Коза, створена в джеррі , неявно пов'язана з екземпляром Rhino, це в Джеррі . В іншому випадку ми робимо явний екземпляр Rhino явним, коли інстанціюємо Goat :
Rhino rhino = new Rhino();
Rhino.Goat goat = rhino.new Goat();
(Зверніть увагу, що ви називаєте внутрішній тип як просто Козел у новому дивному синтаксисі: Java виводить тип містить із частини носорога . І, так, новий rhino.Goat () мав би більше сенсу і для мене.)
То що, це нас отримує? Ну, внутрішній екземпляр класу має доступ до членів екземпляра, що містить екземпляр класу. Ці члени екземплярів, що додаються, посилаються на внутрішній клас за допомогою їх простих імен, а не через це ( це у внутрішньому класі посилається на екземпляр внутрішнього класу, а не на асоційований екземпляр класу):
public class Rhino {
private String barry;
public class Goat {
public void colin() {
System.out.println(barry);
}
}
}
У внутрішньому класі ви можете називати цей клас, що містить, як Rhino.this , і ви можете використовувати це для позначення його членів, наприклад, Rhino.this.barry .
Місцевий внутрішній клас - це клас, оголошений у тілі методу. Такий клас відомий лише в його методі, що містить метод, тому він може бути інстанційним і мати доступ до його членів у межах його методу, що містить. Вигода полягає в тому, що місцевий екземпляр внутрішнього класу пов'язаний і може отримати доступ до кінцевих локальних змінних його методу, що містить. Коли екземпляр використовує остаточний локальний метод, що містить його, змінна зберігає значення, яке воно містило під час створення екземпляра, навіть якщо змінна вийшла з сфери застосування (це фактично сира, обмежена версія закриття Java).
Оскільки локальний внутрішній клас не є членом класу чи пакету, він не оголошується з рівнем доступу. (Будьте зрозумілі, однак, що його члени мають рівні доступу, як у звичайному класі.)
Якщо локальний внутрішній клас оголошено методом екземпляра, інстанція внутрішнього класу прив'язується до екземпляра, який утримується методом, що містить цей, на момент створення екземпляра, і тому члени екземплярів класу, що містять клас, доступні, як у екземплярі внутрішній клас. Місцевий внутрішній клас створюється примірником просто через його ім'я, наприклад, місцевий внутрішній клас Cat інстанціюється як новий Cat () , а не новий this.Cat (), як ви могли очікувати.
Анонімний внутрішній клас - синтаксично зручний спосіб написання місцевого внутрішнього класу. Найчастіше локальний внутрішній клас інстанціюється не більше одного разу щоразу, коли його метод містить. Тоді було б непогано, якби ми могли поєднати визначення місцевого внутрішнього класу та його єдину інстанціювання в одну зручну синтаксичну форму, і було б також непогано, якби нам не довелося придумати назву для класу (менша кількість непосидних імена, які містить ваш код, тим краще). Анонімний внутрішній клас дозволяє обидві речі:
new *ParentClassName*(*constructorArgs*) {*members*}
Це вираз, що повертає новий екземпляр неназваного класу, який розширює ParentClassName . Ви не можете поставити власний конструктор; скоріше, імпліцитно подається, який просто викликає супер конструктор, тому наведені аргументи повинні відповідати супер конструктору. (Якщо батько містить декілька конструкторів, найпростіший називається "найпростішим", що визначається досить складним набором правил, не варто турбуватися, щоб детально вивчати - просто зверніть увагу на те, що вам кажуть NetBeans або Eclipse.)
Можна також вказати інтерфейс для реалізації:
new *InterfaceName*() {*members*}
Така декларація створює новий екземпляр неназваного класу, який розширює Object та реалізує InterfaceName . Знову ж таки, ви не можете поставити власний конструктор; у цьому випадку Java неявно постачає конструктор no-arg, нічого робити (тому в цьому випадку аргументів конструктора ніколи не буде).
Незважаючи на те, що ви не можете надати конструктору анонімний внутрішній клас, ви все одно можете виконати будь-яку установку, яку ви хочете, використовуючи блок ініціалізатора (блок {}, розміщений поза будь-яким методом).
Будьте зрозумілі, що анонімний внутрішній клас - це просто менш гнучкий спосіб створення локального внутрішнього класу одним екземпляром. Якщо ви хочете локальний внутрішній клас, який реалізує кілька інтерфейсів або реалізує інтерфейси, одночасно розширюючи якийсь клас, відмінний від Object, або який вказує власний конструктор, ви застрягли, створюючи звичайний локальний внутрішній клас.
Я не думаю, що реальна різниця стала зрозумілою у наведених вище відповідях.
Спочатку, щоб правильно встановити умови:
Відповідь Мартіна правильна поки що. Однак актуальним є питання: яка мета оголосити вкладений клас статичним чи ні?
Ви використовуєте статичні вкладені класи, якщо ви просто хочете зберігати свої класи разом, якщо вони належать місцево разом, або якщо вкладений клас використовується виключно вкладному класі. Немає смислової різниці між статичним вкладеним класом і будь-яким іншим класом.
Нестатичні вкладені класи - це інший звір. Подібно до анонімних внутрішніх класів, такі вкладені класи насправді є закриттями. Це означає, що вони захоплюють оточуючу сферу і примірник, що їх додає, і роблять це доступним. Можливо, приклад уточнить це. Дивіться цю заглушку контейнера:
public class Container {
public class Item{
Object data;
public Container getContainer(){
return Container.this;
}
public Item(Object data) {
super();
this.data = data;
}
}
public static Item create(Object data){
// does not compile since no instance of Container is available
return new Item(data);
}
public Item createSubItem(Object data){
// compiles, since 'this' Container is available
return new Item(data);
}
}
У цьому випадку потрібно мати посилання від дочірнього елемента до батьківського контейнера. Використовуючи нестатичний вкладений клас, це працює без певної роботи. Ви можете отримати доступ до примірника Container, що додається, із синтаксисом Container.this
.
Більш жорсткі пояснення наступні:
Якщо ви подивитеся на байт-коди Java, компілятор генерує для (нестатичного) вкладеного класу, він може стати ще зрозумілішим:
// class version 49.0 (49)
// access flags 33
public class Container$Item {
// compiled from: Container.java
// access flags 1
public INNERCLASS Container$Item Container Item
// access flags 0
Object data
// access flags 4112
final Container this$0
// access flags 1
public getContainer() : Container
L0
LINENUMBER 7 L0
ALOAD 0: this
GETFIELD Container$Item.this$0 : Container
ARETURN
L1
LOCALVARIABLE this Container$Item L0 L1 0
MAXSTACK = 1
MAXLOCALS = 1
// access flags 1
public <init>(Container,Object) : void
L0
LINENUMBER 12 L0
ALOAD 0: this
ALOAD 1
PUTFIELD Container$Item.this$0 : Container
L1
LINENUMBER 10 L1
ALOAD 0: this
INVOKESPECIAL Object.<init>() : void
L2
LINENUMBER 11 L2
ALOAD 0: this
ALOAD 2: data
PUTFIELD Container$Item.data : Object
RETURN
L3
LOCALVARIABLE this Container$Item L0 L3 0
LOCALVARIABLE data Object L0 L3 2
MAXSTACK = 2
MAXLOCALS = 3
}
Як ви бачите, компілятор створює приховане поле Container this$0
. Це встановлюється в конструкторі, який має додатковий параметр типу Container для вказівки примірника, що вкладається. Ви не можете бачити цей параметр у джерелі, але компілятор неявно генерує його для вкладеного класу.
Приклад Мартіна
OuterClass.InnerClass innerObject = outerObject.new InnerClass();
так буде складено до виклику чогось подібного (у байт-кодах)
new InnerClass(outerObject)
Для повноти:
Анонімний клас є прекрасним прикладом нестатичного вкладеного класу, який просто не має асоційованого з ним імені і не може бути посилається пізніше.
Я думаю, що жоден з наведених вище відповідей не пояснює вам реальну різницю між вкладеним класом та статичним вкладеним класом у плані дизайну програми:
Вкладений клас може бути нестатичним або статичним, і в кожному випадку це клас, визначений в іншому класі . Вкладений клас повинен існувати лише для обслуговування класу , що вкладається, якщо вкладений клас корисний для інших класів (не тільки вкладених), слід оголосити як клас вищого рівня.
Нестатичний вкладений клас : неявно пов’язаний із вкладеним екземпляром класу, що містить, це означає, що можна викликати методи та отримати доступ до змінних примірника, що додає. Одне поширене використання нестатичного вкладеного класу - це визначення класу Adapter.
Статичний вкладений клас : не може отримати доступ до екземпляра класу, що охоплює, та викликати на ньому методи, тому його слід використовувати, коли вкладений клас не потребує доступу до екземпляра класу, що закриває. Загальне використання статичного вкладеного класу - це реалізація компонентів зовнішнього об'єкта.
Отже, основна відмінність між ними з точки зору дизайну полягає в тому, що нестатичний вкладений клас може отримати доступ до екземпляра класу контейнерів, а статичний не може .
Простіше кажучи, нам потрібні вкладені класи насамперед тому, що Java не забезпечує закриття.
Вкладені класи - це класи, визначені всередині іншого класу, що додається. Вони бувають двох типів - статичні та нестатичні.
Вони розглядаються як члени класу, що додається, тому ви можете вказати будь-який із чотирьох специфікаторів доступу - private, package, protected, public
. У нас немає такої розкоші з класами вищого рівня, які можна оголосити лише public
приватними пакетами.
Внутрішні класи, які називаються некласичними класами, мають доступ до інших членів вищого класу, навіть якщо вони оголошені приватними, поки статичні вкладені класи не мають доступу до інших членів вищого класу.
public class OuterClass {
public static class Inner1 {
}
public class Inner2 {
}
}
Inner1
це наш статичний внутрішній клас і Inner2
це наш внутрішній клас, який не є статичним. Ключова різниця між ними, ви не можете створити Inner2
екземпляр без Зовнішнього, де ви можете Inner1
самостійно створити об'єкт.
Коли ви використовуєте Inner class?
Подумайте про ситуацію, коли Class A
і Class B
має відношення, Class B
потребує доступу Class A
членів, і Class B
пов'язана лише з ними Class A
. Внутрішні класи входять у картину.
Для створення екземпляра внутрішнього класу вам потрібно створити екземпляр свого зовнішнього класу.
OuterClass outer = new OuterClass();
OuterClass.Inner2 inner = outer.new Inner2();
або
OuterClass.Inner2 inner = new OuterClass().new Inner2();
Коли ви використовуєте статичний внутрішній клас?
Ви б визначили статичний внутрішній клас, коли знаєте, що він не має жодного зв’язку з екземпляром класу, що додається / верхнього класу. Якщо ваш внутрішній клас не використовує методів чи полів зовнішнього класу, це просто марнотрата місця, тому зробіть це статичним.
Наприклад, щоб створити об’єкт для статичного вкладеного класу, використовуйте цей синтаксис:
OuterClass.Inner1 nestedObject = new OuterClass.Inner1();
Перевага статичного вкладеного класу полягає в тому, що для його роботи не потрібен об'єкт, що містить клас / топ клас. Це може допомогти вам зменшити кількість об'єктів, які ваша програма створює під час виконання.
OuterClass.Inner2 inner = outer.new Inner2();
?
static inner
є суперечливістю термінів.
Ось ключові відмінності та схожість між внутрішнім класом Java та статичним вкладеним класом.
Сподіваюся, це допомагає!
Пов’язаний з екземпляром класу, що вкладається, щоб його інстанціювати спочатку потрібен екземпляр зовнішнього класу (зверніть увагу на нове місце ключового слова):
Outerclass.InnerClass innerObject = outerObject.new Innerclass();
Неможливо визначити які елементи статичні сам
Неможливо отримати доступ до методів або полів екземплярів зовнішнього класу
Не пов’язано з жодним екземпляром укладеного класу. Так, щоб створити його:
OuterClass.StaticNestedClass nestedObject = new OuterClass.StaticNestedClass();
Згідно з документацією Oracle є кілька причин ( повна документація ):
Це спосіб логічного групування класів, які використовуються лише в одному місці: Якщо клас корисний лише одному другому класу, то логічно вбудувати його в цей клас і тримати їх разом. Введення таких "помічницьких класів" робить їх пакет більш впорядкованим.
Це збільшує інкапсуляцію: розгляньте два класи вищого рівня, A і B, де B потрібен доступ до членів A, які в іншому випадку будуть оголошені приватними. Приховуючи клас B у класі A, члени A можуть бути оголошені приватними, і B може отримати доступ до них. Крім того, сам Б може бути прихований від зовнішнього світу.
Це може призвести до більш читабельного та легкодоступного коду: Вкладення малих класів у класах верхнього рівня розміщує код ближче до місця його використання.
Я думаю, що звичайно дотримується конвенція така:
Однак, ще кілька моментів, які слід пам’ятати :
Класи вищого рівня та статичний вкладений клас семантично однакові, за винятком того, що у випадку статичного вкладеного класу він може статично посилатися на приватні статичні поля / методи свого зовнішнього [батьківського] класу та навпаки.
Внутрішні класи мають доступ до змінних екземплярів вкладеного екземпляра зовнішнього [батьківського] класу. Однак не всі внутрішні класи мають приклади, що складаються, наприклад внутрішні класи в статичних контекстах, як анонімний клас, який використовується в блоці статичного ініціалізатора.
Клас "Анонімний" за замовчуванням розширює батьківський клас або реалізує батьківський інтерфейс, і більше немає пропозиції щодо розширення будь-якого іншого класу або впровадження будь-яких інших інтерфейсів. Тому,
new YourClass(){};
засоби class [Anonymous] extends YourClass {}
new YourInterface(){};
засоби class [Anonymous] implements YourInterface {}
Я відчуваю, що питання, яке залишається відкритим, залишається відкритим, який використовувати і коли? Добре, що в основному залежить від того, з яким сценарієм ви маєте справу, але читання відповіді від @jrudolph може допомогти вам прийняти якесь рішення.
Вкладений клас: клас всередині класу
Типи:
Різниця:
Нестатичний вкладений клас [Внутрішній клас]
У нестатичному вкладеному класі об'єкт внутрішнього класу існує всередині об'єкта зовнішнього класу. Таким чином, цей член даних зовнішнього класу є доступним для внутрішнього класу. Отже, щоб створити об'єкт внутрішнього класу, треба спочатку створити об'єкт зовнішнього класу.
outerclass outerobject=new outerobject();
outerclass.innerclass innerobjcet=outerobject.new innerclass();
Статичний вкладений клас
У статичному вкладеному класі об'єкт внутрішнього класу не потребує об'єкта зовнішнього класу, оскільки слово "статичний" вказує на відсутність необхідності створювати об'єкт.
class outerclass A {
static class nestedclass B {
static int x = 10;
}
}
Якщо ви хочете отримати доступ до x, тоді напишіть наступний метод всередині
outerclass.nestedclass.x; i.e. System.out.prinltn( outerclass.nestedclass.x);
Екземпляр внутрішнього класу створюється, коли створюється екземпляр зовнішнього класу. Тому члени та методи внутрішнього класу мають доступ до членів та методів екземпляра (об'єкта) зовнішнього класу. Коли екземпляр зовнішнього класу виходить за межі, також екземпляри внутрішнього класу припиняють своє існування.
Статичний вкладений клас не має конкретного примірника. Він просто завантажується, коли він використовується вперше (як і статичні методи). Це абсолютно незалежна сутність, чиї методи та змінні не мають доступу до екземплярів зовнішнього класу.
Статичні вкладені класи не поєднуються із зовнішнім об'єктом, вони швидші, і вони не беруть пам'ять heap / stack, оскільки для створення екземпляра такого класу не потрібно. Тому правилом є спробувати визначити статичний вкладений клас із максимально обмеженим діапазоном (приватний> = клас> = захищений> = публічний), а потім перетворити його у внутрішній клас (видаливши "статичний" ідентифікатор) та послабити сфера, якщо це дійсно необхідно.
Існує тонкощі використання вкладених статичних класів, які можуть бути корисні в певних ситуаціях.
У той час як статичні атрибути ініціюються до того, як клас інстанціюється через його конструктор, статичні атрибути всередині вкладених статичних класів, схоже, не отримують екземплярів доти, доки не буде викликано конструктор класу або, принаймні, не після того, як атрибути спочатку посилаються, навіть якщо вони позначаються як "остаточні".
Розглянемо цей приклад:
public class C0 {
static C0 instance = null;
// Uncomment the following line and a null pointer exception will be
// generated before anything gets printed.
//public static final String outerItem = instance.makeString(98.6);
public C0() {
instance = this;
}
public String makeString(int i) {
return ((new Integer(i)).toString());
}
public String makeString(double d) {
return ((new Double(d)).toString());
}
public static final class nested {
public static final String innerItem = instance.makeString(42);
}
static public void main(String[] argv) {
System.out.println("start");
// Comment out this line and a null pointer exception will be
// generated after "start" prints and before the following
// try/catch block even gets entered.
new C0();
try {
System.out.println("retrieve item: " + nested.innerItem);
}
catch (Exception e) {
System.out.println("failed to retrieve item: " + e.toString());
}
System.out.println("finish");
}
}
Навіть незважаючи на те, що "вкладені" та "innerItem" обидва оголошені як "статичний фінал". налаштування nested.innerItem не відбудеться до моменту екземпляру класу (або, принаймні, до моменту введення першого вкладеного статичного елемента), як ви можете самі переконатися, коментуючи та коментуючи рядки, на які я посилаюсь, вище. Те ж не справедливо для "externalItem".
Принаймні, це те, що я бачу в Java 6.0.
Терміни вживаються взаємозамінно. Якщо ви хочете бути по-справжньому педантичним щодо цього, тоді ви можете визначити "вкладений клас" для позначення статичного внутрішнього класу, у якого немає екземпляра, що вкладається. У коді у вас може бути щось подібне:
public class Outer {
public class Inner {}
public static class Nested {}
}
Це насправді не є загальноприйнятим визначенням.
У разі створення екземпляра екземпляр нестатичного внутрішнього класу створюється з посиланням на об'єкт зовнішнього класу, в якому він визначений. Це означає, що він має вкладений екземпляр. Але екземпляр статичного внутрішнього класу створюється з посиланням на Зовнішній клас, а не з посиланням на об'єкт зовнішнього класу. Це означає, що він не містить інстанції.
Наприклад:
class A
{
class B
{
// static int x; not allowed here…..
}
static class C
{
static int x; // allowed here
}
}
class Test
{
public static void main(String… str)
{
A o=new A();
A.B obj1 =o.new B();//need of inclosing instance
A.C obj2 =new A.C();
// not need of reference of object of outer class….
}
}
Я не думаю, що тут багато чого додати, більшість відповідей чудово пояснюють відмінності між статичним вкладеним класом та Внутрішніми класами. Однак врахуйте наступне питання при використанні вкладених класів проти внутрішніх класів. Як згадується в парі відповідей внутрішні класи не можуть бути створені без і екземпляр їх огороджувальних класу , який означає , що вони ТРИМАТИ в покажчик на екземпляр свого класу огороджувальної , що може привести до переповнення пам'яті або переповнення стека виключення з - за факту GC не зможе сміття збирати огороджувальні класи, навіть якщо вони більше не використовуються. Щоб зробити це зрозумілим, перевірте наступний код:
public class Outer {
public class Inner {
}
public Inner inner(){
return new Inner();
}
@Override
protected void finalize() throws Throwable {
// as you know finalize is called by the garbage collector due to destroying an object instance
System.out.println("I am destroyed !");
}
}
public static void main(String arg[]) {
Outer outer = new Outer();
Outer.Inner inner = outer.new Inner();
// out instance is no more used and should be garbage collected !!!
// However this will not happen as inner instance is still alive i.e used, not null !
// and outer will be kept in memory until inner is destroyed
outer = null;
//
// inner = null;
//kick out garbage collector
System.gc();
}
Якщо ви видалите коментар до // inner = null;
програми, на екрані з'явиться повідомлення " Я знищений! ", Але зберігати цей коментар не буде.
Причина полягає в тому, що білий внутрішній екземпляр все ще посилається на GC не може його зібрати, і оскільки він посилається (має вказівник на) зовнішній екземпляр, він також не збирається. Достатньо цих об’єктів у вашому проекті та може не вистачати пам’яті.
Порівняно зі статичними внутрішніми класами, які не вказують на екземпляр внутрішнього класу, оскільки він не пов'язаний з екземплярами, а пов'язаний з класом. Вищенаведена програма може надрукувати " Мене зруйновано! ", Якщо ви зробите Inner class статичним та інстанційнимOuter.Inner i = new Outer.Inner();
Вкладений клас - це дуже загальний термін: кожен клас, який не є вищим рівнем, є вкладеним класом. Внутрішній клас - це нестатичний вкладений клас. Джозеф Дарсі написав дуже приємне пояснення про Nested, Inner, Member та класи вищого рівня .
Аммм ... внутрішній клас - це вкладений клас ... ти маєш на увазі анонімний клас та внутрішній клас?
Редагувати: Якщо ви насправді мали на увазі внутрішнє проти анонімне ... внутрішній клас - це просто клас, визначений у класі, наприклад:
public class A {
public class B {
}
}
Тоді як анонімний клас - це розширення класу, визначеного анонімно, тому жоден фактичний "клас не визначається, як у:
public class A {
}
A anon = new A() { /* you could change behavior of A here */ };
Далі редагувати:
Вікіпедія стверджує, що в Java існує різниця , але я працюю з Java вже 8 років, і це перший раз, коли я почув таке розрізнення ... не кажучи вже про те, що там немає посилань на резервне копіювання претензії ... знизу рядок, внутрішній клас - це клас, визначений у класі (статичний чи ні), а вкладений - це лише інший термін, що означає те саме.
Існує тонка різниця між статичним і нестатичним вкладеним класом ... в основному нестатичні внутрішні класи мають неявний доступ до полів екземплярів і методів класу, що вкладається (тому вони не можуть бути побудовані в статичному контексті, це буде компілятором помилка). Статичні вкладені класи, з іншого боку, не мають неявного доступу до полів і методів екземплярів, і МОЖУТЬ бути побудовані в статичному контексті.
Орієнтація на учнів, які не знають Java та / або вкладені класи
Вкладені класи можуть бути:
1. Статичні вкладені класи.
2. Нестатичні вкладені класи. (також відомий як Внутрішні класи ) => Будь ласка, пам’ятайте про це
1.
Приклад внутрішніх класів :
class OuterClass {
/* some code here...*/
class InnerClass { }
/* some code here...*/
}
Внутрішні класи - це підмножини вкладених класів:
Спеціальність внутрішнього класу:
2.Статичні вкладені класи:
Приклад:
class EnclosingClass {
static class Nested {
void someMethod() { System.out.println("hello SO"); }
}
}
Випадок 1: Моментальне встановлення статичного вкладеного класу з класу, що не охоплює
class NonEnclosingClass {
public static void main(String[] args) {
/*instantiate the Nested class that is a static
member of the EnclosingClass class:
*/
EnclosingClass.Nested n = new EnclosingClass.Nested();
n.someMethod(); //prints out "hello"
}
}
Випадок 2: Моментальне встановлення статичного вкладеного класу з класу, що вкладається
class EnclosingClass {
static class Nested {
void anotherMethod() { System.out.println("hi again"); }
}
public static void main(String[] args) {
//access enclosed class:
Nested n = new Nested();
n.anotherMethod(); //prints out "hi again"
}
}
Спеціальність класичних класів:
Висновок:
Питання: в чому головна відмінність внутрішнього класу від статичного вкладеного класу на Java?
Відповідь: просто перегляньте специфіку кожного згаданих вище класів.
Внутрішній клас і вкладений статичний клас на Java - це класи, оголошені всередині іншого класу, відомого як клас верхнього рівня в Java. У термінології Java, якщо ви оголошуєте вкладений клас статичним, він буде називатися вкладеним статичним класом на Java, тоді як нестатичний вкладений клас просто називається Внутрішнім класом.
Що таке Внутрішній клас у Java?
Будь-який клас, який не є найвищим рівнем або оголошений усередині іншого класу, відомий як вкладений клас, а з тих вкладених класів, клас яких оголошено нестатичним, відомий як Внутрішній клас на Java. Є три види внутрішнього класу на Java:
1) Локальний внутрішній клас - оголошується всередині блоку коду чи методу.
2) Анонімний внутрішній клас - це клас, який не має імені для посилання та ініціалізований там же, де його створюють.
3) внутрішній клас члена - оголошується як нестатичний член зовнішнього класу.
public class InnerClassTest {
public static void main(String args[]) {
//creating local inner class inside method i.e. main()
class Local {
public void name() {
System.out.println("Example of Local class in Java");
}
}
//creating instance of local inner class
Local local = new Local();
local.name(); //calling method from local inner class
//Creating anonymous inner class in Java for implementing thread
Thread anonymous = new Thread(){
@Override
public void run(){
System.out.println("Anonymous class example in java");
}
};
anonymous.start();
//example of creating instance of inner class
InnerClassTest test = new InnerClassTest();
InnerClassTest.Inner inner = test.new Inner();
inner.name(); //calling method of inner class
}
//Creating Inner class in Java
private class Inner{
public void name(){
System.out.println("Inner class example in java");
}
}
}
Що є вкладений статичний клас на Java?
Вкладений статичний клас - це ще один клас, який оголошується всередині класу як член та робиться статичним. Вкладений статичний клас також оголошується членом зовнішнього класу і може бути приватним, загальнодоступним або захищеним, як і будь-який інший член. Однією з головних переваг вкладеного статичного класу над внутрішнім класом є те, що екземпляр вкладеного статичного класу не приєднаний до жодного огороджувального екземпляра Зовнішнього класу. Для створення екземпляра вкладеного статичного класу в Java вам також не потрібен екземпляр Зовнішнього класу .
1) Він може отримати доступ до статичних даних членів зовнішнього класу, включаючи приватні.
2) Статичний вкладений клас не може отримати доступ до нестатичних (примірників) даних або методу даних .
public class NestedStaticExample {
public static void main(String args[]){
StaticNested nested = new StaticNested();
nested.name();
}
//static nested class in java
private static class StaticNested{
public void name(){
System.out.println("static nested class example in java");
}
}
}
Посилання: Внутрішній клас та вкладений статичний клас у Java із прикладом
Я думаю, що люди повинні помітити на Плакаті, що: Static Nest Class - лише перший внутрішній клас. Наприклад:
public static class A {} //ERROR
public class A {
public class B {
public static class C {} //ERROR
}
}
public class A {
public static class B {} //COMPILE !!!
}
Отже, підсумовуючи, статичний клас не залежить від того, який клас він містить. Отже, вони не можуть у звичайному класі. (тому що нормальному класу потрібен екземпляр).
Коли ми оголошуємо статичний клас члена всередині класу, він відомий як вкладений клас верхнього рівня або статичний вкладений клас. Це можна продемонструвати як нижче:
class Test{
private static int x = 1;
static class A{
private static int y = 2;
public static int getZ(){
return B.z+x;
}
}
static class B{
private static int z = 3;
public static int getY(){
return A.y;
}
}
}
class TestDemo{
public static void main(String[] args){
Test t = new Test();
System.out.println(Test.A.getZ());
System.out.println(Test.B.getY());
}
}
Коли ми оголошуємо нестатичний клас члена всередині класу, він називається внутрішнім класом. Внутрішній клас можна продемонструвати, як показано нижче:
class Test{
private int i = 10;
class A{
private int i =20;
void display(){
int i = 30;
System.out.println(i);
System.out.println(this.i);
System.out.println(Test.this.i);
}
}
}
Нижче наведено приклад static nested class
та inner class
:
OuterClass.java
public class OuterClass {
private String someVariable = "Non Static";
private static String anotherStaticVariable = "Static";
OuterClass(){
}
//Nested classes are static
static class StaticNestedClass{
private static String privateStaticNestedClassVariable = "Private Static Nested Class Variable";
//can access private variables declared in the outer class
public static void getPrivateVariableofOuterClass(){
System.out.println(anotherStaticVariable);
}
}
//non static
class InnerClass{
//can access private variables of outer class
public String getPrivateNonStaticVariableOfOuterClass(){
return someVariable;
}
}
public static void accessStaticClass(){
//can access any variable declared inside the Static Nested Class
//even if it private
String var = OuterClass.StaticNestedClass.privateStaticNestedClassVariable;
System.out.println(var);
}
}
OuterClassTest:
public class OuterClassTest {
public static void main(String[] args) {
//access the Static Nested Class
OuterClass.StaticNestedClass.getPrivateVariableofOuterClass();
//test the private variable declared inside the static nested class
OuterClass.accessStaticClass();
/*
* Inner Class Test
* */
//Declaration
//first instantiate the outer class
OuterClass outerClass = new OuterClass();
//then instantiate the inner class
OuterClass.InnerClass innerClassExample = outerClass. new InnerClass();
//test the non static private variable
System.out.println(innerClassExample.getPrivateNonStaticVariableOfOuterClass());
}
}
Я думаю, що жоден із наведених вище відповідей не дає справжнього прикладу для вас різниці між вкладеним класом та статичним вкладеним класом у плані дизайну додатків. І головна відмінність статичного вкладеного класу від внутрішнього класу - це можливість доступу до зовнішнього поля екземпляра класу.
Давайте розглянемо два наступні приклади.
Статичний гніздовий клас: Хорошим прикладом використання статичних вкладених класів є модель побудови ( https://dzone.com/articles/design-patterns-the-builder-pattern ).
Для BankAccount ми використовуємо статичний вкладений клас, в основному тому, що
Статичний екземпляр класу гнізд може бути створений перед зовнішнім класом.
У моделі конструктора будівельник - це клас помічників, який використовується для створення BankAccount.
public class BankAccount {
private long accountNumber;
private String owner;
...
public static class Builder {
private long accountNumber;
private String owner;
...
static public Builder(long accountNumber) {
this.accountNumber = accountNumber;
}
public Builder withOwner(String owner){
this.owner = owner;
return this;
}
...
public BankAccount build(){
BankAccount account = new BankAccount();
account.accountNumber = this.accountNumber;
account.owner = this.owner;
...
return account;
}
}
}
Внутрішній клас: загальним використанням внутрішніх класів є визначення обробника подій. https://docs.oracle.com/javase/tutorial/uiswing/events/generalrules.html
Для MyClass ми використовуємо внутрішній клас, головним чином тому, що:
Внутрішній клас MyAdapter потребує доступу до зовнішнього члена класу.
У прикладі MyAdapter асоціюється лише з MyClass. Жоден інший клас не пов'язаний з MyAdapter. тому краще їх організувати разом, не використовуючи конвенцію імен
public class MyClass extends Applet {
...
someObject.addMouseListener(new MyAdapter());
...
class MyAdapter extends MouseAdapter {
public void mouseClicked(MouseEvent e) {
...// Event listener implementation goes here...
...// change some outer class instance property depend on the event
}
}
}
Перш за все, не існує такого класу, який називається Static class. Статичний модифікатор, який використовується з внутрішнім класом (називається вкладеним класом), говорить про те, що він є статичним членом Зовнішнього класу, а це означає, що ми можемо отримати доступ до нього, як і до інших статичних членів, і не маючи жодного екземпляр Зовнішнього класу. (Яка вигода від статики спочатку.)
Різниця між використанням вкладеного класу та звичайним внутрішнім класом:
OuterClass.InnerClass inner = new OuterClass().new InnerClass();
По-перше, ми можемо створити зовнішній клас, а потім отримати доступ до Внутрішнього класу.
Але якщо клас введений, то синтаксис:
OuterClass.InnerClass inner = new OuterClass.InnerClass();
Який використовує статичний синтаксис як звичайну реалізацію статичного ключового слова.
Мова програмування Java дозволяє визначити клас в іншому класі. Такий клас називається вкладеним класом і проілюстрований тут:
class OuterClass {
...
class NestedClass {
...
}
}
Вкладені класи поділяються на дві категорії: статичні та нестатичні. Вкладені класи, які оголошені статичними, називаються статичними вкладеними класами. Нестатичні вкладені класи називають внутрішніми класами. Одне, що ми маємо пам’ятати - це нестатичні вкладені класи (внутрішні класи), які мають доступ до інших членів класу, що додається, навіть якщо вони оголошені приватними. Статичні вкладені класи мають доступ до інших членів класу, що додається, лише якщо вони статичні. Він не може отримати доступ до нестатичних членів зовнішнього класу. Як і у випадку методів та змінних класів, статичний вкладений клас асоціюється із його зовнішнім класом. Наприклад, щоб створити об’єкт для статичного вкладеного класу, використовуйте цей синтаксис:
OuterClass.StaticNestedClass nestedObject =
new OuterClass.StaticNestedClass();
Щоб створити внутрішній клас, потрібно спочатку інстанціювати зовнішній клас. Потім створіть внутрішній об’єкт у зовнішньому об'єкті за допомогою цього синтаксису:
OuterClass.InnerClass innerObject = new OuterClass().new InnerClass();
Чому ми використовуємо вкладені класи
Джерело: Підручники Java ™ - Вкладені класи
Різниця полягає в тому, що вкладене оголошення класу, яке також є статичним, може бути екземпляром поза класом, що додає.
Коли у вас є вкладене оголошення класу, яке не є статичним, також відоме як внутрішній клас , Java не дозволить вам інстанціювати його, окрім , що . Об'єкт, створений із внутрішнього класу, пов'язаний з об'єктом, створеним із зовнішнього класу, тому внутрішній клас може посилатися на поля зовнішнього.
Але якщо вона статична, то посилання не існує, до зовнішніх полів не можна отримати доступ (за винятком звичайної посилання, як будь-який інший об'єкт), і тому ви можете інстанціювати вкладений клас самостійно.
Його досить простий, порівнюючи статичні локальні класи та нестатичні внутрішні класи.
Відмінності:
Статичний локальний клас:
Доступ до лише статичних членів зовнішнього класу.
Неможливо мати статичні ініціалізатори.
Не можна отримати доступ безпосередньо за межами функції, де її оголошено
Я проілюстрував різні можливі правильні сценарії та помилки, які можуть виникнути в коді Java.
class Outter1 {
String OutStr;
Outter1(String str) {
OutStr = str;
}
public void NonStaticMethod(String st) {
String temp1 = "ashish";
final String tempFinal1 = "ashish";
// below static attribute not permitted
// static String tempStatic1 = "static";
// below static with final attribute not permitted
// static final String tempStatic1 = "ashish";
// synchronized keyword is not permitted below
class localInnerNonStatic1 {
synchronized public void innerMethod(String str11) {
str11 = temp1 +" sharma";
System.out.println("innerMethod ===> "+str11);
}
/*
// static method with final not permitted
public static void innerStaticMethod(String str11) {
str11 = temp1 +" india";
System.out.println("innerMethod ===> "+str11);
}*/
}
// static class not permitted below
// static class localInnerStatic1 { }
}
public static void StaticMethod(String st) {
String temp1 = "ashish";
final String tempFinal1 = "ashish";
// static attribute not permitted below
//static String tempStatic1 = "static";
// static with final attribute not permitted below
// static final String tempStatic1 = "ashish";
class localInnerNonStatic1 {
public void innerMethod(String str11) {
str11 = temp1 +" sharma";
System.out.println("innerMethod ===> "+str11);
}
/*
// static method with final not permitted
public static void innerStaticMethod(String str11) {
str11 = temp1 +" india";
System.out.println("innerMethod ===> "+str11);
}*/
}
// static class not permitted below
// static class localInnerStatic1 { }
}
// synchronized keyword is not permitted
static class inner1 {
static String temp1 = "ashish";
String tempNonStatic = "ashish";
// class localInner1 {
public void innerMethod(String str11) {
str11 = temp1 +" sharma";
str11 = str11+ tempNonStatic +" sharma";
System.out.println("innerMethod ===> "+str11);
}
public static void innerStaticMethod(String str11) {
// error in below step
str11 = temp1 +" india";
//str11 = str11+ tempNonStatic +" sharma";
System.out.println("innerMethod ===> "+str11);
}
//}
}
//synchronized keyword is not permitted below
class innerNonStatic1 {
//This is important we have to keep final with static modifier in non
// static innerclass below
static final String temp1 = "ashish";
String tempNonStatic = "ashish";
// class localInner1 {
synchronized public void innerMethod(String str11) {
tempNonStatic = tempNonStatic +" ...";
str11 = temp1 +" sharma";
str11 = str11+ tempNonStatic +" sharma";
System.out.println("innerMethod ===> "+str11);
}
/*
// error in below step
public static void innerStaticMethod(String str11) {
// error in below step
// str11 = tempNonStatic +" india";
str11 = temp1 +" india";
System.out.println("innerMethod ===> "+str11);
}*/
//}
}
}
item 22 : Favor static member classes over non static