This is a design similar to other JPA BaseEntity patterns you may have seen:
#MappedSuperclass()
public abstract class Entity<X extends Entity<X>>
implements
Comparable<X>,
Serializable
{
private static final long serialVersionUID = 1L;
private Long id;
private Date timeStamp;
...
// Simply compare fields in subclass until difference is discovered
private int compareSubclassFields(X that)
{
int result = 0;
for(Comparator<X> comparator : getComparators())
{
result = comparator.compare(this,that); <<=== compilation error
if(result != 0) { break; }
}
return result;
}
/**
* Entity subclasses provide a list of their own special
* comparators that can contribute to the comparison.
*/
protected abstract List<Comparator<X>> getComparators();
}
Here is an example of a class that extends Entity:
public class User extends Entity<User>
{
private static final long serialVersionUID = 1L;
private String firstName;
private String lastName;
private String email;
...
#Override
public List<Comparator<User>> getComparators()
{
List<Comparator<User>> result =
new ArrayList<Comparator<User>>();
result.add(getLastNameComparator()); // Sort first on last name
result.add(getFirstNameComparator());// Next, by first name
result.add(getEmailComparator()); // Finally, by email (unique)
return result;
}
}
When I compile, I get the following error:
error: method compare in interface Comparator<T> cannot be
applied to given types;
result = comparator.compare(this,that);
^
required: X,X
found: Entity<X>,X
reason: actual argument Entity<X> cannot be converted to
X by method invocation conversion
where X,T are type-variables:
X extends Entity<X> declared in class Entity
T extends Object declared in interface Comparator
Reading Java Enum Definition, in particular the part where it says,
public class StatusCode extends Enum<StatusCode>
Now if you check the constraints, we've got Enum - so E=StatusCode. Let's check: does E extend Enum? Yes! We're okay.
I assume that in my example, where X extends Entity<X>, 'this' would be an instance of User and not Entity<User>. Moreover, because Entity is an abstract class it must be extended and, therefore, compareNonIdFields can only be invoked by an instance of X -- on itself. Of course, when I cast I get the unchecked warning:
warning: [unchecked] unchecked cast
result = comparator.compare(((X)this),that);
^
required: X
found: Entity<X>
where X is a type-variable:
X extends Entity<X> declared in class Entity
1 warning
Thoughts on why this recursive generic usage causes a compilation error and solutions to make the unchecked cast warning go away would be greatly appreciated.
You are writing this keyword inside the Entity<X> class. So,
this = Entity<X>
On the other hand, you provided Comparator for X, not for Entity<X>.
You may keep a field to store related X object inside Entity<X> object and write in this manner:
result = comparator.compare(this.getX(),that);
Imagine the following two classes.
class Foo extends Entity<Bar> {}
class Bar extends Entity<Foo> {}
Clearly the comparison can not only be invoked on instances of X: If you invoke it on an instance of Foo then X = Bar and vice versa.
Edit: Just to be clear, while you intend to always substitute the inheriting type itself for X, this is not enforced by the language and/or the compiler. That's the source of your issue.
Weird! It's perfectly happy if you
result = comparator.compare((X)this, that);
So, are there any circumstances under which "this" might not be an X? Some odd permutation of subclassing and leaving the parameter unbound? Or further subclassing a subclass with a bound parameter?
A ha! It can happen if you subclass the class when X is already bound!
… no, that's not right. I gotta admit, I'm flummoxed.
Related
I'm new to Java and coming from Python, so I don't have a great grasp of generics, but I am trying to make a general Parameter class that contains a value field, which can be an int, float, string or an array of one of the previous types:
public class Parameter<T> {
private final String name;
...
private final Utils.Range<T> range;
private final RANGE_TYPE range_type;
private final T value;
public enum RANGE_TYPE {CONTINUOUS, DISCREET};
...
/* constructor / builder class etc */
...
}
It also has to have a range, which I have implemented as follows:
public class Utils {
/**
* Collection of helper classes
*/
public static class Range<T extends Comparable<T>> {
/**
* Generic Inclusive Range (designed for int / float / double).
*/
private final T start;
private final T end;
public Range(T start, T end) {
this.start = start;
this.end = end;
}
public boolean contains(T number) {
return (number.compareTo(start) > 0 && number.compareTo(end) < 0);
}
}
}
The data that I'm pushing into this Parameter class is coming from a REST API that spits out JSON for each "Block" (I also have a Block class that expresses the hierarchy of the blocks - basically a DAG, but each Block can contain sub-Blocks). I wanted a generic way to encapsulate this parameter data without depending directly on the data structure from the REST API.
The issue is, the generic types between the range field in Parameter class and the Range class itself are incompatible. I can't make the Parameter class extend Comparable, as T can be a container (List, ArrayList, etc). Note: In the event T is a container class, the range would be checked element-wise.
Am I coming at this from the wrong direction? In python I would implement this as a dict and not worry too much about the types of the values.
Do you have any dependency between the generic type of Range and the one from Parameter?
In case not, you can separate them in 2 generic params in Parameter class as below.
public static class Parameter<T, R extends Comparable<R>> {
private final String name;
private final Range<R> range;
private final RANGE_TYPE range_type;
private final T value;
Range's generic type parameter must be Comparable. Parameter's generic type parameter is not necessarily Comparable.
Parameter must also enforce this constraint, if you need it to internally create a Range.
class Parameter<T extends Comparable<T>>
By the way, all classes and enums should be camel case, by convention. RANGE_TYPE should be RangeType.
Background: the question came up in this answer (the first revision of the answer, to be exact). The code presented in this question is reduced to the bare minimum to explain the problem.
Suppose we have the following code:
public class Sample<T extends Sample<T>> {
public static Sample<? extends Sample<?>> get() {
return new Sample<>();
}
public static void main(String... args) {
Sample<? extends Sample<?>> sample = Sample.get();
}
}
It compiles without warning and executes fine. However, if one tries to somehow define the inferred type of return new Sample<>(); in get() explicitly the compiler complains.
Up until now, I was under the impression that the diamond operator is just some syntactic sugar to not write explicit types and thus could always be replaced with some explicit type. For the given example, I was not able to define any explicit type for the return value to make the code compile. Is it possible to explicitly define the generic type of the return value or is the diamond-operator needed in this case?
Below are some attempts I made to explicitly define the generic type of the returned value with the corresponding compiler errors.
return new Sample<Sample> results in:
Sample.java:6: error: type argument Sample is not within bounds of type-variable T
return new Sample<Sample>();
^
where T is a type-variable:
T extends Sample<T> declared in class Sample
Sample.java:6: error: incompatible types: Sample<Sample> cannot be converted to Sample<? extends Sample<?>>
return new Sample<Sample>();
^
return new Sample<Sample<?>> results in:
Sample.java:6: error: type argument Sample<?> is not within bounds of type-variable T
return new Sample<Sample<?>>();
^
where T is a type-variable:
T extends Sample<T> declared in class Sample
return new Sample<Sample<>>(); results in:
Sample.java:6: error: illegal start of type
return new Sample<Sample<>>();
^
The JLS simply says:
If the type argument list to the class is empty — the diamond form <> — the type arguments of the class are inferred.
So, is there some inferred X that will satisfy the solution? Yes.
Of course, for you to explicitly define such an X, you'd have to declare it:
public static <X extends Sample<X>> Sample<? extends Sample<?>> get() {
return new Sample<X>();
}
The explicit Sample<X> is compatible with the return type Sample<? extends Sample<?>>, so compiler is happy.
The fact that return type is a messed up Sample<? extends Sample<?>> is an entirely different story.
Instantiating Generics with Wildcards
There's a couple problems here, but before delving into them, let me address your actual question:
Is it possible to explicitly define the generic type of the return value or is the diamond-operator needed in this case?
It is not possible to explicitly instantiate a Sample<? extends Sample<?>> (or a Sample<?> for that matter). Wildcards may not be used as type arguments when instantiating a generic type, though they may be nested within type arguments. For example, while it is legal to instantiate an ArrayList<Sample<?>>, you cannot instantiate an ArrayList<?>.
The most obvious workaround would be to simply return some other concrete type that is assignable to Sample<?>. For example:
class Sample<T extends Sample<T>> {
static class X extends Sample<X> {}
public static Sample<? extends Sample<?>> get() {
return new X();
}
}
However, if you specifically want to return a generic instantiation of the Sample<> class containing wildcards, then you must rely on generic inference to work out the type arguments for you. There are a few ways to go about this, but it usually involves one of the following:
Using the diamond operator, as you are doing right now.
Delegating to a generic method that captures your wildcard with a type variable.
While you cannot include a wildcard directly in a generic instantiation, it's perfectly legal to include a type variable, and that's what makes option (2) possible. All we have to do is ensure that the type variable in the delegate method gets bound to a wildcard at the call site. Every mention of the type variable the method's signature and body then gets replaced with a reference to that wildcard. For example:
public class Sample<T extends Sample<T>> {
public static Sample<? extends Sample<?>> get() {
final Sample<?> s = get0();
return s;
}
private static <T extends Sample<T>> Sample<T> get0() {
return new Sample<T>();
}
}
Here, the return type of Sample<T> get0() gets expanded to Sample<WC#1 extends Sample<WC#1>>, where WC#1 represents a captured copy of the wildcard inferred from the assignment target in Sample<?> s = get0().
Multiple Wildcards in a Type Signature
Now, let's address that method signature of yours. It's hard to tell for sure based on what code you've provided, but I would guess that a return type of Sample<? extends Sample<?>> is *not* what you really want. When wildcards appear in a type, each wildcard is distinct from all others. There is no enforcement that the first wildcard and second wildcard refer to the same type.
Let's say get() returns a value of type X. If it was your intention to ensure that X extends Sample<X>, then you have failed. Consider:
class Sample<T extends Sample<T>> {
static class X extends Sample<X> {}
static class Y extends Sample<X> {}
public static Sample<? extends Sample<?>> get() {
return new Y();
}
public static void main(String... args) {
Sample<?> s = Sample.get(); // legal (!)
}
}
In main, variable s holds a value that is a Sample<X> and a Y, but not a Sample<Y>. Is that what you'd intended? If not, I suggest replacing the wildcard in your method signature with a type variable, then letting the caller decide the type argument:
class Sample<T extends Sample<T>> {
static class X extends Sample<X> {}
static class Y extends Sample<X> {}
public static <T extends Sample<T>> Sample<T> get() { /* ... */ }
public static void main(String... args) {
Sample<X> x = Sample.get(); // legal
Sample<Y> y = Sample.get(); // NOT legal
Sample<?> ww = Sample.get(); // legal
Sample<?> wx = Sample.<X>get(); // legal
Sample<?> wy = Sample.<Y>get(); // NOT legal
}
}
The version above effectively guarantees that, for some return value of type A, the returned value extends Sample<A>. In theory, it even works when T is bound to a wildcard. Why? It goes back to wildcard capture:
In your original get method, the two wildcards could end up referring to different types. In effect, your return type was Sample<WC#1 extends Sample<WC#2>, where WC#1 and WC#2 are separate wildcards that are not related in any way. But in the example above, binding T to a wildcard captures it, allowing the same wildcard to appear in more than one spot. Thus, when T is bound to a wildcard WC#1, the return type expands to Sample<WC#1 extends Sample<WC#1>. Remember, there is no way to express that type directly in Java: it can only be done by relying on type inference.
Now, I said this works with wildcards in theory. In practice, you probably won't be able to implement get in such a way that the generic constraints are runtime-enforceable. That's because of type erasure: the compiler can emit a classcast instruction to verify that the returned value is, for example, both an X and a Sample, but it cannot verify that it's actually a Sample<X>, because all generic forms of Sample have the same runtime type. For concrete type arguments, the compiler can usually prevent suspect code from compiling, but when you throw wildcards into the mix, complex generic constraints become difficult or impossible to enforce. Buyer beware :).
Aside
If all this is confusing to you, don't fret: wildcards and wildcard capture are among the most difficult aspects of Java generics to understand. It's also not clear whether understanding these will actually help you with your immediate goal. If you have an API in mind, it might be best to submit it to the Code Review stack exchange and see what kind of feedback you get.
The code below contains a getter to a Set of objects with class T:
public class Cube <T extends State> {
private Set<T> states = new HashSet<>();
public Set<T> getStates() {
return states;
}
}
Which seemed to me the valid way to return a the Set of states. However, it returns a set of Objects instead. Trying to use:
Cube<DestinationState> cube = new Cube<>();
Set<DestinationState> set = cube.getStates();
Yields a compile error on the second line:
Error:(187, 61) java: incompatible types: java.lang.Object cannot be converted to nl.gijspeters.pubint.graph.state.DestinationState
State is a generic interface with multiple implementation classes (among which DestinationState) and subinterfaces.
This may very well be a duplicate question (as it seems quite basic), however, I was not able to find the answer.
by default T is replaced with Object so this is type inference based on the target so try this
Set<DestinationState> set = cube<DestinationState>.getStates();
I'm working on an open-source Java library that will allow one to compute certain quantities, such as Gini index, of an attribute that takes on a finite number of values. (Formally, it computes the Gini index of the discrete distribution associated with the attribute A, but this is not relevant here.)
For example, one will be able to do the following
String[] namesArray = {"primary_school", "high_school", "university"};
Calculator<String> calc =new Calculator<String>(namesArray);
// p.getEducationLevel() returns `"primary_school"`, `"high_school"`, or `"university"`.
for (Person p : peopleCollection) {
calc.increment(p.getEducationLevel());
}
// e.g. the Gini index of the distribution
double currentStat = calc.getCurrentValue();
The idea is to allow users of the library to use their own type to refer to attribute values; in this case, I am using strings (e.g. "primary_school"). But I might want to use integers or even my own type AttributeValue.
I solve this by defining
public class Calculator<T> {
/* ... */
}
However, using generics causes some problems in the implementation: for example, if I want to maintain a collection of pairs of type (T, double), I have to do nasty type casts:
public class Calculator<T>
/* ... */
private Queue<StreamElement<T>> slidingWindow;
/* ... */
class StreamElement<T> {
private T label;
private double value;
StreamElement(T label, double value) {
this.label = label;
this.value = value;
}
public T getLabel() {
return label;
}
public double getValue() {
return value;
}
}
/* ... */
slidingWindow.add(new StreamElement<T>(label, value));
if (slidingWindow.size() > windowSize) {
StreamElement lastElement = slidingWindow.remove();
// XXX: Nasty type cast
decrement((T)lastElement.getLabel(), lastElement.getValue());
}
/* ... */
}
Here is the warning produced by javac:
Calculator.java:163: warning: [unchecked] unchecked cast
decrement((T)lastElement.getLabel(), lastElement.getValue());
^
required: T
found: Object
where T is a type-variable:
T extends Object declared in class Calculator
1 warning
Update. If I do not do the type cast, I get
Calculator.java:163: error: no suitable method found for decrement(Object,double)
decrement(lastElement.getLabel(), lastElement.getValue());
^
method Calculator.decrement(T) is not applicable
(actual and formal argument lists differ in length)
method Calculator.decrement(T,double) is not applicable
(actual argument Object cannot be converted to T by method invocation conversion)
where T is a type-variable:
T extends Object declared in class Calculator
1 error
Questions:
What is a proper, clean way to do the type cast?
What would be an alternative to using generics here?
More concretely, would it be better to instead define a class Label which user could extend to MyLabel and then use MyLabel for attribute values? This means that Calculator would no longer be a generic type; in the implementation we'd have class StreamElement { Label label; /* ... */ } et cetera.
I think you just made some mistake.
This is the correct implementation:
/* ... */
slidingWindow.add(new StreamElement<T>(label, value));
if (slidingWindow.size() > windowSize) {
// Don't forget the generic argument at StreamElement
StreamElement<T> lastElement = slidingWindow.remove();
decrement(lastElement.getLabel(), lastElement.getValue());
}
/* ... */
An abstract class is declared as
myClass<E extends Number, D extends Number>
Sublasses are
final mySubClass<Double,Integer>
final myOtherSubclass<Double,Double>
Imagine there is a subclass that will not have a parametrized procedure for the first type, I mean, type would be ignored. Is there any way to set it to Void, Null or something?
final mySubClassThatDontUseFirstType<Void,Integer>
For example, if it had a inner List<E> inside, this list would be List because would be never used.
Is there any way to set it to Void, Null or something?
No, not really. What ever you choose it needs to be a subtype of Number (that's simply a requirement of the Java Language).
What you could do is to create an uninstantiable class VoidNumber
class VoidNumber extends Number {
// Private constructor
private VoidNumber() {
}
...
}
and use that to document the fact that it's not used.
I think the problem is Void does not extend Object, because if not If I think it works
Ofcourse class java.lang.Void extends Object, just like any other Java class extends Object.
Note that Void is not the same as void. Void with a capital V is a little bit like the wrapper classes for primitive types (int -> Integer, long -> Long etc.).
Beware that the compiler treats Void like any other class. That means if you have a method that returns Void, it must return a value; for example, the method must end somewhere with return null;. It's not like void, which the compiler understands as "nothing is returned".