Подтвердить что ты не робот

Внутренний класс в интерфейсе 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, пожалуйста, ответьте на этот вопрос ответа, а не на семантико-текстовые книги.

4b9b3361

Ответ 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: это абсолютно неправильно, прочитайте комментарии и другие ответы.