Java erasure error with unrelated generic in method - java

I've read the other questions related to erasures, but I'm still not clear why I get the compile error in the class below. The other questions involve methods that actually use the generic type, whereas I'm just trying to implement a method using the exact same signature. Can anyone explain?
Compile error -> name clash: bar(java.util.Set) in test.Baz and bar(java.util.Set) in test.Foo have the same erasure, yet neither overrides the other
import java.util.Set;
public class test {
public interface Foo<T> {
public void bar(Set<String> s);
}
public abstract class Baz implements Foo {
public void bar(Set<String> s) {}
}
}

Did you intend for Baz to implement Foo<String> or to implement Foo<T> or to implement Foo? What you typed was the last of those, but this means that Bar implements the "ungenerified" Foo. The weird thing is that this turns off generics in Foo's definition entirely, not just the generics that have to do with T.
That means that inside Baz, the method Foo.bar takes a parameter of just Set, not Set<String>.
You want either:
public abstract class Baz implements Foo {
public void bar(Set s) {}
}
or
public abstract class Baz<T> implements Foo<T> {
public void bar(Set<String> s) {}
}
or
public abstract class Baz implements Foo<Void> {
public void bar(Set<String> s) {}
}
Depending on what you're trying to do.

I think you need to change this:
public abstract class Baz implements Foo {
to this:
public abstract class Baz implements Foo<T> {
That way you properly override function Foo.

Related

generics compilation error: type argument is not within bounds of type-variable S

Here's a simplified version of the object model that I am working on.
public class GenericsTest {
public interface FooInterface {
public void foo();
}
public class Bar implements FooInterface {
public void foo() {}
}
public interface GenericInterface <T> {
public T func1();
}
public class Service implements GenericInterface<Bar> {
#Override
public Bar func1() {
return null;
}
}
public class GenericBar <S extends GenericInterface<FooInterface>> {
public S s;
public GenericBar() {}
}
public static void main(String[] args) {
GenericBar<Service> serviceGenericBar; // <-- compilation error at this line
<... more code ...>
}
}
Compiler Error: type argument GenericsTest.Service is not within bounds of type-variable S
IDE (intellij) shows some more details on the error: Type parameter 'GenericsTest.Service' is not within its bound; should implement GenericsTest.GenericInterface<GenericTests.FooInterface>
Service class is implementing the GenericInterface. I have looked at few other SO questions with the same error but they don't offer clues for this particular scenario. Any ideas on how to fix this?
The problem is exactly what two compilers have told you: type Service is not within the bounds that type GenericBar requires of its type parameter, S. Specifically, GenericBar requires the S parameter of its realizations to be bound to a type that extends GenericInterface<FooInterface>. Service does not satisfy that requirement.
Service implements GenericInterface<Bar>, which is neither GenericInterface<FooInterface> nor an extension of that type, the fact that Bar implements FooInterface notwithstanding. You cannot assign a List<String> to a variable of type List<Object>, either, for basically the same reason.
You can resolve the compilation error by modifying the definition of class GenericBar like so:
public class GenericBar <S extends GenericInterface<? extends FooInterface>> {
public S s;
public GenericBar() {}
}
Whether this is what you actually want to use is an entirely different question, which only you can answer.
When you change Service to implement GenericInterface the code would compile.
public class Service implements GenericInterface<FooInterface> {
#Override
public Bar func1() {
return null;
}
}
Or if you prefer to limit Service to base only on Bar you could change GenericBar so it will become more generic:
public class Service implements GenericInterface<Bar> {
#Override
public Bar func1() {
return null;
}
}
public class GenericBar<S extends GenericInterface<? extends FooInterface>> {
public S s;
public GenericBar() {
}
}

Using Java generics while inheriting from an abstract class

I want to extends a generic typ from an abstract class:
abstract class Foo {
public void doStuff() {}
}
public class Bar<T extends Foo> {
public void doFooBar(Foo param) {
/* Code here */
param.doStuff();
}
}
In other words: A class Bar should created with an generic type, which extends from Foo. Bar should be able to have methods, where Foo is an parameter (because the generic type extends from Foo, so it should be possible).
Using instead of Foo a predefined class like String oder BigDecimal, it works so far. But in my case, Bar complains about not finding class Foo.
I'm using Eclipse.
Did I miss something?
SOLUTION:
Foo has to be a public modifier, than it works. I expected, that abstract class are public by default (like Interfaces). Eclipse doesn't complain about the missing modifier.
abstract class Foo() {
...
is a syntax error.
Correcting that to
abstract class Foo {
...
results in no compilation errors. Also, note that it should probably be
public class Bar<T extends Foo> {
public void doFooBar(T param) {
// ----------------------^
// Type parameter here
/* Code here */
}
}
Remove the () parantheses after classname Foo
Here is modified code:
abstract class Foo {
public void doStuff() {}
}

Is there any way to avoid casting this type?

Consider the following class that defines and implements the Foo interface:
public class MyClass {
public Foo getFoo() {
return new FooImpl();
}
public void fooMethod(Foo foo) {
final fooImpl = (FooImpl) foo;
fooImpl.hiddenMethod();
}
public interface Foo {
void doSomething();
}
private class FooImpl implements Foo {
public void doSomething();
void hiddenMethod() {
}
}
}
Outside classes will call MyClass.getFoo() to obtain a Foo object and may pass it back to fooMethod(). fooMethod() expects the FooImpl implementation of Foo and casts Foo to FooImpl so it can call package-private method hiddenMethod().
My question is, I'm not crazy about casting Foo to FooImpl. Is there another pattern I can use to do the same thing?
Thanks in advance...
The problem here is that you are implicitly violating the principal of encapsulation. You have a method in your class which depends on the implementation and is therefore not part of the Foo interface. This is a violation of OO principals, this cast is only the tip of the iceberg. What if you want to design a new Foo implementation class which does not have the methods you want to call?
You should redesign your code so that you can achieve this calling only methods from the Foo interface.
You could add a hiddenMethod method to the Foo interface
public interface Foo {
...
void hiddenMethod();
}
Since an interface is a contract for supported operations, you don't need to (shouldnt?) cast the object to access methods outside of the interface
You have to downcast.
Do in this way
public void fooMethod(Foo foo) {
if(foo instanceof FooImpl){
final FooImpl fooImpl = (FooImpl) foo;
fooImpl.hiddenMethod();
}
}
Super type can't be downcast without an explicit downcast. Be sure to check it before downcast using instanceof operator.
--EDIT--
Do one more thing if you want to avoid the casting. Add hiddenMethod() in Foo interface also.
public interface Foo {
void doSomething();
void hiddenMethod();
}

How to return the generic type of an object inside generic class?

I'd like to write a generic service that should work with an object of a specific type. When I write custom implementation of that service, I'd like to object to be variable. Therefore I wanted to override the method that creates that object.
But it won't work. Is it impossible in java to achieve the following?
class MyService<T extends Foo> {
//Type mismatch: cannot convert from Foo to T
public T createObject() {
return new Foo();
}
public void run() {
T t = createObject();
//work with the object
}
}
class Bar extends Foo;
class CustomService<Bar> {
#Override
public Bar createObject() {
return new Bar();
}
}
class NewArrayList extends ArrayList {
}
abstract class MyService<T> {
public abstract T createObject();
public void run() {
T t = createObject();
//work with the object
}
}
class CustomService extends MyService<NewArrayList> {
#Override
public NewArrayList createObject() {
return new NewArrayList();
}
}
The issue is that you are providing a default implementation which returns Foo. That implementation is not appropriate for subclasses and there is no way to force the subclass to override.
You should have MyService<T> and an abstract T createObject(). For Foo make a Foo-specific subclass FooService<Foo>.
Correct; you can't do that. Your T generic parameter stands for "some class which is a subclass of Foo" (where a class is a subclass of itself). You can't assume that it is Foo exactly, since it might be a class that extends Foo.
Think about it: if you had a class Bar extends Foo and you did:
MyService<Bar> service = ...
Bar myBar = createObject();
then your code would create a Foo and try to downcast it to a Bar — resulting in a ClassCastException. The whole point of generics is to avoid incorrect casts and their resulting exceptions.

Why is a generic argument that "extends" something not allowed in derived function, but generic return type is?

I would like to override a generic function in a subclass, as follows:
Superclass:
public abstract class Metric {
public abstract <T extends Foo> T precompute(); // valid syntax
public abstract <T extends Foo> void distance(T arg); // valid syntax
public static class Foo {}
}
Subclass:
public class MetricDefault extends Metric {
#Override
public Bar precompute() { return new Bar(); } // Valid - return type extends Foo
#Override
public void distance(Bar arg) {} // Invalid ??? - argument type extends foo
public static class Bar extends Metric.Foo {}
}
The generic function, when the generic type is the return value of the function, is valid Java code and builds successfully.
Changing only the placement of the generic type - making it the argument to the function, rather than the return type - and it becomes invalid Java code.
Why is the latter case invalid? What can I do to implement this functionality?
The method declaration
public abstract <T extends Foo> void distance(T arg);
means that the method takes an T argument, and the caller can decide which subtype of Foo to use as T.
The method declaration
public abstract <T extends Foo> T precompute();
means that the method returns some object of type T, and the caller can decide which subtype of Foo to use as T.
This last method can't really be implemented (apart from returning null), since your method does not really know what an object to produce here.
In your concrete class you try to override the methods - for my understanding you shouldn't be allowed for both of them, but maybe the compiler is a bit more relaxed than me.
I think what you really want is something like what Overbose posted.
public abstract class Metric<T extends Foo> {
public abstract T precompute(); // valid syntax
public abstract void distance(T arg); // valid syntax
public class Foo {}
}
then if as I understood Bar extends Foo:
public class MetricDefault extends Metric<Bar> {
#Override
public Bar precompute() { return new Bar(); }
#Override
public void distance(Bar arg){}
public class Bar extends Foo {}
}
Because the signature of distance(T) in the superclass specifies that someone that has a reference to a Metric should be allowed to pass any type that extends Foo as an argument.
The first method works fine because anyone referring to Metric is already prepared to handle the return type of Bar, since the signature refers to a parent type of Bar.
For this to work, you need to make T a parameter of the type, rather than of the methods.
The way you are attempting to do it, your new method does not override the abstract base method. After type erasure is performed, it amounts to the following code:
public abstract class Metric {
public abstract Foo precompute(); // valid syntax
public abstract void distance(Foo arg); // valid syntax
public class Foo {}
}
public class MetricDefault extends Metric {
public Bar precompute() { return new Bar(); } // Valid - return type extends Foo
public void distance(Bar arg) {} // Signature not compatible - does not override distance(Foo)
public class Bar extends Foo {}
}
As #Paŭlo Ebermann mentioned, the following overriding should not be legal
<T extends Foo>
T precompute();
Bar precompute()
Rules in JLSv3 #8.4.8.3 and #8.4.5 forbid this overriding. Javac should have reported error on it.
There are 2 possible explanations
the spec omitted an intuitive&obvious rule: the "is return-type-substitutable" relation should be transitive. T->Foo->Bar, Bar overriding T is legal.
javac is buggy. It somehow mistakes Foo as the return type of method#1 when validating the overriding.
The 1st explanation is quite implausible. If the (nastily defined) relation is transitive, it's too hard to check if it holds for 2 arbitrary types. So the 2nd explanation is probably truer.

Categories