#java #effective-java
#java #эффективный-java
Вопрос:
Это код, о котором я говорю:
public class Stack {
private Object[] elements;
private int size = 0;
private static final int DEFAULT_INITIAL_CAPACITY = 16;
public Stack() {
elements = new Object[DEFAULT_INITIAL_CAPACITY];
}
public void push(Object e) {
ensureCapacity();
elements[size ] = e;
}
public Object pop() {
if (size == 0)
throw new EmptyStackException();
return elements[--size];
}
/**
* Ensure space for at least one more element, roughly
* doubling the capacity each time the array needs to grow.
*/
private void ensureCapacity() {
if (elements.length == size)
elements = Arrays.copyOf(elements, 2 * size 1);
}
}
Почему бы просто не сохранить последнюю строку как elements = Arrays.copyOf(elements, 2 * size);
?
Единственный случай, когда это могло бы быть допустимым, это если бы начальный размер стека был равен 0. Но в данном случае это константа — DEFAULT_INITIAL_CAPACITY (ненулевое значение). И нет другого перегруженного конструктора, который мог бы принять это значение от пользователя (или по умолчанию оно равно 0)
Комментарии:
1. Если начальный размер равен 0, простое удвоение работает не слишком хорошо.
2. да, но здесь этого нет — здесь он начинается с ненулевого значения DEFAULT_INITIAL_CAPACITY (16) . Если он был создан из параметра в конструкторе — это могло быть допустимым случаем.
3. Я думаю, проблема в том, что у вас была начальная емкость 0. Я знаю, что в опубликованном вами коде это невозможно, но я подозреваю, что этот парень Джошуа Блох, вероятно, намеревался добавить перегруженный конструктор, принимая аргумент для настраиваемой начальной емкости. Если вы передали 0 такому конструктору, код не будет вести себя так, как ожидалось, если он только удвоит длину. Тем не менее, аналогичный эффект также может быть достигнут с помощью оператора if для проверки 0, что лично было бы моим первым подходом.
4. этот парень Джошуа Блох — Джи, он Джошуа Блох, ради всего святого! Он не пишет код, предполагающий что-то со стороны читателей, и именно поэтому я задал этот вопрос — просто чтобы перепроверить, не упускаю ли я здесь что-то тонкое!
5. Это или кто-то, вероятно, подкласс this и добавил этот метод «сброса» или перегрузил конструктор, чтобы принять размер 0.
Ответ №1:
Я интерпретирую это как защиту от гипотетической будущей ошибки. Это правда, что, как написано, этот класс не будет иметь емкость массива 0, поэтому добавление 1 не является строго необходимым, но это предположение может незаметно потерпеть неудачу при добавлении новых функций.
Примерами возможных дополнительных функций являются функции from java.util.ArrayList
, которые имеют trimToSize()
метод, который может устанавливать емкость на 0, и конструктор, который позволяет инициализировать данные из (возможно, пустой) коллекции, и конструктор, который позволяет явно устанавливать емкость на 0. Вы также можете представить функцию, которая автоматически уменьшает выделенную емкость этого класса при его освобождении. Или, может быть, кто-то отредактирует DEFAULT_INITIAL_CAPACITY
константу. Теперь представьте, что методы, изменяющие емкость, разделяются полными экранами комментариев javadoc и разделяются по подклассам. Легко забыть, что вы должны были предотвратить превращение емкости в 0.
Если ensureCapacity()
зависит от ненулевого размера, вы всегда должны учитывать это предположение при переработке класса. Добавление 1
— это недорогое изменение, которое устраняет это беспокойство. Это также пример простого арифметического способа решения пограничного случая.
Ответ №2:
Мне это кажется немного более очевидным, чем все формулировки, которые использует @Boann, хотя у него / нее есть более простой ответ в его / ее ответе. Ответ прост: автор хочет поддерживать запуск массива с нулевым размером … настройки DEFAULT_INITIAL_CAPACITY = 0
. Это приведет к сбою кода без 1
. Нет другого способа, чтобы размер elements
массива мог быть равен нулю, кроме как если он начинается таким образом, и это единственная причина для 1
.
По мере написания кода нет причин для 1
.