В чем причина метода BitSet size()?

Есть ли прецедент для метода size() класса java.util.BitSet?

Я имею в виду - JavaDoc ясно говорит, что он зависит от реализации, он возвращает размер внутреннего хранилища long[] в битах. Из того, что он говорит, можно сделать вывод, что вы не сможете установить бит с более высоким индексом, чем size(), но это не так, BitSet может вырасти автоматически:

BitSet myBitSet = new BitSet();
System.out.println(myBitSet.size());    // prints "64"
myBitSet.set(768);
System.out.println(myBitSet.size());    // prints "832"

В каждой отдельной встрече с BitSet, которую я имел в своей жизни, я всегда хотел использовать length(), так как это возвращает логический размер BitSet:

BitSet myBitSet = new BitSet();
System.out.println(myBitSet.length());    // prints "0"
myBitSet.set(768);
System.out.println(myBitSet.length());    // prints "769"

Несмотря на то, что я программировал Java в течение последних 6 лет, эти два метода всегда очень запутывают меня. Я часто смешиваю их и неправильно использую случайно, потому что в моей голове я думаю о BitSet как умном Set<boolean>, где я бы использовал size().

Мне нравится, если ArrayList имеет length(), возвращая число элементов и size() возвращает размер базового массива.

Теперь, есть ли какой-либо прецедент для метода size(), который мне не хватает? Это полезно? Кто-нибудь когда-либо использовал это для чего-нибудь? Может быть, это важно для некоторых ручных бит-скручиваний или чего-то подобного?


EDIT (после нескольких исследований)

Я понял, что BitSet был введен в Java 1.0, тогда как структура Collections с большинством используемых нами классов была введена в Java 1.2. Так что в основном мне кажется, что size() хранится из-за унаследованных причин, и для него нет реального использования. Новые классы Collection не имеют таких методов, в то время как некоторые из старых (Vector, например) делают.

Ответы

Ответ 1

Я понял, что BitSet был представлен в Java 1.0, а структура коллекций с большинством используемых нами классов была введена в Java 1.2.

Правильно.

Так что в основном мне кажется, что size() сохраняется из-за унаследованных причин, и для него нет реального использования.

Да, в значительной степени.

Другой метод "размер" length(), который дает вам наибольший индекс, в котором установлен бит. С логической точки зрения length() более полезен, чем size()... но length() был введен только в Java 1.2.

Единственный (гипотетический) случай использования, я могу думать о том, где size() может быть лучше, чем length(), когда:

  • вы пытаетесь установить "столбец забора" для итерации бит в наборе и
  • очень вероятно, что вы прекратите итерацию до конца, и
  • Неважно, вы немного отстаете от последнего установленного бита.

В этом случае size(), возможно, лучше, чем length(), потому что это более дешевый вызов. (Посмотрите на исходный код...) Но это довольно маргинальный.

(я предполагаю, что другой пример использования аналогичных строк - это когда вы создаете новый BitSet и предопределяете его на основе size() существующего BitSet. Опять же, разница является предельной.)

Но вы правы в отношении совместимости. Понятно, что они не могли либо избавиться от size(), либо изменить свою семантику, не создавая проблем совместимости. Поэтому они, по-видимому, решили оставить его в покое. (Действительно, они даже не видели необходимости его обесценивать. "Урон" в использовании не особенно полезного метода в API минимален.)

Ответ 2

Если метод size не был разработан разработчиками Java как общедоступный, он все равно несомненно существовал бы как частный метод/поле. Поэтому мы обсуждаем его доступность и, возможно, именование.

Java 1.0 взяла много вдохновения, а не только процедурный синтаксис, из C/С++. В стандартной библиотеке С++ существуют аналоги с BitSet length и size. Они называются там size и capacity, соответственно. В С++ редко существует трудная причина использовать capacity, а тем более - в сборнике мусора, таком как Java, но доступный доступ к этому методу по-прежнему полезен. Я объясню в терминах Java.

Скажите, каково максимальное количество машинных команд, когда-либо необходимых для выполнения операции BitSet, например set? Хотелось бы ответить "просто горсткой", но это справедливо только в том случае, если эта конкретная операция не приведет к перераспределению всего базового массива. Теоретически перераспределение превращает алгоритм постоянного времени в линейное время.

Имеет ли это теоретическое различие много практического воздействия? Редко. Массив обычно не растет слишком часто. Однако всякий раз, когда у вас есть алгоритм, работающий над постепенно растущим BitSet с примерно известным конечным размером, вы сэкономите на перераспределениях, если вы передадите окончательный размер уже конструктору BitSet. В некоторых особых обстоятельствах это может даже иметь заметный эффект, в большинстве случаев это не повредит.

  • set тогда имеет постоянную сложность во времени - вызов его никогда не может заблокировать приложение слишком долго.
  • Если только один чрезвычайно большой экземпляр BitSet использует всю вашу доступную память (по дизайну), то замена может начинаться заметно позже, в зависимости от того, как ваша JVM реализует операцию роста (с дополнительной копией или без нее).

Теперь представьте, что вы работаете со многими BitSets, все из которых были выделены целевым размером. Вы создаете один экземпляр BitSet из другого, и вы хотите, чтобы новый делил старый целевой размер, поскольку вы знаете, что будете использовать их рядом друг с другом. Наличие открытого метода size упрощает его реализацию.

Ответ 3

Это число 0 и 1, которое должно быть кратным 64. Вы можете использовать мощность() для числа 1s.

Ответ 4

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

protected Set bitset;
public int length() {
  int returnValue = 0;
  // Make sure set not empty
  // Get maximum value +1
  if (bitset.size() > 0) {
     Integer max = (Integer)Collections.max(bitset);
     returnValue = max.intValue()+1;
  }
  return returnValue;
 }