Как обратиться к классу, когда столкнулись как простые, так и полностью квалифицированные имена
Рассмотрим следующий патологический пример:
class Ideone {
static class ArrayList<T> {
ArrayList() {
System.out.println("!!");
}
}
static class java {
static class util {
static class ArrayList<T> {
ArrayList() {
System.out.println("Here");
}
}
}
}
public static void main(String[] args) {
new ArrayList<>();
new java.util.ArrayList<>();
// Can I refer to the "usual" java.util.ArrayList?
}
}
Два экземпляра, созданных в конструкторе, представляют собой вложенные классы.
Но как я могу обратиться к java.util.ArrayList
который все мы знаем и любим в одном классе? Мы не можем импортировать его, и мы не можем использовать полностью квалифицированное имя, поскольку вместо этого будут использоваться вложенные символы класса.
Что мы можем сделать в этом случае? (За исключением очевидных - прекратите использовать такие бессмысленные злые имена для вложенных классов).
Ответы
Ответ 1
Вы уже не можете напрямую ссылаться на java.util.ArrayList
если вы выполнили две вещи, которые вы сделали:
- Скрыть простое имя
ArrayList
со статическим вложенным классом в области. - Скрыть полное имя
java.util.ArrayList
с классом ArrayList
вложенным в класс util
, вложенным в вложенный класс java
.
Вы даже не можете "разделить" импорт, пытаясь использовать "частично квалифицированный" импорт.
import java.*;
...
// This doesn't work!
new util.ArrayList<>();
Вы можете import java.*;
, но это бесполезно; никакие классы не определены в пакете java
напрямую.
Однако вы можете ссылаться на класс java.util.ArrayList
косвенно, потому что он не является final
. Вне рамки класса Ideone
объявите подкласс с другим именем.
class AnArrayList<T> extends java.util.ArrayList<T> {}
Затем вы можете обратиться к этому классу и программе к интерфейсу:
List<Integer> al = new AnArrayList<>(); // won't print !! or Here
Ответ 2
Я собираюсь выйти на конечность и сказать, что это невозможно сослаться на нее изнутри Ideone
. Единственное решение, которое я вижу, это создать еще один класс Idetwo
(который является nestmate of Ideone
(то есть он находится в одном файле)) и возвращает java.util.ArrayList
оттуда для использования в Ideone
:
import java.util.ArrayList;
class Ideone {
...
}
class Idetwo {
static ArrayList<Integer> getList() {
ArrayList<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
return list;
}
}
И вы просто измените свой основной метод Ideone
на что-то вроде:
public static void main(String[] args) throws Exception {
new Ideone.ArrayList<>();
new Ideone.java.util.ArrayList<>();
Idetwo.getList().forEach(System.out::println);
}
Выход:
!!
Here
1
2
3
Примечание. С помощью этого метода импорт java.util.ArrayList
будет работать нормально. Однако, если вы должны были вызвать List<Integer> list = Idetwo.getList();
внутри основного метода Ideone
вам нужно импортировать java.util.*
, поскольку индивидуальный импорт не будет работать (интересно).
Ответ 3
Ты пытался
Class cls = ClassLoader.getSystemClassLoader().loadClass("java.util.ArrayList");
List arrayList = cls.newInstance();
Прошло много времени с тех пор, как я подумал о загрузчиках классов, но IIRC .loadClass()
будет предпочтительно пытаться загрузить из самого фундаментального загрузчика классов, а реальный пакет java.util
должен быть предоставлен загрузчиком загрузки bootstrap, что дает ему более высокий приоритет чем все, что вы определили в своем приложении.
Ответ 4
Поэтому пакеты начинаются с строчных букв и типов с заглавными буквами, начиная с самого первого выпуска официальных условных кодов для java. Я не думаю, что когда-либо видел, что java-код нарушает это соглашение.
Но вы можете ссылаться на внутренний тип снаружи, используя его полное имя:
com.whatever.bad.project.SomeClass.java.util.ArrayList
Когда вам приходится обращаться к внешнему типу изнутри, вы, вероятно, можете изменить этот исходный файл в соответствии с принципами именования Java.