7

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.

Sean Patrick Floyd
  • 292,901
  • 67
  • 465
  • 588
Manoj
  • 5,707
  • 19
  • 56
  • 86
  • 2
    When you do `Integer i + Integer j`, you're not actually adding `Integers`. `Integers` don't support the `+` operator. They get unboxed into `ints`, not directly added as `Integer` objects. You can't add generic objects because objects don't support the `+` operator. `Strings` are a special case and do support `+`. – Jonathon Faust Jan 24 '11 at 13:30
  • 4
    The only reason you would call both of your examples `add` is because they use the `+` operators, which is actually a meaningless similarity since it does completely different things for Strings and Integers. Name methods based on what they actually do from the caller's point of view -- i.e. `sum` and `concatenate` in this case would be good names. – Dave Costa Jan 24 '11 at 13:35

8 Answers8

5

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
Andreas Dolk
  • 113,398
  • 19
  • 180
  • 268
  • 2
    Your second paragraph isn't true. Return type isn't part of the method signature in Java, just the name and parameter types. As long as the parameters are distinct, you can have differing return types. Or did I misunderstand what you wrote? – Jonathon Faust Jan 24 '11 at 13:35
  • Overloading doesn't determined with return type. It is not necessary the return type should be same for overloading. – Manoj Jan 24 '11 at 13:39
  • @Jonathan - thanks a lot - that was a typical ShortOnCoffeeError :-) Changed the answer an booked another "Java for Beginners" course ;) – Andreas Dolk Jan 24 '11 at 13:39
  • @Jonathan: Return type is part of the signature, but you can't have two methods that differ only in return type (because then it's too ambiguous which one you're calling) – Bart van Heukelom Jan 24 '11 at 15:47
5

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.

Jay
  • 26,876
  • 10
  • 61
  • 112
4

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 ]

jmj
  • 237,923
  • 42
  • 401
  • 438
  • 1
    `will accept String only, no superclass of String no sub class` - That's not true. Something like `void add42(List list) {list.add(42);}` is perfectly valid. – maaartinus Jan 24 '11 at 14:31
4
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 Objects 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.

Bert F
  • 85,407
  • 12
  • 106
  • 123
2

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.

Kevin Jalbert
  • 3,115
  • 3
  • 26
  • 39
  • So I confused with Java Generics with C++ templates. If any links for comparing Generics and templates is more helpful to me. – Manoj Jan 24 '11 at 13:49
  • 1
    http://stackoverflow.com/questions/36347/what-are-the-differences-between-generic-types-in-c-and-java Can help you understand the similarities and differences between these two. – Kevin Jalbert Jan 24 '11 at 14:06
1

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.

AlexR
  • 114,158
  • 16
  • 130
  • 208
1

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)
                             );
Sean Patrick Floyd
  • 292,901
  • 67
  • 465
  • 588
1

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.

Danubian Sailor
  • 1
  • 38
  • 145
  • 223