일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- 플레이 콘솔 프로덕션
- Dialog
- Exposed Drop-Down Menu
- 플레이스토어 앱 게시 문제
- android studio
- Kotlin
- Retrofit
- Callback
- 비동기
- Bottom sheet
- 공유 기능
- 앱 출시
- 안드로이드 http
- 앱개발
- 안드로이드스튜디오
- 안드로이드 api
- 안드로이드 스튜디오
- android api
- urlconnection
- Today
- Total
Strong 감자의 공부
Ch_07 클래스 관계 등 추가 사항 알아보기 본문
-목차
1. 속성과 메서드 재정의
2. 특정 자료를 다루는 클래스 알아보기
1. 속성과 메서드 재정의
🔶 1.1 속성 정의
⚫ 속성의 메서드 세터를 비공개 처리하기
특정 속성의 변경 제한을 처리하려면 속성의 세터 메서드를 private 처리한다.
아래 코드는 ++을 어디에 두느냐에 따라 getter호출 수가 다르다.
책 예제의 get호출되는 수가 예상과 달라서 ++과 print문을 옮겨가며 찍어봤다.
fun main() {
val counter = Counter()
for (i in 1..2) {
counter.inc()
println(counter.value)
}
}
class Counter {
var value: Int = 0
get() {
println("get value $field")
return field
}
private set // 값 수정은 비공개 처리 -> 클래스 안 메서드로 접근
fun inc() = ++value // value값 가져올때 1, 더해서 return시 2, 위에서 println 할때 또 get 3
}
// 결과값
get value 0
get value 1
get value 1
1
get value 1
get value 2
get value 2
2
아래는 디컴파일 한 것이다.
// ExpKt.java
public final class ExpKt {
public static final void main() {
Counter counter = new Counter();
int var1 = 1;
for(byte var2 = 2; var1 <= var2; ++var1) {
counter.inc();
int var3 = counter.getValue();
System.out.println(var3);
}
}
// $FF: synthetic method
public static void main(String[] var0) {
main();
}
}
// Counter.java
public final class Counter {
private int value;
public final int getValue() {
String var1 = "get value " + this.value;
System.out.println(var1);
return this.value;
}
public final int inc() {
this.value = this.getValue() + 1;
return this.getValue();
}
}
fun main() {
val counter = Counter()
for (i in 1..2) {
counter.inc()
println(counter.value)
}
}
class Counter {
var value: Int = 0
get() {
println("get value $field")
return field
}
private set // 값 수정은 비공개 처리 -> 클래스 안 메서드로 접근
fun inc() = value++ // 더해서 return시 1, 위에서 print 2
}
// 결과값
get value 0
get value 1
1
get value 1
get value 2
2
아래는 디컴파일 한 것이다.
// ExpKt.java
public final class ExpKt {
public static final void main() {
Counter counter = new Counter();
int var1 = 1;
for(byte var2 = 2; var1 <= var2; ++var1) {
counter.inc();
int var3 = counter.getValue();
System.out.println(var3);
}
}
// $FF: synthetic method
public static void main(String[] var0) {
main();
}
}
// Counter.java
public final class Counter {
private int value;
public final int getValue() {
String var1 = "get value " + this.value;
System.out.println(var1);
return this.value;
}
public final int inc() {
int var1;
this.value = (var1 = this.getValue()) + 1;
return var1; // var1++이라 var1을 return
}
}
아래는 책에 있는 예제이다.
fun main() {
val counter = Counter()
for (i in 1..2) {
counter.inc()
}
println(counter.value)
}
class Counter {
var value: Int = 0
get() {
println("get value $field")
return field
}
private set // 값 수정은 비공개 처리 -> 클래스 안 메서드로 접근
fun inc() = value++
}
// 결과값
get value 0 // inc
get value 1 // inc
get value 2 // print 할 때 접근
2 // print(valuea)
⚫ 배킹핑드 사용하지 않기
class Thing(val name: String)
class Container(private val maxCapacity: Int) {
private val things = mutableListOf<Thing>()
val capacity: Int
get() = maxCapacity - things.size
val isFull: Boolean
get() = things.size == maxCapacity
fun put(thing: Thing): Boolean =
if (isFull) false
else {
things += thing // 삽입
true
}
fun take(): Thing = things.removeAt(0)
fun query(): List<String> = things.map { it.name }
}
fun main() {
var container = Container(3)
container.put(Thing("침대"))
container.put(Thing("의자"))
container.put(Thing("받침대"))
println(container.isFull)
println(container.query())
println(container.take().name)
println(container.query())
}
// 결과값
true
[침대, 의자, 받침대]
침대
[의자, 받침대]
🔶 1.2 연산자 오버로딩
⚫ 연산자 오버로딩 처리 규직
1. operator fun 으로 작성
2. 클래스 내부의 메서드나 확장함수로 정의 가능
3. 메서드나 함수의 오버로딩 규칙에 따라 매개변수의 개수나 자료형이 다르면 여러개 정의 가능
⚫ 아래는 오버로딩 규칙에 따라 두개의 plus 메서드를 정의한 예이다.
fun main() {
val amt01 = Amount(200, 100)
val amt02 = Amount(300, 100)
val amt03 = amt01 + amt02
val amt04 = amt02 + 100
println(amt03) // Amount(500, 200)
println(amt04) // Amount(400, 200)
}
class Amount(var total: Int, var balance: Int) {
operator fun plus(other: Amount) = Amount(
this.total + other.total,
this.balance + other.balance
)
operator fun plus(scale: Int) = Amount(this.total + scale, this.balance + scale)
override fun toString(): String = "Amount($total, $balance)"
}
⚫ 확장함수 연산자 오버로딩
class Amount(var total: Int, var balance: Int) {
operator fun plus(other: Amount) = Amount(
this.total + other.total,
this.balance + other.balance
)
operator fun plus(scale: Int) = Amount(this.total + scale, this.balance + scale)
override fun toString(): String = "Amount($total, $balance)"
}
// 확장함수 연산자 오버로딩
operator fun Amount.times(other: Amount): Amount {
// 타 클래스안 메서드처럼 리시버클래스 안 속성 접근이 가능하다.
return Amount(total * other.total, balance * other.balance)
}
fun main() {
val amt01 = Amount(200, 100)
val amt02 = Amount(300, 100)
val amt05 = amt01 * amt02
print(amt05) // Amount(60000, 10000)
}
⚫infix 처리
1. infix fun 처럼 함수나 메서드 정의시 맨 앞에 둔다.
2. 매개변수가 1개여야 한다.
2. 매개변수에 초기값을 지정할 수 없다.
fun main() {
val a = Add(100)
println(a add 20)
println(a.add(200))
println(a times 200)
println(a * 200)
println(a div 200)
// 결과값
120
300
20000
20000
0
}
class Add(var x: Int = 0) {
infix fun add(y: Int) = x + y
infix operator fun times(y: Int) = x * y
infix fun divide(y: Int) = x / y
}
infix fun Add.div(y: Int) = this.divide(y) // 확장함수에 infix 지정하기
🔶 1.3 메서드 재정의
⚫ 메서드 재정의 규칙
1. method overload : 클래스 안에 동일한 이름의 메서드를 여러개 정의. 매개변수의 개수, 자료형에 따라 다르게 처리
2. method override : 클래스 상속관계에서 슈퍼클래스의 메서드를 서브클래스 메서드에 동일한 이름과 매개변수로 정의.
- 서브클래스에서 추가로 기능을 재정의 가능. 항상 서브클래스가 먼저 참조되고 없으면 슈퍼클래스의 메서드 검색.
- 서브클래스에서 앞으로의 재정의를 막을려면 "final override fun 메서드이름" 처럼 쓴다.
- 부모클래스에 있는 것을 재정의 할 때, 부모클래스꺼엔 open을 붙이고, 자식클래스에선 override를 붙인다.
- 부모클래스에 있는 속성들은 기본이 final이라 open을 붙이지 않으면 재정의 할 수 없다.
open class Person(var name: String = "돌자반", var food: String = "치킨") {
fun eat() {
println("$name 은 굽네를 먹는다.")
}
open fun sleep() {
println("$name 은 오늘도 일찍 일어난다.")
}
}
class Student(name: String) : Person("감자", "설렁탕") {
override fun sleep() {
println("$name 은 늦게 일어났다...뽈")
}
fun activity() {
println("$name 신나게 $food 먹는다")
}
fun doAll() {
eat()
sleep()
activity()
}
}
fun main() {
var st = Student("돌자르르르ㅡ반")
st.doAll()
// 결과값
감자 은 굽네를 먹는다.
감자 은 늦게 일어났다...뽈
감자 신나게 설렁탕 먹는다
}
2. 특정 자료를 다루는 클래스 알아보기(데이터, 이넘 클래스)
🔶 데이터 클래스
클래스일 때 == 객체끼리 연산이 false
fun main() {
val p1 = Person("감자")
val p2 = Person("감자")
println(p1)
println(p2)
println(p1 == p2)
println(p1 === p2)
// 결과값
Person@27d6c5e0
Person@4f3f5b24
false
false
}
class Person(name: String)
데이터 클래스 일 때 == 연산이 true
fun main() {
val p1 = Person("감자")
val p2 = Person("감자")
println(p1)
println(p2)
println(p1 == p2)
println(p1 === p2)
// 결과값
Person(name=감자)
Person(name=감자)
true
false
}
data class Person(val name: String)
💛 데이터 클래스는 주생성자에 정의된 속성값이 같으면 동일한 값의 객체로 본다. 즉 주생성자의 속성 값이 같을 때 == 연산시 true가 반환된다.
데이터 클래스가 상속 받더라도 값이 같은지(==)의 기준은 데이터 클래스의 주생성자이다.
🔶 2.2 이넘 클래스 -> kotlin 1.9.0 에서는 entries 추천
⚫ 이넘 클래스 작성법
1. enum class 이렇게 작성한다.
2. 생성할 객체를 모두 내부에 정의하고 객체의 이름을 상수처럼 사용하고 대문자로 작성해야한다.
fun main() {
println(Card.PLATINUM.ordinal) // 객체 순서번호 출력
println(Card.PLATINUM.name) // 객체 이름 출력
println(Card.GOLD < Card.SIVER) // 객체 간 순서 비교
// 결과값
2
Card.PLATINUM
false
}
enum class Card {
SIVER, GOLD, PLATINUM // 0번, 1번, 2번 순서
}
웬만하면 oridinary를 쓰지 않는다. 새로운 값이 들어왔을 때 순서가 바뀌기 때문
순서가 필요하다면 속성을 추가하자.
3. 이넘 클래스에 속성 추가
import java.awt.Color.orange
import java.awt.Color.red
fun main() {
println(Card.PLATINUM.color) // 내부 속성 조회
println(Card.valueOf("GOLD")) // 객체 있는지 조회
val type = enumValueOf<Card>("GOLD") // GOLD 검색
println(type)
println(Card.PLATINUM.name)
println(Card.PLATINUM.color)
// 결과값 1
orange
Card.GOLD
Card.GOLD
Card.PLATINUM
orange
val array1 = Card.values() // Array타입
array1.forEach { println("${it.name}=${it.color}") }
// 결과값 2
Card.SIVER =red
Card.GOLD =gold
Card.PLATINUM =orange
val array2 = enumValues<Card>() // Array타입
array2.forEach { println("${it.name}=${it.color}") }
// 결과값 3
Card.SIVER =red
Card.GOLD =gold
PLATINUM=orange
array2.filter { it.color == "red" }.map { it.color }.forEach { println(it) }
// 결과값 4
red
}
enum class Card(var color: String) {
SIVER("red"), GOLD("gold"), PLATINUM("orange") // 0번, 1번, 2번 순서
}
4. 이넘 클래스에 동반객체를 작성할 수 있다. -> 메서드를 클래스 이름으로 바로 접근 가능
fun main() {
for (i in Card.getIter()) {
println(i)
}
}
// 결과값
SIVER
GOLD
PLATINUM
enum class Card(var color: String) {
SIVER("red"), GOLD("gold"), PLATINUM("orange"); // 마지막 객체엔 ;를 넣어줘야한다!!
companion object {
fun getIter() = values() // 반복자
}
}
5. 이넘 클래스 내부에 추상메서드를 정의하면 모든 객체 내부에 메서드를 재정의한다.
fun main() {
println(Card.SIVER.calculate(3)) // 6000
}
enum class Card(var color: String) {
SIVER("red") {
override fun calculate(grade: Int): Int = when (grade) {
in 0..3 -> 6000
in 4..5 -> 404
else -> 3333
}
},
GOLD("gold") {
override fun calculate(grade: Int): Int = when (grade) {
in 0..3 -> 6000
in 4..5 -> 404
else -> 3333
}
};
abstract fun calculate(grade: Int): Int // 객체 선언 후 뒤에 적어야 함
}
6. 인터페이스를 상속받아 내부에 구현할 수 있다. 상수가 객체마다 다른 경우에는 각각 구현하고 전체가 같을 경우엔 하나만 구현.
fun main() {
println(Card.SIVER.calculate(3)) // 6000
}
interface Calculable {
fun calculate(grade: Int): Int
}
enum class Card(var color: String) : Calculable {
SIVER("red"),
GOLD("gold");
override fun calculate(grade: Int): Int = when (grade) {
in 0..3 -> 6000
in 4..5 -> 404
else -> 3333
}
}
kotli 1.9.0에서 인라인 클래스에 세컨더리 컨스트럭터가 생겼다!
data object가 생겼고 toString(), equals(), hashcode 으로 비교도 가능하다.
용도 : 데이터의 성격을 띤 오브젝트 명시, data class에서 속성이 없을 때
'CS > 문법_Kotlin' 카테고리의 다른 글
Ch_ 13 파일 입출력과 스레드 처리 (0) | 2023.10.31 |
---|---|
Ch_10 함수 추가 사항 알아보기 (0) | 2023.09.13 |
Ch_ 06 내장자료형 알아보기 (0) | 2023.08.19 |
Ch_05 클래스 알아보기 (0) | 2023.08.11 |
Ch_04 함수 알아보기 (0) | 2023.08.04 |