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

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

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


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

2
  • Конечный класс и частный конструктор (хорошо, но не обязательно)
  • Публичные статические методы

1

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

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


1
Также не забудьте сделать частный конструктор.
Асаф,

@ Асаф: Согласен. Я добавил немного об этом к своему ответу. Спасибо.
Bill the Lizard

Если вам нужны статические методы внутри внутреннего класса, класс также должен быть статическим.
Rui Marques

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.