이 글은 Android12 및 코틀린 완전 정복을 참고하여 작성하였습니다.
작성자 : 윤승민
개발환경은 Mac, Android Studio입니다.
클래스
클래스는 객체를 생성하기 위한 설계도라고 할 수 있다.
클래스와 관련된 개념을 정리해보면 다음과 같다.
💡 클래스 - 객체를 생성하기 위한 설계도
객체 - 클래스의 내용이 구현돼 생성된 것
생성자 - 클래스 객체를 생성할 때 클래스 내의 멤버 변수 초기화를 돕는 역할
멤버 변수 - 클래스 내에 만들어진 변수
멤버 메소드 - 클래스 내에 만들어진 함수
클래스 객체의 생성
1. 클래스를 정의했다면 이를 사용하기 위해서 클래스 객체를 생성해야 한다.
class Person() {
}
2. 정의한 내용에 따라서 클래스를 생성할 때 클래스에서 요구하는 정보들이 있을 수 있다.
- 생성자를 통해서 이러한 정보들을 받을 수 있다.
- 사람(person)과 관련된 클래스를 만든다면 생각해볼 수 있는 관련 정보는 이름, 나이, 성별 등이 있다.
class Person(name: String, age: Int, sex: String) {
// 클래스 내용
}
3. 만약 필요한 정보들이 있다면 객체 생성 때 이 값들을 넘겨줘야 한다. 없다면 넘겨주는 값 없이 바로 생성한다.
fun main() {
val yoonMin = Person("YoonSeungMin", 24, "남") // 필요한 정보가 있을 경우
val nonePerson = Person() // 필요한 정보가 없을 경우
}
class Person(name: String, age: Int, sex: String) {
// yoonMin 생성을 위한 클래스
}
class Person() {
// nonePerson 생성을 위한 클래스
}
4. 생성자를 통해서 넘겨준 값들을 통해 멤버 변수를 초기화해주고 사용할 준비를 마친다.
class Person(name: String, age: Int, sex: String) {
// yoonMin 생성을 위한 클래스
val name : String = name
val age : Int = age
val sex : String = sex
fun getName() : String {
return name
}
fun getAge(): Int {
return age
}
fun getSex(): String {
return sex
}
}
생성자
생성자는 다음과 같이 만든다.
constructor키워드는 어노테이션이나 접근 제어를 걸어주지 않는다면 생략이 가능하다.
class Person constructor(name: String, age: Int, sex: String){
val name : String = name
val age : Int = age
val sex : String = sex
}
class Person(name: String, age: Int, sex: String){
val name : String = name
val age : Int = age
val sex : String = sex
}
위와 같은 경우에는 클래스 내부에 따로 멤버 변수를 만들어서 초기화 해준다.
괄호 안에서 초기화까지 해주는 것도 가능하다.
class Person(val name: String, val age: Int, val sex: String){
}
생성자를 통해서 값을 받았으나 받은 값들이 적절하지 않을수도 있다.
그래서 값을 받아서 초기화하기 전에 값에 이상이 없는지 검사를 해줄 필요가 있을수도 있다.
이 때 init을 이용한다. init은 클래스가 생성될 때 자동으로 실행된다.
class Person(name: String){
val name : String
init{
if(name.length > 0) {
this.name = name // 클래스 내 멤버 변수 name의 값을 초기화한다.
}
else{
//부적절한 값임을 알린다.
}
}
}
데이터 클래스
- 데이터들을 객체로 묶어서 관리할 수 있다.
- 배열에 데이터를 담는 경우 데이터 클래스를 이용할 수 있음
- 서버 통신을 통해 받은 데이터를 데이터 클래스에 저장할 수 있음 → json 형식을 인식함
- 일반 클래스와 달리 생성하면 메소드가 자동으로 생성되는데 이 메소드들이 굉장히 유용하다.
- hashCode()
- copy()
- equals()
- toString()
- comonentsN()
- 생성시 무조건 1개 이상의 파라미터가 있어야 한다.
- 괄호 내에서 val 혹은 var 키워드를 이용해 만들어야 한다.
- abstract, open, sealed, inner 불가능
data class Person(
val name: String = "YoonSeungMin",
val age: Int = 24,
val sex: String = "남"
)
상속
💡 기존의 클래스를 재사용하여 클래스를 새롭게 만든다.
- 코드의 재사용을 높여서 코드 중복을 방지
- 유지보수가 용이하고 생산성이 높아짐
코틀린에서의 상속은 불가능하다. 클래스를 생성하면 타입이 final이기 때문이다.
상속을 가능하게 하려면 class 앞에 open을 붙여줘야 한다.
open class Person(name: String, age: Int, sex: String) {
}
이제 부모 클래스를 만들었으니 자식 클래스를 만들어야 한다. 자식 클래스가 부모 클래스를 상속 받을 때 다음과 같이 작성한다.
class Student(name: String, age: Int, sex: String, id: String) : Person(name, age, sex) {
}
부모 클래스의 함수를 사용하려면 마찬가지로 부모 클래스 내의 멤버 메소드에 open을 붙여주면 된다.
open class Person(name: String, age: Int, sex: String) {
val name : String = name
val age : Int = age
val sex : String = sex
open fun printInfo() {
println("${this.name} ${this.age} ${this.sex}")
}
}
자식 클래스는 printInfo를 재정의하여 사용할 수 있다.
class Student(name: String, age: Int, sex: String) : Person(name, age, sex) {
override fun printInfo() {
super.printInfo() // 부모 클래스의 printInfo()를 사용할 수 있음
println("정보 출력이 완료됐습니다.")
}
}
인터페이스
💡 클래스가 자세하게 완성된 설계도라 한다면 인터페이스는 두루뭉실한 설계도라 할 수 있다. → 추상 클래스와 유사
- 클래스의 기능을 확장하는데 도움을 줌
- 나중에 구현하고 싶은 특정 함수나 프로퍼티를 대비해서 미리 밑그림만 그려놓는 느낌
- 함수의 몸통이 정의되지 않은 추상 메소드를 가짐
- 상속을 통해서 구체적인 정의를 하여 설계를 완성함
- 인터페이스를 객체로 생성하는 것은 불가능
- 특정 클래스 상속을 통해서 객체를 생성
- 다중상속이 가능
interface Animal {
fun name()
fun color()
fun age()
}
class WhiteDog : Animal {
//
override fun name() {
println("백구")
}
override fun color() {
println("white")
}
override fun age() {
println("3")
}
}
코틀린은 인터페이스 사용시 꼭 override를 붙여야 한다. → 추상 메소드는 반드시 재정의가 필요
추상 클래스
인터페이스와 유사하지만 차이가 있다.
- 추상 클래스는 프로퍼티의 초기화가 가능하지만 인터페이스는 불가능
- 추상클래스는 클래스나 메소드 앞에 abstract를 붙여야 함
- 인터페이스는 다중 상속이 가능하지만 추상 클래스는 다중 상속이 불가능하다.
abstract class Animal {
val year = "2022" // 프로퍼티 초기화가 가능
abstract fun name()
abstract fun color()
abstract fun age()
}
class WhiteDog : Animal {
override fun name() {
println("백구")
}
override fun color() {
println("white")
}
override fun age() {
println("3")
}
}
형 변환
- 코틀린은 변수를 생성할 때 타입으로 Any를 사용할 수 있다.
- 변수를 생성할 때 Any를 타입으로 지정하면 초기화 한 값에 따라서 자동으로 값에 해당하는 타입을 지정해줌
- 예를 들어 문자열을 값으로 설정하면 문자열에 관련된 메소드인 length를 사용할 수 있다.
- is 연산자로 타입 확인이 가능
val name: Any = "YoonMin"
if(name is String) {
println(name.length) // name : String 으로 자동 캐스팅
}
- as 연산자를 이용해 형 변환이 가능
- 형 변환이 불가능하면 에러 발생 → as? 는 형 변환이 불가능하면 null값 반환
val nameBox: String = name as String
val nameBox: String? = name as? String // as? 는 null값을 반환할 수 있기 때문에 값을 받는 변수도 nullable 설정이 필요
'GDSC HUFS 4기 > Kotlin Team #4' 카테고리의 다른 글
[4팀] 퀴즈 앱 안드로이드 12 후반부 (0) | 2022.11.09 |
---|---|
[4팀]계산기 - XML사용법과 UI 생성법 배우기 (0) | 2022.11.08 |
[4팀] 분 단위 나이 계산기 (0) | 2022.10.31 |
[4팀] 코틀린 기능 더 배우기 (0) | 2022.10.10 |
[4팀] 코틀린 기초 (0) | 2022.10.02 |