【scala 笔记(7)】 Scala 扩展类、匿名子类、抽象类、样例类、密封类

来源:互联网 发布:2钻淘宝店铺转让 编辑:程序博客网 时间:2024/05/01 12:28

扩展类

scala 扩展类的方式和Java一样, 使用 extends 关键字,例如:

class Person(val Name:String){  def show() = {println("person name: " + Name)}}class Student(name:String) extends Person(name){  private var id = 0  // 重写字段  override val Name: String = "[%s]".format(name)  // 辅助构造器  def this(name:String, id:Int){    this(name)    this.id = id  }  def learn() = {    println("learn ... ")  }  // 重载方法  def learn(language:String) = {    println("learn language " + language)  }  // 重写方法  override def show() = {    println("student id: %d, name: %s".format(this.id, this.Name))  }}

声明Student 对象

scala> val s1 = new Student("borey")s1: Student = Student@3878be7bscala> s1.showstudent id: 0, name: [borey]scala> val s2 = new Student("borey"10076)s2: Student = Student@10667848scala> s2.learnlearn ... scala> s2 learn "scala"learn language scalascala> s2.showstudent id: 10076, name: [borey]

上述样例包含知识点:

  • 使用extends进行类扩展, 也可以像Java一样把类声明为 final, 这样它就能被扩展;
  • 子类辅助构造器不能直接调用父类构造器; java中可以通用supper(param), scala 不行。
  • 类方法的重载和Java一样;
  • 类方法的重写,必须添加 override; Scala 中 重写一个 非抽象方法 必须使用override修饰符。
  • 类字段的重写,scala的类字段由一个私有字段和取值器/改值器方法构成(scala 类 setter和getter属性)。 你可以用另一个同名的val字段重写一个val(或一个不带参数的def),子类有一个私有字段和一个公有的getter方法, 而这个getter方法重写了超类的getter方法

可以看下 javap 反编译后 上述代码Java的定义:

prod@AWS-TEST-DT:~/borey_zhu/scala$ javap -p Person.class Compiled from "Person.scala"public class Person {  private final java.lang.String Name;  public java.lang.String Name();  public void show();  public Person(java.lang.String);}prod@AWS-TEST-DT:~/borey_zhu/scala$ javap -p Student.class Compiled from "Person.scala"public class Student extends Person {  private int id;  private final java.lang.String Name;  private int id();  private void id_$eq(int);  public java.lang.String Name();  public void learn();  public void learn(java.lang.String);  public void show();  public Student(java.lang.String);  public Student(java.lang.String, int);}

匿名子类

和Java一样, 你可以通过包含带有定义或重写的代码块的方式创建一个匿名的子类, 比如:

scala> val w = new Person("Tom"){     |   def speak(msg:String) {println(Name + " speak:" + msg)}     | }w: Person{def speak(msg: String): Unit} = $anon$1@1e54cb33

从技术上讲, 这将会创建出一个 结构类型 的对象。 该类型标记为 Person{def speak(msg: String): Unit}, 你可以用这个类型作为参数类型的定义函数 :

scala> import scala.language.reflectiveCallsimport scala.language.reflectiveCallsscala> def func(p: Person{def speak(msg: String): Unit}) {     |   p.speak("hello world")     | }func: (p: Person{def speak(msg: String): Unit})Unitscala> func(w)Tom speak:hello world

结构类型 : 指的是一组关于抽象方法、字段和类型的规格说明, 这些抽象方法、字段和类型是满足该规则的类型必须具备的。

上述样例表示: 可以对任意只要拥有{def speak(msg: String): Unit}方法的Person子类进行func调用传参。 验证:

scala> class B(name:String) extends Person(name){     |   def speak(msg:String) {println(msg)}     | }defined class Bscala> val b = new B("bo")b: B = B@6ae3fb94scala> func(b) // ok 成功hello world

抽象类

和Java 一样, 你可以用 abstract 关键字来标记不能被实例化的类, 通常这是因为它的某个方法没有被完整定义。 例如:

abstract class Animal(val Name:String){  val id: Int     // 带有 getter 的抽象字段  var size:Float  // 带有 getter 和 setter 的抽象字段  def eat() // 没有方法体 -- 这是一个抽象方法}class Dog(name:String) extends Animal(name){  val id = 1 // 具体的子类必须提供具体的字段, 否则 不带有  var size = 98.6f  def eat(){  // 子类重写超类抽象方法时, 你不需要使用 override关键字。    println(Name + " eat guo tou ...")  }}

可以看下 javap 反编译后 上述代码Java的定义:

prod@AWS-TEST-DT:~/borey_zhu/scala$ javap -p Animal.class Compiled from "Animal.scala"public abstract class Animal {  private final java.lang.String Name;  public java.lang.String Name();  public abstract void eat();  public abstract int id();  public abstract float size();  public abstract void size_$eq(float);  public Animal(java.lang.String);}prod@AWS-TEST-DT:~/borey_zhu/scala$ javap -p Dog.class Compiled from "Animal.scala"public class Dog extends Animal {  private final int id;  private float size;  public int id();  public float size();  public void size_$eq(float);  public void eat();  public Dog(java.lang.String);}

样例类

样例类是一种特殊的类, 他们经过优化以被用于模式匹配。
例如:

scala> abstract class Animaldefined class Animalscala> case class Dog(Name:String) extends Animaldefined class Dog

也可以是样例对象

scala> case object Cat extends Animaldefined object Cat

样例类帮我们实现了 apply 和 unapply 方法:

scala> val d = Dog("xiao7")d: Dog = Dog(xiao7)scala> d match {     |   case Dog(name) => println("dog name : " + name)     |   case _ => ""     | }dog name : xiao7res1: Any = ()

可以看下 javap 反编译看下Scala对样例类的定义:

// prod@AWS-TEST-DT:~/borey_zhu/scala$ javap -p Animal.class // Compiled from "Animal.scala"public abstract class Animal {  public Animal();}// prod@AWS-TEST-DT:~/borey_zhu/scala$ javap -p Dog.class // Compiled from "Animal.scala"public class Dog extends Animal implements scala.Product,scala.Serializable {  private final java.lang.String Name;  public static scala.Option<java.lang.String> unapply(Dog);  public static Dog apply(java.lang.String);  public static <A> scala.Function1<java.lang.String, A> andThen(scala.Function1<Dog, A>);  public static <A> scala.Function1<A, Dog> compose(scala.Function1<A, java.lang.String>);  public java.lang.String Name();  public Dog copy(java.lang.String);  public java.lang.String copy$default$1();  public java.lang.String productPrefix();  public int productArity();  public java.lang.Object productElement(int);  public scala.collection.Iterator<java.lang.Object> productIterator();  public boolean canEqual(java.lang.Object);  public int hashCode();  public java.lang.String toString();  public boolean equals(java.lang.Object);  public Dog(java.lang.String);}// prod@AWS-TEST-DT:~/borey_zhu/scala$ javap -p Dog$.class // Compiled from "Animal.scala"public final class Dog$ extends scala.runtime.AbstractFunction1<java.lang.String, Dog> implements scala.Serializable {  public static Dog$ MODULE$;  public static {};  public final java.lang.String toString();  public Dog apply(java.lang.String);  public scala.Option<java.lang.String> unapply(Dog);  private java.lang.Object readResolve();  public java.lang.Object apply(java.lang.Object);  private Dog$();}// prod@AWS-TEST-DT:~/borey_zhu/scala$ javap -p Cat.class // Compiled from "Animal.scala"public final class Cat {  public static java.lang.String toString();  public static int hashCode();  public static boolean canEqual(java.lang.Object);  public static scala.collection.Iterator<java.lang.Object> productIterator();  public static java.lang.Object productElement(int);  public static int productArity();  public static java.lang.String productPrefix();}// prod@AWS-TEST-DT:~/borey_zhu/scala$ javap -p Cat$.class // Compiled from "Animal.scala"public final class Cat$ extends Animal implements scala.Product,scala.Serializable {  public static Cat$ MODULE$;  public static {};  public java.lang.String productPrefix();  public int productArity();  public java.lang.Object productElement(int);  public scala.collection.Iterator<java.lang.Object> productIterator();  public boolean canEqual(java.lang.Object);  public int hashCode();  public java.lang.String toString();  private java.lang.Object readResolve();  private Cat$();}// prod@AWS-TEST-DT:~/borey_zhu/scala$ 

当我们申明样例类或对象时, Scala 会帮我们自动实现:

  • 构造器中的每个参数都成为 val (除非它被显式的声明为var ,不建议);
  • 在伴生对象中提供的apply方法;
  • 提供unapply 方法让模式匹配可以工作;
  • 将生成 toString、equals、hashCode 和 copy方法 (除非显式的给出这些方法的定义。 除上述之外, 样例类和其他类完全一样。 可以添加字段和方法,扩展他们等。)

密封类

当你用样例类来做模式匹配时, 你可能想让编译器帮助我们呢确保你已经列出所有可能的选择。 要达到这个目的, 你需要将样例类的通用超类声明为 sealed :

sealed abstract class Colorcase object Red extends Colorcase object Green extends Colorcase object Yellow extends Color

密封类的所有子类都必须在与该密封类相同的文件中定义。那么编译器可以检查模式语句的完整性。让所有同一组样例类都扩展某个密封的类或特质是个好的做法。

原创粉丝点击