Java generic method erasure and inheritance - java

I am running into a problem with javas generics and overriding methods. Imagine I have a deep tree-like class hierarchy. The top-level class defines a method foo which takes 1 argument of type Strategy. Strategy has a generic type parameter.
Each class in my class hierarchy needs to override foo to limit the kind of Strategy it can be passed so that the generic type parameter of the strategy matches the declaring class. Below is an example:
abstract static class TopLevelClass {
static final Strategy<TopLevelClass> s1 = tlc -> System.out.println(tlc.getTopLevelAtt());
String getTopLevelAtt() {
return "TopLevelAtt";
}
void foo(Strategy<TopLevelClass> s) {s.bar(this);}
}
static class MidLevelClass extends TopLevelClass {
static final Strategy<MidLevelClass> s2 = mlc -> System.out.println(mlc.getMidLevelAtt());
String getMidLevelAtt() {
return "MidLevelAtt";
}
void foo(Strategy<MidLevelClass> s) {s.bar(this);}
}
static class LowLevelClass extends MidLevelClass {
static final Strategy<LowLevelClass> s3 = llc -> System.out.println(llc.getTopLevelAtt());
String getLowLevelAtt() {
return "LowLevelAtt";
}
void foo(Strategy<LowLevelClass> s) {s.bar(this);}
}
static interface Strategy<X> {
void bar(X x);
}
In this example I want to be able to call foo on instances of class LowLevelClass with any of the static references s1, s2 and s3 defined in TopLevelClass, MidLevelClass and LowLevelClass respectively. Ideally I would not have to call different methods foo1, foo2 or foo3 depending on the argument.
The code above does NOT compile in java. The compile-time-error is:
Name clash: The method foo(Strategy) of type MidLevelClass has the same erasure as foo(Strategy) of type TopLevelClass but does not override it
I doubt this can easily be resolved. I could just use raw-types and rely on run-time typechecks but I would rather keep type safety. What can I do to achieve this without sacrificing the type hierarchy or type safety? Please note that passing the Strategy in the constructor IS NOT an option for me! It must be possible to call foo multiple times over the life time of the object.
Edit:
I realize, that this problem is perhaps difficult to follow without knowing the circumstances surrounding it. I have opened a more detailed question explaining the background of my problem here: How to make this Strategy-Object pattern type safe

If you are worried about erasure then just use separate method names for separate methods:
abstract class TopLevelClass {
void fooTop(Strategy<TopLevelClass> s) {/*...*/}
}
class MidLevelClass extends TopLevelClass {
void fooMid(Strategy<MidLevelClass> s) {/*...*/}
}
class LowLevelClass extends MidLevelClass {
void fooLow(Strategy<LowLevelClass> s) {/*...*/}
}
However, I suspect erasure is not your problem. You presumably want to override the same method.
An instance of Strategy<LowLevelClass> cannot possibly be a Strategy<MidLevelClass>, which cannot be a Strategy;
Given
Strategy<LowLevelClass> l;
Strategy<MidLevelClass> m;
Then you cannot assign one to another.
l = m; // Compile-time fail.
m = l; // Compile-time fail.
And therefore it would make no sense to be able to do the same via method overriding. (It's also always been true that bar(TopLevelClass) cannot override bar(MidLevelClass), though since 1.5 there are covariant return types.)
Add a type parameter to the class to use as a type argument in the method.
abstract class TopLevelClass<T extends TopLevelClass<T>> {
void foo(Strategy<T> s) {/*...*/}
}
class MidLevelClass<T extends MidLevelClass<T>> extends TopLevelClass<T> {
void foo(Strategy<T> s) {/*...*/}
}
class LowLevelClass<T extends LowLevelClass<T>> extends MidLevelClass<T> {
void foo(Strategy<T> s) {/*...*/}
}
The updated question add the use of this as a argument to a call of Strategy.foo. This implies MidLevelClass must be abstract - it cannot guarantee foo is overridden. The type of this now needs to fit the type parameter. To do that, add an abstract "getThis" method (concrete in concrete subclasses).
protected abstract X getThis();
...
#Override protected X getThis() { return this; }
The type of the static fields requires wildcards:
static final Strategy<? extends TopLevelClass<?>> s1 =
tlc -> System.out.println(tlc.getTopLevelAtt());
(Better designs prefer composition over inheritance.)

I feel that there a couple of difficulties with this design:
Since each of your class implements its own Strategy using only methods within the same class, there is no need for Strategy.bar() to take an instance of the class. This passing of parameter is one of the causes of the hindrance to implementing this neatly.
Since all the implementations of foo() are doing exactly the same thing, you don't need multiple implementations.
Here is a code that has a partial solution. Partial because, in a good solution, you should be able to pass the reference of TopLevelClass in the changed foo() method. If you can figure out a way for that, I think it will be just great. With this solution, the class hierarchy is not a factor since we are using specific reference types.
I have commented the changed parts starting "CHANGE".
public class Erasure1{
public static void main( String[] args ){
LowLevelClass slc = new LowLevelClass(); //'slc' must be exactly the same type as the instance. This is a limitation with this solution. Ideal thing would have been that this reference be of type TopLevelClass.
slc.foo( LowLevelClass.s3, slc );
}
abstract static class TopLevelClass{
static final Strategy<TopLevelClass> s1 = tlc -> System.out.println( tlc.getTopLevelAtt() );
String getTopLevelAtt(){ return "TopLevelAtt"; }
/* CHANGE 1: It is necessary that the instance of TopLevelClass subtype be passed since
* Strategy.bar() doesn't accept wildcards. Changing it to accept a 'T' to pass to bar().
* Also, since, this is now taking 'T' as a parameter, this method could very well be a
* static method in a utility class. */
<T> void foo( Strategy<T> s, T tlc ){
s.bar( tlc );
}
}
static class MidLevelClass extends TopLevelClass{
static final Strategy<MidLevelClass> s2 = mlc -> System.out.println(mlc.getMidLevelAtt());;
String getMidLevelAtt(){ return "MidLevelAtt"; }
/* CHANGE 2: Since this method is not doing anything different from its parent, this is not required. */
//void foo(Strategy<MidLevelClass> s) {s.bar(this);}
}
static class LowLevelClass extends MidLevelClass{
static final Strategy<LowLevelClass> s3 = llc -> System.out.println( llc.getLowLevelAtt() );
String getLowLevelAtt(){ return "LowLevelAtt"; }
/* CHANGE 2: Since this method is not doing anything different from its parent, this is not required. */
//void foo(Strategy<LowLevelClass> s) {s.bar(this);}
}
static interface Strategy<X> {
void bar( X x );
}
}

Related

Convert a Java Method object to a Function object [duplicate]

class A {
public static void foo() {}
}
class B {
public static void foo() {}
}
I have Class clazz = A.class; or B.class;
How do I access this via "clazz" assuming it might be assigned either 'A' or 'B'
It is only possible to access those methods using reflection. You cannot reference a class directly, only an instance of type Class.
To use reflection to invoke methodname(int a, String b):
Method m = clazz.getMethod("methodname", Integer.class, String.class);
m.invoke(null, 1, "Hello World!");
See Class.getMethod() and Method.invoke()
You may want to think about your design again, to avoid the need to dynamically call static methods.
You can invoke a static method via reflection like this :
Method method = clazz.getMethod("methodname", argstype);
Object o = method.invoke(null, args);
Where argstype is an array of arguments type and args is an array of parameters for the call. More informations on the following links :
getMethod()
invoke()
In your case, something like this should work :
Method method = clazz.getMethod("foo", null);
method.invoke(null, null); // foo returns nothing
You cannot access static methods without an explicit reference to the class.
No inheritance here, sorry, so you must either do:
A.foo()
or
B.foo()
If you really need it, you will have to do a check:
Object o = .... // eith an A or B instance.
if( o instanceof A ) {
A.foo()
} else {
B.foo()
}
But why don't you just make those functions instance functions, and let them implement an interface?
Okey, you have a class object. Then do:
Class c = ...;
c.getMethod("foo").invoke(null); // null to invoke static methods
According to my lack of knowledge the need for the requested construct is given by the fact that an interface doesn't offer the possibility of static abstract methods. Here is an example:
public enum Cheese implements Yumy {
GOUDA(49),
ESROM(40),
HWARTI(38);
private int percentage;
private Cheese(int fat100) {...} constructor
public void yamyam() {...} // as in Yumy
public static Cheese getByFat(int fat100) {...} // no chance to be part
of interface
};
I hope this isn't making too many assumptions or deviating too far from your question, but if your two classes share a common supertype and creating an instance is tolerable then you can:
Implement a common interface
Create an instance of the object via myClass.newInstance() (class must have an empty constructor)
Call the static method from the instance object.
interface Foo {
void foo();
}
class A implements Foo {...}
class B implements Foo {...}
<T extends Foo> public void something(Class<T> clazz) {
T myInstance = clazz.newInstance();
myInstance.foo();
}
...
something(A.class);
It's a little bizarre but in my case it proved to be useful, and I began by asking the very same question that you did.

In Java, how do I refer explicitly to a static member of the class of `this`?

In Java, how do I refer explicitly to a static member of the class of this?
I want to refer explicitly to the static member for readability, but to not use a literal class name to respect subclasses overriding the value.
A contrived example:
class Flying {
static final String label = "A Flying Superhero";
String exclamation() {
return "Look! Up in the sky! It’s a bird! It’s a plane! It’s "+(WHAT GOES HERE?)+"!";
}
}
class Superman extends Flying {
static final String label = "Superman";
}
class Howard extends Flying {
static final String label = "Howard the Duck";
}
Note that I want to avoid using label alone, because its meaning could be ambiguous; I want a reader to know immediately that it's a static member, as they would from Flying.label, but without naming the base class.
(In the case that inspired the question, the static member is also final, but I don't think that affects how you refer to it.)
EDIT: Here's a possibly more compelling case. I want to implement main in the superclass, and have it create and use an instance of the subclass that was invoked.
class Super
public static void main( String[] args ) {
Super instance = new (?WHAT GOES HERE?)( /*...*/ );
instance.use();
}
}
class Sub extends Super {
void use() {
/* ... */
}
}
When the jvm is started on Sub, I want it to use the same implementation of main, but use an instance of the subclass.
This case is different in that the context is static, and the static member to access is a constructor.
(This is coming up for a homework assignment in a graduate course in modeling & simulation; the superclass is a model, and different scenarios are implemented as subclasses.)
To clairify the question, I think three things are needed:
Within an invocation of a static method, get the Class on which the method was invoked (I haven't found anything on this)
Given a Class, access a static member of that class (possibly with aClass.getDeclaredField?)
Given a Class, construct a new instance of that class (possibly with aClass.getConstructors?)
Conclusion
I hadn't realized I was trying to do something so contrary to the Java way until reading the answers. Apparently I've gotten used to more dynamic languages. (It seems wrong to feel like I've been spoiled by JavaScript.)
This architecture was largely motivated by the GUI provided by the framework I'm using, which gives you a class picker and then a UI to interact with an instance of the class you pick. This makes the convenient way to work with different scenarios to have a class for each scenario.
For the original case restricted to accessing static members, for the time being it's good enough to use literal class names.
For the edited case involving instantiation, I'm leaving the instantiation in subclasses and passing instances to a method of the superclass, like this:
class Model {
public static void run( Model m ) {
/* ... */
}
}
class Scenario extends Model {
public static void main( String[] args ) {
Model.run( new Scenario( /*...*/ ) );
}
}
In the future, I'll try to avoid following the lead of some library into territory that conflicts with language features.
You can't override variables, instead, you'll need to provide a method instead, for example...
class Flying {
private final String label = "A Flying Superhero";
String exclamation() {
return "Look! Up in the sky! It’s a bird! It’s a plane! It’s " + getLabel() + "!";
}
public String getLabel() {
return label;
}
}
class Superman extends Flying {
private final String label = "Superman";
#Override
public String getLabel() {
return label;
}
}
class Howard extends Flying {
private final String label = "Howard the Duck";
#Override
public String getLabel() {
return label;
}
}
Subclasses do not inherit static members. In your new example, main can be referred to by Sub like Sub.main(args); but it always belongs to Super. You may even check the stack trace which will confirm it is invoked on Super.
Within an invocation of a static method, get the Class on which the method was invoked (I haven't found anything on this)
This can't be done.
Given a Class, access a static member of that class (possibly with aClass.getDeclaredField?)
This can be done but it's a totally cumbersome way to approach a problem that's extremely simple if you just use regular inheritance.
Given a Class, construct a new instance of that class (possibly with aClass.getConstructors?)
This can be done and is useful from time to time. It is less useful now with Java 8 Supplier, for example SomeClass::new.
Static is the wrong way to approach this kind of problem in Java. Regular inheritance lets you do these things trivially.
class InterfacesExample {
public static void main(String[] args) {
#SuppressWarnings("unchecked") // Arrays#asList
List<Class<? extends Printer>> classes = Arrays.asList(
FruitPrinter.class,
TreePrinter.class
);
for(Class<? extends Printer> cls : classes) {
try {
Constructor<? extends Printer> ctor = cls.getDeclaredConstructor();
Printer p = ctor.newInstance();
p.print();
} catch(Exception e) {
System.err.println(e);
}
}
}
}
interface Printer {
void print();
}
class FruitPrinter implements Printer {
#Override
public void print() {
System.out.println("Apple, Banana, Plum, Pear");
}
}
class TreePrinter implements Printer {
#Override
public void print() {
System.out.println("Oak, Maple, Elm, Willow");
}
}

Is the Java compiler allowed to be flow sensitive for static calls?

Here's a brief example from the JLS section 8.4.8.2.
class Super {
static String greeting() { return "Goodnight"; }
String name() { return "Richard"; }
}
class Sub extends Super {
static String greeting() { return "Hello"; }
String name() { return "Dick"; }
}
class Test {
public static void main(String[] args) {
Super s = new Sub();
System.out.println(s.greeting() + ", " + s.name());
}
}
According to the discussion of the example, the output of running main() will be "Goodnight, Dick". This is because static methods are called based on the static type of the variable/expression they are called on.
Here's my question: Any even moderately flow-sensitive compiler could figure out that the type of any object stored in s at the time of the call must always be Sub, so if the compiler were allowed to use that information, even calling static methods could have some of the feel of dynamic binding. Why is this not allowed? Does Java have the express goal that every compiler produces bytecode that behaves exactly the same or is there some other reason?
In fact here s.greeting()is equivalent to Super.greeting() because s is defined to be Super and static methods do not care about class instances. They're class-wide as you surely know. So it directly makes no sense to call a static method from a class instance. And of course the instance s is a Sub() as you specified, so the non-static method Sub.name() is called.
From Java official tutorials:
You can also refer to static fields with an object reference like
myBike.numberOfBicycles
but this is discouraged because it does not make it clear that they
are class variables.
Allowing static methods to be class-instance wise would only make the code less readable, more arcane and harder to debug without really adding any useful feature.
It is not too java specific. Imagine your "intelligent" compilation with s.getClass().greeting() in:
class A extends Sub {
static String greeting() { return "Allo"; }
}
class B extends Sub {
static String greeting() { return "Brrr"; }
}
Super s = condition? new A() : new B();
assert s.greeting.equals(Sub.greeting()); // If compiler cannot infer condition.
Should the compiler do that across more than one source? Out of libraries, where the source code might not be available.
I rather think the fallacy in java is, that s.greeting() is allowed.
As there is no use for static inheritance, better not invent such a feature.

Singletons, Enums and anonymous inner classes

As you may know, some people are declaring singletons with an Enum of 1 instance, because the JVM guarantees that there will always be a single instance with no concurrency problems to handle...
Thus what about an Enum with multiple instances?
Can we say something like an Enum is a kind of ordered set of singletons sharing a common interface?
Why?
public enum EnumPriceType {
WITH_TAXES {
#Override
public float getPrice(float input) {
return input*1.20f;
}
public String getFormattedPrice(float input) {
return input*1.20f + " €";
}
},
WITHOUT_TAXES {
#Override
public float getPrice(float input) {
return input;
}
},
;
public abstract float getPrice(float input);
public static void main(String[] args) {
WITH_TAXES.getFormattedPrice(33f);
}
}
In this code why this doesn't work:
WITH_TAXES.getFormattedPrice(33f);
What is the interest of declaring a public method if it can't be called without passing through the common interface?
I guess this is why i don't see any syntax to be able to declare an interface just for one of the instances of an Enum.
Edit:
It seems that enum instances are a special kind of anonymous classes.
Thus i understand why you can't call that method.
My question is kinda related to: why can't an anonymous class implement an interface (in addition to the interface it may already implement!)
I totally understand why we CANT do that:
Vehicle veh = new Vehicle() {
public String getName() {
return "toto";
}
};
veh.getName();
(getName here is not an override)
Why i don't understand is why we can't do that with anonymous classes:
Runnable veh = new Vehicle() implements Runnable {
#Override
public void run() {
System.out.println("i run!");
}
};
veh.run();
Or something that would result in the same thing.
Think about it: if you do not use anonymous classes you can absolutely extend the Vehicle class and then make that subclass implement any other interfaces you want...
I'm pretty sure that if it was possible we would be able to call WITH_TAXES.getFormattedPrice(33f) in a typesafe way, since WITH_TAXES would not be a real EnumPriceType but it would but a subclass of EnumPriceType, with its own interface, and by calling WITH_TAXES.getFormattedPrice(33f) with a hardcoded WITH_TAXES, you know at compile that which EnumPriceType child you are calling.
So my question is: are there any reasons why this is not possible? Or it just haven't be done yet?
Your enum is equivalent to the following normal class (in fact, that's pretty much what the compiler turns it into):
public abstract class EnumPriceType {
public static final EnumPriceType WITH_TAXES = new EnumPriceType() {
//getPrice() {...}
//getFormattedPrice() {...}
};
public static final EnumPriceType WITHOUT_TAXES = new EnumPriceType() {
//getPrice() {...}
};
public abstract float getPrice(float input);
public static void main(String[] args) {
WITH_TAXES.getFormattedPrice(33f);
}
}
The getFormattedPrice() method is unavailable on the abstract type, and therefore can't be called from the main method. Consider what would happen if the main method is rewritten to use a local variable:
public static void main(String[] args) {
EnumPriceType foo = EnumPriceType.WITH_TAXES;
foo.getFormattedPrice(33f);
}
This doesn't compile because getFormattedPrice() is not available on the base class. Since the WITH_TAXES instance is an anonymous subclass of EnumPriceType, there's no way you can define the local variable to a type where the getFormattedPrice() method is visible.
As a meta observation, this is a key difference between strongly typed languages such as Java and "duck typed" languages such as Ruby. Ruby will happily invoke the getFormattedPrice() method if happens to be there, regardless of what type of object is held in the foo variable.
As another meta observation, it doesn't make much sense for different constants of the same enum to have different sets methods. If you can't put everything you need as abstract (or concrete) methods on the base enum type, you're probably using the wrong tool to solve the problem.
Add
public String getFormattedPrice(float input) {
return input + " €";
}
outside the overrides as the default implementation. (Next to the declaration of getPrice.) And you are good to go.
You can also have enums implement interfaces, to define what everybody needs to implement.
Thus what about an Enum with multiple instances?
There is no such thing, and your example doesn't demonstrate it. You have an Enum with multiple values. They are all singletons.

How to access a static method via a class reference

class A {
public static void foo() {}
}
class B {
public static void foo() {}
}
I have Class clazz = A.class; or B.class;
How do I access this via "clazz" assuming it might be assigned either 'A' or 'B'
It is only possible to access those methods using reflection. You cannot reference a class directly, only an instance of type Class.
To use reflection to invoke methodname(int a, String b):
Method m = clazz.getMethod("methodname", Integer.class, String.class);
m.invoke(null, 1, "Hello World!");
See Class.getMethod() and Method.invoke()
You may want to think about your design again, to avoid the need to dynamically call static methods.
You can invoke a static method via reflection like this :
Method method = clazz.getMethod("methodname", argstype);
Object o = method.invoke(null, args);
Where argstype is an array of arguments type and args is an array of parameters for the call. More informations on the following links :
getMethod()
invoke()
In your case, something like this should work :
Method method = clazz.getMethod("foo", null);
method.invoke(null, null); // foo returns nothing
You cannot access static methods without an explicit reference to the class.
No inheritance here, sorry, so you must either do:
A.foo()
or
B.foo()
If you really need it, you will have to do a check:
Object o = .... // eith an A or B instance.
if( o instanceof A ) {
A.foo()
} else {
B.foo()
}
But why don't you just make those functions instance functions, and let them implement an interface?
Okey, you have a class object. Then do:
Class c = ...;
c.getMethod("foo").invoke(null); // null to invoke static methods
According to my lack of knowledge the need for the requested construct is given by the fact that an interface doesn't offer the possibility of static abstract methods. Here is an example:
public enum Cheese implements Yumy {
GOUDA(49),
ESROM(40),
HWARTI(38);
private int percentage;
private Cheese(int fat100) {...} constructor
public void yamyam() {...} // as in Yumy
public static Cheese getByFat(int fat100) {...} // no chance to be part
of interface
};
I hope this isn't making too many assumptions or deviating too far from your question, but if your two classes share a common supertype and creating an instance is tolerable then you can:
Implement a common interface
Create an instance of the object via myClass.newInstance() (class must have an empty constructor)
Call the static method from the instance object.
interface Foo {
void foo();
}
class A implements Foo {...}
class B implements Foo {...}
<T extends Foo> public void something(Class<T> clazz) {
T myInstance = clazz.newInstance();
myInstance.foo();
}
...
something(A.class);
It's a little bizarre but in my case it proved to be useful, and I began by asking the very same question that you did.

Categories

Resources