Внутренний класс в интерфейсе vs в классе
В чем разница между этими двумя объявлениями внутреннего класса? Также комментируйте преимущества/недостатки?
case A: класс внутри класса.
public class Levels {
static public class Items {
public String value;
public String path;
public String getValue() {
return value;}
}
}
и case B: класс внутри интерфейса.
public interface Levels{
public class Items {
public String value;
public String path;
public String getValue() {
return value;}
}
}
Сделана коррекция: для размещения метода getvalue.
Дополнительная информация:
Я могу создать экземпляр класса Item в обоих случаях A и B в другом классе, который не реализует интерфейс AT ALL.
public class Z{//NOTE: NO INTERFACE IMPLEMENTED here!!!!
Levels.Items items = new Levels.Items();
}
Поскольку интерфейс не создается, все элементы внутри интерфейса доступны с помощью точечной нотации без интерфейса LEVELS, созданной просто потому, что вы не можете создавать экземпляр интерфейса - эффективно создавая класс, определенный внутри интерфейса, проницаемый для статической ссылки.
Так что говорить, что класс Items в случае B не является статичным, не имеет смысла. Поскольку оба случая A и B создаются таким же образом, я не ищу семантики того, что является статическим или внутренним или вложенным. Прекратите давать ответы на семантику. Я хочу компилятор, время исполнения и поведенческие различия/преимущества, или если никто не говорит об этом. Больше нет ответов на семантику, пожалуйста!!!!! Эксперт по спецификациям JVM или .NET VM, пожалуйста, ответьте на этот вопрос ответа, а не на семантико-текстовые книги.
Ответы
Ответ 1
Статические внутренние классы в основном аналогичны классам верхнего уровня, за исключением того, что внутренний класс имеет доступ ко всем статическим переменным и методам охватывающего класса. Вложенное имя класса эффективно добавляется к пространству имен пакета внутреннего класса. Объявляя класс как статический внутренний класс, вы сообщаете, что класс каким-то образом неразрывно связан с контекстом охватывающего класса.
Нестатические внутренние классы менее распространены. Основное различие заключается в том, что экземпляры нестатического внутреннего класса содержат неявную ссылку на экземпляр охватывающего класса и, как результат, имеют доступ к переменным экземпляра и методам этого экземпляра класса. Это приводит к некоторым нечетным типам иконок создания, например:
Levels levels = new Levels(); // first need an instance of the enclosing class
// The items object contains an implicit reference to the levels object
Levels.Items items = levels.new Items();
Нестатические внутренние классы гораздо более тесно связаны с окружающими классами, чем статические внутренние классы. Они имеют правильное использование (например, итераторы часто реализуются как нестатические внутренние классы в классе структуры данных, которые они перебирают).
Общей ошибкой является объявление нестатического внутреннего класса, когда вам действительно нужно поведение статического внутреннего класса.
Ответ 2
Внутренний класс static
- это вложенный класс, а нестатический - внутренний. Для более смотрите здесь.
Однако, мне нравится приводить выдержку из той же ссылки.
Статический вложенный класс взаимодействует с члены экземпляра его внешнего класс (и другие классы), как любой другой класс верхнего уровня. В результате, статический вложенный класс поведенчески класс верхнего уровня, который был вложен в другом классе верхнего уровня для удобство упаковки.
Во втором случае вы не использовали слово static
. И вы думаете, что это неявно будет static
, потому что это интерфейс. Вы правы, если предположить, что.
Вы можете создать экземпляр внутреннего класса в вашем интерфейсе, как статический вложенный класс, потому что это действительно вложенный класс static
.
Levels.Items hello = new Levels.Items();
Итак, вышеприведенный оператор будет действителен в обоих случаях. Ваш первый случай - статический вложенный класс, а во втором случае вы не указали static
, но даже тогда это будет статический вложенный класс, потому что он находится в интерфейсе. Следовательно, нет никакой разницы, кроме того, что один вложен в класс, а другой в интерфейсе.
Обычно внутренний класс в классе не в интерфейсе будет создан таким образом, как показано ниже.
Levels levels = new Levels();
Levels.Items items = levels.new Items();
Кроме того, "нестатический" внутренний класс будет иметь неявную ссылку на свой внешний класс. Это не относится к "статическому" вложенному классу.
Ответ 3
Если вы объявляете вложенный класс в интерфейсе, он всегда является общедоступным и статическим. Итак:
public interface Levels{
class Items {
public String value;
public String path;
public String getValue() {return value;}
}
}
Точно так же, как
public interface Levels{
public static class Items {
public String value;
public String path;
public String getValue() {return value;}
}
}
И даже
public interface Levels{
static class Items {
public String value;
public String path;
public String getValue() {return value;}
}
}
Я проверил это с помощью javap -verbose, и все они производят
Compiled from "Levels.java"
public class Levels$Items extends java.lang.Object
SourceFile: "Levels.java"
InnerClass:
public #14= #3 of #23; //Items=class Levels$Items of class Levels
minor version: 0
major version: 50
Constant pool:
const #1 = Method #4.#21; // java/lang/Object."<init>":()V
const #2 = Field #3.#22; // Levels$Items.value:Ljava/lang/String;
const #3 = class #24; // Levels$Items
const #4 = class #25; // java/lang/Object
const #5 = Asciz value;
const #6 = Asciz Ljava/lang/String;;
const #7 = Asciz path;
const #8 = Asciz <init>;
const #9 = Asciz ()V;
const #10 = Asciz Code;
const #11 = Asciz LineNumberTable;
const #12 = Asciz LocalVariableTable;
const #13 = Asciz this;
const #14 = Asciz Items;
const #15 = Asciz InnerClasses;
const #16 = Asciz LLevels$Items;;
const #17 = Asciz getValue;
const #18 = Asciz ()Ljava/lang/String;;
const #19 = Asciz SourceFile;
const #20 = Asciz Levels.java;
const #21 = NameAndType #8:#9;// "<init>":()V
const #22 = NameAndType #5:#6;// value:Ljava/lang/String;
const #23 = class #26; // Levels
const #24 = Asciz Levels$Items;
const #25 = Asciz java/lang/Object;
const #26 = Asciz Levels;
{
public java.lang.String value;
public java.lang.String path;
public Levels$Items();
Code:
Stack=1, Locals=1, Args_size=1
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 2: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this LLevels$Items;
public java.lang.String getValue();
Code:
Stack=1, Locals=1, Args_size=1
0: aload_0
1: getfield #2; //Field value:Ljava/lang/String;
4: areturn
LineNumberTable:
line 7: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this LLevels$Items;
}
Ответ 4
Примеры, которые вы даете вложенным/внутренним классам, - это (ИМО) плохие примеры. Кроме того, второй пример недействителен Java, поскольку интерфейс может только объявлять (неявно) абстрактные методы. Вот лучший пример:
public interface Worker {
public class Response {
private final Status status;
private final String message;
public Response(Status status, String message) {
this.status = status; this.message = message;
}
public Status getStatus() { return status; }
public String getMessage() { return message; }
}
...
public Response doSomeOperation(...);
}
Встраивая класс Response, мы указываем, что это фундаментальная часть Worker API без каких-либо других целей.
Класс Map.Entry является хорошо известным примером этой идиомы.
Ответ 5
IMHO, преимущество заключается в том, что у вас меньше классов, загромождающих вашу папку проекта, если они тривиальны; недостаток заключается в том, что когда ваш внутренний класс растет по мере изменения требования, maintenacne станет вашим кошмаром.
Ответ 6
Я думал, что первый объявит класс Levels и статический внутренний класс под названием Items. Элементы могут ссылаться на Levels.Items и будут статическими.
Пока второй объявит простой внутренний класс, к которому можно получить доступ, используя Levels.Items, как в следующем:
Levels.Items hello = new Levels.Items();
EDIT: это абсолютно неправильно, прочитайте комментарии и другие ответы.