问题
I'm using Kotlin with Spring Security. When implementing this method:
public interface UserDetails extends Serializable {
Collection<? extends GrantedAuthority> getAuthorities();
...
}
I noticed Intellij generates this Kotlin code:
override fun getAuthorities(): MutableCollection<out GrantedAuthority> { ... }
... which makes sense since java.util.Collection
is mutable.
However, if I replaced the MutableCollection
with Collection
(which should be kotlin.collections.Collection
IIRC), the code still compiles fine. This confuses me because kotlin.collections.Collection
is a read-only interface that MutableCollection
inherits from. It doesn't make sense that I can return an immutable collection for a method that's declared to return a mutable collection.
So my questions are:
- Why does using
kotlin.collections.Collection
not cause an error here? - What's the correct Kotlin return type that's equivalent to
java.util.Collection
?
回答1:
- Why does using
kotlin.collections.Collection
not cause an error here?
If you're not aware, the mutable and non-mutable collection interfaces in Kotlin both resolve to one interface in Java. So Kotlin's Collection
and MutableCollection
are both java.util.Collection
in Java, Kotlin's List
and MutableList
are both java.util.List
in Java, and so on.
Also, Kotlin has what it terms declaration-site variance. The Kotlin Collection
interface is defined as Collection<out E>
which means the interface is a producer of type E
. As a consequence, having:
val col: Collection<GrantedAuthority> = ...
Is nearly the same as:
val col: MutableCollection<out GrantedAuthority> = ...
I say nearly because, while MutableCollection<out ...>
prevents anyone from adding any elements, it does not prevent one from mutating the collection entirely. For example, you could still call clear()
on the collection.
- What's the correct Kotlin return type that's equivalent to
java.util.Collection
?
Java does not have declaration-site variance. It also doesn't distinguish between mutable and non-mutable collections (at least not at the interface level).
This means that, technically, the best match of the following Java type:
Collection<? extends GrantedAuthority>
Is the following Kotlin type:
MutableCollection<out GrantedAuthority>
Both types are mutable collection types and are defined to be producers of type GrantedAuthority
(via ? extends
in Java and out
in Kotlin). Neither type let's you add anything to the collection.
However, if your getAuthorities()
method is supposed to return an unmodifiable collection (e.g. Collections.unmodifiableCollection(collection)
in Java) then the more appropriate conversion from Java to Kotlin would be to use:
kotlin.collections.Collection<GrantedAuthority>
回答2:
The reason that this works is that Collection
and MutableCollection
are both equivalent to java.util.Collection
. You can see the full list of Java types that are mapped for Java interop here.
This works because the non-mutable collection interfaces aren't actually immutable (for that, you'd want the Immutable Collections Library), but they simply provide a read-only interface (as you note). Since Java doesn't make this distinction, both have to be mapped to the same Java platform type.
What's the correct Kotlin return type that's equivalent to
java.util.Collection
?
The correct return type depends on the interface you want to expose to your Kotlin clients. If they shouldn't be mutating the returned collection, use Collection
. If you expect them to want to mutate it, use MutableCollection
. For your Java clients, it doesn't matter: they're equivalent.
来源:https://stackoverflow.com/questions/63128815/implement-java-method-that-returns-collection-in-kotlin