Consider the following pathological example:
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?
}
}
The two instances created in the constructor are of the nested classes.
But how might I refer to the java.util.ArrayList
that we all know and love in the same class? We can't import it, and we can't use the fully-qualified name, as the nested class symbols would be used instead.
What can we do in this case? (Other than the obvious - stop using such wantonly evil names for the nested classes).
You can no longer directly reference java.util.ArrayList
if you've done the 2 things you've done:
- Hide the simple name
ArrayList
with a static nested class in scope. - Hide the fully qualified name
java.util.ArrayList
with a classArrayList
nested within classutil
, nested within nested classjava
.
You can't even "split" the import in an attempt to use a "partially qualified" import.
import java.*;
...
// This doesn't work!
new util.ArrayList<>();
You can import java.*;
, but that is worthless; no classes are defined in the java
package directly.
However, you can reference the class java.util.ArrayList
indirectly because it's not final
. Outside the scope of the class Ideone
, declare a subclass with a different name.
class AnArrayList<T> extends java.util.ArrayList<T> {}
Then you can refer to that class and program to the interface:
List<Integer> al = new AnArrayList<>(); // won't print !! or Here
I'm going to go out on a limb and say that it's not possible to refer to it from within Ideone
. The only solution that I see is to create another class Idetwo
(which is a nestmate of Ideone
(i.e. it resides in the same file)) and return a java.util.ArrayList
from there for use in 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;
}
}
And you'd just change your Ideone
's main method to something like:
public static void main(String[] args) throws Exception {
new Ideone.ArrayList<>();
new Ideone.java.util.ArrayList<>();
Idetwo.getList().forEach(System.out::println);
}
Output:
!!
Here
1
2
3
Note: With this method, importing java.util.ArrayList
will work fine. However, if you were to call List<Integer> list = Idetwo.getList();
inside Ideone
's main method, you need to import java.util.*
, as individual imports will not work (interestingly).
Have you tried
Class cls = ClassLoader.getSystemClassLoader().loadClass("java.util.ArrayList");
List arrayList = cls.newInstance();
It's been a long time since I've thought about classloaders, but IIRC .loadClass()
will preferentially try to load from the most fundamental classloader, and the real java.util
package should be provided by the bootstrap classloader, which gives it higher precedence than anything you define in your application.
That's why packages start with lower case letters, and types with upper case letters, since the very first edition of the official code conventions for java. I don't think I have ever seen java code break this convention.
But you can refer to the inner type from the outside using it's fully qualified name:
com.whatever.bad.project.SomeClass.java.util.ArrayList
When you have to refer to the outer type from inside, you can probably change that source file to comply with Java naming guidelines.
来源:https://stackoverflow.com/questions/50633759/how-to-refer-to-a-class-when-both-simple-and-fully-qualified-names-clash