public class Calculator<T> {
public Calculator(){
}
public T calculateSum(T a,T b){
return a; // I need to do something like a + b
}
}
I need to add the T object, I'm restricting the T to be only numeric types. How can I do this?
Thanks
Generic type arguments must be reference types, which excludes arithmetic types. You can give a boxed type such as Integer as the type argument, but that will not let you do arithmetic because auto-unboxing only works for particular, specific boxed types. Even if you restricted the type parameter to be a descendant of Number, there would be no way the compiler could be sure that the actual type argument was not some user-defined subclass of Number that did not have any auto-unboxing behavior.
More technically, generic types will not let you do anything that you wouldn't be able to achieve by inserting downcasts (and nothing else) in non-generic code. Here, it looks like you want to have a different kind of addition (integer or floating-point) depending on which type the argument is. And there is no way to achieve that solely by inserting casts; you'd have to insert some explicit condition that tested if the values happen to be Integer, then Long, then Float, et cetera. Since this is more complex than a downcast here or there, generics cannot, in principle, to this for you.
This is different from C++ templates, where each instantiation of the template generates (in principle, at least) a separate implementation in the compiler.
What you can do is make Calculator<T> an abstract class or an interface. Then make concrete subtypes such as
public class IntCalculator extends Calculator<Integer> {
public Integer calculateSum(Integer a, Integer b) {
return a+b;
}
}
public class DoubleCalculator extends Calculator<Double> {
public Double calculateSum(Double a, Double b) {
return a+b;
}
}
and so forth.
Methods (as well as classes) can have type parameters.
public class Calculator {
public Calculator(){
}
public <T extends Number > T calculateSum(T a,T b){
return a; // I need to do something like a + b
} }
Generics are not needed for this exercise.
public class Calculator {
public Calculator(){
}
public int calculateSum(int a,int b){
return a + b ;
}
public long calculateSum(long a,long b){
return a + b ;
}
.... you fill in the rest ...
}
In your declaration you need to make sure that T is always a sub-type of Number.
Instead of
Calculator<T>
try
Calculator<T extends Number>
then look in java.lang.Number and you should find a way to get a value that works with +.
Related
I know that a method can be overriden with one that returns a subclass.
Can it also be overloaded by a method which returns a subclass?
public Object foo() {...}
public String foo(int a) {...}
Is the above code valid?(if placed within a Class)
What about?
public Object foo() {...}
public String foo() {...}
Beginning with Java 5, covariant return types are allowed for overridden methods. This means that an overridden method in a subclass is allowed to use a signature which returns a type that may be a subclass of the parent signature's return type.
To make this concrete, say you have this interface:
public interface MyInterface {
Number apply(double op1, double op2);
:
:
}
The following is legal because the return type is a subclass of Number:
public class MyClass implements MyInterface {
:
:
#Override
public Integer apply(double op1, double op2) {
:
:
return Integer.valueOf(result);
}
}
Because overloaded methods (which have the same name but different signatures) are effectively different methods, you are free to use different return types if you like ... however ... this is discouraged because methods that have the same name but different return types can be confusing to programmers and can complicate the use of your API. It's best not to overload mrthods when you can reasonably avoid it.
This example:
public Object foo() {...}
public String foo(int a) {...}
as long as the two methods get different set of variables, there's no problem with returning different types (even if they are not subclass).
The logic is very simple - if the compiler can choose without doubt which one to use - there's no issue. In this case- if you give the method int it's one method, and without parameters it's the other, no dilema (and the same name does not matter here)
as for:
public Object foo() {...}
public String foo() {...}
This one is not valid, since here the compiler can't 'choose' which one to use.
Yes, and it does not even need to be a subclass foo(), and foo(int) are two completely different and unrelated functions as far as the compiler is concerned, each can have any return type you want.
yeah, you overroad foo with foo(int a) , and gave it a new data type String , the compiler see this as a valid code but the other one Object foo() and String foo() is totally invalid in java
I keep getting a message telling me that the operator < is undefined for the types T,T. This is happening around
if(index<lowest)
How would I go about modifying my program so that I could get the smallest and largest values of an array list using a generic method?
package p07;
import java.util.ArrayList;
public class MyList<T extends Number> {
private ArrayList<T> l;
public MyList(ArrayList<T> l) {
this.l=l;
}
public void add(T x) {
l.add(x);
}
public static <T> void smallest(ArrayList<T> l) {
T lowest=l.get(0);
for(T index:l) {
if(index<lowest) {
}
}
}
}
The compiler is right: the operator < is only applicable to primitive numeric type. Quoting section 15.20.1 of the JLS:
The type of each of the operands of a numerical comparison operator must be a type that is convertible (§5.1.8) to a primitive numeric type, or a compile-time error occurs.
Hence, it is not defined for Objects, not even for Numbers, because they cannot be unboxed to a primitive type: section 5.1.8 of the JLS:
A type is said to be convertible to a numeric type if it is a numeric type (§4.2), or it is a reference type that may be converted to a numeric type by unboxing conversion.
What you need is to use a Comparator or make your objects Comparable. Comparators are responsible for comparing two objects of the same type. Since the objects here are Numbers, and they are not Comparable, you need to use a custom Comparator, like this:
Comparator<Number> myComparator = new Comparator<Number>() {
#Override
public int compareTo(Number n1, Number n2) {
// implement logic here.
// Return -1 if n1 < n2, 0 if n1 = n2, 1 if n1 > n2
}
};
Then you can use this comparator like this:
public static <T extends Number> T smallest(List<T> l) {
T lowest = l.get(0);
for (T index : l) {
if (myComparator.compareTo(index, lowest) < 0) {
index = lowest;
}
}
return lowest;
}
(Note that I added T extends Number to the type of the method - that is because the method is static so it's in fact declaring another type T that the one the class is).
There are several things awry here, but let's start with the low-hanging syntax fruit.
The arithmetic operators only work for primitive values, and T is very much an Object, so you wouldn't be able to use them here.
Another nuance to your syntax is that you're T for that static function is not the same as the T which is bound to your class.
You can fix that, either by adding the bound yourself...
public static <T extends Number> void smallest(ArrayList<T> l)
...but this leads me to ask, why would you want this method to be static at all?
You're obscuring the name of the field l with the parameter l, so while you may think that this is going to work for the instance's provided l, it won't since the method itself is declared static, and you'd still be shadowing the field's name if it weren't.
What you should do is remove static from that method, and remove the parameter from the function.
public void smallest() {}
But now, you've got an issue in that you don't actually return what the smallest value is. You should return it instead of nothing:
public T smallest() {}
Getting the last value out of an array is straightforward if you're capable of sorting. You just need to ensure that all of your elements are Comparable so that they can be sorted, and the values you care about the most - like Integer, Double, Float, Long - are.
public class MyList<T extends Number & Comparable<T>> {}
If you can sort, then getting the smallest is straightforward:
public T smallest() {
// Don't mutate the order of the original array.
ArrayList<T> listCopy = new ArrayList<>(l);
Collections.sort(listCopy);
return listCopy.get(0);
}
Getting the highest via this approach I leave as an exercise for the reader.
I am trying to create a generic class in Java that will perform operations on numbers. In the following example, addition, as follows:
public class Example <T extends Number> {
public T add(T a, T b){
return a + b;
}
}
Forgive my naivety as I am relatively new to Java Generics. This code fails to compile with the error:
The operator + is undefined for the argument type(s) T, T
I thought that with the addition of "extends Number" the code would compile. Is it possible to do this Java or will I have to create overridden methods for each Number type?
Number does not have a + operator associated with it, nor can it since there is no operator overloading.
It would be nice though.
Basically, you are asking java to autobox a descedant of Number which happens to include Integer, Float and Double, that could be autoboxed and have a plus operator applied, however, there could be any number of other unknown descendants of Number that cannot be autoboxed, and this cannot be known until runtime. (Damn erasure)
Your problem is not really related to generics, rather to operators, primitives vs objects, and autoboxing.
Think about this:
public static void main(String[] args) {
Number a = new Integer(2);
Number b = new Integer(3);
Number c = a + b;
}
The above does not compile
public static void main(String[] args) {
Integer a = new Integer(2);
Integer b = new Integer(3);
Number c = a + b;
}
The above does compile, but only because of autoboxing - which is kind of a hacky syntax glue introduced in Java 5, and only works (in compile time) with some concrete types : int-Integer for example.
Behind the scenes, the Java compiler is rewriting the last statement ("I must unbox a and b to apply the sum operator with primitive datatypes, and box the result to assign it to object c") thus:
Number c = Integer.valueOf( a.intValue() + b.intValue() );
Java can't unbox a Number because it does not know at compile time the concrete type and hence it cannot guess its primitive counterpart.
You can do something like this
class Example <T extends Number> {
public Number add(T a, T b){
return new Double(a.doubleValue() + b.doubleValue());
}
}
Yes, Nathan is correct. If you want something like this, you have to write it yourself
public class Example <T extends Number> {
private final Calculator<T> calc;
public Example(Calculator<T> calc) {
this.calc = calc;
}
public T add(T a, T b){
return calc.add(a,b);
}
}
public interface Calculator<T extends Number> {
public T add(T a, T b);
}
public class IntCalc implements Calculator<Integer> {
public final static IntCalc INSTANCE = new IntCalc();
private IntCalc(){}
public Integer add(Integer a, Integer b) { return a + b; }
}
...
Example<Integer> ex = new Example<Integer>(IntCalc.INSTANCE);
System.out.println(ex.add(12,13));
Too bad Java has no type classes (Haskell) or implicit objects (Scala), this task would be a perfect use case...
There are similar questions to this one, and the answer is you can't do it like that.
You could check if a and b are an instance of Long/Double/Integer/etc. and delegate the add to methods like:
public Integer add(Integer a, Integer b) {
return a+b; // this actually uses auto boxing and unboxing to int
}
And you would need to create one for every type that extends Number, so that's not really feasible. In other words, don't use generics for numeric operations. Number as a superclass is pretty limited.
Consider Example<Number>, how would + work on that? There is no add or similar in Number or even the likes of Integer.
Worse consider final class FunkyNumber extends Number { ... weird stuff, no add op ... }.
Even the java runtime library has this problem, most of the methods dealing with primitives have to duplicate the same functionality.
The fastest option would be to write your code for one type and then copy it and replace the type to generate the methods for the other types. A short script should be enough to do this.
Can someone tell me why this code gives me a compile-error?
public class Main {
public static void main(String[] args) {
System.out.println(sum(2, 6.9));
}
public static <T extends Number<T>> T sum(T a, T b) {
T result = a + b; // compile-error here
return result;
}
}
Number is not a generic class, so you can't parameterize it:
public abstract class Number implements java.io.Serializable {
...
}
Further, the + operator only works on primitive types like int, long, etc., rather than Number subtypes like Integer, Long, etc. (EDIT: It will operate on these by unboxing, yes, but it cannot automatically box the result in the appropriate wrapper class.)
(You've stumbled upon one of the reasons Number is a poor example of polymorphism. It really only performs object-to-primitive conversions.)
You can, instead create an interface with
public interface ALU <T extends Number> {
public T add(T a, T b);
}
And make your main class implementing the interface created.
public class Main implements ALU <Integer>.
And create the method add inside your main class.
public Integer add(Integer a, Integer b){
return a + b;
}
And this will work.
The error The operator + is undefined for the argument type(s) T, T is caused because The type Number is not generic; it cannot be parameterized with arguments <T>
The error highlighting in eclipse provides this information, not sure if other IDE's provide the same information.
You have to use:
a.doubleValue()+b.doubleValue()
as Number is a class and does not support the operator +
I want to write a generic method in java like below:
public <T extends Number & Comparable<T>> void test(T[] a){
T b=a[0];
if(a[0]>0){
a[0]*=a[0];
b+=a[1];
}
}
Then later, I can supply either Integer[] or Double[] or other Number subtypes to the method. But the code I tried above gives me errors.
Please help me. Thank you.
all types (including the inferred generic types) except the primitives are Objects which don't support the arithmetic operations (the wrapper classes use boxing/unboxing to get the known psuedo behavior)
and type erasure makes the compiled code use casts to get the proper behavior (i.e. at runtime the JVM doesn't know what type was passed in which it would need to know to get the proper boxing/unboxing behavior)
the only (real) solution is to provide implementations for all primitives you want to support
You can't do this in Java with generics. That's a benefit of C++ for example.
In some way you can define this as "strange", because it is possible to use operators on Java's primitive wrappers. But that is because you can't use operators on java.lang.Number, the superclass of the primitive wrappers.
Some resources:
Simple Java generics question
What are the differences between "generic" types in C++ and Java?
Can I do arithmetic operations on the Number baseclass?
Java generics and the Number class
Generic Arithmetic in Java
You've got Comparable, so if we has a zero, a[0]>0 could be replaced by a[0].compareTo(zero) > 0 (no, I think it's < 0, I can never remember). But now we've run out of useful stuff from Double and the like.
If Double and friends weren't java.lang.Comparable we could supply our own java.util.Comparator. That is we take the implementation of comparison outside of the data object. We can also do that addition and multiplication.
public interface Testor<T> { // Choose a better name...
boolean isStriclyPositive(T value);
T add(T lhs, T rhs);
T square(T value);
}
static final Testor<Integer> INTEGER_TESTOR = new Testor<>() { // Java SE 7 diamond.
public boolean isStriclyPositive(Integer value) { return value > 0; }
public Integer add(Integer lhs, Integer rhs) { return lhs + rhs; }
public Integer square(Integer value) { return value*value; }
}
// ... same for Double, etc.; can't use an enum :( ...
test(new Integer[] { 42, 1972, 86 }, INTEGER_TESTOR);
public <T> void test(T[] a, Testor<T> testor) {
T b = a[0];
if (testor.isStrictlyPositive(a[0])) {
a[0] = testor.square(a[0]);
b = testor.add(b, a[1]);
}
}
Note for things like Short, summing two of them will give you an int.
(Usual Stack Overflow disclaimer: not so much as attempted to compile the code.)