主頁 > 後端開發 > Scala面向物件

Scala面向物件

2023-06-18 07:42:11 後端開發

類和物件

組成結構
? 建構式: 在創建物件的時候給屬性賦值
? 成員變數:
? 成員方法(函式)
? 區域變數
? 代碼塊

構造器

每個類都有一個主構造器,這個構造器和類定義"交織"在一起類名后面的內容就是主構造器,如果引數串列為空的話,()可以省略
scala的類有且僅有一個主構造器,要想提供更加豐富的構造器,就需要使用輔助構造器,輔助構造器是可選的,它們叫做this def this
注意:主構造器會執行類定義中的所有陳述句
代碼示例:

// 類默認有一個無參的主建構式
class User { 
}

val user: User = new User

// 兩個引數的主建構式
class User2(val name: String, age: Int) { 

}
val user2 = new User2("jim", 23)
// 使用val修飾的變數默認是成員變數,物件可以訪問
// user2.age   // age沒有使用val或者var修飾 所以不能被訪問,他不是一個成員變數,而是一個區域變數


//輔助構造器
class User3 {
   var name: String = _
   var age: Int = _
  // 輔助建構式
  def this(name: String, age: Int) {
    // 建構式中的首行必須呼叫主建構式或者其他建構式
    this()
    this.name = name
    this.age = age
  }
  // 輔助建構式
  def this(msg: String) = {
    // 首行呼叫一個構造
    this("ww", 12)
    println(msg)
  }
}
val u1 = new User3()
val u2 = new User3("")
val u3 = new User3("lisi", 23)
println(u3.name)

總結:

  1. 有兩類構造器:主構造器,輔助構造器
  2. 構造器的定義位置:主構造器和類交織在一起,class Student2(val name: String, var age: Int)
  3. 輔助構造器是一個特殊的方法,定義在類中 def this(name:String,age:Int,gender:String)
  4. 輔助構造器,第一行必須呼叫主構造器(或者其他的輔助構造器)
  5. 輔助構造器的引數不能和主構造器的引數完全一致(引數個數,引數型別,引數順序)
  6. 可以定義空參的輔助構造器,但是主構造器的引數必須進行初始化賦值
  7. 作用域:輔助構造器的變數作用域,只在方法中,主構造器的作用域是類中除了成員屬性和成員方法之外的所有范圍(可以通過反編譯查看原始碼)

構造器的引數說明

  • 主建構式中使用val 和 var修飾的變數為成員變數
  • val 修飾的變數默認只有getter方法 一要初始化
  • var 修飾的變數默認有 get和set方法 直接點屬性操作 使用 _ 占位可以稍后賦值
  • @BeanProperty會生成getMsg setMsg方法

成員方法/函式

在類的成員位置定義的函式或者方法是類的成員的一部分

代碼塊

在類或者物件中的代碼塊在實體化的時候會被呼叫

  • 在類成員位置的代碼塊 構造代碼塊 每次創建物件都會執行一次
  • 在object中成員位置的代碼塊是靜態代碼塊 只執行一次
  • 代碼有回傳值

object類的底層原理

package com.doit.day01.day02

//如果構造器中的變數,不加var 或者val 那他就是一個區域變數
//加了var 或者val 的話他就是一個私有的成員變數
class Student1(var id: Int, val name: String) {

  def sayHello: Unit = {
    println(name + ":你好")
  }

  val sayFunc = () => {
    println("hello:" + name)
  }
}


object Student2{
  var id: Int = 1
  //如果在成員變數的位置上給一個_作為占位符,相當于是給他賦了一個默認值啊
  var name: String =_

  def sayHello: Unit = {
    println(name + ":你好")
  }
  val sayFunc = (x:String) => {
    println("hello:" + name + x)
  }
}


object Demo01_面向物件 {
  def main(args: Array[String]): Unit = {

    Student2.sayFunc("a")

    val student1: Student1 = new Student1(1, "zhangsan")
    println(student1.name)
    println(student1.id)
    //    student1.name = "lisi"  用val 修飾的,不能修改
    student1.id = 2
    println(student1.id)

    student1.sayHello
    student1.sayFunc()
    println(Student2.name)
  }
}

java手寫實作:

package com.doit;


public class Person {
    public static String getName(){
        return Person$.person.getName();
    }

    public static Integer getAge(){
        return Person$.person.getAge();
    }

    public static void setName(String name ){
        Person$.person.setName(name);
    }

    public static void setAge(Integer age ){
        Person$.person.setAge(age);
    }
}

class Person$ {
    //自己的物件
    public static Person$ person ;
    //成員變數
    private String name;
    private int age;

    static {
        person  = new Person$();
    }

    private Person$() {
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}


class Test{
    public static void main(String[] args) {
        Person person = new Person();
        person.setName("張三");
        person.setAge(18);
        String name1 = person.getName();
        Integer age1 = person.getAge();
        System.out.println(name1);
        System.out.println(age1);
    }
}

scala中底層反編譯后的代碼:

package com.doit.day01.day02;

import java.lang.invoke.SerializedLambda;
import scala.Function1;
import scala.Predef.;
import scala.runtime.BoxedUnit;

public final class Student2$ {
   public static Student2$ MODULE$;
   private int id;
   private String name;
   private final Function1 sayFunc;

   static {
      new Student2$();
   }

   public int id() {
      return this.id;
   }

   public void id_$eq(final int x$1) {
      this.id = x$1;
   }

   public String name() {
      return this.name;
   }

   public void name_$eq(final String x$1) {
      this.name = x$1;
   }

   public void sayHello() {
      .MODULE$.println((new StringBuilder(3)).append(this.name()).append(":你好").toString());
   }

   public Function1 sayFunc() {
      return this.sayFunc;
   }

// $FF: synthetic method
   public static final void $anonfun$sayFunc$1(final String x) {
      .MODULE$.println((new StringBuilder(6)).append("hello:").append(MODULE$.name()).append(x).toString());
   }

   private Student2$() {
      MODULE$ = this;
      this.id = 1;
      this.sayFunc = (x) -> {
         $anonfun$sayFunc$1(x);
         return BoxedUnit.UNIT;
      };
   }

// $FF: synthetic method
   private static Object $deserializeLambda$(SerializedLambda var0) {
      return var0.lambdaDeserialize<invokedynamic>(var0);
   }
}

 //decompiled from Student2.class
package com.doit.day01.day02;

import scala.Function1;
import scala.reflect.ScalaSignature;

@ScalaSignature(
   bytes = "\u0006\u0001!;Q\u0001D\u0007\t\u0002Y1Q\u0001G\u0007\t\u0002eAQ\u0001I\u0001\u0005\u0002\u0005BqAI\u0001A\u0002\u0013\u00051\u0005C\u0004(\u0003\u0001\u0007I\u0011\u0001\u0015\t\r9\n\u0001\u0015)\u0003%\u0011%y\u0013\u00011AA\u0002\u0013\u0005\u0001\u0007C\u0005=\u0003\u0001\u0007\t\u0019!C\u0001{!Iq(\u0001a\u0001\u0002\u0003\u0006K!\r\u0005\u0006\u0001\u0006!\t!\u0011\u0005\b\u0005\u0006\u0011\r\u0011\"\u0001D\u0011\u00199\u0015\u0001)A\u0005\t\u0006A1\u000b^;eK:$(G\u0003\u0002\u000f\u001f\u0005)A-Y=1e)\u0011\u0001#E\u0001\u0006I\u0006L\b'\r\u0006\u0003%M\tA\u0001Z8ji*\tA#A\u0002d_6\u001c\u0001\u0001\u0005\u0002\u0018\u00035\tQB\u0001\u0005TiV$WM\u001c;3'\t\t!\u0004\u0005\u0002\u001c=5\tADC\u0001\u001e\u0003\u0015\u00198-\u00197b\u0013\tyBD\u0001\u0004B]f\u0014VMZ\u0001\u0007y%t\u0017\u000e\u001e \u0015\u0003Y\t!!\u001b3\u0016\u0003\u0011\u0002\"aG\u0013\n\u0005\u0019b\"aA%oi\u00061\u0011\u000eZ0%KF$\"!\u000b\u0017\u0011\u0005mQ\u0013BA\u0016\u001d\u0005\u0011)f.\u001b;\t\u000f5\"\u0011\u0011!a\u0001I\u0005\u0019\u0001\u0010J\u0019\u0002\u0007%$\u0007%\u0001\u0003oC6,W#A\u0019\u0011\u0005IJdBA\u001a8!\t!D$D\u00016\u0015\t1T#\u0001\u0004=e>|GOP\u0005\u0003qq\ta\u0001\u0015:fI\u00164\u0017B\u0001\u001e<\u0005\u0019\u0019FO]5oO*\u0011\u0001\bH\u0001\t]\u0006lWm\u0018\u0013fcR\u0011\u0011F\u0010\u0005\b[\u001d\t\t\u00111\u00012\u0003\u0015q\u0017-\\3!\u0003!\u0019\u0018-\u001f%fY2|W#A\u0015\u0002\u000fM\f\u0017PR;oGV\tA\t\u0005\u0003\u001c\u000bFJ\u0013B\u0001$\u001d\u0005%1UO\\2uS>t\u0017'\u0001\u0005tCf4UO\\2!\u0001"
)
public final class Student2 {
   public static Function1 sayFunc() {
      return Student2$.MODULE$.sayFunc();
   }

   public static void sayHello() {
      Student2$.MODULE$.sayHello();
   }

   public static void name_$eq(final String x$1) {
      Student2$.MODULE$.name_$eq(var0);
   }

   public static String name() {
      return Student2$.MODULE$.name();
   }

   public static void id_$eq(final int x$1) {
      Student2$.MODULE$.id_$eq(var0);
   }

   public static int id() {
      return Student2$.MODULE$.id();
   }
}

伴生類和伴生物件

條件 1:在同一個源檔案中, 條件 2:物件名和類名相同

  //類名和object的名稱一致
  //類是物件的伴生類
  //物件是類的伴生物件

class Demo6(val name: String) {
}
object Demo6 {
}

條件 2:伴生物件和伴生類之間可以互相訪問彼此的私有屬性和私有方法

package com.doit.day01.day02

/**
 * 伴生物件的用途:
 *      1.可以將靜態的成員變數和普通成員變數分別宣告
 *      2.伴生物件自己內部定義了一個apply方法,可以簡化創建物件(類的實體構造)
 *      3.伴生物件自己定義了一個unapply方法,可以用于模式匹配
 */
class Car(var brand: String, var price: Double) {

  def sayHello(): Unit ={
    println("hello")
  }

  private val color: String = Car.color
  Car.start()
}


object Car {
  var color :String = "red"

  def start(): Unit ={
    println("汽車啟動了,嗡~~~~~~~~")
  }
}

object Demo02_伴生物件 {
  def main(args: Array[String]): Unit = {
    val car: Car = new Car("華為", 9.9)
    println(car.brand)
    println(car.price)
    car.sayHello()
    Car.start()
  }
}

伴生物件的底層原理:

//decompiled from Car.class
package com.doit.day01.day02;

import scala.Predef.;
import scala.reflect.ScalaSignature;

@ScalaSignature(
   bytes = "\u0006\u0001E3A\u0001E\t\u00015!A\u0011\u0005\u0001BA\u0002\u0013\u0005!\u0005\u0003\u0005/\u0001\t\u0005\r\u0011\"\u00010\u0011!)\u0004A!A!B\u0013\u0019\u0003\u0002\u0003\u001c\u0001\u0005\u0003\u0007I\u0011A\u001c\t\u0011m\u0002!\u00111A\u0005\u0002qB\u0001B\u0010\u0001\u0003\u0002\u0003\u0006K\u0001\u000f\u0005\u0006\u007f\u0001!\t\u0001\u0011\u0005\u0006\u000b\u0002!\tAR\u0004\u0006\u000fFA\t\u0001\u0013\u0004\u0006!EA\t!\u0013\u0005\u0006\u007f)!\tA\u0013\u0005\b\u0017*\u0001\r\u0011\"\u0001#\u0011\u001da%\u00021A\u0005\u00025Caa\u0014\u0006!B\u0013\u0019\u0003\"\u0002)\u000b\t\u00031%aA\"be*\u0011!cE\u0001\u0006I\u0006L\bG\r\u0006\u0003)U\tQ\u0001Z1zaER!AF\f\u0002\t\u0011|\u0017\u000e\u001e\u0006\u00021\u0005\u00191m\\7\u0004\u0001M\u0011\u0001a\u0007\t\u00039}i\u0011!\b\u0006\u0002=\u0005)1oY1mC&\u0011\u0001%\b\u0002\u0007\u0003:L(+\u001a4\u0002\u000b\t\u0014\u0018M\u001c3\u0016\u0003\r\u0002\"\u0001J\u0016\u000f\u0005\u0015J\u0003C\u0001\u0014\u001e\u001b\u00059#B\u0001\u0015\u001a\u0003\u0019a$o\\8u}%\u0011!&H\u0001\u0007!J,G-\u001a4\n\u00051j#AB*ue&twM\u0003\u0002+;\u0005I!M]1oI~#S-\u001d\u000b\u0003aM\u0002\"\u0001H\u0019\n\u0005Ij\"\u0001B+oSRDq\u0001\u000e\u0002\u0002\u0002\u0003\u00071%A\u0002yIE\naA\u0019:b]\u0012\u0004\u0013!\u00029sS\u000e,W#\u0001\u001d\u0011\u0005qI\u0014B\u0001\u001e\u001e\u0005\u0019!u.\u001e2mK\u0006I\u0001O]5dK~#S-\u001d\u000b\u0003auBq\u0001N\u0003\u0002\u0002\u0003\u0007\u0001(\u0001\u0004qe&\u001cW\rI\u0001\u0007y%t\u0017\u000e\u001e \u0015\u0007\u0005\u001bE\t\u0005\u0002C\u00015\t\u0011\u0003C\u0003\"\u000f\u0001\u00071\u0005C\u00037\u000f\u0001\u0007\u0001(\u0001\u0005tCfDU\r\u001c7p)\u0005\u0001\u0014aA\"beB\u0011!IC\n\u0003\u0015m!\u0012\u0001S\u0001\u0006G>dwN]\u0001\nG>dwN]0%KF$\"\u0001\r(\t\u000fQj\u0011\u0011!a\u0001G\u000511m\u001c7pe\u0002\nQa\u001d;beR\u0004"
)
public class Car {
   private String brand;
   private double price;

   public static void start() {
      Car$.MODULE$.start();
   }

   public static void color_$eq(final String x$1) {
      Car$.MODULE$.color_$eq(var0);
   }

   public static String color() {
      return Car$.MODULE$.color();
   }

   public String brand() {
      return this.brand;
   }

   public void brand_$eq(final String x$1) {
      this.brand = x$1;
   }

   public double price() {
      return this.price;
   }

   public void price_$eq(final double x$1) {
      this.price = x$1;
   }

   public void sayHello() {
      .MODULE$.println("hello");
   }

   public Car(final String brand, final double price) {
      this.brand = brand;
      this.price = price;
      super();
   }
}

        //decompiled from Car$.class
package com.doit.day01.day02;

import scala.Predef.;

public final class Car$ {
   public static Car$ MODULE$;
   private String color;

   static {
      new Car$();
   }

   public String color() {
      return this.color;
   }

   public void color_$eq(final String x$1) {
      this.color = x$1;
   }

   public void start() {
      .MODULE$.println("汽車啟動了,嗡~~~~~~~~");
   }

   private Car$() {
      MODULE$ = this;
      this.color = "red";
   }
}

圖示:

image
伴生物件用途:

  1. 可以將靜態的成員變數和普通成員變數分別宣告(class中沒辦法添加靜態成員,需要經過object類來添加)
  2. 伴生物件自己內部定義了一個apply方法,可以簡化創建物件(類的實體構造)
  3. 伴生物件自己定義了一個unapply方法,可以用于模式匹配

apply方法

使用此方法時,可以在main函式中不通過new來創建一個物件,即可以不用專門的一次一次地進行實體化,加載創建物件的這個類的時候,會自動呼叫apply這個方法,類似Java中的static靜態塊,

  1. 通過伴生物件的 apply 方法,實作不使用 new 方法創建物件,
  2. apply 方法可以多載,
  3. Scala 中 obj(arg)的陳述句實際是在呼叫該物件的 apply 方法,即 obj.apply(arg),用以統一面向物件編程和函式式編程的風格,
  4. 當使用 new 關鍵字構建物件時,呼叫的其實是類的構造方法,當直接使用類名構建物件時,呼叫的其實是伴生物件的 apply 方法,
object Test {
 def main(args: Array[String]): Unit = {
 //(1)通過伴生物件的 apply 方法,實作不使用 new 關鍵字創建物件,
 val p1 = Person()
 println("p1.name=" + p1.name)
 val p2 = Person("bobo")
 println("p2.name=" + p2.name)
 } 
}
//(2)如果想讓主構造器變成私有的,可以在()之前加上 private
class Person private(cName: String) {
 var name: String = cName
}

object Person {
 def apply(): Person = {
 println("apply 空參被呼叫")
 new Person("xx")
 }
 
 def apply(name: String): Person = {
 println("apply 有參被呼叫")
 new Person(name)
}
}

權限修飾符

在 Java 中,訪問權限分為:public,private,protected 和默認,在 Scala 中,你可以通過類似的修飾符達到同樣的效果,但是使用上有區別,
(1)Scala 中屬性和方法的默認訪問權限為 public,但 Scala 中無 public 關鍵字,
(2)private 為私有權限,只在類的內部和伴生物件中可用,
(3)protected 為受保護權限,Scala 中受保護權限比 Java 中更嚴格,同類、子類可以訪問,同包無法訪問,
(4)private[包名]增加包訪問權限,包名下的其他類也可以使用
代碼演示:

class Person {
 private var name: String = "bobo"
 protected var age: Int = 18
 private[test] var sex: String = "男"
 def say(): Unit = {
 println(name)
 } 
}
object Person {
 def main(args: Array[String]): Unit = {
 val person = new Person
 person.say()
 println(person.name)
 println(person.age)
 } 
}
class Teacher extends Person {
 def test(): Unit = {
 this.age
 this.sex
 } 
}
class Animal {
 def test: Unit = {
 new Person().sex
 }
}

特質和抽象類

特質

Trait(特質)相當于 java 的介面,比介面功能更強大,特質中可以定義屬性和抽象方法和方法的實作,
Scala 的類只能夠繼承單一父類,但是可以實作(繼承,混入)多個特質(Trait),使用的關鍵字是 with 和 extends
注意,特質不能有主建構式
基本語法

trait 特質名 {
trait 主體
} 

如何使用特質:
沒有父類:class 類名 extends 特質 1 with 特質 2 with 特質 3 …
有父類:class 類名 extends 父類 with 特質 1 with 特質 2 with 特質 3…
代碼演示:

trait PersonTrait {
 // 宣告屬性
 var name:String = _
 // 宣告方法
 def eat():Unit={
 }
 // 抽象屬性
 var age:Int
 
 // 抽象方法
 def say():Unit
}

特質的本質就是抽象類+介面

特質的動態混入

1.創建物件時混入 trait,而無需使類混入該 trait
2.如果混入的 trait 中有未實作的方法,則需要實作
代碼演示:

trait PersonTrait {
 //(1)特質可以同時擁有抽象方法和具體方法
 // 宣告屬性
 var name: String = _
 // 抽象屬性
 var age: Int
 // 宣告方法
 def eat(): Unit = {
 println("eat")
 }
 // 抽象方法
 def say(): Unit
}
trait SexTrait {
 var sex: String
}
//(2)一個類可以實作/繼承多個特質
//(3)所有的 Java 介面都可以當做 Scala 特質使用
class Teacher extends PersonTrait with java.io.Serializable {
 override def say(): Unit = {
 println("say")
 }
 override var age: Int = _
}
object TestTrait {
 def main(args: Array[String]): Unit = {
 val teacher = new Teacher
 teacher.say()
 teacher.eat()
 //(4)動態混入:可靈活的擴展類的功能
 val t2 = new Teacher with SexTrait {
 override var sex: String = "男"
 }
 //呼叫混入 trait 的屬性
 println(t2.sex)
 } 
}

抽象類

在 Scala 中, 使用 abstract 修飾的類稱為抽象類. 在抽象類中可以定義屬性、未實作的方法(抽象方法)和具體實作的方法, 含有抽象方法的類就是抽象類

  • 抽象類中的屬性
  • 抽象方法
  • 具體實作的方法
  • 類的單繼承

示例:

/*
* abstract 修飾的類是一個抽象類
* */
abstract class Animal {
  println("Animal's constructor ....")
  // 定義一個 name 屬性
  val name: String = "animal"
  // 沒有任何實作的方法
  def sleep()
  // 帶有具體的實作的方法
  def eat(f: String): Unit = {
    println(s"$f")
    }
  }

抽象類的繼承和重寫

  • 如果父類為抽象類,那么子類要么也是抽象類,要么就需要重寫父類中的所有的抽象方法和抽象的成員變數
  • 重寫非抽象方法需要用 override 修飾,重寫抽象方法則可以不加 override,
  • 子類中呼叫父類的方法使用 super 關鍵字,在子類重寫了父類的方法后,如果不加super,直接寫方法名呼叫的就是子類重寫后的,如果加了,呼叫的還是父類的
  • 子類對抽象屬性進行實作,父類抽象屬性可以用 var 修飾;子類對非抽象屬性重寫,父類非抽象屬性只支持 val 型別,而不支持 var(var修飾具體方法和變數不好重寫)

因為 var 修飾的為可變變數,子類繼承之后就可以直接使用,沒有必要重寫

樣例類

使用case修飾的類就是樣例類(封裝資料,模式匹配)

  1. 構造器中的引數默認是val修飾的[成員,賦值1次]
  2. 樣例類會自動創建伴生物件, 同時在里面實作;的apply和unapply方法 ,創建物件的時候不用new
  3. 很好的支持匹配模式
  4. 默認實作了自己的toString , hashCode , copy , equals,序列化方法

定義一個樣例類:

case class Person(var name:String , var age:Int){}
//如果類中沒有別的需要定義的,可以不寫大括號

反編譯之后的結果:

//decompiled from Person$.class
package com.doit.day01.day02;

import scala.Option;
import scala.Serializable;
import scala.Some;
import scala.Tuple2;
import scala.None.;
import scala.runtime.AbstractFunction2;
import scala.runtime.BoxesRunTime;

public final class Person$ extends AbstractFunction2 implements Serializable {
   public static Person$ MODULE$;

   static {
      new Person$();
   }

   public final String toString() {
      return "Person";
   }

   public Person apply(final String name, final int age) {
      return new Person(name, age);
   }

   public Option unapply(final Person x$0) {
      return (Option)(x$0 == null ? .MODULE$ : new Some(new Tuple2(x$0.name(), BoxesRunTime.boxToInteger(x$0.age()))));
   }

   private Object readResolve() {
      return MODULE$;
   }

   // $FF: synthetic method
   // $FF: bridge method
   public Object apply(final Object v1, final Object v2) {
      return this.apply((String)v1, BoxesRunTime.unboxToInt(v2));
   }

   private Person$() {
      MODULE$ = this;
   }
}

        //decompiled from Person.class
package com.doit.day01.day02;

import scala.Function1;
import scala.Option;
import scala.Product;
import scala.Serializable;
import scala.collection.Iterator;
import scala.reflect.ScalaSignature;
import scala.runtime.BoxesRunTime;
import scala.runtime.Statics;
import scala.runtime.ScalaRunTime.;

@ScalaSignature(
   bytes = "\u0006\u0001\u0005Uc\u0001\u0002\u000e\u001c\u0001\u0012B\u0001\"\r\u0001\u0003\u0012\u0004%\tA\r\u0005\t}\u0001\u0011\t\u0019!C\u0001\u007f!AQ\t\u0001B\tB\u0003&1\u0007\u0003\u0005G\u0001\tE\r\u0011\"\u0001H\u0011!Y\u0005A!a\u0001\n\u0003a\u0005\u0002\u0003(\u0001\u0005#\u0005\u000b\u0015\u0002%\t\u000b=\u0003A\u0011\u0001)\t\u000fU\u0003\u0011\u0011!C\u0001-\"9\u0011\fAI\u0001\n\u0003Q\u0006bB3\u0001#\u0003%\tA\u001a\u0005\bQ\u0002\t\t\u0011\"\u0011j\u0011\u001d\t\b!!A\u0005\u0002\u001dCqA\u001d\u0001\u0002\u0002\u0013\u00051\u000fC\u0004y\u0001\u0005\u0005I\u0011I=\t\u0013\u0005\u0005\u0001!!A\u0005\u0002\u0005\r\u0001\"CA\u0007\u0001\u0005\u0005I\u0011IA\b\u0011%\t\t\u0002AA\u0001\n\u0003\n\u0019\u0002C\u0005\u0002\u0016\u0001\t\t\u0011\"\u0011\u0002\u0018\u001dI\u00111D\u000e\u0002\u0002#\u0005\u0011Q\u0004\u0004\t5m\t\t\u0011#\u0001\u0002 !1q\n\u0006C\u0001\u0003[A\u0011\"!\u0005\u0015\u0003\u0003%)%a\u0005\t\u0013\u0005=B#!A\u0005\u0002\u0006E\u0002\"CA\u001c)\u0005\u0005I\u0011QA\u001d\u0011%\tY\u0005FA\u0001\n\u0013\tiE\u0001\u0004QKJ\u001cxN\u001c\u0006\u00039u\tQ\u0001Z1zaIR!AH\u0010\u0002\u000b\u0011\f\u0017\u0010M\u0019\u000b\u0005\u0001\n\u0013\u0001\u00023pSRT\u0011AI\u0001\u0004G>l7\u0001A\n\u0005\u0001\u0015Zc\u0006\u0005\u0002'S5\tqEC\u0001)\u0003\u0015\u00198-\u00197b\u0013\tQsE\u0001\u0004B]f\u0014VM\u001a\t\u0003M1J!!L\u0014\u0003\u000fA\u0013x\u000eZ;diB\u0011aeL\u0005\u0003a\u001d\u0012AbU3sS\u0006d\u0017N_1cY\u0016\fAA\\1nKV\t1\u0007\u0005\u00025w9\u0011Q'\u000f\t\u0003m\u001dj\u0011a\u000e\u0006\u0003q\r\na\u0001\u0010:p_Rt\u0014B\u0001\u001e(\u0003\u0019\u0001&/\u001a3fM&\u0011A(\u0010\u0002\u0007'R\u0014\u0018N\\4\u000b\u0005i:\u0013\u0001\u00038b[\u0016|F%Z9\u0015\u0005\u0001\u001b\u0005C\u0001\u0014B\u0013\t\u0011uE\u0001\u0003V]&$\bb\u0002#\u0003\u0003\u0003\u0005\raM\u0001\u0004q\u0012\n\u0014!\u00028b[\u0016\u0004\u0013aA1hKV\t\u0001\n\u0005\u0002'\u0013&\u0011!j\n\u0002\u0004\u0013:$\u0018aB1hK~#S-\u001d\u000b\u0003\u00016Cq\u0001R\u0003\u0002\u0002\u0003\u0007\u0001*\u0001\u0003bO\u0016\u0004\u0013A\u0002\u001fj]&$h\bF\u0002R'R\u0003\"A\u0015\u0001\u000e\u0003mAQ!M\u0004A\u0002MBQAR\u0004A\u0002!\u000bAaY8qsR\u0019\u0011k\u0016-\t\u000fEB\u0001\u0013!a\u0001g!9a\t\u0003I\u0001\u0002\u0004A\u0015AD2paf$C-\u001a4bk2$H%M\u000b\u00027*\u00121\u0007X\u0016\u0002;B\u0011alY\u0007\u0002?*\u0011\u0001-Y\u0001\nk:\u001c\u0007.Z2lK\u0012T!AY\u0014\u0002\u0015\u0005tgn\u001c;bi&|g.\u0003\u0002e?\n\tRO\\2iK\u000e\\W\r\u001a,be&\fgnY3\u0002\u001d\r|\u0007/\u001f\u0013eK\u001a\fW\u000f\u001c;%eU\tqM\u000b\u0002I9\u0006i\u0001O]8ek\u000e$\bK]3gSb,\u0012A\u001b\t\u0003WBl\u0011\u0001\u001c\u0006\u0003[:\fA\u0001\\1oO*\tq.\u0001\u0003kCZ\f\u0017B\u0001\u001fm\u00031\u0001(o\u001c3vGR\f%/\u001b;z\u00039\u0001(o\u001c3vGR,E.Z7f]R$\"\u0001^<\u0011\u0005\u0019*\u0018B\u0001<(\u0005\r\te.\u001f\u0005\b\t6\t\t\u00111\u0001I\u0003=\u0001(o\u001c3vGRLE/\u001a:bi>\u0014X#\u0001>\u0011\u0007mtH/D\u0001}\u0015\tix%\u0001\u0006d_2dWm\u0019;j_:L!a ?\u0003\u0011%#XM]1u_J\f\u0001bY1o\u000bF,\u0018\r\u001c\u000b\u0005\u0003\u000b\tY\u0001E\u0002'\u0003\u000fI1!!\u0003(\u0005\u001d\u0011un\u001c7fC:Dq\u0001R\b\u0002\u0002\u0003\u0007A/\u0001\u0005iCND7i\u001c3f)\u0005A\u0015\u0001\u0003;p'R\u0014\u0018N\\4\u0015\u0003)\fa!Z9vC2\u001cH\u0003BA\u0003\u00033Aq\u0001\u0012\n\u0002\u0002\u0003\u0007A/\u0001\u0004QKJ\u001cxN\u001c\t\u0003%R\u0019B\u0001FA\u0011]A9\u00111EA\u0015g!\u000bVBAA\u0013\u0015\r\t9cJ\u0001\beVtG/[7f\u0013\u0011\tY#!\n\u0003#\u0005\u00137\u000f\u001e:bGR4UO\\2uS>t'\u0007\u0006\u0002\u0002\u001e\u0005)\u0011\r\u001d9msR)\u0011+a\r\u00026!)\u0011g\u0006a\u0001g!)ai\u0006a\u0001\u0011\u00069QO\\1qa2LH\u0003BA\u001e\u0003\u000f\u0002RAJA\u001f\u0003\u0003J1!a\u0010(\u0005\u0019y\u0005\u000f^5p]B)a%a\u00114\u0011&\u0019\u0011QI\u0014\u0003\rQ+\b\u000f\\33\u0011!\tI\u0005GA\u0001\u0002\u0004\t\u0016a\u0001=%a\u0005Y!/Z1e%\u0016\u001cx\u000e\u001c<f)\t\ty\u0005E\u0002l\u0003#J1!a\u0015m\u0005\u0019y%M[3di\u0002"
)
public class Person implements Product, Serializable {
   private String name;
   private int age;

   public static Option unapply(final Person x$0) {
      return Person$.MODULE$.unapply(var0);
   }

   public static Person apply(final String name, final int age) {
      return Person$.MODULE$.apply(var0, var1);
   }

   public static Function1 tupled() {
      return Person$.MODULE$.tupled();
   }

   public static Function1 curried() {
      return Person$.MODULE$.curried();
   }

   public String name() {
      return this.name;
   }

   public void name_$eq(final String x$1) {
      this.name = x$1;
   }

   public int age() {
      return this.age;
   }

   public void age_$eq(final int x$1) {
      this.age = x$1;
   }

   public Person copy(final String name, final int age) {
      return new Person(name, age);
   }

   public String copy$default$1() {
      return this.name();
   }

   public int copy$default$2() {
      return this.age();
   }

   public String productPrefix() {
      return "Person";
   }

   public int productArity() {
      return 2;
   }

   public Object productElement(final int x$1) {
      Object var10000;
      switch(x$1) {
      case 0:
         var10000 = this.name();
         break;
      case 1:
         var10000 = BoxesRunTime.boxToInteger(this.age());
         break;
      default:
         throw new IndexOutOfBoundsException(BoxesRunTime.boxToInteger(x$1).toString());
      }

      return var10000;
   }

   public Iterator productIterator() {
      return .MODULE$.typedProductIterator(this);
   }

   public boolean canEqual(final Object x$1) {
      return x$1 instanceof Person;
   }

   public int hashCode() {
      int var1 = -889275714;
      var1 = Statics.mix(var1, Statics.anyHash(this.name()));
      var1 = Statics.mix(var1, this.age());
      return Statics.finalizeHash(var1, 2);
   }

   public String toString() {
      return .MODULE$._toString(this);
   }

   public boolean equals(final Object x$1) {
      boolean var6;
      if (this != x$1) {
         label55: {
            boolean var2;
            if (x$1 instanceof Person) {
               var2 = true;
            } else {
               var2 = false;
            }

            if (var2) {
               label38: {
                  label37: {
                     Person var4 = (Person)x$1;
                     String var10000 = this.name();
                     String var5 = var4.name();
                     if (var10000 == null) {
                        if (var5 != null) {
                           break label37;
                        }
                     } else if (!var10000.equals(var5)) {
                        break label37;
                     }

                     if (this.age() == var4.age() && var4.canEqual(this)) {
                        var6 = true;
                        break label38;
                     }
                  }

                  var6 = false;
               }

               if (var6) {
                  break label55;
               }
            }

            var6 = false;
            return var6;
         }
      }

      var6 = true;
      return var6;
   }

   public Person(final String name, final int age) {
      this.name = name;
      this.age = age;
      super();
      Product.$init$(this);
   }
}

case class 和 class 的一些區別:

  1. case class 在初始化的時候,不用 new,而普通類初始化時必須要 new,
  2. case class 重寫了 toString 方法, 默認實作了 equals 和 hashCode
  3. case class 實作了序列化介面 with Serializable
  4. case class 支持模式匹配(最重要的特征),所有 case class 必須要有引數串列
  5. 有引數用 case class,無參用 case object

繼承和多型

基本語法
class 子類名 extends 父類名 { 類體 }
(1)子類繼承父類的屬性和方法
(2)scala 是單繼承
案例實操:
(1)子類繼承父類的屬性和方法
(2)繼承的呼叫順序:父類構造器->子類構造器

class Person(nameParam: String) {
 var name = nameParam
 var age: Int = _
 def this(nameParam: String, ageParam: Int) {
 this(nameParam)
 this.age = ageParam
 println("父類輔助構造器")
 }
 println("父類主構造器")
}
class Emp(nameParam: String, ageParam: Int) extends 
Person(nameParam, ageParam) {
 var empNo: Int = _
 def this(nameParam: String, ageParam: Int, empNoParam: Int) {
 this(nameParam, ageParam)
 this.empNo = empNoParam
 println("子類的輔助構造器")
 }
  println("子類主構造器")
}
object Test {
 def main(args: Array[String]): Unit = {
 new Emp("z3", 11,1001)
 }
}

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/555443.html

標籤:其他

上一篇:Django學習筆記

下一篇:返回列表

標籤雲
其他(161184) Python(38240) JavaScript(25504) Java(18245) C(15237) 區塊鏈(8271) C#(7972) AI(7469) 爪哇(7425) MySQL(7256) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5875) 数组(5741) R(5409) Linux(5347) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4601) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2436) ASP.NET(2404) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) .NET技术(1984) HtmlCss(1968) 功能(1967) Web開發(1951) C++(1941) python-3.x(1918) 弹簧靴(1913) xml(1889) PostgreSQL(1881) .NETCore(1863) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【C++】Microsoft C++、C 和匯編程式檔案

    ......

    uj5u.com 2020-09-10 00:57:23 more
  • 例外宣告

    相比于斷言適用于排除邏輯上不可能存在的狀態,例外通常是用于邏輯上可能發生的錯誤。 例外宣告 Item 1:當函式不可能拋出例外或不能接受拋出例外時,使用noexcept 理由 如果不打算拋出例外的話,程式就會認為無法處理這種錯誤,并且應當盡早終止,如此可以有效地阻止例外的傳播與擴散。 示例 //不可 ......

    uj5u.com 2020-09-10 00:57:27 more
  • Codeforces 1400E Clear the Multiset(貪心 + 分治)

    鏈接:https://codeforces.com/problemset/problem/1400/E 來源:Codeforces 思路:給你一個陣列,現在你可以進行兩種操作,操作1:將一段沒有 0 的區間進行減一的操作,操作2:將 i 位置上的元素歸零。最終問:將這個陣列的全部元素歸零后操作的最少 ......

    uj5u.com 2020-09-10 00:57:30 more
  • UVA11610 【Reverse Prime】

    本人看到此題沒有翻譯,就附帶了一個自己的翻譯版本 思考 這一題,它的第一個要求是找出所有 $7$ 位反向質數及其質因數的個數。 我們應該需要質數篩篩選1~$10^{7}$的所有數,這里就不慢慢介紹了。但是,重讀題,我們突然發現反向質數都是 $7$ 位,而將它反過來后的數字卻是 $6$ 位數,這就說明 ......

    uj5u.com 2020-09-10 00:57:36 more
  • 統計區間素數數量

    1 #pragma GCC optimize(2) 2 #include <bits/stdc++.h> 3 using namespace std; 4 bool isprime[1000000010]; 5 vector<int> prime; 6 inline int getlist(int ......

    uj5u.com 2020-09-10 00:57:47 more
  • C/C++編程筆記:C++中的 const 變數詳解,教你正確認識const用法

    1、C中的const 1、區域const變數存放在堆疊區中,會分配記憶體(也就是說可以通過地址間接修改變數的值)。測驗代碼如下: 運行結果: 2、全域const變數存放在只讀資料段(不能通過地址修改,會發生寫入錯誤), 默認為外部聯編,可以給其他源檔案使用(需要用extern關鍵字修飾) 運行結果: ......

    uj5u.com 2020-09-10 00:58:04 more
  • 【C++犯錯記錄】VS2019 MFC添加資源不懂如何修改資源宏ID

    1. 首先在資源視圖中,添加資源 2. 點擊新添加的資源,復制自動生成的ID 3. 在解決方案資源管理器中找到Resource.h檔案,編輯,使用整個專案搜索和替換的方式快速替換 宏宣告 4. Ctrl+Shift+F 全域搜索,點擊查找全部,然后逐個替換 5. 為什么使用搜索替換而不使用屬性視窗直 ......

    uj5u.com 2020-09-10 00:59:11 more
  • 【C++犯錯記錄】VS2019 MFC不懂的批量添加資源

    1. 打開資源頭檔案Resource.h,在其中預先定義好宏 ID(不清楚其實ID值應該設定多少,可以先新建一個相同的資源項,再在這個資源的ID值的基礎上遞增即可) 2. 在資源視圖中選中專案資源,按F7編輯資源檔案,按 ID 型別 相對路徑的形式添加 資源。(別忘了先把檔案拷貝到專案中的res檔案 ......

    uj5u.com 2020-09-10 01:00:19 more
  • C/C++編程筆記:關于C++的參考型別,專供新手入門使用

    今天要講的是C++中我最喜歡的一個用法——參考,也叫別名。 參考就是給一個變數名取一個變數名,方便我們間接地使用這個變數。我們可以給一個變數創建N個參考,這N + 1個變數共享了同一塊記憶體區域。(參考型別的變數會占用記憶體空間,占用的記憶體空間的大小和指標型別的大小是相同的。雖然參考是一個物件的別名,但 ......

    uj5u.com 2020-09-10 01:00:22 more
  • 【C/C++編程筆記】從頭開始學習C ++:初學者完整指南

    眾所周知,C ++的學習曲線陡峭,但是花時間學習這種語言將為您的職業帶來奇跡,并使您與其他開發人員區分開。您會更輕松地學習新語言,形成真正的解決問題的技能,并在編程的基礎上打下堅實的基礎。 C ++將幫助您養成良好的編程習慣(即清晰一致的編碼風格,在撰寫代碼時注釋代碼,并限制類內部的可見性),并且由 ......

    uj5u.com 2020-09-10 01:00:41 more
最新发布
  • Scala面向物件

    # 類和物件 **組成結構** ? 建構式: 在創建物件的時候給屬性賦值 ? 成員變數: ? 成員方法(函式) ? 區域變數 ? 代碼塊 ## 構造器 每個類都有一個主構造器,這個構造器和類定義"交織"在一起類名后面的內容就是主構造器,如果引數串列為空的話,()可以省略 scala的類有且僅有一個 ......

    uj5u.com 2023-06-18 07:42:11 more
  • Django學習筆記

    ## 1.常用命令 `創建專案:django-admin startproject 專案名` `創建APP(進入工程目錄):python manage.py startapp 網站名` `創建庫表(進入工程目錄):python manage.py makemigrations` `執行庫表建立(進入 ......

    uj5u.com 2023-06-18 07:40:09 more
  • Go 語言之自定義 zap 日志

    # Go 語言之自定義 zap 日志 [zap 日志](https://github.com/uber-go/zap):https://github.com/uber-go/zap ## 一、日志寫入檔案 - `zap.NewProduction`、`zap.NewDevelopment` 是預設配 ......

    uj5u.com 2023-06-18 07:40:00 more
  • Spring Boot實作高質量的CRUD-5

    (續前文) ## 9、Service實作類代碼示例 ? ? 以用戶管理模塊為例,展示Service實作類代碼。用戶管理的Service實作類為UserManServiceImpl。?UserManServiceImpl除了沒有deleteItems方法外,具備CRUD的其它常規方法。實際上?User ......

    uj5u.com 2023-06-18 07:39:53 more
  • ?任務編排工具在之家業務系統中應用探究

    本文主要介紹在之家廣告業務系統中運用任務編排治理工具的場景及其可以解決的問題,講解任務編排框架的核心要點,以及向大家演示一個任務編排框架的基本結構,讓大家對任務編排工具增強業務開發效率,提高研發質量有更深刻的理解。 ......

    uj5u.com 2023-06-18 07:39:37 more
  • Go 語言之 zap 日志庫簡單使用

    # Go 語言之 zap 日志庫簡單使用 ## 默認的 Go log log:https://pkg.go.dev/log ```go package main import ( "log" "os" ) func init() { log.SetPrefix("LOG: ") // 設定前綴 f, ......

    uj5u.com 2023-06-18 07:39:24 more
  • Scala面向物件

    # 類和物件 **組成結構** ? 建構式: 在創建物件的時候給屬性賦值 ? 成員變數: ? 成員方法(函式) ? 區域變數 ? 代碼塊 ## 構造器 每個類都有一個主構造器,這個構造器和類定義"交織"在一起類名后面的內容就是主構造器,如果引數串列為空的話,()可以省略 scala的類有且僅有一個 ......

    uj5u.com 2023-06-18 07:39:00 more
  • 基于回歸分析的波士頓房價分析

    #基于回歸分析的波士頓房價分析 專案實作步驟: 1.專案結構 2.處理資料 3.處理繪圖 4.對資料進行分析 5.結果展示 一.專案結構 ![image](https://img2023.cnblogs.com/blog/3047082/202306/3047082-2023061722315431 ......

    uj5u.com 2023-06-18 07:38:30 more
  • 通過模仿學會Python爬蟲(一):零基礎上手

    好家伙,爬蟲來了 爬蟲,這玩意,不會怎么辦, 誒,先抄一份作業回來 1.別人的爬蟲 Python爬蟲史上超詳細講解(零基礎入門,老年人都看的懂)_ChenBinBini的博客-CSDN博客 # -*- codeing = utf-8 -*- from bs4 import BeautifulSoup ......

    uj5u.com 2023-06-18 07:38:11 more
  • Python潮流周刊#7:我討厭用 asyncio

    你好,我是貓哥。這里記錄每周值得分享的 Python 及通用技術內容,部分為英文,已在小標題注明。(標題取自其中一則分享,不代表全部內容都是該主題,特此宣告。) 首發于我的博客:[https://pythoncat.top/posts/2023-06-17-weekly7](https://pyth ......

    uj5u.com 2023-06-18 07:32:25 more