Using generic interfaces [duplicate] - java

This question already has answers here:
What is a raw type and why shouldn't we use it?
(16 answers)
Closed 8 years ago.
Is there any differences between those two class declarations
1:
class MyClass <T extends Number & Comparable>
2:
class MyClass <T extends Number & Comparable<T>>
I think that there are differences. But I cannot find an example which would show differences because I don't understand it exact.
Can you show me this example?

There is a difference. The first one is using raw types, and thus, is less type-safe. For example:
This works, but should not work
class MyClass<T extends Number & Comparable>
{
void use(T t)
{
String s = null;
t.compareTo(s); // Works, but will cause a runtime error
}
}
Whereas this does not work (because it should not work)
class MyClass<T extends Number & Comparable<T>>
{
void use(T t)
{
String s = null;
t.compareTo(s); // Compile-time error
}
}
EDIT: Full code, as requested:
class MyClass<T extends Number & Comparable>
{
void use(T t)
{
String s = "Laziness";
t.compareTo(s); // Works, but will cause a runtime error
}
}
public class MyClassTest
{
public static void main(String[] args)
{
MyClass<Integer> m = new MyClass<Integer>();
Integer integer = new Integer(42);
m.use(integer);
}
}

Related

Unable to assign method reference to generic interface method [duplicate]

This question already has answers here:
What is PECS (Producer Extends Consumer Super)?
(16 answers)
Closed 1 year ago.
I am trying to assign a method reference to the following generic interface.
interface Interface1<R> {
public R doIt();
}
interface Interface2<P, R> {
public R doIt(P x);
}
public class Test {
public static Long foo(Long x) {
return x;
}
public static Long bar() {
Long x = 1L;
return x;
}
public static void main(String[] args) {
Interface1<? extends Number> fun1 = Test::bar; //works
Interface2<? extends Number, ? extends Number> fun2 = Test::foo; // does not work
}
}
The second assignment gives me
incompatible types: Number cannot be converted to Long
What am I missing here!
You cant do this because then you can do fun2.doIt((Number)0.5);
The idea is that you need something like
Interface2<? super Number, ? extends Number>

How to don't allow Type Inference and require a explicit type on method call? [duplicate]

This question already has answers here:
How to write a generic method that takes two arguments of the same types in java?
(4 answers)
Closed 3 years ago.
I'm currently building a class with a Pair-Structure. I want to somehow guarantee that each member of the pair has the exact same type.
My question goes in the direction of: How type inference work for method calls?
Following code illustrates my problem:
public class MyClass {
public class MyPair<E> {
private E oldObj;
private E newObj;
MyPair(E pOldObj, E pNewObj) {
oldObj = pOldObj;
newObj = pNewObj;
}
}
public class MyObject {
List<MyPair<?>> listWithPairs = new ArrayList<>();
public <T> void addPair(T oldObj, T newObj) {
listWithPairs.add(new MyPair<T>(oldObj, newObj));
}
}
public static void main(String[] args) {
MyObject pairHolder = new MyObject();
pairHolder.addPair(12L, "asdf");//Call 1
pairHolder.<Long>addPair(12L, 12L);//Call 2
}
}
Is there a way in Java to make Call 1 impossible and always require a type specification like in Call 2?
perhaps by declaring your method like that way
public <T extends Number> void addPair(T oldObj, T newObj) {
listWithPairs.add(new MyPair<T>(oldObj, newObj));
}

Apparent type violation, but compiles [duplicate]

This question already has answers here:
String gets assigned to a List without a compilation error [duplicate]
(1 answer)
Why can this generic method with a bound return any type?
(1 answer)
Generic return type upper bound - interface vs. class - surprisingly valid code
(2 answers)
Closed 5 years ago.
Why does the below snippet compile ? OtherInterface does not extends Concrete so I would have bet a kidney that this wouldn't compile. But it does.
public class Test {
public static interface SomeInterface {}
public static interface OtherInterface{}
public static class Concrete implements SomeInterface {
public <T extends Concrete> T getConcrete() {
return null;
}
}
public static void doStuff() {
Concrete c = new Concrete();
OtherInterface iCompile = c.getConcrete();
}
}
On the other hand, the next snippet does not compile, which is what I expect.
public class Test {
public static interface SomeInterface {}
public static class UnrelatedClass{}
public static class Concrete implements SomeInterface {
public <T extends Concrete> T getConcrete() {
return null;
}
}
public static void doStuff() {
Concrete c = new Concrete();
UnrelatedClass iCompile = c.getConcrete();
}
}
The difference is here:
public static interface OtherInterface{} ...
OtherInterface iCompile = c.getConcrete();
vs.
public static class UnrelatedClass{} ...
UnrelatedClass iCompile = c.getConcrete();
Meaning: in the first case, you call the method to return an instance of some interface. Interfaces can be any class.
In the second example, you instruct that returned type is of be a specific class! A class which is known, and that does not implement that other interface!
And the error message:
reason: no unique maximal instance exists for type variable T with upper bounds UnrelatedClass,Concrete
is pretty specific here.
In other words: the compiler factors in the left hand side of that assignment - to determine the valid types. And UnrelatedClass can never be a Concrete - because the class UnrelatedClass does not extend Concrete!
Whereas something that is SomeInterface can as well implement OtherInterface.

Compiler not checking type parameter bounds? [duplicate]

This question already has answers here:
What is a raw type and why shouldn't we use it?
(16 answers)
Closed 7 years ago.
I have an interface defining the following method:
public <C extends RTSpan<V>, V extends Object> void onEffectSelected(Effect<V, C> effect, V value);
I'm calling this like this:
mListener.onEffectSelected(Effects.BOLD, true);
with Effects.BOLD being an Effect<Boolean,RTSpan<Boolean>> object.
I was under the impression that the compiler should make sure that the two Vs in the onEffectSelected are of the same type?
However if I write:
mListener.onEffectSelected(Effects.BOLD, 1);
It compiles without issues and of course throws a runtime exception.
What's wrong here? How can I make sure that the second parameter has an identical type to the one used in the first parameter?
EDIT
public class GenericsTest {
interface RTSpan<V> {}
static class BoldSpan implements RTSpan<Boolean> {}
static class Effect<V extends Object, C extends RTSpan<V>> {}
static class BoldEffect extends Effect<Boolean, BoldSpan> {}
interface TheListener {
public <C extends RTSpan<V>, V extends Object> void onEffectSelected(Effect<V, C> effect, V value);
}
static class Effects {
public static final Effect BOLD = new BoldEffect();
}
public static void main(String[] args) {
TheListener listener = new TheListener() {
#Override
public <C extends RTSpan<V>, V> void onEffectSelected(Effect<V, C> effect, V value) {}
};
listener.onEffectSelected(Effects.BOLD, Boolean.TRUE);
listener.onEffectSelected(Effects.BOLD, 1); // this compiles
listener.onEffectSelected(new BoldEffect(), 1); // this doesn't compile
}
}
The issue seems to be Effects.BOLD. If I replace it with a new BoldEffect() the compiler complains. Does anyone know why the static instantiation throws off the compiler?
public static final Effect BOLD = new BoldEffect();
This use of raw types essentially turns off type checking entirely anywhere BOLD is used. Turn it into Effect<Boolean, BoldSpan> and type checking will work properly.

Bounded types: Multiple bounds

I have read this article here and tried to figure out how to work with bound types. What I try to achieve is a parametrized method that handles four different cases:
T extends B only
T extends B and I (here D)
T extends I only
everything else
So here is the code:
public class Main {
public static void main(String... args) {
B b = new B();
D d = new D();
I i = new I() {
};
handle("aaasd");
handle(b);
handle(d); <---- Problem 1
handle(i);
}
public static class B {
}
public static interface I {
}
public static class D extends B implements I {
}
public static <T> void handle(T objT) {
System.out.println("T");
}
private static <T extends B> void handle(T obj) {
System.out.println("B");
}
public static <T extends B & I> void handle(T objT) { <--- Problem 2
System.out.println("B+I");
}
private static <T extends I> void handle(T obj) {
System.out.println("I");
}
}
The compiler complains and says two things:
Ambiguous call
The method handle(Main.D) is ambiguous for the type Main
I guess the problem is caused by the same cause as Problem number 2. The & I clearly bounds the type of T to a subtype of B AND I thus removing ambiguity in my opinion.
Same erasure handle
Method handle(T) has the same erasure handle(Main.B) as another method in type Main
My guess is that this is the real cause for all the problems. Java somehow removes bounding to I during runtime? But when I call the method with type B this doesn't call the annoted method.
Can someone explain how I fix the problem/distinguish between B, B&I and I?
Java somehow removes bounding to I during runtime?
No, Java removes every type information at runtime (except for reflection purposes) which is called type erasure.
Using bounds the compiler would be able to translate your code to handle(Object), handle(B) and handle(I) but in the T extends B & I case the compiler would get conflicts.
AFAIK, there's no way to fix this without having a common bound, e.g. T extends D instead of T extends B & I where D extends B implements I or to change the method name or add another parameter.
Another way might be to add the logic in the B+I case to either the B or I method and check for the second condition inside, e.g.
private static <T extends B> void handle(T obj) {
if( obj instanceof I) {
System.out.println("B+I");
}
else {
System.out.println("B");
}
}
There's a concept known as type erasure that applies to all generics in Java. With generic methods, after compilation, the methods in the byte code appear as their erasure, so
public static <T> void handle(T objT) {
System.out.println("T");
}
private static <T extends B> void handle(T obj) {
System.out.println("B");
}
public static <T extends B & I> void handle(T objT) { <--- Problem 2
System.out.println("B+I");
}
private static <T extends I> void handle(T obj) {
System.out.println("I");
}
actually become
public static void handle(Object objT) {
System.out.println("T");
}
private static void handle(B obj) {
System.out.println("B");
}
public static void handle(B objT) {
System.out.println("B+I");
}
private static void handle(I obj) {
System.out.println("I");
}
The left-most bound of a type variable is what a parameter of that type gets replaced with. As you can see, both your 2nd and 3rd method have the same name and same parameter types, ie. the same signature. This cannot be allowed by the compiler.
However, the syntax of bounds forces you to provide the class type before any interface types so
<T extends I & B>
wouldn't work. It also wouldn't work because your 4th method would again have the same erasure.
Additionally, invoking
handle(d);
is a problem since both the 2nd and 4th method could handle it, none is more specific. This is known as overloading ambiguity.

Categories