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

Неинициализированные примитивные переменные экземпляра используют память?

В Java, стоит ли в памяти объявлять переменную экземпляра класса без ее инициализации?
Например: использует ли int i; любую память, если я не инициализирую ее с помощью i = 5;?

Подробнее:

У меня есть огромный суперкласс, в котором расширяются многие разные (не совсем другие, чтобы иметь свои суперклассы). Некоторые подклассы не используют каждый примитив, объявленный суперклассом. Могу ли я просто сохранить такие примитивы как неинициализированные и только инициализировать их в необходимых подклассах для сохранения памяти?

4b9b3361

Ответ 1

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

Например, каждый int по умолчанию будет инициализирован 0 и будет занимать 4 байты.

Для членов класса:

int i;

совпадает с:

int i = 0;

Вот что JLS говорит о переменных экземпляра:

Если класс T имеет поле a, которое является переменной экземпляра, то создается новая инициальная переменная a и инициализируется значением по умолчанию (§ 4.12.5) как часть каждого вновь созданного объекта класса T или любого класса, который является подклассом T (§8.1.4). Переменная экземпляра эффективно перестает существовать, когда объект, о котором он является полем, больше не ссылается после завершения любой необходимой финализации объекта (§12.6).

Ответ 2

Да, память выделяется, хотя вы не присваиваете ей никакого значения.

int i;

Требуется 32 bit память (распределение). Независимо от того, используете вы это или нет.

Некоторые подклассы не используют каждый примитив, объявленный суперклассом. Могу ли я просто сохранить такие примитивы как неинициализированные и только инициализировать их в необходимых подклассах для сохранения памяти?

Опять же, независимо от того, где вы инициализировали, память выделяет.

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

Edit: Добавление еще одной точки, которая в отличие от примитивных ссылок по умолчанию равна null, которая несет в себе память

 4 bytes(32-bit) 
 8 bytes on (64-bit)

Ответ 3

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

Возьмем небольшой пример:

public class MemTest {
    public void doSomething() {
        long i = 0;  // Line 3
        if(System.currentTimeMillis() > 0) {
            i = System.currentTimeMillis();
            System.out.println(i);
        }
        System.out.println(i);
    }
}

Если мы посмотрим на генерируемый байт-код:

  L0
    LINENUMBER 3 L0
    LCONST_0
    LSTORE 1

Хорошо, как и ожидалось, мы присваиваем значение в строке 3 в коде, теперь, если мы изменим строку 3 на (и удалим второй println из-за ошибки компилятора):

long i; // Line 3

... и проверьте байт-код, тогда ничего не генерируется для строки 3. Таким образом, ответ заключается в том, что в данный момент памяти не используется. Фактически, LSTORE встречается только в строке 5, когда мы назначаем переменную. Таким образом, объявление неназначенной переменной метода не использует никакой памяти и, по сути, не генерирует какой-либо байт-код. Это эквивалентно объявлению, в котором вы его сначала назначили.

Ответ 4

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

В этом случае переменные int присваиваются 0 и будут занимать 4 bytes за каждый.

Ответ 5

Ни спецификация языка Java, ни спецификация виртуальной машины Java не указывают ответ на этот вопрос, поскольку это деталь реализации. Фактически, JVMS §2.7 конкретно говорит:

Представление объектов

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

Теоретически, соответствующая виртуальная машина может реализовывать объекты, которые имеют множество полей, используя набор битовых флагов, чтобы отметить, какие поля были установлены для значений, отличных от значений по умолчанию. Первоначально никакие поля не были бы выделены, биты флага были бы все 0, и объект был бы небольшим. Когда поле сначала задано, бит соответствующего флага будет установлен в 1, и объект будет изменен, чтобы освободить место для него. [Сборщик мусора уже предоставляет необходимое оборудование для мгновенного приостановки запуска кода, чтобы переместить живые объекты вокруг кучи, что необходимо для их изменения.]

На практике это не очень хорошая идея, потому что, даже если она экономит память, она сложна и медленна. Доступ к полям требует временного блокирования объекта для предотвращения коррупции из-за многопоточности; затем считывание текущих битов флага; и если поле существует, то подсчет установленных бит для вычисления текущего смещения желаемого поля относительно основания объекта; затем чтение поля; и, наконец, разблокировать объект.

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

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

В конечном итоге плоская компоновка полей - это соглашение, а не правило, хотя вы все равно можете положиться на него.

Ответ 6

В Java, когда вы объявляете атрибут класса, например String str;, вы объявляете ссылку на объект, но он пока не указывает на какой-либо объект, если вы не повлияли на его значение str=value;. Но, как вы можете догадаться, ссылка, даже не указывая на место памяти, потребляет себе некоторую память.