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

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 (e.g., 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 (e.g., 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.

Related

EnumSet as a parameter in generic Interface

I've a use case :
inteface A{
get(EnumSet<?> fetchModes);
}
class B implements A{
//Here FetchMode is an enum
get(EnumSet<FetchMode> fetchMode){
//Some logic here
}
}
But it's throwing compile time error :
Method get of class B has the same erasure as get(EnumSet fetchMode) of type A but doesn't override it.
I had read that Enums cannot be generic but is there any way to implement this usecase ?
(Basically want the EnumSet to be generic and different implementations can pass different Enums)
A method can override another if the argument types match exactly, but yours doesn't. Eventhough EnumSet<FetchMode> is a subtype of EnumSet<?>, they are not exactly the same. You are not overriding the super class method get(EnumSet<?> fetchModes); in your subclass, rather you are overloading it with a different parameter type. Both of these has the same signature due to erasure when you inspect or decompile the bytecode which is get(EnumSet fetchModes) and your compiler starts complaining.
This is covered in JLS §8.4.8.1:
A class cannot have two member methods with the same name and type
erasure
A naive attempt at fixing the problem is to change the parameter type such that it is compatible with that of the super class, overriding the method properly in your sub class.
#Override
public void get(EnumSet<?> fetchModes) {
}
Though this fixes the compiler error after a fashion, it is still not elegant since it allows your EnumSet to store any Object. But ideally you may want it to store only some subtype of Enum. This idiom supports that.
What you have to do is declare a generic interface with bounded type parameter and then implement it by overriding the method properly as shown below.
public interface A<E extends Enum<E>> {
void get(EnumSet<E> fetchModes);
}
public class B implements A<FetchMode> {
#Override
public void get(EnumSet<FetchMode> fetchModes) {
}
}
try this you have to make the generic type extends Enum:
public class B implements A<FetchMode> {
//Here FetchMode is an enum
public void get(EnumSet<FetchMode> fetchMode){
//Some logic here
}
}
}
interface A<T extends Enum<T>> {
void get(EnumSet<T> fetchModes);
}

How to fix "type argument S is not within bounds of type-variable E" in Java

I'm trying make polymorphic access to different Enum classes by defining some base access method using interfaces. For example:
package com.company;
public interface StatesInterface<E extends Enum<E>> {
E getOneState();
E getTwoState();
E getThreeState();
}
And some implementation:
package com.company;
public enum States implements StatesInterface<States> {
ONE, TWO, THREE, FOUR;
#Override
public States getOneState() {
return ONE;
}
#Override
public States getTwoState() {
return TWO;
}
#Override
public States getThreeState() {
return THREE;
}
}
Note: I know that this code has problem because interface provides static enum values via non-static interface, but I don't have any idea how to solve it.
When I'm trying to use this interface as type constraint in classes, I have got type errors. For example:
package com.company;
public class Lifecycle<S extends StatesInterface> {
private S state;
public void transit() {
state = state.getOneState(); // <---- incompatible types
}
}
In this case I can't assign state.getOneState(); of type Enum to state of type StatesInterface<Enum>.
When I try to change generic type to Lifecycle<S extends StatesInterface<S>> compiles says me Error:(3, 50) java: type argument S is not within bounds of type-variable E.
My goal is make a set of different Enum classes with common interface for creating a new classes that generalize class Lifecycle to a specific Enum type.
Is it possible to achieve this using provided code and how to fix it?
I think what you are looking for is this:
class Lifecycle<S extends Enum<S> & StatesInterface<S>>
In comparison, with your definitions like this:
interface StatesInterface<E extends Enum<E>>
enum States implements StatesInterface<States>
class Lifecycle<S extends StatesInterface>
then getOneState() just returns a type Object extends Enum<Object>, because you were using the raw type for StatesInterface by not giving it type parameters, which is not compatible with the type S extends StatesInterface, thus giving you the "Type mismatch: cannot convert from Enum to S"
By changing your definition to class Lifecycle<S extends Enum<S> & StatesInterface<S>> you allow getOneState() to return S extends Enum<S> & StatesInterface<S> which is of course compatible to be set into a variable of type S, S state = getOneState()
What to take away from this
You should strive to avoid using raw types because they forgo the type safety of generics and also just wont play nice with other generics in general, as you have experienced here.

Intertwined java generic interfaces and classes

I have a very specific problem with java generics. The follwowing classes and interfaces have been predefined:
public interface IFirst<R, T> {...}
public abstract class AbstractFirst<T extends AbstractFirst, L extends IFirst<String, T>> {...}
public interface ISecond extends IFirst<String, AbstractSecond> {...}
public abstract class AbstractSecond extends AbstractFirst<AbstractSecond, ISecond> {...}
Now I've created a following repo definition which seems to be valid:
public abstract class AbstractRepo<T extends AbstractFirst<T, IFirst<String,T>>> {...}
But now that i want to extend it:
public class RepoFirst extends AbstractRepo<AbstractSecond> {...}
I get the following error:
Bound mismatch: The type AbstractSecond is not a valid substitute for the bounded parameter
<T extends AbstractFirst<T,IFirst<String,T>>> of the type AbstractRepo<T>
I cannot change the first four (at least not radically) beacuse they are too heavily ingrained with the rest of the application, but the second two are new and up for change if need be.
Also intrestingly it allows the following (with raw type warnings):
public class RepoFirst extends AbstractRepo {
...
#Override
AbstractFirst someAbstractMethod() {
return new AbstractSecond() {...};
}
...
}
But for code clarity I would like to implement it with clearly defining AbstractSecond as the generic type for Abstract Repo.
What am I missing?
Your AbstractRepo expects an instance of IFirst and not a subtype of IFirst. But your AbstractSecond is clearly not IFirst. (I mean it is, from a OO standpoint but for generics, List<Number> is not the same as List<Integer>). It's ISecond. It might work if you could change your AbstractRepo from IFirst to ? extends IFirst as you did for AbstractFirst.

An interface has two type parameters. Can I implement the interface with the two types being the same, such that they are then compatible?

This is an existing interface:
public interface MyInterface<T, U> {
public T foo(U u);
}
I want to implement this interface under the assumption that T and U are the same type. I thought maybe I could leave the type parameters in as they are, and then as long as I only ever instantiate this particular implementation with two of the same type, that it might work:
public class MyOuterClass<A> {
public class MyClass<T, U> implements MyInterface<T, U> {
#Override
public T foo(U u) {
return u; //error here
}
//even though in the only instantiation of MyClass, T and U are the same
private MyClass<A, A> myInstance = new MyClass<A, A>();
}
But, perhaps unsurprisingly, this doesn't work, as types T and U are incompatible.
So then I thought maybe I could change MyClass to specify that its types would always be the same, by changing it to something like MyClass<A, A> implements MyInterface<A, A> or similar, but I get errors saying that T is already defined.
Is there a way to implement MyClass so that its two types will be the same?
(I'm more of a C++ guy than Java, so sorry if I'm missing something fundamental about Java's generic's here.)
Your myclass needs to look like this:
public class MyClass<T> implements MyInterface<T, T> {
#Override
public T foo(T in) {
return in;
}
}
Let's review what your suggested class definition does:
public class MyClass<T, U> implements MyInterface<T, U>
In this code, T and U do two things each:
in the first occurance they define a type variable of your MyClass class
in the second occurance they specify the concrete type of the MyInterface class
Since inside the body of your class T and U are unbounded type variables (i.e. nothing is known about the actual types), they are assumed to be incompatible.
By having only a single type variable in your MyClass you make your assumption explicit: there's only a single type, and I'm using it for both types of the interface.
Last but not least: remember that the compilation of a type is complete once the source is fully handled. In other words: contrary to what C++ does, "instantiation" of a generic type ("template type" or similar in C++; Sorry for my rusty terminology) does not handle. MyClass<Foo> and MyClass<Bar> are the same type, as far as the JVM is concerned (only the compiler actually distinguishes them).
Define a single type parameter for MyClass:
class MyOuterClass<A> {
public class MyClass<T> implements MyInterface<T, T> {
public T foo(T u) {
return u;
}
}
// Need only one 'A' here.
private MyClass<A> myInstance = new MyClass<A>();
}
When you say
public class MyClass<T> implements MyInterface<T, T> {
... you are defining one generic variable for MyClass and you are saying that it fulfills both the roles T and U in MyInterface.

what could this generic class declaration could mean?

I know this isn't a good question to ask and I might get cursed to ask it but I cannot find any place to get help on this question
Below is a Generic class that appeared in my interview question (which I have already failed). The question was to tell what this Class declaration is doing and in what circumstances this could be used for ?
I have very limited understanding of Generic programming but I understand that 'T' is Type and 'extends' here means that the Type should have inherited 'SimpleGenericClass' but I do not understand the '?' at the end and in what circumstances this Class could be potentially used for
public abstract class SimpleGenericClass<T extends SimpleGenericClass<?>> {
}
First, because the class SimpleGenericClass is abstract, it is meant to be subclassed.
Second, it is a generic class which means that inside the class somewhere you will almost assuredly be using the generic parameter T as the type of a field.
public abstract class SimpleGenericClass<T...> {
T x;
}
Now the first interesting thing here is that T is bounded. Because it is declared as T extends SimpleGenericClass<?> it can only be SimpleGenericClass<?> or some subclass of SimpleGenericClass<?>. You also asked about thr ?. That's known as a wildcard and there is a pretty good explanation of it at the Java Tutorial on Wildcards. In your case we would say this is a "SimpleGenericClass of unknown." It is needed in Java because SimpleGenericClass<Object> is NOT the superclass of SimpleGenericClass<String>, for example.
The second interesting thing though is that since T is a SimpleGenericClass of some sort, your class is more than likely defining recursive structures. What comes to my mind are trees (think of expression trees) where SimpleGenericClass is the (abstract) node type, designed to be subclassed with all kinds of specialized node types.
UPDATE This SO question on self-bounded generics might be helpful to you.
UPDATE 2
I went ahead and put together some code that illustrates how this can be used. The app doesn't do anything but it does compile and it shows you how the generic bounds can supply some possibly-meaningful constraints.
public abstract class Node<T extends Node<?>> {
public abstract T[] getChildren();
}
class NumberNode extends Node {
int data;
public Node[] getChildren() {return new Node[]{};}
}
class IdentifierNode extends Node {
int data;
public Node[] getChildren() {return new Node[]{};}
}
class PlusNode extends Node {
NumberNode left;
NumberNode right;
public NumberNode[] getChildren() {return new NumberNode[]{};}
}
The nice thing here is that NumberNode[] is a valid return type for PlusNode.getChildren! Does that matter in practice? No idea, but it is pretty cool. :)
It's not the greatest example, but the question was rather open ended ("what might such a thing be used for?"). There are other ways to define trees, of course.
This really only means that you allow the user of class SimpleGenericClass to parametrize instances of the class with the type T. However, T cannot be any type, but must be a subtype of SampleGenericClass (or SampleGenericClass itself).
In the remainder of the code of class SimpleGenericClass you may use type T in method signatures.
Let's assume for a second that SimpleGenericClass is not abstract. When using it, you could then write:
new SimpleGenericClass<SampleGenericClass<String>>();
I.e. you parametrize SimpleGenericClass with SampleGenericClass and SampleGenericClass with String.
This basically sais: in this class you have a Type placeholder called T, and a restriction on that placeholder, it must be of type SimpleGenericClass or something that extends it. Once you obey that rule you can create instances of your class and give an actual type to T, that later on can be used in methods of that class, something like this:
public class C <T extends Number>{
public void doSomething(T t) {
}
public static void main(String... args) {
//works:
C<Number> c = new C<Number>();
c.doSomething(new Number() {
//Aonimous implementation of number
});
//won't work
//C<Object> c = new C<Object>();
C<Integer> c2 = new C<Integer>();
c2.doSomething(new Integer(1));
//won't work
//c2.doSomething(new Number() {
//Aonimous implementation of number
//});
}
}
The SimpleGenericClass<?> is pretty redundant at this point. If another generic type is needed on this class, you can have more than one (SimpleGenericClass<T extends SimpleGenericClass, T2 extends Whatever>)
By definition it says that the SimpleGenericClass can work on a type <T> which is subclass of SimpleGenericClass.
So I assume there will be some operations which will work on <T>.
Now to see why one would define a template like this - (not much I can think of , really ) may be a scenario where the SimpleGenericClass is an abstract class (just realized it is as per OP :P) and expects that it can work on any concrete classes ?
Guys what do you think ?
I guess you have got the question in this form (T instead of ?):
public abstract class SimpleGenericClass<T extends SimpleGenericClass<T>>
Take a look at this code:
abstract class Foo<SubClassOfFoo extends Foo<SubClassOfFoo>>
{
/** subclasses are forced to return themselves from this method */
public abstract SubClassOfFoo subclassAwareDeepCopy();
}
class Bar extends Foo<Bar> {
public Bar subclassAwareDeepCopy() {
Bar b = new Bar();
// ...
return b;
}
}
Bar b = new Bar();
Foo<Bar> f = b;
Bar b2 = b.subclassAwareDeepCopy();
Bar b3 = f.subclassAwareDeepCopy(); // no need to cast, return type is Bar
The trick going on with Foo<SubClassOfFoo extends Foo<SubClassOfFoo>> is:
Any subclass of Foo must supply a type argument to Foo.
That type argument must actually be a subclass of Foo.
Subclasses of Foo (like Bar) follow the idiom that the type
argument they supply to Foo is themselves.
Foo has a method that returns SubClassOfFoo. Combined
with the above idiom, this allows Foo to formulate a contract that
says “any subclass of me must implement subclassAwareDeepCopy() and
they must declare that it returns that actual subclass“.
To say that another way: this idiom allows a superclass (such as an Abstract Factory) to define methods whose argument types and return types are in terms of the subclass type, not the superclass type.
The trick is done for example in Enum JDK class:
public abstract class Enum<E extends Enum<E>>
Refer here for more details.

Categories

Resources