2016-11-12 68 views
6

我有一个Java/Kotlin互操作问题。一个Kotlin不可变列表被编译成一个可变的普通java.util.ArrayList!如何在Kotlin中创建一个也是Java中不可变列表的不可变列表?

科特林(库):

class A { 
    val items: List<Item> = ArrayList() 
} 

的Java(消费者):

A a = new A(); 
a.getItems().add(new Item()); // Compiles and runs but I wish to fail or throw 

如何使我的科特林类从Java透视图中也完全不变的?

+0

我不熟悉Kotlin,但番石榴Java库有一个'ImmutableList'类型,您可以使用它来包装可变的'ArrayList'。 – pathfinderelite

+1

unmodifiableList(ArrayList()) –

+1

Works。请将其张贴为答案。 – WindRider

回答

10

所有非Mutable____集合在科特林是编译时只读类型默认,但不是一成不变的。请看下面的代码片段:

fun main(args: Array<String>) { 
    // Explanation for ArrayList(listOf()) later down the post 
    val list: List<Int> = ArrayList(listOf(1, 2, 3)) 
    println(list) // [1, 2, 3] 

    // Fails at compile time 
    // list.add(4) 

    // Uh oh! This works at runtime! 
    (list as MutableList<Int>).add(4) 
    println(list) // [1, 2, 3, 4] 
} 

真正拥有的不可变列表,可以考虑番石榴的Immutable____集合:

import com.google.common.collect.ImmutableList 

fun main(args: Array<String>) { 
    val list: List<Int> = ImmutableList.of(1, 2, 3) 
    println(list) // [1, 2, 3] 

    // Fails at compile time 
    // list.add(4) 

    // Fails at runtime, as expected 
    (list as MutableList<Int>).add(4) 
    println(list) // [1, 2, 3, 4] 
} 

要知道,有些科特林的标准运行功能可能返回或者是不可修改的集合,而不是可调整大小等等,所以当您直接将只读集合转换为可变集合时,所有投注都将关闭。

例如,目前listOf()这可能在未来改变!)经由Arrays.asList(T...)返回的可变参数参数阵列周围一个java.util.Arrays.ArrayList。这个“列表”可以修改,但元素永远不能被添加或删除,因为你不能调整数组的大小。有关更多信息,请参阅Arrays.asList(T...) javadoc

如果你真的想从任何给定集合中获得可变集合,请考虑使用.toMutableList()来制作副本。这将适用于任何集合:

import com.google.common.collect.ImmutableList 

fun main(args: Array<String>) { 
    val list: List<Int> = ImmutableList.of(1, 2, 3) 

    val copy = list.toMutableList() 
    copy.add(4) 

    println(copy) // [1, 2, 3, 4] 
    println(list) // [1, 2, 3] 
} 
+0

Guava必须在Android上避免。 'Collections.unmodifiableList()'是最安全和最简单的解决方案。 – WindRider

+0

@WindRider [Guava可以与Android一起使用就好了](http://stackoverflow.com/questions/14978699/is-it-a-good-idea-to-use-google-guava-library-for-android-开发),但建议使用ProGuard – kbolino

相关问题