Is there a syntax or workaround to constrain a generic type parameter to any of a range of types?
I am aware that you can constrain a type to be all of a range of types (ie AND
logic):
public class MyClass<T extends Comparable<T> & Serializable> { } // legal syntax
Is there an OR
logic version, ie something like this:
public class MyClass<T extends Comparable<T> | Serializable> { } // illegal syntax
If there isn't a syntax that supports this (I don't think there is), is there a workaround or approach that is a good pattern?
For some context, one example use case might be:
/** @return true if the obj is either has the same id, or if obj is the same as id */
public <T extends MyClass | String> boolean sameAs(T obj) {
if (obj instanceof String) return this.id.equals(obj);
if (obj instanceof MyClass) return this.id.equals(((MyClass)obj).id);
return false;
}
People seem to be getting hung up on the exact semantic of my method example above. Let's try this instead:
public class MyWrapper<T extends A | B> {
// my class can wrap A or B (unrelated classes). Yes I will probably use instanceof
}
EDITED:
I won't know at compile time which I might get (coming from external code), so I want to avoid having concrete classes for each type. Also, I have to give my class to a foreign system who invokes my class.method, but the other system can give me instances of a variety of classes, but a narrowly defined and known variety.
Some people have commented on instanceof
being "impure". Well, one workaround is to use a factory method to pick my concrete class based on the class of the incoming object, but that factory method would have to use instanceof
, so you're just moving the instanceof
to another place - you still need the instanceof
.
Or is this idea just not ever a good one?
Multiple parametersYou can also use more than one type parameter in generics in Java, you just need to pass specify another type parameter in the angle brackets separated by comma.
To declare a bounded type parameter, list the type parameter's name, followed by the extends keyword, followed by its upper bound, which in this example is Number . Note that, in this context, extends is used in a general sense to mean either "extends" (as in classes) or "implements" (as in interfaces).
Whenever you want to restrict the type parameter to subtypes of a particular class you can use the bounded type parameter. If you just specify a type (class) as bounded parameter, only sub types of that particular class are accepted by the current generic class. These are known as bounded-types in generics in Java.
public class MyWrapper<T extends A | B> {}
You can't do this for interfaces that you don't have control over, but for your own stuff you could use an empty marker interface:
interface AOrB {
}
interface A extends AOrB {
someMethodHere();
}
interface B extends AOrB {
someOtherMethodHere();
}
public class MyClass<T extends AOrB> {}
Regardless of what purists say, using instanceof
is perfectly fine when you need it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With