Почему вы не можете объявить класс статическим в Java?


459

Почему вы не можете объявить класс статическим в Java?


72
Встречный вопрос: какой эффект вы ожидаете получить, если объявите класс верхнего уровня static?
Иоахим Зауэр

3
Нет, вы не можете, кроме статических внутренних классов. Но что вы хотите достичь с этим?
manolowar

60
@Joachim Sauer: Ну, C # интерпретирует staticклассы как abstract final, то есть они не могут быть созданы и не могут быть расширены. Это означает, что они могут содержать только статические члены, что полезно для классов, которые содержат только вспомогательные методы.
Bcat

30
@bcat это верно для C #, но класс java может быть абстрактным или окончательным, а не оба. Чтобы предотвратить создание экземпляра класса, можно объявить закрытый конструктор.
Лоренцо Полидори

7
@JoachimSauer Просто, я бы хотел, чтобы все члены в классе были статическими (возможно, даже с объявлением каждого метода или свойства).
hmartinezd

Ответы:


475

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

class OuterClass{
    public static class StaticNestedClass{
    }

    public class InnerClass{
    }

    public InnerClass getAnInnerClass(){
        return new InnerClass();
    }

    //This method doesn't work
    public static InnerClass getAnInnerClassStatically(){
        return new InnerClass();
    }
}

class OtherClass{
    //Use of a static nested class:
    private OuterClass.StaticNestedClass staticNestedClass = new OuterClass.StaticNestedClass();

    //Doesn't work
    private OuterClass.InnerClass innerClass = new OuterClass.InnerClass();

    //Use of an inner class:
    private OuterClass outerclass= new OuterClass();
    private OuterClass.InnerClass innerClass2 = outerclass.getAnInnerClass();
    private OuterClass.InnerClass innerClass3 = outerclass.new InnerClass();
}

Источники:

На ту же тему:


3
+1 несмотря на то, что первая фраза не является точной. Как говорится в руководстве, «нестатические вложенные классы называются внутренними классами». (JLS: «Внутренний класс - это вложенный класс, который не объявлен явно или неявно как статический.»)
user85421

74
Вы наверняка правы; но я не вижу, как это отвечает на вопрос
Джори Хендриккс

2
@ Карлос Хойбергер, ты прав, я обновил пост. @Joeri Hendrickx, вопрос был, «почему класс не может быть объявлен как статический?», Они могут, и [прочитайте мой пост здесь]. Это объяснение использования статических классов и почему они должны быть вложенными классами.
Колин Хеберт

1
Решение, приведенное здесь, прекрасно ... Но я все еще удивляюсь, что вы не объяснили логически, что статический класс невозможен в java ... некоторые объяснения концепции ООП были бы правильным ответом. Я
жду

9
Это правда, но вопрос, о котором вы думаете, обычно решается сам, когда вы начинаете задавать себе вопрос, каким будет «статический класс». В Java статический элемент означает, что вы можете обращаться к нему / вызывать его без экземпляра включающего класса; Что это может означать, если вы примените ключевое слово к самому классу? Каковы ваши намерения? Чего бы вы ожидали? Теперь, когда у вас есть представление о том, что это может быть, я почти уверен, что это будет либо «не совсем понятно», либо «надумано» (это будет иметь смысл, но в конце концов, это просто выбор что было сделано).
Колин Хеберт

39

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


14
»Классы верхнего уровня статичны по умолчанию.« Это лучший ответ. Они статичны, потому что вам не нужен какой-либо экземпляр, чтобы ссылаться на них. На них можно ссылаться откуда угодно. Они находятся в статическом хранилище (как в классах хранения C). - Как отмечали другие (Iain Elder в комментарии к другому ответу), разработчики языка могли позволить staticключевому слову в классе верхнего уровня обозначать и обеспечивать, чтобы оно могло содержать только статические члены и не создавалось для него; это могло бы, однако, сбить с толку людей, поскольку staticимеет другое значение для вложенных классов.
Луми

35

Итак, я опаздываю на вечеринку, но вот мои два цента - философски добавляю к ответу Колина Хеберта.

На высоком уровне ваш вопрос касается различий между объектами и типами. В то время как существует много автомобилей (объектов), существует только один класс (тип) автомобилей. Объявление чего-либо как статического означает, что вы работаете в пространстве типа. Здесь только один. Ключевое слово класса верхнего уровня уже определяет тип в пространстве «type». В результате «общедоступный статический класс Car» является избыточным.


1
Да. Другими словами, классы верхнего уровня являются статическими по умолчанию, поэтому ключевое слово не нужно.
Уоррен Дью

1
Ну, я бы добавил к тому, что сказал Уоррен Дью: «классы верхнего уровня статичны по умолчанию при доступе к статическим членам».
Декстер

1
Недооцененный ответ. Было бы хорошо, если бы новое ключевое слово заставляло каждый метод в классе быть статическим, а конструктор private. Я бы не назвал это статичным, потому что это просто сбивает с толку.
G_V

@G_V Хотя Java может создать такого монстра, Java почти делает все возможное, чтобы затруднять глупые вещи. Статика - плохая идея в целом, статические классы ужасны (хуже, чем одиночные, которые сами по себе считаются анти-паттернами). Многие люди не понимают этого, поэтому дать ему ключевое слово было бы очень плохой идеей. Вместо этого мы усложняем плохие вещи и просто оставляем все как есть. Обратите внимание, что здесь также нет ключевого слова "Singleton". и без ключевого слова свойства. Все они вызывают плохой код (хотя люди все еще используют свойства настолько, что Java может их поддерживать)
Bill K

29

Класс с приватным конструктором является статическим.

Объявите свой класс следующим образом:

public class eOAuth {

    private eOAuth(){}

    public final static int    ECodeOauthInvalidGrant = 0x1;
    public final static int    ECodeOauthUnknown       = 0x10;
    public static GetSomeStuff(){}

}

и вы можете использовать без инициализации:

if (value == eOAuth.ECodeOauthInvalidGrant)
    eOAuth.GetSomeStuff();
...

3
Это не статично, но содержит статические свойства. Если вы напишите public final int ECodeOauthUnknown = 0x10; это больше не статично.
user1883212

9
Если кому-то интересно, что здесь происходит, это соответствует определению C # «статического класса» - msdn.microsoft.com/en-us/library/79b3xss3%28v=vs.90%29.aspx . Учитывая Java-определение «статического класса», все не внутренние классы являются статическими (см. Ответы братьев и сестер).
Калум

1
Помимо @ user1883212 прав, я бы даже сказал, что этот ответ сбивает с толку читателя, что приватный конструктор здесь так или иначе важен, хотя на самом деле он вообще не имеет значения.
tlwhitec

В мире .NET, если класс помечен как абстрактный и конечный (эффект static classобъявления в C #), компилятор даже не позволит коду объявлять переменные этого типа и не использует его в качестве параметра универсального типа. Простое отсутствие доступных конструкторов в классе, который в противном случае мог бы быть либо создан, либо наследован, не исключало бы объявление переменных этого типа или его использование в качестве параметра универсального типа.
суперкат

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

13

Конечно, они могут, но только внутренние вложенные классы. Там это означает, что экземпляры вложенного класса не требуют включения внешнего класса.

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


+1 несмотря на то, что первая фраза не является точной. Как говорится в JLS: «Внутренний класс - это вложенный класс, который не является явно или неявно объявленным статическим». (Просто терминология, я знаю ...)
user85421

7
Хотя класс верхнего уровня не может быть объявлен static, иногда имеет смысл это сделать. Например, класс, содержащий только статические вспомогательные методы, не имеет смысла создавать экземпляры, но язык Java не мешает вам это делать. Вы можете сделать класс неинстанцируемым (и практически «статичным») для других классов, объявив конструктор по умолчанию private, который запрещает инстанцирование, поскольку конструктор не виден.
Иэн Сэмюэль Маклин, старейшина

12

Вы можете создать служебный класс (у которого не может быть созданных экземпляров), объявив тип enum без экземпляров. то есть вы конкретно заявляете, что нет никаких экземпляров.

public enum MyUtilities {;
   public static void myMethod();
}

25
перечисление как тип является специфическим ожиданием: это перечислимый набор элементов. Использование его для «служебного класса», когда вы могли бы просто иметь класс с закрытым конструктором, семантически запутанно.
Решения Visionary Software

5
@VisionarySoftwareSolutions Для меня эта специфика говорит, что нет экземпляров этого класса, а косвенно делает невозможным создание экземпляров класса.
Питер Лори

8
public class Outer {
   public static class Inner {}
}

... он может быть объявлен как статический - до тех пор, пока он является членом класса.

Из JLS:

Классы-члены могут быть статическими, и в этом случае они не имеют доступа к переменным экземпляра окружающего класса; или они могут быть внутренними классами (§8.1.3).

и здесь:

Ключевое слово static может изменить объявление типа члена C в теле не внутреннего класса T. Его эффект - объявить, что C не является внутренним классом. Так же, как статический метод T не имеет текущего экземпляра T в своем теле, C также не имеет текущего экземпляра T и не имеет каких-либо лексически включающих экземпляров.

Ключевое слово static не имеет никакого смысла для класса верхнего уровня, просто потому, что класс верхнего уровня не имеет вложенного типа.


Если это не внутреннее, зачем это называть Inner? Nestedбыл бы менее запутанным выбором.
Маркиз Лорн

5

Как объяснено выше, класс не может быть статическим, если он не является членом другого класса.

Если вы хотите спроектировать класс, «которого не может быть несколько экземпляров», вы можете посмотреть шаблон проектирования «Singleton».

Информация для начинающих Singleton здесь .

Предостережение:

Если вы думаете об использовании шаблона синглтона, сопротивляйтесь изо всех сил. Это один из самых простых в понимании DesignPatterns, вероятно, самый популярный и, безусловно, самый злоупотребляемый. (источник: JavaRanch, как указано выше)


4

В дополнение к тому, как Java определяет статические внутренние классы, есть другое определение статических классов согласно миру C # [1] . Статический класс - это класс, который имеет только статические методы (функции) и предназначен для поддержки процедурного программирования. Такие классы на самом деле не являются классами в том смысле, что пользователь класса интересуется только вспомогательными функциями, а не созданием экземпляров класса. Хотя статические классы поддерживаются в C #, в Java такой прямой поддержки не существует. Однако вы можете использовать перечисления для имитации статических классов C # в Java, чтобы пользователь никогда не мог создавать экземпляры данного класса (даже используя отражение) [2] :

public enum StaticClass2 {
    // Empty enum trick to avoid instance creation
    ; // this semi-colon is important

    public static boolean isEmpty(final String s) {
        return s == null || s.isEmpty();
    }
}

3

Все, что мы кодируем в Java, входит в класс. Всякий раз, когда мы запускаем класс, JVM создает объект. JVM может создавать несколько объектов, по определению Static означает, что у вас одинаковый набор копий для всех объектов.

Таким образом, если бы Java позволяла верхнему классу быть статичным при каждом запуске программы, она создает объект и переопределяет одно и то же место в памяти.

Если Вы просто заменяете объект каждый раз, когда запускаете его, какой смысл его создавать?

Вот почему Java избавилась от статики для класса верхнего уровня.

Могут быть и более конкретные причины, но для меня это логично.


3
Внутренние классы связаны с внешними классами, и поэтому они могут быть статическими, поскольку у вас есть другой объект, от которого вы можете зависеть.
user2626445

1
Вы имеете в виду «вот почему они не могут быть статичными».
Маркиз Лорн

2

Единственными классами, которые могут быть статическими, являются внутренние классы. Следующий код работает просто отлично:

public class whatever {
    static class innerclass {
    }
}

Суть статических внутренних классов в том, что они не имеют ссылки на внешний объект класса.


1
«статический внутренний» является противоречием в терминах. «static» и «inner» являются взаимоисключающими. Слово, которое вы ищете, является «вложенным», а не «внутренним».
Маркиз Лорн

1

Я думаю, что это возможно так же просто, как выпить стакан кофе! Просто взгляните на это. Мы не используем статическое ключевое слово явно при определении класса.

public class StaticClass {

    static private int me = 3;
    public static void printHelloWorld() {
       System.out.println("Hello World");
    }



    public static void main(String[] args) {
        StaticClass.printHelloWorld();
        System.out.println(StaticClass.me);
    }
}

Разве это не определение статического класса? Мы просто используем функцию, связанную только с классом. Будьте осторожны, чтобы в этом случае мы могли использовать другой класс из этого вложенного. Посмотри на это:

class StaticClass1 {

    public static int yum = 4;

    static void  printHowAreYou() {
        System.out.println("How are you?");
    }
}

public class StaticClass {

    static int me = 3; 
    public static void printHelloWorld() {
       System.out.println("Hello World");
       StaticClass1.printHowAreYou();
       System.out.println(StaticClass1.yum);
    }



    public static void main(String[] args) {
        StaticClass.printHelloWorld();
        System.out.println(StaticClass.me);
    }
}

Я думаю, что мы можем рассматривать такие классы как статический класс, ссылаясь на определение статического класса, а не просто используя статическое ключевое слово в качестве квалификатора.
Эрфанкам

Обязательно создайте приватный конструктор, иначе вы могли бы сказать, new StaticClass()и это не имеет особого смысла. С частным конструктором это не позволило бы экземпляры этого.
Гринч

1

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

public final class <class name>
{
   //static constants
   //static memebers
}

0

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

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