Using static nested class as generic parameter - java

I'm trying to create an interface with a bounded type parameter, with implementations supplying static nested classes to implement this parameter, as follows:
public interface InterfaceProblem<T extends IMyParameter>{
T getParameterInstance();
}
interface IMyParameter {}
class MyClass implements InterfaceProblem<MyParameter> {
public MyParameter getParameterInstance() {
return new MyParameter();
}
class MyParameter implements IMyParameter{}
}
This gives me a compile error "MyParameter cannot be resolved to a type" on the MyClass declaration and its method. This disappears if I move the static class to its own type:
class MyClass implements InterfaceProblem<MyParameter> {
public MyParameter getParameterInstance() {
return new MyParameter();
}
}
class MyParameter implements IMyParameter{}
However, I'd like to avoid that, since the MyParameter implementation is closely related to the MyClass implementation. Is there a better way I can acheive this? Is this correct compiler behaviour? (I'm using Eclipse Mars and Oracle jdk1.8.0_60)

You're missing an import:
import com.example.MyClass.MyParameter;
While the MyParameter type is on scope for the getParameterInstance() method's return type, it is not for the MyClass's binding of <T>

Related

Implementing a method that returns a Class

There is an interface with a method that returns a Class, like so.
public interface MyInterface {
public Class<? extends Object> returnsSomething ();
}
I have to create a class which implements the interface, like so.
public class MyClass implements MyInterface {
public Class<? extends Object> returnsSomething () {
return Object; // This is currently an error.
}
}
The return line in the implementation of returnsSomething in MyClass is incorrect. The IDE hints "cannot find symbol Object".
What correction do I need to apply in returnSomething's body to compile successfully?
Object is just the name of the class.
Object.class is the instance of the Class<Object> class that represents the Object class. See Class.
So you need:
return Object.class;
Your return type is incorrect in your method. You need to understand that this '.class' is used in Java for code Reflection. Generally you can gather meta data for your class such as the full qualified class name, list of constants, list of public fields,etc... So in your example you are basically saying that the Class type to be returned for the wildcard used will either be Object or Subclass of object to be returned at Runtime. Note that you want Java to determine the object returned at Runtime.

Java nested genericsType

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.

Guava TypeToken and generic classes

I'm using Guava TypeToken class in my project, but I'm getting an unexpected result.
I have MyGenericClass<T>:
public class MyGenericClass<T> implements MyInterface {
private TypeToken<T> recordType;
public MyGenericClass(String name) {
this.recordType = new TypeToken<T>(getClass()) {};
// ...
}
// ...
#SuppressWarnings("unchecked")
protected Class<T> getRecordType() {
return (Class<T>) recordType.getRawType();
}
}
So if I instantiate an object via new MyGenericClass<String>() and then invoke getRecordType() I expect to get java.lang.String, instead I'm getting java.lang.Object.
But, if I extend generic class:
public class MyStringImpl extends MyGenericClass<String> {
// ...
}
and instantiate this new class: new MyStringImpl() then I get the correct result.
Why is this happening? Is this the expected behaviour of TypeToken?
To add some boring details to Ian's answer: It would be nice if TypeToken worked the way you expected, but this is impossible. When you declare
public class MyGenericClass<T> implements MyInterface {...}
the JVM sees something like
public class MyGenericClass<Object> implements MyInterface {...}
due to erasure.
But when you declare
public class MyStringImpl extends MyGenericClass<String> {...}
then in the definition of MyStringImpl the generics used are recorded and can be obtained via Class#getGenericSuperclass(). That's (a part of) the magic behind TypeToken.
To make this work you need the same anonymous subclass trick when you instantiate MyGenericClass:
new MyGenericClass<String>() {}
If you do that then you will get String returned by getRecordType. The reason why this is necessary is explained in the JavaDocs for that TypeToken constructor.
Clients create an empty anonymous subclass. Doing so embeds the type parameter in the anonymous class's type hierarchy so we can reconstitute it at runtime despite erasure.

Overriding non-parameterized classes nested in a parameterized outer class in Java

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 {

Optional parametrization in Java with Generics

Is is it possible to specify default type when parametrzing a class?
Example:
// abstract class
public abstract class AbsClass<T1 extends Par1Class, T2 extends Par2Class> {
// code
}
// parametrized imlementation class
public class RealClass extends AbsClass<ClassThatExtendsPar1, ClassThatExtendsPar2Class> {
// code
}
// non-parametrized imlementation class
public class RealClass extends AbsClass {
// code
}
in my implementation I have to specify NONE or ALL parameters. Is possible to make the second parameter non-mandatory, something like this:
// abstract class
public abstract class AbsClass<T1 extends Par1Class, T2 extends Par2Class : default Par2Class > {
// code
}
// parametrized only mandatory imlementation class
public class RealClass extends AbsClass<ClassThatExtendsPar1> {
// code
}
Simple answer: no, java does not support default parametrizations like that.
There is never really a good reason to do this. Typically you specify generic type parameters because some method arguments take or return a parameter of that type. If unspecified were valid, that would seem to suggest you intended not to perform any meaningful implementation of those methods.
Anyway, to solve your perceived problem, just specify "Object" for any type parameter that you don't care to specify. Or extend the abstract class with another abstract class which has only one type parameter (specifying Object as the second type parameter in your extends call).
Well, the correct solution for your case may be
// parametrized only mandatory imlementation class
public class RealClass<StillGeneric extends Par1Class>
extends AbsClass<ClassThatExtendsPar1, StillGeneric> {
// code
}

Categories