Java: статический класс?

130

У меня есть класс, полный служебных функций. Создание его экземпляра не имеет семантического смысла, но я все же хочу вызывать его методы. Как лучше всего с этим справиться? Статический класс? Аннотация?

Ник Хайнер
источник
14
Между прочим, вы не можете сделать класс верхнего уровня статическим ...
Джон,

Ответы:

163

Частный конструктор и статические методы в классе, помеченном как final.

Дэвид Роблес
источник
19
@matt b: Как указывает Дэвид Роблес в своем ответе, вам не нужно делать класс окончательным ... он не может быть подклассом, потому что подкласс не сможет вызвать конструктор суперкласса, потому что он частный. Однако ... нет ничего плохого в том, чтобы быть откровенным. Но яфу :-).
Том
93

Согласно великой книге «Эффективная Java» :

Правило 4: Обеспечьте невозможность создания экземпляров с помощью частного конструктора

- Попытка обеспечить неинстанциональность путем создания абстрактного класса не работает.

- Конструктор по умолчанию создается только в том случае, если класс не содержит явных конструкторов, поэтому класс можно сделать неинстанцируемым, включив частный конструктор:

// Noninstantiable utility class
public class UtilityClass
{
    // Suppress default constructor for noninstantiability
    private UtilityClass() {
        throw new AssertionError();
    }
}

Поскольку явный конструктор является закрытым, он недоступен вне класса. AssertionError не является строго обязательным, но он обеспечивает страховку на случай, если конструктор будет случайно вызван из класса. Это гарантирует, что класс никогда не будет создан ни при каких обстоятельствах. Эта идиома слегка противоречит здравому смыслу, поскольку конструктор предоставляется явно, поэтому его нельзя вызвать. Поэтому разумно включить комментарий, как показано выше.

В качестве побочного эффекта эта идиома также предотвращает создание подкласса класса. Все конструкторы должны вызывать конструктор суперкласса, явно или неявно, и у подкласса не будет доступного конструктора суперкласса для вызова.

Дэвид Роблес
источник
1
Почему вы выбрали AssertionErrorдругие альтернативы, например IllegalStateException, UnsupportedOperationExceptionи т. Д.?
Pacerier
@Pacerier Смотрите это .
bcsb1001
@ bcsb1001, Это подводит нас к следующему .
Pacerier
21

Похоже, у вас есть служебный класс, похожий на java.lang.Math .
Подход есть финальный класс с частным конструктором и статическими методами.

Но остерегайтесь того, что это делает для тестируемости, я рекомендую прочитать эту статью
Статические методы - смерть тестируемости.

Краун
источник
Так что же java.lang.Math «смерть для проверки»?
Pacerier
1
Было бы интересно посмотреть , как он забивает , когда проходят через code.google.com/p/testability-explorer
Краун
6

Просто чтобы плыть против течения, статические члены и классы не участвуют в объектно-ориентированном взаимодействии и поэтому являются злом. Нет, не зло, но серьезно, я бы порекомендовал обычный класс с одноэлементным шаблоном для доступа. Таким образом, если вам нужно переопределить поведение в любых случаях в будущем, это не будет серьезным переоснащением. OO твой друг :-)

Мои 0,02 доллара

Беннет Дилл
источник
17
Синглтоны тоже считаются злом.
Дэн Дайер,
3
Вы используете частный конструктор, чтобы никто не мог создать экземпляр класса или создать его подкласс. См. Ответ Дэвида Роблеса: stackoverflow.com/questions/1844355/java-static-class/…
ограбить
5
синглтон не больше зла , чем инъекции зависимостей :)
irreputable
12
ОО имеет свое место, но бывают случаи, когда это просто непрактично или было бы пустой тратой ресурсов - например, что-то столь же простое, как Math.abs (). Нет причин создавать экземпляр объекта только ради создания экземпляра объекта, когда вызов статического метода с таким же успехом послужил бы вам без каких-либо дополнительных затрат на объектно-ориентированные разработки. ;)
ограбить
2
@rob re OO, я согласен, Math.Abs, вероятно, никогда не нуждается в экземпляре. Когда я слышу «у меня есть служебный класс», я вижу Math.Avg (), где вам теперь нужно добавить поддержку для средневзвешенного значения. Я вижу генератор URL-адресов, параметры входа и выхода, которые необходимо отредактировать для поддержки href, или только URL-адреса и т. Д. По этим причинам использование служебного класса на основе объектно-ориентированного программирования может окупиться. Кроме того, теперь я откажусь от стандартной тактики ОО-защиты, тестирования! / me ducks
Беннет Дилл
3

прокомментируйте аргументы "частного конструктора": давайте, разработчики не такие тупые; но они ленивы. создание объекта, а затем вызов статических методов? не произойдет.

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

irreputable
источник
7
Кто-то, кто видел (в производственном коде, а не только в студенческом коде) object.staticMethod Я думаю, вы переоцениваете способности Джо Случайного Программиста! :-P
TofuBeer
2
  • Конечный класс и частный конструктор (хорошо, но не обязательно)
  • Публичные статические методы
fastcodejava
источник
1

Нет смысла объявлять класс как static. Просто объявите его методы staticи вызовите их из имени класса как обычно, как класс Java Math .

Кроме того, даже если не обязательно делать конструктор закрытым, это хорошая идея. Если пометить конструктор как закрытый, другие люди не смогут создавать экземпляры вашего класса, а затем вызывать статические методы из этих экземпляров. (Эти вызовы работают точно так же в Java, они просто вводят в заблуждение и ухудшают читаемость вашего кода.)

Билл Ящерица
источник
1
Также не забудьте сделать частный конструктор.
Асаф,
@ Асаф: Согласен. Я добавил немного об этом к своему ответу. Спасибо.
Bill the Lizard
Если вам нужны статические методы внутри внутреннего класса, класс также должен быть статическим.
Rui Marques