Can someone please help with the syntax of subclassing a non-parameterized nested class inside a parameterized outer class, like the following?
public abstract class Foo<T> {
public class Bar {
Set<T> aSet;
}
abstract class Baz {
abstract void doSomething(Map<? extends Bar, T> aMap);
}
}
Then in a separate file, I'm not entirely sure how to define the type variable S here without parameterizing ConcreteBaz. And I can't use a wildcard variable like extends Foo<?>.Baz (I think) because I need access to that generic type variable in the doSomething method:
public class ConcreteBaz extends Foo<S>.Baz { // compilation error
public ConcreteBaz(Foo<S> foo) { foo.super(); }
public void doSomething(Map<? extends Foo<S>.Bar, S> aMap) { ... }
}
Can someone please help me figure out a way around this? Thanks.
Declare S as a type parameter:
public class ConcreteBaz<S> extends Foo<S>.Baz {
Otherwise the compiler will think S is a concrete type instead of a type parameter.
Complete example:
public class ConcreteBaz<S> extends Foo<S>.Baz {
public ConcreteBaz(Foo<S> foo) {
foo.super();
}
#Override
void doSomething(Map<? extends Foo<S>.Bar, S> aMap) {
// ...
}
}
Your problem is that the nested class is nonstatic. I'll check it out, but I'm pretty sure you cannot subclass such classes, except maybe if nested in the same class, or when creating an anonymous type.
Is declaring the nested class static viable? Them it would definitely work.
Edit: scratch all that. I don't have a compilation error. What is S in your case? You do realize you have to pass a concrete class to Foo, and cannot leave it parametrized with an unknown parameter S?
If ConcreteBaz needs to refer to the type parameter, that implies that it needs the type parameter itself:
public class ConcreteBaz<S> extends Foo<S>.Baz {
Related
I got an interesting issue. Consider the following code:
public class GenericsTest
{
// An interface with a generic type.
public interface IObject<K>{}
// An class with a generic type
public static class ObjectA<K>
{
// An inner class without generic type, but implementing the interface with generic Type
// When adding a genericType to this class, it will popup the warning: 'hiding'
public class ObjectB implements IObject<K>
{
}
// A getter with the interface as return Type
public IObject<K> getObjectB()
{
return new ObjectB();
}
}
public ObjectA<String> objectA = new ObjectA<String>();
// This field is yelling for an genericType, though it can't get one because the class doesn't support a generic argument.
public ObjectB genericObject = (ObjectB)objectA.getObjectB();
}
So the issue is that my IDE is complaining about a missing genericType of the genericObject field, and that I should add a SupressWarning annotation to the method. (luckily not code breaking, though still pretty annoying).
I could add a generic type to the inner class, though than it would 'hide' a generic argument, meaning I would need to add a SupressWarning annotation there.
A second fix would be to use a second generic type like <S extends K>. In which case I don't need a SupressWarning annotation at the class. Though when I try to use the getter, my IDE is complaining:
The member type GenericsTest.ObjectA.ObjectB<String> must be qualified with a parameterized type, since it is not static.
So basically I can't use the getter, unless I add an argument of the genericType to the method.
My question is, what is the cleanest way to solve this problem without changing the inner class to a nested class?
Here's a short example that compiles with no issues:
public class Test
{
interface K<T> { }
static class A<T>
{
class B implements K<T> { }
public K<T> getK() { return new B(); }
}
A<String> a = new A<String>();
A<String>.B b = (A<String>.B) a.getK();
}
Notice the last line:
A<String>.B b = (A<String>.B) a.getK();
To be honest, I'm not sure how the example you've given even compiles as far as it does - the class 'ObjectB' is not visible from the main 'GenericsTest' scope, it needs to be prefixed with its' parent class.
Just met this piece of code:
public class Container <T extends Containter<T>> {
protected Map<String, Rule> inspect (T t) {
// ....
}
public boolean isValid () {
// ...
inspect ((T)this);
// ...
}
}
What I'm confused about is the "isValid"-method.
When you replace the line with inspect(this); it won't compile: incompatible types: Container <T> cannot be converted to T.
In subclasses the error does not occur. So I'm asking myself: Could there be a situation where this is of Type other than Container? I mean what would be the type of this in the code above? The explicit cast seems to be unnecessary.
Hope you guys can understand me, I find it hard to explain stuff like that in english.
Thanks!
UPDATE
First, thank you and sorry for letting you wait.
There was confusion about the intention of the inspect method. It is supposed to work on the Container itself (not on the generic Type). Basically only subclasses of Container should be able to use it. So the whole thing is about inheritance.
It's about type safety for sub classes using the inspect method.
Imagine an instantiation like (inside the Container's inspect-method):
List<T> listOfSimilarContainers = new LinkedList<T>();
Now, if there was a subclass like
public class SubContainer extends Container<SubContainer> { }
calling inspect on that class should force the listOfSimilarContainers inside the inspect method to only contain SubContainers.
That is what I wanted to achieve.
Here is a simplified version:
interface Foo<T extends Foo<T>> { }
class Bar implements Foo<Bar> { }
class Baz implements Foo<Bar> { }
Note that Baz inherits from Foo<Bar> and not from Foo<Baz>. The code compiles without any errors.
In other words, the declaration of the interface does not guarantee, that T is the subclass of Foo<T>.
How should work inspect method? If you want to inspect the generic type, then T could be a Class<T> object, else inspect's signature sholud be:
public class Container<T extends Container<T>> {
protected Map<String, String> inspect(Container<T> t) {
}
public boolean isValid() {
// ...
inspect(this);
// ...
}
}
I have superclass Foo. And a class Bar extending it.
public class Bar extends Foo
Function in Foo:
protected void saveAll(Collection<?> many)
Function in Bar:
public void saveAll(Collection<MyClass> stuff) {
super.saveAll(stuff);
}
Getting error :
Name clash: The method saveAll(Collection<MyClass>) of type Bar has the same erasure as saveAll(Collection<?>) of type Foo but does not override it.
What am I doing wrong?
You are overriding the saveAll method with an incompatible type. Perhaps you want to do something like:
public class Bar extends Foo<MyClass>
Function in Foo<E>
protected void saveAll(Collection<E> many)
and function in Bar:
public void saveAll(Collection<MyClass> stuff) {
super.saveAll(stuff);
}
Due to the type erasure feature of Java, the JVM will not be able to know whether it is the method that has the parametrized type MyClass or the first one that should be called.
If possible or applicable, the most commonly used pattern I've seen to avoid this is to change the class Foo to have a parametrized type as well:
public class Foo<T> {
protected void saveAll(Collection<T> many) {}
}
and then have Bar simply implement Foo for your specific type:
public class Bar extends Foo<MyClass> {
public void saveAll(Collection<MyClass> many) {
super.saveAll(many);
}
}
At runtime, the parameter types are replaced by Object.
So saveAll(Collection<?>) and saveAll(Collection<MyClass>) are transformed to saveAll(Collection). This is a name clash.
Look here for details.
You could do this :
public class Foo<T> {
protected void saveAll(Collection many) {
// do stuff
}
}
public class Bar extends Foo<MyClass> {
}
When the compilers compiles to byte code a process called Erasure happens. This remove the type information from the collections. I believe it will manually do the casts etc as part of the process of generating the byte code. If you remove the generic parts of your class (ie the <..> ) then you will see you have two saveAll methods. The error is that you have two save all methods will the same signature. The collections have type object in the byte code.
Try removing the <..> which might make it clearer. When you put the <...> back in then consider the name of the methods. If they are different it should compile.
Also I dont think this is a hibernate problem so this tag should be removed. It is a java generic problem you have.
What you could do here is type the class
public class Bar extends Foo<MyClass>
and then have the method types to T
public void saveAll(Collection<MyClass> stuff) {
super.saveAll(stuff);
}
and then the declaration of Foo would be something like
public abstract class Bar extends Foo<T> {
public void saveAll(Collection<T> stuff) {
}
You just overriding methods with different Signatures.
What will be good idea is to use PECS (Producer - Extends, Consumer - Super) rule described in Effective Java Second Edition by Joshua Bloch.
according to this rule it should looks like this.
In Foo class:
public class Foo<E>{
protected void saveAll(Collection<? super E> many){....}
protected void getAll(Collection<? extends E> many){....}
}
While the existing answers are correct, this error easily occurs when you declare the actual type not in the "extends ..." clause but in the actual class name:
Wrong:
public class Bar<MyClass> extends Foo
{
...
}
Correct:
public class Bar extends Foo<MyClass>
{
...
}
Please take a look at the code snippet below:
interface IFoo<E>{
void doFoo(E env);
}
class A<E>{
public void doA(E env){}
}
public class Foo<E> implements IFoo<E>{
public A<E> a;
#Override
public void doFoo(E env) {
a.doA(env);
}
private class FooInner<E> implements IFoo<E>{
#Override
public void doFoo(E env) {
a.doA(env);
}
}
}
Eclipse complains inside of private inner class a.doA(env) with the following message.
The method doA(E) in the type A<E> is not applicable for the arguments (E)
It doesn't seem like accessibility issue because non-static inner class have an access to all instance variables of the outter class. It looks like I defined my generics wrong somewhere. Can anyone explain me what I am doing wrong here?
You've used the same generic parameter name for the inner class, so the type E of the inner class is shadowing the E of the outer class.
Remove generic parameter from the inner class, like this:
public class Foo<E> implements IFoo<E>{
...
private class FooInner implements IFoo<E>{ // "E" here is the same "E" from Foo
#Override
public void doFoo(E env) {
a.doA(env);
}
}
}
The type of the enclosing class is part of the type of the inner class. FooInner is already parameterized by E, because it's part of the outer class; the explicit parameterization is redundant and incorrect, because it's actually trying to introduce a new type parameter using the same name as the existing one. Just remove the <E> in private class FooInner<E>, and you're golden.
Just wonder why type parameter are not allowed after the class name on the constructor. I mean what's the reason behind this. Is it becos' the type parameter already defined on the class header and so doesn't make sense to have it on the constructor?
Class A <E> {
public E e;
A <E> {
}
}
Just curious
You can define type parameters for a constructor, using the same syntax used for methods.
However, it's important to realize this is a new type parameter, visible only during execution of the constructor; if it happens to have the same name as a type parameter on the class, it will hide that parameter in the larger scope.
class Foo<T>
{
<T> Foo(T bar) /* This "T" hides the "T" at the class level. */
{
...
If you define generics in class level they must be declared during declaration of class.
class A<T>{}
Do you want to declare T when declaring constructor, i.e. something like this:
class A {
public A<T>() {
}
}
But in this case you cannot use T before constructor when you wish to declare fileds:
class A {
private T t; // this will throw compilation error: T is undefined.
public A<T>() {
}
}
I think that this is the reason that Sun defined existing syntax for generics.
Although you can use generic type as parameter of constructor:
class A<T> {
public A(T t) {
}
}
Well, at least the following seems to compile in Eclipse:
public class A{
private boolean same;
public <T> A(T t1, T t2, Comparator<? super T> comparator){
this.same = (comparator.compare(t1, t2) == 0);
}
...
}
As the name says, it is a type parameter, and so its scope is wider than just a constructor or a method.