2. Class
/* Java */
public class PersonJava {
private final String name;
public PersonJava(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
3. Class
/* Java */
Person person = new Person("myeonginWoo");
System.out.println(person.getName());
8. Property
class Person(firstName: String, lastName: String, age: Int)
class Person2(val firstName: String, val lastName: String, val age: Int)
val person = Person("myeongin", "woo", 32 )
val person2 = Person2("myeongin", "woo", 32 )
9. Property
class Person(firstName: String, lastName: String, age: Int)
class Person2(val firstName: String, val lastName: String, val age: Int)
val person = Person("myeongin", "woo", 32 )
val person2 = Person2("myeongin", "woo", 32 )
println(person.firstName) // Error
println(person2.firstName) // Ok
10. Property
class Person(firstName: String, lastName: String, age: Int)
class Person2(val firstName: String, val lastName: String, val age: Int)
• Java의 class 내부에 선언되는 field와 비슷하지만 다릅니다.
• field는 별도로 getter, setter를 선언해줘야 합니다.
• propertry는 getter와 setter를 자동으로 생성해 줍니다.
• public, private, protected 와 같은 접근제어자만 잘 사용한다면 보일러플레이트들이 많
이 제거되어 실제 로직에 더 집중 할 수 있습니다.
11. Property
/* Java */
public class PersonJava {
String firstNam;
String lastName;
int age;
public PersonJava(String firstName, String lastName, int age) {
this.firstNam = firstName;
this.lastName = lastName;
this.age = age;
}
public String getFirstNam() {
return firstNam;
}
public String getLastName() {
return lastName;
}
public int getAge() {
return age;
}
public void setFirstNam(String firstNam){
this.firstNam = firstNam;
}
public void setLastName(String lastName){
this.lastName = lastName;
}
public void setAge(int age){
this.age = age;
}
12. Property
/* Java */
public class PersonJava {
String firstNam;
String lastName;
int age;
public PersonJava(String firstName, String lastName, int age) {
this.firstNam = firstName;
this.lastName = lastName;
this.age = age;
}
public String getFirstNam() {
return firstNam;
}
public String getLastName() {
return lastName;
}
public int getAge() {
return age;
}
public void setFirstNam(String firstNam){
this.firstNam = firstNam;
}
public void setLastName(String lastName){
this.lastName = lastName;
}
public void setAge(int age){
this.age = age;
}
/* kotlin */
class PersonKotlin(
var firstName: String,
var lastName: String,
var age: Int)
13. Property
class Person {
var name: String = ""
get() = field.toUpperCase()
set(value) {
field = "Name : " + value
}
}
14. Property
class Person {
var name: String = ""
get() = field.toUpperCase()
set(value) {
field = "Name : " + value
}
}
person.name = "test"
15. Property
class Person {
var name: String = ""
get() = field.toUpperCase()
set(value) {
field = "Name : " + value
}
}
person.name = "test"
println(person.name) //NAME : TEST
16. Constructor
class Person(firstName: String, lastName: String, age: Int)
class Person constructor(firstName: String, lastName: String, age: Int)
val person = Person(“myeongin”, “woo”, 32)
17. Constructor
class Person(firstName: String, lastName: String, age: Int)
class Person constructor(firstName: String, lastName: String, age: Int)
val person = Person(“myeongin”, “woo”, 32)
class 이름 뒤에 constructor을 붙이는 것을 primary constructor 이라고 합니다.
기본적으로 생략해도 되지만 어노테이션을 붙여야 할 필요가 있을 경우에는 primary constructor
를 사용하고 constructor 앞에 annotation을 붙입니다.
18. Constructor
class Person(firstName: String, lastName: String, age: Int)
class Person constructor(firstName: String, lastName: String, age: Int)
val person = Person(“myeongin”, “woo”, 32)
class 이름 뒤에 constructor을 붙이는 것을 primary constructor 이라고 합니다.
기본적으로 생략해도 되지만 어노테이션을 붙여야 할 필요가 있을 경우에는 primary constructor
를 사용하고 constructor 앞에 annotation을 붙입니다.
class Persion @Inject constructor(firstName: String, lastName: String, age: Int)
23. Constructor
class Person(val name: String) {
constructor(name: String, parent: Person) : this(name)
}
firstConstructor 호출
Java에서 생성자가 여러개인 경우를 Kotlin 에서는 위와 같이 표현합니다.
24. Data class
/* Java */
public class JavaPerson {
private String firstName;
private String lastName;
private int age;
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
JavaPerson that = (JavaPerson) o;
if (age != that.age) {
return false;
}
if (firstName != null ? !firstName.equals(that.firstName) : that.firstName !=
return false;
}
return lastName != null ? lastName.equals(that.lastName) : that.lastName
}
@Override
public int hashCode() {
int result = firstName != null ? firstName.hashCode() : 0;
result = 31 * result + (lastName != null ? lastName.hashCode() : 0);
result = 31 * result + age;
return result;
}
}
25. Data class
data class dataClassPerson(val firstName: String,
val lastName: String,val age: Int)
26. Data class
/* Kotlin */
class Person(val firstName: String, val lastName: String, val age: Int)
data class DataClassPerson(val firstName: String, val lastName: String,
val age: Int)
27. Data class
/* Kotlin */
class Person(val firstName: String, val lastName: String, val age: Int)
data class DataClassPerson(val firstName: String, val lastName: String,
val age: Int)
val person = Person("myeongin", "woo", 24)
val person2 = Person("myeongin", "woo", 24)
val dataClassPerson = DataClassPerson("myeongin", "woo", 24)
val dataClassPerson2 = DataClassPerson("myeongin", "woo", 24)
28. Data class
/* Kotlin */
class Person(val firstName: String, val lastName: String, val age: Int)
data class DataClassPerson(val firstName: String, val lastName: String,
val age: Int)
val person = Person("myeongin", "woo", 24)
val person2 = Person("myeongin", "woo", 24)
val dataClassPerson = DataClassPerson("myeongin", "woo", 24)
val dataClassPerson2 = DataClassPerson("myeongin", "woo", 24)
println(person == person2) //false
println(dataClassPerson == dataClassPerson2) //true
println(person.toString()) //Main$Person@76ed5528
println(dataClassPerson.toString()) //DataClassPErson(
firstName=myeongin, lastName=woo, age=24)
29. Data class
/* Kotlin */
data class Person(val firstName: String, val lastName: String, val age: Int)
val person = Person("myeongin", "woo", 24)
println(person.component1()) // myeongin
println(person.component2()) // woo
println(person.component3()) // 24
30. Data class
/* Kotlin */
data class Person(val firstName: String, val lastName: String, val age: Int)
val person = Person("myeongin", "woo", 24)
println(person.component1()) // myeongin
println(person.component2()) // woo
println(person.component3()) // 24
val (firstName, lastName, age) = person
31. Data class
/* Kotlin */
data class Person(val firstName: String, val lastName: String, val age: Int)
val person = Person("myeongin", "woo", 24)
println(person.component1()) // myeongin
println(person.component2()) // woo
println(person.component3()) // 24
val (firstName, lastName, age) = person
println(firstName) // myeongin
println(lastName) // woo
println(age) // 24
32. Data class
/* Kotlin */
data class Person(val firstName: String, val lastName: String, val age: Int)
val person = Person("myeongin", "woo", 24)
println(person.component1()) // myeongin
println(person.component2()) // woo
println(person.component3()) // 24
val (firstName, lastName, age) = person
println(firstName) // myeongin
println(lastName) // woo
println(age) // 24
val copyPerson = person.copy(age = 19)
33. Data class
/* Kotlin */
data class Person(val firstName: String, val lastName: String, val age: Int)
val person = Person("myeongin", "woo", 24)
println(person.component1()) // myeongin
println(person.component2()) // woo
println(person.component3()) // 24
val (firstName, lastName, age) = person
println(firstName) // myeongin
println(lastName) // woo
println(age) // 24
val copyPerson = person.copy(age = 19)
println(copyPerson) // Person(firstName=myeongin, lastName=woo, age=19)
34. Data class
• 제약사항
• primary constructor가 있어야 합니다.
• 1개 이상의 파라미터가 있어야 합니다.
• 파라미터는 모두 프로퍼티 이어야 합니다. (val or var)
• abstract, open, sealed, inner 가 아니어야 합니다.
• 장점
• 컴파일러가 equals(), hashCode()를 생성해줍니다.
• toString()을 만들어 줍니다.
• componentN() 함수를 제공합니다. (Destructuring)
• copy() 메소드도 만들어 줍니다.
35. DefaultValue
/* Java */
class JavaPerson {
private JavaPerson(JavaPersonBuilder builder) {
name = builder.name;
age = builder.age;
email = builder.email;
isAdult = builder.isAdult;
}
private String name;
private int age;
private String email;
private boolean isAdult;
public String getName() {
return name;
}
public int getAge() {
return age;
}
public String getEmail() {
return email;
}
public boolean isAdult() {
return isAdult;
}
@Override
public String toString() {
return "name : " + name + ", age : " + age +
", email : " + email + ", isAdult : "+ isAdult;
}
public static class JavaPersonBuilder {
private String name = "Lezhin";
private int age = 3;
private String email = null;
private boolean isAdult = false;
public JavaPersonBuilder setName(String name) {
this.name = name;
return this;
}
public JavaPersonBuilder setAge(int age) {
this.age = age;
return this;
}
public JavaPersonBuilder setEmail(String email) {
this.email = email;
return this;
}
public JavaPersonBuilder setIsAdult(boolean isAdult) {
this.isAdult = isAdult;
return this;
}
public JavaPerson build() {
return new JavaPerson(this);
}
}
}
38. DefaultValue
data class Person(val name: String = "Lezhin", val age: Int = 3,
val email: String? = null, val isAdult: Boolean = false)
val person = Person()
println(person)
39. DefaultValue
data class Person(val name: String = "Lezhin", val age: Int = 3,
val email: String? = null, val isAdult: Boolean = false)
val person = Person()
println(person)
//Person(name=Lezhin, age=3, email=null, isAdult=false)
40. DefaultValue
data class Person(val name: String = "Lezhin", val age: Int = 3,
val email: String? = null, val isAdult: Boolean = false)
val person = Person()
println(person)
//Person(name=Lezhin, age=3, email=null, isAdult=false)
val person2 = Person("myeongin", 32)
println(person2)
41. DefaultValue
data class Person(val name: String = "Lezhin", val age: Int = 3,
val email: String? = null, val isAdult: Boolean = false)
val person = Person()
println(person)
//Person(name=Lezhin, age=3, email=null, isAdult=false)
val person2 = Person("myeongin", 32)
println(person2)
//Person(name=myeongin, age=32, email=null, isAdult=false)
42. DefaultValue
data class Person(val name: String = "Lezhin", val age: Int = 3,
val email: String? = null, val isAdult: Boolean = false)
val person = Person()
println(person)
//Person(name=Lezhin, age=3, email=null, isAdult=false)
val person2 = Person("myeongin", 32)
println(person2)
//Person(name=myeongin, age=32, email=null, isAdult=false)
val person3 = Person(age=32, isAdult = true)
println(person3)
43. DefaultValue
data class Person(val name: String = "Lezhin", val age: Int = 3,
val email: String? = null, val isAdult: Boolean = false)
val person = Person()
println(person)
//Person(name=Lezhin, age=3, email=null, isAdult=false)
val person2 = Person("myeongin", 32)
println(person2)
//Person(name=myeongin, age=32, email=null, isAdult=false)
val person3 = Person(age=32, isAdult = true)
println(person3)
//Person(name=Lezhin, age=32, email=null, isAdult=true)
46. Class(enum)
enum class Color(val rgb: Int) {
RED(0xFF0000),
GREEN(0x00FF00),
BLUE(0x0000FF)
}
val green: Color = Color.GREEN
val red: Color = Color.valueOf("RED")
val colorList: Array<Color> = Color.values()
47. Class(inheritance)
enum class ProtocolState {
WAITING {
override fun signal() = TALKING
},
TALKING {
override fun signal() = WAITING
};
abstract fun signal(): ProtocolState
}
49. Class(inheritance)
• Kotlin의 class는 기본적으로 final 입니다.
• final class는 상속이 되지 않습니다.
• override 할 메소드에는 override 키워드를 붙여줍니다.(Java의
@Override와 동일)
50. Class(inheritance)
• Kotlin의 class는 기본적으로 final 입니다.
• final class는 상속이 되지 않습니다.
• override 할 메소드에는 override 키워드를 붙여줍니다.(Java의
@Override와 동일)
• 상속 가능한 class를 만드려면 open, abstract키워드를 사용합
니다.
• open과 abstract 모두 자바의 abstract와 비슷합니다.
• open class는 instance를 생성 할 수 있지만 abstract class는
instance를 생성 할 수 없습니다.
51. Class(open)
open class Foo {
open val x: Int get { ... }
}
class Bar1 : Foo() {
override val x: Int = ...
}
52. Class(open)
open class Foo {
open val x: Int get { ... }
}
class Bar1 : Foo() {
override val x: Int = ...
}
• property 도 override가 가능합니다.
53. Class(open)
open class Base {
open fun v() {}
fun nv() {}
}
class Derived() : Base() {
override fun v() {}
}
54. Class(open)
open class Base {
open fun v() {}
fun nv() {}
}
class Derived() : Base() {
override fun v() {}
}
• open이 없는 property와 function은 final 이기 때문에
override 할 수 없습니다.
55. Class(open)
interface Foo {
val count: Int
}
class Bar1(override val count: Int) : Foo
class Bar2 : Foo {
override var count = 0
}
56. Class(open)
interface Foo {
val count: Int
}
class Bar1(override val count: Int) : Foo
class Bar2 : Foo {
override var count = 0
}
• val 을 var 로도 override 할 수 있습니다. 반대는 안됩니다.
61. Interface
interface say {
fun hello()
}
class Person(val name: String, val age: Int) : Say{
override fun hello() {
println("Hello")
}
}
62. Interface
interface say {
fun hello()
fun hi() { println("Hi") }
}
class Person(val name: String, val age: Int) : Say{
override fun hello() {
println("Hello")
}
}
63. Interface
• Kotlin은 Interface의 body도 구현 가능합니다.
interface say {
fun hello()
fun hi() { println("Hi") }
}
class Person(val name: String, val age: Int) : Say{
override fun hello() {
println("Hello")
}
}
64. Interface
interface Korean {
fun hello() { println("안녕") }
}
interface Newyorker {
fun hello() { println("Hello")}
}
class Person(val name: String, val age: Int) : Korean, Newyorker {
override fun hello() {
super<Korean>.hello()
super<Newyorker>.hello()
}
}
65. Interface
• Kotlin은 서로 다른 interface들이 같은 method 정의 및 구현
이 가능하며, 각각 호출 할 수 있습니다.
interface Korean {
fun hello() { println("안녕") }
}
interface Newyorker {
fun hello() { println("Hello")}
}
class Person(val name: String, val age: Int) : Korean, Newyorker {
override fun hello() {
super<Korean>.hello()
super<Newyorker>.hello()
}
}
66. Class(sealed)
/* Sealed classes */
sealed class Expr
data class Const(val number: Double) : Expr()
data class Sum(val e1: Expr, val e2: Expr) : Expr()
object NotANumber : Expr()
67. Class(sealed)
• enum class와 매우 유사합니다.
• enum은 각 object들이 같은 생성자와 같은 함수들을 갖지만, sealed
class는 object의 hierarchies 제한만 갖고 별도의 생성자와 프로퍼티를 갖
을 수 있습니다.
/* Sealed classes */
sealed class Expr
data class Const(val number: Double) : Expr()
data class Sum(val e1: Expr, val e2: Expr) : Expr()
object NotANumber : Expr()
68. Class(sealed)
/* Interface */
interface Expr
data class Const(val number: Double) : Expr
data class Sum(val e1: Expr, val e2: Expr) : Expr
object NotANumber : Expr
/* Sealed classes */
sealed class Expr
data class Const(val number: Double) : Expr()
data class Sum(val e1: Expr, val e2: Expr) : Expr()
object NotANumber : Expr()
69. Class(sealed)
• interface 로도 같은 효과를 낼 수 있습니다.
/* Interface */
interface Expr
data class Const(val number: Double) : Expr
data class Sum(val e1: Expr, val e2: Expr) : Expr
object NotANumber : Expr
/* Sealed classes */
sealed class Expr
data class Const(val number: Double) : Expr()
data class Sum(val e1: Expr, val e2: Expr) : Expr()
object NotANumber : Expr()
70. Class(sealed)
/* Sealed classes */
fun eval(expr: Expr): Double = when(expr) {
is Const -> expr.number
is Sum -> eval(expr.e1) + eval(expr.e2)
NotANumber -> Double.NaN
}
71. Class(sealed)
/* Sealed classes */
fun eval(expr: Expr): Double = when(expr) {
is Const -> expr.number
is Sum -> eval(expr.e1) + eval(expr.e2)
NotANumber -> Double.NaN
}
/* interface */
fun eval(expr: Expr): Double = when(expr) {
is Const -> expr.number
is Sum -> eval(expr.e1) + eval(expr.e2)
NotANumber -> Double.NaN
else -> throw IllegalArgumentException("error")
}
72. Class(sealed)
/* Sealed classes */
fun eval(expr: Expr): Double = when(expr) {
is Const -> expr.number
is Sum -> eval(expr.e1) + eval(expr.e2)
NotANumber -> Double.NaN
// the `else` clause is not required because we've covered all the cases
}
/* interface */
fun eval(expr: Expr): Double = when(expr) {
is Const -> expr.number
is Sum -> eval(expr.e1) + eval(expr.e2)
NotANumber -> Double.NaN
else -> throw IllegalArgumentException("error")
// the `else` clause is not required because we've covered all the cases
}
• 비슷한 효과를 낼 수 있지만 when 표현식을 사용할 때 else를 작성 하냐 마냐 하는 차이가 있습니다.
• Sealed나 enum 을 사용 하게 되면 case 들이 명확해집니다. 따라서 생각 하지 않은 케이스(사전에 정의하지 않은 케이스
)를 사전에 방지해 주고, 사전에 정의한 case 에 대해 실수로 인한 누락을 컴파일 타임에 잡아줍니다. 즉 훨씬 안전하고
명확한 코딩을 할 수 있습니다.