Using Java generics while inheriting from an abstract class - java

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() {}
}

Related

Java generics with multiple enums implementing an interface

I want to pass a list of enum classes to a method, where all of the enums implement a common interface, and have the method return one of the enum values.
Looking at Java Generics Wildcarding With Multiple Classes, it seems that
public class Main
{
interface Foo {}
enum First implements Foo {
A, B, C;
}
enum Second implements Foo {
X, Y, Z;
}
interface Bar {}
enum Third implements Bar {
M, N, P;
}
enum Fourth implements Bar {
A, X, Z;
}
public static <I, T extends Enum<?> & I>
I enumVarArgs(Class<? extends T>... classes)
{
// Do stuff and return some instance of T
return null;
}
public static void main(String[] args) {
Foo foo = enumVarArgs(First.class,
Second.class);
Bar bar = enumVarArgs(Third.class,
Fourth.class);
}
}
should do what I want. However, this fails to compile under Java 10:
[ERROR] /me/test/src/main/java/test/Main.java:[17,42] error: unexpected type
required: class
found: type parameter I
where I,T are type-variables:
I extends Object declared in method <I,T>enumVarArgs(Class<? extends T>...)
T extends Enum<?>,I declared in method <I,T>enumVarArgs(Class<? extends T>...)
[INFO] 1 error
From the error message, I am guessing that Java wants me to do something like T extends Enum<?> & Serializable, where I pass an actual interface, rather than a type parameter. However, I need the API to be general so that I remains a generic parameter.
Is there a syntax that makes this work?
If it matters, we are using Java 10.
If interfaces are your design, then you can make the two interfaces extend a marker interface:
interface FooBar{}
interface Foo extends FooBar {}
interface Bar extends FooBar {}
And you can use this marker interface:
public static <T extends Enum<?> & FooBar>
FooBar enumVarArgs(Class<? extends T>... classes) {
return null;
}
I think what you need is:
interface OnlyImpelents<T> {}
interface Foo extends OnlyImpelents<Foo> {}
interface Bar extends OnlyImpelents<Bar> {}
static <T extends Enum<?> & OnlyImpelents<? super T>> T enumVarArgs(T... values) {
return values[0];
}
public static void main(String[] args) {
Foo foo = enumVarArgs(First.A, Second.X);
}
The marker interface OnlyImpelents<T> prevents any class from implementing both Foo and Bar
The only way to get enum values from a enum class is via reflection, which doesn't need to have a static type. Personally I think this is not a good object-oriented design, using T... as args should be better

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() {
}
}

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.

Using a generic type of a subclass within it's abstract superclass?

Within my code a have the following abstract superclass
public abstract class AbstractClass<Type extends A> {...}
and some child classes like
public class ChildClassA extends AbstractClass<GenericTypeA> {...}
public class ChildClassB extends AbstractClass<GenericTypeB> {...}
I'm searching for an elegant way how I can use the generic type of the child classes (GenericTypeA, GenericTypeB, ...) inside the abstract class in a generic way.
To solve this problem I currently defined the method
protected abstract Class<Type> getGenericTypeClass();
in my abstract class and implemented the method
#Override
protected Class<GenericType> getGenericTypeClass() {
return GenericType.class;
}
in every child class.
Is it possible to get the generic type of the child classes in my abstract class without implementing this helper method?
BR,
Markus
I think its possible. I saw this was being used in the DAO patterns along with generics. e.g.
Consider classes:
public class A {}
public class B extends A {}
And your generic class:
import java.lang.reflect.ParameterizedType;
public abstract class Test<T extends A> {
private Class<T> theType;
public Test() {
theType = (Class<T>) (
(ParameterizedType) getClass().getGenericSuperclass())
.getActualTypeArguments()[0];
}
// this method will always return the type that extends class "A"
public Class<T> getTheType() {
return theType;
}
public void printType() {
Class<T> clazz = getTheType();
System.out.println(clazz);
}
}
You can have a class Test1 that extends Test with class B (it extends A)
public class Test1 extends Test<B> {
public static void main(String[] args) {
Test1 t = new Test1();
Class<B> clazz = t.getTheType();
System.out.println(clazz); // will print 'class B'
System.out.println(printType()); // will print 'class B'
}
}
I'm not sure I fully understand your question - <Type> is the generic type of the subclass, even when it's being expressed in the abstract class. For example, if your abstract superclass defines a method:
public void augment(Type entity) {
...
}
and you instantiate a ChildClassA, you'll only be able to call augment with an instance of GenericTypeA.
Now if you want a class literal, then you'll need to provide the method as you indicated. But if you just want the generic parameter, you don't need to do anything special.

Java erasure error with unrelated generic in method

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.

Categories