简体   繁体   中英

Arraylist generics/wildcard etiquette

I'm looking to understand all of the detailed reasons/motivations/uses for each of these, but there are so many combinations while it all seems the same to me, that I am confused about the nuances of what I think is called generics(wildcards, Object, T, E etc., don't know if all of that falls under generics)

If I have something like this I want to make an arraylist out of:

Media<T> //Baseclass
Book<T> //Subclass
Movie<T> //Subclass

Which of these would be most appropriate to make/use in this case, and why?(If necessary, let's assume I'll only use String and Integer for these Books, Movies) :

  • ArrayList<Media> = new ArrayList<Media>;
  • ArrayList<Media<T>> = new ArrayList<Media<T>>;
  • ArrayList<Media<?>> = new ArrayList<Media<?>>;
  • ArrayList<? extends Media> = new ArrayList<? extends Media>;
  • ArrayList<Object> = new ArrayList<Object>;
  • ArrayList<> = new ArrayList<>;
  • Some other one?

And if the baseclass was abstract, would that make a difference/impact the choice?

I know that Object is the super-super class and "can assume any form", I know wildcards signal that the next object may be any kind, but so do E and T, right? I know that ? extends Media means it will be a type of Media. It all seems the same to me otherwise, I wouldn't know how to justify a specific choice.

EDIT: Complete example below

import java.awt.*;
import java.util.ArrayList;

public class Something {

    public class Media<T>{
        T data;
        public T getData(){ return this.data; }
        public void setData(T data){ this.data = data; }
    }
    public class Book<T> extends Media<T>{
        T data;
        @Override
        public T getData(){ return this.data; }
        @Override
        public void setData(T data){ this.data = data; }
    }
    public class Movie<T> extends Media<T>{
        T data;
        @Override
        public T getData(){ return this.data; }
        @Override
        public void setData(T data){ this.data = data; }
    }

    ArrayList<Media> arrList;

    public Something() {
         this.arrList = new ArrayList<Media>();
         this.arrList.add(new Book<Integer>());
         this.arrList.add(new Movie<String>());

         this.arrList.get(0).setData(12);
         this.arrList.get(1).setData("Hello");

         System.out.println(this.arrList.get(0).getData()+10);
         System.out.println(this.arrList.get(1).getData()+10);
    }

    public static void main(String[] args) {
        Something s = new Something();
    }

}

This is not a complete answer, but see this question on the effects of using "super" or "extends" in generic type specifications. The short version is that Collection<? extends T> Collection<? extends T> is read-only while Collection<? super T> Collection<? super T> is append-only.

For this reason I personally prefer to completely avoid both these qualifiers since they are generally more restrictive than a simple Collection<T> .

However, they are sometimes useful when designing APIs for purposes of contra and counter variance (see this question )

Collection<?> I only use when dealing with legacy code (that doesnt use generics) to avoid a compiler warning. Its effectively the same as Collection<Object> , but to me is clearer. I try never to write new code that requires <?>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM