Generics bounded parameter not applied for interface - java

Below is the code where I declared two methods whose return type are bounded parameters but one is based on interface whereas other is based on a class. In the test() method, assigning return type to String fails for method where bounded parameter extends from Class which is expected, but compiler doesn't throw error when the bounded parameter is based on interface. Can you explain why does this happen?
import java.io.FileInputStream;
import java.util.function.Predicate;
public class Dummy
{
<T extends Predicate<String>> T getBoundedByInterface()
{
return null;
}
<T extends FileInputStream> T getBoundedByClass() {
return null;
}
public void test()
{
String compilationError = getBoundedByClass(); //Expected
String works = getBoundedByInterface(); //No compilation error. Why?
}
}

The Java compiler will determine if the variable type can satisfy the generic return type of the method called. With a class such as FileInputStream, it knows that no class can be both a FileInputStream and a String because a class can't inherit from more than one class, so this is disallowed. Additionally we know that String is also final, but that doesn't figure into the compiler's logic.
However, with an interface, it's possible for a subclass to extend the bound and be a subclass of another class.
class Thing extends FileInputStream implements Predicate<String> {
// Implementation
}
This compiles for that reason.
Thing works = getBoundedByInterface();
Notice that it also works with String because the compiler doesn't take into account that String is final.

Related

Intellij not recognizing wrong return type

I have this method:
public <T extends CacheResult> T get(Object key, CacheDefinition cacheDefinition) {
return load(key, cacheDefinition.name(), cacheDefinition.getTypeReference());
}
Now my IDE complains (as expected, and which is correct) about this line, because the return type is supposed to be CacheResult
User user = spxCacheManager.get(username, CacheDefinition.USERS_BY_USERNAME);
What I currently dont understand, is that the IDE (IntelliJ) is not complaining about this:
List<User> usersFromCache = spxCacheManager.get(username, CacheDefinition.USERS_BY_USERNAME);
Which is actually wrong. What am I missing here?
This works because T gets inferred as an intersection type - List<User> & CacheResult & Object. After all, why can't a class both implement List<User> and implement/extend CacheResult? Such a type is certainly possible!
You can see this happen by writing a toy program and using the --debug=verboseResolution=all option:
import java.util.List;
public class Main {
public static void main(String[] args) {
List<User> u = new Main().get();
}
public <T extends CacheResult> T get() {
return null;
}
}
interface CacheResult {}
class User implements CacheResult {}
javac with verboseResolution=all would output:
instantiated signature: ()INT#1
target-type: List<User>
where T is a type-variable:
T extends CacheResult declared in method <T>get()
where INT#1 is an intersection type:
INT#1 extends Object,List<User>,CacheResult
You can also follow through the process of how Java does type inference. Eventually (somewhere in "resolution"), you'll reach a point where you need to find the greatest lower bound ("glb") of Object, List<User> and CacheResult, and that type is exactly their intersection type, as defined here.
On the other hand, your code won't compile if CacheResult is a class, and the type you are assigning the method result to is an unrelated class, since no class can inherit from two unrelated classes.

Class<Result> cannot be converted to Class<Result<Integer>>

Suppose I have and API method declared as following
public class Dummy {
public static class Result<ValueT extends Comparable> {
public ValueT value;
}
public static <ValueT extends Comparable> Result<ValueT>
getResult(Class<? extends Result<ValueT>> ofType) throws Exception {
return ofType.newInstance();
}
}
Now I'd like to invoke it relying on Java compile-time type verification and just can't find correct syntax to do this:
Attempts:
getResult(Result<Integer>.class) <-- expected syntax
public static void invokeGetResult() {
Result<Integer> intResult = getResult(Result<Integer>.class);
}
results in
error: <identifier> expected
Result<Integer> intResult = getResult(Result<Integer>.class);
^
getResult(Result.class) <-- just to try
public static void invokeGetResult() {
Result<Integer> intResult = getResult(Result.class);
}
results in
error: method getResult in class Dummy cannot be applied to given types;
Result<Integer> intResult = getResult(Result.class);
^
required: Class<? extends Result<ValueT>>
found: Class<Result>
reason: cannot infer type-variable(s) ValueT
(argument mismatch; Class<Result> cannot be converted to Class<? extends Result<ValueT>>)
where ValueT is a type-variable:
ValueT extends Comparable declared in method <ValueT>getResult(Class<? extends Result<ValueT>>)
getResult((Class<Result<Integer>>)Result.class) <-- just to try
public static void invokeGetResult() {
Result<Integer> intResult = getResult((Class<Result<Integer>>)Result.class);
}
results in
error: incompatible types: Class<Result> cannot be converted to Class<Result<Integer>>
Result<Integer> intResult = getResult((Class<Result<Integer>>)Result.class);
^
If the only purpose of passing the Class<...> is to instantiate it, consider using a Supplier<...> instead. It does not have this problem, and does not throw any exceptions.
Here is an example:
class SomeClass extends Result<Integer> {...}
public static <T extends Result<?>> T getResult(Supplier<T> constructor) {
return constructor.get();
}
Use like:
getResult(SomeClass::new); // Passes the constructor.
There isn't really such thing as a Class<Result<Integer>>. Class objects represent reifiable classes at runtime, and there is only one single Class object at runtime for the class Result, which you can get via the expression Result.class, which has type Class<Result>. There are no Class objects representing Result<Integer> or Result<String>, etc.
You can take the expression of type Class<Result> (which you get from Result.class) and do a bunch of unsafe casts on it to turn it into a Class<Result<Integer>> or something like that, for example:
`(Class<Result<Integer>>)(Class<?>)Result.class`
but not that this is unsafe. It is unsafe because the interface of Class has certain methods that return T (the type parameter of the class Class) based on runtime type operations with the class. For example, Class has a method .cast() which checks whether the passed object is an instance of the class, and if not, throws an exception, and if it is, then returns the object, as type T. If you call Result.class.cast(), it returns a Result, and the method indeed checks at runtime that the object is a Result. But if you call .cast() on an expression of type Class<Result<Integer>>, it returns type Result<Integer>, but the class could not have checked at runtime that the thing is a Result<Integer>, because 1) this is just the same Result class object, and 2) generic information doesn't exist at runtime. So you would get a Result<Integer> that might not be a Result<Integer>.
So basically, you need to think about what you are using this class object to do, and how it makes sense to have it as a Class<Result<Integer>> when all you can have at runtime is a class object representing the raw type Result.
Here you have a method that takes Class<? extends Result<ValueT>>. I am wondering why you have the wildcard here. Are you trying to have it accept subclasses of Result? Because if not, then the only thing that can be passed in is the unique Result class object itself, which means the parameter is basically pointless because it's always the same thing that can be passed in; in that case you might as well get rid of the parameter and just do:
public static <ValueT extends Comparable<? super ValueT>> Result<ValueT>
getResult() throws Exception {
return new Result<ValueT>();
}
If you are going to accept subclasses of Result, then you're assuming that all subclasses must have a no-parameter constructor, as you are calling .newInstance() on it, which is bad design. You should use something like a Supplier as Jorn Vernee's answer suggests.
EDIT: I did not understand clearly the original intentions. This example should work for your call, however it is a bit hacky and not so recommended.
public class Dummy {
public static class Result<ValueT extends Comparable> {
public ValueT value;
}
public static <ValueT extends Comparable> Result<ValueT>
getResult(Class<? extends Result<ValueT>> ofType) {
return null;
}
}
You can call it like this:
Dummy.Result<Integer> result = Dummy.getResult(new Result<Integer>(){}.getClass());
The compile time verification should work with this example, as you are creating an anonymous empty class and it's type information can be retrieved successfully.
You could also do a type cast as #Jorn suggested in comments, although your compiler will warn you about the fact it is an "unchecked cast".

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.

Passing parameterized Class instance to the constructor

I have lost in the Jungle of Generics, please help me :) I have something like this:
public class BaseClass<TYPE> {
public BaseClass(Class<TYPE> clazz) {};
}
public class FirstLevelClass<REFRESHABLE
extends RefreshableInterface> extends BaseClass<REFRESHABLE> {
public FirstLevelClass(Class<REFRESHABLE> clazz) {
super(clazz);
};
}
public class Argument<T extends AnyOtherClass>
implements RefreshableInterface {
public refresh() {}
}
pulbic class ProblematicClass
extends FirstLevelClass<Argument<AnyOtherClassDescendant>> {
public ProblematicClass() {
//Compiler error: Constructor
//FirstLevelClass<Argument<AnyOtherClassDescendant>>(Class<Argument>) is undefined
super(Argument.class);
}
}
As far as I think, the compiler should accept Argument since it implements RefreshableInterface.
Why do I get this error?
How can I make the ProblematicClass working?
ps: if you have better title for this, please change it. I could not make up better.
Issue is, your constructor expects a Class<T>, and T in your code is inferred as Argument<AnyOtherClassDescendant>.
So, you should pass a Class<Argument<AnyOtherClassDescendant>>, and you're passing Class<Argument>. But you can't pass that Class instance directly, as you cannot do Argument<AnyOtherClassDescendant>.class.
You can however, solve the issue by typecasting the class to required instance:
public ProblematicClass() {
super((Class<Argument<AnyOtherClassDescendant>>)(Class<?>)Argument.class);
}
Note, how you've to typecast Class<Argument> first to Class<?>, and then the resultant type to Class<Argument<AnyOtherClassDescendant>>. There is no simple way to achieve that.
The reason behind this is, there is only a single Class instance for all parameterized instantiation of a generic type, that is associated with the class itself. A single compilation unit of a generic type, compiles to just a single class file. I guess this is different in how C++ implements templates. There you get different machine codes for different instantiation.
So, if you execute the below code, you'll get true as output:
List<String> strList = new ArrayList<String>();
List<Integer> intList = new ArrayList<Integer>();
boolean isSameClassInstance = strList.getClass() == intList.getClass();
System.out.println(isSameClassInstance);

Multiple Inheritance with Base Class and Interface having same function with different return types

I have written a class which is a base class of Class A and implements an interface of Class B.
Now my compiler is giving a wierd kind of error saying that "The return types of functiona from Class A is not compatible with return type of functiona in class B."
My Code is as below,
public class X extends A implements B
{
}
public class A
{
public Enumeration<String> test(){}
}
public interface B
{
public Enumeration<Object> test();
}
Now I can't understand why the compiler is giving such an error since already String is a type of an object, so what i understood is that automatic type conversion should happen in runtime because of that. Am i right? or my conceptual understanding has gone wierd on me?
If you can change the definition of the interface, you can broaden it and get what you want. The return type would be Enumeration<? extends Object>
What you're trying to do is possible in Java. As Ernest stated, an Enumeration is not a subclass of Enumeration, since Java genercis lacks the concept of variance.
Anyway, you can express you intention using type wildcard. You have to change you interface this way:
public interface B
{
public Enumeration<?> test();
}
Now your code compile fine. Just to let you know, you can also restrict your interface to some other type than Object. For example, if you have to build an interface that return Enumerations
of Number:
class X extends A implements B
{
}
class A
{
public Enumeration<Long> test(){return null;}
}
class C
{
public Enumeration<String> test(){return null;}
}
//This doesn't compile! String does not extend Number
/*class Y extends C implements B
{
}*/
interface B
{
public Enumeration<? extends Number> test();
}
String is a subclass of Object, but Enumeration<String> is not a subclass of Enumeration<Object>. If it were, then I could cast an Enumeration<String> to an Enumeration<Object>, then cast it to an Enumeration<Integer>, all without a warning; but when I tried to use it as an Enumeration<Integer>, I'd get ClassCastExceptions.
Note that Java arrays behave as I've described above, and this is widely considered a significant flaw in the design of the language.

Categories