Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java generics parameter bounding to any of a range of types

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?

like image 390
Bohemian Avatar asked Jul 06 '11 07:07

Bohemian


People also ask

Can generics take multiple type parameters?

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.

How do you declare a generic bounded type parameter in Java?

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).

What are bounded type parameters in generic?

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.


1 Answers

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.

like image 82
Joonas Pulakka Avatar answered Sep 29 '22 18:09

Joonas Pulakka