Scala: объектно-ориентированный, объект, абстрактный класс, внутренний класс, трейт (2)

Большие данные
Scala: объектно-ориентированный, объект, абстрактный класс, внутренний класс, трейт (2)

Scala: объектно-ориентированный, объект, абстрактные классы, внутренние классы, черта

цель обучения

  • Освойте использование классов и объектов scala
  • Освоить использование наследования
  • Научитесь использовать черты

1. Классы и объекты

Scala является объектно-ориентированным и имеет концепцию классов и объектов. Мы по-прежнему можем разрабатывать объектно-ориентированные приложения на основе языка scala.

1.1 Создание классов и объектов

использование

  • использоватьclassопределить класс
  • использоватьnewсоздавать объекты

Пример

Создайте класс Person и создайте его объект

шаг

  1. Создайте проект scala и создайте объект
  2. добавить основной метод
  3. Создание классов и объектов

выполнить

  1. Создайте проект в IDEA и создайте объект (основной метод должен быть помещен в объект)
  2. добавить основной метод
  3. Создайте класс человека
  4. Создайте объект класса Person в основном методе

Код ссылки

object _01ClassDemo {
  // 创建类
  class Person{}

  def main(args: Array[String]): Unit = {
    // 创建对象
    val p = new Person()
    println(p)
  }
}

1.2 Стенография

использование

  • Если класс пустой и не имеет членов, его можно опустить.{}

  • Если параметр конструктора пустой, его можно опустить()

Пример

Воссоздайте класс и объект Person, используя сокращенный метод

Код ссылки

object _02ClassDemo {

  // 创建类,省略花括号
  class Person

  def main(args: Array[String]): Unit = {
    // 创建对象,省略括号
    val person = new Person
  }
}

2. Определение переменных-членов и доступ к ним

Класс будет иметь свои атрибуты, например: класс, как и человек, имеет свое имя и возраст. Затем мы научимся определять и получать доступ к переменным-членам в классе.

использование

  • использовать в классеvar/valдля определения переменных-членов
  • Объекты используют имена переменных-членов напрямую для доступа к переменным-членам.

Пример

  1. Определите класс Person с полем имени и возраста
  2. Создайте объект с именем «Чжансан» в возрасте 20 лет.
  3. напечатать имя и возраст объекта

шаг

  1. Создайте объект и добавьте основной метод
  2. Создайте класс Person, добавьте поле имени и поле возраста, инициализируйте поля и позвольте scala автоматически выполнять вывод типа.
  3. Создайте объект класса Person в основном методе и установите для переменных-членов значение «Чжан Сан», 20
  4. напечатать имя и возраст объекта

Код ссылки

object _03ClassDemo {
  class Person {
    // 定义成员变量
    var name = ""
    var age = 0
  }

  def main(args: Array[String]): Unit = {
    // 创建Person对象
    val person = new Person
    person.name = "zhangsan"
    person.age = 20

    // 获取变量值
    println(person.name)
    println(person.age)
  }
}

3. Инициализируйте переменные-члены символом подчеркивания

В scala существует более лаконичный способ инициализации переменных-членов, который может сделать код более лаконичным.

использование

  • по определениюvarКогда переменная-член типа, вы можете использовать_для инициализации переменных-членов
    • String => null
    • Int => 0
    • Boolean => false
    • Double => 0.0
    • ...
  • valПеременные-члены типа должны быть вручную инициализированы сами по себе

Пример

  1. Определите класс Person с полем имени и возраста
  2. Создайте объект с именем «Чжансан» в возрасте 20 лет.
  3. напечатать имя и возраст объекта

шаг

  1. Создайте объект и добавьте основной метод
  2. Создайте класс Person, добавьте поле имени и поле возраста, укажите тип данных, инициализируйте символом подчеркивания.
  3. Создайте объект класса Person в основном методе и установите для переменных-членов значение «Чжан Сан», 20
  4. напечатать имя и возраст объекта

Код ссылки

object _04ClassDemo {

  class Person{
    // 使用下划线进行初始化
    var name:String = _
    var age:Int = _
  }

  def main(args: Array[String]): Unit = {
    val person = new Person
    
    println(person.name)
    println(person.age)
  }
}

4. Определите методы-члены

Класс может иметь собственное поведение, и scala также может определять поведение класса, определяя методы-члены.

определение

В классе scala он также используетсяdefдля определения методов-членов

Пример

  1. Создайте класс клиентов

    1557322180244

  2. Создайте объект этого класса и вызовите метод printHello

шаг

  1. Создайте объект и добавьте основной метод
  2. Создайте класс Customer, добавьте переменные-члены и методы-члены.
  3. Создайте объект класса Customer в основном методе и установите значение переменной-члена (Чжан Сан, мужчина)
  4. вызов метода члена

Код ссылки

object _05ClassDemo {

  class Customer {
    var name:String = _
    var sex:String = _

    // 定义成员方法
    def sayHi(msg:String) = {
      println(msg)
    }
  }

  def main(args: Array[String]): Unit = {
    val customer = new Customer
    customer.name = "张三"
    customer.sex = "男"
    customer.sayHi("你好")
  }
}

5. Модификаторы доступа

Подобно Java, Scala также может использовать модификаторы доступа для управления доступом к переменным-членам и методам-членам.

определение

Контроль доступа в Java также применим к scala.Вы можете добавить ключевые слова private/protected перед членами, чтобы управлять видимостью членов. Но в скале,没有public关键字, любой член, не помеченный как частный или защищенный, является общедоступным

кейс

  • Определить класс Person

    1557664595693

  • Создайте объект класса в основном методе и проверьте, можно ли получить доступ к закрытым членам.

Код ссылки

object _02AccessDemo {

  class Person {
    // 定义私有成员变量
    private var name:String = _
    private var age:Int = _

    def getName() = name
    def setName(name:String) = this.name = name
    def getAge() = age
    def setAge(age:Int) = this.age = age

    // 定义私有成员方法
    private def getNameAndAge = {
      name -> age
    }
  }

  def main(args: Array[String]): Unit = {
    val person = new Person
    person.setName("张三")
    person.setAge(10)

    println(person.getName())
    println(person.getAge())
  }
}

6. Конструктор классов

При создании объекта класса автоматически вызывается конструктор класса. Конструкторы по умолчанию использовались ранее, и далее мы узнаем, как настроить конструкторы.

6.1 Основной конструктор

Мы узнали, что конструкторы Java имеют списки построения и блоки кода построения.

class Person {
    // 成员变量
    private String name;
    private Integer age;

    // Java构造器
    public Person(String name, Integer age) {
        // 初始化成员变量
        this.name = name;
        this.age = age;
    }
}

В scala мы можем сделать это, используя более лаконичный синтаксис.

грамматика

class 类名(var/val 参数名:类型 = 默认值, var/val 参数名:类型 = 默认值){
    // 构造代码块
}

[!NOTE]

  • Список параметров основного конструктора определяется непосредственно после имени класса, а val/var добавляется, чтобы указать, что переменные-члены определяются непосредственно через основной конструктор.
  • Список параметров конструктора может указывать значения по умолчанию
  • Создайте экземпляр и вызовите конструктор, чтобы указать поля для инициализации
  • Код во всем классе, за исключением определений полей и определений методов, является кодом построения.

Пример

  1. Определите класс Person, определите поля имени и возраста через список параметров основного конструктора и установите их значения по умолчанию.
  2. Вывод «Вызвать главный конструктор» в главном конструкторе
  3. Создайте объект "Чжан Сан" (имя Чжан Сан, возраст 20 лет), напечатайте имя и возраст объекта.
  4. Создайте «пустой» объект, не передавайте конструктору никаких параметров, напечатайте имя и возраст объекта.
  5. Создайте объект «man40», не передавайте параметр имени, укажите возраст как 40 и напечатайте имя и возраст объекта.

Код ссылки

object _06ConstructorDemo {

  // 定义类的主构造器
  // 指定默认值
  class Person(var name:String = "", var age:Int = 0) {
    println("调用主构造器")
  }

  def main(args: Array[String]): Unit = {
    // 给构造器传入参数
    val zhangsan = new Person("张三", 20)
    println(zhangsan.name)
    println(zhangsan.age)

    println("---")

    // 不传入任何参数
    val empty = new Person
    println(empty.name)
    println(empty.age)

    println("---")

    // 指定字段进行初始化
    val man40 = new Person(age = 40)
    println(man40.name)
    println(man40.age)
  }
}

6.2 Вспомогательные конструкторы

В Scala, помимо определения основного конструктора, вы также можете определить вспомогательные конструкторы по мере необходимости. Например, объекты можно создавать несколькими способами, и в это время можно определить больше конструкторов. Мы вызываем конструкторы, отличные от основного конструктораВспомогательный конструктор.

грамматика

  • Определение вспомогательных конструкторов, как и определение методов, также используетdefключевое слово для определения
  • Название этого методаthis
def this(参数名:类型, 参数名:类型) {
    // 第一行需要调用主构造器或者其他构造器
    // 构造器代码
}

[!DANGER]

Первая строка кода вспомогательного конструктора должна бытьВызов основного конструктора или других вспомогательных конструкторов

Пример

Пример описания

  • Определите класс Customer с полем имени и адреса
  • Определите основной конструктор класса Customer (инициализируйте имя и адрес)
  • Определите вспомогательный конструктор для класса Customer, который получает параметр массива и использует параметр массива для инициализации переменных-членов.
  • Используйте вспомогательный конструктор класса Person для создания объекта «zhangsan».
    • Меня зовут Чжан Сан.
    • Адрес Пекин.
  • Распечатать название и адрес объекта

Код ссылки

object _07ConstructorDemo {

  class Customer(var name:String = "", var address:String = "") {
    // 定义辅助构造器
    def this(arr:Array[String]) = {
      // 辅助构造器必须要调用主构造器或者其他辅助构造器
      this(arr(0), arr(1))
    }
  }

  def main(args: Array[String]): Unit = {
    val zhangsan = new Customer(Array("张三", "北京"))

    println(zhangsan.name)
    println(zhangsan.address)
  }
}

7. Объект Singleton (Объект)

В Java в scala нет статического члена.Если мы хотим определить статические переменные и статические методы, подобные Java, нам нужно использовать объект singleton в scala — объект.

7.1 Определение одноэлементного объекта

Одноэлементный объект означает, что в глобальном масштабе существует только один объект (аналогично статической концепции Java).

  • Определение одноэлементного объекта очень похоже на определение класса, просто замените класс объектом.
  • Переменные-члены, определенные в объекте, аналогичны статическим переменным в Java.
  • Вы можете использовать объект для прямой ссылки на переменные-члены

Пример

Пример описания

  • Определите одноэлементный объект Dog, чтобы сохранить количество ног у собаки.
  • вывести количество собачьих лап в основном методе

Код ссылки

object _08ObjectDemo {

  // 定义一个单例对象
  object Dog {
    // 定义腿的数量
    val LEG_NUM = 4
  }

  def main(args: Array[String]): Unit = {
    println(Dog.LEG_NUM)
  }
}

7.2 Определение методов-членов в одноэлементном объекте

  • Методы-члены, определенные в объекте, аналогичны статическим методам в Java.

Пример

Пример описания

  • Разработайте одноэлементный объект и определите метод, способный печатать разделительные линии (15 знаков минус).
  • Вызовите этот метод в основном методе, чтобы напечатать разделительную линию.

Код ссылки

object _09ObjectDemo {

  object PrintUtil {

    // 打印分割线
    def printSpliter() = {
      // 字符串乘法,表示返回多少个字符串
      println("-" * 10)
    }
  }

  def main(args: Array[String]): Unit = {
    PrintUtil.printSpliter()
  }
}

7.3 Чемодан для инструментов

необходимость

  • Напишите класс инструментов DateUtil специально для форматирования даты и времени.
  • Определите метод для преобразования даты (Date) в строку год-месяц-день, например: 2030-10-05.

шаг

  • Определите одноэлементный объект DateUtil и определите метод форматирования даты (формат).
  • Преобразование даты в строку с помощью SimpleDateFormat

Код ссылки

object _10ObjectDemo {

  object DateUtils {
    // 在object中定义的成员变量,相当于Java中定义一个静态变量
    // 定义一个SimpleDateFormat日期时间格式化对象
    val simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm")

    // 相当于Java中定义一个静态方法
    def format(date: Date) = simpleDateFormat.format(date)
  }

  // main是一个静态方法,所以必须要写在object中
  def main(args: Array[String]): Unit = {
    println(DateUtils.format(new Date()))
  }
}

8. основной метод

В Scala, как и в Java, должен быть метод main, если вы хотите запустить программу. В то время как в Java основной метод является статическим, в scala статического метода нет. В scala этот основной метод должен быть помещен в одноэлементный объект.

8.1 Определение основного метода

основной метод

def main(args:Array[String]):Unit = {
    // 方法体
}

Пример

Пример описания

  • Создайте одноэлементный объект и напечатайте «hello, scala» в одноэлементном объекте.

Код ссылки

object Main5 {
  def main(args:Array[String]) = {
    println("hello, scala")
  }
}

8.2 Реализуйте App Trait для определения записи

Создайте объект, наследуйте от App Trait (черта), а затем напишите код, который нужно написать в методе main в теле конструктора объекта.

object 单例对象名 extends App {
    // 方法体
}

Пример

Пример описания

  • Наследуйте трейт App для реализации записи. Также выведите «привет, скала»

Код ссылки

object Main5 extends App {
  println("hello, scala")
}

9. Сопутствующие объекты

В Java часто есть классы, которые имеют как члены-экземпляры, так и статические члены. Например:

public class CustomerService {

    private static String SERVICE_NAME = "CustomerService";

    public void save() {
        // 保存客户
        System.out.println(SERVICE_NAME + ":保存客户");
    }

    public static void main(String[] args) {
        new CustomerService().save();
    }
}

В scala для достижения аналогичного эффекта можно использовать сопутствующий объект.

Мы также можем использовать сопутствующие объекты для быстрого создания объектов, например:

// 无需使用new就可以快速来创建对象
val a = Array(1,2,3)
val b = Set(1,2,3)

9.1 Определение сопутствующих объектов

Класс и объект имеют одно и то же имя. Этот объект называетсясопутствующий объект, этот класс называетсясопутствующий класс

  • Объект-компаньон должен иметь то же имя, что и класс-компаньон.
  • Объект-компаньон и класс-компаньон в одном и том же исходном файле scala
  • Сопутствующие объекты и сопутствующие классы могут обращаться к частным свойствам друг друга.

Пример

Пример описания

  • Напишите класс CustomerService с методом сохранения, который печатает

    服务类名称:保存客户
    
  • Напишите объект-компаньон CustomerService и определите закрытую переменную для сохранения имени класса обслуживания.

  • Создайте объект CustomerService и вызовите метод сохранения

Код ссылки

object _11ObjectDemo {

  class CustomerService {
    def save() = {
      println(s"${CustomerService.SERVICE_NAME}:保存客户")
    }
  }

  // CustomerService的伴生对象
  object CustomerService {
    private val SERVICE_NAME = "CustomerService"
  }

  def main(args: Array[String]): Unit = {
    val customerService = new CustomerService()
    customerService.save()
  }
}

9.2 права доступа private[this]

Если разрешение члена установлено как private[this], к нему можно получить доступ только в текущем классе. Сопутствующие объекты также недоступны

Пример

Пример описания

  • Определите класс Person с полем имени
  • Определите сопутствующий объект класса Person и определите метод printPerson.
  • Проверяет, может ли объект-компаньон получить доступ к членам разрешения private[this]

образец кода

  class Person(private[this] var name:String)
  
  object Person {
    def printPerson(person:Person): Unit = {
      println(person.name)
    }
  }
  
  def main(args: Array[String]): Unit = {
    val person = new Person("张三")
    Person.printPerson(person)
  }

Приведенный выше код скомпилируется с ошибкой. Но удалите [это], чтобы получить доступ

9.3 Метод применения

Мы уже использовали этот метод для создания объекта Array.

// 创建一个Array对象
val a = Array(1,2,3,4)

Этот способ написания очень прост, вам не нужно писать новый, затем печатать пробел, а затем писать имя класса. Мы можем сделать это с помощью метода apply объекта-компаньона.

определение

Определите метод применения

object 伴生对象名 {
	def apply(参数名:参数类型, 参数名:参数类型...) = new 类(...)
}

создать объект

伴生对象名(参数1, 参数2...)

Пример

Пример описания

  • Определите класс Person с двумя полями: имя и возраст
  • Переопределите метод применения и используйте имя класса Person для создания объекта.
  • Создайте объект этого класса в основном методе и напечатайте имя и возраст

Код ссылки

object _12ApplyDemo {
  class Person(var name:String = "", var age:Int = 0)

  object Person {
    // 定义apply方法,接收两个参数
    def apply(name:String, age:Int) = new Person(name, age)
  }

  def main(args: Array[String]): Unit = {
    // 使用伴生对象名称来创建对象
    val zhangsan = Person("张三", 20)
    println(zhangsan.name)
    println(zhangsan.age)
  }
}

10. Наследование

Язык scala поддерживает объектно-ориентированное программирование, мы также можем использовать scala для реализации наследования и сокращения повторяющегося кода за счет наследования.

10.1 Синтаксис определения

  • Scala, как и Java, используетextendsключевое слово для реализации наследования
  • Вы можете определить поля и методы в подклассе, которых нет в суперклассе, или переопределить методы суперкласса.
  • И классы, и одноэлементные объекты могут наследоваться от некоторого родительского класса.

грамматика

class/object 子类 extends 父类 {
    ..
}

10.2 Наследование классов

  • Определите класс Person, а затем определите класс Student, который наследуется от класса Person.

    1557324172277

  • Создайте экземпляр объекта класса Student и установите имя «Чжан Сан».

  • печатать имя

Код ссылки

class Person {
  var name = "super"

  def getName = this.name
}

class Student extends Person

object Main13 {
  def main(args: Array[String]): Unit = {
    val p1 = new Person()
    val p2 = new Student()

    p2.name = "张三"

    println(p2.getName)
  }
}

10.3 Наследование одноэлементных объектов

Пример описания

  • Создайте одноэлементный объект Student и позвольте одноэлементному объекту наследовать класс Person в примере 1.
  • Установите имя объекта Singleton на «Чжан Сан» и позвоните в метод GetName Of Student Singleton Object
class Person {
  var name = "super"

  def getName = this.name
}

object Student extends Person

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

    println(Student.getName)
  }
}

10.4 переопределение и супер

Подобно языку Java, мы используем переопределение в подклассе для переопределения членов родительского класса, и мы можем использовать super для ссылки на родительский класс.

использование

  • Чтобы переопределить метод в родительском классе, подкласс должен использовать ключевое слово override.
  • Используйте переопределение, чтобы переопределить поле val
  • Используйте ключевое слово super для доступа к методам-членам родительского класса.

Пример

Пример описания

  • Определите класс Person, который содержит
    • Поле имени (непереназначаемое)
    • метод получения имени
  • Определить студенческий класс
    • Переопределить поле имени
    • Перепишите метод, чтобы получить имя, вернуть «привет,» + имя
  • Создайте пример объекта Student и вызовите его метод getName.

Код ссылки

class Person {
  val name = "super"

  def getName = name
}

class Student extends Person {
  // 重写val字段
  override val name: String = "child"

  // 重写getName方法
  override def getName: String = "hello, " + super.getName
}

object Main13 {
  def main(args: Array[String]): Unit = {
    println(new Student().getName)
  }
}

11. Типовая оценка

Иногда мы разрабатываем программы для выполнения соответствующей логики в зависимости от типа переменных.

1557152463629

В scala, как выполнить оценку типа?

Есть два способа:

  • isInstanceOf
  • getClass/classOf

11.1 isInstanceOf/asInstanceOf

В Java мы можем использовать ключевое слово instanceof для определения типа и (тип) объекта для выполнения преобразования типа Как реализовать это в scala?

Объекты в scala предоставляют методы isInstanceOf и asInstanceOf.

  • isInstanceOf определяет, является ли объект объектом указанного класса
  • asInstanceOf преобразует объект в указанный тип

использование

// 判断对象是否为指定类型
val trueOrFalse:Boolean = 对象.isInstanceOf[类型]
// 将对象转换为指定类型
val 变量 = 对象.asInstanceOf[类型]

Пример

Пример описания

  • Определить класс Person
  • Определите класс Student, который наследуется от класса Person
  • Создайте объект студенческого класса
  • Определите, относится ли объект к типу «Студент», если да, преобразуйте его в тип «Студент» и распечатайте объект.

Код ссылки

class Person3
class Student3 extends Person3

object Main3 {
  def main(args: Array[String]): Unit = {
    val s1:Person3 = new Student3

    // 判断s1是否为Student3类型
    if(s1.isInstanceOf[Student3]) {
      // 将s1转换为Student3类型
      val s2 =  s1.asInstanceOf[Student3]
      println(s2)
    }

  }
}

11.2 getClass и classOf

isInstanceOf может только определить, является ли объектОпределяет класс и его подклассыНельзя точно судить о том, что объект является объектом указанного класса. Если требуется точно определить, что объект является объектом указанного класса, то можно использовать только getClass и classOf.

использование

  • p.getClass может точно получить тип объекта
  • classOf[x] может получить точный тип
  • Используйте оператор == для прямого сравнения типов

Пример

Пример описания

  • Определить класс Person
  • Определите класс Student, который наследуется от класса Person
  • Создайте объект класса Student и укажите его тип как Person
  • Тест использует isInstance, чтобы определить, относится ли объект к типу Person.
  • Тест использует getClass/classOf, чтобы определить, относится ли объект к типу Person.
  • Тест использует getClass/classOf, чтобы определить, относится ли объект к типу Student.

Код ссылки

class Person4
class Student4 extends Person4

object Student4{
  def main(args: Array[String]) {
    val p:Person4=new Student4
    //判断p是否为Person4类的实例
    println(p.isInstanceOf[Person4])//true

    //判断p的类型是否为Person4类
    println(p.getClass == classOf[Person4])//false

    //判断p的类型是否为Student4类
    println(p.getClass == classOf[Student4])//true
  }
}

12. Абстрактные классы

Как и в языке Java, абстрактные классы также могут быть определены в scala.

12.1 Определения

Если член класса не полностью определен в текущем классе, этоабстрактный класс

Возможны два случая неполного определения:

  1. Методы не имеют тела (абстрактный метод)
  2. Переменная не инициализирована (абстрактное поле)

Определение абстрактного класса такое же, как в Java, добавление перед классомabstractключевые слова

// 定义抽象类
abstract class 抽象类名 {
  // 定义抽象字段
  val 抽象字段名:类型
  // 定义抽象方法
  def 方法名(参数:参数类型,参数:参数类型...):返回类型
}

12.2 Абстрактные методы

Пример

1552449400240

  • Разработайте 4 класса для представления отношения наследования на приведенном выше рисунке.
  • Каждая фигура имеет свой собственный метод нахождения площади, но разные фигуры имеют разные методы вычисления площади.

шаг

  1. Создайте абстрактный класс Shape и добавьте абстрактный метод площади для вычисления площади.
  2. Создайте класс Square Square, унаследованный от Shape, он имеет основной конструктор для длины стороны и реализует метод расчета площади.
  3. Создайте класс прямоугольника, наследуемый от Shape, который имеет главный конструктор для длины и ширины и реализует метод вычисления площади
  4. Создайте класс круга, наследуемый от Shape, он имеет основной конструктор для радиуса и реализует метод для вычисления площади.
  5. Напишите основной метод для создания квадратных, прямоугольных и круглых объектов соответственно и распечатайте их площадь.

Код ссылки

// 创建形状抽象类
abstract class Shape {
  def area:Double
}

// 创建正方形类
class Square(var edge:Double /*边长*/) extends Shape {
  // 实现父类计算面积的方法
  override def area: Double = edge * edge
}

// 创建长方形类
class Rectangle(var length:Double /*长*/, var width:Double /*宽*/) extends Shape {
  override def area: Double = length * width
}

// 创建圆形类
class Cirle(var radius:Double /*半径*/) extends Shape {
  override def area: Double = Math.PI * radius * radius
}

object Main6 {
  def main(args: Array[String]): Unit = {
    val s1:Shape = new Square(2)
    val s2:Shape = new Rectangle(2,3)
    val s3:Shape = new Cirle(2)

    println(s1.area)
    println(s2.area)
    println(s3.area)
  }
}

12.3 Абстрактные поля

В scala также можно определять абстрактные поля. Если переменная-член не инициализирована, мы считаем ее абстрактной.

определение

грамматика

abstract class 抽象类 {
    val/var 抽象字段:类型
}

Пример

Пример описания

  1. Создайте абстрактный класс Person с абстрактным полем String WHO_AM_I.
  2. Создайте класс Student, наследуйте от класса Person, перепишите поле WHO_AM_I и инициализируйте его как ученика.
  3. Создайте класс Policeman, наследуйте от класса Person, перепишите поле WHO_AM_I и инициализируйте полицию.
  4. Добавьте основной метод, создайте экземпляры Student/Policeman соответственно, а затем напечатайте WHO_AM_I соответственно.

Код ссылки

// 定义一个人的抽象类
abstract class Person6 {
  // 没有初始化的val字段就是抽象字段
  val WHO_AM_I:String
}

class Student6 extends Person6 {
  override val WHO_AM_I: String = "学生"
}

class Policeman6 extends Person6 {
  override val WHO_AM_I: String = "警察"
}

object Main6 {
  def main(args: Array[String]): Unit = {
    val p1 = new Student6
    val p2 = new Policeman6

    println(p1.WHO_AM_I)
    println(p2.WHO_AM_I)
  }
}

13. Анонимные внутренние классы

Анонимный внутренний класс — это подкласс без имени, который используется непосредственно для создания объектов-экземпляров. Анонимные внутренние классы широко используются в исходном коде Spark.

Анонимные внутренние классы в scala совместимы с Java.

определение

грамматика

val/var 变量名 = new 类/抽象类 {
    // 重写方法
}

Пример

Пример описания

  1. Создайте абстрактный класс Person и добавьте абстрактный метод sayHello.
  2. Добавьте основной метод для реализации Person, создав анонимный внутренний класс.
  3. Метод Sayhello для вызова анонимного объекта внутреннего класса

Код ссылки

abstract class Person7 {
  def sayHello:Unit
}

object Main7 {
  def main(args: Array[String]): Unit = {
    // 直接用new来创建一个匿名内部类对象
    val p1 = new Person7 {
      override def sayHello: Unit = println("我是一个匿名内部类")
    }
    p1.sayHello
  }
}

14. Черты

В джаве в scala нет интерфейса, альтернативное понятие - трейт

14.1 Определения

  • Трейты — это основная единица повторного использования кода в scala.
  • Он может инкапсулировать определения методов и полей, а затем добавлять их в класс.
  • В отличие от наследования классов, наследование классов требует, чтобы каждый класс мог наследовать только一个суперкласс, в то время как класс может добавить任意数量характеристики.
  • Определение трейта похоже на определение абстрактного класса, но оно определяется с помощьюtraitключевые слова

грамматика

определить черты

trait 名称 {
    // 抽象字段
    // 抽象方法
}

унаследованные черты

class 类 extends 特质1 with 特质2 {
    // 字段实现
    // 方法实现
}
  • использоватьextendsЧтобы наследовать признак (в scala, будь то класс или признак, используется ключевое слово extends)

  • Если вы хотите унаследовать несколько признаков, используйтеwithключевые слова

14.2 Использование трейтов в качестве интерфейсов

Черты используются в качестве интерфейсов так же, как используются интерфейсы Java.

Пример | Наследование одного признака

Пример описания

  1. Создайте трейт Logger и добавьте абстрактный метод журнала, который принимает параметр String.
  2. Создайте класс ConsoleLogger, наследуйте трейт Logger, реализуйте метод журнала и печатайте сообщения.
  3. Добавьте основной метод, создайте объект ConsoleLogger и вызовите метод журнала.

Код ссылки

  trait Logger {
    // 抽象方法
    def log(message:String)
  }

  class ConsoleLogger extends Logger {
    override def log(message: String): Unit = println("控制台日志:" + message)
  }

  def main(args: Array[String]): Unit = {
    val logger = new ConsoleLogger
    logger.log("这是一条日志")
  }

Пример | Наследование нескольких признаков

Пример описания

  1. Создайте трейт MessageSender и добавьте метод отправки
  2. Создайте трейт MessageReceiver и добавьте метод получения
  3. Создайте MessageWorker, который реализует эти две черты.
  4. Вызывается в основном, вызывает метод отправки и метод получения соответственно

Код ссылки

trait MessageSender {
    def send(msg:String)
}

trait MessageReceive {
    def receive():String
}

class MessageWorker extends MessageSender with MessageReceive {
    override def send(msg: String): Unit = println(s"发送消息:${msg}")

    override def receive(): String = "你好!我叫一个好人!"
}

def main(args: Array[String]): Unit = {
    val worker = new MessageWorker
    worker.send("hello")
    println(worker.receive())
}

Пример | Объект наследует трейт

Пример описания

  1. Создайте трейт Logger и добавьте абстрактный метод журнала.
  2. Создайте объект ConsoleLogger, реализуйте трейт LoggerForObject, реализуйте метод журнала и распечатайте сообщение.
  3. Напишите основной метод и вызовите метод журнала ConsoleLogger.

Код ссылки

trait Logger {
    def log(message:String)
}

object ConsoleLogger extends Logger {
    override def log(message: String): Unit = println("控制台消息:" + message)
}

def main(args: Array[String]): Unit = {
    ConsoleLogger.log("程序退出!")
}

14.3 Определение конкретных методов

Подобно классам, трейты также могут определять определенные методы.

Пример

Пример описания

  1. Определите трейт Logger и добавьте метод реализации журнала.
  2. Определите класс UserService, реализующий трейт Logger.
  • Добавьте метод добавления, который печатает «Добавить пользователя».
  1. добавить основной метод
  • Создайте экземпляр объекта UserService
  • вызвать метод добавления

Код ссылки

trait LoggerDetail {
  // 在trait中定义具体方法
  def log(msg:String) = println(msg)
}

class UserService extends LoggerDetail {
  def add() = log("添加用户")
}

object MethodInTrait {
  def main(args: Array[String]): Unit = {
    val userService = new UserService
    userService.add()
  }
}

14.4 Определение конкретных полей и абстрактных полей в признаках

определение

  • Конкретные поля и абстрактные поля могут быть определены в трейтах.

  • Подклассы, которые наследуют признак, автоматически имеют поля, определенные в признаке.

  • Поля добавляются непосредственно в подклассы

Пример

Пример описания

Реализовать инструмент вывода лога через трейт, который может автоматически добавлять дату лога

шаг

  1. Создайте трейт Logger
    • Определите поле SimpleDateFormat для форматирования даты (отображаемой во времени)
    • Определите абстрактное поле TYPE для определения выходной информации.
    • Создайте абстрактный метод журнала для вывода журналов
  2. Создайте класс ConsoleLogger, реализуйте абстрактное поле TYPE и метод журнала.
  3. добавить основной метод
  • Создайте объект класса ConsoleLogger
  • метод журнала вызовов

Код ссылки

  trait Logger {
    val sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm")
    def log(msg:String)
  }

  class ConsoleLogger extends Logger {
    override def log(msg: String): Unit = {
      val info = s"${sdf.format(new Date())}:控制台消息:${msg}"
      println(info)
    }
  }

  def main(args: Array[String]): Unit = {
    val logger = new ConsoleLogger()
    logger.log("NullPointerException")
  }

14.5 Экземпляры объектов, смешанные с чертами

В scala трейты можно смешивать с объектами, то есть к объекту добавляются методы и поля, определенные в трейтах.

определение

грамматика

val/var 对象名 = new 类 with 特质

Пример

  • датьобъектдобавить дополнительное поведение

шаг

  1. Создайте трейт Logger
    • Добавьте метод реализации журнала для печати параметров
  2. Создайте класс UserService
  3. добавить основной метод
    • Создайте объект UserService и добавьте трейт Logger.
    • метод журнала вызовов

Код ссылки

  trait Logger {
    def log(msg:String) = println(msg)
  }

  class UserService

  def main(args: Array[String]): Unit = {
    val service = new UserService with Logger
    service.log("混入的方法")
  }

14.6 Механизмы построения признаков

Если класс реализует несколько признаков, как создаются эти свойства?

определение

  • Трейты также имеют код конструктора, но, в отличие от классов, трейты не могут иметь параметров конструктора.
  • Каждая черта имеет только **一个无参数** конструктор.
  • Класс наследует другой класс, а также несколько трейтов.При создании экземпляра класса его порядок построения следующий:
    1. Выполнить конструктор родительского класса
    2. 从左到右Выполнить конструктор трейта по очереди
    3. Если у трейта есть родительский трейт, сначала создайте родительский трейт.Если несколько трейтов имеют один и тот же родительский трейт, они будут инициализированы только один раз.
    4. Выполнить конструктор подкласса

Пример

Пример описания

  • Определить несколько трейтов и реализовать их в классе
  • Проверить порядок построения признаков

шаг

  1. Создайте трейт Logger, который печатает «Execute Logger Constructor!» в конструкторе.
  2. Создайте трейт MyLogger, наследуемый от трейта Logger, и напечатайте «Выполнить конструктор MyLogger!» в конструкторе.
  3. Создайте трейт TimeLogger, наследуемый от трейта Logger, и напечатайте «Выполнить конструктор TimeLogger!» в конструкторе.
  4. Создайте класс Person и напечатайте «Execute Person Constructor!» в конструкторе.
  5. Создайте класс Student, наследуйте черты от Person, MyLogger, TimeLogge и напечатайте в конструкторе «Выполнить конструктор Student!»
  6. Добавьте основной метод, создайте экземпляр класса Student_One и посмотрите на результат.

Код ссылки

trait Logger {
    println("执行Logger构造器")
}

trait MyLogger extends Logger {
    println("执行MyLogger构造器")
}

trait TimeLogger extends Logger {
    println("执行TimeLogger构造器")
}

class Person{
    println("执行Person构造器")
}

class Student extends Person with TimeLogger with MyLogger {
    println("执行Student构造器")
}

def main(args: Array[String]): Unit = {
    new Student
}

// 程序运行输出如下:
// 执行Person构造器
// 执行Logger构造器
// 执行TimeLogger构造器
// 执行MyLogger构造器
// 执行Student构造器

14.7 Черты наследуют классы

определение

Трейты также могут наследоваться от классов. Черты наследуют все члены класса.

Пример

Пример описания

  • Определяет признак, который наследуется от класса

шаг

  1. Создайте класс MyUtils и определите метод printMsg.
  2. Создайте трейт Logger, наследуйте от MyUtils и определите метод журнала.
  3. Создайте класс Person и добавьте поле имени
    • Унаследовать черту лесоруба
    • Реализуйте метод sayHello и вызовите метод журнала.
  4. Добавьте основной метод, создайте объект Person и вызовите метод sayHello.

Код ссылки

class MyUtil {
    def printMsg(msg:String) = println(msg)
}

trait Logger extends MyUtil {
    def log(msg:String) = printMsg("Logger:" + msg)
}

class Person extends Logger {
    def sayHello() = log("你好")
}

def main(args: Array[String]): Unit = {
    val person = new Person
    person.sayHello()
}

**

  1. Создайте трейт Logger, который печатает «Execute Logger Constructor!» в конструкторе.
  2. Создайте трейт MyLogger, наследуемый от трейта Logger, и напечатайте «Выполнить конструктор MyLogger!» в конструкторе.
  3. Создайте трейт TimeLogger, наследуемый от трейта Logger, и напечатайте «Выполнить конструктор TimeLogger!» в конструкторе.
  4. Создайте класс Person и напечатайте «Execute Person Constructor!» в конструкторе.
  5. Создайте класс Student, наследуйте черты от Person, MyLogger, TimeLogge и напечатайте в конструкторе «Выполнить конструктор Student!»
  6. Добавьте основной метод, создайте экземпляр класса Student_One и посмотрите на результат.

Код ссылки

trait Logger {
    println("执行Logger构造器")
}

trait MyLogger extends Logger {
    println("执行MyLogger构造器")
}

trait TimeLogger extends Logger {
    println("执行TimeLogger构造器")
}

class Person{
    println("执行Person构造器")
}

class Student extends Person with TimeLogger with MyLogger {
    println("执行Student构造器")
}

def main(args: Array[String]): Unit = {
    new Student
}

// 程序运行输出如下:
// 执行Person构造器
// 执行Logger构造器
// 执行TimeLogger构造器
// 执行MyLogger构造器
// 执行Student构造器

14.7 Черты наследуют классы

определение

Трейты также могут наследоваться от классов. Черты наследуют все члены класса.

Пример

Пример описания

  • Определяет признак, который наследуется от класса

шаг

  1. Создайте класс MyUtils и определите метод printMsg.
  2. Создайте трейт Logger, наследуйте от MyUtils и определите метод журнала.
  3. Создайте класс Person и добавьте поле имени
    • Унаследовать черту лесоруба
    • Реализуйте метод sayHello и вызовите метод журнала.
  4. Добавьте основной метод, создайте объект Person и вызовите метод sayHello.

Код ссылки

class MyUtil {
    def printMsg(msg:String) = println(msg)
}

trait Logger extends MyUtil {
    def log(msg:String) = printMsg("Logger:" + msg)
}

class Person extends Logger {
    def sayHello() = log("你好")
}

def main(args: Array[String]): Unit = {
    val person = new Person
    person.sayHello()
}