Java generic parameter as exact subclass? - java

Assuming we have a method like this:
public void foo(Class<? extends ClassBar> x) {
...
}
By modifying the generic expression;
< ? extends ClassBar >
Is it possible to ensure that ClassBar.class can't be passed in but anything extends ClassBar directly or indirectly be passed in WITHOUT throwing an exception on the runtime?

If you have only a bunch of classes extending ClassBar you can follow these two approaches.
Solution 1:
have all subclasses of ClassBar extend a custom interface (except for ClassBar itself), and change the method signature to:
public <T extends ClassBar & MyInterface> void foo(Class<T> x) {
...
}
Solution 2:
use something similar to this #AndyTurner's trick and provide instances only for specific types.
E.g:
class ClassBar {}
class ClassBarA extends ClassBar{}
class ClassBarB extends ClassBar{}
Your class containing foo:
class Foo<T extends ClassBar> {
private Foo() {} // private constructor
public static <T extends ClassBarA> Foo<T> instance(T c) {
return new Foo<T>();
}
public static <T extends ClassBarB> Foo<T> instance(T c) {
return new Foo<T>();
}
public void foo(Class<T> c) {
}
}
Only subclass of ClassBarA would be accepted in this case
Foo<ClassBarA> foo1 = Foo.instance(this.classBarA);
foo1.foo(ClassBarA.class); // pass
foo1.foo(ClassBar.class); // fail

Related

Can we use generic to allow only specific types instead of any type <T>?

Suppose I have three isolated public classes (no IS-A relationship) A, B and C. I want to define a field in C such that it's type can either be A or B.
Currently I'm achieving this by defining C as below:
class A{} class B{}
public class C<T> {
private T obj;
public C(T param){
if ( !(param instanceof A)
|| !(param instanceof B) ) {
throw new InvalidParameterException("Only types A and B are allowed!");
}
this.obj = param;
}
}
Above code will throw exception only at runtime. But what I would rather prefer is to throw error at compile time itself to generate a compiler error in case any type other than A or B is used to construct C.
Make the constructor private:
private C(T param){
And then provide static factory methods to create instances of particular types:
public static <T extends A> C<T> create(T param) {
return new C<>(param);
}
public static <T extends B> C<T> create(T param) {
return new C<>(param);
}
This doesn't prevent you from using the type C<SomeOtherType>; you just can't create an instance of it.
You could use a marker interface for that:
interface AllowedInC {
// intentionally empty because it will be used as a mere marker
}
class A implements AllowedInC {
...
}
class B implements AllowedInC {
...
}
class C<T extends AllowedInC> {
...
}
Only classes A or B (or another class implementing AllowedInC) will be useable in C<T>.
You can't do that but you can set boundaries on what type you want to accept.
If you have
class A extends BaseType {}
class B extends BaseType {}
you can define the class C to be
class C<T extends BaseType> { ... }
Either a class or an interface as base type work.

Returning Class<T> From a Method

I have two classes that extend a common base class. The base class has code that, for one concrete subclass, needs to know the Class of the other concrete subclass. So, given Foo and Bar extending Base, an instance of Foo needs to know Bar.class, and an instance of Bar needs to know Foo.class.
And, silly me, I'm trying to Do the Right Thing and use Java generics to ensure that the subclasses return a valid Java class object, one that extends the base class.
So, I tried this:
class Base {
abstract protected <T extends Base> Class<T> getOtherClass();
}
The compiler seems reasonably happy with that construction. The problem comes in the implementations.
First, I tried:
class Foo extends Base {
#Override
protected <T extends Base> Class<T> getOtherClass() {
return Bar.class;
}
}
(where Bar also extends Base)
That complains that I have a type mismatch in the return value, and it requires a cast.
Then, I tried:
class Foo extends Base {
#Override
protected Class<Bar> getOtherClass() {
return Bar.class;
}
}
Now the compiler complains about needing a cast at Class<Bar>.
Then I tried:
class Foo extends Base {
#Override
protected Class<Base> getOtherClass() {
return Bar.class;
}
}
Now I get both complaints: needing a cast in the Class<Base> and in the return value.
Is there a way of expressing this that avoids any casts?
abstract class Base<T extends Base> {
abstract Class<T> getOtherClass();
}
class Foo extends Base<Bar> {
#Override Class<Bar> getOtherClass() { return Bar.class; }
}
...or...
abstract class Base {
abstract Class<? extends Base> getOtherClass();
}
class Foo extends Base {
#Override Class<Bar> getOtherClass() { return Bar.class; }
}

Java Generics - Compile time validation of type and implementing object

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

Java: generics inheritance confusion

Imagine we have following classes:
public interface MyInterface<T> {
List<T> getList(T t);
}
abstract class BaseClass<T extends Number> implements MyInterface<T> {
#Override
public List<T> getList(Number t) {
return null;
}
}
class ChildClass extends BaseClass<Integer> {
#Override
public List<Integer> getList(Integer t) {
return super.getList(t); //this doesn't compile
}
}
getList in ChildClass doesn't compile, the output is:
abstract method getList(T) in com.mypackage.MyInterface cannot be accessed directly
I can't get why BaseClass.getList method isn't overriden in ChildClass.
But what makes me completely confused is the fix that makes it compile:
class ChildClass extends BaseClass<Integer> {
#Override
public List<Integer> getList(Integer t) {
return super.getList((Number) t); //Now it compiles!
}
}
So I cast Integer to Number, and is solves the problem.
Could anyone explain what's going on in this code?
Your base class should look like:
abstract class BaseClass<T extends Number> implements MyInterface<T> {
#Override
public List<T> getList(T t) {
return null;
}
}
You weren't using T, but the Number class as a parameter.
It doesn't override because the abstract method takes a Number as a parameter and the concrete method takes an Integer. They must be the same in order to override.
You should change your abstract class implementation to take type T as a parameter.
Why isn't the superclass method defined as
public List<T> getList(T t)
?
What is going on in the imaginary class.
abstract class BaseClass<T extends Number> implements MyInterface<T> {
#Override
public List<T> getList(Number t) {
return null;
}
}
This class has one generic parameter (T) that has to extend Number class and implement the interface MyInterface
You also Try to override a method that does not exists, because this class do not extend other any class. While a class is implementing an interface there is no need to override the interface method because the are only the description.
What happen if we remove the #override annotation.
abstract class BaseClass<T extends Number> implements MyInterface<T> {
public List<T> getList(Number t) {
return null;
}
}
In this case we do not implement the method from the interface but create a new one, a this method parameter is Number that is same type as T, it will probably cause some error that class has two the same methods. (not tested by compiler)
Them implementation of this method should look like this
abstract class BaseClass<T extends Number> implements MyInterface<T> {
public List<T> getList(T t) { //Because T is allready restricted to be Number
return null;
}
}
And when You specify the type You will not have a problem to call this method when you override it
class ChildClass extends BaseClass<Integer> {
#Override
public List<Integer> getList(Integer t) {
return super.getList(t);
}
}
In advance You don have to implement it only for return null and then override it in some child class. What You can do is create class like this
abstract class BaseClass<T extends Number> implements MyInterface<T> {
private List<T> list = new ArrayList<T>(); //The way of initialization is up to You
public List<T> getList() { //Because T is allready restricted to be Number
return list;
}
}
As other colleagues pointed out the reason for issue is incorrect signature of parent method. The reason why the casting works is due to the way how compiler treats generics. It guarantees that there won't be runtime ClassCastException issues if you use generic but only if you don't do casting. As soon as you did it you actually said compiler to shut up as you know better what your type really is. However after this you potentially could get ClassCastException in runtime (not in this case I assume)

Java field type for a value of a generically recursive self-type?

Given a class hierarchy where the base class defines a recursive self-type:
abstract class A<T extends A<T>> { }
How can I declare another class (which should not be generic in T, because such a T could vary over the lifetime of the object) with a field that can hold any subclass of A?
The following does not work:
public class B {
//fails to compile, because the capture of ? is not sufficiently narrow
private A<?> a;
public <T extends A<T>> setA(T a) {
this.a = a;
}
}
-- END OF QUESTION --
I've noticed a tendency of a number of StackOverflow members to approach certain difficult questions with "why are you doing that in the first place?" The following is a justification of my use of this pattern - you can note that the Java standard library also uses recursive self-types in its definition of the Enum class: Enum<E extends Enum<E>>. This question could similarly be asked as "how to define a field of type Enum<?>.
Justification example:
abstract class A<T extends A<T>> {
public abtract T self();
public B<T> bify(Bifyer bifyer) {
return bifyer.bify(self());
}
}
with subclasses:
class ASub1 extends A<ASub1> {
public ASub1 self() { return this; }
}
class ASub2 extends A<ASub2> {
public ASub2 self() { return this; }
}
bound to a parallel class hierarchy:
abstract class B<T extends A<T>> {
}
class BSub1<T extends A<T>> implements B<T> { }
class BSub2<T extends A<T>> implements B<T> { }
//and others
And with generation of B instances managed by implementations of a Bifyer interface:
interface Bifyer {
B<ASub1> bify(ASub1 asub1);
B<ASub2> bify(ASub2 asub2);
}
Implementations of this interface may return a BSub1 or BSub2 for the B. This is essentially an application of the Visitor pattern where the Bifyer is the visitor, but unlike the standard Visitor the accept method returns a value instead of void. This provides a modular framework where different Bifyer implementations can be specified to provide alternate behavior and return types for the Bify method - say one for each subclass of B.
If you bound the wildcard ? below by A, it should work:
public class B {
private A<? extends A> a;
public <T extends A<T>> void setA(T a) {
this.a = a;
}
}

Categories

Resources