Coming from this answer I'm wondering how I can cast an object to <T extends Number & Comparable<T>>. I mean I have a method that is supposed to sort values. And in case the values are numbers I want to compare them with each other.
My naive first attempt was
Object value1 = getAttributeValueFromHit(hit1, attributeName);
Object value2 = getAttributeValueFromHit(hit2, attributeName);
:
:
} else if (value1 instanceof Number) {
Number nValue1 = (Number & Comparable<Number>) value1;
/*
Multiple markers at this line
- Type safety: Unchecked cast from Object to Number & Comparable<Number>
- Additional bounds are not allowed in cast operator at source levels below 1.8
*/
Number nValue2 = (Number & Comparable<Number>) value2;
/* same as above */
return compareNumbers(nValue1, nValue2);
/*
Multiple markers at this line
- Type safety: Unchecked cast from Object to Number & Comparable<Number>
- Type safety: Unchecked cast from Object to Number & Comparable<Number>
- Bound mismatch: The generic method compareNumbers(T, T) of type DataHitComparator is not applicable for the arguments (Number, Number). The inferred type Number is not a valid substitute for the bounded parameter <T extends Number & Comparable<T>>
- Bound mismatch: The generic method compareNumbers(T, T) of type DataHitComparator is not applicable for the arguments (Number & Comparable<Number>, Number & Comparable<Number>). The inferred type Number & Comparable<Number> is not a valid substitute for the bounded parameter <T extends Number & Comparable<T>>
*/
}
compareNumbers() is based on the linked answer:
private <T extends Number & Comparable<T>> int compareNumbers(T n1, T n2) {
return n1.compareTo(n2);
}
Do I have any chance to make this work with Java 7?
Use a generic type parameter (you can define one on your method or re-use one that is defined in the scope of the class).
public static <X extends Number & Comparable<X>> int test() {
Object o1 = getAttributeValueFromHit(hit1, attributeName);
Object o2 = getAttributeValueFromHit(hit2, attributeName);
return compareNumbers((X) o1, (X) o2);
}
This will leave you with two warnings (because a cast to Comparable<X> cannot be checked) but it will not have any compile errors (and it works as well)
EDIT:
The above is absolutely true! To weave this into compareNumbers() and avoid the warnings it looks like this:
private <T extends Number & Comparable<T>> int compareNumbers(Number number1, Number number2) {
#SuppressWarnings("unchecked")
T number1Cast = (T) number1;
#SuppressWarnings("unchecked")
T number2Cast = (T) number2;
return number1Cast.compareTo(number2Cast);
}
and its call:
return compareNumbers((Number) value1, (Number) value2);
Related
public class GenMethodDemo{
public GenMethodDemo(){
Sum.<Integer,Integer,Integer>sum(1,2);
}
public static void main(String args[]){
new GenMethodDemo();
}
}
class Sum{
public static final <S extends Number,Z extends S,X extends S> S sum(Z v1,X v2){
System.out.printf("v1=%1$s,v2=%2$s%n",v1.getClass(),v2.getClass());
return v1+v2;
}
Error get:
error: bad operand types for binary operator '+'
return v1+v2;
first type: Z
second type: X
where Z,S,X are type-variables:
Z extends S declared in method <S,Z,X>sum(Z,X)
S extends Number declared in method <S,Z,X>sum(Z,X)
X extends S declared in method <S,Z,X>sum(Z,X)
1 error
Can't understand what i'm doing wrong? If i change S.Z.X with Integer - all works fine but why with generics code won't compile?
Refactored code to:
public class GenMethodDemo2{
public GenMethodDemo2(){
Sum.<Integer>sum(1,2);
}
public static void main(String args[]){
new GenMethodDemo2();
}
}
class Sum{
public static final <S extends Integer> S sum(S v1,S v2){
System.out.printf("v1=%1$s, v2=%2$s%n",v1.getClass(),v2.getClass());
return v1+v2;
}
}
error: incompatible types: int cannot be converted to S
return v1+v2;
where S is a type-variable:
S extends Integer declared in method <S>sum(S,S)
1 error
So, S supposed to be an Integer or any subclass of Integer class, in any way it definitely should be possible to + their values. What's wrong with this version?
S extends Integer but int cannot be converted to S, how it could be? Why there is no autoboxing?
The problem you're experiencing is because there is no + operator defined for Number, only specific subclasses of Number. For example, + is defined for Integer, Double etc, but not BigInteger, BigDecimal or any other non-standard implementation of Number.
There is no good way to do generic addition. You end up having to provide a BinaryOperator<S>, so your code looks like:
sum(1, 2, Integer::sum);
sum(1.0, 2.0, Double::sum);
which is more verbose than just:
1 + 2
1.0 + 2.0
The compiler requires + to be defined for the compile-time types of v1 and v2. It doesn't matter if they are Integer (or whatever) at runtime: the decision as to whether to allow the + is made by the compiler, because it has to be able to guarantee that the method is type-safe for any arguments.
The method above is compiled to this:
public static final Number sum(Number v1, Number v2){
System.out.printf("v1=%1$s,v2=%2$s%n",v1.getClass(),v2.getClass());
return v1+v2;
}
This is called type erasure.
If + isn't defined for a Number, this code isn't allowed.
As a general solution for all inbuilt Number extensions:
public static Number sum(final Number a, final Number b) {
return new BigDecimal(a.toString()).add(new BigDecimal(b.toString()));
}
(Note: there's no guarantee that toString() will give a String which is parseable by BigDecimal but it does for all the inbuilt JDK Number extensions to the best of my knowledge.)
If you wanted to do something more clever, you could do some checks with instanceof to find the types of the inputs and work from there, but I tried that once for implementing Comparable between all Numbers and the performance wasn't any better than casting to BigDecimal.
I want to create a function to calculate the power of a number of the type Number (the class) via recursion. There is an issue in the following line:
return base * NumberOpp.power(base, pow - 1);
It doesn't know how to perform the '*' operation. I am guessing this is because of the generic type. It is bounded which I think would fix the problem. I tried casting (it's a little ugly.) It didn't seem to work either.
return (T) (Number.doubleValue(base) * Number.doubleValue(NumberOpp.power(base, pow - 1)));
All the code is below:
public class NumberOpp {
public static <T extends Number> T power(T base, int pow){
if (pow == 1) { /* If power is one return base */
return base;
}else{ /* Else recursivly multiply by base until power is one */
return base * NumberOpp.power(base, pow - 1);
}
}
}
You can only perform numeric operations (such as multiplication) on numeric primitive types. Number has no automatic conversion to a primitive numeric type, which is why your <T extends Number> type bound doesn't help.
You can decide to perform the operation of a specific numeric type, such as double:
public class NumberOpp {
public static <T extends Number> double power(T base, int pow) {
if (pow == 1) {
return base.doubleValue ();
} else {
return base.doubleValue () * NumberOpp.power(base, pow - 1);
}
}
}
This will accept any numeric type as input, but will always return a double result.
For example, there needs to be a written a generic program for addition. It needs to be intelligent in a way that it determines the type of arguments passed to it and then output the answer in the same type.
For more elaboration:
If I want to write only one method to add two numbers ( of any type
like int, float, double etc), what should I do that the method itself
determines the type of number passed and returns the calculated sum in
the same type?
Is there any way to sort this out? Any help would be highly appreciated!
Code view: For example arguments passed are 5 & 6 i.e. integers.
addition(5,6);
Now, what I want is a function add that somehow determines the type (i.e. integer in this case) & returns the result. Like:
public (determined return type) add((determined returned type) space variable, (determined returned type) space variable){
return result;
}
This should work:
public static <T extends Number> T addition(T a, T b) {
if (a instanceof Integer)
return (T) (Object) (a.intValue() + b.intValue());
// + similar code for all primitive types and possibly also BigInteger and BigDecimal
}
You could have a method declared:
public <N extends Number> N add(N n1, N n2)
This would require instanceof checks to actually implement and return the desired type.
More complex answer.
#SuppressWarnings("unchecked")
public <T extends Number> T addition (T argA, T argb)
{
if(argA instanceof Integer)
{
return (T)new Integer ((Integer)argA + (Integer)argb);
}
else if (argA instanceof Double)
{
return (T)new Double((Double)argA + (Double)argb);
}
//..
}
I'm having a problem with a generic method since i upgrade my java version to 8.
The call is the following:
Operator o;
Comparable a;
Comparable<?> b;
boolean match = o.evaluate(a, b)
and the method
public enum Operator{
public <T extends Comparable<T>> boolean evaluate(T value1, T value2) {
if (value1 == null && value2 != null) {
return false;
}
switch (this) {
//some code here
}
}
}
And the exception is:
The method evaluate(T, T) in the type Operator is not applicable for the arguments (Comparable, Comparable)
Thanks in advance!
evaluate expects to arguments that are known to be the same type, which can be compared to itself, but that's just not the case here.
Your generic method imposes two conditions:
That its return type extends the Comparable interface with respect to itself.
That its two parameters (and return type) are all of the same type.
However, you are passing two parameters which are not, strictly speaking, the same type. One of them is a raw Comparable object (whose base type is Object), and the other is a Comparable which is not raw, but has an unknown base type.
In reality you could assign an Integer to b, and that is not strictly compatible with a raw Comparable.
Using a.compareTo(b) would not result in a compile-time error, because a is a raw Comparable that will accept any Comparable object but will consider it to be Comparable and b can be cast to Object. That's how it works with raw types. You get only a warning, and a runtime error if the two objects do not match.
However, using b.compareTo(a) would result in a compile-time error, because b is known to have a base type, it's just not known what it is at the moment. So it's not known whether a Comparable<Object> can or cannot be cast to it.
The following gives me an error message:
public static List<Comparable<?>> merge(Set<List<Comparable<?>>> lists) {
List<Comparable<?>> result = new LinkedList<Comparable<?>>();
HashBiMap<List<Comparable<?>>, Integer> location = HashBiMap.create();
int totalSize;
for (List<Comparable<?>> l : lists) {
location.put(l, 0);
totalSize += l.size();
}
boolean first;
List<Comparable<?>> lowest; //the list with the lowest item to add
int index;
while (result.size() < totalSize) {
first = true;
for (List<Comparable<?>> l : lists) {
if (! l.isEmpty()) {
if (first) {
lowest = l;
}
else if (l.get(location.get(l)).compareTo(lowest.get(location.get(lowest))) <= 0) { //error here
lowest = l;
}
}
}
index = location.get(lowest);
result.add(lowest.get(index));
lowest.remove(index);
}
return result;
}
The error is:
The method compareTo(capture#1-of ?) in the type Comparable<capture#1-of ?> is not applicable for the arguments (Comparable<capture#2-of ?>)
What's going on here? I made the type of everything Comparable so I could call .compareTo and sort this list. Am I using generics incorrectly?
List<?> means "List of anything", so two objects with this type are not the same: One could be a list of String, the other a list of BigDecimal. Obviously, those are not the same.
List<T> means "List of anything but when you see T again, it's the same T".
You must tell the compiler when you mean the same type in different places. Try:
public static <T extends Comparable<? super T>> List<T> merge(Set<List<T>> lists) {
List<T> result = new LinkedList<T>();
HashBiMap<List<T>, Integer> location = HashBiMap.create();
[EDIT] So what does <T extends Comparable<? super T>> List<T> mean? The first part defines a type T with the following properties: It must implement the interface Comparable<? super T> (or Comparable<X> where X is also defined in terms of T).
? super T means that the type which the Comparable supports must T or one of its super types.
Imagine for a moment this inheritance: Double extends Integer extends Number. This is not correct in Java but imagine that Double is just an Integer plus a fraction part. In this scenario, a Comparable which works for Number also works for Integer and Double since both derive from Number. So Comparable<Number> would satisfy the super part for T being Number, Integer or Double.
As long as each of these types support the Comparable interface, they also satisfy the first part of the declaration. This means, you can pass in Number for T and the resulting code will also work when there are Integer and Double instances in the lists. If you Integer for T, you can still use Double but Number is not possible because it doesn't satisfy T extends Comparable anymore (the super part would still work, though).
The next step is to understand that the expression between static and List just declares the properties of the type T which is used later in the code. This way, you don't have to repeat this long declaration over and over again. It's part of the behavior of the method (like public) and not part of the actual code.