GDSC HUFS 4기/Kotlin Team #7

[7팀]코틀린 기초 더 배우기(1)

sung.hyun.1204 2022. 10. 10. 15:33

이 글은  유데미 강의 Android 12 및 Kotlin 개발 완전 정복를 참고하여 작성하였습니다.

작성자 : 조성현

개발환경은 Windows, Android Studio입니다.

 

우리는 일상속에 있는 개념을 데이터와 로직 함수등으로 전환을 하고 이를 010101 과 같은 컴퓨터 언어로 바꾸는 작업을 하는 "객체지향"을 추구 한다.

 

코틀린은 자바를 대신하여  사용하는 안드로이드에서 공식적으로 인정한 언어 이므로 다음 개념 및 앞으로의 개념을 볼때 단순하게 문법을 보는게 아니라

어떻게 사용할지 생각 하고 보는것이 맞다라고 본다 . 자세한 문법은 공식 문서 및 다른 사람들의 블로그를 보면 잘 나와있다 . 그걸 보자.

 

1. 접근 제한자

접근 제한자를 왜 쓸까? 

 

프로젝트를 하다보면 당연하게 다른 팀원과의 협업이 있고 코드가 커지면서 (모놀리식 아키텍처 특히) , 다른 사람이 작성한 

라이브러리 및 클라스 에서 호출하는 일이 빈번하다.

예를 들어) C 라는 클라스에서 작업을 하는 나는  단순하게 A 라는 클라스의 있는 멤버 함수를 불렀고 멤버값 set()을 이용하여 변경을 주었는데 ,  기존의 다른 팀원이 작성하던 A 클라스에 의존적인  B 라는 클라스에서 에러 가 터진다.

 

oop 의 특성상 클라스들을 레이어로 쌓아 올리고 이들은 서로 독립적이지만(주장 은 독립 실제 코드들은 종속적인 케이스가 많다.),

접근을 제한 하지 않는다면  어디서 어떻게  내부 로직이 변경되거나 주석처리를 했던 리턴값이 아닌 다른 값이 나올 수 가 있다.

 

위의 관점에서 접근 제한자를 보자 . 

public,private,Internal,protected ,open

 

자바 를 사용한 입장에서는 private 과 public 이 친근하다.  -> 아마 코틀린에서 대부분 이 두개를 사용한다.

단위는 블럭 단위 로 생각을하자 

private - > 블록에서만 요소에 접근할 수 있게 해준다.  코틀린은 기본이 public 이니 private 을 항상 고려하자. 특하 함수 선언시

Internal : 신박한 친구다,  자바에는 없고 코틀린 만의 기능이다.  Internal 은  프로젝트의 "모듈" 안에서 누구가 접근이 가능하다

 

protected :최상위에 정의되는 클래스에 사용 하며 인터페이스에서는 사용할 수 없다

아니 왜  ? 인터페이스에 사용을 못하나 ? 라고  물으시면, 인터 페이스를 보고 오자 , 인터페이스의 개념의 따라 당연하게 보일것이다.

 

 

 

정리 

- public : project 내부 모든 곳에서 접근이 가능하다.

 

- private : propertiees , fields 등이 선언된 블록에서만 접근이 가능하다. => 선언된 장소에서만 사용이 가능하다.

                  추가로 prvate package 를 선언하면 다른 파일에서는 접근이 불가 하다. same file same class

 

- open :  java 와 반대로 class 의 선언시 상속을 할거면  open 을 적어준다.

 

- protected : 클래스 내부와 상속받는 객체에서 접근이 가능합니다 , top level Packages 는 보호가 불가 하다.

 

- Internal :프로젝트의 모듈 안의 누구나 접근이 가능합니다.  , internal (class,fun,val)

 

 

2. 중첩 클라스 

중첩 클라스를 왜 쓸까? 

레이어를 쌓아올리고 우리는 독립적인 instance 를 만들어 내는 붕어빵 틀 즉 클라스를 제작한다.

클라스 내부의 클라스를 만들어 좀더 세부적인 "데이터 타입"을 만들 수가 있다.

- > 스트링 인트 선언시 이들은 코틀린 클라스 타입 이다.    oop 를 가장 잘 보여주는 개념인것같다. 단순하게 car 라는 클라스가 아니라 우리는 Car 라는 데이터 를 관리하는 "Type" 을 만든 것이다. (감동적이다.)

 

상속, 인터페이스 , 중첨 클라스 3가지를 비교해보자 (저 말고,, 이글을 읽으시는 분이 해주세요)

 

다음 코드는 에러가 난다.  Inner1 Class 앞에 inner 라고 명시 해주자. 

class Outer {
    private val bar: Int = 1
    class Inner1 {
        fun gal() = bar // error 
    }
}

val demo = Outer().Inner().gal() // == 1

fun main() {
    print(demo)
}

수정 후)

class Outer {
    private val bar: Int = 1
    inner class Inner1 {
        fun gal() = bar // not Error
    }
}

val demo = Outer().Inner().gal() // == 1

fun main() {
    print(demo)
}

 

3.SafeCast & UnsafeCast 

예외를 피하기 위하여 "as?" 를 사용한 safeCast 를 사용하자


    fun <T> safeCast(t: T){
        val res = t as? String //Type: String?
    }

    fun <T> unsafeCast(t: T){
        val res = t as String? //Type: String?
    }

    fun test(){
        safeCast(1234);  //No exception, `res` is null
        safeCast(null);  //No exception, `res` is null
        safeCast("aa");  // res = aa (String)
        unsafeCast(1234);//throws a ClassCastException
    }

 

 

 

4.Try-catch

fun main() {

   val maxAge = 100
    if(maxAge !in 0..99) {
        throw IllegalArgumentException("wrong")
    }else {
        print(maxAge)
    }

}

try catch finally 를 이용하는 방식은 자바와 동일 하며,  Transaction 처리를 할때 유용하게 사용이 가능하다.

에 ) 

try :  db connect,  etc query 

catch: rollback()

finally: commit and flush .

 

- Try catch : 정상적인 프로그램 흐름이 아닌 제어할 수 없는 문제 : 블럭

            에러 발생시 객체를 전부 소멸 시켜 다른 곳에서의 참조를 막는다. -> 메모리 누수 방지 + 더큰 에러 방지 

 

- if else:  정상적인 흐름과 오류 검사   : 구문

     에러를 처리하는 중에도 값을 참조 할 수가 있다.