Чому змінні інтерфейсу статичні та кінцеві за замовчуванням?


274

Чому змінні інтерфейсу статичні та кінцеві за замовчуванням у Java?


41
Ви не повинні розміщувати змінних всередині інтерфейсів.
cherouvim

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

10
Ми, звичайно, можемо, коли ми знаємо, що всі класи, що реалізують інтерфейс, мають деякі постійні змінні (наприклад, імена полів).
Анікет Такур

Чи гарна ідея зробити змінну в класі екземпляром інтерфейсу, який клас реалізує? Я чув це раніше.
Дуг Хауф

Інтерфейси в java відповідають принципу ACID, остаточний через нормалізацію в C. @cherouvim Тип змінної - це реалізація, змінна повинна бути оголошена зі значенням або без нього, а визначення змінної - значення. Якщо зміна значення змінної не є реімплементацією, її перевизначення.
Похмурий

Відповіді:


264

З питань FAQ щодо дизайну інтерфейсу Java Філіпа Шоу:

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

джерело


39
Зауважте, що абстрактні класи не можуть бути ідентифіковані "власними силами", і вони не можуть мати змінних примірників.
macias

18
Це пояснення для staticмодифікатора є абсолютно помилковим. Змінні загальнодоступних екземплярів класу є частиною його інтерфейсу, і немає ніяких причин, чому їх не слід абстрагувати на Java interface, як і методи екземплярів. Не має значення, що Java interfaceне може бути безпосередньо створена інстанцією - ви все одно можете мати екземпляри класів, які реалізують, interfaceі розумно вимагати, щоб вони мали певну змінну публічного екземпляра. Що стосується частини final, яка зовсім не пропонує пояснення - вона просто описує, що finalозначає.
пірокрастія

3
Цитата вище краща в контексті. Причиною цього є те, що "інтерфейсні змінні призначені для констант Java". Цитата лише роз'яснювала, чому така константа буде статичною і остаточною. Це правда, але справжнє питання полягає в тому, чому змінні не дозволені як частина фактичного інтерфейсу (тобто, із зазначенням імен та типів не приватних членів, які повинні зустрічатися в класі реалізації). Якби вони хотіли спеціальних "констант інтерфейсу", вони могли використовувати новий синтаксис або просто вирішили, що будь-які змінні, фактично визначені в інтерфейсі, є константами інтерфейсу.
пірокрастія

6
Інтерфейси не можуть мати змінних примірників, щоб уникнути багаторазового успадкування проблем стану. Дивіться docs.oracle.com/javase/tutorial/java/IandI/… . Клас не може поширюватися на більш ніж один клас з тієї ж причини.
denis

1
Як вводяться методи за замовчуванням, і у них є екземпляр, але змінна екземпляр не підтримується ...
M.kazem Akhgary

41

Оскільки інтерфейс не має прямого об'єкта, єдиний спосіб отримати доступ до них - це за допомогою класу / інтерфейсу, і тому, якщо існує змінна інтерфейс, він повинен бути статичним, інакше він взагалі не може бути доступним для зовнішнього світу. Оскільки він статичний, він може містити лише одне значення, і будь-які класи, що реалізують його, можуть змінити його, отже, все буде безлад.

Отже, якщо взагалі є змінна інтерфейс, вона буде неявно статичною, остаточною і, очевидно, загальнодоступною !!!


Звичайно, змінна інстанція була б доступною, якби вона була дозволена в Java interface. Клас буде реалізувати інтерфейс, оголошуючи змінну екземпляра (як того вимагає інтерфейс). Його конструктор (або інший метод) встановлює змінну екземпляра. Коли екземпляр класу інстанціюється, ви зможете отримати доступ до його змінної екземпляра.
пірокрастія

Java дозволяє статичним методам з тілами існувати в інтерфейсі. Вони могли отримати доступ до статичних змінних. Вони просто не можуть їх змінити, а значить, статичні функції не можуть зберігати жодні дані
simpleuser

36

public : для доступності для всіх класів, як і методи, наявні в інтерфейсі

статичний : оскільки інтерфейс не може мати об'єкт, інтерфейсName.variableName може використовуватися для його посилання або безпосередньо до змінноїName у класі, що реалізує його.

остаточний : зробити їх константами. Якщо два класи реалізують один і той же інтерфейс, і ви даєте обом правом змінити значення, конфлікт виникне в поточному значенні var, тому дозволена лише одноразова ініціалізація.

Крім того, всі ці модифікатори є прихованими для інтерфейсу, вам не потрібно вказувати будь-який з них.


15

( Це не філософська відповідь, а більше практична ). Вимога staticмодифікатора очевидна, на що відповіли інші. В основному, оскільки інтерфейси неможливо встановити, єдиний спосіб отримати доступ до його полів - це зробити їх класовим полем - static.

Причина, за якою interfaceполя автоматично стають final(постійними), полягає в тому, щоб запобігти різним реалізаціям випадково змінити значення змінної інтерфейсу, що може ненавмисно вплинути на поведінку інших реалізацій. Уявіть нижченаведений сценарій, коли Java interfaceвластивість явно не стала final:

public interface Actionable {
    public static boolean isActionable = false;

    public void performAction();
}

public NuclearAction implements Actionable {

    public void performAction() {
        // Code that depends on isActionable variable
        if (isActionable) {
            // Launch nuclear weapon!!!
        }
    }
}

Тепер подумайте, що буде, якщо інший клас, який реалізує, Actionableзмінює стан змінної інтерфейсу:

public CleanAction implements Actionable  {

    public void performAction() {
        // Code that can alter isActionable state since it is not constant
        isActionable = true;
    }
}

Якщо ці класи завантажуються в одному JVM завантажувачем класів, то на поведінку класу NuclearActionможе впливати інший клас, CleanActionколи його performAction()викликається після того, як CleanAction's виконується (в тій же нитці чи іншим чином), що в цьому випадку може бути катастрофічним. (семантично це є).

Оскільки ми не знаємо, як кожна реалізація програми interfaceвикористовуватиме ці змінні, вони повинні неявно бути final.


9

Тому що все інше є частиною реалізації, а інтерфейси не можуть містити жодної реалізації.


1
то яка причина остаточного.
Джоті

7
Щоб вказати, що його константа. У Java немає ключового слова const. статичний фінал - це те, як ви оголошуєте константи.
Амір Афгані

5
Оскільки Java 8, вони можуть містити реалізацію, але настійно рекомендується не використовувати її, якщо вам не потрібна зворотна сумісність. :)
codepleb

6
public interface A{
    int x=65;
}
public interface B{
    int x=66;
}
public class D implements A,B {
    public static void main(String[] a){
        System.out.println(x); // which x?
    }
}

Ось рішення.

System.out.println(A.x); // done

Я думаю, що це одна з причин, чому змінна інтерфейсу є статичною.

Не оголошуйте змінні всередині інтерфейсу.


3
Насправді, без специфікації "Axe" вона навіть не складеться ", тому фактично безпечно використовувати змінні (які неявно є загальнодоступними статичними фіналами) в інтерфейсах.
Марко,

Я не згоден з відповіддю, оскільки @Marco сказав, що навіть не збирається. Я ще не знайшов жодного іншого недоліку, можливо, просто ви не бачите написаного static finalперед змінною, яка насправді є статичною і остаточною.
Місер

5

статичний - оскільки інтерфейс не може мати жодного примірника. і остаточне - адже нам це не потрібно міняти.


15
"нам не потрібно" == "нас не дозволяють", не змішуйте значення.
peterh

3

тому що:

Static : оскільки у нас не може бути об'єктів інтерфейсів, тому ми повинні уникати використання змінних членів рівня об'єкта і використовувати змінні рівня класу, тобто статичні.

Final : щоб у нас не було неоднозначних значень змінних (проблема Алмаза - множинне спадкування).

І відповідно до документаційного інтерфейсу - це договір, а не імплементація.

довідка: Відповідь Абхішека Джайна на квору


2

Java не дозволяє абстрактні змінні та / або визначення конструктора в інтерфейсах. Рішення: Просто повісьте абстрактний клас між інтерфейсом та вашою реалізацією, який лише розширює абстрактний клас так:

 public interface IMyClass {

     void methodA();
     String methodB();
     Integer methodC();

 }

 public abstract class myAbstractClass implements IMyClass {
     protected String varA, varB;

     //Constructor
     myAbstractClass(String varA, String varB) {
         this.varA = varA;
         this.varB = VarB;
     }

     //Implement (some) interface methods here or leave them for the concrete class
     protected void methodA() {
         //Do something
     }

     //Add additional methods here which must be implemented in the concrete class
     protected abstract Long methodD();

     //Write some completely new methods which can be used by all subclasses
     protected Float methodE() {
         return 42.0;
     }

 }

 public class myConcreteClass extends myAbstractClass {

     //Constructor must now be implemented!
     myClass(String varA, String varB) {
         super(varA, varB);
     }

     //All non-private variables from the abstract class are available here
     //All methods not implemented in the abstract class must be implemented here

 }

Ви також можете використовувати абстрактний клас без будь-якого інтерфейсу, якщо Ви впевнені, що не хочете його реалізувати разом з іншими інтерфейсами пізніше. Зауважте, що ви не можете створити екземпляр абстрактного класу, ви СПРИЙМО його спочатку розширити.

("Захищене" ключове слово означає, що лише розширені класи можуть отримати доступ до цих методів та змінних.)

шпигун



1

Інтерфейс: обслуговування системних вимог.

В інтерфейсі змінні за замовчуванням призначаються загальнодоступним, статичним, остаточним модифікатором доступу. Тому що :

public: Іноді трапляється, що інтерфейс може бути розміщений в якомусь іншому пакеті. Тож йому потрібно отримати доступ до змінної з будь-якої точки проекту.

статичний: Як такий неповний клас не може створити об'єкт. Тому в проекті нам потрібно отримати доступ до змінної без об'єкта, щоб ми могли отримати доступ за допомогоюinterface_filename.variable_name

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


0

В Javaінтерфейс не дозволяє оголошувати змінні екземпляра. Використання змінної, оголошеної в інтерфейсі як змінної екземпляра, поверне помилку часу компіляції.

Ви можете оголосити постійну змінну, використовуючи static finalяку відрізняється від змінної екземпляра.


Це явно неправильно. Компілятор не збирається скаржитися, якщо ви не зробите це приватним або захищеним. Під кришкою, як уже згадували інші, вони перетворюються на публічний статичний фінал. І я думаю, це цілком очевидно, чому. Тому що інтерфейс покликаний диктувати поведінку, а не стан.
Мікаїл Абдуллаєв

0

Інтерфейс може бути реалізований будь-якими класами, і що, якщо це значення буде змінено одним із класів-реалізовувачів, то для інших класів-реалізаторів буде введено в оману. В основному інтерфейс є посиланням на об'єднання двох основних, але різних сутностей. Тому, декларувальна змінна всередині інтерфейсу неявно буде остаточною, а також статичною, оскільки інтерфейс не може бути примірником.


0

Придумайте веб-додаток, де у вас визначений інтерфейс та інші класи його реалізують. Оскільки ви не можете створити примірник інтерфейсу для доступу до змінних, вам потрібно мати статичне ключове слово. Оскільки його статична, будь-яка зміна значення відображатиметься на інших екземплярах, які її застосували. Отже, щоб запобігти цьому, ми визначаємо їх як остаточні.


0

Щойно спробувавши в Eclipse, змінна в інтерфейсі за замовчуванням є остаточною, тому ви не можете її змінити. У порівнянні з батьківським класом, змінні, безумовно, змінюються. Чому? З моєї точки зору, змінна в класі - це атрибут, який успадковуватиметься дітьми, і діти можуть змінювати його відповідно до фактичної потреби. Навпаки, інтерфейс визначає лише поведінку, а не атрибут. Єдина причина вводити змінні в інтерфейс - це використовувати їх як consts, що пов'язані з цим інтерфейсом. Хоча, згідно з наступним уривком, це не є хорошою практикою:

"Розміщення констант в інтерфейсі було популярною методикою в перші дні Java, але зараз багато хто вважає це неприємним використанням інтерфейсів, оскільки інтерфейси повинні мати справу з послугами, що надаються об'єктом, а не його даними. Також константи використовуються за класом, як правило, є детальною інформацією про реалізацію, але розміщення їх в інтерфейсі просуває їх до загальнодоступного API класу. "

Я також спробував або поставити статичну, або зовсім не має ніякої різниці. Код наведено нижче:

public interface Addable {
    static int count = 6;

    public int add(int i);

}

public class Impl implements Addable {

    @Override
    public int add(int i) {
        return i+count;
    }
}

public class Test {

    public static void main(String... args) {
        Impl impl = new Impl();

        System.out.println(impl.add(4));
    }
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.