Если вы пытаетесь избежать шаблона, подобного этому, я просто украл:
if (access_flag & ACC_PUBLIC != 0)
{
public++;
}
if (access_flag & ACC_FINAL != 0)
{
final++;
}
...
Это отличный инстинкт. Я считаю правилом никогда не писать код, который выглядит таким избыточным. Он не только подвержен ошибкам и содержит больше кода в вашем классе, но и копирует и вставляет код, писать его очень скучно.
Таким образом, большая хитрость заключается в том, чтобы сделать этот доступ «универсальным» и легким для понимания из вызывающего класса - вытащить все повторяющиеся дерьма и просто оставить «мясо», перенести сложность в общую процедуру.
Таким образом, простой способ вызова метода - это что-то вроде этого, который дает массив битовых полей, которые содержат много битовых комбинаций, которые необходимо посчитать, и список полей, которые вас интересуют (чтобы вы не тратили время на тестирование). поля, которые вас не интересуют):
int[] counts = sumUpBits(arrayOfFlagBitfields, ACC_PUBLIC | ACC_FINAL | ACC_...);
Это действительно чисто, но тогда как вы получите доступ к полям возврата? Я изначально думал что-то вроде этого:
System.out.println("Number of public classes="+counts[findBitPosition(ACC_PUBLIC]));
System.out.println("Number of final classes="+counts[findBitPosition(ACC_FINAL)]);
Большая часть шаблонов здесь пропала, за исключением необходимости менять битовые поля в их положение. Я думаю, что два изменения могут сделать его лучше - инкапсулировать его в класс и использовать хеш для отслеживания позиций, чтобы вам не приходилось все время преобразовывать bitPosition (если вы предпочитаете не использовать хеш, findBitPosition находится в конце ).
Давайте попробуем полноценный класс. Как это должно выглядеть с точки зрения звонящего?
BitSummer bitSums=new BitSummer(arrayOfFlagBitfields, ACC_PUBLIC, ACC_FINAL);
System.out.println("Number of public classes="+bitSums.getCount(ACC_PUBLIC));
System.out.println("Number of final classes="+bitSums.getCount(ACC_FINAL));
Это довольно чисто и легко - я действительно люблю ОО! Теперь вы просто используете bitSums для хранения ваших значений до тех пор, пока они не понадобятся (это менее шаблонно, чем хранить их в переменных класса, и более понятно, чем при использовании массива или коллекции)
Так что теперь, чтобы закодировать класс. Обратите внимание, что конструктор теперь использует переменные аргументы - меньше удивления / более обычного и имеет больше смысла для реализации хэша.
Кстати, я знаю, что это кажется медленным и неэффективным, но, вероятно, это не плохо для большинства применений - если это так, его можно улучшить, но это должно быть намного короче и менее избыточно, чем коммутатор оператор (который на самом деле такой же, как этот, только что развернутый - однако этот использует хэш и автобокс, что повлечет за собой дополнительный штраф).
public class BitSummer {
// sums will store the "sum" as <flag, count>
private final HashMap<Integer, Integer> sums=new HashMap<Integer, Integer>();
// Constructor does all the work, the rest is just an easy lookup.
public BitSummer(int[] arrayOfFlagBitfields, int ... positionsToCount) {
// Loop over each bitfield we want to count
for(int bitfield : arrayOfFlagBitfields) {
// and over each flag to check
for(int flag : positionsToCount) {
// Test to see if we actually should count this bitfield as having the flag set
if((bitfield & flag) != 0) {
sums.put(flag, sums.get(flag) +1); // Increment value
}
}
}
}
// Return the count for a given bit position
public int getCount(int bit) {
return sums.get(bit);
}
}
Я не проверял это, но я думаю, что это довольно близко. Я бы не использовал его для обработки видеопакетов в режиме реального времени или чего-либо еще, но для большинства целей он должен быть достаточно быстрым.
Что касается поддержки кода, то он может выглядеть «длинным» по сравнению с исходным примером, но если у вас есть более 5 или 6 полей для проверки, это на самом деле будет более коротким решением, чем цепочечные операторы if, и значительно меньше ошибок / склонностей и более ремонтопригоден - тоже интереснее писать.
Если вы действительно чувствуете необходимость удалить хеш-таблицу, вы можете легко заменить ее разреженным массивом с позицией флага в качестве индекса (например, счетчик флага 00001000 / 0x08 будет сохранен в четвертой позиции массива). Для этого потребуется функция, подобная этой, для вычисления позиции бита для доступа к массиву (как сохранение в массиве, так и получение)
private int findBitPosition(int flag) {
int ret;
while( ( flag << 1 ) != 0 )
ret++;
return ret;
}
Это было весело.