Welcome to Software Development on Codidact!
Will you help us build our independent community of developers helping developers? We're small and trying to grow. We welcome questions about all aspects of software development, from design to code to QA and more. Got questions? Got answers? Got code you'd like someone to review? Please join us.
How can one import two classes with the same name in Java8?
Some development tools provide an error message when a user tries to import two things (classes, packages) with the same name. Some programming languages offer a syntax to import one of those things under a different name. In Python, that syntax is import foo from bar as foobar
. Does Java have an analogous construct for this?
2 answers
Elaborating with an example:
Java doesn't allow imports to aliased (not currently), to my knowledge.
The current standard is writing out the fully-qualified name:
ClassA.java:
package com.folder; // (the folder of this java file)
public class ClassA {
public class Inner { /* Class-A inner-class */ }
public static class Nested { /* Class-A nested-class */ }
public String v = "Class-A string";
public static String st_v = "static Class-A string";
public void f () { /* Class-A method */ }
public static void st_f () { /* static: Class-A method */ }
}
ClassB.java:
package com.folder; // (the folder of this java file)
public class ClassB {
public class Inner { /* Class-B inner-class */ }
public static class Nested { /* Class-B nested-class */ }
public String v = "Class B string";
public static String st_v = "static: Class-B string";
public void f () { /* Class-B method */ }
public static void st_f () { /* static: Class-B method */ }
}
ImporthingClass.java:
/* Note:
* import com.folder.ClassA.Inner;
* import com.folder.ClassB.Inner;
* This should cause an error in the second import ("Classes collide").
* import com.folder.ClassA.Nested;
* import com.folder.ClassB.Nested;
* This should cause an error in the second import ("Classes collide").
*
* For static importing:
* ...
* import static com.folder.ClassA.Nested;
* import static com.folder.ClassB.Nested;
*
* import static com.folder.ClassA.st_v;
* import static com.folder.ClassB.st_v;
*
* import static com.folder.ClassA.st_f;
* import static com.folder.ClassB.st_f;
* ...
* These static imports will NOT cause an error, UNTIL you try to use them (examples below)
*
* Also:
* Java allows only classes to be imported. (and interfaces). Although static-variables and static-methods can be static imported, neither variables nor methods can be regular imported.
* So, the "v" and "f" members don't matter in this example, but are there for this extra information.
*/
public class ImportingClass {
// From static imports: ALL will cause an "ambiguous" error
// Inner object = new Inner();
// String variable = st_v;
// st_f();
...
In general, this is how we are supposed to reference ambiguous imports:
...
// you can import Class A and Class B regardless, because their names are different
ClassA.st_f(); // will call static f (from class-A)
new ClassA().f(); // will call f (from class-A)
ClassB.st_f(); // will call static f (from class-B)
new ClassB().f(); // will call f (from class-B)
String Av = ClassA.st_v; // will get static v (from class-A)
String AS = new ClassA().v; // will get v (from class-A)
String Bv = ClassB.st_v; // will get static v (from class-B)
String BS = new ClassB().v; // will get v (from class-B)
// remember, we cannot import both inner/ nested classes though
ClassA.Nested n_obj = new ClassA.Nested();
ClassB.Nested n_obj2 = new ClassB.Nested();
ClassA.Inner i_obj = new ClassA().new Inner(); // weird syntax
ClassB.Inner i_obj2 = new ClassB().new Inner(); // weird syntax
// and of course, instead of calling new ClassA() and new Class B(), it is ideal to have variable instances of those classes...
}
However....... there is technically a work-around.
We can't import com.folder.ClassName as AliasName
but we can use another class as a Wrapper for your imports:
public class A {
public static class Nested { } // to be regular imported
public static int x = 0; // to be static imported
}
public class B {
public static class Nested { } // to be regular imported also
public static int x = 0; // to be static imported also
}
Here are some wrapper classes:
import com.folder.A.Nested;
import static com.folder.A.x;
public class WrapperForA {
public static int x_A = x; // an alias (technically)
// Nested can't be aliased
public static class NotAnAlias_A
extends Nested // iff Nested is non-final
{
// classes can't be aliased, this is inheritance
}
}
import com.folder.B.Nested;
import static com.folder.B.x;
public class WrapperForB {
public static int x_B = x; // an alias (technically)
// Nested can't be aliased
public static class NotAnAlias_B
extends Nested // iff Nested is non-final
{
// classes can't be aliased, this is inheritance
}
}
and finally, implementing your "aliases" (before and after):
import static com.folder.WrapperForA.x_A;
// instead of import static com.folder.A.x;
import static com.folder.WrapperForB.x_B;
// instead of import static com.folder.B.x;
import com.folder.WrapperForA.NotAnAlias_A;
// instead of import com.folder.A.Nested;
import com.folder.WrapperForA.NotAnAlias_B;
// instead of import com.folder.B.Nested;
public class ImportingClass {
// technically, the static imports are aliasing:
int x1 = x_A;
int x2 = x_B;
// x1 and x2 are the same type.
// this would work for variables and methods (DON'T CODE LIKE THIS, ~probably. This is purely demonstrational...)
NotAnAlias_A obj_A = new NotAnAlias_A();
NotAnAlias_B obj_B = new NotAnAlias_B();
// this is technically not aliasing, at all. observe this behavior:
NotAnAlias_A obj_A2 = new NotAnAlias_A();
NotAnAlias_B obj_B2 = new NotAnAlias_B();
obj_A = obj_A2; // is fine (same types)
obj_B = obj_B2; // is fine (same types)
// obj_A = obj_B2; // is NOT fine (different types)
// obj_B = obj_A2; // is NOT fine (different types)
// that's why it's not aliasing (aliasing means the under-lining types are preserved: I think. *In reality, this example is very different from aliasing...)
}
This is the limit of what Java can do for aliasing. Another honorable mention:
- Strings: using Strings to run your system to reference different things you want to import (like psuedo-aliasing / faking it):
public abstract class ExampleStrings {
Map<String, Object> OVERLY_COMPLICATED;
// Version-1: Object could refer to "Class": A string ie. "AliasName" could map to com.folder.Class.Nested.class (Issue: is Class is usually in a generic form Class<T>, which causes problems)
// Version-2: Object could refer to a Lambda, that constructs an instance: A string ie. "AliasName" could map to () -> { return new com.folder.Class.Nested(); } (Issue: we don't know what the return type is, meaning Nested is essentially useless)
}
So, ff you want to be able to use importing with aliasing in Java, there aren't any built-in solutions; you will likely need to incorporate a plugin.
The best solution is difficult to implement: you can make a POJO class that generates a Java class file for you, after reading custom String logic like import X as Y
.
Specifically, in your projects pom.xml, dispatch an execution to run at compile time that will read your code and rewrite it into something readable by the compiler (you have to reroute the compiler somehow, because, ideally you don't want to have the execution rewrite your code permanently). And viola... aliases in Java.
This is a huge waste of time. Best of luck!
0 comment threads
While other JVM languages, such as Groovy, Kotlin and Scala have Python-like import aliasing, Java does not.
It's not possible to 're-name' imports, however, when you call a class from a package, you can use its FQN (Fully Qualified Name), that is, add the full package name before the class name.
For example, when calling FooClass.methodName()
after importing a different copy of FooClass
, com.company.utils.FooClass.methodName()
specifies the FooClass
in the com.company.utils
package. This allows you to reference multiple copies of FooClass
.
Full example:
import com.company.special.FooClass;
class BarClass {
public void exampleMethod(){
//Call method1 from FooClass that we imported above
int i = FooClass.method1();
//Call a class named FooClass that is in a different package
String str = com.company.utils.FooClass.methodName();
}
}
1 comment thread