Reputation: 5867
I want to code a single method add()
in Java, that could add both integers, strings etc. Is Generics will help me.
I couldn't understand the ultimate aim of Generics. I am so confused.
Generics vs Overloading?
public Integer add(Integer i, Integer j){return i+j;}
public String add(String i, String j){return i+j;}
public <T> T add(T i, T j){return i+j;} //this gives me error.
Please get me out of it.
Thanks.
Upvotes: 7
Views: 3115
Reputation: 87573
public Integer add(Integer i, Integer j){return i+j;}
public String add(String i, String j){return i+j;}
public <T> T add(T i, T j){return i+j;} //this gives me error.
Although the methods look nearly identical, in this case, generics cannot help. Consider this:
public <T> T add(T i, T j){return i+j;}
...
add(new Object(), new Object());
What does it mean to add to just regular Object
s together? No, +
is not supported for Object
and is not supported for many other types that could be substituted for T
.
In creating a generic method <T> T add(T i, T j)
, the generic method is restricted to methods and operations that are allowed on the generic type parameter T
, which effectively means only things that you can do with Object
. You are trying to use a method/operation +
, which is not something you can do with Object
.
We could try to solve this problem by finding a common base class of String
and Integer
that supports all the methods and operations we have to use in our generic method body. If there were such a common base class XXXXX
that supported the +
operator, we could do this:
public <T extends XXXXX> T add(T i, T j) { return i+j; }
However, there is no common base class XXXXX
that supports everything we want to do in the generic method (+
), so generics can't be used to solve this problem.
Upvotes: 4
Reputation: 299048
How about an approach with a generic interface:
interface Adder<T> {
T add(T first, T second);
}
And a manager class:
public class AdderManager{
public <T> AdderManager putAdder(final Class<T> clazz,
final Adder<? extends T> adder){
adders.put(clazz, adder);
return this;
}
@SuppressWarnings("unchecked")
public <T> Adder<T> getAdder(final Class<T> clazz){
return (Adder<T>) adders.get(clazz);
}
private final Map<Class<?>, Adder<?>> adders =
new HashMap<Class<?>, Adder<?>>();
}
Now you can register and use custom adders for different classes:
final AdderManager manager = new AdderManager();
manager
.putAdder(String.class, new Adder<String>(){
@Override
public String add(final String first, final String second){
return first.concat(second);
}
})
.putAdder(Integer.class, new Adder<Integer>(){
@Override
public Integer add(final Integer first, final Integer second){
return first + second;
}
})
.putAdder(List.class, new Adder<List<?>>(){
@Override
public List<?> add(final List<?> first, final List<?> second){
final List<Object> newList = new ArrayList<Object>();
return newList;
}
});
And now you can use those adders like this:
String addedString = manager.getAdder(String.class).add("abc", "def");
@SuppressWarnings("unchecked") // this is necessary because of
// the generic <Integer> type
List<Integer> addedList = manager
.getAdder(List.class)
.add(
Arrays.asList(1,2,3),
Arrays.asList(4,5,6)
);
Upvotes: 1
Reputation: 27492
Others have pointed out why this doesn't work. Let me just add, I think you are misunderstanding what Java generics are for. Perhaps you are familiar with C++ templates, or with C macro expansion, both of which resemble generics but are a very different thing.
Generics are really about type safety and avoiding messy casts. You tell the compiler that a certain collection contains Strings, and then it knows that everything you put in or take out must be a String. You get some compile-time checking on the things you put in, and you save some casts on the things you take out.
It does NOT cause the compiler to generate different code depending on the type. Generics are not a short-hand way to avoid having to write, say, both an "int" version and a "float" version of the same function, like a macro or a C++ template will do for you. You may be able to get such desired distinct behavior by having two classes that implement the same function but one using int and the other using floats. But you can do that with object-oriented techniques without generics. If you can't get the desired distinct behavior using "non-generic" object-oriented techniques, then you can't do it with generics either.
Upvotes: 5
Reputation: 22867
Generics in java add only casting to bytecode.
The code will be the same, except the casting.
So the two constructions:
List list1 = new ArrayList();
List<String list2 = new ArrayList<String>();
....
String string1 = (String) list1.get(0);
String string2 = list2.get(0);
Are doing the same.
Upvotes: 1
Reputation: 114807
Generics could help, the problem here is that the +
operation is only defined for java primitives and String
but not for types in general. And in Java we can't overload operators (like we can do in C++ for instance).
A practical solution without generics would be:
public Integer add(Integer a, Integer b) { return a + b; } // sum of a and b
public String add(String a, String b) { return a + b; } // concatenate operation!
public MyType add(MyType a, MyType b) { return a.add(b); } // requires add operation
Upvotes: 5
Reputation: 115378
This is exactly the point of generics. You do not want to implement one method that can accept everything. Frankly speaking you can always implement method
add(Object obj)
and pass to it integers, strings, booleans... But in most cases you do not want to to this. The method has to deal with the argument and therefore it should know the parameter's type. This is the reason that if you wish to make method add that receives Strings and integers implement 2 methods:
add(String s);
add(int i);
Now you cannot send boolean to add() method: such method just does not exist.
you can also implement generic method
<T> void add(T arg);
and call it: this.<String>add("hello");
or this.<Integer>add(123);
In this case this.<String>add(123);
causes compilation error.
Upvotes: 1
Reputation: 3245
Generics are nice since if done properly it allows you to generalize some of the code you have written. In terms of writing software you want to minimize unnecessary code and to reuse as much code as possible.
By using the overload approach you have to write out each of the overloads, while with generics you only need to do it once. Generics work well in situations where you are manipulating a collection since you perform certain common operations on a set of collections. In some situations if you desire a more customized approach to handling some situations then you might have to overload the methods, but I would make it a goal to write generics if you can use it in multiple places.
Upvotes: 2
Reputation: 240928
I want to code a single method add() in Java, that could add both integers, strings etc. Is Generics will help me.
NO
Generics are used for type safety mostly at compile time.
You can specify only one type to add in collection
List<String> lst;
will accept String only, no superclass of String no sub class [ for example if exist ]
Upvotes: 4