5

I have declared a method whose argument is subtype of Number as given below:

public static void organizeData(java.util.List<? extends Number> c) {
    //operation on the list
}

I am able to pass any non-parameterized lists as argument. So what is the point of using wildcard <? extends Number>?

List newList = new LinkedList<>();
ClassName.organizeData(newList);

Why do I get element of type Object from c? And not of type Number? Is there a way to allow only subtypes of a type to be passed as arguments as opposed to allowing non-parameterized arguments also?

durron597
  • 31,968
  • 17
  • 99
  • 158
Meena Chaudhary
  • 9,909
  • 16
  • 60
  • 94
  • 5
    You cannot prevent that. A user can always cast first to the rawtype and then to whatever is required. Generics have their limitations and rawtypes always break them. – Boris the Spider Oct 08 '14 at 13:35

3 Answers3

6

You are asking three questions here, I will answer them separately. By the way, you would find it valuable to read the Java Generics FAQ - considered by many to be the canonical reference on the subject:

  1. So what is the point of using wildcard <? extends Number>?

You need to use the wildcard for the times when the parameterized argument is a subclass of Number, say, Integer. For instance:

import java.util.LinkedList;
import java.util.List;

public class NumberTest {
    public static void main(String... args) {
        List<Integer> newList = new LinkedList<Integer>();
        organizeData(newList); // This works!
        anotherMethod(newList); // Doesn't compile
    }

    private static void organizeData(List<? extends Number> list) {

    }

    private static void anotherMethod(List<Number> list) {

    }
}

The second method call fails with the compilation error:

NumberTest.java:9: error: method anotherMethod in class NumberTest cannot be applied to given types;
                        anotherMethod(newList); // Doesn't compile
                        ^
  required: List<Number>
  found: List<Integer>
  reason: actual argument List<Integer> cannot be converted to List<Number> by method invocation conversion
1 error

  1. Why do I get element of type Object from c? And not of type Number?

The reason you get a type of Object in your second case is because you are using the Raw Type. You should never use a raw type if you can avoid it for that reason - you lose all the advantages of compiler type checking.


  1. Is there a way to allow only subtypes of a type to be passed as arguments as opposed to allowing non-parameterized arguments also?

You cannot prevent Heap Pollution in the way you describe because someone can always cast to the Raw type and then to whatever is required. Generics are a compile time only construct, and are ultimately erased after compilation. This is why the Unchecked Type Conversion warning can only be suppressed via annotation.

Community
  • 1
  • 1
durron597
  • 31,968
  • 17
  • 99
  • 158
1

You must remember that in Java generics are a compile-time construct to help with type-safety. At run-time, type erasure converts all generic types to Object and add casting where required. If you bypass the compile-time checking by using raw types (for which the compiler gives you a warning) you have bypassed the benefit of generics (compile-time type checking and run-time safe casting).

John B
  • 32,493
  • 6
  • 77
  • 98
0

Generics in Java are implemented via Type erasure. i.e: type information that you specify in <> do not exist during runtime. During compile time the java compiler makes use of the information given in <> to make sure that everything is in order. If however you do not specify the type in <> as you have done for the variable 'newList' nothing prevents you from passing it to the 'organizeData' method.

Dev Blanked
  • 8,555
  • 3
  • 26
  • 32