Обучение Kotlin (1) основные понятия, типы объектов данных, поток управления, проверка нулевых значений, классы и интерфейсы

Каталог статей

Знакомьтесь, Котлин

вставьте сюда описание изображения
Как и язык Java, Kotlin компилируется в байт-код и запускается на виртуальной машине JVM. Возможности языка Kotlin зависят от компилятора синтаксиса Kotlin. Языки, похожие на котлин:

  • Scala: язык разработки больших данных
  • Groovy: язык динамических сценариев, основанный на платформе JVM.Используется в разработке Android для написания зависимостей, плагинов и т. д.

В 2019 году Google объявил, что Kotlin стал первым языком разработки для Android, и программисты Android неизбежно перейдут с Java на Kotlin.

кроссплатформенные функции

тип языка

Языки делятся на интерпретируемые и компилируемые:

  • Скомпилированный язык, компилятор по одному скомпилирует исходный код в двоичный файл, и компьютер может выполнить его напрямую, напримерC和C++
    • Преимущества: его можно запустить после компиляции, во время выполнения компиляция не требуется, эффективность высокая.
    • Недостатки: разные операционные системы требуют разных машинных кодов, а изменение кода требует перекомпиляции модуль за модулем.
  • Интерпретируемый язык: при запуске программы интерпретатор будет анализировать исходный код построчно в двоичный код в реальном времени и выполнять его, например, на соответствующей виртуальной машине.JS、Python
    • Преимущества: Платформа имеет хорошую совместимость и может работать после установки соответствующей виртуальной машины.
    • Недостатки: его необходимо интерпретировать и выполнять во время выполнения, эффективность низкая.

тип языка Java

Java — это наполовину скомпилированный и наполовину интерпретируемый гибридный язык, но он более интерпретируемый.

Java сначала компилирует исходную программу в независимый от платформы байт-код Java (.class) с помощью компилятора javac, а затем интерпретирует и выполняет байт-код с помощью JVM.

Как работает котлин

JVM отвечает только за интерпретацию и выполнение файла байт-кода file.class, независимо от того, как генерируется файл байт-кода. Kotlin основан на этом принципе. Перед запуском он компилируется в класс, а затем запускается виртуальной машиной Java.

Kotlin不仅能够,还能脱离虚拟机层,直接编译成可以在Windows、Linux和MacOS平台上运行的原生二进制代码,被称为Android领域的Swift

Привет, мир

Точкой входа в приложение Kotlin является основная функция main, которая не может принимать никаких параметров и не возвращать никаких значений.

fun main() {
    
    
    var str:String = "Hello World"
    println(str)
}

основная концепция

вход в программу

Не может быть никаких параметров или списка параметров, но запись программы не имеет возвращаемого значения.

fun main() {
    
    
}

fun main(args: Array<String>) {
    
    
}

Типы данных и объектов

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

== и ===

Котлин предоставляет два способа сравнения объектов

  • сравнивать структуры объектов на предмет равенства ( ==или equals)
  • Сравните ссылки на объекты на предмет равенства===
fun main() {
    
    
//sampleStart
    val a: Int = 100
    val boxedA: Int? = a
    val anotherBoxedA: Int? = a

    val b: Int = 10000
    val boxedB: Int? = b
    val anotherBoxedB: Int? = b

    println(boxedA === anotherBoxedA) // true
    println(boxedB === anotherBoxedB) // false
//sampleEnd
}

Поскольку JVM применяет оптимизацию памяти к целым числам от -128 до 127 (целое число), все ссылки, допускающие значение NULL, на самом деле являются одним и тем же объектом. Но к b не применяется никакая оптимизация памяти, поэтому это разные объекты ( ===результат ложный).

С другой стороны, их содержимое по-прежнему одинаково:

fun main() {
    
    
//sampleStart
    val b: Int = 10000
    println(b == b) // 输出“true”
    val boxedB: Int? = b
    val anotherBoxedB: Int? = b
    println(boxedB == anotherBoxedB) // 输出“true”
//sampleEnd
}

явное преобразование чисел

Меньшие типы в Kotlin не могут быть неявно преобразованы в более крупные типы, а это означает, что присвоение Byteтипа Intпеременной должно быть явно преобразовано:

fun main() {
    
    
	val b : Byte = 1

	val i1: Int = b.toInt();
}

Все числовые типы поддерживают преобразование в другие типы:

  • toByte(): Байт
  • toShort(): Короткий
  • toInt(): Целое
  • toLong(): Длинный
  • toFloat(): Плавать
  • toDouble(): Двойной

Во многих случаях явное преобразование типов не требуется, поскольку тип будет выведен из контекста, а арифметическая операция будет перегружена для выполнения соответствующего преобразования, например:

val l = 1L + 3 // Long + Int => Long

тип с плавающей запятой

Kotlin предоставляет типы с плавающей запятой. Типы Float и Double, которые имеют разные размеры и обеспечивают хранение чисел с плавающей запятой двух разных точности:
вставьте сюда описание изображения

  1. Для переменных, инициализированных десятичными знаками, компилятор определяет Doubleтип:
val pi = 3.14  // Double
// val one: Double = 1 // 错误:类型不匹配
val oneDouble = 1.0 //Double
  1. Чтобы явно указать значение как Floatтип, добавьте fили Fсуффикс, и такое значение будет округлено, если оно содержит более 6–7 десятичных цифр:
val e = 2.7182818284 // Double
val eFloat = 2.7182818284f // Float,实际值为 2.7182817
  1. В отличие от других языков,Числа в Kotlin не имеют неявных расширяющих преобразований, например, функции с параметрами Double можно вызывать только для значений Double, а не для Float, Int или других числовых значений.:
fun main() {
    
    
    fun printDouble(d: Double) {
    
     print(d) }

    val i = 1    
    val d = 1.0
    val f = 1.0f 

    printDouble(d)
//    printDouble(i) // 错误:类型不匹配
//    printDouble(f) // 错误:类型不匹配
}

битовая операция

Kotlin предоставляет набор побитовых операций для целочисленных типов Intи .Long

  • shl(биты) – сдвиг влево со знаком (сдвиг влево)
  • shr(биты) – сдвиг вправо со знаком (сдвиг вправо)
  • ushr(биты) – беззнаковый сдвиг вправо
  • and(bits) – бит и
  • or(bits) – биты или
  • xor(bits) – исключающий бит или
  • inv() – побитовая инверсия

Любой

Any — это корневой тип непустого типа, аналогичный Object как верхнему уровню иерархии классов Java. Когда Any类型是Kotlin中所有非空类型的超类。Any используется в функции Kotlin, он будет скомпилирован в Object в байт-коде Java.

Any?类型是Kotlin所有类型的根类
В самом низу иерархии типов Kotlin находится тип Nothing. Схема структуры типов выглядит следующим образом:
вставьте сюда описание изображения

Единица

UnitФункция аналогична функции в Java void, но смысл void в том, что нет возвращаемого значения. Котлин более тщательно разбирается с объектами. Возвращаемое значение без возвращаемого значения также должно быть объектом, поэтому существует Unit. Если эта концепция Не указано
явно returnвозвращаемое значение, то компилятор автоматически добавит возвращаемое значение Unit:

fun returnUnit() : Unit {
    
    
	return Unit
}

Ничего

UnitСмысл этой функции – отсутствие возвращаемого значения.
Однако NothingэтоПодскажите разработчику, что эта функция не вернет результат, например 可能是抛异常, не возвращается, или拥有无限循环的函数。

Функция 1: возвращаемое значение функции, которая генерирует исключение.

fun throwOnNameNull() : Nothing {
    
    
	throw NullPointerException("姓名不能为空!")
}

Помимо использования исключения, описанного выше, объект ==Nothing также является общим подтипом всех типов объектов. == Таким образом, Nothing на самом деле является множественным наследованием, то есть правила наследования расширены в Kotlin, 类不允许多重继承,Nothing除外поскольку конструктор Nothing является частным, у него не будет никаких объектов-экземпляров, поэтому его множественное наследование не принесет какого-либо реального риска. .

Учитывая тот факт, что Nothing является подклассом всех типов, его можно комбинировать с дженериками для создания общего пустого списка следующим образом:

вставьте сюда описание изображения
Функция 2: В качестве общего пустого временного заполнения для общих переменных.

Функция 3: Ничто не делает Kotlin более полным на грамматическом уровне.

В базовой логике котлина throw имеет возвращаемое значение, а тип возвращаемого значения — Nothing,
поэтому следующая запись допустима:

val nothing: Nothing = throw RuntimeException("抛异常!"

Поскольку Nothing является подклассом всех типов, работает все следующее:

var _name: String? = null
val name: String = _name ?:throw NullPointerException("_name 运行时不能为空!")

объявить переменную

Kotlin использует ключевые слова varдля объявления переменных-переменных, а имя переменной и тип переменной разделяются :двоеточием.Этот язык сценариев, как и Python, не требует ;окончания.

вставьте сюда описание изображения
var: переменная переменная, соответствующая 非finaпеременной l в Java.

var b = 1

val: Неизменяемые переменные, соответствующие finalпеременным Java.

val a = 1

В приведенном выше процессе объявления не используется двоеточие :для обозначения типа, поскольку в Kotlin имеется механизм создания классов, указанная выше aсумма bбудет считаться по умолчанию в соответствии с результатом присваивания.Int

Переменная только для чтения val и изменяемая переменная var

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

В основном разница между нефинальным и финальным.

Просмотр байт-кода Котлина

вставьте сюда описание изображения

развлечение (метод/функция)

Ключевое слово fun используется для объявления методов:
Ниже приведен метод, который принимает 2 параметра Int и возвращает Int.

fun sum(a: Int, b: Int): Int {
    
    
	return a + b;
}

Тело метода может быть выражением, возвращаемое значение которого можно вывести:

fun sum (a: Int, b: Int) = a + b 

Метод может не иметь возвращаемого значения или возвращать бессмысленное значение (Unit).

fun printSum(a: Int, b:Int): Unit {
    
    
	println("sum of $a and $b is ${
      
      a + b}")
}

Среди них Unit также можно игнорировать;

fun printSum(a: Int, b:Int) {
    
    
	println("sum of $a and $b is ${
      
      a + b}")
}

Значения параметров функции по умолчанию

Kotlin поддерживает функции со значениями по умолчанию, которые используются следующим образом:

fun main() {
    
    
	myPrint(1)
	myPrint(1, "lalala")
}

fun myPrint(value : Int, str : String = "hello") {
    
    
	println("num is $value, str is $str")
}

Если значение хочет быть значением по умолчанию, оно будет сохранено, поскольку первый переданный параметр должен иметь тип Int. Тип входящей строки не будет соответствовать:

fun main() {
    
    
    myPrint("zjm")//报错
}

fun myPrint(value: Int = 100, str: String) {
    
    
    println("num is $value, str is $str")
}

Передача параметров функции в Котлине поддерживает ту же передачу параметров пары ключ-значение, что и в Python, поэтому порядок параметров можно изменить:

fun main() {
    
    
    myPrint(str = "zjm") //正确调用
}

fun myPrint(value: Int = 100, str: String) {
    
    
    println("num is $value, str is $str")
}

класс (класс)

Определить
класс. Атрибуты класса можно поместить в определение или внутри класса, например:

class Rectangle(var height: Double, var length: Double) {
    
    
	var perimeter = (height + length) * 2
}

var rectangle = Rectangle(5.0, 2.0)
println("The perimeter is ${
      
      rectangle.perimeter}")

Для Kotlin версии 1.4.30 наследование класса :представлено двоеточием.Класс по умолчанию является окончательным и не может быть унаследован.Чтобы сделать класс наследуемым, используйте openключевые слова и поместите их перед классом:

open class Rectangle(var height: Double, var length: Double) {
    
    
	var perimeter = (height + length) * 2
}

$(шаблон строки)

Используя $шаблоны, которые могут помочь определить строки, перевести строковые переменные.
Для непосредственного использования переменных $и использования выражений необходимы фигурные скобки.${}

Ниже приведен пример:

var a = 1
val S1 = "a is $a"
println(S1)
a = 2;
val S2 = "${
      
      S1.replace("is", "was")}, but now is $a"
println(S2)

результат:

a is 1
a was 1, but now is 2

поток управления

if-else (условное выражение)

fun getMax(a: Int, b: Int): Int {
    
    
	if (a > b) {
    
    
		return a
	} else {
    
    
		return b
	}
}

Вышеуказанное if также можно записать в виде выражения, аналогичного тернарному оператору:

fun getMax(a: Int, b: Int) = if (a > b) a else b

цикл

для

  1. используйте inключевые слова
  2. использовать нижний индекс
val items = listof("apple", "banana", "kiwifruit")
for (item in items) {
    
    
	println(item)
}

for (index in item.indices) {
    
    
	println("item at $index is ${
      
      items[index]}")
}
// 闭区间打印[1, 3]
// 输出 1,2,3
for (i in 1..3) {
    
    
	println(i)
}
// 从7到0,降序,步长为2
// 输出 7,5,3,1
for (i in 7 downTo 0 step 2) {
    
    
	println(i)
}

for- inДиапазон по умолчанию – это диапазон с двойным закрытием. Если вы хотите использовать диапазон с закрытием слева и открытием справа, вам необходимо использовать ключевые словаuntil

fun main() {
    
    
	for (i in 0 until 10) {
    
    
		
	}
}

пока

val items = listOf("apple", "banana", "kiwifruit")
var index = 0
while (index < items.size) {
    
    
    println("item at $index is ${
      
      items[index++]}")
}

результат:

item at 0 is apple
item at 1 is banana
item at 2 is kiwifruit

когда выражение

когда выражение немного похоже на смену регистра в Java.

fun describe(obj: Any): String = 
	when (obj) {
    
    
		1 -> "One"
		"Hello" -> "Greeting"
		is Long -> "Long"
		!is String -> "Not a String"
		else -> "Unknown"
	}

аномальный

Класс исключения Throwable

Все классы исключений в Kotlin наследуются от классов и генерируют исключения Throwableс помощью выражений:throw

fun main() {
    
    
//sampleStart
    throw Exception("Hi There!")
//sampleEnd
}

Используйте выражения try...catch для перехвата исключений:

try {
    
    
    // 一些代码
} catch (e: SomeException) {
    
    
    // 处理程序
} finally {
    
    
    // 可选的 finally 块
}

Блоков catch может быть ноль или более, и, наконец, блоки могут быть опущены. Но требуется хотя бы один захват и, наконец, блок.

Нулевые значения и проверки нулевых значений

Переменная, которая может иметь значение NULL, требует после себя знака вопроса ?.
Например, метод ниже возвращает Int или null

fun parseInt(str: String) : Int? {
    
    
	...
}

оператор безопасного звонка?.

Этот оператор позволяет объединить проверку на нулевое значение и вызов метода в одну операцию. Например

s?.toUpperCase()

Эквивалентно следующему написанию:

if (s!=null) {
    
    
	s.toUpperCase
} else {
    
    
	null
}

Безопасные вызовы можно использовать не только для вызова методов, но и для доступа к свойствам.

Если в вашем объекте есть несколько свойств типов, допускающих значение NULL, часто бывает удобно использовать несколько безопасных вызовов в одном и том же выражении. Используя этот оператор, вы можете получить доступ к более глубоким свойствам в одной строке кода без дополнительных проверок. следующее:

class Address(val streetAddress:String,val code:Int,val city:String)
class Company(val name:String,val address: Address?)
class Person(val name:String,val company: Company?)

fun Person.cityName():String{
    
    
    val city = this.company?.address?.city
    return if (city != null) city else "unKnown"
}

Оператор Элвиса?:

Оператор Элвиса принимает два операнда, и если первый операнд не равен нулю, результатом операции является первый операнд, в противном случае результатом операции является второй операнд.
Например, ниже, если s не пусто, str равно s, в противном случае str — пустой строковый объект.

fun foo(s: String) {
    
    
	val str: String = s?:""
}

Оператор Элвиса часто используется с оператором безопасного вызова для замены значения NULL, возвращаемого путем вызова метода для объекта NULL со значением. Давайте упростим предыдущий код:

fun Person.cityName():String {
    
    
	val city = this.company?.address?.city
	return city ?: "unKnown"
}

В котлине есть сцена, где оператор Элвиса очень подходит.Операции типа return и throw на самом деле являются выражениями, поэтому их можно записать в правой части оператора Элвиса. Если значение слева от оператора равно нулю, функция немедленно генерирует исключение.

fun printPersonName(person : Person) {
    
    
	val name = person.name? : throw IllegalArgumetException("no name")
	println(name)
}

Следите за конверсиейas?

как и оператор Kotlin, используемый для преобразования типов, как и типов Java, если преобразуемое значение не является типом, который вы пытаетесь преобразовать. Будет выброшено ClassCastException.

as?оператор пытается преобразовать значение в указанный тип,Возвращает ноль, если значение не относится к соответствующему типу. мы можемИспользуйте этот оператор с Элвисом, например реализация метода равенства класса Person

class Person(val name:String, val company: Company?) {
    
    
	override fun equals(other: Any?): Boolean {
    
    
		val otherPerson = other as? Person ?: return false
		return otherPerson.name && other.company == company
	}
}

ненулевое утверждение!!

Ненулевое утверждение — это самый простой и прямой инструмент, предоставляемый Kotlin для работы со значениями типа, допускающими значение NULL. Используйте двойные восклицательные знаки, чтобы указать, что любое значение можно преобразовать в тип, отличный от NULL. Исключение будет выдано, если для нулевого значения будет сделано ненулевое утверждение.

fun ignoreNull(s:String){
    
    
    val notNull = s!!
    println(notNull.length)
}

Если s в этой функции имеет значение null, во время выполнения будет выдано исключение. Местом, где выдается исключение, является строка, в которой делается утверждение о ненулевом значении, а не строка, в которой значение затем пытается быть использовано.

Поскольку информация трассировки стека вызовов исключений показывает только, на какой строке произошло исключение,!!Чтобы сделать информацию трассировки более явной, избегайте нескольких утверждений в одной и той же строке в конце .

пусть функционирует

Функция let упрощает работу с выражениями, допускающими значение NULL. При использовании вместе с оператором безопасного вызова она позволяет оценить выражение, проверить, является ли результат нулевым, и сохранить результат в переменной, причем все это в одном и том же месте. простое выражение.

Функция let превращает вызывающий ее объект в параметр лямбда-выражения. В сочетании с синтаксисом безопасного вызова она может эффективно преобразовать объект, допускающий значение NULL, который вызывает функцию let, в тип, отличный от NULL. Другими словами, функция let превращает вызывающий ее объект в параметр лямбда-выражения. ,Let, вызов которого безопасен, будет выполнять лямбду только в том случае, если выражение не равно нулю.

s?.let {
    
     
    print(s.length)
}

Если вы хотите добиться вышеуказанного эффекта, код Java выглядит следующим образом:

public static final void ignoreNull(@Nullable String s) {
    
    
	if (s != null) {
    
    
		System.out.print(s.length());
	}
}

lateinit Свойства ленивой инициализации

Kotlin обычно требует, чтобы все свойства были инициализированы в конструкторе. Если свойство является ненулевым свойством, необходимо указать ненулевое значение инициализации, в противном случае необходимо использовать тип, допускающий значение NULL. Если это сделано, свойство требует или утверждает каждый раз, когда к нему null检查обращаются !!.

class MyService {
    
    
	fun performAction():String = "foo"
}

class MyTest{
    
    
	private var myService:MyService?=null
	
	fun test() {
    
    
		myService!!.performAction()
	}
}

Его можно использовать lateinitдля задержки инициализации myService.Все свойства отложенной инициализации — var.Хотя это непустой тип, его не нужно инициализировать в конструкторе.

class MyService{
    
    
    fun performAction():String = "foo"
}

class MyTest{
    
    
    // 声明一个不需要初始化器的非空类型的属性
    private lateinit var myService:MyService

    fun test(){
    
    
        myService.performAction()
    }
}

Расширение типа, допускающее значение NULL

Стандартная библиотека Kotlin определяет две функции расширения String isEmpty, isBlank
isNullOrBlankчтобы определить, является ли это пустой строкой или содержит только пустые символы.Эта функция расширения может позволить вызывать получателя как null:

fun  verifyInput(input:String?){
    
    
    if (input.isNullOrBlank()){
    
    
        print("it is not ok")
    }
}

Безопасный доступ не требуется, поскольку возможные нулевые значения обрабатываются внутри функции:

@kotlin.internal.InlineOnly
public inline fun CharSequence?.isNullOrBlank(): Boolean {
    
    
    contract {
    
    
        returns(false) implies (this@isNullOrBlank != null)
    }

    return this == null || this.isBlank()
}

Обнуляемость параметров типа

Параметры типа всех универсальных классов и универсальных функций в Kotlin по умолчанию имеют значение NULL, и в этом случае значение NULL допускается для объявлений, которые используют параметры типа в качестве типов, даже если параметр типа T не заканчивается вопросительным знаком.

fun <T> printSomething(t:T){
    
    
    // 因为 t 可能为 null,所以必须使用安全调用
    print(t?.hashCode())
}
// 传入 null 进行调用
printSomething(null)

В этом методе выведенный тип параметра типа T является типом, допускающим значение NULL, Any?, поэтому фактический параметр t по-прежнему допускает значение NULL, даже если он не заканчивается вопросительным знаком.

Если параметр типа не равен NULL, вы должны указать для него ненулевую верхнюю границу, чтобы дженерики отклоняли значения, допускающие значение NULL, как фактические параметры.

// 这样的话,T 就不是可空的
fun <T:Any> printSomething1(t:T){
    
    
    print(t.hashCode())
}

это: проверка типов и автоматическое преобразование

Он используетсяis для проверки принадлежности объекта к определенному типу.Если тип неизменяемой переменной определен, то при ее дальнейшем использовании явное преобразование не требуется:

fun getStringLength(obj: Any): Int? {
    
    
	if (obj is String) {
    
    
		// 这里obj已经转为String类型
		return obj.length
	}
	return null
}

Или !isнапишите наоборот:

fun getStringLength(obj: Any): Int? {
    
    
	if (obj !is String) return null

	return obj.length
}

классы и объекты

Создайте класс Person:

class Person {
    
    
	var name = ""
	var age = 0
	fun printInfo() {
    
    
		println("name is $name, age is $age")
	}
}

наследовать

Класс по умолчанию в Kotlin не наследуется (то есть он модифицируется финалом).Если вы хотите, чтобы этот класс наследовался, вам нужно classиспользовать openключевое слово перед ним.

open class Person {
    
    
	var name = ""
	var age = 0
	fun printInfo() {
    
    
		println("name is $name, age is $age")
	}
}

Объявите класс Student для наследования от класса Person. В котлине наследование использует :конструкцию родительского класса:

class Student : Person() {
    
    
	var number = ""
	var grade = 0
	fun study() {
    
    
		println("$name is studying")
	}
}

состав

Структура разделена на основную структуру и вторичную структуру.

основная структура

Основная конструкция пишется сразу после класса.

class Student(val number: String, val grade: Int) : Person() {
    
    
	fun study() {
    
    
		println("$name is studying")
	}
}

Создайте объект Student:

val student = Student("1234", 90)

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

open class Person(val name : String, val age : Int) {
    
    
	fun printInfo() {
    
    
		println("name is $name, age is $age")
	}
}

В этот момент Student сообщает об ошибке, поскольку при наследовании Person конструкция без аргументов Person() используется позже, а выше мы изменили конструкцию без аргументов Person, поэтому конструкция без аргументов отсутствует.

class Student(name: String,  age: Int, val number: String, val grade: Int) : Person(name, age){
    
    
	fun study() {
    
    
		println("$name is studying")
	}
}

В это время создайте класс Student;

val student = Student("zjm", 20, "1234", 90)

Что делать, если строительство требует особого подхода? Kotlin предоставляет initструктуру, и логика основной структуры может обрабатываться в init, например:

open class Person(val name : String, val age : Int) {
    
    
	init {
    
    
		println("name is $name")
		println("age is $age")
	}
}

Все вышеперечисленные модификации таковы 主构造: что, если классу потребуется несколько конструкций? Нужна помощь в это время次构造

вторичная структура

Вторичная конструкция: constructorдля объявления конструктора используйте ключевое слово, :за которым следует this(), то естьСуть вторичного конструктора заключается в вызове первичного конструктора
Реализуйте следующие две подструктуры:

  1. Построение трех параметров, имя, возраст, номер, разряд не передает параметры, по умолчанию 0.
  2. Конструкция без параметров: Int по умолчанию имеет значение 0, String по умолчанию — пустая строка.
class Student(name: String,  age: Int, var number: String, var grade: Int) : Person(name, age){
    
    
    fun study() {
    
    
        println("$name is studying")
    }
    constructor(name: String, age: Int, number: String) : this(name, age, number, 0) {
    
    

    }
    
    constructor() : this("", 0, "", 0) {
    
    
        
    }
}

// 调用
val student = Student("lzy", 23, "1234", 90)
val student1 = Student("lzy", 23, "121");
val student2 = Student()

модификатор разрешения

Разница между Java и котлином следующая:
вставьте сюда описание изображения
введен котлин internal, заброшенdefault

Классы данных и одноэлементные классы

класс данных

Класс данных имеет дело только с данными, связанными с данными, и Java Beanобычно должен реализовывать свои методы get, set, hashcode, и другие.equaltoString

Следующая реализация UserBeanвключает в себя: id, name, pwdатрибуты.
Джава:

public class UserBean {
    
    
    private String id;
    private String name;
    private String pwd;

    public UserBean() {
    
    

    }

    public UserBean(String id, String name, String pwd) {
    
    
        this.id = id;
        this.name = name;
        this.pwd = pwd;
    }

    @Override
    public boolean equals(Object o) {
    
    
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        UserBean userBean = (UserBean) o;
        return Objects.equals(id, userBean.id) && Objects.equals(name, userBean.name) && Objects.equals(pwd, userBean.pwd);
    }

    @Override
    public int hashCode() {
    
    
        return Objects.hash(id, name, pwd);
    }

    @Override
    public String toString() {
    
    
        return "UserBean{" +
                "id='" + id + '\'' +
                ", name='" + name + '\'' +
                ", pwd='" + pwd + '\'' +
                '}';
    }

    public String getId() {
    
    
        return id;
    }

    public void setId(String id) {
    
    
        this.id = id;
    }

    public String getName() {
    
    
        return name;
    }

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

    public String getPwd() {
    
    
        return pwd;
    }

    public void setPwd(String pwd) {
    
    
        this.pwd = pwd;
    }
}

Написать этот класс на Kotlin станет очень просто: создайте новый ktфайл и выберите следующее:
вставьте сюда описание изображения
можно написать одну строку кода, и котлин автоматически реализует описанный выше метод.
Дважды щелкните Shift, чтобы вызвать 工具搜索, выполнить поиск show kotlin ByteCodeи просмотреть байт-код Kotlin:
соответствующий класс Java Bean действительно создан.
вставьте сюда описание изображения

одноэлементный класс

В настоящее время наиболее широко используемый одноэлементный режим (статический внутренний класс) в Java реализован следующим образом:

public class SingleInstance {
    
    
	private SingleInstance() {
    
    
	}
	private static class SingleHolder {
    
    
		private static final SingleInstance INSTANCE = new SingleInstance();
	}

	public static SingleInstance getInstance() {
    
    
		return SingleHolder.INSTANCE;
	}
	public void test() {
    
    
	}
}

KotlinЧтобы создать одноэлементный класс в , вам необходимо выбрать сгенерированный Object
вставьте сюда описание изображения
код следующим образом:

object SingleInstance {
    
    
	fun test () {
    
    
	}
}

Соответствующие javaфайлы следующие: они аналогичны вышеупомянутой наиболее часто используемой javaреализации синглтона:

public final class Singleton {
    
    
   @NotNull
   public static final Singleton INSTANCE;

   public final void test() {
    
    
   }

   private Singleton() {
    
    
   }

   static {
    
    
      Singleton var0 = new Singleton();
      INSTANCE = var0;
   }
}

Используйте следующим образом:

fun main() {
    
    
    Singleton.test() //对应的java代码为Singleton.INSTANCE.test();
}

класс перечисления

Самый простой сценарий применения класса перечисления — реализация типобезопасного перечисления:

enum class Direction {
    
    
    NORTH, SOUTH, WEST, EAST
}

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

Поскольку каждое перечисление является экземпляром класса перечисления, его можно инициализировать следующим образом:

enum class Color(val rgb: Int) {
    
    
    RED(0xFF0000),
    GREEN(0x00FF00),
    BLUE(0x0000FF)
}

Каждая константа перечисления также имеет эти два свойства: имя и порядковый номер, позволяющие получить ее имя и позицию (от 0) в объявлении класса перечисления:

enum class RGB {
    
     RED, GREEN, BLUE }

fun main() {
    
    
    //sampleStart
    println(RGB.RED.name) // prints RED
    println(RGB.RED.ordinal) // prints 0
    //sampleEnd
}

Запечатанный класс запечатанный

Определите интерфейс результата:

interface Result 
class Success(val msg: String) : Result
class Failure(val msg: String) : Result

Определите метод:

fun getResultMsg(result: Result) = when(result) {
    
    
    is Success -> result.msg
    is Failure -> result.error.message
    else -> throw IllegalArgumentException()
}

Из-за особенностей Kotlin необходимо написать else, но приведенный выше код возможен только в двух случаях, иначе он просто избыточен. Если программист пренебрегает передачей класса UnKown, приложение выйдет из строя.

Чтобы решить вышеуказанные проблемы, необходимо полагаться на sealedзапечатанный класс, а его подклассы могут быть определены только на верхнем уровне одного и того же файла и не могут быть вложены в другие классы.

sealed class Result
class Success(val msg: String) : Result()
class Failure(val error: Exception) : Result()
fun getResultMsg(result: Result) = when(result) {
    
    
    is Success -> result.msg
    is Failure -> result.error.message
}

интерфейс

Определите интерфейс:

interface Study {
    
    
    fun study()
    fun readBooks()
    fun doHomeWork()
    fun exercise()
}

наследование интерфейса

Унаследованный интерфейс нужно использовать только за классом ,и реализовывать Studyвсе объявленные функции:

class GoodStudent(name: String, age: Int, var ID: String, var grade: Int) : Person(name, age) , Study{
    
    
    override fun study() {
    
    
        TODO("Not yet implemented")
    }

    override fun readBooks() {
    
    
        TODO("Not yet implemented")
    }

    override fun doHomeWork() {
    
    
        TODO("Not yet implemented")
    }

    override fun exercise() {
    
    
        TODO("Not yet implemented")
    }

}

Kotlin поддерживает реализацию методов интерфейса по умолчанию, а позднее JDK1.8 также поддерживает эту функцию. Если метод имеет реализацию по умолчанию, унаследованный класс не обязан реализовывать этот метод.

interface Study {
    
    
    fun study() {
    
    
        println("study")
    }
    fun readBooks()
    fun doHomework()
}

разрешить конфликты наложения

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

interface A {
    
    
    fun foo() {
    
     print("A") }
    fun bar()
}

interface B {
    
    
    fun foo() {
    
     print("B") }
    fun bar() {
    
     print("bar") }
}

class C : A {
    
    
    override fun bar() {
    
     print("bar") }
}

class D : A, B {
    
    
    override fun foo() {
    
    
        super<A>.foo()
        super<B>.foo()
    }

    override fun bar() {
    
    
        super<B>.bar()
    }
}

В приведенном выше примере интерфейсы A и B определяют методы foo() и bar(). Оба реализуют foo(), но только B реализует bar() (bar() не помечен как абстрактный в A, поскольку по умолчанию он является абстрактным, когда в интерфейсе нет тела метода). Теперь, если вы реализуете конкретный класс C из A, вы должны переопределить bar() и реализовать этот абстрактный метод.

Однако если вы наследуете D от A и B, вам необходимо реализовать все методы, унаследованные от нескольких интерфейсов, и указать, как D должен их реализовать. Это правило применимо как к методам, наследующим одну реализацию ( bar() ), так и к методам, наследующим несколько реализаций ( foo() ).

Функциональный интерфейс (SAM) Интерфейс

Интерфейс только с одним абстрактным методом называется функциональным интерфейсом или интерфейсом одного абстрактного метода (SAM). Функциональный интерфейс может иметь несколько неабстрактных членов, но только один абстрактный член.

Например, есть такой функциональный интерфейс Kotlin:

fun interface IntPredicate {
    
    
   fun accept(i: Int): Boolean
}

Если вы не используете преобразование SAM, вам нужно написать такой код:

// 创建一个类的实例
val isEven = object : IntPredicate {
    
    
   override fun accept(i: Int): Boolean {
    
    
       return i % 2 == 0
   }
}

Воспользовавшись преимуществами преобразования SAM в Kotlin, вместо этого можно изменить следующий эквивалентный код:

fun interface IntPredicate {
    
    
   fun accept(i: Int): Boolean
}

val isEven = IntPredicate {
    
     it % 2 == 0 }

fun main() {
    
    
   println("Is 7 even? - ${
      
      isEven.accept(7)}")
}

Supongo que te gusta

Origin blog.csdn.net/baiduwaimai/article/details/131101935
Recomendado
Clasificación