I have a method to add implementing class' objects against interface class and I want to make this as a generic one.
The implementing class also extends a class X
public abstract class X<T>{...}
public interface InterfaceA{...}
public class A extends X implements InterfaceA{...}
now, currently my method is:
public <S, <T extends X<S>> void add(Class<S> clazz, T object){...}
But I have no use of type parameter on X, it is just for the above method. Is there a way I could have X without type parameter and still have compile-time validation in method 'add' please?
Thanks
EDIT:
I think my question is not clear. Please look at the below example code:
public interface I {}
public abstract class X {}
public class A extends X implements I {}
public class B implements I {}
public class C extends X {}
public class Main {
public static void main(String[] args) {
add(I.class, new A()); // uses first method
add(I.class, new B()); // uses second method
add(I.class, new C()); // uses first method
}
public static <P, T extends P> void add(Class<P> c, T object) {} //No
public static <P, T extends X> void add(Class<P> c, T object) {} //No
}
I need an 'add' method that just accepts A's instance and not B's not C's.
Both the above method signature don't fulfill my requirement
If you don't care about the type parameter of X, just make it Object:
public class A extends X<Object> implements InterfaceA{...}
So the method will work with anything.
I believe you can remove the type on X and still get a compile-time error for add in the following manner. Now, of course, a little more context will be more helpful if this doesn't meet your requirement.
public abstract class X {
}
public class A<T> extends X implements InterfaceA {
public <S, M extends X> void add(Class<S> clazz, M object){
}
public void abc() {
Class<String> clazz = String.class;
this.add(clazz, new B());//This should throw compilation error
}
}
public class B implements InterfaceA {
}
Following is my code
class A<B2 extends B, A2 extends A<B2, A2>> {
C<B2, A2> c;
void test() {
c.acceptParameterOfTypeA(this);
}
}
class B {
}
class C<B2 extends B, A2 extends A<B2, A2>> {
void acceptParameterOfTypeA(A2 a) {
}
}
The error occurs at c.acceptParameterOfTypeA(this);.
The error is
The method acceptParameterOfTypeA(A2) in the type C is not
applicable for the arguments (A)
From what I see, the method acceptParameterOfTypeA expects a parameter of type A, and this at the line giving the error is of type A.
What am I doing wrong? How to fix this problem?
If its important, I'm using Java8
I will again rename your classes, so that everything is more readable. So, let's have:
public class First<T extends Second, U extends First<T, U>> {
Third<T, U> c;
void test() {
c.acceptParameterOfTypeA(this);
}
}
class Second {
}
public class Third<X extends Second, Y extends First<X, Y>> {
void acceptParameterOfTypeA(Y a) {
}
}
From the definition of the c member (Third<T, U>), we can conclude that c will expose a method with this signature:
void acceptParameterOfTypeA(U a) { .. }
What is U? U is a sub-type of First<T, U>.
But if U can be substituted with First after type-erasure, this will mean that First extends First<T, First>, which is not true, because U stands for sub-type of First, which is parameterized with some concrete sub-types of Second and First.
In order to get to U, you can apply the so-called Get This approach.
First, since you need U, which is a sub-type of First, but can't get it from First, you can introduce an abstract method that returns it:
abstract class First<T extends Second, U extends First<T, U>> {
Third<T, U> c;
void test() {
c.acceptParameterOfTypeA(getU());
}
abstract U getU();
}
Then, implement a sample sub-class of First, called Fourth, which extends First with some concrete types for T and U, for example:
class Fourth extends First<Second, Fourth> {
Fourth getU() {
return this;
}
}
In the getU() method, just do return this; as this will return the correct substitute for U in the super-class.
More info:
What is the "getThis" trick?
Strategy Pattern with Generics
Simply put, c.acceptParameterOfTypeA() accepts A2. this has type A<B2, A2>, which is not known to extend A2. It's only known that A2 extends A<B2, A2>.
Based on kocko's answer, the original question had the same solution:
public class Main {
abstract class A<A2 extends A<A2, B2>, B2 extends B<A2, B2>> {
B2 b;
void test() {
b.testMethod(getThis()); //getThis() instead of this;
}
abstract A2 getThis();
}
class B<A2 extends A<A2, B2>, B2 extends B<A2, B2>> {
void testMethod(A2 a) {
}
}
public void execute() {
}
public static void main(String[] args) {
Main main = new Main();
main.execute();
}
}
We can simplify it by removing the B part which doesn't contribute to the problem -
class A<T extends A<T>>
{
void test(C<T> c)
{
c.acceptParameterOfTypeA(this); // ERROR
}
}
class C<T extends A<T>>
{
void acceptParameterOfTypeA(T a) {}
}
this type is A<T>; and the question is whether A<T> <: T, which is false.
What we really want here is "self type", so that this type is T. We don't have that in Java.
Usually we use T extends A<T> for "self type"; but it is flawed and inadequate in some use cases.
One remedy for that is T getThis(), as kocko mentioned.
You could simply do a brute cast (T)this, which is obviously correct by the intention of T.
My preferred approach is to simply omit the bound of T, and rename it to This to indicate the purpose of the type variable. Casting (This)this looks obviously correct. See my other post. That approach usually works; but it doesn't work here, since C would need This to have the bound A<This>. The deeper problem is A and C depends on each other, which might be redesigned.
I would like to create an Java interface with a method that accepts all subtypes of a type:
interface A{};
interface B{
void method(A a);
}
What I want to accomplish is to make an implementation of the method(A a) accept
all subtypes of A (like return type polymorphism but with an argument).
Is this even possible?
You've already done it!
To prove it, try something like this:
public class ThisA implements A {}
public class ThatA implements A {}
public class OtherA implements A {}
public class SubclassA extends OtherA {}
then call your method:
B b = new B {
public void method(A a) {
System.out.println("Called with "+a);
}
}
b.method(new ThisA());
b.method(new ThatA());
b.method(new OtherA());
b.method(new SubclassA());
This answer no doubt exists on SO, but I haven't found the right combination of search terms to come up with it.
I have a method that I want to take a parameter that is of class A, but also implements interface B. How do I do it?
e.g.
public class MySubclassWithInterface extends MyClass implements MyInterface { }
public class MySubclass extends MyClass { }
public class MyInterfaceClass implements MyInterface { }
public class MyOtherSubclassWithInterface extends MyClass implements MyInterface { }
Out of the three classes above, I only want my method to accept an object that is MyClass and implements MyInterface, in other words, either MySubclassWithInterface or MyOthersubclassWithInterface but not MySubclass or MyIntefaceClass
I very sheepishly tried the following which obviously failed:
public void myMethod( (MyClass MyInterface) parameterName) {
...
}
Thanks for your help in advance.
You can express this with a generic type as in the following signature:
<T extends MyClass & MyInterface> void m(T p)
The rule is that the first type must be a class or an interface and any following parameter must be an interface type.
Suppose I have the following static method and interface (List is java.util.List). Note that the static method enforces a "super Foo" on the wildcard type of the list.
public class StaticMethod {
public static void doSomething(List<? super Foo> fooList) {
...
}
}
public interface MyInterface<T> {
public void aMethod(List<T> aList);
}
I would like to be able to add a class which implements the interface using the static method as follows:
public class MyClass<T> implements MyInterface<T> {
public void aMethod(List<T> aList) {
StaticMethod.doSomething(aList);
}
}
This obviously won't compile because T does not have the "super Foo" constraint. However, I can't see any way of adding the "super Foo" constraint. For example - the following is not legal:
public class MyClass<T super Foo> implements MyInterface<T> {
public void aMethod(List<T> aList) {
StaticMethod.doSomething(aList);
}
}
Is there any way of solving this problem - ideally without altering StaticMethod or MyInterface?
I'm going out on a limb here, but I think lower bounding is the problem here, because you have to know about the actual class that fits the bound when you refer to it... you can't use inheritance.
Here's a usage that compiles, but notice that I need to name the actual class that is a super of Foo:
class SomeOtherClass
{
}
class Foo extends SomeOtherClass
{
}
class StaticMethod
{
public static <T> void doSomething(List<? super Foo> fooList)
{
}
}
interface MyInterface<T>
{
public void aMethod(List<T> aList);
}
class MySpecificClass implements MyInterface<SomeOtherClass>
{
public void aMethod(List<SomeOtherClass> aList)
{
StaticMethod.doSomething(aList);
}
}
Comments?
p.s. I like the question :)
If you are sure that aList contains objects that can be safely cast to <? super Foo>, then you can do:
public static class MyClass<T> implements MyInterface<T> {
#Override
public void aMethod(List<T> aList) {
StaticMethod.doSomething((List<? super Foo>) aList);
}
}
See the complete and working example: http://ideone.com/fvm67