Как обратиться к классу, когда столкнулись как простые, так и полностью квалифицированные имена

Рассмотрим следующий патологический пример:

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 если вы выполнили две вещи, которые вы сделали:

  1. Скрыть простое имя ArrayList со статическим вложенным классом в области.
  2. Скрыть полное имя 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.