Scala: объектно-ориентированный, объект, абстрактные классы, внутренние классы, черта
цель обучения
- Освойте использование классов и объектов scala
- Освоить использование наследования
- Научитесь использовать черты
1. Классы и объекты
Scala является объектно-ориентированным и имеет концепцию классов и объектов. Мы по-прежнему можем разрабатывать объектно-ориентированные приложения на основе языка scala.
1.1 Создание классов и объектов
использование
- использовать
class
определить класс - использовать
new
создавать объекты
Пример
Создайте класс Person и создайте его объект
шаг
- Создайте проект scala и создайте объект
- добавить основной метод
- Создание классов и объектов
выполнить
- Создайте проект в IDEA и создайте объект (основной метод должен быть помещен в объект)
- добавить основной метод
- Создайте класс человека
- Создайте объект класса 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
для определения переменных-членов - Объекты используют имена переменных-членов напрямую для доступа к переменным-членам.
Пример
- Определите класс Person с полем имени и возраста
- Создайте объект с именем «Чжансан» в возрасте 20 лет.
- напечатать имя и возраст объекта
шаг
- Создайте объект и добавьте основной метод
- Создайте класс Person, добавьте поле имени и поле возраста, инициализируйте поля и позвольте scala автоматически выполнять вывод типа.
- Создайте объект класса Person в основном методе и установите для переменных-членов значение «Чжан Сан», 20
- напечатать имя и возраст объекта
Код ссылки
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
Переменные-члены типа должны быть вручную инициализированы сами по себе
Пример
- Определите класс Person с полем имени и возраста
- Создайте объект с именем «Чжансан» в возрасте 20 лет.
- напечатать имя и возраст объекта
шаг
- Создайте объект и добавьте основной метод
- Создайте класс Person, добавьте поле имени и поле возраста, укажите тип данных, инициализируйте символом подчеркивания.
- Создайте объект класса Person в основном методе и установите для переменных-членов значение «Чжан Сан», 20
- напечатать имя и возраст объекта
Код ссылки
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
для определения методов-членов
Пример
-
Создайте класс клиентов
-
Создайте объект этого класса и вызовите метод printHello
шаг
- Создайте объект и добавьте основной метод
- Создайте класс Customer, добавьте переменные-члены и методы-члены.
- Создайте объект класса Customer в основном методе и установите значение переменной-члена (Чжан Сан, мужчина)
- вызов метода члена
Код ссылки
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
-
Создайте объект класса в основном методе и проверьте, можно ли получить доступ к закрытым членам.
Код ссылки
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 добавляется, чтобы указать, что переменные-члены определяются непосредственно через основной конструктор.
- Список параметров конструктора может указывать значения по умолчанию
- Создайте экземпляр и вызовите конструктор, чтобы указать поля для инициализации
- Код во всем классе, за исключением определений полей и определений методов, является кодом построения.
Пример
- Определите класс Person, определите поля имени и возраста через список параметров основного конструктора и установите их значения по умолчанию.
- Вывод «Вызвать главный конструктор» в главном конструкторе
- Создайте объект "Чжан Сан" (имя Чжан Сан, возраст 20 лет), напечатайте имя и возраст объекта.
- Создайте «пустой» объект, не передавайте конструктору никаких параметров, напечатайте имя и возраст объекта.
- Создайте объект «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.
-
Создайте экземпляр объекта класса 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. Типовая оценка
Иногда мы разрабатываем программы для выполнения соответствующей логики в зависимости от типа переменных.
В 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 Определения
Если член класса не полностью определен в текущем классе, этоабстрактный класс
Возможны два случая неполного определения:
- Методы не имеют тела (абстрактный метод)
- Переменная не инициализирована (абстрактное поле)
Определение абстрактного класса такое же, как в Java, добавление перед классомabstractключевые слова
// 定义抽象类
abstract class 抽象类名 {
// 定义抽象字段
val 抽象字段名:类型
// 定义抽象方法
def 方法名(参数:参数类型,参数:参数类型...):返回类型
}
12.2 Абстрактные методы
Пример
- Разработайте 4 класса для представления отношения наследования на приведенном выше рисунке.
- Каждая фигура имеет свой собственный метод нахождения площади, но разные фигуры имеют разные методы вычисления площади.
шаг
- Создайте абстрактный класс Shape и добавьте абстрактный метод площади для вычисления площади.
- Создайте класс Square Square, унаследованный от Shape, он имеет основной конструктор для длины стороны и реализует метод расчета площади.
- Создайте класс прямоугольника, наследуемый от Shape, который имеет главный конструктор для длины и ширины и реализует метод вычисления площади
- Создайте класс круга, наследуемый от Shape, он имеет основной конструктор для радиуса и реализует метод для вычисления площади.
- Напишите основной метод для создания квадратных, прямоугольных и круглых объектов соответственно и распечатайте их площадь.
Код ссылки
// 创建形状抽象类
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 抽象字段:类型
}
Пример
Пример описания
- Создайте абстрактный класс Person с абстрактным полем String WHO_AM_I.
- Создайте класс Student, наследуйте от класса Person, перепишите поле WHO_AM_I и инициализируйте его как ученика.
- Создайте класс Policeman, наследуйте от класса Person, перепишите поле WHO_AM_I и инициализируйте полицию.
- Добавьте основной метод, создайте экземпляры 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 类/抽象类 {
// 重写方法
}
Пример
Пример описания
- Создайте абстрактный класс Person и добавьте абстрактный метод sayHello.
- Добавьте основной метод для реализации Person, создав анонимный внутренний класс.
- Метод 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.
Пример | Наследование одного признака
Пример описания
- Создайте трейт Logger и добавьте абстрактный метод журнала, который принимает параметр String.
- Создайте класс ConsoleLogger, наследуйте трейт Logger, реализуйте метод журнала и печатайте сообщения.
- Добавьте основной метод, создайте объект 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("这是一条日志")
}
Пример | Наследование нескольких признаков
Пример описания
- Создайте трейт MessageSender и добавьте метод отправки
- Создайте трейт MessageReceiver и добавьте метод получения
- Создайте MessageWorker, который реализует эти две черты.
- Вызывается в основном, вызывает метод отправки и метод получения соответственно
Код ссылки
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())
}
Пример | Объект наследует трейт
Пример описания
- Создайте трейт Logger и добавьте абстрактный метод журнала.
- Создайте объект ConsoleLogger, реализуйте трейт LoggerForObject, реализуйте метод журнала и распечатайте сообщение.
- Напишите основной метод и вызовите метод журнала 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 Определение конкретных методов
Подобно классам, трейты также могут определять определенные методы.
Пример
Пример описания
- Определите трейт Logger и добавьте метод реализации журнала.
- Определите класс UserService, реализующий трейт Logger.
- Добавьте метод добавления, который печатает «Добавить пользователя».
- добавить основной метод
- Создайте экземпляр объекта 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 Определение конкретных полей и абстрактных полей в признаках
определение
-
Конкретные поля и абстрактные поля могут быть определены в трейтах.
-
Подклассы, которые наследуют признак, автоматически имеют поля, определенные в признаке.
-
Поля добавляются непосредственно в подклассы
Пример
Пример описания
Реализовать инструмент вывода лога через трейт, который может автоматически добавлять дату лога
шаг
- Создайте трейт Logger
- Определите поле SimpleDateFormat для форматирования даты (отображаемой во времени)
- Определите абстрактное поле TYPE для определения выходной информации.
- Создайте абстрактный метод журнала для вывода журналов
- Создайте класс ConsoleLogger, реализуйте абстрактное поле TYPE и метод журнала.
- добавить основной метод
- Создайте объект класса 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 特质
Пример
- датьобъектдобавить дополнительное поведение
шаг
- Создайте трейт Logger
- Добавьте метод реализации журнала для печати параметров
- Создайте класс UserService
- добавить основной метод
- Создайте объект 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 Механизмы построения признаков
Если класс реализует несколько признаков, как создаются эти свойства?
определение
- Трейты также имеют код конструктора, но, в отличие от классов, трейты не могут иметь параметров конструктора.
- Каждая черта имеет только **
一个无参数
** конструктор. - Класс наследует другой класс, а также несколько трейтов.При создании экземпляра класса его порядок построения следующий:
- Выполнить конструктор родительского класса
-
从左到右
Выполнить конструктор трейта по очереди - Если у трейта есть родительский трейт, сначала создайте родительский трейт.Если несколько трейтов имеют один и тот же родительский трейт, они будут инициализированы только один раз.
- Выполнить конструктор подкласса
Пример
Пример описания
- Определить несколько трейтов и реализовать их в классе
- Проверить порядок построения признаков
шаг
- Создайте трейт Logger, который печатает «Execute Logger Constructor!» в конструкторе.
- Создайте трейт MyLogger, наследуемый от трейта Logger, и напечатайте «Выполнить конструктор MyLogger!» в конструкторе.
- Создайте трейт TimeLogger, наследуемый от трейта Logger, и напечатайте «Выполнить конструктор TimeLogger!» в конструкторе.
- Создайте класс Person и напечатайте «Execute Person Constructor!» в конструкторе.
- Создайте класс Student, наследуйте черты от Person, MyLogger, TimeLogge и напечатайте в конструкторе «Выполнить конструктор Student!»
- Добавьте основной метод, создайте экземпляр класса 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 Черты наследуют классы
определение
Трейты также могут наследоваться от классов. Черты наследуют все члены класса.
Пример
Пример описания
- Определяет признак, который наследуется от класса
шаг
- Создайте класс MyUtils и определите метод printMsg.
- Создайте трейт Logger, наследуйте от MyUtils и определите метод журнала.
- Создайте класс Person и добавьте поле имени
- Унаследовать черту лесоруба
- Реализуйте метод sayHello и вызовите метод журнала.
- Добавьте основной метод, создайте объект 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()
}
**
- Создайте трейт Logger, который печатает «Execute Logger Constructor!» в конструкторе.
- Создайте трейт MyLogger, наследуемый от трейта Logger, и напечатайте «Выполнить конструктор MyLogger!» в конструкторе.
- Создайте трейт TimeLogger, наследуемый от трейта Logger, и напечатайте «Выполнить конструктор TimeLogger!» в конструкторе.
- Создайте класс Person и напечатайте «Execute Person Constructor!» в конструкторе.
- Создайте класс Student, наследуйте черты от Person, MyLogger, TimeLogge и напечатайте в конструкторе «Выполнить конструктор Student!»
- Добавьте основной метод, создайте экземпляр класса 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 Черты наследуют классы
определение
Трейты также могут наследоваться от классов. Черты наследуют все члены класса.
Пример
Пример описания
- Определяет признак, который наследуется от класса
шаг
- Создайте класс MyUtils и определите метод printMsg.
- Создайте трейт Logger, наследуйте от MyUtils и определите метод журнала.
- Создайте класс Person и добавьте поле имени
- Унаследовать черту лесоруба
- Реализуйте метод sayHello и вызовите метод журнала.
- Добавьте основной метод, создайте объект 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()
}