Scala中的类、接口及协变和逆变



4.   OOP

4.1.     类class

4.1.1.  定义

例子1:

class User {

var name = "anonymous"

var age:Int = _

val country = "china"

def email = name + "@mail"

}

使用:

val u = new User

// var定义的属性可读可写

u.name = "qh"; u.age = 30

println(u.name + ", " + u.age) // "qh, 30"

// val 定义的属性只读不可写

u.country = "usa" // 报错

println(u.country) // "china"

// def 定义的是方法, 每次调用时重新计算

u.email // "[email protected]"

例子2:

// 定义

class Person(ln : String, fn : String, s : Person = null) {

def lastName = ln;   // 用def定义后才是属性,ln,fn,s不可见

def firstName = fn;

def spouse = s;

def introduction() : String =

return (

("Hi, " + firstName + " " + lastName) +

(if (spouse != null) " and spouse, " + spouse.firstName + " " + spouse.lastName + "."

else ".")

);

}

// 调用

new Person("aa","bb", new Person("cc","dd")).introduction();

4.1.2.  构造方法

class c1(x:String) // 等同于:class c1(private var x:String)

val o1 = new c1("aaa")

o1.x // 报错,因为是private的,定义成 class
c1(var x:String) 或者
class c1(val x:String) 才能这样用

例子1:

object construct1 {

class c1(name:String, age:Int) { // (1)直接在类定义处

def this() { this("anonymous", 20) } // (2)用this定义

def m1() = {  printf("%s=%d\n", name, age) }

}

def main(args:Array[String]) = {

new c1().m1()

new c1("qh", 30).m1()

}

}

编译:fsc construct1.scala

运行:java construct1

例子2:继承中的构造方法:

class c2(name:String, age:Int, female:Boolean=false) extends c1(name,age) {

override def toString = { name + "," +  age + "," + female }

}

4.1.3.  override

不同于Java的使用 @Override,或者直接使用相同名字覆盖父类方法。

override def toString = { name + "," +  age + "," + female }

如果是覆盖抽象方法,可以不用override关键字。

4.1.4.  object单例对象
天然的Singleton

classes in Scala cannot have static members. Instead, Scala has singleton objects.

A singleton object definition looks like a class definition, except instead of the keyword class you use the keyword object.

Defining a singleton object doesn‘t define a type.

When a singleton object shares the same name with a class, it is called that class’s companion object. You must define both the class and its companion object in the same source file. The class is called the companion class of the singleton object. A class
and its companion object can access each other‘s private members.

A singleton object is more than a holder of static methods, however. It is a first-class object. A singleton object is initialized the first time some code accesses it.

如:


Java


Scala

[java] view plaincopyprint?

  1. public class User {
  2. private String name;
  3. private User(String name) { this.name=name; }
  4. private static theUser = new User("Nick");
  5. public static User instance() {
  6. return theUser;
  7. }
  8. }
public class User {
  private String name;
  private User(String name) { this.name=name; }
  private static theUser = new User("Nick");
  public static User instance() {
    return theUser;
  }
}

[java] view plaincopyprint?

  1. object User {
  2. var name:String = _
  3. def apply(name:String){this.name=name; this}
  4. override def toString = "name: " + name
  5. }
object User {
  var name:String = _
  def apply(name:String){this.name=name; this}
  override def toString = "name: " + name
}

[java] view plaincopyprint?

</pre></td></tr></tbody></table><p style="color: rgb(51, 51, 51); font-family: Helvetica,Arial,sans-serif; font-size: 14px; background-color: rgb(249, 249, 249);"> <span style="color: rgb(51, 51, 51); font-family: 宋体; font-size: 14px; background-color: rgb(249, 249, 249);">A singleton object that does not share the same name with a companion class is called a standalone object. You can use standalone objects for many purposes, including collecting related utility methods together, or defining an entry point to a Scala application.</span></p><h3 style="color: rgb(51, 51, 51); font-family: Helvetica,Arial,sans-serif; background-color: rgb(249, 249, 249);"><a target=_blank name="t6"></a><a target=_blank name="_Toc282027560" class="ui-link             " style="color: rgb(36, 137, 206);" target="_blank" rel="nofollow"></a><a target=_blank name="_Toc281660028" class="ui-link             " style="color: rgb(36, 137, 206);" target="_blank" rel="nofollow"></a><span style="line-height: 24px; font-family: Consolas; font-size: 10.5pt;">4.1.5.<span style="line-height: normal; font-family: 'Times New Roman'; font-size: 7pt; font-weight: normal;">  </span></span><u><span style="line-height: 32px; font-family: 微软雅黑,sans-serif; font-size: 14pt;">静态方法</span></u></h3><p style="color: rgb(51, 51, 51); font-family: Helvetica,Arial,sans-serif; font-size: 14px; background-color: rgb(249, 249, 249);"><span style="font-family: Consolas;">Scala</span><span style="font-family: 宋体;">没有静态方法,类似静态方法的函数定义在</span><span style="font-family: Consolas;">object</span><span style="font-family: 宋体;">中:</span></p><p style="color: rgb(51, 51, 51); font-family: Helvetica,Arial,sans-serif; font-size: 14px; background-color: rgb(249, 249, 249);"><span style="font-family: Consolas;">object Stringx {</span></p><p style="color: rgb(51, 51, 51); font-family: Helvetica,Arial,sans-serif; font-size: 14px; background-color: rgb(249, 249, 249);"><span style="font-family: Consolas;">    def left(s0:String, s:String) = ...</span></p><p style="color: rgb(51, 51, 51); font-family: Helvetica,Arial,sans-serif; font-size: 14px; background-color: rgb(249, 249, 249);"><span style="font-family: Consolas;">}</span></p><p style="color: rgb(51, 51, 51); font-family: Helvetica,Arial,sans-serif; font-size: 14px; background-color: rgb(249, 249, 249);"><span style="font-family: 宋体;">直接调用</span><span style="font-family: Consolas;">Stringx.left(s0, s)</span><span style="font-family: 宋体;">,或者</span><span style="font-family: Consolas;"> Stringx left (s0, s)</span></p><p style="color: rgb(51, 51, 51); font-family: Helvetica,Arial,sans-serif; font-size: 14px; background-color: rgb(249, 249, 249);"><span style="font-family: Consolas;"> </span></p><p style="color: rgb(51, 51, 51); font-family: Helvetica,Arial,sans-serif; font-size: 14px; background-color: rgb(249, 249, 249);"><span style="font-family: 宋体;">定义在</span><span style="font-family: Consolas;">object</span><span style="font-family: 宋体;">中的</span><span style="font-family: Consolas;">implicit</span><span style="font-family: 宋体;">方法也能被直接调用:</span></p><p style="color: rgb(51, 51, 51); font-family: Helvetica,Arial,sans-serif; font-size: 14px; background-color: rgb(249, 249, 249);"><span style="font-family: 宋体;">例如:</span></p><p style="color: rgb(51, 51, 51); font-family: Helvetica,Arial,sans-serif; font-size: 14px; background-color: rgb(249, 249, 249);"><span style="font-family: Consolas;">--------- <u>ImportSub.scala</u></span></p><p style="color: rgb(51, 51, 51); font-family: Helvetica,Arial,sans-serif; font-size: 14px; background-color: rgb(249, 249, 249);"><span style="color: rgb(127, 0, 85); font-family: Consolas;">object</span><span style="font-family: Consolas;"> <span style="background-color: silver;">ImportSub</span> {</span></p><p style="color: rgb(51, 51, 51); font-family: Helvetica,Arial,sans-serif; font-size: 14px; background-color: rgb(249, 249, 249);"><span style="font-family: Consolas;">  </span><span style="color: rgb(127, 0, 85); font-family: Consolas;">def</span><span style="font-family: Consolas;"> fac(n: </span><span style="color: rgb(127, 0, 85); font-family: Consolas;">Int</span><span style="font-family: Consolas;">) = 1 to n reduceLeft (_ * _)</span></p><p style="color: rgb(51, 51, 51); font-family: Helvetica,Arial,sans-serif; font-size: 14px; background-color: rgb(249, 249, 249);"><span style="font-family: Consolas;">  </span><span style="color: rgb(127, 0, 85); font-family: Consolas;">implicit</span><span style="font-family: Consolas;"> </span><span style="color: rgb(127, 0, 85); font-family: Consolas;">def</span><span style="font-family: Consolas;"> foo(n: </span><span style="color: rgb(127, 0, 85); font-family: Consolas;">Int</span><span style="font-family: Consolas;">) = </span><span style="color: rgb(127, 0, 85); font-family: Consolas;">new</span><span style="font-family: Consolas;"> { </span><span style="color: rgb(127, 0, 85); font-family: Consolas;">def</span><span style="font-family: Consolas;"> ! = fac(n) }</span></p><p style="color: rgb(51, 51, 51); font-family: Helvetica,Arial,sans-serif; font-size: 14px; background-color: rgb(249, 249, 249);"><span style="font-family: Consolas;">}</span></p><p style="color: rgb(51, 51, 51); font-family: Helvetica,Arial,sans-serif; font-size: 14px; background-color: rgb(249, 249, 249);"><a target=_blank name="_case_class" class="ui-link             " style="color: rgb(36, 137, 206); font-weight: bold;" target="_blank" rel="nofollow"></a><span style="font-family: Consolas;">--------- <u>ImportMain.scala</u></span></p><p style="color: rgb(51, 51, 51); font-family: Helvetica,Arial,sans-serif; font-size: 14px; background-color: rgb(249, 249, 249);"><span style="color: rgb(127, 0, 85); font-family: Consolas; background-color: yellow;">import</span><span style="font-family: Consolas; background-color: yellow;"> ImportSub._</span></p><p style="color: rgb(51, 51, 51); font-family: Helvetica,Arial,sans-serif; font-size: 14px; background-color: rgb(249, 249, 249);"><span style="color: rgb(127, 0, 85); font-family: Consolas;">object</span><span style="font-family: Consolas;"> ImportMain {</span></p><p style="color: rgb(51, 51, 51); font-family: Helvetica,Arial,sans-serif; font-size: 14px; background-color: rgb(249, 249, 249);"><span style="font-family: Consolas;">  </span><span style="color: rgb(127, 0, 85); font-family: Consolas;">def</span><span style="font-family: Consolas;"> main(args : </span><span style="color: rgb(127, 0, 85); font-family: Consolas;">Array</span><span style="font-family: Consolas;">[String]) : </span><span style="color: rgb(127, 0, 85); font-family: Consolas;">Unit</span><span style="font-family: Consolas;"> = {</span></p><p style="color: rgb(51, 51, 51); font-family: Helvetica,Arial,sans-serif; font-size: 14px; background-color: rgb(249, 249, 249);"><span style="font-family: Consolas;">      println(<span style="background-color: yellow;">5!</span>) </span><span style="color: rgb(63, 127, 95); font-family: Consolas;">// </span><span style="color: rgb(63, 127, 95); font-family: 宋体;">调用</span><span style="color: rgb(63, 127, 95); font-family: Consolas;">ImportSub</span><span style="color: rgb(63, 127, 95); font-family: 宋体;">中定义的</span><span style="color: rgb(63, 127, 95); font-family: Consolas;">implicit</span><span style="color: rgb(63, 127, 95); font-family: 宋体;">函数</span></p><p style="color: rgb(51, 51, 51); font-family: Helvetica,Arial,sans-serif; font-size: 14px; background-color: rgb(249, 249, 249);"><span style="font-family: Consolas;">  }</span></p><p style="color: rgb(51, 51, 51); font-family: Helvetica,Arial,sans-serif; font-size: 14px; background-color: rgb(249, 249, 249);"><span style="font-family: Consolas;">}</span></p><h3 style="color: rgb(51, 51, 51); font-family: Helvetica,Arial,sans-serif; background-color: rgb(249, 249, 249);"><a target=_blank name="t7"></a><a target=_blank name="_Toc282027561" class="ui-link             " style="color: rgb(36, 137, 206);" target="_blank" rel="nofollow"></a><a target=_blank name="_Toc281660029" class="ui-link             " style="color: rgb(36, 137, 206);" target="_blank" rel="nofollow"></a><span style="line-height: 24px; font-family: Consolas; font-size: 10.5pt;">4.1.6.<span style="line-height: normal; font-family: 'Times New Roman'; font-size: 7pt; font-weight: normal;">  </span></span><u><span style="line-height: 32px; font-family: Consolas; font-size: 14pt;">case class(</span><span style="line-height: 32px; font-family: 微软雅黑,sans-serif; font-size: 14pt;">条件类</span><span style="line-height: 32px; font-family: Consolas; font-size: 14pt;">)</span></u></h3><p style="color: rgb(51, 51, 51); font-family: Helvetica,Arial,sans-serif; font-size: 14px; background-color: rgb(249, 249, 249);"><span style="font-family: 宋体;">例如:</span></p><p style="color: rgb(51, 51, 51); font-family: Helvetica,Arial,sans-serif; font-size: 14px; background-color: rgb(249, 249, 249);"><span style="font-family: Consolas; background-color: yellow;">case class</span><span style="font-family: Consolas;"> Person(name:String, age:Int)   </span></p><p style="color: rgb(51, 51, 51); font-family: Helvetica,Arial,sans-serif; font-size: 14px; background-color: rgb(249, 249, 249);"><span style="font-family: 宋体;">特殊之处:</span></p><p style="color: rgb(51, 51, 51); font-family: Helvetica,Arial,sans-serif; font-size: 14px; background-color: rgb(249, 249, 249);"><span style="font-family: Wingdings;">l<span style="font-family: 'Times New Roman'; font-size: 7pt;">  </span></span><span style="font-family: 宋体;">新建类实例不用</span><span style="font-family: Consolas;">new Person(..)</span><span style="font-family: 宋体;">,直接用</span><span style="font-family: Consolas;">Person("qh",20)</span></p><p style="color: rgb(51, 51, 51); font-family: Helvetica,Arial,sans-serif; font-size: 14px; background-color: rgb(249, 249, 249);"><span style="font-family: Wingdings;">l<span style="font-family: 'Times New Roman'; font-size: 7pt;">  </span></span><span style="font-family: 宋体;">自动定义好</span><span style="font-family: Consolas;">getXX</span><span style="font-family: 宋体;">方法,</span><span style="font-family: Consolas;">Person("qh",20).name // "qh"</span></p><p style="color: rgb(51, 51, 51); font-family: Helvetica,Arial,sans-serif; font-size: 14px; background-color: rgb(249, 249, 249);"><span style="font-family: Wingdings;">l<span style="font-family: 'Times New Roman'; font-size: 7pt;">  </span></span><span style="font-family: 宋体;">提供默认的</span><span style="font-family: Consolas;">toString(), Person("qh",20) // "Person(qh,20)"</span></p><p style="color: rgb(51, 51, 51); font-family: Helvetica,Arial,sans-serif; font-size: 14px; background-color: rgb(249, 249, 249);"><span style="font-family: Wingdings;">l<span style="font-family: 'Times New Roman'; font-size: 7pt;">  </span></span><span style="font-family: 宋体;">结合类继承可以通过模式匹配进行分解</span></p><p style="color: rgb(51, 51, 51); font-family: Helvetica,Arial,sans-serif; font-size: 14px; background-color: rgb(249, 249, 249);"><span style="font-family: 宋体;">例子</span><span style="font-family: Consolas;">1</span><span style="font-family: 宋体;">:</span></p><p style="color: rgb(51, 51, 51); font-family: Helvetica,Arial,sans-serif; font-size: 14px; background-color: rgb(249, 249, 249);"><span style="font-family: Consolas;">abstract class Person</span></p><p style="color: rgb(51, 51, 51); font-family: Helvetica,Arial,sans-serif; font-size: 14px; background-color: rgb(249, 249, 249);"><span style="font-family: Consolas;">case class Man(power:Int) extends Person</span></p><p style="color: rgb(51, 51, 51); font-family: Helvetica,Arial,sans-serif; font-size: 14px; background-color: rgb(249, 249, 249);"><span style="font-family: Consolas;">case class Woman(beauty:Int, from:String) extends Person</span></p><p style="color: rgb(51, 51, 51); font-family: Helvetica,Arial,sans-serif; font-size: 14px; background-color: rgb(249, 249, 249);"><span style="font-family: Consolas;"> </span></p><p style="color: rgb(51, 51, 51); font-family: Helvetica,Arial,sans-serif; font-size: 14px; background-color: rgb(249, 249, 249);"><span style="font-family: Consolas;">val w1 = Woman(100,"china")</span></p><p style="color: rgb(51, 51, 51); font-family: Helvetica,Arial,sans-serif; font-size: 14px; background-color: rgb(249, 249, 249);"><span style="font-family: Consolas;">val w2 = w1.<span style="background-color: yellow;">copy</span>(from="usa") // Woman(100,"usa")</span></p><p style="color: rgb(51, 51, 51); font-family: Helvetica,Arial,sans-serif; font-size: 14px; background-color: rgb(249, 249, 249);"><span style="font-family: Consolas;"> </span></p><p style="color: rgb(51, 51, 51); font-family: Helvetica,Arial,sans-serif; font-size: 14px; background-color: rgb(249, 249, 249);"><span style="font-family: Consolas;">def f(t:Person) = t match {</span></p><p style="color: rgb(51, 51, 51); font-family: Helvetica,Arial,sans-serif; font-size: 14px; background-color: rgb(249, 249, 249);"><span style="font-family: Consolas; background-color: yellow;">case Man</span><span style="font-family: Consolas;">(x) => "man's power:" + x</span></p><p style="color: rgb(51, 51, 51); font-family: Helvetica,Arial,sans-serif; font-size: 14px; background-color: rgb(249, 249, 249);"><span style="font-family: Consolas; background-color: yellow;">case Woman</span><span style="font-family: Consolas;">(x,y) => y + " beauty:" + x</span></p><p style="color: rgb(51, 51, 51); font-family: Helvetica,Arial,sans-serif; font-size: 14px; background-color: rgb(249, 249, 249);"><span style="font-family: Consolas;">}</span></p><p style="color: rgb(51, 51, 51); font-family: Helvetica,Arial,sans-serif; font-size: 14px; background-color: rgb(249, 249, 249);"><span style="font-family: Consolas;">f(Man(100)) // man's power:100</span></p><p style="color: rgb(51, 51, 51); font-family: Helvetica,Arial,sans-serif; font-size: 14px; background-color: rgb(249, 249, 249);"><span style="font-family: Consolas;">f(Woman(90, "china")) // china beauty:90</span></p><p style="color: rgb(51, 51, 51); font-family: Helvetica,Arial,sans-serif; font-size: 14px; background-color: rgb(249, 249, 249);"><span style="font-family: Consolas;"> </span></p><p style="color: rgb(51, 51, 51); font-family: Helvetica,Arial,sans-serif; font-size: 14px; background-color: rgb(249, 249, 249);"><span style="font-family: 宋体;">注:基本类型直接可以用</span><span style="font-family: Consolas;"><a target=_blank class="ui-link" style="color: rgb(36, 137, 206); font-weight: bold;" href="http://qiujj.com/static/Scala-Handbook.htm#_match..case(switch)" target="_blank" rel="nofollow">math case</a></span></p><p style="color: rgb(51, 51, 51); font-family: Helvetica,Arial,sans-serif; font-size: 14px; background-color: rgb(249, 249, 249);"><span style="font-family: Consolas;"> </span></p><p style="color: rgb(51, 51, 51); font-family: Helvetica,Arial,sans-serif; font-size: 14px; background-color: rgb(249, 249, 249);"><span style="font-family: 宋体;">例子</span><span style="font-family: Consolas;">2</span><span style="font-family: 宋体;">:可变的类状态</span></p><p style="color: rgb(51, 51, 51); font-family: Helvetica,Arial,sans-serif; font-size: 14px; background-color: rgb(249, 249, 249);"><span style="font-family: Consolas;">case class C1(<span style="background-color: yellow;">var s</span>: String, <span style="background-color: yellow;">var ops</span>: Int) { </span></p><p style="color: rgb(51, 51, 51); font-family: Helvetica,Arial,sans-serif; font-size: 14px; background-color: rgb(249, 249, 249);"><span style="font-family: Consolas;">  def >>= (f: (String=>String)) = {</span></p><p style="color: rgb(51, 51, 51); font-family: Helvetica,Arial,sans-serif; font-size: 14px; background-color: rgb(249, 249, 249);"><span style="font-family: Consolas;">    s = f(s)  // s</span><span style="font-family: 宋体;">改变</span></p><p style="color: rgb(51, 51, 51); font-family: Helvetica,Arial,sans-serif; font-size: 14px; background-color: rgb(249, 249, 249);"><span style="font-family: Consolas;">    ops += 1  // ops</span><span style="font-family: 宋体;">改变</span></p><p style="color: rgb(51, 51, 51); font-family: Helvetica,Arial,sans-serif; font-size: 14px; background-color: rgb(249, 249, 249);"><span style="font-family: Consolas;">    this // </span><span style="font-family: 宋体;">返回自身,可以连续调用</span></p><p style="color: rgb(51, 51, 51); font-family: Helvetica,Arial,sans-serif; font-size: 14px; background-color: rgb(249, 249, 249);"><span style="font-family: Consolas;">  } </span></p><p style="color: rgb(51, 51, 51); font-family: Helvetica,Arial,sans-serif; font-size: 14px; background-color: rgb(249, 249, 249);"><span style="font-family: Consolas;">}  </span></p><p style="color: rgb(51, 51, 51); font-family: Helvetica,Arial,sans-serif; font-size: 14px; background-color: rgb(249, 249, 249);"><span style="font-family: Consolas;">val C1(res, ops) = C1("ab", 0) >>= (_ * 3) >>= (_ drop 3)</span></p><p style="color: rgb(51, 51, 51); font-family: Helvetica,Arial,sans-serif; font-size: 14px; background-color: rgb(249, 249, 249);"><span style="font-family: Consolas;">// res="ab"->"ababab"->"bab", ops=0-> 0+1+1->2</span></p><p style="font-size: 14px; background-color: rgb(249, 249, 249);"><span style="color: rgb(204, 0, 0); font-family: Consolas;">细细体会构造对象,连续调用>>方法,然后match的这一系列过程。</span></p><p style="color: rgb(51, 51, 51); font-family: Helvetica,Arial,sans-serif; font-size: 14px; background-color: rgb(249, 249, 249);"><span style="font-family: Consolas;"> </span></p><p style="color: rgb(51, 51, 51); font-family: Helvetica,Arial,sans-serif; font-size: 14px; background-color: rgb(249, 249, 249);"><span style="font-family: 宋体;">例子</span><span style="font-family: Consolas;">3</span><span style="font-family: 宋体;">:用</span><span style="font-family: Consolas;">case class</span><span style="font-family: 宋体;">代替</span><span style="font-family: Consolas;">tuple</span></p><p style="color: rgb(51, 51, 51); font-family: Helvetica,Arial,sans-serif; font-size: 14px; background-color: rgb(249, 249, 249);"><span style="font-family: Consolas;">val p = ("qh",20) // p._1 = "qh", p._2 = 20</span><span style="font-family: 宋体;">;好处是简洁,但无意义</span></p><p style="color: rgb(51, 51, 51); font-family: Helvetica,Arial,sans-serif; font-size: 14px; background-color: rgb(249, 249, 249);"><span style="font-family: Consolas; background-color: yellow;">case class person</span><span style="font-family: Consolas;">(name:String, age:Int)</span></p><p style="color: rgb(51, 51, 51); font-family: Helvetica,Arial,sans-serif; font-size: 14px; background-color: rgb(249, 249, 249);"><span style="font-family: Consolas;">val p = person("qh",20) // p.name = "qh", p.age = 20; </span><span style="font-family: 宋体;">好处是有名字,自说明,可读性强</span></p><p style="color: rgb(51, 51, 51); font-family: Helvetica,Arial,sans-serif; font-size: 14px; background-color: rgb(249, 249, 249);"><span style="font-family: Consolas;"> </span></p><p style="color: rgb(51, 51, 51); font-family: Helvetica,Arial,sans-serif; font-size: 14px; background-color: rgb(249, 249, 249);"><span style="font-family: 宋体;">例子</span><span style="font-family: Consolas;">4</span><span style="font-family: 宋体;">:用</span><span style="font-family: Consolas;">case class</span><span style="font-family: 宋体;">来描述元数据</span></p><p style="color: rgb(51, 51, 51); font-family: Helvetica,Arial,sans-serif; font-size: 14px; background-color: rgb(249, 249, 249);"><span style="font-family: Consolas;">xml</span><span style="font-family: 宋体;">的版本:</span></p><p style="color: rgb(51, 51, 51); font-family: Helvetica,Arial,sans-serif; font-size: 14px; background-color: rgb(249, 249, 249);"><span style="font-family: Consolas;"><todo name = "housework"></span></p><p style="color: rgb(51, 51, 51); font-family: Helvetica,Arial,sans-serif; font-size: 14px; background-color: rgb(249, 249, 249);"><span style="font-family: Consolas;"><item priority = "high">Clean the hose</item></span></p><p style="color: rgb(51, 51, 51); font-family: Helvetica,Arial,sans-serif; font-size: 14px; background-color: rgb(249, 249, 249);"><span style="font-family: Consolas;"><item priority = "medium">Wash the dishes</item></span></p><p style="color: rgb(51, 51, 51); font-family: Helvetica,Arial,sans-serif; font-size: 14px; background-color: rgb(249, 249, 249);"><span style="font-family: Consolas;"><item priority = "medium">Buy more soap</item></span></p><p style="color: rgb(51, 51, 51); font-family: Helvetica,Arial,sans-serif; font-size: 14px; background-color: rgb(249, 249, 249);"><span style="font-family: Consolas;"></todo></span></p><p style="color: rgb(51, 51, 51); font-family: Helvetica,Arial,sans-serif; font-size: 14px; background-color: rgb(249, 249, 249);"><span style="font-family: Consolas;">Scala</span><span style="font-family: 宋体;">的版本:</span></p><p style="color: rgb(51, 51, 51); font-family: Helvetica,Arial,sans-serif; font-size: 14px; background-color: rgb(249, 249, 249);"><span style="font-family: Consolas;">    case class item(priority:String, s:String)</span></p><p style="color: rgb(51, 51, 51); font-family: Helvetica,Arial,sans-serif; font-size: 14px; background-color: rgb(249, 249, 249);"><span style="font-family: Consolas;">    case class todo(name:String, items:List[item])</span></p><p style="color: rgb(51, 51, 51); font-family: Helvetica,Arial,sans-serif; font-size: 14px; background-color: rgb(249, 249, 249);"><span style="font-family: Consolas;">    todo (name="housework",</span></p><p style="color: rgb(51, 51, 51); font-family: Helvetica,Arial,sans-serif; font-size: 14px; background-color: rgb(249, 249, 249);"><span style="font-family: Consolas;">items=item("high","Clean the house")::</span></p><p style="color: rgb(51, 51, 51); font-family: Helvetica,Arial,sans-serif; font-size: 14px; background-color: rgb(249, 249, 249);"><span style="font-family: Consolas;">item("medium","Wash the dishes")::</span></p><p style="color: rgb(51, 51, 51); font-family: Helvetica,Arial,sans-serif; font-size: 14px; background-color: rgb(249, 249, 249);"><span style="font-family: Consolas;">item("medium","Buy more soap")::Nil)</span></p><p style="color: rgb(51, 51, 51); font-family: Helvetica,Arial,sans-serif; font-size: 14px; background-color: rgb(249, 249, 249);"><span style="font-family: Consolas;"> </span></p><h3 style="color: rgb(51, 51, 51); font-family: Helvetica,Arial,sans-serif; background-color: rgb(249, 249, 249);"><a target=_blank name="t8"></a><a target=_blank name="_Toc282027563" class="ui-link             " style="color: rgb(36, 137, 206);" target="_blank" rel="nofollow"></a><a target=_blank name="_Toc281660030" class="ui-link             " style="color: rgb(36, 137, 206);" target="_blank" rel="nofollow"></a><span style="line-height: 24px; font-family: Consolas; font-size: 10.5pt;">4.1.7.<span style="line-height: normal; font-family: 'Times New Roman'; font-size: 7pt; font-weight: normal;">  </span></span><u><span style="line-height: 32px; font-family: Consolas; font-size: 14pt;">case object(</span><span style="line-height: 32px; font-family: 微软雅黑,sans-serif; font-size: 14pt;">条件单例对象</span><span style="line-height: 32px; font-family: Consolas; font-size: 14pt;">)</span></u></h3><p style="color: rgb(51, 51, 51); font-family: Helvetica,Arial,sans-serif; font-size: 14px; background-color: rgb(249, 249, 249);"><span style="font-family: 宋体;">比如定义一个标识类(而不是字符串):</span></p><p style="color: rgb(51, 51, 51); font-family: Helvetica,Arial,sans-serif; font-size: 14px; background-color: rgb(249, 249, 249);"><span style="font-family: Consolas;">case object Start</span></p><p style="color: rgb(51, 51, 51); font-family: Helvetica,Arial,sans-serif; font-size: 14px; background-color: rgb(249, 249, 249);"><span style="font-family: Consolas;">case object Stop</span></p><p style="color: rgb(51, 51, 51); font-family: Helvetica,Arial,sans-serif; font-size: 14px; background-color: rgb(249, 249, 249);"><span style="font-family: Consolas;"> </span></p><h3 style="color: rgb(51, 51, 51); font-family: Helvetica,Arial,sans-serif; background-color: rgb(249, 249, 249);"><a target=_blank name="t9"></a><a target=_blank name="_Toc282027564" class="ui-link             " style="color: rgb(36, 137, 206);" target="_blank" rel="nofollow"></a><a target=_blank name="_Toc281660031" class="ui-link             " style="color: rgb(36, 137, 206);" target="_blank" rel="nofollow"></a><span style="line-height: 24px; font-family: Consolas; font-size: 10.5pt;">4.1.8.<span style="line-height: normal; font-family: 'Times New Roman'; font-size: 7pt; font-weight: normal;">  </span></span><u><span style="line-height: 32px; font-family: 微软雅黑,sans-serif; font-size: 14pt;">枚举</span></u></h3><p style="color: rgb(51, 51, 51); font-family: Helvetica,Arial,sans-serif; font-size: 14px; background-color: rgb(249, 249, 249);"><span style="font-family: Consolas;">Java</span><span style="font-family: 宋体;">中:</span></p><pre style="color: rgb(51, 51, 51); background-color: rgb(249, 249, 249);" code_snippet_id="248416" snippet_file_name="blog_20140321_2_1518544"><span style="font-family: Consolas; font-size: 10.5pt;">   enum</span><span style="font-family: Consolas; font-size: 10.5pt;"> fruits { apple, banana, cherry }</span>

在Scala中,则是:

sealed abstract class Fruits // sealed类似于java的final

case object Apple extends Fruits

case object Banana extends Fruits

case object Cherry extends Fruits

也可以是 case class

4.1.9.  属性和Bean

例子1(直接定义和使用属性):

class c {

var name = "anonymous" // var定义的是r/w的属性

val age = 20  // val定义的是只r属性

}

val o = new c

o.name = "qh"

o.name // "qh"

o.age = 10 // 错误

o.age // 20

o.

例子2(定义get/set方法):

class
c2 {

@reflect.BeanProperty var name = "anonymous"

}

val o2 = new c2

o2.name = "qh" // 也可以直接存取

o2.name // "qh"

o2.setName("james") // 增加了set/get方法

o2.getName() // "james"

4.1.10.      反射

Scala没有太特别的反射机制,使用java的即可,不过Scala在match..case中可以匹配类型:

case o:FooClass1 => ...

相关还有isInstanceOf[T], asInstanceOf[T]

例1(利用java的reflect):

"hello".getClass.getMethods.map(_.getName).toList.sortWith(_<_).mkString(", ")

例子2:

classOf[String] // 相当于java中的String.class

"aaa".isInstanceOf[String] // true

"aaa".asInstanceOf[String]

疑问:为什么是中括号而不是小括号呢?泛型?

4.2.     trait超级接口

注:trait  [treit] n.特征,特点,特性

和Java的Interface类似,但可以定义实体方法,而非仅仅方法定义

trait可以看作有方法实现和字段的interface;代表一类事物的特性;

比如

Tom,可能是Engine 和Son两个trait的混合;

Sunny可能Sales、Son和Father三个trait的混合;

当在运行时往Son里面增加方法或者字段的时候,Tom和Sunny都得到增加的特性。

4.2.1.  trait使用

trait Runnable {

def run(): Unit;

}

只是用一个接口,就用extends:

class c1 extends Runnable {...}

2个接口(或一个继承一个接口),用with而不是implements如下:

class c1 extends c0 with Runnable {

def run(): Unit = {...}

}

一个类可以组合多个trait:

class c1 extends t1 with t2 with t3 {...}

4.2.2.  mixin

class Human

class Child

trait Dad {

private var children:List[Child]
= Nil

def add(child:Child) = child :: children

}

class Man1(name:String) extends Human with Dad // 静态mixin

class Man2(name:String) extends Human // 先不具备Dad
trait

val m1 = new Man1("qh")

m1.add(new Child)

val m2 = new Man2("小孩")

//    m2.add(new Child) // 报错

val m2$ = new Man2("james") with Dad // 动态mixin

m2$.add(new Child)

4.3.     协变和逆变(co-|contra-)variance

(找到应用,然后理解。仅仅是为了看懂定义中的符号?)

4.3.1.  概念

使用“+”“-”差异标记

Function[A, B]和Function[-A, +B]的区别图示:




Function[A,B]


Function[-A,+B]


trait Queue[T] {}


非变


trait Queue[+T] {}


协变

如果S extends A (S为子类型,A为父类型),

则Queue[S]为子类型,Queue[A]为父类型

S <: A => Queue[S] <: Queue[A]


trait Queue[-T] {}


逆变

如果S extends A (S为子类型,A为父类型)

则Queue[S]为父类型,Queue[A]为子类型,和协变互逆

S <: A => Queue[S] >: Queue[A]

-A是A的子集,叫逆变

+B是B的超集,叫协变

4.3.2.  类型上下界


<%


foo[T <% Ordered[T]](...)

关系较弱:T能够隐式转换为Ordered[T]


<:


foo[T <: Ordered[T]](...)

关系较强:T必须是Ordered[T]的子类型,即T的类型范围小于Ordered[T],Ordered[T]为上界


>:


foo[T >: A](...)

关系较强:T必须是A的父类型,即Tde类型范围大于A,A为下界

4.3.3.  协变、逆变结合上下界

例子1:


trait c1[+T] {

def m[K >: T](x:K) = x }


trait c1[-T] {

def m[K <: T](x:K) = x }


object c2 extends c1[Int]

c2.m(3) // 3

c2.m(3.0) // 3.0

c2.m("abc") // "abc"


object c2 extends c1[Int]

c2.m(3) // 3

c2.m(3.0) // 报错

c2.m("abc") // 报错

例子2:

// 非变

case class T1[T](e:T)

val v1:T1[java.lang.Integer] = new T1(100)

val v2:T1[java.lang.Integer] = v1

v2.e // 100

val v3:T1[java.lang.Number] = v1 // 报错

// 协变

case class T1[+T](e:T)

val v1:T1[java.lang.Integer] = new T1(100)

val v2:T1[java.lang.Integer] = v1

v2.e // 100

val v3:T1[java.lang.Number] = v1 // 合法

v3.e // 100

val v4:T1[java.lang.Integer] = v3 //非法

// 逆变

class T1[-T](e:T)

val v1:T1[java.lang.Number] = new T1(100)

val v2:T1[java.lang.Number] = v1

val v3:T1[java.lang.Integer] = v1 // 合法

val v4:T1[java.lang.Number] = v3 // 非法

时间: 2024-08-25 04:15:33

Scala中的类、接口及协变和逆变的相关文章

Scala 深入浅出实战经典 第81讲:Scala中List的构造是的类型约束逆变、协变、下界详解

王家林亲授<DT大数据梦工厂>大数据实战视频 Scala 深入浅出实战经典(1-97讲)完整视频.PPT.代码下载:百度云盘:http://pan.baidu.com/s/1c0noOt6 腾讯微云:http://url.cn/TnGbdC 360云盘:http://yunpan.cn/cQ4c2UALDjSKy 访问密码 45e2土豆:http://www.tudou.com/programs/view/ceac2IoB-ik/优酷:http://v.youku.com/v_show/id_

Scala中List的构造是的类型约束逆变、协变、下界详解

学习了Scala中List的构造是的类型约束逆变.协变.下界详解,列表中用::加入父类的对象,列表会协变为父类,例子如下: Def :: [B>:A](x:B):List(B)= New scala:collection.imutable.::(x,this) 王家林亲授<DT大数据梦工厂>大数据实战视频“Scala深入浅出实战经典”视频.音频和PPT下载!第81讲:Scala中List的构造是的类型约束逆变.协变.下界详解腾讯微云:http://url.cn/UNeLA2百度云盘:ht

第81讲:Scala中List的构造和类型约束逆变、协变、下界详解

今天来学习一下scala中List的构造和类型约束等内容. 让我们来看一下代码 package scala.learn /** * @author zhang */abstract class Big_Data class Hadoop extends Big_Dataclass Spark extends Big_Data object List_Constructor {  def main(args:Array[String]){    val hadoop = new Hadoop ::

接口的协变和逆变

class Animal { public string Name;}//基类 class Dog : Animal { }//派生类 interface IMyIf<out T>//协变关键字out,泛型接口+接口的协变 { T GetFirst();//约束方法 } class SimpleReturn<T> : IMyIf<T>//实现泛型接口的泛型类型 { public T[] items =new T[2];//初始化对象数组 public T GetFirs

C# - 协变与逆变

public interface IFication<T>{    void Method1 ( T t );    T Method2();} public class Parent : IFication<Parent>{    public string Car="阿斯顿马丁";  // 父亲具有车子 public void Method1 ( Parent p )    {        Console.WriteLine ( p.Car );    }

协变和逆变(转载)

前言 个人感觉协变(Covariance)与逆变(Contravariance)是 C# 4 中最难理解的一个特性了,因为 C# 4 用了一个非常直观的语法(in和out关键字),在很多情况下,这似乎很简单,in用于输入的参数,out用于输出的返回值,但事实上不完全如此,比如Method(Action<T> action)(会让人抓狂,一会再说).这也是困扰了我相当久的问题,所以今天打算分享一下我自己的理解. 协变和逆变 我们先引入一些记号,假设 T 和 U 是两个类型,那它们之间会有几种关系

Scala类型参数中协变(+)、逆变(-)、类型上界(&lt;:)和类型下界(&gt;:)的使用

转自:http://fineqtbull.iteye.com/blog/477994#bc2364938 有位je上的同学来短信向我问起了Scala类型参数中协变.逆变.类型上界和类型下界的使用方法和原理,自己虽然也刚学不久,在主要调查了<Programing in Scala>的19章后,试着在下面做一个总结.如有错误之处还请各位指正. 先说说协变和逆变(实际上还有非变).协变和逆变主要是用来解决参数化类型的泛化问题.由于参数化类型的参数(参数类型)是可变的,当两个参数化类型的参数是继承关系

Scala中的协变,逆变,上界,下界等

Scala中的协变,逆变,上界,下界等 目录 [−] Java中的协变和逆变 Scala的协变 Scala的逆变 下界lower bounds 上界upper bounds 综合协变,逆变,上界,下界 View Bound <% Context Bound 参考文档 Scala中的协变逆变和Java中的协变逆变不一样,看起来更复杂. 本文对Scala中的这些概念做一总结.首先看几个概念: covariant 协变.使你能够使用比原始指定的类型的子类 Contravariance 逆变.使你能够使

scala学习笔记-类型参数中协变(+)、逆变(-)、类型上界(&lt;:)和类型下界(&gt;:)的使用

转载自  fineqtbull   http://fineqtbull.iteye.com/blog/477994 有位je上的同学来短信向我问起了Scala类型参数中协变.逆变.类型上界和类型下界的使用方法和原理,自己虽然也刚学不久,在主要调查了<Programing in Scala>的19章后,试着在下面做一个总结.如有错误之处还请各位指正. 先说说协变和逆变(实际上还有非变).协变和逆变主要是用来解决参数化类型的泛化问题.由于参数化类型的参数(参数类型)是可变的,当两个参数化类型的参数