java generics: Bound mismatch for string - java

my code is as below, and I got the error message Bound Mismatch Error: The type String is not a valid substitute for the bounded parameter <K extends myComparable<K>> of the type myInterface<K,V>:
interface myComparable<T> {
public int compareTo(T o);
}
interface myInterface<K extends myComparable<K>, V> {
}
public class myClass implements myInterface<String,String>{
public static void main(String[] args) {
System.out.println("Hello world!");
}
}
However, if I changed K extends myComparable<K> to K extends Comparable<K> (without changing the first line; i.e. to use Comparable instead of myComparable), the error will be solved.
Why? And how can I use my own myComparable?

I finally got a solution (i.e. to use myString instead of String):
interface myComparable<T> {
public int compareTo(T o);
}
interface myInterface<K extends myComparable<K>, V> {
}
class myString implements myComparable<myString>{
#Override
public int compareTo(myString o) {
return 0;
}
}
public class myClass implements myInterface<myString,myString>{
public static void main(String[] args) {
System.out.println("Hello world!");
}
}

When you write implements myInterface<String, String>, you're 'binding' the K type variable to String and the V type variable to String.
The declaration of the K type variable in particular has a bound on it: You've declared it as myInterface<K extends myComparable<K>, V> which means that any bound you pick for K must at least 'fit' this restriction.
And it doesn't, which is why the compiler won't let you.
The java.lang.String class actually implements Comparable<String> - it's right there in the javadoc as well as the source if you care to look; you can also just cast it:
Comparable<String> test = "hello"; // this compiles and runs fine.
The reason is that string was written by sun/oracle as: public final class String implements Comparable<String>.
It was not written with implements myComparable<String>.
It is not possible to make java.lang.String implement your interface.
That is not how interfaces work; java is nominally and not structurally typed: You can't decree that all Strings are myComparables, just because they so happen to have a compareTo method.
Imagine it worked that way and I wrote this class:
public class Gun {
public void shoot(Person person) { ... }
}
quite a dangerous class!
Let's say it worked the way you appear things are. Then I could do:
public interface Camera {
public void shoot(Person p);
}
Camera c = new Gun();
c.shoot(somebody);
and good grief, now we have an extremely dangerous situation going on. Fortunately, java does not work this way; A Gun is not a Camera. Eventhough it so happens to have all the methods that the Camera interface declared.
You can make your own types that implement your own interfaces, of course. That's no problem. However, in general, it doesn't seem useful to make an interface named myComparable.

Related

Java Incompatible equality constraint in list

I have a multi level class structure and want to pass their implementation to a function that can call functions on them, but I get an Incompatible equality constraint: Test.SubDTO2 and Test.SubDTO error.
Here is the code:
public class Test {
abstract class DTO { }
class SubDTO extends DTO implements Interf{ }
class SubDTO2 extends DTO implements Interf{ }
class DAO<T extends DTO> { }
interface Interf { }
static DAO<SubDTO> daoImpl1;
static DAO<SubDTO2> daoImpl2;
public static void main(String... args) {
func(Arrays.asList(daoImpl1, daoImpl2)); // <- error is in this line
}
static <T extends DTO & Interf> void func(List<DAO<T>> arg) {
}
}
A more detailed example on what I try to achieve:
public class Test {
abstract class DTO {
abstract void func1();
}
class SubDTO extends DTO implements Interf{
#Override
public void func2() {
// comes from Interf
}
#Override
public void func1() {
// comes from DTO
}
}
class SubDTO2 extends DTO implements Interf{
#Override
public void func2() {
// comes from Interf
}
#Override
public void func1() {
// comes from DTO
}
}
class DAO<T extends DTO> {
public T dto() {
return null;
}
}
interface Interf {
void func2();
}
static DAO<SubDTO> daoImpl1;
static DAO<SubDTO2> daoImpl2;
public static void main(String... args) {
func(Arrays.asList(daoImpl1, daoImpl2));
}
static <T extends DTO & Interf> void func(List<? extends DAO<? extends DTO>> arg) {
arg.get(0).dto().func1(); // <- I can't call func2() here
}
}
exact error message:
[ERROR] required: java.util.List<Test.DAO<T>>
[ERROR] found: java.util.List<Test.DAO<? extends Test.DTO>>
[ERROR] reason: inference variable T has incompatible equality constraints Test.SubDTO2,Test.SubDTO
I need the list in the function func to extend DTO and also implement Interf as well, because I call certain functions on them.
Why is this happening? It works fine if I change the signature of the func and pass only one DAO, but I need it to work with multiple.
What are my options here?
I tried it with multiple java versions (1.8+), all the same.
Your function should be declared like this:
static <T extends DTO & Interf> void func(List<DAO<? extends T>> arg) {
Notice that I changed List<DAO<T>> to List<DAO<? extends T>>. This is because the expression Arrays.asList(daoImpl1, daoImpl2) produces a value of type
List<DAO<? extends DTO & Interf>>
(Of course, this isn't real syntax for a type in Java. There's no syntax for intersection types in Java but Java does know about them when doing type inference, and you could have these types in your code if you use var. I use this notation here just for illustrative purposes.)
If you know PECS, you'll know that this is a list of DAOs that produces DTO & Interfs/Ts, but does not consume DTO & Interfs/Ts. If you are lost at this point, please go read the PECS post - it's great. See also: Difference between <? super T> and <? extends T> in Java
The reason why it does this is quite intuitive. Imagine if DAO is just a container for a T.
static class DAO<T extends DTO> {
private T t;
public T getT() {
return t;
}
public void setT(T t) {
this.t = t;
}
}
If Arrays.asList(daoImpl1, daoImpl2) had produced a list of DAO<DTO & Interf> (with no extends or super), you'd be able to call getT and setT on elements of the list! And being able to call setT is especially dangerous you see - you'd be able to do this:
// suppose arg is a List<DAO<DTO & Interf>>
arg.get(someRandomNumber).setT(new SubDTO());
What if someRandomNumber happens to be 1, and we get the second element, which is a DAO<SubDTO2>? Putting a SubDTO inside that destroys the whole type-safety of generics.
The only type-safe thing to do on elements of such a list like [daoImpl1, daoImpl2] is to use them as producers of DTO & Interfs, hence the type is marked ? extends DTO & Interf. This means that if you have any methods on DAO that takes in a T, you won't be able to call them on elements of this list*.
Also note that, just in case I was not clear, it is not the list that is only a producer - the list is both a producer and consumer of DAOs. It's just that the DAOs in the list are producers of their Ts.
* except by passing nulls.

Why does the generic type of a superclass field not get erased to the concrete bound in a subtype?

package ir.openuniverse;
public class Main {
public static void main(String[] args) throws NoSuchFieldException {
System.out.println(A.class.getField("t").getType().getName());
}
}
class A extends B<D> {}
class B<T extends C> {
public T t;
}
class C {}
class D extends C {}
The output is ir.openuniverse.C. Why? I expect D!
EDIT:
This question wasn't about workarounds or alternative ways. So answers aren't about workarounds. For alternative ways see myself answer below.
This happens because of type erasure.
Java compiles your generic class B<T> into byte code suitable for use with all classes that may reference it, including any class that may be extending B<T>.
Since T is restricted to classes extending C, Java knows that any value that you could assign B.t will extend C, so it compiles your class into an equivalent
class B {
C t;
}
At this point any assignment of t would work; reading from t would yield C, though, so the compiler must do some "magic" to fix this. Specifically, the compiler inserts type casts in places where the subtype is known. It may also generate bridge methods if necessary. See the link at the top of the answer for the details.
During compilation, Java's type erasure change
class B<T extends C> {
public T t;
}
to :
class B<C> {
public C t;
}
Since getType() identifies the declared type for the field, the output is ir.openuniverse.C
Thanks for all's helps. Finally, I forced to change my A's definition to:
class A extends B<D> {
public D t;
}
It's sufficient for my purpose (although I don't like it at all!).
EDIT:
Above way is not a fundamental way. See #DanielPryden's first two comments below.
Alternative workaround:
class A extends B<D> {
#Override public D getT() { return super.getT(); }
}
class B<T extends C> {
private T t;
public T getT() { return t; }
}
And in main():
System.out.println(A.class.getMethod("getT").getReturnType().getName());
Output: ir.openuniverse.D
Another way:
NOTE: This is not a solution to the main problem (See #DanielPryden's fourth comment below). But maybe helps you (like me).
This workaround can be used when you have at least one instance of A:
public class Main {
public static void main(String[] args) {
A a = new A();
System.out.println(a.t.getClass().getName());
// Or via reflection:
// System.out.println(a.getClass().getField("t").get(a).getClass().getName());
}
}
class A extends B<D> {
{ t = new D(); }
}
class B<T extends C> {
public T t;
}
Output: ir.openuniverse.D

Java Generics & operator

I am facing some difficulty to understand an expression in java generics.
Please help on this:
public interface Inter {
<T extends Enum<T> & FunctionalInterface> String getString();
}
The code you have given is legal, but useless.
It is useless for two reasons:
You have defined a generic type, T, as part of the method declaration that must implement the Enum<T> interface as well as the FunctionalInterface interface. However you haven't then used that type anywhere in the method's signature (i.e. arguments or return type) so it is effectively ignored.
Having an interface implement 'FunctionalInterface' is possible, but certainly not it's intended use. It is designed to be an annotation to an interface, not an interface itself.
You could make this combination work:
public interface Inter {
<T extends Enum<T> & FunctionalInterface> String getString(T value);
}
static class InterImpl implements Inter {
#Override
public <T extends Enum<T> & FunctionalInterface> String getString(T value) {
return value.name();
}
}
enum EnumImpl implements FunctionalInterface {
A, B, C;
#Override
public Class<? extends Annotation> annotationType() {
return null;
}
}
public static void main(String[] args) {
InterImpl impl = new InterImpl();
System.out.println(impl.getString(EnumImpl.B));
}
You'll see that the EnumImpl enumeration implemements Enum and FunctionalInterface so it can be used as an argument to getString.
So that's an explanation but, frankly, I can't think of any useful use case for such a piece of code.

Overriding necessary to avoid runtime type check for Java generic method?

The following snippet of generic magic has saved me some grief by caching very expensive functions on Strings (which Phrase simply wraps).
public class Phrase {
private final ConcurrentHashMap<Function<? extends Phrase, ?>, Object> memos;
public final String text;
public <X, T extends Phrase> X memo(Function<T, X> app) {
return (X) memos.computeIfAbsent(app, unused -> app.apply((T) this));
}
}
// Example follows
public class Joke extends Phrase {
boolean isoffcolor;
}
public class BigramJokeEvaluator {
public Boolean static isFunny(Joke joke) {
return !joke.isoffcolor;
}
}
public class MilesAway {
public static void main(String[] args) {
// Boom
new Phrase("Moo goes the cow!").memo(BigramJokeEvaluator::isFunny);
}
}
I have several subclasses of Phrase, with their own respective functions, and when other modules use subclasses of Phrase along with those functions, it's up to the programmer to make sure type T of T extends Phrase lines up correctly.
Function<>'s are immutable so the runtime coercion of (X) is guaranteed. But if I want to make the coercion of T into a compile-time type check:
Is there some way I can forward the lower function's type constraint to the higher-level function's type constraint? (Effectively making memo in the case of Joke as if it was <X> X memo(Function<Joke, X>);) [Does Type Erasure prevent this?]
Do I have to make delegate functions in all the subclasses of Phrase?
Is there some trick other than 'just not making any mistakes'?
The best you can do is this:
public class Phrase<P extends Phrase<P>> {
private final ConcurrentHashMap<Function<P, ?>, Object> memos;
public final String text;
public <X> X memo(Function<P, X> app) {
return (X) memos.computeIfAbsent(app, unused -> app.apply((P) this));
}
}
class Joke extends Phrase<Joke> {...}
This is called F-bounded quantification and it's used by e.g. Enum<E extends Enum<E>>.
It's a bit of a pain in the neck but it generally works.
Note that it does not guarantee that P is the type of this:
class Joke extends Phrase<Joke> {}
// oops
class Troll extends Phrase<Joke> {}
It's also impossible to capture a Class<? extends Phrase<?>>:
{
Class<? extends Phrase<?>> j = Joke.class;
m( j ); // fails, but would pass if P was not F-bounded
}
static <P extends Phrase<P>> void m(Class<P> c) {}
But overall, it makes it harder to make the more likely types of mistakes.
Do I have to make delegate functions in all the subclasses of Phrase?
Delegating to subclasses is difficult because of 1. no covariant parameters and 2. erasure.
class Phrase {
...
<X> X memo(Function<Phrase, X> f) {...}
}
class Joke extends Phrase {
...
// this is a compiler error
// (technically, I think it's classified as
// "override-equivalent", but specified to fail)
<X> X memo(Function<Joke, X> f) {...}
}
(If that's the type of thing you're referring to by 'delegate'. Otherwise, feel free to clarify.)
You could delegate with a type parameter e.g.:
class Phrase<P> {
abstract <X> X memo(Function<P, X> f);
}
class Joke extends Phrase<Joke> {
#Override
<X> X memo(Function<Joke, X> f) {...}
}
This avoids the unchecked casting.
You should make a type parameter (here we call P) to represent the type of the subclass, and then for the method that cares about the relationship of P to its type parameter, we use a generic method to do it (it's static so it's "outside" the class):
class Phrase<P> {
final HashMap<Function<P, ?>, Object> memos = new HashMap<>();
public static <X, T extends Phrase<T>> X memo(T phrase, Function<T, X> app) {
return (X) phrase.memos.computeIfAbsent(app, unused -> app.apply(phrase));
}
}
Phrase.memo(new Phrase(), BigramJokeEvaluator::isFunny);

Method with typed list and inheritance

I have some troubles with a method having a typed List parameter, inherited from another (typed) class.
Let's keep it simple :
public class B<T> {
public void test(List<Integer> i) {
}
}
The B class has a useless generic T, and test() want an Integer List.
Now if I do :
public class A extends B {
// don't compile
#Override
public void test(List<Integer> i) {
}
}
I get a "The method test(List) of type A must override or implement a supertype method" error, that should not happen.
But removing the type of the list works... although it doesn't depend on the class generic.
public class A extends B {
// compile
#Override
public void test(List i) {
And also defining the useless generic below to use the typed list
public class A extends B<String> {
// compile
#Override
public void test(List<Integer> i) {
So I'm clueless, the generic of B should have no influence on the type of the test() list. Does anyone have an idea of what's happening?
Thanks
You're extending the raw type of B, not the generic one. The raw one effectively does not have a test(List<Integer> i) method, but a test(List) method.
If you switch to raw types, all generics are replaced by raws, regardless of whether their type was filled in or not.
To do it properly, do
public class A<T> extends B<T>
This will use the generic type B<T>, which includes the method you want to override.
When you remove use a class without generics (and use it raw), all generics from class methods are forgotten.
Due this reason when you inform the generic type on the second case you get it working.
This:
class T<G> {
public void test(G g);
}
in this case:
class A extends T {
}
will look like this:
class T {
public void test(Object g);
}
This was a java puzzle presented on Google IO 2011 you can see video here

Categories