ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • TECHIT 앱 스쿨 2기: Android 14일차 (23.05.12)
    [THEC!T] 앱 스쿨2기 : Android 2023. 5. 12. 23:28
    728x90

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

     

    오늘은 코틀린에서 객체 생성 방법과 클래스에 대한 설명으로 시작하였습니다.

    코틀린에서 객체를 생성하는 것은 자바와 마찬가지로 클래스를 이용하여 생성합니다.

     

    코틀린 코드

    fun main () {
    
        val one = OneClass()
        
    }
    
    class OneClass{
    // 내용 입력 없음
    }

    디컴파일 된 자바 코드

    public final class OneClass {
    }
    // Main2Kt.java
    
    public final class Main2Kt {
       public static final void main() {
          new OneClass();
       }
    
       // $FF: synthetic method
       public static void main(String[] var0) {
          main();
       }
    }

     

    만약 객체를 생성할 때 생성자를 통하여 값을 지정한다거나 할 때는 자바에서는 클래스명 과 동일한 public 의 메서드를 작성하면 생성자의 역할을 하였었습니다.

    하지만 코틀린에서는 생성자를 문법 상 여러 형태로 지원합니다. 또한 생성자는 자바와 마찬가지로 오버로딩이 가능합니다.

    Overloading(오버로딩) : 함수의 이름은 같으나 매개 변수를 달리하여 기능을 다르게 설정이 가능하다.

     

    코틀린 코드

    fun main () {
    
        val one = OneClass()
    
        val one2 = OneClass(100, 200)
    
        val two = TwoClass()
    
        val two2 = TwoClass(40, 50)
    
    }
    
    class OneClass {
        // 매개변수가 없는 기본 생성자
        constructor(){
            var oc1 = 1
            var oc2 = 2
            println("매개 변수가 없는 생성자 사용")
            println("OneClass 생성자 사용")
        }
        // 매개변수를 받은 기본 생성자
        constructor(oc1:Int,oc2:Int){
            println("매개 변수를 받아 생성자 사용")
            println("oc1 : $oc1 , oc2 : $oc2")
        }
    }
    
    // 멤버 변수를 가진 클래스
    class TwoClass {
        var tc1 = 10
        var tc2 = 20
    
        // 매개 변수가 없는 기본 생성자
        constructor(){
            println("매개 변수가 없는 생성자 사용")
            println("tc1 : $tc1 , tc2 : $tc2")
        }
    
        // 매개변수를 받은 기본 생성자
        constructor(tc1:Int,tc2:Int){
            println("매개 변수를 받아 생성자 사용하여 멤버 변수 수정")
            this.tc1 = tc1
            this.tc2 = tc2
            println("tc1 : $tc1 , tc2 : $tc2")
        }
    }

    디컴파일 된 자바 코드

    public final class TwoClass {
       private int tc1 = 10;
       private int tc2 = 20;
    
       public final int getTc1() {
          return this.tc1;
       }
    
       public final void setTc1(int var1) {
          this.tc1 = var1;
       }
    
       public final int getTc2() {
          return this.tc2;
       }
    
       public final void setTc2(int var1) {
          this.tc2 = var1;
       }
    
       public TwoClass() {
          String var1 = "매개 변수가 없는 생성자 사용";
          System.out.println(var1);
          var1 = "tc1 : " + this.tc1 + " , tc2 : " + this.tc2;
          System.out.println(var1);
       }
    
       public TwoClass(int tc1, int tc2) {
          String var3 = "매개 변수를 받아 생성자 사용하여 멤버 변수 수정";
          System.out.println(var3);
          this.tc1 = tc1;
          this.tc2 = tc2;
          var3 = "tc1 : " + tc1 + " , tc2 : " + tc2;
          System.out.println(var3);
       }
    }
    // OneClass.java
    import kotlin.Metadata;
    
    public final class OneClass {
       public OneClass() {
          int oc1 = true;
          int oc2 = true;
          String var3 = "매개 변수가 없는 생성자 사용";
          System.out.println(var3);
          var3 = "OneClass 생성자 사용";
          System.out.println(var3);
       }
    
       public OneClass(int oc1, int oc2) {
          String var3 = "매개 변수를 받아 생성자 사용";
          System.out.println(var3);
          var3 = "oc1 : " + oc1 + " , oc2 : " + oc2;
          System.out.println(var3);
       }
    }
    // Main2Kt.java
    import kotlin.Metadata;
    
    
    public final class Main2Kt {
       public static final void main() {
          new OneClass();
          new OneClass(100, 200);
          new TwoClass();
          new TwoClass(40, 50);
       }
    
       // $FF: synthetic method
       public static void main(String[] var0) {
          main();
       }
    }

    출력 결과

    매개 변수가 없는 생성자 사용
    OneClass 생성자 사용
    매개 변수를 받아 생성자 사용
    oc1 : 100 , oc2 : 200
    매개 변수가 없는 생성자 사용
    tc1 : 10 , tc2 : 20
    매개 변수를 받아 생성자 사용하여 멤버 변수 수정
    tc1 : 40 , tc2 : 50

     

    만약 생성자의 역할이 매개 변수로 들어오는 값을 멤버 변수에 담는 것만 한다면 하기와 같이 작성 할 수도 있습니다.

     

    코틀린 코드

    fun main () {
    
        val one = OneClass(100, 200)
        println("one.a1 : ${one.a1}, one.a2 : ${one.a2}")
    
        val two = TwoClass(300, 400)
        println("constructor는 생략이 가능합니다.")
        println("two.b1 : ${two.b1}, one.a2 : ${two.b2}")
    
    }
    
    class OneClass constructor(val a1 : Int, val a2 : Int)
    
    class TwoClass (val b1 : Int, val b2 : Int)

    디컴파일된 자바 코드

    // TwoClass.java
    import kotlin.Metadata;
    
    public final class TwoClass {
       private final int b1;
       private final int b2;
    
       public final int getB1() {
          return this.b1;
       }
    
       public final int getB2() {
          return this.b2;
       }
    
       public TwoClass(int b1, int b2) {
          this.b1 = b1;
          this.b2 = b2;
       }
    }
    // OneClass.java
    import kotlin.Metadata;
    
    
    public final class OneClass {
       private final int a1;
       private final int a2;
    
       public final int getA1() {
          return this.a1;
       }
    
       public final int getA2() {
          return this.a2;
       }
    
       public OneClass(int a1, int a2) {
          this.a1 = a1;
          this.a2 = a2;
       }
    }
    // Main2Kt.java
    import kotlin.Metadata;
    
    
    public final class Main2Kt {
       public static final void main() {
          OneClass one = new OneClass(100, 200);
          String var1 = "one.a1 : " + one.getA1() + ", one.a2 : " + one.getA2();
          System.out.println(var1);
          TwoClass two = new TwoClass(300, 400);
          String var2 = "constructor는 생략이 가능합니다.";
          System.out.println(var2);
          var2 = "two.b1 : " + two.getB1() + ", one.a2 : " + two.getB2();
          System.out.println(var2);
       }
    
       // $FF: synthetic method
       public static void main(String[] var0) {
          main();
       }
    }

    출력 결과

    one.a1 : 100, one.a2 : 200
    constructor는 생략이 가능합니다.
    two.b1 : 300, one.a2 : 400

     

     

    그리고 생성자는 아니지만 객체가 생성이 될 때 반드시 호출하는 함수를 만들 수 가 있습니다.

    해당 함수는 init 키워드를 사용하여 만들 수 있으며, 매개 변수를 받지 못하기 때문에 생성자는 아닙니다.

     

    코틀린 코드

    fun main () {
    
        val one = OneClass(100,200)
    
    }
    
    class OneClass {
        constructor(a1 : Int, a2 : Int){
            println("기본 생성자 입니다.")
        }
        init {
            println("init{} 안에 있는 코드는 객체가 생성되면 자동으로 실행이 됩니다.")
        }
    }

    디컴파일 된 자바 코드

    public final class OneClass {
       public OneClass(int a1, int a2) {
          String var3 = "init{} 안에 있는 코드는 객체가 생성되면 자동으로 실행이 됩니다.";
          System.out.println(var3);
          var3 = "기본 생성자 입니다.";
          System.out.println(var3);
       }
    }
    // Main2Kt.java
    import kotlin.Metadata;
    
    public final class Main2Kt {
       public static final void main() {
          new OneClass(100, 200);
       }
    
       // $FF: synthetic method
       public static void main(String[] var0) {
          main();
       }
    }

    출력결과

    init{} 안에 있는 코드는 객체가 생성되면 자동으로 실행이 됩니다.
    기본 생성자 입니다

     

    코틀린 코드에서는 기본 생성자를 먼저 작성하고 init문을 작성하였습니다. 하지만 출력결과를 봤을 때 init문이 먼저 실행 된 것을 볼 수 있습니다. init문을 작성하게 되면 객체가 생성될 때 생성자 보다 뒤에 작성한다고 하더라도 자바로 변환이 될 때 기본 생성자 보다 먼저 호출이 되는 것을 알 수 있습니다.

     

    코틀린 코드

    fun main () {
    
        val one = OneClass(100,200)
    
    }
    
    class OneClass {
        constructor(a1 : Int, a2 : Int){
            println("기본 생성자 입니다.")
        }
        init {
            println("init{} 안에 있는 코드는 객체가 생성되면 자동으로 실행이 됩니다.")
        }
    
        init {
            println("init를 두 번 작성하였습니다.")
        }
    
    }

    디컴파일 된 자바 코드

    // OneClass.java
    import kotlin.Metadata;
    
    
    public final class OneClass {
       public OneClass(int a1, int a2) {
          String var3 = "init{} 안에 있는 코드는 객체가 생성되면 자동으로 실행이 됩니다.";
          System.out.println(var3);
          var3 = "init를 두 번 작성하였습니다.";
          System.out.println(var3);
          var3 = "기본 생성자 입니다.";
          System.out.println(var3);
       }
    }
    // Main2Kt.java
    import kotlin.Metadata;
    
    
    public final class Main2Kt {
       public static final void main() {
          new OneClass(100, 200);
       }
    
       // $FF: synthetic method
       public static void main(String[] var0) {
          main();
       }
    }

    출력 결과

    init{} 안에 있는 코드는 객체가 생성되면 자동으로 실행이 됩니다.
    init를 두 번 작성하였습니다.
    기본 생성자 입니다.

     

    init를 추가로 작성한다면 이때는 init를 작성한 순서 대로 실행되는 점을 확인해 볼 수 있습니다.

     

     

    마지막으로는 만약 클래스가 멤버 변수의 값을 가지고 있을 때 매개 변수 하나만 변경을 하여 사용하고 싶을 경우, 혹은 객체를 생성할 때 멤버 변수의 값을 지정하여 저장하고 싶은 경우 입니다.

     

    fun main () {
    
        val zero = OneClass()
        println("아무것도 지정하여 저장하지 않았을 때 oc1 : ${zero.oc1}, oc2 : ${zero.oc2}")
    
        val one = OneClass(oc1 = 500)
    
    
    }
    
    class OneClass(var oc1 : Int, var oc2 :Int) {
    
        // 추가적인 생성자를 정의할 때는
        // 클래스 이름 옆에 정의한 생성자를 반드시 호출해야 한다.
    
        // 아무것도 입력 받지 않은 경우
        constructor() : this(100,200)
    
        // oc1을 입력 받은 경우
        constructor(oc1: Int) : this( oc1, 800){
            this.oc1 = oc1
            println("지정된 oc1 : $oc1 , oc1만을 입력받았을 때 oc2 : $oc2")
        }
    
    
    
    }

    디컴파일 된 자바코드

    // OneClass.java
    import kotlin.Metadata;
    
    
    public final class OneClass {
       private int oc1;
       private int oc2;
    
       public final int getOc1() {
          return this.oc1;
       }
    
       public final void setOc1(int var1) {
          this.oc1 = var1;
       }
    
       public final int getOc2() {
          return this.oc2;
       }
    
       public final void setOc2(int var1) {
          this.oc2 = var1;
       }
    
       public OneClass(int oc1, int oc2) {
          this.oc1 = oc1;
          this.oc2 = oc2;
       }
    
       public OneClass() {
          this(100, 200);
       }
    
       public OneClass(int oc1) {
          this(oc1, 800);
          this.oc1 = oc1;
          String var2 = "지정된 oc1 : " + oc1 + " , oc1만을 입력받았을 때 oc2 : " + this.oc2;
          System.out.println(var2);
       }
    }
    // Main2Kt.java
    import kotlin.Metadata;
    
    public final class Main2Kt {
       public static final void main() {
          OneClass zero = new OneClass();
          String var1 = "아무것도 지정하여 저장하지 않았을 때 oc1 : " + zero.getOc1() + ", oc2 : " + zero.getOc2();
          System.out.println(var1);
          new OneClass(500);
       }
    
       // $FF: synthetic method
       public static void main(String[] var0) {
          main();
       }
    }

    출력 결과

    아무것도 지정하여 저장하지 않았을 때 oc1 : 100, oc2 : 200
    지정된 oc1 : 500 , oc1만을 입력받았을 때 oc2 : 800

    코틀린에서는 객체를 생성 할 때 다양한 문법을 지원하므로 개발자는 자신이 편한 방식대로 작성해도 됩니다.

     

    이 이후로는 지금까지 배운 코틀린 문법을 이용하여 문제를 풀어보는 시간을 가졌습니다.

    문제는 총 3개를 내주셨고 2개는 강사님께서 풀이를 해주시면서 작성하는 시간을 가졌으며, 마지막으로 내주신 문제는

    다음주 월요일 같이 작성하기로 하였습니다.

     

    문제의 형식은 사용자에게 입력받은 숫자를 토대로 객체를 생성하고 0을 입력 받으면 정보를 출력하는 형식이였습니다.

    처음에 조원들끼리 코드를 작성하였을 때는 함수형으로 작성하였었으나, 강사님께서는 객체형 프로그래밍 언어 스타일로 작성하셨습니다. 그리고 작성하시면서 말씀하시기를 코틀린은 굳이 클래스를 사용하지 않아도 된다 라고 말씀을 해주셨습니다. 생각을 해보니 자바로 디컴파일 된 코드를 보면 함수를 작성하더라도 결국은 클래스 파일 내 메서드로 변환이 되어 작동되기 때문에 클래스를 생성하지 않아도 된다고 말씀해주셨던 것 같습니다. 그리고 코틀린이 어떤한 언어인지 검색을 해보면 함수형 프로그래밍 언어, 객체형 프로그래밍 언어 모두 지원하므로 사용자의 스타일에 따라 작성법이 조금 달라질 수 있습니다. 라고 알려져 있기도 합니다.

     

    하기 코틀린 코드는 강사님께서 마지막에 내주신 문제를 강사님이 객체형 스타일로 작성하신 스타일을 따라하여 작성한 코드 입니다.

    import java.util.Scanner
    
    fun main (){
    
        //CarFatory에 접근할 변수를 생성한다.
        val carFatoryMgr = CarFatory()
    
        // 사용자에게 입력받기 위해 스캐너를 생성한다.
        val scan = Scanner(System.`in`)
    
        // 사용자에게 입력받은 숫자를 저장할 변수를 생성한다.
        var inputNum = 0
    
        // 자동차를 생성한다.
        // createCar은
        // 0이 아니면 반복적으로 호출한다.
        do{
            println("생산할 자동차를 선택해주세요")
            println("1. 붕붕, 2. 승용차, 3. 버스, 4. 트럭, 0. 생산종료")
    
            // 사용자에게 생산할 자동차의 번호를 입력받는다.
            inputNum = scan.nextInt()
            // 입력 받은 번호가 0이 아니라면 createCar에 입력받은 타입번호를 전달한다.
            if(inputNum != 0){
                carFatoryMgr.createCar(inputNum)
            }
        }while(inputNum != 0)
    
        // 생산된 자동차들의 총 대수와 종류 별 대수를 출력한다.
        carFatoryMgr.printCreateCarCount()
    
        // 생산된 자동차들의 종류를 출력한다.
        carFatoryMgr.printCarInfo()
    
        // 생산된 자동차들의 평균 속도와 총 탑승인원수를 출력한다.
        carFatoryMgr.printAvgspeedSeat()
    
        //연료 종류별 자동차들의 대수를 출력한다.
        carFatoryMgr.fuelKindCount()
    
    }
    
    // 자동차를 생산하는 클래스
    class CarFatory{
        // 생산된 자동차를 저장 할 배열
        val carList = ArrayList<Car>()
    
        // 생산할 자동차의 타입을 입력받는다.
        fun createCar(typeNumber : Int){
            when(typeNumber){
                // 입력받은 타입 넘버에 따라 리스트에 생산한 자동차를 넣어준다.
                1 -> carList.add(Car("붕붕",300,"꽃향기",1))
                2 -> carList.add(Car("승용차",200,"휘발유",4))
                3 -> carList.add(Car("버스",150,"가스",50))
                else -> carList.add(Car("트럭",100,"가스",3))
                // else에는 4를 입력받았을때만 접근한다.
            }
        }
    
        // 생산한 자동차의 대수를 종류별로 출력한다.
        fun printCreateCarCount(){
            //총 생산 자동차 수 : 000대
            println("총 생산 자동차 수 : ${carList.size}대")
    
            // 붕붕의 생산량을 저장할 변수
            var bung = 0
            // 승용차의 생산량을 저장할 변수
            var basic = 0
            // 버스의 생산량을 저장할 변수
            var bus = 0
            // 트럭의 생산량을 저장할 변수
            var truck = 0
    
            // 반복문을 진행하면서 자동차 종류별 변수 값 증가 시킨다.
            for (car in carList){
                when(car.kind){
                    "붕붕" -> bung++
                    "승용차" -> basic++
                    "버스" -> bus++
                    "트럭" -> truck++
                }
            }
    
            //        붕붕 : 00대
            //        승용차 : 00대
            //        버스 : 00대
            //        트럭 : 00대
            println("붕붕 : ${bung}대")
            println("승용차 : ${basic}대")
            println("버스 : ${bus}대")
            println("트럭 : ${truck}대")
            println()
        }
    
    
        // 생산한 자동차의 정보를 출력한다.
        fun printCarInfo(){
            // 생산한 자동차의 정보가 담긴 리스트를 반복하며 자동차의 정보를 출력한다.
            for(car in carList){
                car.printCar()
                println() // 구분 편하기 하려고 사용함.
            }
        }
    
    
        // 생산된 자동차들의 평균속도와 총 탑승인원수를 출력한다.
        fun printAvgspeedSeat(){
            // 스피드를 저장할 변수
            var speedTotal = 0
            // 타습인원수를 저장할 변수
            var seatCount = 0
    
            // 리스트에 저장된 시트 수와 스피드를 누적한다.
            for(car in carList){
                seatCount += car.seat
                speedTotal += car.maxSpeed
            }
    
            // 평균을 구한다.
            val speedAvg = speedTotal / carList.size
            val seatAvg = seatCount / carList.size
    
            println("생산된 자동차들의 평균 속도 : ${speedAvg}km/h")
            println("생산된 자동차들의 총 탑승인원수 : ${seatAvg}명")
            println()
    
        }
    
        // 연료 별 자동차의 수를 출력한다.
        fun fuelKindCount(){
            // 각 연료별 저장할 변수 선언
            var flower = 0
            var gasoline = 0
            var gas = 0
            // 반복문을 진행하면서 자동차의 연료에 따라 변수에 값을 누적한다.
            for(car in carList){
                when(car.fuel){
                    "꽃향기" -> flower++
                    "휘발유" -> gasoline++
                    "가스" -> gas++
                }
            }
    
    //        연료가 꽃향기인 자동차의 수 : 00대
    //        연료가 휘발유인 자동차의 수 : 00대
    //        연료가 가스인 자동차의 수 : 00대
    
            // 출력형식에 맞게 각 연료별 자동차의 수를 출력한다.
            println("연료가 꽃향기인 자동차의 수 : ${flower}대")
            println("연료가 휘발유인 자동차의 수 : ${gasoline}대")
            println("연료가 가스인 자동차의 수 : ${gas}대")
            println()
    
    
    
        }
    
    
    }
    
    // 자동차 클래스 생성
    
    //종류 : 트럭
    //최대속도 : 100km/h
    //연료 : 가스
    //탑승인원수 : 3명
    
    class Car(val kind:String, val maxSpeed : Int, val fuel: String, val seat: Int){
    
        // 자동차 클래스의 멤버변수를 출력하는 메서드
        fun printCar(){
    //        println("""종류 : $kind
    //            | 최대속도 : ${maxSpeed}km/h
    //            | 연료 : $fuel
    //            | 탑승인원수 : ${seat}명
    //        """.trimIndent())
            println("종류 : $kind")
            println("최대속도 : ${maxSpeed}km/h")
            println("연료 : $fuel")
            println("탑승인원수 : ${seat}명")
    
        }
    
    }
Designed by Tistory.