THE Java™ Programming Language, Fourth Edition

(Jeff_L) #1
supertypes) so S is a subtype of Object and T is subtype of Number. Because S is a subtype of
Object and not String, the check fails.

The check failed, so the generic method is not more specific than the non-generic method. Since neither
method is more specific than the other the call is ambiguous and the compiler rejects it as such.


Informally, one method is more specific than another if all calls to the first method could be handled by the
second. Looking at the two methods here, the most general signature of the generic method would have
parameters of type Object and Number. So if we consider the first parameter, anything we pass to the
non-generic method must be a String, and a String is always an Object, so the generic method could
accept all first arguments to the first method. So considering just the first parameter, the non-generic method
is more specific than the generic method. But conversely, the generic method can accept first arguments that
are not String objects, so the generic method is not more specific than the non-generic method. Considering
the second parameter, you can pass arbitrary objects to the non-generic method but only Number objects to
the generic method. Consequently, the non-generic method is not more specific at the second parameter and
so it is not more specific. As neither is more specific, the call is ambiguous.


You can remove the ambiguity in two ways. You can cast the first argument to Object so that the
non-generic method is no longer applicable and so the generic version must be called:


m((Object) "hello", Integer.valueOf(29));


The alternative is to cast the second argument to Object so that the generic method is no longer applicable
and so the non-generic version must be called:


m("hello", (Object) Integer.valueOf(29));


Note that parameterizing the invocation itself does not automatically exclude the non-generic methodits
applicability is determined without consideration of the type arguments.


Overloading, even without involving generics, should be used judiciously and only to improve the resulting
clarity of the program. With generics added to the mix, it is even easier to create programs in which the intent
can only be established by detailed recourse to the language specification. Avoid mixing generic and
non-generic overloads of a method unless you have an extremely compelling reason.


11.7. Class Extension and Generic Types


Generic types add an extra dimension to the type system, and force you to think more deeply about how to
define classes and interfaces and how to use existing classes and interfaces. You can extend a non-generic
type to produce either a generic or a non-generic subtype. You can extend a generic type to produce a generic
subtype, or you can extend a specific parameterized type to yield a non-generic subtype, or you can combine
both. This degree of flexibility can be overwhelming, but the key thing to focus on is what abstraction your
new class or interface represents and what abstraction the class or interface you are inheriting from represents.


For example, the List interface is generic and represents a list of elements of some kind. If you
implement that interface then you may be providing a general-purpose implementation that can deal with
arbitrary element types, and in that case your class would also be a generic class, such as


class GeneralList implements List { / ... / }

Free download pdf