Suppose there is classes/interfaces hierarchy:
class A<T>{
T method(T t){
return t;
}
}
class B<T> extends A{
T method(T t){ // method(T)' in 'B' clashes with 'method(T)' in 'A'; both methods have same erasure, yet neither overrides the other
return t;
}
}
As we see there are a compiler error.
I've never came across the rules how to treat generics when inherit. What are the restrictions?
(please don't be confused with inheritance IN generic type itself, i'm asking about inheritance in original classes
also don't be confused with "What is a raw type", I know the raw types, at this question I wanna figure out what are the rules for inheritance)
also don't be confused thinking I wanna fix this error. Of course class B extends A fix it. My question is about: "where can I read the restrictions?"
You will have to use T in your class definition, so that the T wildcard gets bound to the same generic type in both A and B, resolving the conflict:
class B<T> extends A<T>
You didn't prolong A's T, you just introduced a new type parameter T for B. Those Ts are different unless you write B<T> extends A<T>:
class B<T> extends A<T> {
#Override
T method(T t) {
return t;
}
}
Both A's T and B's T would be erased to Object, the class B would contain 2 methods Object method(Object t).
Example 8.4.8.3-4. Erasure Affects Overriding
A class cannot have two member methods with the same name and type
erasure:
class C<T> {
T id (T x) {...}
}
class D extends C<String> {
Object id(Object x) {...}
}
https://docs.oracle.com/javase/specs/jls/se11/html/jls-8.html#d5e14416
To read: 8.4.8.3. Requirements in Overriding and Hiding
You compile error is just as #f1sh says.
Now as to the rules,
They will have the same rules be applied to them. This would include:
Type eraser
Upper, lower, and Unbounded types
Also, generics can be applied to individual methods. How and when you use them depends on what you are trying to do.
For more information https://www.tutorialspoint.com/java/java_generics.htm
Related
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);
}
This question already has answers here:
interface and a class. name clash: same erasure, yet neither overrides other
(3 answers)
Closed 3 years ago.
I have the following structure
public interface A <T extends B> {
List<String> getVals();
void setVals(List<String> vals);
T getContext();
void setContext(T context);
}
public abstract class C <T extends B> implements A {
protected T context;
//Some code
}
public class Regex <T extends B> extends C <T> {
public List<String> getVals() {
//Some code
}
public void setVals(List<String> vals) {
//Some code
}
}
The thing is that, when I compile, I'm getting the following error:
Regex.java:[53,15]
name clash: setVals(java.util.List<java.lang.String>) in Regex and setVals(java.util.List<java.lang.String>) in A have the same erasure, yet neither overrides the other
Why is this? If I ask Intellij to "do the overwrite" for me and it replaces the setVals(List vals) with setVals(List vals) instead.
public void setVals(List vals) {
//Some code
}
It shouldn't be, "exactly the same definition of the method"?
Sorry in advance for my lack of interfaces knowledge
I am guessing you want to implement parameterized type but are actually implementing the raw one.
Replace
public abstract class C <T extends B> implements A
with
public abstract class C <T extends B> implements A<T>
An interesting observation to note here is, that the function setVals is not even using the type parameter T, even then there is a name clash. So it is not obvious at first why this is happening, and why simply extending, A<T> works. At least not to me.
The answer lies here,
The supertype of a class may be a raw type. Member accesses for the
class are treated as normal, and member accesses for the supertype are
treated as for raw types. In the constructor of the class, calls to
super are treated as method calls on a raw type.
and
The type of a constructor (§8.8), instance method (§8.4, §9.4), or
non-static field (§8.3) of a raw type C that is not inherited from its
superclasses or superinterfaces is the raw type that corresponds to
the erasure of its type in the generic declaration corresponding to C.
C in our case is also coincidentally C.
So without extending A<T> from Cs perspective the signature of A is,
void setVals(List vals)
and the compiler doesn't see void setVals(List<String> vals) in Regex as overriding that of A, instead it is considering it overloading, and that too an illegal overload because of type erasure. (You can't overload foo(List) with foo(List<String>)
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.
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.
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.