1. 泛型基础
像 java 一样,Kotlin 中可以拥有类型参数
java实现:
class Box<T>
{
public T value;
public Box(T t)
{
value = t;
}
}
public class GenericBasic
{
public static void main(String[] args)
{
List list = new ArrayList();
list.add("abc");
list.add(30);
list.add(true);
List<String> strList = new ArrayList<>();
strList.add("abc");
strList.add("xyz");
List<Integer> intList = new ArrayList<>();
intList.add(30);
intList.add(40);
Box<Integer> box1 = new Box<>(20);
Box<String> box2 = new Box<>("abcd");
}
}
kotlin实现:
// 泛型:泛型基础
class Box1<T>(t:T)
{
var value = t
}
fun main(args: Array<String>)
{
var box1:Box1<Int> = Box1(30)
var box2:Box1<String> = Box1("hello world")
println(box1.value)
println(box2.value)
}
2. 类型变异
java 类型系统最棘手的一部分就是通配符类型。但 kotlin 没有,代替它的是两种其
它的东西:声明变化和类型投影(declaration-site variance and type projections)。
首先,我们想想为什么 java 需要这些神秘的通配符。这个问题在Effective Java,条
目18中是这样解释的:使用界限通配符增加 API 的灵活性。首先 java 中的泛型是
不变的,这就意味着 List 不是 List 的子类型。为什么
呢,如果 List 不是不变的,就会引发下面的问题:
// Java
List<String> strs = new ArrayList<String>();
List<Object> objs = strs; // !!! The cause of the upcoming probl
em sits here. Java prohibits this!
objs.add(1); // Here we put an Integer into a list of Strings
String s = strs.get(0); // !!! ClassCastException: Cannot cast I
nteger to String
因此 java 禁止了这样的事情来保证运行时安全。但这有些其它影响。比
如, Collection 接口的 addAll() 方法。这个方法的签名在哪呢?直观来讲
是这样的:
//java
interface Collection<E> ... {
void addAdd(Collection<E> items);
}
但接下来我们就不能做下面这些简单事情了:
//java
void copyAll(Collection<Object> to, Collection<String> from){
to.addAll(from);
}
这就是为什么 addAll() 的签名是下面这样的:
//java
interface Collection<E> ... {
void addAll(Colletion<? extend E> items);
}
这个通配符参数 ? extends T 意味着这个方法接受一些 T 类型的子类而非 T 类
型本身。这就是说我们可以安全的读 T’s (这里表示 T 子类元素的集合),但不能
写,因为我们不知道 T 的子类究竟是什么样的,针对这样的限制,我们很想要这样
的行为: Collection 是 Collection
// 泛型:类型变异
// out:使用out声明的T只能在获取值的地方使用
// in:使用in声明的T只能在设置值的地方使用
// out称为生产者(Producer) clear
// in称为消费者(Consumer)
abstract class Source<out T>
{
abstract fun nextT():T
}
fun demo(strs:Source<String>)
{
val objects:Source<Any> = strs
println(strs.nextT())
}
abstract class Comparable<in T>
{
abstract fun compareTo(other:T):Int
}
fun demo1(x:Comparable<Double>)
{
var a = x.compareTo(1.0)
val y:Comparable<Double> = x
println(y.compareTo(2.0))
}
class AAA : Comparable<Double>(){
override fun compareTo(other: Double): Int {
return (other+other).toInt()
}
}
class BBB : Source<String>(){
override fun nextT(): String {
return "hello"
}
}
fun main(args: Array<String>)
{
var mComparable: AAA = AAA()
var mSource: BBB = BBB()
demo(mSource)
demo1(mComparable)
}
3.类型投射(Type Projection)
// 类型投射(Type Projection)
// out和in out T, List<String>可以作为List<Object>的子类型
class MyArray<T>(val size:Int)
{
fun get(index:Int):T?
{
var t:T? = null
return t
}
fun set(index:Int, value:T)
{
}
}
/*fun copy(from:MyArray<Any>, to:MyArray<Any>)
{
//
}*/
// out的目的就是不允许copy函数修改from的任何数据
// 类型投射
fun copy(from:MyArray<out Any>, to:MyArray<Any>)
{
//
}
// 类型投射
fun fill(dest:MyArray<in String>, value:String)
{
}
fun main(args: Array<String>)
{
val ints:MyArray<Int> = MyArray(10)
val any: MyArray<Any> = MyArray(10)
copy(ints, any)
}