В чем причина метода 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(), который мне не хватает? Это полезно в любом случае? Кто-нибудь когда-нибудь использовал его для чего-нибудь? Может быть важно какое-то ручное вращение бит или что-то подобное?


ИЗМЕНИТЬ (после дополнительных исследований)

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


person Petr Janeček    schedule 02.06.2013    source источник
comment
Эта ошибка содержит исходное объяснение! Джош Блош (сокращено мной, дух сообщения сохранен): Метод size... был прискорбно занижен. ...при условии, что *НИЧЕГО* о возвращаемом значении было... опасно... Значение может... отличаться на разных платформах. Многократное выполнение двух BitSet может привести к тому, что значение... будет расти без ограничений... ...невозможно исправить..., поэтому мы добавили новый, точно определенный метод (length), который возвращает полезную информацию... [ и] заменяет метод size.   -  person Petr Janeček    schedule 05.09.2019


Ответы (4)


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

Верный.

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

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

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

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

  • вы пытаетесь установить «столб забора» для итерации битов в наборе, и
  • весьма вероятно, что вы перестанете повторять задолго до конца, и
  • не имеет значения, если вы идете немного дальше последнего установленного бита.

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

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

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

person Stephen C    schedule 02.06.2013
comment
Похоже, я все-таки был на правильном пути. Я подожду еще немного, если кто-нибудь предложит революционное применение этому методу, но, думаю, галочка будет за вами. Жалко, что не осудили. Это сэкономило бы мне драгоценное время при использовании неправильного. - person Petr Janeček; 02.06.2013

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

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

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

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

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

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

person Jirka Hanika    schedule 02.06.2013

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

person Peter Lawrey    schedule 02.06.2013
comment
Я знаю, что он делает. Но мне интересно, почему кто-то когда-либо захочет вызывать такой метод. Или включить его в API, в первую очередь. Прав ли я со своим предположением о том, что BitSet является классом утилит старого поколения? (см. мое редактирование) - person Petr Janeček; 02.06.2013
comment
@EJP Хотя это может быть яснее, не видите разницы. Есть ли место, не заполненное нулями и единицами? - person Peter Lawrey; 02.06.2013

Одна из основных причин, по которой я думаю, что это может быть полезно, заключается в том, что нам нужно расширить класс 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;
 }
person user4840623    schedule 28.04.2015