Чому змінні інтерфейсу статичні та кінцеві за замовчуванням у Java?
Чому змінні інтерфейсу статичні та кінцеві за замовчуванням у Java?
Відповіді:
З питань FAQ щодо дизайну інтерфейсу Java Філіпа Шоу:
Змінні інтерфейсу є статичними, оскільки інтерфейси Java не можуть бути створені самостійно; значення змінної повинно бути призначене в статичному контексті, в якому не існує жодного примірника. Кінцевий модифікатор гарантує, що значення, присвоєне змінній інтерфейсу, є справжньою константою, яку не можна повторно призначити програмним кодом.
static
модифікатора є абсолютно помилковим. Змінні загальнодоступних екземплярів класу є частиною його інтерфейсу, і немає ніяких причин, чому їх не слід абстрагувати на Java interface
, як і методи екземплярів. Не має значення, що Java interface
не може бути безпосередньо створена інстанцією - ви все одно можете мати екземпляри класів, які реалізують, interface
і розумно вимагати, щоб вони мали певну змінну публічного екземпляра. Що стосується частини final
, яка зовсім не пропонує пояснення - вона просто описує, що final
означає.
Оскільки інтерфейс не має прямого об'єкта, єдиний спосіб отримати доступ до них - це за допомогою класу / інтерфейсу, і тому, якщо існує змінна інтерфейс, він повинен бути статичним, інакше він взагалі не може бути доступним для зовнішнього світу. Оскільки він статичний, він може містити лише одне значення, і будь-які класи, що реалізують його, можуть змінити його, отже, все буде безлад.
Отже, якщо взагалі є змінна інтерфейс, вона буде неявно статичною, остаточною і, очевидно, загальнодоступною !!!
interface
. Клас буде реалізувати інтерфейс, оголошуючи змінну екземпляра (як того вимагає інтерфейс). Його конструктор (або інший метод) встановлює змінну екземпляра. Коли екземпляр класу інстанціюється, ви зможете отримати доступ до його змінної екземпляра.
public : для доступності для всіх класів, як і методи, наявні в інтерфейсі
статичний : оскільки інтерфейс не може мати об'єкт, інтерфейсName.variableName може використовуватися для його посилання або безпосередньо до змінноїName у класі, що реалізує його.
остаточний : зробити їх константами. Якщо два класи реалізують один і той же інтерфейс, і ви даєте обом правом змінити значення, конфлікт виникне в поточному значенні var, тому дозволена лише одноразова ініціалізація.
Крім того, всі ці модифікатори є прихованими для інтерфейсу, вам не потрібно вказувати будь-який з них.
( Це не філософська відповідь, а більше практична ). Вимога 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
.
Тому що все інше є частиною реалізації, а інтерфейси не можуть містити жодної реалізації.
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
Я думаю, що це одна з причин, чому змінна інтерфейсу є статичною.
Не оголошуйте змінні всередині інтерфейсу.
static final
перед змінною, яка насправді є статичною і остаточною.
тому що:
Static
: оскільки у нас не може бути об'єктів інтерфейсів, тому ми повинні уникати використання змінних членів рівня об'єкта і використовувати змінні рівня класу, тобто статичні.
Final
: щоб у нас не було неоднозначних значень змінних (проблема Алмаза - множинне спадкування).
І відповідно до документаційного інтерфейсу - це договір, а не імплементація.
довідка: Відповідь Абхішека Джайна на квору
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
}
Ви також можете використовувати абстрактний клас без будь-якого інтерфейсу, якщо Ви впевнені, що не хочете його реалізувати разом з іншими інтерфейсами пізніше. Зауважте, що ви не можете створити екземпляр абстрактного класу, ви СПРИЙМО його спочатку розширити.
("Захищене" ключове слово означає, що лише розширені класи можуть отримати доступ до цих методів та змінних.)
шпигун
Інтерфейс - це договір між двома сторонами, який є інваріантним, вирізаним у камені, отже, остаточним. Див. Дизайн за контрактом .
Інтерфейс: обслуговування системних вимог.
В інтерфейсі змінні за замовчуванням призначаються загальнодоступним, статичним, остаточним модифікатором доступу. Тому що :
public: Іноді трапляється, що інтерфейс може бути розміщений в якомусь іншому пакеті. Тож йому потрібно отримати доступ до змінної з будь-якої точки проекту.
статичний: Як такий неповний клас не може створити об'єкт. Тому в проекті нам потрібно отримати доступ до змінної без об'єкта, щоб ми могли отримати доступ за допомогоюinterface_filename.variable_name
остаточний: припустимо, що один інтерфейс реалізується багатьма класами, а всі класи намагаються отримати доступ та оновити змінну інтерфейсу. Тож це призводить до суперечливості зміни даних і стосується кожного іншого класу. Тому потрібно оголосити модифікатор доступу остаточним.
В Java
інтерфейс не дозволяє оголошувати змінні екземпляра. Використання змінної, оголошеної в інтерфейсі як змінної екземпляра, поверне помилку часу компіляції.
Ви можете оголосити постійну змінну, використовуючи static final
яку відрізняється від змінної екземпляра.
Інтерфейс може бути реалізований будь-якими класами, і що, якщо це значення буде змінено одним із класів-реалізовувачів, то для інших класів-реалізаторів буде введено в оману. В основному інтерфейс є посиланням на об'єднання двох основних, але різних сутностей. Тому, декларувальна змінна всередині інтерфейсу неявно буде остаточною, а також статичною, оскільки інтерфейс не може бути примірником.
Придумайте веб-додаток, де у вас визначений інтерфейс та інші класи його реалізують. Оскільки ви не можете створити примірник інтерфейсу для доступу до змінних, вам потрібно мати статичне ключове слово. Оскільки його статична, будь-яка зміна значення відображатиметься на інших екземплярах, які її застосували. Отже, щоб запобігти цьому, ми визначаємо їх як остаточні.
Щойно спробувавши в 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));
}
}