Курс по дисциплине "Разработка оконных приложений", с использованием ЯП Kotlin и библиотеки JavaFX
Более подробно тут:
fun main(args: Array<String>){
println("Hello Kotlin")
}
Byte, Short, Int, Long, Float, Double - всё довольно стандартно
Стоит отметить тип any
var name: Any = "42"
name = 42
Any
- базовый тип данных
val a: Int = 42;
var b = 0.0;
a = -42 //error
b = 42.0
val - неизменяемая переменная
var - изменяемая
if(a == b)
println("a == b")
else
println("a != b")
может работать как тернарный оператор
val c = if (a > b){
a
} else {
b
}
val a = 10
when(a){
10 -> println("a = 10")
20 -> println("a = 20")
else -> println("неопределенное значение")
}
так же может работать как аналог тернарного оператора + может быть не только с константами и ренджами
val rate = when(sum){
in 100..999 -> 10
in 1000..9999 -> 15
else -> 20
}
for(n in 1..9){
print("${n} \t")
}
for - может быть только через итераторы
В принципе можно спокойно написать свой For
inline fun <T> For(it : Iterator<T>, cb : (T) -> Unit) {
while (it.hasNext()) cb(it.next())
}
fun main() {
For(list.iterator()) {
println(it)
}
}
Синтаксис позволяет вынести определение лямбды за скобку.
while - аналогичен c++
while(i > 0){
println(i*i)
i--;
}
var range = 1..10
range = "a".."z"
range = 10 downTo 0
range = 10 downTo 0 step 2
if (1 in range) {
print("Yey")
}
val numbers: Array<Int> = arrayOf(1, 2, 3, 4, 5)
val numbers2 = Array(3, {5}) // [5, 5, 5]
//2D array
val table: Array<Array<Int>> = Array(3, { Array(5, {0}) })
val arr: Array<String> = arrayOf("1", "2", "3")
for(elem in arr){
println(elem)
}
fun funName(param1: type1, param2: type2, ...) : returnType {
code
}
fun displayUser(name: String, age: Int = 18, position: String="unemployed"){
println("Name: $name Age: $age Position: $position")
}
displayUser(age=21, name="Alice")
vararg
- ключевое слово, для передачи переменного количества параметров одного типа
fun sum(vararg numbers: Int){
var result=0
for(n in numbers)
result += n
println("Сумма чисел равна $result")
}
Если параметров много, то vararg
- должен быть последним
(Это можно нарушить, если после vararg-параметра идут еще какие-нибудь параметры, то при вызове функции значения этим параметрам передаются через именованные аргументы)
Помагает распаковать массив для передачи его как параметр vararg
fun printUserGroup(group: String, vararg users: String, count:Int){
println("Count: $count")
for(user in users)
println(user)
}
fun main(args: Array<String>) {
val users = arrayOf("Tom", "Bob", "Alice")
printUserGroup("MO-011", *users, count=3)
}
Возвращение значение из функции осуществляется с помощью оператора return
fun fun42() : Int{
return 42
}
Забавный факт, если функция ничего не возвращает, то ее тип возвращаемого значения - Uint
Однострочные функции (single expression function) используют сокращенный синтаксис определения функции в виде одного выражения. Эта форма позволяет опустить возвращаемый тип и оператор return.
fun pow2(x: Int) : Int = x * x
fun check(num: Int): Boolean{
fun pow2(num: Int) = num*num
return pow2(num) > 100
}
fun add(a: Int, b: Int) : Int{
return a + b
}
fun add(a: Double, b: Double) : Double{
return a + b
}
Важно в kotlin
при перегрузке не учитывает возвращаемый результат функции
Лямбда-выражения представляют небольшие кусочки кода, которые выполняют некоторые действия. Фактически лямбды преставляют сокращенную запись функций. При этом лямбды могут передаваться в качестве параметра в функции.
val printer = {message: String -> println(message)}
val summer = {a: Int, b: Int -> a+b}
val summerAndPrinter = {x:Int, y:Int ->
val result = x + y
println("$x + $y = $result")
result
}
Анонимные функции выглядят как обычные за тем исключением, что они не имеют имени.
fun(x: Int): x+x
fun(x: Int, y: Int): Int{
return x + y
}
Зачем нам и лямбды и анонимные функции??
fun loop(list: List<Element>): Boolean {
list.forEach { element ->
if (!element.process()) return false // returns from loop()
}
return true
}
fun loop(list: List<Element>): Boolean {
list.forEach { element ->
if (!element.process()) return@forEach // returns from forEach
}
return true
}
fun loop(list: List<Element>): Boolean {
list.forEach(fun(element) {
if (!element.process()) return false // returns from forEach
})
return true
}
Для чего они нужны? Да чтобы их в функции передавать))
Функции высокого порядка (high order function) - это функции, которые либо принимают функцию в качестве параметра, либо возвращают функцию, либо и то, и другое.
fun action (n1: Int, n2: Int, operation: (Int, Int)-> Int){
val result = operation(n1, n2)
println(result)
}
fun selectAction(key: Int): (Int, Int) -> Int{
// определение возвращаемого результата
when(key){
1 -> return {x:Int, y: Int -> x + y}
2 -> return {x:Int, y: Int -> x - y}
3 -> return {x:Int, y: Int -> x * y}
else -> return {x:Int, y: Int -> 0}
}
}
Ключевое слово inline - сообщит компилятору, что мы хотим, чтобы код этой функции подставлялся в месте её вызова.
inline fun pow(i: Int): Int {
return i*i
}
Класс создается с использованием ключевого слова class
class ClassName {
val a = 10
fun getA() : Int{
return a
}
}
...
val obj: ClassName = ClassName()
В Kotlin
классы могут содержать ряд компонентов:
- конструкторы и инициализаторы
- функции
- свойства
- вложенные классы
- объявления объектов
class Class constructor(param: Int, param2: String) {
val p1: String
val p2: Int
init {
p1 = param2
p2 = param
}
//Дополнительный конструктор
constructor(param: Int) : this(param, ""){
p2 = param
}
}
class Name {
companion object {
@JvmStatic
fun main(args: Array<String>) {
launch(GUI1::class.java)
}
}
}
Как Вы могли заметить раньше, обчно в качестве точки входа используется fun main()
, но можно сделать в стиде java
статичную функцию main
В котлин нет статик методов, но есть вспомогательные объекты.
private
: классы, объекты, интерфейсы, а также функции и свойства, определенные вне класса, с этим модификатором видны только в том файле, в котором они определены. Члены класса с этим модификатором видны только в рамках своего классаprotected
: члены класса с этим модификатором видны в классе, в котором они определены, и в классах-наследникахinternal
: классы, объекты, интерфейсы, функции, свойства, конструкторы с этим модификатором видны в любой части модуля, в котором они определены. Модуль представляет набор файлов Kotlin, скомпилированных вместе в одну структурную единицу. Это может быть модуль IntelliJ IDEA или проект Mavenpublic
: классы, функции, свойства, объекты, интерфейсы с этим модификатором видны в любой части программы. (При этом если функции или классы с этим модификатором определены в другом пакете их все равно нужно импортировать)
По умолчанию всё - public
Чтобы функциональность класса можно было унаследовать, необходимо определить для этого класса аннотацию open
В kotlin
нет множественного наследования!
super
- доступ к базовому классу
open class Person(val name: String) {
open fun display(){
println("Base")
}
}
class Employee: Person{
constructor(name: String) : super(name){
}
override fun display() {
println("Name: $name")
}
}
Для каждого свойства можно определять геттер и сеттер.
class Person{
val name: String
get() {
return "Name: $name Age: $age"
}
set(value){
if(value != "")
field = value
}
}
Идентификатор field представляет автоматически генерируемое поле, которое непосредственно хранит значение свойства.
Интерфейсы представляют контракт, который должен реализовать класс. Интерфейсы могут содержать объявления свойств и функций, а также их реализацию по умолчанию.
Можно наследоваться от нескольких интерфейсов
interface Movable{
fun move() // определение функции без реализации
fun stop(){ // определение функции с реализацией по умолчанию
println("Остановка")
}
}
class Car : Movable{
override fun move(){
println("Машина едет")
}
}
Абстрактные классы - это классы, определенные с модификатором abstract. Отличительной особенностью абстрактных классов является то, что мы не можем создать объект подобного класса.
val kate: Human // можем инициализировать классом наследникои
val alice: Human = Human("Alice") // ошибка
Абстрактные классы могут иметь абстрактные методы. Это такие функции, которые определяются с ключевым словом abstract и не содержат реализацию, то есть у них нет тела. При этом абстрактные методы можно определить только в абстрактных классах.
Абстрактные классы могут иметь собственную реализацию методов.
Для моздания enum класса используется ключевое слово enum
.
Enum можно наследовать от интерфейсов.
interface Printable{
fun printName()
}
enum class DayTime: Printable{
DAY{
override fun printName(){
println("День")
}
},
NIGHT{
override fun printName(){
println("Ночь")
}
}
}
Одна из ключевых фишек Kotlin - проверка на null во время компиляции.
Ключевое слово null
представляет специальный литерал, который указывает, что переменная не имеет как такового значения.
Для присвоения типу null
, нужно чтобы этот тип был Nullable, для этого нужно добавить ?
к типу.
val a : Int = null //ошибка
val a : Int? = null
Позволяет получить альтернативное занченик в случае, если переменная null
var name : String? = "Tom"
val firstName: String = name ?: "Undefined" // если name = null, то присваивается "Undefined"
позволяет объединить проверку значения объекта на null и выполнение функции этого объекта
val name : String? = "Tom"
val length: Int? = name?.length
Если name - null
, то length - null
, иначе length = name.length
Оператор !! (not-null assertion operator) принимает один операнд. Если операнд равен null, то генерируется исключение
val name : String? = null
val length :Int = name!!.length