[THEC!T] 앱 스쿨2기 : Android

TECHIT 앱 스쿨 2기: Android 18일차 (23.05.18)

끝까지 처음처럼 2023. 5. 18. 23:40
728x90

자료 출처 : 안드로이드 앱스쿨 2기 윤재성 강사님 수업 내용

 

오늘 오후에는 중간과제를 작성하였습니다.

중간과제는 제가 실수도 하고, 어쩌다 보니 다르게 구현하기도 한 문제와 유사한 문제가 나왔었습니다.

연습을 몇번했어서 그런지 빠른 속도는 아니지만 스스로 만족할 만한 결과물이 나와서 뿌듯했으나, 제출을 하기전에는 안보이다가 제출을 하고 나서 맘에 안드는 부분이 보여 뿌듯함이 사라져버렸습니다. 작성을 하고 나서 출력결과에 대해서 확인을 하다보니 정작 코드 내부를 자세히 못봤던 것 같습니다. 마지막에 좀 더 꼼꼼하게 점검을 했어야 됬는데 뭔가 마무리가 어설퍼 조금 착잡해졌던 것 같습니다. 앞으로는 코드 작성 후 마무리를 좀 더 꼼꼼하게 할 수 있도록 노력하겠습니다.

 

오늘은 코틀린에 대한 학습은 오전에만 진행하였습니다.

 

시작은 캐스팅에 대해서 학습하였습니다. 내용을 따로 적으면 헷갈릴 것 같아 모아서 작성하였습니다.

학습 내용은 하기 코드에 모두 적어놓도록 하겠습니다.

fun main(){
    val super1 = Super()
    val sub1 = Sub()
    // 부모 클래스 혹은 인터페이스를 구현한 클래스 타입에
    // 자식 클래스 타입 변수를 담는 것은 자바에서도 가능합니다.
    // 반대의 경우는 불가능 합니다.
    val superSub : Super = sub1
    val interSub : Inter = sub1
    // val subSuper : Sub = super1 불가


    // 하기 코드는 Sub 클래스를 통해 객체를 생성하였지만
    // 객체에 접근 할 때 부모클래스 혹은 인터페이스 타입으로 접근하면
    // 자식 클래스에 있는 메서드 중 오버라이딩 한것이 아니라면 호출 할 수 없습니다.
//    superSub.sub1()
//    interSub.sub2()


    // 하기 코드는 as 를 사용하여 Sub 클래스형으로 변환하였습니다.
    // as : 변수의 타입을 다른 클래스 타입으로 변경하는 연산자 입니다.
    // 상속 관계가 잇거나 구현한 인터페이스 관계가 있을 경우에만 성공합니다.
    superSub as Sub
    interSub as Sub
    superSub.sub1()
    interSub.sub2()
    // 출력결과
//    서브메서드1
//    서브메서드2

    // 하기 코드는 작성단계에서는 문제가 없지만
    // 실행할 경우 ClassCastingException 가 발생하게 됩니다.
    // 비유를 하자면 부모가 자식에게 메모리를 내어주긴 해도 자식의 메모리를 뺏어가지 않는 것처럼.
//    val test : Super = Super()
//    test as Sub
    // 출력 결과
//    Exception in thread "main" java.lang.ClassCastException: class Super cannot be cast to class Sub (Super and Sub are in unnamed module of loader 'app')
//    at StudyKt.main(study.kt:34)
//    at StudyKt.main(study.kt)

    val test2: Sub = Sub()
    // 객체를 담을 변수에타입을 설정하면 형변환이 자동으로 이루어 집니다.
    val test3: Super = test2
    // 객체를 담을 변수에 타입을 설정하지 않으면 변수의 타입은 객체의 클래스 타입으로
    // 결정됩니다. 이럴 때는 as를 이용하여 형변환해주면 형변환된 클래스 타입 변수로 정의 됩니다.
    val test4 = test2 as Super

    // is 연산자
    // is 연산자는 참조변수를 통해 접근할 수 있는 객체에 해당 클래스 영역이 있는지 확인하는 연산자 입니다.
    // 만약 해당 참조 변수를 통해 해당 클래스 영역이 있다면 true 없다면 false를 반환합니다.

    val test5 = test4 is Sub
    val test6 = test4 is Super
    val test7 = test4 is Inter
    val test8 = test4 is Inter2
    println("$test5, $test6, $test7, $test8 ")
    // 출력 결과
    // true, true, true, false


    // 스마트 캐스팅
    // 참조변수를 통해 접근할 수 있는 객체에 원하는 클래스의 영역이 잇는 경우
    // 자동으로 형변환을 해준다.
    val test9:Super = Sub()
    if(test9 is Sub){
        test9.sub1()
        test9.sub2()
    }
    // 출력 결과
//    서브메서드1
//    서브메서드2
    // if 문 밖으로 나가면 형변환 되지 않은 상태로 됩니다.

    // 스마트 캐스팅과 Any를 이용하면 하나의 메서드로 여러 클래스타입의 객체에 대한
    // 작업을 수행 할 수 있습니다.
    var test10 = ArrayList<Any>()
    test10.add("문자열")
    test10.add(100)
    test10.add(11.11)
    typeCheck(test10)
    // 출력 결과
//    문자열
//    정수형
//    실수
}

fun typeCheck(list : ArrayList<Any>){
    for(type in list){
        when(type){
            is Int -> println("정수형")
            is String -> println("문자열")
            is Double -> println("실수")
        }
    }
}


open class Super{

}

interface Inter
interface Inter2

class Sub: Super(),Inter{
    fun sub1(){
        println("서브메서드1")
    }
    fun sub2(){
        println("서브메서드2")
    }
}

 

다음으로는 열거형 클래스에 대해서 배웠습니다.

 

열거형 클래스

열겨형 클래스는 프로그램 개발 시 특정 그룹안의 구성 요소를 정의하는 값이 필요하고자 할 때  사용합니다. 

월을 나타내는 단어들, 혈액형, 방향,성별 등등

// 열거형 정의
// 시험 성적의 유형 5개 정의
enum class Test{
    BEST, GOOD, NOMAL, NOT_BAD, WORST
}

 

추가로 열거형을 정의 할 때  값도 설정할 수 있습니다.

이때 주생성자는 열거형 하나를 만드는 양식을 의미하며, 변수의 개수는 무제한 입니다.

 

열거형클래스를 하기처럼 정의 해보았습니다.

fun main(){

}

// 열거형 정의
// 시험 성적의 유형 5개 정의

enum class Test(val clearCount: Int,val coment:String){
    BEST(5,"참잘했어요"),
    GOOD(4,"잘했어요"),
    NOMAL(3,"보통이에요"),
    NOT_BAD(2,"조금 부족해요"),
    WORST(1,"많이 부족해요")
}

상기 코드처럼 열거형 클래스를 생성하였을 때 사용 방법입니다.

fun main(){

    val resultList = ArrayList<Int>()
    resultList.add(1)
    resultList.add(2)
    resultList.add(5)
    resultList.add(4)
    resultList.add(3)
    resultList.add(5)
    resultList.add(1)

    for(result in resultList){
        when(result){
            5 -> println(Test.BEST.coment)
            4 -> println(Test.GOOD.coment)
            3 -> println(Test.NOMAL.coment)
            2 -> println(Test.NOT_BAD.coment)
            1 -> println(Test.WORST.coment)
        }
    }
    println("--------------------------")
    for(result in resultList){
        when(result){
            Test.BEST.clearCount -> println(Test.BEST.coment)
            Test.GOOD.clearCount -> println(Test.GOOD.coment)
            Test.NOMAL.clearCount -> println(Test.NOMAL.coment)
            Test.NOT_BAD.clearCount -> println(Test.NOT_BAD.coment)
            Test.WORST.clearCount -> println(Test.WORST.coment)
        }
    }

    println("--------------------------")

    val resultList2 = ArrayList<String>()
    resultList2.add("잘했어요")
    resultList2.add("조금 부족해요")
    resultList2.add("참잘했어요")
    resultList2.add("보통이에요")
    resultList2.add("잘했어요")
    resultList2.add("참잘했어요")
    resultList2.add("많이 부족해요")


    for(result in resultList2){
        when(result){
            Test.BEST.coment -> println(Test.BEST.clearCount)
            Test.GOOD.coment -> println(Test.GOOD.clearCount)
            Test.NOMAL.coment -> println(Test.NOMAL.clearCount)
            Test.NOT_BAD.coment -> println(Test.NOT_BAD.clearCount)
            Test.WORST.coment -> println(Test.WORST.clearCount)
        }
    }

}

// 열거형 정의
// 시험 성적의 유형 5개 정의

enum class Test(val clearCount: Int,val coment:String){
    BEST(5,"참잘했어요"),
    GOOD(4,"잘했어요"),
    NOMAL(3,"보통이에요"),
    NOT_BAD(2,"조금 부족해요"),
    WORST(1,"많이 부족해요")
}

출력결과

많이 부족해요
조금 부족해요
참잘했어요
잘했어요
보통이에요
참잘했어요
많이 부족해요
--------------------------
많이 부족해요
조금 부족해요
참잘했어요
잘했어요
보통이에요
참잘했어요
많이 부족해요
--------------------------
4
2
5
3
4
5
1

 

실드 클래스

열거형 클래스가 무언가를 의미하는 값들을 모아서 관리하는 개념이라면, 실드 클래스는 클래스를 모아서 관리하는 개념입니다.

 

fun main(){
    // enum 은 무언가를 의미하는 값들을 모아서 관리하는 개념이라면
    // sealedClass는 클래스들을 모아 관리하는 개념이다.


    // Sealed 클래스 내부에 정의한 클래스의 객체를 생성한다.
    val s1 = Number2.OneClass(100, 200)
    val s2 = Number2.TwoClass(300)
    val s3 = Number2.ThreeClass(100, 11.11)
    val s4 = Number2.TwoClass(400)

    checkNumber2(s1)
    checkNumber2(s2)
    checkNumber2(s3)
    checkNumber2(s4)
}

// Sealed 클래스는 자기를 상속받은 클래스들을 모아 관리하는 개념
sealed class Number2{
    
    open fun number2Method(){
        println("number2 메서드 입니다")
    }
    
    class OneClass(var a1:Int, var a2:Int) : Number2()
    class TwoClass(var a1:Int) : Number2(){
        fun twoMethod(){
            println("TwoClass의 메서드 입니다")
        }

        override fun number2Method(){
            println("overriding된 number2메서드")
        }
    }
    class ThreeClass(var a1:Int, var a2:Double) : Number2()
}

class Test1 : Number2(){
    
}

// 매개변수의 타입은 sealed 클래스 타입으로 넣어준다.
fun checkNumber2(obj1:Number2){
    // when으로 분기할 때 is를 통해 어떤 클래스를 통해 만든 객체인지 검사한다.
    when(obj1){
        is Number2.OneClass -> {
            // 스마트 캐스팅도 이루어진다.
            println("OneClass 입니다")
            println(obj1.a1)
            println(obj1.a2)
            obj1.number2Method()
        }
        is Number2.TwoClass -> {
            println("TwoClass 입니다")
            println(obj1.a1)
            obj1.twoMethod()
            obj1.number2Method()
        }
        is Number2.ThreeClass -> {
            println("ThreeClass 입니다")
            println(obj1.a1)
            println(obj1.a2)
            obj1.number2Method()
        }
    }
}

 

마무리

내일은 휴강이며, 기초 스터디만 있습니다. 그렇기에 충분한 휴식을 취한 후 주말에는 자격증 공부를 할 수 있도록 하겠습니다. 시간과 체력이 된다면 알고리즘 문제도 작성하도록 하겠습니다.