-
TECHIT 앱 스쿨 2기: Android 15일차 (23.05.15)[THEC!T] 앱 스쿨2기 : Android 2023. 5. 15. 22:33728x90
자료 출처 : 안드로이드 앱스쿨 2기 윤재성 강사님 수업 내용
오늘의 시작은 어제 내주신 과제풀이로 시작하였습니다.
강사님이 적어주신것을 보니 제가 중간에 빼먹은 부분도 보였기에 코드 작성 전 설계에 대한 중요성을 다시금 깨닫게 되었습니다.
문제에 대한 설명이 끝난 후 코틀린에서의 상속에 관하여 알려주셨습니다.
기본적으로 코틀린에서 class를 정의하면 자바로 변환될 때 final 클래스가 됩니다. 따라서 코틀린에서 일반 클래스는 상속이 불가능 합니다.
클래스를 정의할 때 클래스명 앞에 open 키워드를 붙혀주면 일반 클래스로 정의되고, 상속이 가능해 집니다.
그리고 자바에서는 extends 키워드를 이용하였지만 코틀린에서는 :(콜론) 을 이용하면 됩니다.
fun main(){ val s1 = SubClass1() println("s1.subMember1 : ${s1.subMember1}") s1.subMethod1() println("s1.superMember1 : ${s1.superMember1}") s1.superMethod1() } // 코틀린에서 class를 정의하면 final 클래스가 된다. // 클래스를 정의할 때 open 키워드를 붙혀주면 읿나 클래스로 정의되고 // 상속이 가능해진다. open class SuperClass{ var superMember1 = 100 constructor(){ println("SuperClass의 기본 생성자") } fun superMethod1(){ println("SuperClass1의 메서드 입니다.") } } // 자식 클래스 class SubClass1 : SuperClass(){ val subMember1 = 200 fun subMethod1(){ println("SubClass1의 메서드 입니다.") } }
출력 결과
SuperClass의 기본 생성자 s1.subMember1 : 200 SubClass1의 메서드 입니다. s1.superMember1 : 100 SuperClass1의 메서드 입니다.
그리고 코틀린언어는 자바 코드로 변경되어 자바 코드가 실행이 되는 것 처럼 자바와 동일하게 클래스의 객체를 생성하면, 부모 클래스의 기본 생성자를 자동으로 호출하게 됩니다.
이때 만약 부모 클래스에 기본 생성자가 없다면 자식 클래스에서 명시적으로 호출해줘야 합니다.
open class SuperClass2(var a1:Int) class SubClass2 : SuperClass2{ // 부모의 생성자를 호출한다. constructor() : super(100){ // 필요한 코드를 작성해주세요. } } // 만약 생성자에 작성할 코드가 없다면... class SubClass3 : SuperClass2(100)
그리고 다음으로는 접근 제한자에 대해서 말씀해주셨습니다.
강사님께서는 많은 예제를 작성하여 알려주셨으나, 최대한 간단하게 기재해 보겠습니다.
하기에서 말하는 모듈이란 일반적으로 같은 컴파일 단위를 의미합니다. 즉, 하나의 프로젝트,하나의 프로그램 등
class
private : 파일이 같을 경우에만 사용이 가능하다.
public : 패키지, 모듈이 달라도 사용이 가능하다.
internal : 패키지, 모듈이 다르면 사용이 불가능하다.
변수, 메서드
private : 모든 경우에 사용이 불가능하다.
public : 모든 경우에 사용이 가능하다.
protected : 상속 관계에서만 사용이 가능하다. 패키지, 모듈이 달라도 사용 가능하다.
internal : 모듈이 다르면 사용이 불가능하다.만약 접근제한자를 명시하지 않는다면 기본값은 public 입니다.
다음으로는 프로퍼티에 대해 배웠습니다. 일반적으로 코틀린에서는 클래스 내에 선언한 변수를 프로퍼티라고 부르며, 자바에서는 이런 변수를 필드라고 부르고 있습니다.
간단하게 코드를 작성하여 설명하겠습니다.
fun main(){ val s1 = study("one", 15) println(s1.name) // 게터에 의한 값 확인 s1.age = 20 // 세터에 의한 값 변경 println(s1.age) // 게터에 의한 값 확인 val s2 = study("two", 18) println(s2.name) // 게터에 의한 값 확인 //s2.name = "변경안됨" s2.age = 24 // 세터에 의한 값 변경 println(s2.age) // 게터에 의한 값 확인 } class study(val name :String, var age :Int)
자바에서는 . 을 이용하면 해당 필드에 직접접근이 가능합니다. 하지만 데이터의 무결성이 깨질 수 있고 보안상 문제가 있기 때문에 게터와 세터라는 접근 메서드를 사용합니다.
코틀린에서는 . 을 이용하여 직접접근 하는 것 처럼 보이지만 사실 게터와 세터를 생성하여 사용하고 있습니다.
하기 코드는 상기 코드를 자바로 디컴파일 한 코드 입니다.
하기 코드에서 확인 할 수 있듯 매개변수로 val로 선언했을 경우에는 세터는 선언되지 않습니다.
val로 선언했다는 것은 즉 자바에서는 final 변수 이기때문에 변경이 되지 않기 때문에 값을 얻어오는 getter 만을 사용할 수 있습니다.
public final class study { @NotNull private final String name; private int age; @NotNull public final String getName() { return this.name; } public final int getAge() { return this.age; } public final void setAge(int var1) { this.age = var1; } public study(@NotNull String name, int age) { Intrinsics.checkNotNullParameter(name, "name"); super(); this.name = name; this.age = age; } }
그리고 코틀린에서는 게터와 세터를 커스텀할 수 있습니다.
fun main(){ val s1 = study("one") s1.age = 5 // 커스텀 세터에 의한 값 변경 println(s1.age) val s2 = study("two") s2.age = 24 // 커스텀 세터에 의한 값 변경 println(s2.age) val s3 = study("three") s3.age = 35 // 커스텀 세터에 의한 값 변경 println(s3.age) } class study(val name :String){ var age = 0 set(value) { // value 는 전달 받은 값. field = when{ // field 는 전달 받은 값에 따라 저장할 값 value in 1 .. 10 -> { 10 } value in 11 .. 29 ->{ 20 } else -> 30 } } }
그리고 지연 초기화에 대해서 배웠습니다.
요약하자면 var 타입의 경우 lateinit 를 사용
val 타입은 by lazy 를 사용.
fun main(){ val t1 = TestClass1() t1.testMethod1() println("-----------------------------------------") // a4 프로퍼티에 값 저장 t1.a4 = "문자열입니다" t1.testMethod1() } class TestClass1{ // 프로퍼티 정의 // Kotlin은 프로퍼티를 정의할 때 반드시 값을 넣어줘야 한다. var a1:Int = 100 var a2 = 200 var a3:Int // lateinit // var 프로퍼티에만 사용이 가능하며 변수를 정의할 때 값을 저장하지 않아도 된다. // lateinit은 기본 자료형(Int, Double 등)에서는 사용할 수 없다. lateinit var a4:String // lazy // val 프로퍼티에서 사용하는 키워드 이다. // val 프로퍼티에 저장할 값을 어떠한 처리를 통해서 구해야 한다면 lazy를 사용한다. // lazy 코드 블록의 제일 마지막에 작성한 값이나 변수의 값, 수식의 값을 프로퍼티에 저장한다. val a5:Int by lazy{ val temp = 1 + 2 + 3 + 4 + 5 temp } // 만약 init 블럭에서 프로퍼티에 값을 저장한다면 프로퍼티를 정의할 때 // 값을 저장하지 않아도 된다. init{ a3 = 300 } fun testMethod1(){ println("a1 : $a1") println("a2 : $a2") println("a3 : $a3") // lateinit 프로퍼티는 사용 전에 반드시 // 값을 저장한 적이 있는지를 확인해야 한다. if(::a4.isInitialized) { println("a4 : $a4") } println("a5 : $a5") } }
::a4.isInitialized 는 프로퍼티가 초기화 되었는지 검사하는 코틀린 표준 함수의 API 입니다.
만일 true를 반환하면 프로퍼티가 할당되었다는 뜻이며, false를 반환하면 할당되지 않았다는 뜻 입니다.
마지막으로는 오버라이딩에 대해서 배웠습니다.
오버라이딩 : 상속관계에 있는 부모클래스와 자식 클래스 가 있을 때 자식 클래스에서 부모의 메서드를 같은 이름으로 사용하지만 다른 기능을 하게함.
코틀린과 기본적인 개념은 같습니다.
하지만 문법이 조금 다름니다.
기본적으로 자바에서는 상속이나 오버라이딩을 할 때 해주는 클래스나 메서드에는 아무것도 표시를 하지 않았고, 상속을 받거나 오버라이딩 하는 메서드에 표시를 하였었습니다.
하지만 코틀린은 둘 다 입니다.
상속이나 오버라이딩을 기본적으로 허용하지 않으며 허용하고 싶다면 클래스명 이나 함수명 앞에 open 키워드를 적어 줘야 하며, 상속을 받는 클래스는 :(콜론)을 이용하여 명시하며, 함수는 override fun 함수명 이라는 형식으로 적어야 합니다.
fun main(){ // 객체를 생성하여 자기 타입 변수에 담아준다. val obj1 = SubClass1() // val obj1:SubClass1 = SubClass1() // 자식 클래스 타입이므로 자기 것과 부모 것 모두 사용 가능하다. println("obj1.subA1 : ${obj1.subA1}") println("obj1.superA1 : ${obj1.superA1}") obj1.subMethod1() obj1.superMethod1() println("---------------------------------------") // 객체를 생성하여 부모 클래스 타입에 담아준다. var obj2:SuperClass1 = SubClass1() // 부모클래스 타입이기 때문에 부모 것만 사용이 가능하다. // println("obj2.subA1 : ${obj2.subA1}") println("obj2.superA1 : ${obj2.superA1}") // obj2.subMethod1() obj2.superMethod1() println("-----------------------------------------") val obj3 = SubClass2() obj3.superMethod2() // 부모 클래스 타입 변수를 통해 Overriding한 메서드를 호출할 경우 // 부모의 것이 아닌 자식의 것이 호출된다. val obj4:SuperClass2 = SubClass2() obj4.superMethod2() } open class SuperClass1{ var superA1 = 100 fun superMethod1(){ println("SuperClass1의 superMethod1 입니다") } } class SubClass1 : SuperClass1(){ var subA1 = 200 fun subMethod1(){ println("SubClass1의 subMethod1 입니다") } } open class SuperClass2{ var superA2 = 300 // 메서드는 final 메서드로 정의된다. // 이에 overriding이 가능하게 하기 위해서 open 키워드를 사용한다. // open 키워드를 사용하면 메서드는 final 메서드가 아닌 메서드로 변환된다. open fun superMethod2(){ println("SuperClass2의 superMethod2 입니다") } } class SubClass2 : SuperClass2(){ // Overriding하는 메서드는 overrdide라는 키워드를 붙혀주도록 강제하고 있다. // 이는, 이 메서드는 Overriding한 메서드라는 것을 명시하기 위함이다. override fun superMethod2(){ // 부모의 메서드 호출 super.superMethod2() println("SubClass2의 superMethod2 입니다") } }
마무리
오늘은 국민취업지원 제도의 상담일정 때문에 끝까지 집중하여 듣지는 못하였습니다.
물론 상담받으러 출발하기 전까지는 집중을 하여 들었고, 상담 받으러 가면서도 스마트폰을 이용하여 강의를 들었었습니다. 사실 제가 이동중에 강의를 보면서 이동할 거라고는 옛날에 저라면 생각도 못했을 것 같습니다. 그만큼 지금 배우는 것 자체가 재밌다고 느끼고 있습니다. 점점 공부를 하면서 느끼는 점은 내가 안드로이드 쪽으로 정하기를 잘했다는 점과 현재 듣고 있는 교육과정을 잘 만났다는 것 같습니다.
오늘의 마음가짐 : 즐기듯이 열심히 한다면 좋은 결과가 있을 거라 생각하자~!
'[THEC!T] 앱 스쿨2기 : Android' 카테고리의 다른 글
TECHIT 앱 스쿨 2기: Android 17일차 (23.05.17) (0) 2023.05.17 TECHIT 앱 스쿨 2기: Android 16일차 (23.05.16) (1) 2023.05.17 TECHIT 앱 스쿨 2기: Android 14일차 (23.05.12) (0) 2023.05.12 TECHIT 앱 스쿨 2기: Android 13일차 (23.05.11) (0) 2023.05.11 TECHIT 앱 스쿨 2기: Android 12일차 (23.05.10) (0) 2023.05.10