Странности с локальными классами связанные с модификаторами доступа. Откуда растут ноги этих странностей?
Ну понятно, что смысла нет использовать модификаторы доступа для объявления локальных классов. Но вот интересно:
1) почему в локальных классах разрешено объявлять поля, методы, конструкторы и private и public и protected???
2) если объявлять два локальных классов в одном методе, то даже если один из полей одного класса будет иметь private модификатор доступа, то это никак не помешает другому классу использовать этот private поле. Например:
public class Catcher {
public int BookCatcher(){
class Book{
private int color;
String name;
int countOfPages;
Book(){}
}
class Ou{
Ou(){
Book book = new Book();
book.color=5;
Log.i("Room8000", String.valueOf(book.color));
}
}
Book book = new Book();
Ou ou = new Ou();
return book.color;
}
}
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Catcher catcher = new Catcher();
catcher.BookCatcher();
}
}
result:
2020-04-22 17:09:58.410 20627-20627/com.example.android.javaoop I/Room8000: 5
3) но вот если этот самый private поле сделать static то компилятор вспоминает, что надо ругаться.
компилятор:
inner classes cannot have static declarations
4) да и если вместо private использовать protected то можно убедится, что нет вообще необходимости добавить extends к вызывающему данное поле классу. (ну этот пункт можно и не учесть как странность, но все же)
И так вопросы:
В чем смысл таких допущении в языке Java? Это баги или имеют какое то логичное объяснение, которую я просто не вижу? А если баг, то как получается что в течении столько обновлении версии java к этой проблеме не уделили ни малейшего внимания?
Ответы (1 шт):
На будущее, по правилам stack сообществ один вопрос = один вопрос. 4 вопроса внутри одного задавать не стоит, даже если они как-то связаны между собой
1) а почему нет? Тот факт, что вы создали класс внутри метода не означает, что он должен работать иначе. Если вы создадите private inner class, то у него тоже можно создавать public методы и поля. Просто нет смысла добавлять другой интерпретатор для внутренних классов
2) почитайте подробнее про модификаторы доступа. private = доступный в этом же файле. default - в этом пакете. protected - в этом файле и наследованных классах. Т.к. вложенные в метод классы не могут находится в разных файлах у вас нет инструмента изолировать поля одного от другого
3) inner классы не могут иметь static полей и методов, что вам и сказала IDE. Вообще никакие вложенные классы никаких static элементов не могут содержать. Если в одном файле записаны несколько классов еще можно, но тогда они не вложенные, просто в одном файле лежат, а не внутри друг друга
4) опять же, проблема в том как в java интерпретируется private и protected. Как я говорил выше, нет возможности изолировать поля созданных в одном методе классов друг от друга.
В целом вложенные в методы классы можно отнести к bad practices, как и inner классы. Первые малоэффективны, а вторые еще и не безопасны по памяти. Если их использование в конкретном случае правда упрощает код, то можно воспользоваться, но в большинстве случаев их можно избежать не потеряв в эффективности и читаемости кода. Используйте только статичные внутренние классы
public class A {
static public/private/default class B{
}
}
Потому что без static класс становится зависим от экземпляра родителя и хранит на него ссылку. То есть код
public class A{
public class B{
}
}
эквивалентен
public class A{
static public class B{
A parent;
B(A parent){
this.parent = parent;
}
}
}
В результате есть риск сохранить объект класса B, а он не даст сборщику убить класс A. Если класс А - это активити, то можно нахватать много проблем по незнанию
Вывод. Из все этой простыни выносим следующее: если нужно создать класс внутри другого, то он (желательно)должен быть static. Классы внутри методов лучше не использовать вообще, т.к. это малополезно и это все те же inner классы. И внимательно читаем принципы работы модификаторов доступа, т.к. в java они работают не совсем по парадигме ООП