3

In the documentation for the utility interface Types, of which an instance must be made available to an annotation processor for Java SE 6 or 7 by the compiler, there are two methods which interest me for a code snippet I'm working on. I need to check if a field's type is a type that inherits from a specific abstract class. The two methods that seem applicable are isAssignable and isSubtype. But I'm not certain which of these to use.

I've checked those parts of the Java Language Specification that are referenced in the above documentation. I understand the difference between the concepts of subtypes and assignment conversion (at least I think I do). Unless I'm mistaken, java.lang.Short would not be a subtype of the primitive long (subtyping is defined amongst primitves, but not across classes and primitives), but it can be assigned like so thanks to unboxing and widening conversion:

final Short s = 0;
final long l = s;

However, I'm still not certain what the best method to use would be in my case. Checking for a subtype seems more strict and preferable than assignability, but when it comes to classes it feels as if one automatically implies the other.

Long version short: are isAssignable and isSubtype equivalent when the compared TypeMirrors are both for classes (not interfaces or enums)?

G_H
  • 11,514
  • 2
  • 32
  • 73

1 Answers1

1

If we take assignment of references, the only conversion which applies in this case is the widening reference conversion (except for the identity conversion, of course). Now we have the following rules for carrying it out:

A widening reference conversion exists from any type S to any type T, provided S is a subtype (§4.10) of T.

This means that if you consider only classes, it doesn't matter whether you talk about subtypes or assignability. So yes, the mentioned methods are equivalent in this case.

Malcolm
  • 38,924
  • 10
  • 67
  • 89
  • Excellent! Then I guess it won't matter a great deal. I'll go with the subtype method since it seems to express the intent best. – G_H Oct 14 '11 at 12:02
  • 1
    The cited statement does seem to imply such thing. What about raw types? I am pretty sure, that `HashMap` is not subtype of `HashMap`, yet it is assignable to it. – user1643723 Mar 22 '16 at 05:04
  • @user1643723 As far as the JVM is concerned, these two types are exactly the same because of the type erasure. And since they are the same, `isAssignableFrom` will return `true`. – Malcolm Mar 22 '16 at 09:44
  • 1
    We are talking from compiler standpoint here, not runtime standpoint. Compiler allows assignment via unchecked conversion, but according to JLS, raw type is not subtype of it's generic version. Hence your answer seems to be wrong. – user1643723 Mar 23 '16 at 02:27
  • @user1643723 I don't see how your rumination is relevant to the question. It names very specific circumstances and asks about the methods (runtime behavior). Obviously enough, the answer to such a question doesn't apply to the compiler behavior and assignability in general, so I don't see what you are getting at. – Malcolm Mar 23 '16 at 08:23
  • 1
    @Malcolm sorry, but have you read the question before answering? It asks about specific methods from [java.lang.mode](http://docs.oracle.com/javase/7/docs/api/javax/lang/model/package-summary.html) package, used for writing javac plugins. It certainly *does* have to do with "compiler behavior and assignability in general". – user1643723 Mar 23 '16 at 09:31
  • @user1643723 Did _you_ though? I will quote the question: "I need to check if a field's type is a type that inherits from a specific abstract class." The answer pertains only to this specific case. I should've probably explained the question you asked based on the JLS, but it in any case has no relevance to original question. – Malcolm Mar 23 '16 at 09:45
  • 1
    It does have relevance: "are isAssignable and isSubtype equivalent when the compared TypeMirrors are both for classes". The asker was interested in his particular case, but haven't posted his code. The actual behavior in his case is going to depend on the way he creates TypeMirrors (e.g. whether or not [Types#erasure](https://docs.oracle.com/javase/8/docs/api/javax/lang/model/util/Types.html#erasure-javax.lang.model.type.TypeMirror-) is called). IMO, the full, proper answer would be: "as of JLS 8, they are the same except for when raw types are involved". – user1643723 Mar 23 '16 at 10:30
  • @user1643723 You can suggest an edit in that case with the clarification you metnioned. – Malcolm Mar 23 '16 at 12:42
  • 1
    @user1643723 you are totally right. This answer is incomplete. I suggest you to write a better answer with the generics case, since I feel that would be useful for future readers. – Aurasphere Sep 03 '16 at 22:17