correct java syntax for generics with extends - java

this is a piece of code i'm struggling with.
public class Channel<T extends Something>{
public Channel(){}
public void method(T something){}
}
public class Manager{
private static ArrayList<Channel<? extends Something>> channels
= new ArrayList<Channel<? extends Something>>();
public static <T extends Something> void OtherMethod(T foo){
for(Channel<? extends Something> c : channels)
c.method(foo); // this does not work
}
}
The line that does not work gives me compiler error:
The method method(capture#1-of ? extends Something) in the type Channel<capture#1-of ? extends Something> is not applicable for the arguments (T)
I don't understand this error. If I remove all the generics in Manager class it is working but type unsafe.
How should I do this in correct Java?

You need a type parameter for your method public <T extends Something> void method(T foo)
public class Channel<T extends Something> {
public Channel() {
}
public <T extends Something> void method(T foo) {
}
}
public class Manager {
private static ArrayList<Channel<? extends Something>> channels = new ArrayList<Channel<? extends Something>>();
public static <T extends Something> void OtherMethod(T foo) {
for (Channel<? extends Something> c : channels)
c.method(foo); // this does not work
}
}

That's inherently unsafe.
What happens if you add a Channel<MyThing> to the list, then call OtherMethod() with a YourThing?
You should make the entire class generic (and make the members non-static), and use the same T for the channels and the parameter.

Related

Interface implementation propagation in Java generics

I have the following code (simplified, to show the problem core):
public interface IElement {}
public interface IDataSet<E extends IElement> {}
public interface IPropertyTranslator<D extends IDataSet<? super E>, E extends IElement> {}
public interface IElementTranslator<D extends IDataSet<?>> {}
public class AnimalElement implements IElement {}
public class AnimalDataSet implements IDataSet<AnimalElement> {}
public class AnimalPropertyTranslator implements IPropertyTranslator<AnimalDataSet, AnimalElement> {}
public class UniversalPropertyTranslator implements IPropertyTranslator<IDataSet<IElement>, IElement> {}
public class ElementTranslator<D extends IDataSet<? super E>, E extends IElement> implements IElementTranslator<D> {
public Collection<IPropertyTranslator<? super D, ? super E>> propertyTranslators = new HashSet<>();
}
public class Demo {
public static void demo() {
ElementTranslator<AnimalDataSet, AnimalElement> animalElementTranslator = new ElementTranslator<>();
animalElementTranslator.propertyTranslators.add(new AnimalPropertyTranslator());
animalElementTranslator.propertyTranslators.add(new UniversalPropertyTranslator());
}
}
Unfortunately, the last line of the demo method yields the following error: The method add(IPropertyTranslator<? super AnimalDataSet,? super AnimalElement>) in the type Collection<IPropertyTranslator<? super AnimalDataSet,? super AnimalElement>> is not applicable for the arguments (UniversalPropertyTranslator). Through random trials I discovered, that the problem is probably connected with the <D extends IDataSet<? super E>, E extends IElement> expression, although I still do not know how to fix it.
In the meantime the following variantion of the code works perfectly:
public interface IDataSet {}
public interface IPropertyTranslator<D extends IDataSet> {}
public interface IElementTranslator<D extends IDataSet> {}
public class AnimalDataSet implements IDataSet {}
public class AnimalPropertyTranslator implements IPropertyTranslator<AnimalDataSet> {}
public class UniversalPropertyTranslator implements IPropertyTranslator<IDataSet> {}
public class ElementTranslator<D extends IDataSet> implements IElementTranslator<D> {
public Collection<IPropertyTranslator<? super D>> propertyTranslators = new HashSet<>();
}
public class Demo {
public static void demo() {
ElementTranslator<AnimalDataSet> animalElementTranslator = new ElementTranslator<>();
animalElementTranslator.propertyTranslators.add(new AnimalPropertyTranslator());
animalElementTranslator.propertyTranslators.add(new UniversalPropertyTranslator());
}
}
I do not understand why the second generic part of the interface causes the code to behave differently.
The solution is slightly related to the "Producer Extends, Consumer Super" rule. In the problem code one need to change the following headers into those below:
public interface IPropertyTranslator<D extends IDataSet<? extends E>, E extends IElement> {}
public class UniversalPropertyTranslator implements IPropertyTranslator<IDataSet<? extends IElement>, IElement> {}
and everything would be working just fine.

Java - Getting a more specific type than "Class<?>" for a parameterized generic class

I have a base interface that is parameterized using a type R extending the same base interface :
public interface IWidget<R extends IWidget<R>> {}
Then another interface is parameterized the same way :
public interface IWidgetManager<R extends IWidget<R>> {}
Finally, a class implements the second interface. This class will receive the IWidget implementation class when it will be declared :
public class MyWidgetManager<R extends IWidget<R>> implements IWidgetManager<R> {}
My question :
What is the more specific type that we can use to specify MyWidgetManager?
Class<?> works, of course :
public Class<?> ok() {
return MyWidgetManager.class;
}
But it is very generic and I'd like something more specific...
Those attempts don't compile:
public Class<? extends IWidgetManager<?>> fails() {
return MyWidgetManager.class;
}
==> Type mismatch: cannot convert from Class<MyWidgetManager> to Class<? extends IWidgetManager<?>>
public <R extends IWidget<?>> Class<? extends IWidgetManager<R>> fails() {
return MyWidgetManager.class;
}
==> Type mismatch: cannot convert from Class<MyWidgetManager> to Class<? extends IWidgetManager<R>>
public <R extends IWidget<R>> Class<? extends IWidgetManager<R>> fails() {
return MyWidgetManager.class;
}
==> Type mismatch: cannot convert from Class<MyWidgetManager> to Class<? extends IWidgetManager<R>>
public Class<? extends IWidgetManager<? extends IWidget<?>>> fails() {
return MyWidgetManager.class;
}
==> Type mismatch: cannot convert from Class<MyWidgetManager> to Class<? extends IWidgetManager<? extends IWidget<?>>>
Is there any way I can get a type more specific than Class<?> for MyWidgetManager.class?
UPDATE :
I changed the name of my interfaces. The final class is not a Widget itself, which wasn't clear in my original question... Sorry for the confusion.
UPDATE 2 :
Things are way easier when using concrete types, indeed.
This is really specific to my current situation, but I think I'll fix my "problem" by transforming MyWidgetManager<R extends IWidget<R>> implements IWidgetManager<R> into a WidgetManagerBase that doesn't implement anything. Then provide a default implementation with a concrete Widget class. Finally, the get method could be overriden easily (which is my main goal from the start, by the way!). So :
public interface IWidget<R extends IWidget<?>> {}
public interface IWidgetManager<R extends IWidget<R>> {}
public class WidgetManagerBase {}
// Default implementation
public class WidgetA implements IWidget<WidgetA> {}
public class AWidgetManager extends WidgetManagerBase implements IWidgetManager<WidgetA> {}
// default get method
public Class<? extends IWidgetManager<?>> getWidgetManagerClass() {
return AWidgetManager.class;
}
// The default get method then can be overriden with :
public class WidgetB implements IWidget<WidgetB> {}
public class BWidgetManager extends WidgetManagerBase implements IWidgetManager<WidgetB> {}
#Override
public Class<? extends IWidgetManager<?>> getWidgetManagerClass() {
return BWidgetManager.class;
}
Because of Java Type Erasure the most specific match for MyWidget.class is Class<? extends IWidget>:
public Class<? extends IWidget> test() {
return MyWidget.class;
}
If you want to be even more specific than you should extend MyWidget with concrete type parameters:
public class ConcreteBaseWidget implements IBaseWidget<ConcreteBaseWidget> {
}
public class ConcreteWidget extends MyWidget<ConcreteBaseWidget> {
}
And then all these methods will work:
public Class<? extends IWidget<? extends IBaseWidget<? extends IBaseWidget<?>>>> test1() {
return ConcreteWidget.class;
}
public Class<? extends IWidget<? extends IBaseWidget<ConcreteBaseWidget>>> test2() {
return ConcreteWidget.class;
}
public Class<? extends IWidget<? extends ConcreteBaseWidget>> test3() {
return ConcreteWidget.class;
}
I really think you're just looking for
public interface IBaseWidget<R extends IBaseWidget<R>> {}
and
public interface IWidget<R extends IWidget<R>> extends IBaseWidget<R> {} //not sure about this one.
and
public class MyWidget implements IWidget<MyWidget> {}
That way you can see MyWidget.class as Class<R>.
Is this what you are looking for, or do I misinterpret your intentions?
EDIT:
In that case,
public interface IWidgetManager<R extends IWidget<R>> {}
public class MyWidgetManager<R extends IWidget<R>> implements IWidgetManager<R> {}
could be replaced with
public interface IWidgetManager<R extends IWidget<R>, WM extends IWidgetManager<R, WM>> {}
public class MyWidgetManager<R extends IWidget<R>> implements IWidgetManager<R, MyWidgetManager> {}
because then you will be able to access MyWidgetManager.class as Class<WM>.

Generics and wildcards in static values. It says that is the same class but doesnt compile

public interface Moo<T> {
T getValue();
}
public class Bar<T> {
}
public class Foo<T extends Moo<Long>> {
private static Foo<?> foo;
private Bar<T> bar;
public Foo(Bar<T> bar) {
this.bar = bar;
}
//getters and setters
public void barfoo(List<T> list) {
System.out.println(list);
}
public void foobar(T t) {
System.out.println(t.getValue());
}
public void other() {
List<? extends Moo<Long>> somelist = null;
foo.barfoo(somelist);
}
}
It generates a error, says that I can't compile because somelist can't go in that function. Says "Required ? extends Moo<Long> found ? extends Moo<Long>"
I don't know why this happens, either how to solve it.
Just for clarification, let's create an implementation of the Moo interface:
public class MooImpl implements Moo<Long> {
#Override
public Long getValue() {
return null;
}
}
Getting back to your class, in the eyes of the compiler, the static member of type Foo has an unknown generic parameter, which means that at Runtime, this parameter can be replaced with anything. We can easily instantiate the static member with a Foo instance, parameterized by MooImpl (we're allowed to do so, because MooImpl extends Moo<Long>. We say that MooImpl is a known subtype of Moo<Long> at Compile-time.
Now let's take a look on the other() method. At Runtime, the ? extends Moo<Long> may result in different type than the T, which is why the compiler gives you an error. It does so, because ? extends Moo<Long> stands for an unknown subtype of Moo<Long>. This way it differs with the known subtype (MooImpl).
In order to make it work, we can change the parameter of the barfoo() method to List<? extends Moo<Long>>.
public class Foo<T extends Moo<Long>> {
private static Foo<?> foo = new Foo<MooImpl>(new Bar<MooImpl>());
private Bar<T> bar;
public Foo(Bar<T> bar) {
this.bar = bar;
}
public void barfoo(List<? extends Moo<Long>> list) {
System.out.println(list);
}
public void foobar(T t) {
System.out.println(t.getValue());
}
public void other() {
List<? extends Moo<Long>> somelist = null;
foo.barfoo(somelist);
}
}
Any instance of your class Foo will be created with a concrete type T that is extending Moo<Long>. The method barfoo requires an argument of type List<T> where this T is the exact same type from instantiation.
Now you call this method with a List<? extends Moo<Long>>. That ? extends Moo<Long> is not the same as your type T. It could be any other subtype of Moo<Long>. So the compiler must reject this method call.

Generic error: type ... is not applicable for the arguments

Ok. Let's say I have following small Interface:
public interface MyInterface {
void interfaceMethod();
}
and a class which implements this interface:
public class GenericsTest implements MyInterface {
#Override
public void interfaceMethod() {
// do something
}
}
That's simple!
Now I have also another class which use a generic type <T extends MyInterface>:
public class AnotherClass<T extends MyInterface> {
public void doSomethingWith(T obj) {
System.out.println(obj.toString());
}
}
And now the point which I don't understand. If I want call the AnotherClass.doSomethingWith(T) method like in the following code snippet (this class is wrong; please see my edit below):
public class ClassWithError {
public ClassWithError(AnotherClass<? extends MyInterface> another) {
another.doSomethingWith(another);
}
}
I get following error:
The method doSomethingWith(capture#1-of ? extends MyInterface) in the type
AnotherClass<capture#1-of ? extends MyInterface> is not applicable for the
arguments (AnotherClass<capture#2-of ? extends MyInterface>)
Why That?
EDIT
Ohhhh nooo! My sample is wrong! ... grrrrrr ... SORRY!!
The ClassWithError must be right:
public class ClassWithError {
public ClassWithError(AnotherClass<? extends MyInterface> another, GenericsTest test) {
another.doSomethingWith(test);
}
}
And then the error is:
The method doSomethingWith(capture#1-of ? extends MyInterface) in the type
AnotherClass<capture#1-of ? extends MyInterface> is not applicable for the
arguments (GenericsTest)
AnotherClass#doSomethingWith is waiting for a parameter of type T, i.e. a subtype of MyInterface. In ClassWithError, you're passing an instance of AnotherClass, which does not fulfil this contract.
Either change doSomethingWith signature to (example):
public void doSomethingWith(AnotherClass<?> obj)
Or change body of ClassWithError to (example):
public ClassWithError(AnotherClass<GenericsTest> another) {
GenericsTest instance = /* ... */;
another.doSomethingWith(instance);
}
EDIT
With your new snippet, parameterizing your constructor could be a generic solution:
public class ClassWithError {
public <T extends MyInterface> ClassWithError(AnotherClass<T> another, T test) {
another.doSomethingWith(test);
}
}
If you need to be sure T is a GenericsTest, then use:
public class ClassWithError {
public <T extends GenericsTest> ClassWithError(AnotherClass<T> another, T test) {
another.doSomethingWith(test);
}
}
Or even simply:
public class ClassWithError {
public ClassWithError(AnotherClass<GenericsTest> another, GenericsTest test) {
another.doSomethingWith(test);
}
}
You attempted to use an upper bound generic type outside the scope of a generic type declaration. It's a little difficult to explain without seeing it and it's possible my terminology may be a bit off.
How would the compiler know what generic type AnotherClass<? extends MyInterface> actually is?
public class ClassWithError {
public ClassWithError(AnotherClass<? extends MyInterface> another, GenericsTest test) {
another.doSomethingWith(test);
}
}
You have to capture that generic type somewhere, or specify it explicitly.
Either:
public class ClassWithError<T extends MyInterface> {
public ClassWithError(AnotherClass<T> another, GenericsTest test) {
another.doSomethingWith(test);
}
}
or
public class ClassWithError {
public ClassWithError(AnotherClass<MyInterface> another, GenericsTest test) {
another.doSomethingWith(test);
}
}
please change your AnotherClass like below code.
public class AnotherClass<T extends MyInterfacee> {
public void doSomethingWith(AnotherClass<? extends MyInterfacee> another) {
System.out.println(another.toString());
}
}
thanks.

Java generics static type inference

I do have an abstract class with an delegation interface defined:
public abstract class MyAbstractClass extends AsyncLoader {
public interface MyAbstractClassDelegate<M> {
//The parameter in this method should be the concrete subtype of MyAbstractClass
public M performThisCall(MyAbstractClass concreteSubclassOfAbstractClass);
}
private MyAbstractClassLoaderDelegate delegate;
...
}
The Problem is, I do not want the delegate parameter to be MyAbstractClass, instead it should be the concrete subclass. Why? Because the implementation of the delegate needs the concrete subclass for further handling and I don't want to cast it...
I know I could define an Interface in each subclass, but it'll look the same in every subclass except for the parameter type
EDIT
Here is the perfect solution solving exactly what I wanted. Great thanks!
public abstract class MyAbstractClass {
public interface MyAbstractClassDelegate<M, Subtype extends MyAbstractClass> {
public M myMethod(Subtype t);
}
}
Is this possible with java 6 and if yes - how?
My solution would be:
public final class Example<T extends Example<T>> {
public interface Interface<M, Subtype extends Interface<M, Subtype>> {
public M myMethod(Subtype t);
}
}
You have no access to the generic from the outer class inside the interface (because the interface is static) so you have to declare it again.
If you use your interface you get something like this:
private static class Impl1 implements Interface<String, Impl1> {
#Override
public String myMethod(final Impl1 t) {
return null;
}
}
I don't know if it will help but here is my complete example:
public final class Example<M, T extends Example.Delegate<M, T>> {
public interface Delegate<M, Subtype extends Delegate<M, Subtype>> {
public M myMethod(Subtype t);
}
private T delegate;
private static class Impl1 implements Delegate<String, Impl1> {
#Override
public String myMethod(final Impl1 t) {
return null;
}
}
public static void main(String[] args) {
Example<String, Impl1> example = new Example<>();
example.delegate = new Impl1();
example.delegate.myMethod(example.delegate); //works but whout?
}
}
What you could do is to give your abstract class a type parameter with the concrete subclass, similar to the way Java's Enum does it.
Something along the lines of this:
public abstract class MyAbstractClass<S extends MyAbstractClass<S>> extends AsyncLoader {
public interface MyAbstractClassDelegate<M, S> {
public M performThisCall(S concreteSubclassOfAbstractClass);
}
...

Categories