How do I create an instance of a parameterized interface [duplicate] - java

This question already has answers here:
Create instance of generic type in Java?
(29 answers)
Closed 7 years ago.
I have this code:
ObjProcessor processor = getProcessor();
MyClass myObj = getObjToProcess();// MyClass extends PersistentObj
and classes:
public class ObjProcessor {
public <OP extends PersistentObj) void process(Class<OP> objClazz, OP object, Modifier<OP> modifier) {
...
}
}
public interface Modifier<T> {
void modify(T obj);
}
I am stuck. How do I create an instance of the Modifier to be able to invoke:
processor.process(myObj.getClass(), myObj, ???);
After Ron C's comment, I created this Modifier:
Modifier<MyClass> mod = new Modifier<MyClass>() {
#Override
public void modify(MyClass obj) {
// empty
}
};
proc.process(myObj.getClass(), myObj, mod); // compilation error!
Eclipse gave this error:
The method process(Class<OP>, OP, Modifier<OP>) in the type ObjProcessor is not applicable for the arguments (Class< capture#1-of ? extends MyClass>, MyClass, Modifier<MyClass>)

You can create an anonymous inner class as an instance of the Modifier interface:
processor.process(myObj.getClass(), myObj, new Modifier<MyClass>() {
#Override
public void modify(MyClass obj) {
//Add implementation here
}
});
If you're using java 8, you can also use lambada expressions. Because your interface is considered as a Functional Interface (interface with only one method), you can use lambada expression instead of creating anonymous class:
processor.process(myObj.getClass(), myObj, obj -> {
//Add implementation here
});
For the second problem, the solution is to change the declaration of process to:
public <OP extends ObjProcessor> void process(Class<? extends OP> objClazz, OP object, Modifier<OP> modifier) {
}
I've replaced Class<OP> with Class<? extends OP>. The older decleration only works with: MyClass.class, but not with: instanceOfMyClass.getClass().
The reason for this is that the Class<OP> type argument can't accept Class<ClassExtendsOP> as an argument, it's only allow one class.
If your'e using MyClass as OP,
when you're using MyClass.class, you're always getting Class<MyClass> object. But when you're using instanceOfMyClass.getClass(), you can get Class<ClassExtendsMyClass>, which not match the argument type.

Related

Java generic interface implementation cannot omit type parameter?

I found that in Java I could use anonymous class to implement interface like Runnable (non-generic). I could also declare a variable without specifying type parameter on the right of "=". But I found for generic type, I cannot omit this:
import java.util.ArrayList;
import java.util.List;
interface Normal {
Integer f();
void g();
}
interface Generic<T> {
T f();
void g();
}
public class GenericInterface {
public static void main(String[] args) {
List<Integer> li = new ArrayList<>(); // ArrayList without type parameter, OK
Runnable r = new Runnable() {
#Override public void run() {}
};
Normal n = new Normal() { // declare implementation, OK.
#Override public Integer f() {
return new Integer(0);
}
#Override public void g() {}
};
Generic<Integer> i = new Generic<>() { // Why need type paramter here?
#Override public Integer f() {
return new Integer(0);
}
#Override public void g() {}
};
}
}
As you could see, javac report compilation failure for this line:
Generic<Integer> i = new Generic<>() {
While the compiler is smart enough to compile List<Integer> li = new ArrayList<>(), when compiler already know the real type from the left of this statement, why it still needs me to write new Generic<Integer>() { ?
Or Java prevents generic interface implementation without specifying the type parameter? What is the reason?
In Java 8 the compiler gives this error:
GenericInterface.java:23: error: cannot infer type arguments for Generic<T>
Generic<Integer> i = new Generic<>() { // Why need type paramter here?
^
reason: cannot use '<>' with anonymous inner classes
where T is a type-variable:
T extends Object declared in interface Generic
1 error
I cannot see where this is explicitly forbidden in the Java 8 edition of the JLS (but I might have missed it).
In any case, this is permitted in Java 9 and later. It was one of the changes made as part of Project Coin (JEP 213):
"3. Allow diamond with anonymous classes if the argument type of the inferred type is denotable. Because the inferred type using diamond with an anonymous class constructor could be outside of the set of types supported by the signature attribute, using diamond with anonymous classes was disallowed in Java SE 7. As noted in the JSR 334 proposed final draft, it would be possible to ease this restriction if the inferred type was denotable."
This improvement was delivered in Java 9.
What is the reason?
The technical reason is given in the quoted text above.

Can I force a constructor to put a stricter bound on its generic type?

In java, generic classes have constructors to construct instances of some generic type. This is simple, and callers of the constructor can specify any type that is within bounds.
Is it possible to have a constructor that puts stricter bounds on that generic type?
E.g., have a constructor that forces the generic type to be String.
public class GenericClass<T extends Serializable> {
public GenericClass() {
// normal constructor
}
public GenericClass(String argument) {
// Can I force this constructor to construct a `GenericClass<String>`?
}
}
// The first constructor can have any type
GenericClass<String> stringInstance = new GenericClass<>();
GenericClass<Integer> intInstance = new GenericClass<>();
// The second constructor is limited to `GenericClass<String>`
stringInstance = new GenericClass<>("with generic type String is okay");
intInstance = new GenericClass<>("with other generic type is not okay");
I would like to have the last line fail because of incompatible types.
Is this possible?
public GenericClass(String argument)
The problem with this is how is the compiler supposed to know that String is T? There is no link between the parameter and the generic type parameter and no way to specify one. You could use
public GenericClass(T argument)
and construct it with
new GenericClass<>("foo");
but that would allow GenericClass to be instantiated with an object of any type.
You can achieve roughly what you want using inheritance, though you need to introduce a second class:
class GenericClass<T extends Serializable> {
public GenericClass() {
}
}
class StringClass extends GenericClass<String> {
public StringClass(String argument) {
}
}
You can introduce an interface and have both classes implement that if you want to avoid using inheritance. That's what I'd do.
One way to cause the last line to fail is this:
public class GenericClass<T extends Serializable> {
public GenericClass() {
// normal constructor
}
public GenericClass(T argument) {
}
}
But obviously that doesn't stop people from calling new GenericClass<>(1).
Alternatively, you can write a factory method ofString:
public static GenericClass<String> ofString(String s) {
GenericClass<String> gc = new GenericClass<>();
// do stuff to gc
return gc;
}

Reference Object Through Its Implemented Generalized Interface [duplicate]

This question already has answers here:
Java generic interfaces with typesafe implementations
(2 answers)
Closed 8 years ago.
I have a converter interface that looks something like this:
public interface MyTypeConverter<T>
{
public MyObject toMyObject(T obj);
public T fromMyObject(MyObject mo);
}
I also have an implementation of that interface:
public class ABCTypeConverter implements MyTypeConverter<ABCObject>
{
public MyObject toMyObject(ABCObject obj)
{
...do conversion...
}
public ABCObject fromMyObject(MyObject mo)
{
...do conversion...
}
}
And a factory that evaluates the objects type, and returns an appropriate converter implementation:
public class MyTypeConverterFactory
{
public static MyTypeConverter<?> create(Object source)
{
if ( source instanceof ABCObject )
return new ABCTypeConverter();
...and so on...
}
}
Now the problem I am having is in referencing the Factory's returned converter instance by using the interface:
MyTypeConverter<?> converter = MyTypeConverterFactory.create(someObject);
MyObject mo = converter.toMyObject(someObject);
The last line gives me the following compile-time error:
The method toMyObject(capture#3-of ?) in the type MyTypeConverter<capture#3-of ?>
is not applicable for the arguments (ABCObject)
So how could I reference the converter in a generic fashion?
EDIT
The core of my question is: How do I call a method on an interface reference without first casting to the underlying concrete type? And if I can't, then what is the point of creating a generic interface to begin with? I.E., How do I do this (regardless of how I get the reference):
MyTypeConverter<?> converter = MyTypeConverterFactory.create(someObject);
MyObject mo = converter.toMyObject(someObject);
Without first casting "converter" to its underlying concrete type?
This is a total anti-pattern approach to the FactoryMethod Pattern:
if ( source instanceof ABCObject )
return new ABCTypeConverter();
...and so on...
Don't do that it will never scale and will never be maintainable.
What is wrong with:
TypeConverter<ABCObject> tc = new TypeConverter<ABCObject>();
That is how every sane framework that implements something like this works.
For example:
com.google.common.base.Converter
Look at the how Jackson does it for JSON Serializer/Deserializers as well.
There is a way with Guava to get an instance of a type T
Class<T> klass = (Class<T>) new TypeToken<T>(getClass()) {}.getRawType();
Then you can do klass.newInstance(); but this is hacky was well.
You can try with Polymorphism as well instead of making it Generic.
Just return the interface reference instead of actual object reference from factory's create() method. At run-time the actual object decide what method should be called based on overridden method logic.
In below sample code I have created an interface MyTypeConverterObject that is implemented by all the classes that are part of MyTypeConverter interface.
Now simply return MyTypeConverterObject from factory's create() method.
Sample code:
interface MyTypeConverterObject {}
class ABCObject implements MyTypeConverterObject {}
class XYZObject implements MyTypeConverterObject {}
class MyObject {}
interface MyTypeConverter {
public MyObject toMyObject(MyTypeConverterObject obj);
public MyTypeConverterObject fromMyObject(MyObject mo);
}
class ABCTypeConverter implements MyTypeConverter {
public MyObject toMyObject(MyTypeConverterObject obj) {
return new MyObject();
}
public MyTypeConverterObject fromMyObject(MyObject mo) {
return new ABCObject();
}
}
class MyTypeConverterFactory {
public static MyTypeConverter create(Object source) {
if (source instanceof ABCObject) {
return new ABCTypeConverter();
}
return ...;
}
}
A Factory method should return product of same type i.e. product that implements same interface.
For example: A car factory can return cars of different type but can't produce bike.
If you need to return different type of products then use Abstract factory.

Java generics seem to work differently for classes than for methods

I'm following this:
http://rickyclarkson.blogspot.com/2006/07/duck-typing-in-java-and-no-reflection.html
And I'm trying to adapt this:
<T extends CanQuack & CanWalk> void doDucklikeThings(T t)
{
t.quack();
t.walk();
}
To this:
public class Activate<D extends CanQuack & CanWalk> {
D d = new MyWaterFowl(); //Type mismatch
}
Even though MyWaterFowl implements those interfaces.
I'd like a solution that never mentions MyWaterFowl in the <>'s since I'm going to eventually just be injecting it (or anything else that implements those interfaces).
If your answer is basically "You can't do that, what type would it even be?". Please explain why it's working for the method doDucklikeThings and conclusively state if it is impossible to do the same with a class or, if it is possible, how to do it.
The T in doDucklikeThings must be something valid since it's working. If I passed that into a class what would I be passing in?
As requested here's the MyWaterFowl code:
package singleResponsibilityPrinciple;
interface CanWalk { public void walk(); }
interface CanQuack { public void quack(); }
interface CanSwim { public void swim(); }
public class MyWaterFowl implements CanWalk, CanQuack, CanSwim {
public void walk() { System.out.println("I'm walkin` here!"); }
public void quack() { System.out.println("Quack!"); }
public void swim() { System.out.println("Stroke! Stroke! Stroke!"); }
}
Remember I've confirmed that doDucklikeThings works. I need the syntax that will let me inject anything that implements the required interfaces.
This does not work, because the class/method is generic and the caller of your class/method can set D to MyAmericanEagle.
Activate<MyAmericanEagle> active = new Activate<>();
Then your code would result in
MyAmericanEagle d = new MyWaterFowl();
Since that makes no sense (would result in ClassCastException) the compiler rejects it.
// Type mismatch
Even though MyWaterFowl implements those interfaces.
It's not about the type D implementing those interfaces (and/or extending a class). A generic type variable is bound to a specific type argument. That type might be completely different than MyWaterFowl so you cannot use them interchangeably.
To answer your edit, you are doing two completely different things in your two snippets. The type variable is declared with some bounds. It is therefore guaranteed to be a type that implements some interface (or extends some class), but you don't know which type that is, in either case.
I want to clarify the two things you did, ie. what you expect in your question and the solution you gave in your answer.
Generics are a compile time feature where the server code, for example
class Activate<D extends CanWalk & CanQuack> {
D instance;
public Activate(D d) {
this.instance = d;
}
public D getInstance() {
return instance ;
}
}
declares a type variable. This is a variable. Within its declaration context, you don't know its exact type at compile time.
The client code, for example,
new Activate<>(new MyWaterFowl());
binds the type MyWaterFowl to the type variable declared in Activate. So the client code knows what D is at compile time.
If the following
public D getInstance() {
D someRef = new MyWaterFowl();
return someRef;
}
was allowed in the server code, this would fail
Activate<SomeOtherBird> activate = new Activate<>(new SomeOtherBird());
SomeOtherBird reference = activate.getInstance();
Generics guarantee that getInstance() is type safe because it is declared as returning whatever type is bound to the type variable D. In this case, that is SomeOtherBird. If the getInstance() code above was allowed, type safety would be broken as getInstance() would return something other than what was bound to it.
This doesn't change the fact that within your server code (the generic class), you do know the bounds of D, ie. it is both a CanQuack and a CanWalk. Therefore, anything an object of those types can do, so can an object referenced by a D variable do.
It actually can be done.
The generic code between <>'s is fine. It's not different for methods and classes. Just needed to finish doing the dependency injection:
public class Activate<D extends CanQuack & CanWalk> {
private D d;
Activate(D d) {
this.d = d;
}
void doDuckLikeThings() {
d.quack();
d.walk();
//d.swim(); //Doesn't work
//And shouldn't since that was the whole point of ISP.
}
}
public class MainClass {
public static void main(String[] args) {
Activate<MyWaterFowl> a = new Activate<>(new MyWaterFowl());
a.doDuckLikeThings();
}
}
Thought I'd provide an answer that says what to do to fix it.
Type of class which extends Object is different with type of Object. This means you cannot instantiate super class for its extenders.
When you compile this:
1 public class Sample<T extends Object> {
2 public Sample() {
3 T t = new Object();
4 }
5 }
you got incompatible types error.
Sample.java:3: error: incompatible types
T t = new Object();
^
required: T
found: Object
where T is a type-variable:
T extends Object declared in class Sample
1 error
Its same as when you do it in non generic form:
1 public class Sample{
2 public Sample() {
3 }
4 }
5
6 class SampleExtends extends Sample {
7 public SampleExtends() {
8
9 }
10 }
11
12 class User {
13 public User() {
14 SampleExtends se = new Sample();
15 }
16 }
you get this error from compiler: incompatible types
Sample.java:14: error: incompatible types
SampleExtends se = new Sample();
^
required: SampleExtends
found: Sample
1 error
What do you expect the actual type of D to be in the second code snippet?
Let's say something does this:
Activate<Daffy> myActivate = Activate<Daffy>();
What should happen then? This means D needs to be of type Daffy but you are trying to set d to an instance of MyWaterFowl.
Generics works just the same for classes as for methods.
You seem to misunderstand Generics a bit. A type parameter <T extends CanQuack & CanWalk> is not a definition of a new type alias valid for the scope of method or class, it is a placeholder for some type, which is later filled by someone else.
For a generic method like your example
<T extends CanQuack & CanWalk> void doDucklikeThings(T t)
{
t.quack();
t.walk();
}
the caller of the method decides which type to substitute for T (within the limits stated by the bounds).
So one can use
doDuckLikeThings(myWaterfowl);
and the compiler guesses what type parameter you want here (likely the type of the myWaterfowl variable).
For a generic class, it is the code which creates an instance of the class who decides the actual type parameter.
So I can say
Activate<Duck> duckActivator = new Activate<Duck>();
After this, the duckActivator instance is an instance of Activate<Duck>, and inside it, D is now bound to Duck.
Now obviously your variable declaration says
Duck d = new MyWaterfowl();
and this doesn't work.
It wouldn't work in a generic method, either – this one is invalid just as well:
<T extends CanQuack & CanWalk> void doDucklikeThings()
{
T t = new MyWaterfowl();
}
I'd like a solution that never mentions MyWaterFowl in the <>'s since I'm going to eventually
just be injecting it (or anything else that implements those interfaces).
Then don't mention its constructor either.
Whoever is injecting your duck like object also has to decide the actual type parameter – i.e. this should be the one who creates the Activate instance. And this can't change after construction of your Activate object.
A candidate solution to the actual problem
If this restriction doesn't fit for you (e.g. because the same instance of Activate will need to be able to work with different types of duck like objects one after another), maybe a type parameter is not for you.
Maybe a generic wrapper with a wildcard type parameter for a variable helps instead.
Take this generic wrapper (or something similar):
public class Holder<T> {
private final T t;
public T get() { return t; }
public Holder(T t) { this.t = t; }
}
Then your Activate class doesn't need the type parameter, but just holds a holder variable with a wildcard type parameter. (Note that the actual Holder instantiation has a non-wildcard type argument.)
public class Activate {
private Holder<? extends CanQuack & CanWalk> holder;
public <D extends CanQuack & CanWalk> void setDuckLike(D d) {
this.holder = new Holder<D>(d);
}
public Activate() {}
public void doDucklikeThings() {
holder.get().quack();
holder.get().walk();
}
}
Now you do something like this:
Activate a = new Activate();
a.setDuckLike(new Duck());
a.doDucklikeThings();
a.setDuckLike(new MyWaterfowl());
a.doDucklikeThings();

Java - Overriding return type of extended interface when return type uses generics for own method parameter types

i've stumbled upon a curiosity in the java inheritance, and I wanted you to ask for better ideas on that:
Assume two interfaces A and A1
Interface A1 extends A
Interface A has a method which returns a generic type.
The generic type would be like GenericType<T>.
A basic idea is now to change this generic return type from
GenericType<Object> in Interface A into
GenericType<String> in Interface A1
Well seems to be easy at first (bad things will come later on)
We declare Interface A like
public interface InterfaceA {
public GenericType<? extends Object> getAGenericType();
}
and Interface A1 like
public interface InterfaceA1 extends InterfaceA
{
#Override
public GenericType<String> getAGenericType();
}
As you see we are forced to write GenericType<? extends Object> in Interface A itself to allow overriding it with generic based "subclasses".
(In fact the generic parameter of the generictype is subclassed not the generic type itself)
Now assume the GenericType has its own method looking like:
public interface GenericType<D>
{
public void doSomethingWith( D something );
}
Now trying to instantiate A1 works great.
Rather trying to instantiate A will suck. To see why look at this "use the interface" class:
public class LookAtTheInstance
{
#SuppressWarnings("null")
public static void method()
{
InterfaceA a = null;
InterfaceA1 a1 = null;
GenericType<String> aGenericType = a1.getAGenericType();
GenericType<? extends Object> aGenericType2 = a.getAGenericType();
Object something = null;
aGenericType2.doSomethingWith( something );
}
}
You ask: "And now?"
It does not work on the last lines. In fact the parameter "something" is not even from type "Object" it is from Type "? extends Object". So you cannot pass the declared "Object" type. You can't pass anything at all.
So you end up declaring nice interfaces which, as it turns out, cannot be instantiated right.
Do you have ideas how to model such a use case, where the subclasses will have to override the return type, while the return type is a generics?
Or how would you go around such a model case?
Or am I just missing a simple point in the generic declaration and my example is possible this way?
----------- (1) edit due to answers -----------
A very good basic idea is making the interface A more abstract! I had exactly the same idea first, but... (this has to come)
Assume doing this:
We introduce a new interface AGeneric
public interface InterfaceAGeneric<T>{
public GenericType<T> getAGenericType();
}
Now we will have to extend A and A1 from this new interface:
public interface InterfaceA extends InterfaceAGeneric<Object>{}
public interface InterfaceA1 extends InterfaceAGeneric<String>{}
That works fine, althought it breaks the path of the original inheritance.
If we want A1 still be extendable from A, we have to change A1 to
public interface InterfaceA1 extends InterfaceA, InterfaceAGeneric<String>{}
and there a problem is again. This does not work, since we extend indirectly the same interface with different generic types. This is unfortunately not allowed.
You see the problem?
-
And to point to another circumstance:
If you cast the GenericType<? extends Object> to GenericType<Object> it obviously works.
Example:
public class LookAtTheInstance
{
public static void main( String[] args )
{
InterfaceA a = new InterfaceA()
{
#Override
public GenericType<? extends Object> getAGenericType()
{
return new GenericType<Object>()
{
#Override
public void doSomethingWith( Object something )
{
System.out.println( something );
}
};
}
};
;
#SuppressWarnings("unchecked")
GenericType<Object> aGenericType2 = (GenericType<Object>) a.getAGenericType();
Object something = "test";
aGenericType2.doSomethingWith( something );
}
}
So it seems for me that the resolving of the parameter type of the method
public interface GenericType<D extends Object>
{
public void doSomethingWith( D something );
}
is wrong.
If D is unified with "? extends Object" why the parameter type is not forced to be "Object"?
Wouldnt this make more sence?
A basic idea is now to change this generic return type from GenericType in Interface A into GenericType in Interface A1
This is not possible, because Java Generics are invariant. [1]
As you found out, you cannot have an interface declaring a method that returns GenericType<Object> and in a sub interface override the method to return GenericType<String>: The latter return type is not a subtype of the former. And for good reason!
You tried to
extend indirectly the same interface with different generic types. This is unfortunately not allowed.
There is no way this could possibly work: E.g. what should be the type of E in public E set(int index, E element) in a class that implemented both List<String> and List<Object>? Your subclassed interface would have to produce a similar hybrid: The return value of getAGenericType in the sub interface would have to implement both the GenericType<String> and the GenericType<Object> interface. And as we saw, this is impossible.
The compiler does not know what you are going to do with the type parameter in GenericType (although it theoretically could find out, it doesn't). If you had a variable of type GenericType<String> and assigned a GenericType<Object> to it, you may very well end up putting a Long instance where a String is expected, and get a ClassCastException where you won't expect one.
In the doSomethingWith method of your variable GenericType<? extends Object> aGenericType2 you can pass one thing: null. null is the only object reference that has a subtype of ? extends Object. The lower bound type of ? extends Object is the null type, which cannot be expressed in Java, and only implicitly exists as the type of the null reference.
[1] http://en.wikipedia.org/wiki/Covariance_and_contravariance_%28computer_science%29#Java
I don't know if this is what you are expecting, but you can declare your interface something like:
public interface Interface <K extends Object> { ... }
While your class might look like:
public class InterfaceImpl implements Interface<String> { ... }
#Override annotation:
When overriding a method, you might
want to use the #Override annotation
that instructs the compiler that you
intend to override a method in the
superclass. If, for some reason, the
compiler detects that the method does
not exist in one of the superclasses,
it will generate an error.
With this annotation you cannot change return type of function.
If you want to override return type, just make interface A more abstract, add generic to this interface:
public interface InterfaceA<T> {
public GenericType<T> getAGenericType();
}
Sample about overriding a generic method in a generic class.
The trouble is that InterfaceA doesn't know what type it's holding. If you get InterfaceA to take a generic argument then you could do this:
public interface InterfaceA<T>
{
public GenericType<T> getAGenericType();
}
public interface InterfaceA1 extends InterfaceA<String>
{
#Override
public GenericType<String> getAGenericType();
}
public class LookAtTheInstance
{
#SuppressWarnings("null")
public static void method()
{
InterfaceA<String> a = null;
InterfaceA1 a1 = null;
GenericType<String> aGenericType = a1.getAGenericType();
GenericType<String> aGenericType2 = a.getAGenericType();
String something = null;
aGenericType2.doSomethingWith( something );
}
}
I'm several years late to the party, but I found this page while searching for a related question and none of the answers really hit on the central issue, which I think is worth clarifying. Let's look at a slightly-more-fleshed-out example:
interface GenericType<D> {
D getAValue();
void doSomethingWith(D value);
}
class StringType implements GenericType<String> {
#Override
public String getAValue() {
return "Hello World";
}
#Override
public void doSomethingWith(final String value) {
System.out.println(value.length());
}
}
interface InterfaceA {
GenericType<? extends Object> getAGenericType();
}
interface InterfaceA1 extends InterfaceA {
#Override
GenericType<String> getAGenericType();
}
class AnActualA1 implements InterfaceA1 {
#Override
public GenericType<String> getAGenericType() {
return new StringType();
}
}
class LookAtTheInstance {
public static void method() {
InterfaceA1 a1 = new AnActualA1();
// 'g1' is a StringType, which implements GenericType<String>; yay!
GenericType<String> g1 = a1.getAGenericType();
// Everything here is fine.
String value = g1.getAValue();
g1.doSomethingWith("Hello World");
// But if we upcast to InterfaceA???
InterfaceA a = (InterfaceA) a1;
// Note: a.getAGenericType() still returns a new StringType instance,
// which is-a GenericType<? extends Object>.
GenricType<? extends Object> g = a.getAGenericType();
// StringType.getAValue() returns a String, which is-an Object; yay!
Object object = g.getAValue();
// StringType.doSomethingWith() method requires a String as the parameter,
// so it is ILLEGAL for us to pass it anything that cannot be cast to a
// String. Java (correctly) prevents you from doing so.
g.doSomethingWith(new Object()); // Compiler error!
}
}
Conceptually, GenericType is NOT a GenericType, since a GenericType can only doSomethingWith() Strings, while a GenericType needs to be able to doSomethingWith() any object. GenericType is a compromise which the compiler allows you to use as a "base class" for any GenericType where D is-an Object, but only allows you to use a reference of that type to call methods that are type-safe for any possible runtime value of '?' (such as getAValue(), whose return value can always be safely cast to an Object since D is-an Object regardless of runtime type).
It's hard to tell what (if anything) the original poster was actually trying to model with this code, and in particular how much of the generic-ness of GenericType was really needed, but perhaps the inheritance should have gone the other way around?
/**
* I can do something with instances of one particular type and one particular
* type only.
*/
interface GenericType<D> {
void doSomethingWith(D value);
}
/**
* I can do something with instances of any type: I am-a GenericType<String>
* because I can totally do something with a String (or any other kind of
* Object).
*/
interface NonGenericType extends GenericType<Object>, GenericType<String> {
#Override
void doSomethingWith(Object value);
}
interface StringHandlerFactory { // nee InterfaceA1
GenericType<String> getAGenericType();
}
/**
* I extend StringHandlerFactory by returning a NonGenericType (which is-a
* GenericType<String>, satisfying the interface contract, but also so much
* more).
*/
interface ObjectHandlerFactory extends StringHandlerFactory { // nee InterfaceA
#Override
NonGenericType getAGenericType();
}
The downside being that there's no good way to express to the java compiler that NonGenericType extends GenericType, even though conceptually it could in this case, since GenericType never uses D as a return value. You have to manually specify each GenericType that you want it to extend. :(
So you end up declaring nice interfaces which, as it turns out, cannot be instantiated right.
I think that the purpose of InterfaceA is not to be instantiated at all, because one of its dependable classes are generic. That's what you meant declaring:
public GenericType<? extends Object> getAGenericType()

Categories

Resources