Чому ви не можете оголосити клас статичним на Java?


459

Чому ви не можете оголосити клас статичним на Java?


72
Зустрічне запитання: яким би ви очікували ефекту, якби ви оголосили клас вищого рівня static?
Йоахім Зауер

3
Ні, ви не можете, крім статичних внутрішніх класів. Але чого ви хочете досягти з цим?
manolowar

60
@Joachim Sauer: Ну, C # трактує staticкласи як abstract final, тобто вони не можуть бути ініційовані і не можуть бути розширені. Це означає, що вони можуть містити лише статичні члени, що корисно для класів, які містять лише допоміжні методи.
bcat

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

7
@JoachimSauer Simple, я хотів би змусити всіх членів у класі статично (можливо, навіть потрібно заявити про кожен метод чи властивість).
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
Ти, безумовно, маєш рацію; але я не бачу, як це відповідає на питання
Joeri Hendrickx,

2
@Carlos Heuberger, ти маєш рацію, я оновив пост. @Joeri Hendrickx, Питання було: "чому клас не можна оголосити статичним ..?", Вони можуть і [читати тут мій пост]. Це пояснення щодо використання статичних класів та чому вони мають бути вкладеними класами.
Колін Геберт

1
Наведене тут рішення є прекрасним ... Але я все ще дивуюсь, що y ppl не пояснили логічно, що статичний клас неможливий у Java. Деякі пояснення концепції OOP будуть правильною відповіддю. Я чекаю цього
Punith Raj

9
Це правда, але питання, про яке ти думаєш, зазвичай вирішуєш себе, коли починаєш запитувати себе, що таке "статичний клас". У java статичний елемент означає, що ви можете отримати доступ до нього / викликати його без екземпляра класу, що додається; що це може означати, якщо застосувати ключове слово до самого класу? Які ваші наміри? Що б ви очікували? Тепер, коли ви маєте уявлення про те, що це може бути, я майже впевнений, що це буде або "не дуже сенс", або буде "далеко надуманий" (це мало б сенс, але в кінці це просто вибір що було зроблено).
Колін Геберт

39

Класи вищого рівня за замовчуванням статичні. Внутрішні класи за замовчуванням нестатичні. Ви можете змінити типові для внутрішніх класів, чітко позначивши їх статичними. Класи вищого рівня, в силу вищого рівня, не можуть мати нестатичну семантику, оскільки не може бути батьківського класу, на який можна посилатися. Тому немає можливості змінити типове значення для класів вищого рівня.


14
»Класи вищого рівня за замовчуванням статичні.« Це найкраща відповідь. Вони статичні, тому що вам не потрібен жоден примірник нічого, щоб звернутися до них. На них можна звернутися з будь-якого місця. Вони знаходяться в статичному сховищі (як у класах зберігання C). - Як зазначали інші (Ієн Старший у коментарі до іншої відповіді), мовні дизайнери могли дозволити staticключовому слову класу вищого рівня позначати та застосовувати, що воно може містити лише статичні члени, а не бути екземплярами; що, однак, може бентежити людей, оскільки staticдля вкладених класів має інше значення.
Лумі

35

Отже, я запізнююсь на вечірку, але ось два мої центи - по-філософськи додав відповідь Коліна Геберта.

На високому рівні ваше питання стосується різниці між об'єктами та типами. Хоча автомобілів (об'єктів) багато, є лише один клас автомобілів (тип). Оголошення чогось статичним означає, що ви працюєте в просторі "типу". Є лише одна. Ключове слово верхнього рівня вже визначає тип у просторі "type". В результаті "автомобіль загального статичного класу" є зайвим.


1
Так. Інакше кажучи, класи вищого рівня за замовчуванням статичні, тому ключового слова немає необхідності.
Warren Dew

1
Ну, я б додав до того, що сказав Уоррен Дью: "Класи вищого рівня є статичними за замовчуванням при доступі до статичних членів".
Dexter

1
Занижена відповідь. Нове ключове слово, щоб змусити кожен метод у класі статичним і конструктором приватним було б непогано. Я б не назвав це статичним, тому що це просто заплутано.
G_V

@G_V Хоча Java могла створити такого монстра, Java майже не виходить із цього способу ускладнити дурні речі. Статистика - це погана ідея, статичні класи - жахливі (гірше, ніж одиночні, які самі вважаються анти-зразком). Багато людей цього не розуміють, тому введення ключового слова було б дуже поганою ідеєю. Натомість ми ускладнюємо погані речі і просто залишаємо це. Зауважте, що також немає ключового слова "Singleton". і немає ключового слова властивості. Вони все спричиняють поганий код (Хоча люди все ще користуються властивостями настільки, що Java може також їх підтримувати)
Білл К

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; це вже не статично.
користувач1883212

9
Якщо когось цікавить, що тут відбувається, це відповідає визначенню C # "статичного класу" - msdn.microsoft.com/en-us/library/79b3xss3%28v=vs.90%29.aspx . Враховуючи визначення Java "статичного класу", всі не внутрішні класи є статичними (див. Відповіді щодо побратимів).
Calum

1
Окрім @ user1883212 має рацію, я навіть скажу, що ця відповідь бентежить читача, що приватний конструктор тут якимось чином важливий, хоча він насправді не має значення.
tlwhitec

У світі .NET, якщо клас позначений як абстрактним, так і кінцевим (ефект static classдекларації в C #), компілятор навіть не дозволить коду оголошувати змінні цього типу, а також не використовуватиме його як загальний параметр типу. Проста відсутність доступних конструкторів у класі, які в іншому випадку можуть бути або інстанційними, або успадкованими, не виключатиме оголошення оголошень змінних цього типу, а також його використання як загального параметра типу.
supercat

Ця відповідь є абсолютно невірною. Приватні конструктори тут ні до чого. Код є лише прикладом класу, в якому немає нічого, крім статичних атрибутів та методів. Це не має нічого спільного зі статичними класами.
Маркіз Лорн

13

Звичайно, вони можуть, але лише внутрішні вкладені класи. Там це означає, що екземпляри вкладеного класу не потребують вкладеного екземпляра зовнішнього класу.

Але для класів вищого рівня мовні дизайнери не могли придумати нічого корисного з ключовим словом, тому це заборонено.


+1, незважаючи на те, що перша фраза не точна. Як зазначає JLS: "Внутрішній клас - це вкладений клас, який явно або неявно не оголошений статичним". (Просто термінологія, я знаю ...)
користувач85421

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

12

Ви можете створити клас утиліти (який не може створити екземпляри), оголосивши тип перерахунку без жодних екземплярів. тобто ви конкретно заявляєте, що жодних випадків немає.

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

25
перерахування як тип - це специфічне очікування: це перелічений набір елементів. Використовувати його для "класу корисності", коли в іншому випадку ви могли просто мати клас із приватним конструктором, семантично заплутано.
Visionary Software Solutions

5
@VisionarySoftwareSolutions Мені ця специфіка говорить про відсутність екземплярів цього класу, а не побічно, що унеможливлює створення примірників класу.
Пітер Лоурі

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

... його можна оголосити статичним - до тих пір, поки це клас-член.

Від JLS:

Класи учасників можуть бути статичними, і в цьому випадку вони не мають доступу до змінних екземплярів навколишнього класу; або вони можуть бути внутрішніми класами (§8.1.3).

і ось:

Статичне ключове слово може змінювати оголошення типу члена C у тілі не внутрішнього класу T. Його дія полягає в тому, щоб оголосити, що C не є внутрішнім класом. Подібно до того, як статичний метод T не має поточного екземпляра T у своєму тілі, C також не має поточного екземпляра T, а також не має жодних лексично огороджуючих екземплярів.

Статичне ключове слово не матиме сенсу для класу вищого рівня, лише тому, що клас верхнього рівня не має типу закривання.


Якщо це не внутрішнє, навіщо його називати Inner? Nestedбув би менш заплутаним вибором.
Маркіз Лорн

5

Як було пояснено вище, клас не може бути статичним, якщо він не є членом іншого класу.

Якщо ви хочете створити клас, "якого не може бути декілька екземплярів", ви можете заглянути в шаблон дизайну "Singleton".

Інформація для початківців Сінглтон тут .

Caveat:

Якщо ви думаєте скористатися одинарним візерунком, чиніть опір усім силам. Це один із найпростіших для розуміння DesignPatterns, мабуть, найпопулярніший і, безумовно, найбільш зловживаний. (джерело: JavaRanch, як пов’язано вище)


4

Окрім того, як Java визначає статичні внутрішні класи, існує ще одне визначення статичних класів відповідно до світу C # [1] . Статичний клас - це лише статичні методи (функції) і він призначений для підтримки процедурного програмування. Такі класи насправді не є класами, оскільки користувач класу зацікавлений лише у допоміжних функціях, а не у створенні екземплярів класу. Хоча статичні класи підтримуються на C #, у Java немає такої прямої підтримки. Однак ви можете використовувати enums для імітації 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 дозволила б вищому класу статичним стати при кожному запуску програми, вона створює Object і продовжує переосмислюватись на одне і те ж Місце пам'яті.

Якщо ви просто замінюєте об'єкт щоразу, коли запускаєте його, у чому сенс його створення?

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

Можуть бути і більш конкретні причини, але це мало для мене логічний сенс.


3
Внутрішні класи асоціюються із зовнішніми класами, і саме тому вони можуть стати статичними, оскільки від вас має залежати інший об'єкт.
користувач2626445

1
Ви маєте на увазі "це причина, що вони не можуть бути статичними".
Маркіз Лорн

2

Єдиними класами, які можуть бути статичними, є внутрішні класи. Наступний код працює чудово:

public class whatever {
    static class innerclass {
    }
}

Сенс статичних внутрішніх класів полягає в тому, що вони не мають посилання на зовнішній об’єкт класу.


1
"статичний внутрішній" - це суперечність в термінах. "статичний" і "внутрішній" взаємовиключні. Ви шукаєте слово "вкладене", а не "внутрішнє".
Маркіз Лорн

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.