3

Quick Question... Can collections in Java hold more than one type? Or do they all have to be the same type?

thanks

Jake
  • 2,737
  • 8
  • 39
  • 60
  • The problem of this kind of question is: 1) they have been asked several times. 2) they attract a lot of low quality answers, because it is a topic where even a novice knows *something* about. As a result (on top of it) most answers here contain mistakes, just because they are posted by novice developers. In my opinion this question should be closed. – bvdb Jan 24 '16 at 18:46
  • 1
    Possible duplicate of [Defining a type for a Java Collection](http://stackoverflow.com/questions/9281996/defining-a-type-for-a-java-collection) – bvdb Jan 24 '16 at 18:49

9 Answers9

7

Simple answer

Yes.

More detailed answer

You can either use generic collection, without <T> value, for example:

ArrayList a = new ArrayList();
a.add(2);
a.add("String");

Using collections without <T> is a bad habit and most IDEs / compilers give a warning here. You can circumvent it by using a collection of Object, i.e.:

ArrayList<Object> a = new ArrayList<Object>();

Or you can find some common interface or supertype that these element must have in, for example ArrayList<Number> - and you can store various objects that have common Number superclass, i.e. BigDecimal, BigInteger, Byte, Double, Float, Integer, Long, Short:

ArrayList<Number> a = new ArrayList<Number>();
a.add(2); // integer
a.add(42L); // long
a.add(123.45d); // double
System.out.println(a.toString()); // => [2, 42, 123.45]

Note that it essentially means that a elements are of Number class — i.e. you can't ask to execute subclass-specific methods (for example, Double#isInfinite(), which doesn't exist in Number superclass), although you can typecast in run-time if you somehow know it's safe to typecast:

a.get(2).isInfinite()          // compile-time error
((Double) a.get(2)).isInfinite() // => false
((Double) a.get(1)).isInfinite() // run-time error (ClassCastException)

Run-time typecasting is also generally frowned upon, as it effectively circumvents proper compile-time type safety.

Also note that it's impossible to assign (or use) ArrayList<Number> in place of ArrayList<Integer> and vice-versa, i.e. this will fail to compile:

public void printNumbers(ArrayList<Number> list) {
    list.forEach(System.out::println);
}
ArrayList<Integer> a = new ArrayList<Integer>();
printNumbers(a); // "incompatible types"

as well as this:

public void printIntegers(ArrayList<Integer> list) {
    list.forEach(System.out::println);
}
ArrayList<Number> a = new ArrayList<Number>();
printIntegers(a); // "incompatible types"

To declare a variable to be able to accept both ArrayList<Number> or any of its subclasses, one can use ArrayList<? extends Number> or ArrayList<? super Number> syntax. extends is generally used when you're going to consume (i.e. read) from the object in your method, super is used when you're going to produce (i.e. write). Given that printout is consuming, it's safe to use extends:

public void printNumbers(ArrayList<? extends Number> list) {
    list.forEach(System.out::println);
}

ArrayList<Integer> listInt = new ArrayList<Integer>();
printNumbers(listInt); // works
ArrayList<Double> listDbl = new ArrayList<Double>();
printNumbers(listDbl); // also works

There is a good answer in Difference between <? super T> and <? extends T> in Java for more in-depth explanation.

Community
  • 1
  • 1
GreyCat
  • 15,483
  • 17
  • 70
  • 107
  • Unfortunately, this is not entirely correct. You cannot store a `Double` in an `ArrayList extends Number>`. Why not? Because an `ArrayList extends Number>` could be an `ArrayList`. On the other hand, you can in fact store a `Double` in an `ArrayList super Number>` – bvdb Jan 24 '16 at 18:39
  • Sorry for the confusion. A simple collection that allows addition of both integers and doubles is in fact just `ArrayList`. ` extends Number>` or ` super Number>` is a fancy way to reference semi-unknown type, which would be known to be either in compile-time (in `extends`) or run-time (in `super`) — and they both don't really allow you to store *both* integers and doubles in the same collection as topic starter requests. I'll try to clarify answer now. – GreyCat Jan 25 '16 at 07:44
  • In a `List super Number>` you can in fact store both integers and doubles at the same time. In the same collection. For example: `List super Number> list = new ArrayList();` – bvdb Jan 25 '16 at 20:55
  • The difference between `extends` and `super` has nothing to do with compile-time vs. runtime. All generic bounds are applied at compile-time. – shmosel Feb 28 '18 at 05:24
2

If you want them to hold any more than one type, use Collection<Object>. However, you won't know what you're getting without doing some if (x instanceof MyType) calls, which are rather inefficient.

Actorclavilis
  • 953
  • 7
  • 17
  • So a collection can contain two strings and two integers? – Jake Nov 23 '10 at 22:42
  • if you call it `Vector` (for instance) and store your `int` as `Integer`. – Actorclavilis Nov 23 '10 at 22:42
  • Yeah, sure, as long as these two share the same supertype, i.e. `Object`. Strictly speaking, you can't put `int` into collection, but you can put a `String` and `Integer` there. – GreyCat Nov 23 '10 at 22:44
2

They have to be of the same Supertype. So if you have objects of type A, then a Collection<A> can store objects of type A and of every subtype of A.

If you want to allow arbitrary types, then use Collection<Object>, otherwise take the most general appropriate super-class.

However, you will then have to manually cast from the most general type (Object) to the specific type you have in mind. You can use the typeof operator to find out what the type is.

Lagerbaer
  • 4,506
  • 1
  • 14
  • 29
1

Every Collection classes can contains heterogeneous objects except TreeSet and TreeMap. Since TreeSet and TreeMap stores elements according to some sorting order. so, if objects are of different type it will not be able to sort it because comparison between the objects will not be possible for sorting.

Badal
  • 336
  • 3
  • 11
0

Yes collections in java can hold more than one type as below. But it will throw an exception if done using the following way.

    ArrayList al = new ArrayList();
    al.add(1);
    al.add("name");
    al.add(1.2f);

    Iterator itr =al.iterator();
    while(itr.hasNext())
    {
        System.out.println(itr.next());
    }

Hence it's better to mention the type that you're using. To get rid of the exception the above program can be modified as below.

    ArrayList<Integer> al = new ArrayList<Integer>();
    al.add(1);
    al.add(2);
    al.add(3);

    Iterator itr =al.iterator();
    while(itr.hasNext())
    {
        System.out.println(itr.next());
    }

    ArrayList<String> al1 = new ArrayList<String>();
    al1.add("Words");
    al1.add("Names");
    al1.add("Characters");

    Iterator itr1 =al1.iterator();
    while(itr1.hasNext())
    {
        System.out.println(itr1.next());
    }

You can also use more than these types.

Pankti
  • 393
  • 3
  • 13
0

Yes they can but they should not (that's why generics have been put in place since 5th version of jdk) in general store different types, as this is the straight way to errors.

Ol_dirty
  • 81
  • 6
0

Yes,

My mistake the correct code is this one and

ArrayList<Elements>()=new ArrayList();

or

ArrayList<E>()=new ArrayList();

should be the correct declaration if you want to use Generics in Collection.

class Test
{
   public static void main(String[] args)
   {
      // For Generic class of List
      ArrayList<E> arrL1 = new ArrayList<E>();
      arrL1.add("stackoverflow");
      arrL1.add(1);   
      Iterator itr1=list.iterator();

     while(itr1.hasNext())
     {
        System.out.println(itr1.next());
     }


  // for Particular datatype in List
    ArrayList<String> list=new ArrayList<String>(); // Creating arraylist
    list.add("Ravi"); // Adding object in arraylist
    list.add("Vijay");
    list.add("Ravi");
    list.add("Ajay");

    // transversing the values
    Iterator itr=list.iterator();
    while(itr.hasNext())
    {
        System.out.println(itr.next());
    }
}

}

Output 1

stackoverflow

1

Output 2

Ravi

Vijay

Ravi 

Ajay
Sunil
  • 3,279
  • 10
  • 19
  • 27
Snehalb
  • 1
  • 2
-1

I believe you can also use Collection<?>.

-2

Yes, you can have more than one datatype in ArrayList of Collection.

class Test
{
    public static void main(String[] args)
    {
        // For Generic class of List
        ArrayList<> arrL1 = new ArrayList<>();
        arrL1.add("stackoverflow");
        arrL1.add(1);

        // for Particular datatype in List
        ArrayList<String> list=new ArrayList<String>(); // Creating arraylist
        list.add("Ravi"); // Adding object in arraylist
        list.add("Vijay");
        list.add("Ravi");
        list.add("Ajay");

        // transversing the values
        Iterator itr=list.iterator();
        while(itr.hasNext())
        {
            System.out.println(itr.next());
        }
    }
}

Output 1:

stackoverflow

1

Output 2:

Ravi

Vijay

Ravi

Ajay

vallismortis
  • 6,155
  • 12
  • 65
  • 81
Snehalb
  • 1
  • 2
  • That code does not compile for me because of the `ArrayList<>` syntax (*"illegal start of type"*). Also, I don't see where in the code the "Output 1" would come from. – haukex Feb 26 '18 at 13:51