15

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).

user207421
  • 305,947
  • 44
  • 307
  • 483
Andy Turner
  • 137,514
  • 11
  • 162
  • 243
  • Do you have a reason to believe there's some solution? – shmosel May 31 '18 at 22:42
  • @shmosel not especially. I'm just thinking up bizarre corner cases for imports, whilst working on some Error Prone checks. – Andy Turner May 31 '18 at 22:44
  • 2
    I'd love to see one of the language architects answer this question. – Jacob G. May 31 '18 at 22:52
  • 1
    That problem can't happen if you follow standard [**Java Naming Conventions**](http://www.oracle.com/technetwork/java/codeconventions-135099.html), i.e. package names in all lowercase, and class names in mixed case. Naming conventions exist for a reason. – Andreas May 31 '18 at 23:00
  • 1
    @Andreas I agree; but I am asking about what is permitted by the *language*, not what is used by convention. – Andy Turner May 31 '18 at 23:02
  • @shmosel in C# there is a solution. You can specify global:: prefix to reference an original Java class. I.e. new global::java.util.ArrayList<>(); – TOP KEK Jun 17 '20 at 18:05

4 Answers4

3

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).

Jacob G.
  • 28,856
  • 5
  • 62
  • 116
3

You can no longer directly reference java.util.ArrayList if you've done the 2 things you've done:

  1. Hide the simple name ArrayList with a static nested class in scope.
  2. Hide the fully qualified name java.util.ArrayList with a class ArrayList nested within class util, nested within nested class java.

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
rgettman
  • 176,041
  • 30
  • 275
  • 357
  • 2
    Of course, you could get an *actual* `java.util.ArrayList` by using something like `Stream.of().collect(Collectors.toList())`. – Andy Turner May 31 '18 at 23:17
  • @AndyTurner That sounds like you should answer your own question. I looked up the source code for `Collectors.toList`, and it uses `ArrayList::new`, confirming your claim. – rgettman May 31 '18 at 23:25
  • maybe. It's not really an answer to the question I'm intending to ask, which is can you refer to the *type*, not how do you get an instance of the type. – Andy Turner May 31 '18 at 23:27
2

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.

DavidW
  • 1,413
  • 10
  • 17
1

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.

meriton
  • 68,356
  • 14
  • 108
  • 175
  • 2
    I refer you to the my reply to @Andreas' comment: "I am asking about what is permitted by the language, not what is used by convention". – Andy Turner May 31 '18 at 23:13