Столкнулся с интересным различием поведения компиляторов javac и Eclipse Compiler for Java помогите разобраться почему их поведение отличается и какое соответствует спецификации!
Есть класс (назовём его Parent) в котором объявлен второй внутренний класс(назовем его InnerClass), который является потомком класс Parent. У обоих классов есть методы с одинаковыми именами (в примере имя methodA) но разной сигнатурой.
Проблема в том, что компилятор javac не видит private методы внешнего родительского класса при вызове их из потомка если у потомка есть метод с таким же именем, но другой сигнатурой. При этом Eclipse все устраивает код компилируется и запускается. Поведение одинаково как для статических методов так и для методов экземпляров.
Была идея, что Eclipse видит этот метод из области видимости т.к. оба находятся в теле родительского класса, а не через наследование.
Но если убрать наследование между классами Parent и InnerClass то methodA становиться недоступен и с точки зрения Eclipse кроме того это противоречит вот этому параграфу JLS которым судя по всему и руководствуется javac.
Методы экземпляров:
Eclipse:
public class Parent {
private void methodB(){}
private void methodA(String a) {}
class InnerClass extends Parent {
private void methodA(Integer a) {}
void callPrivateSuper() {
methodB(); //Eclipse BYTECODE -> INVOKESTATIC Parent.access$0 (LParent;)V
methodA(""); //Eclipse BYTECODE -> INVOKESTATIC Parent.access$1 (LParent;Ljava/lang/String;)V
}
}
}
javac:
public class Parent {
private void methodB(){}
private void methodA(String a) {}
class InnerClass extends Parent {
private void methodA(Integer a) {}
void callPrivateSuper() {
methodB();
methodA(""); //javac -> java: incompatible types: java.lang.String cannot be converted to java.lang.Integer
}
}
}
Статические методы:
Eclipse:
public class Parent {
private static void methodB(){}
private static void methodA(String a) {}
class InnerClass extends Parent {
private void methodA(Integer a) {}
void callPrivateSuper() {
methodB(); //Eclipse BYTECODE -> INVOKESTATIC Parent.access$0 ()V
methodA(""); //Eclipse BYTECODE -> INVOKESTATIC Parent.access$1 (Ljava/lang/String;)V
}
}
}
javac:
public class Parent {
private static void methodB(){}
private static void methodA(String a) {}
class InnerClass extends Parent {
private void methodA(Integer a) {}
void callPrivateSuper() {
methodB();
methodA(""); //javac -> java: incompatible types: java.lang.String cannot be converted to java.lang.Integer
}
}
}
При этом если в родительском классе у метода methodA изменить модификатор доступа с private на любой другой то javac компилирует код и все работает согласно JLS 1 и JLS 2 теперь метод предка виден доступен через наследование.
public class Parent {
void methodA(String a) {}
class InnerClass extends Parent {
private void methodA(Integer a) {}
void callPrivateSuper() {
methodA(""); //javac BYTECODE -> INVOKEVIRTUAL Parent$InnerClass.methodA (Ljava/lang/String;)V
//Eclipse BYTECODE -> INVOKEVIRTUAL Parent$InnerClass.methodA (Ljava/lang/String;)V
}
}
}
Почему того же что Eclipse не делает javac для private метода methodA?
Где в JLS и JVMS определено как должен вести себя компилятор в данном случае?
Правильно ли я понимаю что private методы не видны через наследования на первом этапе определения выполняемого метода, даже в том случае если эти методы доступны/видны по месту определения класса?
Из "коробки" Eclipse не показывает некоторые предупреждения в коде при программировании. Поля и методы материнского класса с модификатором private не доступны дочерним классам. Используйте protected, если необходимо открыть доступ к полям/методам материнского класса для дочерних элементов. Этот модификатор предоставляет доступ к полю/методу всем в основном классе, включая дочерние классы.
На мой взгляд javac обоснованно вам это показывает. А вот Eclipse достаточно часто может компилировать "нерабочий" код. Всё зависит от того как вы его настроите.
Ели вам необходимо иметь более "жёсткие" правила анализа кода в Eclipse, то их можно изменить в: Preferences -> Java -> Compiler -> Errors/Warnings.
Пример уведомлений Eclipse для private модификатора:
Пример уведомлений Eclipse для protected модификатора:
Основные этапы разработки сайта для стоматологической клиники
Продвижение своими сайтами как стратегия роста и независимости