Scala学习笔记(八)----类型问题

先看一段 java代码

public class test
{

	public static void main(String[] args) throws ClassNotFoundException, SQLException
	{
		List<Pet> list = new ArrayList<Pet>();
		list.add(new Dog("Limbo",1));
		list.add(new Dog("Yu",1));
		workWithPets(list);
	}
	public static void workWithPets(List<Pet> list)
	{
		for(Pet p : list)
		{
			System.out.println(p);
		}
	}
}
class Pet{
	private String name;
	private int age;
	public Pet(){}
	public Pet(String name,int age)
	{
		this.name = name;
		this.age = age;
		// TODO Auto-generated constructor stub
	}
	@Override
	public String toString()
	{
		return "name: "+ this.name +" age: "+ this.age;
	}
}
class Dog extends Pet{
	public Dog(String name,int age)
	{
		super(name,age);
		// TODO Auto-generated constructor stub
	}
}
OK,这一段代码编译执行均无问题

接下来让我们看一段Scala代码

class Pets(var name:String,var age:Int) {
  override def toString() :String = {"name: " + name + " age: " + age}
}
class Dog(override var name:String,override var age:Int )extends Pets(name, age)
{}

object test3{
  def main(args: Array[String]): Unit = {
    val dogs = Array(new Dog("Limbo",1),new Dog("Yu",2))
    workWithPets(dogs)   //Compiling Error
  }
  def workWithPets(pets:Array[Pets])={
    pets.foreach(println)
  }
}
调用workWithPets()的时候,Scala会提示错误,Dog数组不能穿给接收Pet数组的方法,但是,对这个方法而言,这么做没有什么不良后果。不过Scala不知道这一点,它试图保护我们。我们需要做的就是告诉Scala这样做是可行的

def workWithPets[T <: Pet](pets:Array[T])={
    pets.foreach(println)
  }
这里用特殊的语法定义了workWithPets()。 T <: Pet 表示T所代表的类派生自Pet。通过使用这种上界语法,我们告诉Scala,具有参数化类型T的类型T的参数数组必须至少是Pet的数组,也可以是Pet的派生类的数组。

协变:将子类实例的容器赋给基类容器的能力

逆变:将超类实例的容器赋给子类容器的能力
例子:

如果一个方法要接受Dog参数,那么另一个接受Animal参数的方法肯定也可以接受这个方法的参数,这是Animal向Dog方向的转变是逆变。如果一个方法要求的返回值是Animal,那么返回Dog的方法肯定是可以满足其返回值要求的,这是Dog向Animal方向的转变是协变。


你可能感兴趣的:(Scala学习笔记(八)----类型问题)