Каталог статей
- Знакомьтесь, Котлин
- основная концепция
- поток управления
- аномальный
- классы и объекты
- интерфейс
Знакомьтесь, Котлин
Как и язык 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, которые имеют разные размеры и обеспечивают хранение чисел с плавающей запятой двух разных точности:
- Для переменных, инициализированных десятичными знаками, компилятор определяет
Double
тип:
val pi = 3.14 // Double
// val one: Double = 1 // 错误:类型不匹配
val oneDouble = 1.0 //Double
- Чтобы явно указать значение как
Float
тип, добавьтеf
илиF
суффикс, и такое значение будет округлено, если оно содержит более 6–7 десятичных цифр:
val e = 2.7182818284 // Double
val eFloat = 2.7182818284f // Float,实际值为 2.7182817
- В отличие от других языков,Числа в 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
цикл
для
- используйте
in
ключевые слова - использовать нижний индекс
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()
, то естьСуть вторичного конструктора заключается в вызове первичного конструктора
Реализуйте следующие две подструктуры:
- Построение трех параметров, имя, возраст, номер, разряд не передает параметры, по умолчанию 0.
- Конструкция без параметров: 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
, и другие.equal
toString
Следующая реализация 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)}")
}