이 글은 유데미 강의 Android 12 및 Kotlin 개발 완전 정복을 참고하여 작성하였습니다.
작성자 : 조윤주
개발환경은 Windows, Android Studio입니다.
데이터 클래스
1. 데이터 클래스 사용법
data class 클래스이름()으로 사용하며, 매개변수가 무조건 한 개 이상 있어야한다.
data class User(val id: Long, val name: String)
또한 데이터 클래스는 추상, 오픈, 봉인, 내부 클래스일 수 없다. (즉, abstract, open, sealed, inner 키워드를 사용할 수 없다.)
2. 데이터 클래스에서 사용할 수 있는 것들
- equals : 매개변수로 받은 객체와 같은지 알려주는 메서드
- println(user1.equals(user2)) //user1 == user2 와 같은 의미
- toString : 객체의 문자열 표현을 알려주는 메서드
- copy : 객체를 복사하면서 일부 프로퍼티를 바꿀 수 있게 해주는 메서드
- val updatedUser = user1.copy(name="Denis")
- component : component뒤에 숫자를 붙여서 사용하며, componentN의 경우, N번째에 있는 프로버티 값을 출력한다.
- println(updatedUser.component1())
- 구조 분해 : 밑의 코드 참고id1, name1, age1에 updateUser의 프로퍼티들의 값이 저장된다.
- val (id1,name1,age1) = updatedUser
상속
1. 상속
상속은 객체 지향 프로그래밍의 기본 개념 중 하나로, 어떤 클래스의 프로퍼티나 메서드 같은 특성을 다른 클래스에서 물려받는 것이다.
상속의 구조는 Super class(부모 클래스)와 Sub class(자식 클래스)로 이루어져 있다. 이 때, 부모 클래스가 open 클래스여야 상속이 가능하다. 코틀린에서 클래스를 선언하면 자동으로 상속이 금지되어있는 형태로 생성되는데, 이 때문에 부모 클래스 앞에 open이라는 키워드를 붙여야한다.
추가적으로 sealed 키워드를 앞에 붙여주면 해당 클래스는 상속 불가능하다.
open class Vehicle{
//프로퍼티
//메서드
}
sealed class Car: Vehicle(){
//상속 불가능
}
위의 코드에서는 Vehicle이 Super class, Car이 Sub Class이다.
open class Car(val name: String, val brand : String){
var range: Double = 0.0
fun extendRange(amount:Double){
if(amount > 0)
range+=amount
}
fun drive(distance: Double){
println("Drive")
}
}
class ElectricCar(name: String, brand: String, batteryLife: Double) : Car(name,brand){
}
fun main(){
var myCar = Car("A3","Audi")
var myEcar = ElectricCar("S-Model","Tesla",85.0)
myCar.drive(200.0)
myEcar.drive(200.0)
}
ElectricCar에는 따로 drive라는 메서드를 정의하지 않았지만, Car을 상속했기 때문에 Car의 메서드인 drive를 사용할 수 있다.
2. Any 클래스
이 외에도 모든 클래스에서는 toString, hashCode, equals 등과 같은 함수를 항상 사용할 수 있다. 이는, Any클래스는 모든 객체의 슈퍼클래스이기 때문이다.
3. overriding
오버라이딩은 슈퍼클래스의 함수를 서브클래스의 버전으로 사용하기 위해 서브클래스 내부에서 슈퍼클래스의 함수를 재정의하는 것을 의미한다.
오버라이딩을 사용하기 위해서는 슈퍼클래스의 해당 함수나 변수가 open이어야 한다.
open class Car(val name: String, val brand : String){
open var range: Double = 0.0
fun extendRange(amount:Double){
if(amount > 0)
range+=amount
}
open fun drive(distance: Double){
println("Drive")
}
}
class ElectricCar(name: String, brand: String, batteryLife: Double) : Car(name,brand){
override var range = batteryLife * 6
override fun drive(distance:Double){
println("Drive~~")
}
}
4. 다형성(Polymorphism)
다형성이란 비슷한 특성을 가진 객체들이 공통된 방법으로 여겨지는 것을 의미한다.
인터페이스
인터페이스는 클래스 기능을 확장하게 해준다. 인터페이스에서는 함수의 자세한 내용을 적을 필요는 없다. 또한 인터페이스는 객체를 생성할 수 없다.
인터페이스에서 구현된 부분이 있다면 그 인터페이스를 사용하는 클래스에서 오버라이딩을 할 수 있다.
인터페이스를 사용한 클래스에서는 인터페이스의 프로퍼티의 구조를 따라야하고, 인터페이스 내부에 있는 함수를 구현되어야 한다. 이 때, 프로퍼티는 주생성자에서 생성하고, 함수는 클래스 내부에서 생성한다.
또한 인터페이스를 사용한 클래스를 상속받은 경우, 자식 클래스에서도 해당 인터페이스 구조를 따라야한다.
interface Drivable{
val maxSpeed: Double
fun drive():String
fun brake(){
println("braking")
}
}
open class Car(override val maxSpeed: Double, val name: String, val brand : String):Drivable{
open var range: Double = 0.0
fun extendRange(amount:Double){
if(amount > 0)
range+=amount
}
override fun drive():String{
return "Drive~~~"
}
open fun drive(distance: Double){
println("Drive")
}
}
class ElectricCar(maxSpeed: Double, name: String, brand: String, batteryLife: Double)
: Car(maxSpeed, name, brand){
override var range = batteryLife * 6
override fun drive(distance:Double){
println("Drive~~")
}
override fun drive():String{
return "Drove for $range km on electricity"
}
override fun brake(){
super.brake()
println("brake inside of electric car")
}
}
fun main(){
var myCar = Car(200.0,"A3","Audi")
var myEcar = ElectricCar(200.0,"S-Model","Tesla",85.0)
myCar.drive(200.0)
myEcar.drive(200.0)
}
추가적으로, 인터페이스는 다른 인터페이스에서 상속받을 수 있다.
추상 클래스
추상 클래스 또한 인터페이스처럼 객체를 생성할 수 없다. 추상 클래스에서 프로퍼티와 메서드 같은 멤버 변수들은 키워드 abstract를 사용하지 않는 한 추상적인 것이 아니다. abstract키워드를 사용하지 않은 것들은 그대로 상속받을 수 있지만, abstract 키워드를 사용한 멤버변수들은 이를 상속받은 서브클래스에서 구현해야한다.
abstract class Mammal(private val name: String, private val origin: String,
private val weight: Double){ //매개변수들은 추상적이지 않다.
abstract var maxSpeed: Double// 안에서 선언된 프로퍼티와 함수들은 추상적임.(abstract 키워드 유무)
abstract fun run() //함수의 body없이 헤드만 있다.
abstract fun breath()
//추상 클래스 내부의 함수가 abstract 함수가 아니어도 된다.
fun displayDetails(){
println("Name : $name, Origin: $origin 이하생략.")
}
}
class Human(name: String, origin: String, weight: Double,
override var maxSpeed: Double):Mammal(name,origin, weight){
override fun run(){
println("run")
}
override fun breath(){
println("breath")
}
}
fun main(){
val mammal = Mammal("Yunju","Korea",50.0) //에러 발생
}
추가적으로 abstract로 정의된 클래스는 open 키워드를 사용하지 않아도 상속이 가능하다.
그렇다면 추상 클래스와 인터페이스의 차이점은 뭘까 ?
인터 페이스는 프로퍼티의 상태 정보를 저장할 수 없고, 여러 개의 인터페이스를 구현할 수 있다.(한 클래스가 여러개의 인터페이스를 상속받을 수 있다.) 또한 인터페이스는 생성자가 없다.
그러나 추상 클래스는 프로퍼티의 상태정보를 저장할 수 있고, 한 개만 상속받을 수 있으며, 생성자가 존재한다.
interface Drivable{
val maxSpeed: Double = 3 // 인터페이스에서는 프로퍼티의 상태를 저장할 수 없다.
fun drive():String
fun brake(){
println("braking")
}
}
abstract class Mammal(private val name: String, private val origin: String,
private val weight: Double = 30.0){ //추상적이지 않은 프로퍼티는 값을 넣어 저장 가능.
abstract var maxSpeed: Double
abstract fun run()
abstract fun breath()
fun displayDetails(){
println("Name : $name, Origin: $origin 이하생략.")
}
}
형 변환
리스트를 생성할 때, Any 키워드를 사용하면 다양한 데이터 타입의 변수들을 저장할 수 있다.
fun main(){
val stringList: List<String> = listOf("Yunju","Min","Yunsu") //String 타입만 존재하는 리스트
val mixedTypeList: List<Any> = listOf("Yunju",24) //여러타입을 저장할 수 있는 리스트
}
코틀린에는 스마트 캐스트가 있다. 스마트 캐스트란 컴파일러가 자동으로 형을 변환해주는 기능이다.
is를 사용하면 변수의 타입을 검사할 수 있다. 그런데 is 연산자는 타입 검사 후 컴파일러가 자동으로 형 변환을 해준다.
이를 스마트 캐스트라고 한다.
val obj1: Any = "I have a car"
if(obj1 !is String){
println("Not a String")
}
else{
println("It is a String")
}
또한, as를사용하여 형변환을 할 수 있다. 이 때, 형변환에 부적합 하거나, null이라면 에러(ClassCastException)를 발생시킨다.
따라서 as뒤에 ?를 붙여서 이러한 오류를 방지해야한다.
// 그냥 as 키워드를 사용하면 해당 객체가 다른 타입일 경우 잘못될 수 있다.
val obj2: Any = 1337
val str2: String = obj2 as String
println(str2)
// 따라서 as? 사용
val obj3: Any = 1337
val str3: String? = obj3 as? String
println(str3)
추가적으로, 위 코드 처럼 as?를 사용하여 null이 반환되고, 이 값이 변수에 저장되려면 변수는 nullable이어야 한다.
'GDSC HUFS 4기 > Kotlin Team #2' 카테고리의 다른 글
[2팀] 코틀린으로 XML, UI를 생성해서 계산기 만들기 (0) | 2022.10.31 |
---|---|
[2팀] 코틀린으로 분 단위 계산기 만들기 (0) | 2022.10.26 |
[2팀] 코틀린 객체지향 프로그래밍 기초 (1) (1) | 2022.10.05 |
[2팀] 코틀린 기초 더 배우기(2) (0) | 2022.10.05 |
[2팀] 코틀린 기초 (0) | 2022.10.03 |