简体   繁体   中英

Java syntax: public class Me extends Thing<String,Integer,Character>

Disclaimer : I'm new to Java generics and collections.

Background : I've studied the basics of Java Generics here and here . Now I'm trying to understand how they apply to Hadoop's Mapper ( public static class TokenizerMapper extends Mapper<Object, Text, Text, IntWritable> )

Problem : Until today, I had only seen placeholders in the class definition ( public class OrderedPair<K,V> implements Pair<K,V> ), not concrete classes ( public class Me extends Thing<String,Integer,Character> ).

Question : So in general, if I have this...

public class Me extends Thing<String,Integer,Character>

...what does "extends Thing<String,Integer,Character> " mean? It seems that I'm "extending" Thing--that is, the Me subclass inherits the methods of the Thing superclass. Is that inheritance different from Thing<String,String,String> ?

Clarification : Put another way, what is the difference between extending a class without generics (eg, public class X extends Y ) and with generics ( public class X extends Y<a,b,c> )?

A generic class can have different types that it is used with (you choose which type to use it with when you instantiate an object of it). If you extend a generic class and do put concrete types there, as you did here: public class Me extends Thing<String,Integer,Character> that means that Me is extending Thing, but Thing is not generic anymore since it is now bound to the given types.

Previously you could instantiate Thing so:

Thing<String, Character, Integer> myThing = new Thing<>();

but Me is bound now, you can not choose types for it anymore.

Me myMe = new Me();

You could also extend Thing with actual generic types, so your Me class would be still generic.

public class <T, K, V> Me extends Thing<T, K, V>
...
// init with
Me<String, Character, Integer> myMe = new Me<>();

With this you can initialize Me anywhere with given generic types, that will be passed to the generic Thing.

You can also do it partially. So some types of Thing are fixed, and some will be free to choose at the time you instantiate Me.

public class <T> Me extends Thing<String, T, String>
...
// init with
Me<String> myMe = new Me<>();

When extending a class that has a generic type, you can choose to specify the type under which the subclass will be working. For example, class MyList extends ArrayList<String> will have the ArrayList methods, but will be specific to Strings.

In the same manner, when you extend Mapper , you need to specify what types of parameters the mapper will be working on. You do that by providing the type parameters Mapper declares.

Clarification: Put another way, what is the difference between extending a class without generics (eg, public class X extends Y) and with generics ( public class X extends Y<a,b,c> )?

The difference is that in the second case (generic class), you have to conform to the constraints of the types specified by the generic class if you want to compile fine or else you should declare a raw subclass.
Generally, the types specified by a generic class are used by the method of it.
So defining them correctly matters.
You have mainly 3 cases.

Takes this generic class declaration that specifies 3 parameters and that uses them in a myMethod() method :

public class Y <A extends AClass,B extends BClass, C extends CClass> {
    public void myMethod(A a, B b, C c){
         ...
    }
}

1) Your subclass is a raw class :

public class Z extends Y {
       ....
}

In this case, it compiles fine but with warning.
You lose benefits of generic in method invocations. The compiler will consider the method of Z with this signature :

public void myMethod(Object a, Object b, Object c){
     ...
}

2) You subclass is a generic compliant subclass :

public class Z extends Y<ASubClass,BSubClass,CSubClass> {
       ....
}

The compiler will consider the method of Z with this signature :

public void myMethod(ASubClass a, BSubClass b, CSubClass c){
     ...
}

3) Your subclass is a generic class but not compliant with the parameters specified by the parent class, you have a compilation error.

public class Z extends Y<BSubClass,ASubClass,CSubClass> {
       ....
}

If the supertype uses generics, then, as for any generic type, referring to it without generic parameters is the bad mistake of using raw types . You must either use a generic type variable or concrete type for each type variable in the generic type. For example, a variable would be like

Thing<String, Integer, Character> thing = new Thing<>();

Naturally that is different from

Thing<String, String, String> thing = ...

because it handles different types!

Same thing holds for inheritance. In your case you're locking down the type parameters to concrete types.

public class SomeThing extends Thing<String, Integer, Character> { ...

locks down the types that SomeThing can handle, so that SomeThing is actually not a generic class.

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