Меня всегда волновал вопрос класса Enum: какие у них есть преимущества перед обычными static final примитивами?
И, если можно, поделитесь вашим опытом, в котором использование Enum было бы действительно оправданным.
Ответы
Ответ 1
enum имеет ряд преимуществ при использовании в сравнении с static final int. И использовать его стоит в том случае если вам нужны эти преимущества.
Главным отличием является то что используя enum вы можете проверить тип данных.
Например:
public class SomeClass {
public static int RED = 1;
public static int BLUE = 2;
public static int YELLOW = 3;
public static int GREEN = 3; // Совпадающие значения
private int color;
public void setColor(int color) {
this.color = color;
}
}
При этом вы можете передать в класс любое значение int.
new SomeClass().setColor(999);
Следовательно, основные проблемы использования static final int это:
Необходимость проверки вводимых данных.
Нет никакой защиты от создания static final int переменной с дублирующимся значением.
Еще одним преимуществом enum является возможность перегружать методы.
public enum UnitConverter{
METERS{
@Override
public double toMiles(final double meters){
return meters * 0.00062137D;
}
@Override
public double toMeters(final double meters){
return meters;
}
},
MILES{
@Override
public double toMiles(final double miles){
return miles;
}
@Override
public double toMeters(final double miles){
return miles / 0.00062137D;
}
};
public abstract double toMiles(double unit);
public abstract double toMeters(double unit);
}
Недостатки использования enum
К ним не применимы операторы >, <, >=, <=. Следовательно enum не
стоит применять в списке последовательных данных.
enum также требует больше памяти для хранения чем обычная
константа.
IntDef и StringDef в Android
Google не рекомендует использовать enum в Android приложениях из-за того что эт
требует больше памяти. Вместо этого для Android можно использовать IntDef и StringDe
которые позволяют ограничивать пространство значений для обычных констант. Следовательно, вы получаете главное преимущество enum не теряя в использовании памяти. Это практика повсеместно используется в стандартных классах Android:
/** @hide */
@IntDef({VISIBLE, INVISIBLE, GONE})
@Retention(RetentionPolicy.SOURCE)
public @interface Visibility {}
/**
* This view is visible.
* Use with {@link #setVisibility} and {@code
* android:visibility}.
*/
public static final int VISIBLE = 0x00000000;
/**
* This view is invisible, but it still takes up space for layout purposes.
* Use with {@link #setVisibility} and {@code
* android:visibility}.
*/
public static final int INVISIBLE = 0x00000004;
/**
* This view is invisible, and it doesn't take any space for layout
* purposes. Use with {@link #setVisibility} and {@code
* android:visibility}.
*/
public static final int GONE = 0x00000008;
В принимающем методе используется специальная аннотация:
public void setVisibility(@Visibility int visibility) {
setFlags(visibility, VISIBILITY_MASK);
if (mBackground != null) mBackground.setVisible(visibility == VISIBLE, false);
}
В таком случае вы не сможете использовать другую константу для этого метода:
view.setVisibility(456);//Error: Must be one of: View.VISIBLE, View.INVISIBLE, View.GONE
Ответ 2
Перечисления (Enum) удобно использовать для представления множества взаимоисключающих состояний.
Пример Перечисления кодов сообщения:
enum MessageCode
{
// Установка однозначного соответствия
// между элементом перечисления и целочисленным значением.
UNKNOWN(0),
TOAST(1),
MESSAGE(2);
private final int id;
MessageCode(int code)
{
id = code;
}
// Метод получения целочисленного значения,
// соответствующего выбранному элементу Перечисления (Enum)
public int getId()
{
return id;
}
// Метод получения элемента Перечисления (Enum),
// соответствующего переданному целочисленному значению
public static MessageCode fromId(int code)
{
MessageCode[] list = MessageCode.values();
if (code >= 0 && code < list.length)
return list[code];
else
return MessageCode.UNKNOWN;
}
}
Пример анализа сообщений:
private Messenger chatUIThreadMessenger = new Messenger(new Handler()
{
@Override
public void handleMessage(Message msg)
{
String str;
switch (MessageCode.fromId(msg.what))
{
// Доступ к выводу Toast'ов для Thread'ов прослушивающих Socket'ы
case TOAST:
str = (String) msg.obj;
Toast.makeText(getBaseContext(), str, Toast.LENGTH_LONG).show();
break;
// Вывод сообщений в лог чата
case MESSAGE:
str = (String) msg.obj;
messages.add(str);
messagesAdapter.notifyDataSetChanged();
final ListView listView = (ListView) findViewById(R.id.listViewChat);
listView.smoothScrollToPosition(messagesAdapter.getCount() - 1);
break;
// Исключительная ситуация
case UNKNOWN:
Toast.makeText(getBaseContext(),
"Messenger: неопределённый тип сообщения!", Toast.LENGTH_LONG).show();
break;
default:
super.handleMessage(msg);
}
}
});
Ответ 3
Использование enum вместо констант полезно, например, когда вы хотите ограничит
возможное множество значений аргумента к-л метода. Если использовать к-л константу (in
или String, например), и метод, который должен её принимать будет иметь соответствующий тип аргумента, то ничто вам не помешает передать туда что-то помимо констант. Если же вы используете enum то передать что-то кроме enum у вас не получится.
Ответ 4
Enum можно использовать как реализацию паттерна Singleton.
Преимущества:
Сериализация из коробки
Потокобезопасность из коробки
Возможность использования EnumSet, EnumMap и т.д
Поддержка switch
Недостатки
Не ленивая инициализация
По мнению Joshua Bloch’а это лучший способ реализации шаблона
public enum Singleton {
INSTANCE;
}
Комментариев нет:
Отправить комментарий