当简单名称和完全限定名称发生冲突时如何引用 class

How to refer to a class when both simple and fully-qualified names clash

考虑以下病态示例:

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?
  }
}

构造函数中创建的两个实例是嵌套的classes.

但是我怎么能在同一个 class 中提到我们都知道和喜爱的 java.util.ArrayList?我们不能导入它,也不能使用完全限定名称,因为会使用嵌套的 class 符号。

在这种情况下我们能做什么? (除了明显的 - 停止为嵌套的 classes 使用这种肆意邪恶的名称)。

你试过了吗

Class cls = ClassLoader.getSystemClassLoader().loadClass("java.util.ArrayList");
List arrayList = cls.newInstance();

很久没考虑类加载器了,不过IIRC.loadClass()会优先尝试从最基础的类加载器加载,真正的java.util包应该由bootstrap 类加载器,其优先级高于您在应用程序中定义的任何内容。

我要冒昧地说,不可能从 Ideone 内部引用它。我看到的唯一解决方案是创建另一个 class Idetwo(它是 Ideone 的 nestmate(即它驻留在同一个文件中))和 return a 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就可以了。但是,如果您要在 Ideone 的主要方法中调用 List<Integer> list = Idetwo.getList();,则需要导入 java.util.*,因为单个导入将不起作用(有趣的是)。

这就是为什么包以小写字母开头,类型以大写字母开头的原因,因为 very first edition of the official code conventions for java。我认为我从未见过 java 代码违反此约定。

但是您可以使用它的完全限定名称从外部引用内部类型:

com.whatever.bad.project.SomeClass.java.util.ArrayList

当您必须从内部引用外部类型时,您可以更改该源文件以符合 Java 命名准则。

如果您已完成以下两件事,您将无法再直接引用 java.util.ArrayList

  1. 在作用域中用静态嵌套 class 隐藏简单名称 ArrayList
  2. 隐藏完全限定名称 java.util.ArrayList 与 class ArrayList 嵌套在 class util 中,嵌套在嵌套 class java.

您甚至无法 "split" 尝试使用 "partially qualified" 导入。

import java.*;

...

// This doesn't work!
new util.ArrayList<>();

你可以import java.*;,但那是没有价值的;没有 class 直接在 java 包中定义。

但是,您可以间接引用 class java.util.ArrayList,因为它不是 final。在 class Ideone 的范围之外,声明一个具有不同名称的子class。

class AnArrayList<T> extends java.util.ArrayList<T> {}

那你可以参考那个class编程到接口:

List<Integer> al = new AnArrayList<>();  // won't print !! or Here