I have classes that are structured like the ones below:
interface Z {}
interface Y extends Z {}
interface X extends Y {}
private static class A<T extends Z> {}
private static class B<T extends Y> extends A<T> {}
private static class C extends B<X> {}
Why is the first one valid while the second one is not?
private Class<? extends A<? extends Z>> clazz = C.class; // valid
private Class<? extends A<? extends Z>> clazzb = B.class; // error: Type mismatch: cannot convert from Class<TEST.B> to Class<? extends TEST.A<? extends TEST.Z>>
I guess it is because the type of Y is unclear in the second example but how would you be able to clarify it?
Thank you
Java Class literal constraint
Simply said; no you can't bound the Class literal assignment as B<T> is a generic type, i.e. you can have:
Class<? extends A<? extends Z>> clazzb = B<X>.class; // illegal statement
// OR
Class<? extends A<? extends Z>> clazzb = B<W>.class; // assuming W is a sub-type of X
as there is only one class literal (in terms of byte code (runtime) and in terms of language constraints (compile-time)): B.class
And since the compiler won't be able to know of which type the type parameter T would be for the B class, it won't allow such an assignment.
Legal assignment
Below assignment statement would be legal (compiles fine):
Class<? extends A> clazzb = B.class;
but with warnings and that would perfectly complies with the Generic Class and Type Parameters Java Language Specification.
I've seen many times a Java specific-pattern where developers work-around the compiler type-check with a generic utility method inferring its return type to match the assigned reference type:
<!-- language : lang-java -->
#SuppressWarnings("unchecked")
public static <T> Class<T> inferType(Class<?> clazz) {
return (Class<T>) clazz;
}
Then you would be able to perform what used to be forbidden:
Class<? extends A<? extends Z>> clazzb = generify(B.class);
Note that this should be nothing but a non-recommended workaround. Just to let you be more sure, here down a quite confusing statement that compiles just fine:
Class<C> clazzb = generify(A.class);
At first glance, that should not work, but it will as you are assigning a class literal to a class reference after all.
Related
Please, consider my code:
class A {
}
class B extends A {
}
class AWrapper<T extends A> {
}
class BWrapper<T extends B> extends AWrapper<T> {
}
So, I have C extends B etc, and CWrapper<T extends C> extends BWrapper<T> etc.
Now, I use these classes this way:
class Test {
private Class<? extends AWrapper<? extends A>> klass;//LINE X
public Test() {
this.klass = BWrapper.class;//LINE Z
}
}
At LINE X I need to set different classes - AWrapper, BWrapper, CWrapper etc. However, at LINE Z I get an error. Could anyone help to fix it?
imho, what you are looking for is :
private Class<? extends AWrapper> klass;
even if AWrapper is raw. At least this way you could say that your parameter takes "a class that is subtype (or self) of AWrapper". But that should be the thing you care about anyway. Generics are not preserved at runtime, so no matter what Class you have there, it is going to be without its inferred parameters.
Here is an example of my Java code:
package com.company;
public class Main {
private static class Something<T>{
public void fun(Class<T> someClass){
someClass.cast(null);
}
}
private interface Hello{}
public static void some(Something<? extends Hello> mySomething, Class<? extends Hello> myClass){
mySomething.fun(myClass);
}
}
And I'm getting a weird error at the mySomething.fun(myClass) line:
Required type: Class<? extends com.company.Main.Hello>
Provided: Class<? extends com.company.Main.Hello>
Which are the exact same type...
What am I missing here?
I believe the problem is that the question mark in the "required" and "provided" can be different. Suppose I have two implementations of Hello: Hello1 and Hello2. I could call:
some(new Something<Hello2>(), Hello1.class);
That fulfills the contract of some, but you don't want to be able to call new Something<Hello2>().someClass(Hello1.class).
I believe you need to express the constraint once, by making some generic:
public static <T extends Hello> void some(Something<T> mySomething, Class<T> myClass)
Now the two parameters are appropriately related, so the call to fun is valid.
Class<? extends com.company.Main.Hello> is a Class whose type parameter is Hello or some class that extends Hello.
Therefore two unrelated Class<? extends com.company.Main.Hello> might represent two different sub-classes of Hello.
For example, suppose you passed to your some(Something<? extends Hello> mySomething, Class<? extends Hello> myClass) method a Something<Hello1> and a Class<Hello2>. Both Hello1 and Hello2 are sub-classes of Hello, but you can't pass a Class<Hello2> argument to the fun() method of Something<Hello1> (which requires a Class<Hello1>).
<? extends MyClass> (in the first parameter) is not guaranteed to be the compatible to <? extends MyClass> (in the second parameter).
If the types were the same, for example:
public static <T> void some(Something<T> mySomething, Class<T> myClass) {
mySomething.fun(myClass);
}
then compilation passes just fine.
You need to change your some() definition to:
public static <T extends Hello> void some(Something<T> mySomething, Class<T> myClass) {
mySomething.fun(myClass);
}
This is because in your Something class, the type T is used in the fun declaration in a way that the actual type of T must exactly be the same.
But in your some method, ? extends Hello can be different classes. Hello can have multiple child classes.
In Java Generics, given a generic class/interface Foo<T>,
What's the difference between declaring a new generic class:
Foobar<T extends Foo<T>> or simply Foobar<T extends Foo>, also why can I instantiate a generic class Foo<T> without instantiating the type parameter T?, i.e. why can i write the following:
Foo var = new Foo();, does this mean that the class is instantiated with an object, through which i can only use the non-generic method?
please forgive me if the question is not so clear, the example i was working on is the following:
MyClass<T extends Comparable<T>>
class Foo<T> {}
is your class.
Foo yourVariable = new Foo();
equals Foo<Object> yourFoo = new Foo<Object>();
class Foobar<T> extends Foo {}
equals class Foobar<T> extends Foo<Object> {}
the answer to your question
class YourClass<T extends Comparable<T>> {}
means YourClass's type T is able to compare itself to objects of T (its class), whereas
class YourClass<T extends Comparable> {}
's type T is able to compare itself to objects of class Object, which is not what you want
I am in a strange situation here, namely eclipse tells me that Long is "not a valid substitute for the bounded parameter <T extends Comparable<? super T>>". Any suggestions on what may be the cause? I'm pasting relevant code below
abstract Pair:
public abstract class Pair<T extends Comparable<? super T>, R> implements Comparable<Pair<T, R>>{
private T tt;
private R rr;
public Pair(T t, R r){
tt = t;
rr = r;
}
#Override
public String toString(){
return tt+ ": " +rr.toString();
}
}
concrete Pair:
import utilities.Pair;
public class LogBookRecord<Long, String> extends Pair<Long, String>{
LogBookRecord(Comparable t, Object r) {
super(t, r);
// TODO Auto-generated constructor stub
}
}
I tried changing abstract class header to:
public abstract class Pair<T extends Comparable<T>, R> implements Comparable<Pair<T, R>>
which did not help, and also to:
public abstract class Pair<T, R> implements Comparable<Pair<T, R>>
but then, in concrete class I get a notification which suggests that I should change type parameters to <Comparable, Object>.
public class LogBookRecord<Long, String> extends Pair<Long, String>{
^ ^
| |
generic type variable declaration (new type names) |
generic type arguments
That code is equivalent to
public class LogBookRecord<T, R> extends Pair<T, R>{
You've simply shadowed the names Long and String with your own type variable names.
Since T has no bounds, it is not necessarily Comparable and the compiler cannot validate them as type arguments to Pair.
What you want is
public class LogBookRecord extends Pair<Long, String>{
A class that is not generic, that provides concrete types as type arguments to the Pair superclass declaration.
The Java Language Specification describes the class declaration syntax.
I'm trying to create library with a container that releases instances of its contained objects according to descriptors it is passed. I'd like to make it so the descriptor determines the type of the returned object, but the descriptor can specify a bounded type. How do I implement this? For example the closest I can get is:
/*Block 1 - First Attempt. Compiles, but forces user to cast*/
interface ItemDescriptor<I> {
Class<? extends I> getType();
}
interface ArchiveContainer<I, D extends ItemDescriptor<? extends I>> {
Iterable<? extends D> getDescriptors();
I getItem(D descriptor);
}
//Implementations
class ChannelItemDescriptor<I extends ByteChannel> implements ItemDescriptor<I>
{
final Class<? extends I> type;
ChannelItemDescriptor(Class<I> type) {
this.type = type;
}
#Override Class<? extends I> getType() {return type;}
}
class ChannelArchive implements ArchiveContainer<ByteChannel, ChannelItemDescriptor<? extends ByteChannel>> {
#Override ByteChannel getItem(ChannelItemDescriptor<? extends ByteChannel> descriptor) {...}
}
The above code compiles, but the problem is ChannelArchive's getItem can return SeekableByteChannels as well. The user of this library knows this at compile time (because they know the type parameter of the descriptor), so I'm trying to avoid adding a method parameter of type Class for forcing the user to explicitly cast the returned value to SeekableByteChannel when necessary. I can't figure out how to get getItem to return a specific subtype of ByteChannel without forcing the user to cast. I want to do this:
/*Block 2 - Test code*/
ChannelArchive archive = ...;
ChannelItemDescriptor<SeekableByteChannel> desc = ...;
ChannelItemDescriptor<ByteChannel> otherDesc = ...;
SeekableByteChannel sbc = archive.getItem(desc);
SeekableByteChannel sbc = archive.getItem(otherDesc); //Should fail to compile, or compile with warning
ByteChannel bc = archive.getItem(otherDesc);
I could add a Class<? extends I> parameter to each method, but the code for the method would completely ignore Class method parameter! It's only purpose would be to help the compiler infer types. I think it just obfuscates the code so much that it would be easier to just have the user use instanceof checks and casts.
I've tried this:
/*Block 3 - Failed attempt.*/
class ChannelArchive implements ArchiveContainer<ByteChannel, ChannelItemDescriptor<? extends ByteChannel>> {
//Won't compile, getItem doesn't override
#Override <II extends ByteChannel> II getItem(ChannelItemDescriptor<II> descriptor) {...}
}
but that doesn't work: ChannelArchive is not abstract and does not override abstract method getItem(ChannelItemDescriptor<? extends ByteChannel>) in ArchiveContainer. I assume this is because the second type parameter <II extends ByteChannel> has different type erasure than <? extends ByteChannel>?
I've also tried this, which compiles:
/*Block 4 - Almost specific enough*/
interface ArchiveContainer<I, D extends ItemDescriptor<? extends I>> {
Iterable<? extends D> getDescriptors();
<II extends I, DD extends ItemDescriptor<II>> II getItem(DD descriptor);
}
class ChannelArchive implements ArchiveContainer<ByteChannel, ChannelItemDescriptor<? extends ByteChannel>> {
#Override <II extends ByteChannel, DD extends ItemDescriptor<II>> II getItem(DD descriptor) {...}
}
Even though it compiles, it won't really work because I need a ChannelItemDescriptor inside that method, and the resulting cast would defeat the purpose of using the added type-safety of generics.
I don't see why I can't do it, because the right types are known at compile time. What I really need on that ArchiveContainer interface is a parameterized type parameter, like: <II extends I, DD extends D<II>>. What am I doing wrong?
NOTE: I don't actually use ByteChannel and SeekableByteChannel, but what I do use is quite similiar.
That's to ruakh, I settled on the code in block 4. In my case, its highly unlikely the user would send the wrong sublcass of ItemDescriptor in a call to a getItem, especially because the descriptors are all returned from the ArchiveContainer itself via getDescriptors!
I think this code, which is (almost?) the same as your third attempt, is as good as you're going to get:
// in ArchiveContainer:
<II extends I, DD extends ItemDescriptor<II>> II getItem(DD descriptor);
// in ChannelArchive:
public <II extends ByteChannel, DD extends ItemDescriptor<II>>
II getItem(DD descriptor)
{ ... }
Generics do offer a way to declare a type variable with two separate upper bounds:
public <T extends Foo & Bar> Foo fooBar(T t) { ... }
but apparently that's not allowed when one of the upper bounds is a type-parameter rather than a class or interface:
Type variables have an optional bound, T & I1 ... In. The bound consists of either a type variable, or a class or interface type T possibly followed by further interface types I1 , ..., In. […] It is a compile-time error if any of the types I1 ... In is a class type or type variable. [link]
(emphases mine). I don't know why this is.
But I don't think this should be a big problem. Note that, even after Map was genericized to Map<K,V>, its get method still took type Object. Naturally that method will always return null if you pass in a reference to an object that's not of type K (since such an object should never have been inserted into the map), but this doesn't harm type-safety.
I know that this is probably not what you want to hear, but even though Java generics look syntactically like C++ templates, they differ quite a bit in how they work.
Look up java type erasure in your favorite search engine.
Just because a type is known at compile-time does not, unfortunately, mean that the type is recoverable at runtime, or even during later compile phases.