2

I am a bit confused about instance creating since I started to learn Generics because I realize for example, you can create a HashMap like this,

HashMap hashmap = new HashMap();

but also,

HashMap<String,String> hashmap = new HashMap<String, String>();

While I can also declare instance hashmap like this since HashMap is implemented from Map Interface

Map<String,String> hashmap = new HashMap<String, String>();

But if above is true, then I can also create instance of ArrayList this way, is it right?

List<String> arraylist = new ArrayList<String>();

And, how about a custom defined one, lets say class Walk implemented from interface Move so to create an instance object of Walk I can use code like both,

Walk walk = new Walk();
Move walk = new Walk(); 

And these won't cause problems, are these two declarations the same? And is Implementation the key feature to enable the feature while how about class extended from another for exapmle, class Son extended from class Father, is this one legal then?

Father son = new Son(); 
ZoeH
  • 109
  • 9

5 Answers5

7

Okay, so that's a lot of questions and stuff to talk about but I'll see how much I can cover in a short answer.

Generics in Collection Declarations.

Let's start with reasons to use generics in your declarations rather than not using them.

Take the following two declarations;

HashMap hashmap = new HashMap();
HashMap<String,String> hashmap = new HashMap<String, String>();

The first will accept any key/value combinations and you will have to manually use instanceof and casting to get the objects from the map because there is no guarantee that it will contain the object types you think it does.

The second uses generics in the declaration and ENSURES that only String keys and values will make their way into your HashMap instance at compile time. Also, when you call get(), you will have a String object returned automatically and will not have to check and cast it yourself. Unless you have a very good reason, you should always be using generics with your declarations.

Polymorphism in Collection Declarations.

Now onto polymorphism when declaring your collections. Take the following two examples;

List<String> sl = new ArrayList<String>();
ArrayList<String> sl2 = new ArrayList<String>();

The first is more flexible and could hold any custom List subclass that any method decides to return. This means that methods such as get() might return slightly different results depending on the List subclass it contains, or that the items in the List might be kept in a different order or such. Think about that for a moment. This gives you much greater flexibility but much fewer certainties.

If you absolutely want to make sure that your List is an ArrayList and so that variable's methods will always act in accordance to ArrayList (and will always use insertion order), then use the second example. Otherwise if you want to allow some flexibility in List type (for example if you want it to be able to take some ordered AND sorted lists) use the first.

I hope this helps, and I hope I didn't miss anything too important.

Here are some links for further reading from the official Java tutorials;

Community
  • 1
  • 1
Rudi Kershaw
  • 12,332
  • 7
  • 52
  • 77
  • therefore sl will basically be able to use all the methods written in List which sl2 couldn't?its very helpful so are the rest ones, either solved my problems or enriched my knowledge. I read your profile and very impressed because you are self educated n me too though I failed to learn more so I am joined a training program here in China, however, my teacher didn't really introduce generics with collections at all, I read on books though, but without you guys I can't understand it well, so very greatful to you guys all!anyway Sry for posting a farfetched comment :D – ZoeH Jun 26 '14 at 16:44
1

Your first line, HashMap hashmap = new HashMap() works because you're using raw types. This will throw a compiler warning in more recent versions of Java, but it's perfectly valid syntax; it essentially means that you can store keys and values of any type, and you won't get a compiler error. (This answer discusses raw types in more detail).

The only difference between that and your second instantiation of HashMap is that you are providing some restrictions on what the types of your keys and values can be.

All the rest of your examples are related to inheritance. As long as the left-hand side of an object instantiation is more general than the right-hand side (i.e., the type of the right-hand side inherits from the type of the left-hand side), then there's no compiler error.

Part of your confusion seems to be about the difference between implementing an interface and extending a class. For this problem, there isn't a difference; you can instantiate either the same way.

Community
  • 1
  • 1
Jason Baker
  • 2,471
  • 3
  • 23
  • 28
1

Legal ways to create an instance of set/map/list with generics: (E is an object of some class)

List<E> arraylist = new ArrayList<E>();
Map<Integer,E> hashmap = new HashMap<Integer, E>();
LinkedList<E> list = new LinkedList<E>();

Generics can be defined using

  • Data types(Integer, Double, etc)
  • Reference variables
  • Array of reference variable,
  • List, Queue or even Map

With the help of generics, its easier because you wont have to type cast from Object type to the required type everywhere else in the program. Such as consider the program below: (Legal ways to create an instance of set/map/list without generics)

public class ListDemo {

    public static void main(String[] args) {

        ArrayList courseList = new ArrayList();
        courseList.add("Java");
        courseList.add("J2EE");
        courseList.add("Android");
        courseList.add("Hibernate");
        courseList.add("Spring");
        System.out.println("Displaying the contents: ");
        for (Object obj : courseList)
        {
            String courseName = (String)obj;
            System.out.println(courseName);
        }
    }
}

If you observe, type casting to String from Object is needed. Therefore when same kind of data is to be stored in a list, its better to go for Generics.

Whereas consider the program below, where different kinds of data is to be stored onto a list. Then, the default Object type comes into use.

public class ListDemo {

    public static void main(String[] args) {

        ArrayList sampleList = new ArrayList();
        sampleList.add("StackOverflow");
        sampleList.add(12345);
        sampleList.add(new Car (2014,"Hyundai","SantaFe"));
        sampleList.add(23.234);
        System.out.println("Displaying the contents: ");
        for (Object obj : sampleList)
             System.out.println(obj);
    }
}

Also note that compiler gives a Type Safety warning "The method add(Object) belongs to the raw type ArrayList. References to generic type ArrayList should be parameterized"

Read more on Generics here.

0

This has nothing to with generics, it's all inheritance: A a = new B() is valid when:

  1. B is A (e.g., A a = new A())
  2. A is an ancestor of B (as in Father above)
  3. B or one of its ancestors implement interface A (as in Map and List above)

This is true whether or not generics are used.

dfb
  • 13,133
  • 2
  • 31
  • 52
  • I see, and it wont work in inheritance, because father is an independent class as well, thanks! – ZoeH Jun 26 '14 at 15:46
  • What do you mean by "it wont work in inheritance"? If `Son extends Father` then the code should be valid – dfb Jun 26 '14 at 15:47
  • like in situation of class Son extended from class Father and Father son = new Son(); is wrong – ZoeH Jun 26 '14 at 15:48
  • I thought you typed implementation, sorry i must be too dizzy. and yes how about in implementation – ZoeH Jun 26 '14 at 15:50
  • Implementing an interface and extending a class behave the same way for the purposes of your question – Jason Baker Jun 26 '14 at 15:51
  • Not sure what you mean by in implementation. `son` is now a reference of type `Father`. You can call any method that is valid for father, but the actual object in memory is a `Son`. – dfb Jun 26 '14 at 15:51
0

But if above is true, then I can also create instance of ArrayList this way, is it right?

Yes, and it's better because it hides the detail that it's an ArrayList.

And, how about a custom defined one, lets say class Walk implemented from interface Move so to create an instance object of Walk I can use code like both,

These aren't generic; they're just a typical class hierarchy. Generics are used for things like collections that you want to use for a specific data type.

And these won't cause problems, are these two declarations the same?

Nearly, only you're only exposing Move's methods with the second declaration. It's saying "here's a movement, but you don't need to know the details about which movement it is."

And is Implementation the key feature to enable the feature while how about class extended from another for exapmle,

Search around for Abstract Class vs. Interface. Part of it is the "is a" vs "can it" distinction, and part is that class inheritance lets you provide an implementation. The quick aside in the guy who created Java jokingly said he regretted adding inheritance, saying he favored interfaces and composition.

If you want a good example of classes vs. interfaces, look at Collection, List, and AbstractList. They're structured quite well, and you'll notice you rarely knowingly work with an AbstractList unless you're subclassing it.

class Son extended from class Father, is this one legal then?

Could be. If Father has the getChildren() method and Son has getFather() and getMother().

David Ehrmann
  • 7,366
  • 2
  • 31
  • 40