Как выглядит Java в памяти - PullRequest
       0

Как выглядит Java в памяти

7 голосов
/ 31 января 2010

Я новичок в Java и все еще учусь. Я получил голову вокруг внутренних и анонимных классов. Теперь у меня есть технический вопрос о том, как выглядит Java в памяти, при выделении объектов, определении классов и т. Д.

Как выглядит память, когда у меня есть поле, которое является объектом, который определен во внешнем классе, по сравнению с внутренним классом. Статические классы выглядят иначе, чем не статичные?

Мне просто нужен визуальный справочник.

Спасибо, ребята

Ответы [ 6 ]

4 голосов
/ 31 января 2010

Полезная ссылка

http://www.artima.com/insidejvm/ed2/jvm6.html

3 голосов
/ 31 января 2010

Добро пожаловать в мир Java. В отличие от языка Си, в котором языковая конструкция и представление памяти в значительной степени взаимно однозначны, Java немного сложнее.

Прежде всего, когда люди говорят о Java, это может означать две вещи: Java-язык и Java-платформа. Здесь я буду понимать Java как язык программирования Java. Код, написанный на Java, сначала компилируется в байт-код, машинный код для виртуальной машины Java. Если вас интересуют подробности языка Java, вот Спецификация языка Java . А для JVM есть Спецификация виртуальной машины Java .

как выглядит память, когда у меня есть поле, которое является объектом, который определен во внешнем классе по сравнению с внутренним классом.

Я интерпретирую это так, как выглядит макет памяти в виртуальной машине Java, поскольку физический макет зависит от реализации JVM. Для этого я просмотрел Структура виртуальной машины Java .

Как и язык Java, виртуальная машина Java работает с двумя типами типов: примитивными типами и ссылочными типами . Соответственно, есть два вида значений, которые могут храниться в переменных, передаваться как аргументы, возвращаться методами и обрабатываться: примитивные значения и ссылочные значения .

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

....

Считается, что ссылка на объект имеет тип виртуальной машины Java reference. Значения типа reference можно рассматривать как указатели на объекты.

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

3 голосов
/ 31 января 2010

Подробности в реализации (не в спецификации). Однако реализации обычно следуют очень простому шаблону. Большая часть макета памяти в Java очень проста и понятна. Моя терминология может не соответствовать терминологии Java, так как я не много занимаюсь программированием на Java.

Как правило, объект начинается с указателя на свою vtable, а затем имеет несколько полей, которые следуют. Поля являются либо примитивными типами (int / bool / float), либо указателями на объекты. Вот и все для объектов. (Классы тоже являются объектами.) Нулевые указатели похожи на C, они недопустимы, не похожи на Python, где None - это объект.

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

В виртуальной таблице происходит вся магия. У каждого класса есть свой собственный vtable, общий для всех объектов. В vtable есть информация о классе, такая как размер его экземпляров и порядок расположения полей. Эта информация используется сборщиком мусора. В vtable также есть указатели на все методы, которые реализует класс. При вызове метода среда выполнения сначала извлекает указатель виртуальной таблицы из объекта, затем извлекает указатель метода из виртуальной таблицы, затем вызывает метод и передает объект методу в качестве неявного параметра. Он похож на C ++, но гораздо проще в реализации. Процесс можно пропустить, если метод или класс "final".

Я знаю, что в Java на самом деле нет "указателей", у нее есть "символические маркеры" или что-то подобное, но в общих реализациях просто используются старые старые указатели.

1 голос
/ 31 января 2010

Как то, на что похожа память, когда я есть поле, которое является объектом, который является определено во внешнем классе против внутренний класс. Ли статические классы смотреть отличается от нестатического?

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

(Обратите внимание, что другой механизм используется, когда анонимный класс использует локальные переменные / параметры в области действия метода, который его создает ...)

Если вам нужны более подробные сведения, вы можете использовать javap для дизассемблирования байт-кодов некоторых простых примеров классов.

Мне просто нужен визуальный справочник.

Извините, я не делаю красивые картинки: -)

0 голосов
/ 31 января 2010
public class I {
    class inner {
        public void ctor() {};
    }
}

Выглядит растерянно, как вы могли бы использовать JAD

class I$inner {

  // Field descriptor #6 LI;
  final synthetic I this$0;

  // Method descriptor #8 (LI;)V
  // Stack: 2, Locals: 2
  I$inner(I arg0);
     0  aload_0 [this]
     1  aload_1
     2  putfield I$inner.this$0 : I [10]
     5  aload_0 [this]
     6  invokespecial java.lang.Object() [12]
     9  return
      Line numbers:
        [pc: 0, line: 3]
      Local variable table:
        [pc: 0, pc: 10] local: this index: 0 type: I.inner

  // Method descriptor #14 ()V
  // Stack: 0, Locals: 1
  public void ctor();
    0  return
      Line numbers:
        [pc: 0, line: 4]
      Local variable table:
        [pc: 0, pc: 1] local: this index: 0 type: I.inner
}

Как hexdump, он будет начинаться с 0xcafebabe

0 голосов
/ 31 января 2010

Статический (вложенный) класс работает точно так же, как класс верхнего уровня. Единственное отличие состоит в том, что у его имени есть другое имя класса с префиксом. (Если вы посмотрите на скомпилированные файлы .class, то увидите, что вы получите что-то вроде «Outer $ Nested.class» для класса с именем Nested, вложенного в класс с именем Outer.)

Внутренний класс имеет скрытое поле, которое является ссылкой на содержащий экземпляр его внешнего класса. Когда вы пишете:

class Outer {
  final int x;

  class Nested {
    int y;

    Nested(int y) {
      this.y = y;
    }

    int bar() {
      return x + y;
    }
  }

  void foo() {
    Nested n = new Nested(5);
  }
}

Это как если бы вы написали:

class Outer {
  final int x;

  static class Nested {
    Outer outer;
    int y;

    Nested(Outer outer, int y) {
      this.outer = outer;
      this.y = y;
    }

    int bar() {
      return outer.x + y;
    }
  }

  void foo() {
    Nested n = new Nested(this, 5);
  }
}

Имя этого скрытого поля (которое я назвал здесь "внешним") скрыто к вам, хотя вы можете обратиться к нему, сказав Outer.this внутри внутренний класс (где Outer - это имя вашего внешнего класса, конечно). Также обратите внимание, что когда метод во внутреннем классе ссылается на что-то во внешнем классе, эта ссылка на самом деле через этот скрытый ссылка на внешний класс.

Есть несколько дополнительных сложностей, связанных с тем, как управление доступом (например, private) работает с вложенными / внутренними классами, но это не влияет на вопрос «памяти», который вы задаете.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...