5월, 2023의 게시물 표시

Kotlin as 연산자

이미지
Kotlin as 연산자 객체를 지정된 클래스 타입으로 변환하는 연산자이다. 참조 변수 as 클래스 타입 만약 객체가 지정된 클래스타입과 관계가 없을 경우 오류가 발생한다. 형 변환이 발생한 참조 변수는 변환된 타입을 유지한다. as 연산자 여기서 변수는 형변환을 수행하려는 변수이고, 타입은 변수를 변환하려는 타입입니다. as 연산자를 사용하여 변수를 다른 타입으로 변환하면, 변수는 해당 타입으로 강제로 변환됩니다. 명시적 형변환 Kotlin에서 as 연산자는 명시적으로 변수의 타입을 변환하기 위해 사용됩니다. as 연산자를 사용하여 변수를 다른 타입으로 변환할 수 있습니다. 이는 명시적 형변환이라고도 합니다. fun main () { val obj1:SubClass1 = SubClass1() val super1:SuperClass1 = obj1 // SubClass1 으로 명시적 형변환을 하지 않으면 subMethod1 을 사용할 수 없다 . // super1 as SubClass1 // 주석을 해제 하면 Error가 해결된다. super1.subMethod1() // Error } open class SuperClass1 interface Inter1 class SubClass1 : SuperClass1() { fun subMethod1 () { println ( "subMethod1" ) } } class SubClass2 : Inter1 Kotlin: Unresolved reference: subMethod1 fun main () { val obj1:SubClass1 = SubClass1() val super1:SuperClass1 = obj1 super1 as Inter1 // Runtime Error } open class SuperClass1 interface Inter1 class SubClass1 : SuperClass1() { fu

Kotlin 형변환

Kotlin 형변환 변수에 담긴 값이나 객체를 다른 형태로 변환하는 것을 의미한다. Kotlin 은 모든 값을 객체로 관리하기 떄문에, Kotlin 에서의 형변환은 다른 클래스 타입의 객체로 변환하는것을 의미한다. 스마트 캐스팅 Java에서 자동형변환이라고 부르는 개념이다. 특정 조건을 만족하면 자동으로 형변환이 발생하는 개념이다. 스마트 캐스팅 기능 덕분에 형변환에 대해 개발자가 크게 신경을 쓰지 않아도 된다. 형 변환은 객체의 클래스 타입이 아닌 객체의 주소 값을 가지고 있는 참조 변수의 타입이 변경되는 것이다. 객체 타입 변환 객체의 타입변환은 상속관계나 구현한 인터페이스 타입에 해당한다. 부모클래스의 타입으로 형변환 fun main () { val obj1:SubClass1 = SubClass1() val obj2:SubClass2 = SubClass2() // 부모클래스 타입 참조 변수에 담는다 . val super1:SuperClass1 = obj1 } open class SuperClass1 interface Inter1 class SubClass1 : SuperClass1() class SubClass2 : Inter1\ 구현한 인터페이스 타입으로 형변환 fun main () { val obj1:SubClass1 = SubClass1() val obj2:SubClass2 = SubClass2() // 부모클래스 타입 참조 변수에 담는다 . val inter1:Inter1 = obj2 } open class SuperClass1 interface Inter1 class SubClass1 : SuperClass1() class SubClass2 : Inter1 구현한 인터페이스 타입으로 형변환 fun main () { val obj1:SubClass1 = SubClass1() val obj2:SubClass2 = SubClass2() val super1:Su

Kotlin - JetPack Compose Desktop Application 개발 기초

Kotlin - JetPack  Compose Desktop Application 개발 기초 Kotlin Jetpack Compose Desktop는 Kotlin 언어로 작성된 데스크톱 애플리케이션을 개발하기 위한 프레임워크입니다. 이를 사용하면 선언적 UI 프로그래밍 방식을 통해 사용자 인터페이스를 구축할 수 있습니다. Jetpack Compose Desktop은 Android용 Jetpack Compose의 데스크톱 버전으로, Android 앱이 아닌 일반적인 데스크톱 플랫폼에서 작동하는 애플리케이션을 만들 수 있습니다. 아래는 Kotlin Jetpack Compose Desktop 애플리케이션을 개발하기 위한 기초 단계입니다. 개발 환경 설정  1. IntelliJ IDEA - 2022.3.3  2. Kotlin -   3. JetPack Compose - 1.0.0  4. JDK - Amazon Correctoo 18.0.2 프로젝트 생성  1. File - New - Project  2. Compose Multiplatform  - name , location, configuration : Signal Platform.  - JDK 18 버젼 선택 및 다운로드  - Compose , gradle 빌드 시 , JDK 18 버젼이 필요하다.  

Kotlin Null 처리

null 처리 NullPointerException Java 언어로 소프트웨어를 개발하다 보면 NullPointerException 에러를 자주 만나게된다. 이는 객체의 주소값이 담겨져 있지 않는(null 값이 들어있는) 참조 변수를 통해 객체 접근을 시도하면 발생되는 오류이다. null safe  Kotlin 은 개발자가 null 이 담겨 있는 참조변수를 통해 객체 접근을 시도할때 오류가 발생되는 것을 방지하고자 다양한 방법을 제공하고 있다.  이를 통해 null 값에 대한 안정성을 확보 (null safe) 할 수 있다. ?: 연산자 ?: 연산자는 참조변수에 null 이 들어있으면 지정된 기본값을 반환한다. ?: 연산자는 nullable 타입 변수가 null인 경우 대체(default) 값을 지정하는 데 사용됩니다. 이 연산자를 사용하여 null인 경우 대체 값을 제공할 수 있습니다. fun main () { testFun1 ( " 문자열 " ) testFun1 ( null ) } fun testFun1 (str:String?) { val value1:String = str ?: " 기본문자열 " println (value1) } // 결과 문자열 기본문자열 ?. 연산자  참조 변수를 통해 메서드를 호출하거나 멤버 변수를 사용할 떄 참조 변수에 객체의 주소값이 들어있다면 객체에 접근해서 메서드나 변수를 사용한다. 만약 참조 변수에 null 이 들어 있다면 오류가 발생하지 않고 null 을 반환한다. ?. 연산자는 nullable 타입 변수 또는 객체에 접근할 때 사용됩니다. 해당 변수가 null이 아닌 경우에만 프로퍼티나 메소드에 접근하며, null인 경우에는 접근 대상을 null로 반환합니다. fun main () { testFun1 ( " 문자열 " ) testFun1 ( null ) } fun testFun1 (str:String?) { printl

Kotlin 중첩 클래스

Kotlin 중첩 클래스 중첩 클래스 클래스안에 만드는 클래스를 중첩클래스라고 부른다. 중첩 클래스에서는 각 클래스의 정의한 멤버를 사용할 수 있는가를 숙지 해야 한다. Inner 클래스는 OuterClass의 멤버변수를 사용하기가 쉬워진다. class Outer1 { inner class Inner { } } Inner Class , Outer Class 내부클래스는 외부 클래스로 부터 생성된 객체를 통해서만 객체 생성이 가능하다. 외부클래스는 내부클래스의 멤버를 자유롭게 사용할 수 없지만, 내부 클래스는 외부 클래스의 멤버를 자유롭게 사용할 수 있다. fun main () { var obj2 = Inner1() // Error } class Outer1 { inner class Inner1 { } } Kotlin: Unresolved reference: Inner1 내부클래스를 직접적으로 객체를 생성할 수 없기때문에, 에러가 발생한다. fun main () { var obj1 = Outer1() var obj2 = obj1.Inner1() } class Outer1 { inner class Inner1 { } } 외부클래스의 객체를 먼저 생성한뒤, 내부 클래스의 객체를 생성 할 수 있다. fun main () { var obj1 = Outer1() var obj2 = obj1.Inner1() } class Outer1 { val outerMember1 = 100 fun outerMethod1 () { println ( "Outer Method" ) println(innerMember1) // Error innerMethod1() // Error } inner class Inner1 { val innerMember1 = 100 fun inner

Kotlin 가변성

Kotlin 가변성 불변성 : 제너릭이 설정된 객체의 주소 값을 같은 타입의 제네릭이 설정된 변수에만 담을 수 있다. 공변성 : 제네릭이 설정된 객채의 주소 값을 부모 클래스 타입의 제네릭이 설정된 변수에도 담을 수 있다. 반 공변성 : 제네릭이 설정된 객체의 주소 값을 자식 클래스 타입의 제네릭이 설정된 변수에도 담을 수 있다. 불변성(무변성)  불변성 (Invariant): 기본적으로 제네릭 타입은 불변성입니다. 불변성은 타입 간에 하위 타입 관계가 없음을 의미합니다. 즉, List<String>은 List<Any>의 하위 타입도 상위 타입도 아닙니다. 이는 제네릭 타입이 완전히 독립적으로 동작하고 서로 호환되지 않는 것을 의미합니다. fun main () { var obj1:TestClass1<SubClass1> = TestClass1<SubClass1>() var obj2:TestClass1<SubClass2> = TestClass1<SubClass1>() // ERROR } open class SuperClass1 open class SubClass1 : SuperClass1() class SubClass2 : SubClass1() class TestClass1< T >() Kotlin: Type mismatch: inferred type is SubClass1 but SubClass2 was expected Kotlin: Type mismatch: inferred type is TestClass1<SubClass1> but TestClass1<SubClass2> was expected  클래스가 상속 관계 이더라도, 타입에는 하위 관계가 없기 때문에, 동일한 타입을 사용해야 한다. 이러한 오류는 주로 제네릭 클래스나 함수를 다룰 때 발생하며, 기대하는 제네릭 타입 매개변수와 다른 타입의 값을 할당하려고 할 때 발생한다. 공변성  공변성은 제

Kotlin Generic

Kotlin Generic  클래스를 만들 때, 변수를 선언하겠다고하면, val , var 를 적고, 타입을 적거나 적지 않을 수 있다. 변수를 정의를 할때는 타입을 명시적, 비명시적이라도 정의해야 한다.  자료형을 클래스를 선언할때 정하는것이 아니라, 객체를 생성할 때 결정하도록 하는것이 Generic 이다.  클래스를 설계할 때 변수의 타입을 유동적으로 할고 싶을 때 사용한다.   Generic 효과  코틀린에서의 제네릭(Generic)은 타입 매개변수(Type Parameter)를 사용하여 클래스, 함수 또는 인터페이스를 정의할 때 일반화된 타입을 지정하는 기능입니다. 이를 통해 코드의 재사용성과 타입 안정성을 개선할 수 있습니다.  제네릭을 사용하면 클래스나 함수를 선언할 때 특정 타입이 아닌 일반적인 타입을 사용하며, 사용할 때 실제 타입을 지정할 수 있습니다. 예를 들어, List<T>는 요소의 타입을 T로 지정하는 리스트를 나타냅니다. 이렇게 선언된 제네릭 타입은 여러 종류의 타입에 대해 동작할 수 있습니다. fun main () { var t1 = TestClass1<Int>() t1.testMethod1( 100 ) var t2 = TestClass1<String>() t2.testMethod1( " 문자열 " ) } class TestClass1< T > { fun testMethod1 (a1: T ) { println (a1) } }  위의 예제에서 <T>는 타입 매개변수로, 어떤 타입이든 받을 수 있습니다. 함수를 호출할 때 실제 타입을 지정하여 사용할 수 있습니다:  <T> 에는 아무런 문자열이 와도 되나, 일반적으로 generic 을 나타내기 위해서는 대문자 T를 사용한다.

Kotlin Data Class

Kotlin Data Class DataClass는 매개체의 데이터를 관리하는 용도로 사용하느 클래스이다. abstract, open, sealed, inner 클래스로 정의할 수 없다. 반드시 주 생성자를 가지고 있어야 한다. DataClass 를 사용하면 몇가지 메소드를 기본적으로 추가해서 사용상의 용이하게 할 수 있다. Data Class의 메서드 equals : 객체가 가지고 있는 변수를 모두 비교하는 메서드 hashCode : 객체를 구분ㄴ하기 위한 고유한 정수값 copy : 객체를 복제하는 메서드 toString : 객체가 가지고 있는 변수의 값을 출력 componentN : 객체 분해  이러한 메서드들이 자동으로 오버라이딩되어서 추가된다. data class TestClass { } data class는 위와 같이 class 앞에 data를 붙여준다. data class는 무조건 주 생성자가 있어야 하므로 없으면 아래와 같은 에러가 발생한다. Kotlin: Data class must have at least one primary constructor parameter abstract data class TestClass2( var a1 :Int , var a2 :Int) { } open data class TestClass2( var a1 :Int , var a2 :Int) { } Kotlin: Modifier 'abstract' is incompatible with 'data' Kotlin: Modifier 'open' is incompatible with 'data' 또한, data class는 abstract, open 등의 추상크래스, 부모 클래스로 선언될 수 없다. Data Class 의 toString fun main () { var obj1 = TestClass1( 100 , 200 ) var obj2 = TestClass2( 100 , 200 )

Kotlin Companion

Kotlin Companion 정적 멤버 클래스를 정의할 때 변수나 메서드를 정적 멤버로 정의하면 객체를 생성하지 않고 사용할 수 있다. Java 에서는 static 을 사용하는데, Kotlin은 Companion 객체를 사용한다. 같은 클래스를 통해서 만든 객체들이 같은 멤버 변수를 사용한다면 공통적으로 한가지 값만 사용할 때 정적 멤버를 사용한다. fun main () { TestClass.testFun1() // Error } class TestClass { val a1 = 100 fun testFun1 () { println ( "testFun1" ) } } Kotlin: Unresolved reference: testFun1 Class 를 정의하고 그 Class 에 대한 객체 (Instance)를 생성하지 않고 함수를 사용하고자 할 때 에러가 발생한다. fun main () { var obj1 = TestClass() println (obj1. a1 ) obj1.testFun1() println(obj1.a2) // Error } class TestClass { var a1 = 100 companion object { var a2 = 1000 fun testFun2 () { println ( "testFun2" ) } } fun testFun1 () { println ( "testFun1" ) } } Kotlin: Unresolved reference: a2  companion object 로 정의된 a2 멤버변수는 객체 참조 변수를 통해서 접근할 수 없다. fun main () { var obj1 = TestClass() println (obj1. a1 )

Kotlin Interface

Kotlin Interface  Kotlin은 다중 상속을 지원하지 않는다.  특정 클래스를 동시에 두개 이상의 클래스를 상속 받는것을 의미한다.  이 때문에 자기 타입의 변수나 부모형 타입 변수에만 담을 수 있다.  만약, 생성된 객체의 주소 값을 다양한 타입에 변수에 담을 수 있도록 한다면 인터페이스를 활용하면 된다. Interface 여러 부모 클래스를 상속을 받아서 하나의 클래스에 모으고 싶을 때 사용한다. 인터페이스는 클래스가 아니므로 객체를 생성할 떄 사용할 수 없다. 단, 클래스는 한개 이상의 인터페이스를 구현할 수 있으며, 생성된 객체는 구현한 인터페이스형 참조 변수에 담을 수 있다. 인터페이스에는 추상 메서드와 일반 메서드 모두를 구현해서 사용할 수 있다. 인터페이스는 추상 클래스의 목적이 비슷하지만, 하나의 클래스에 여러 인터페이스를 구현할 수 있는 장점을 가지고 있다. fun main () { val obj1 = Inter1() // Error } interface Inter1 { fun inter1Method1 () { println ( "Inter1 의 interMethod1 입니다 ." ) } fun inter1Method2 () } 인터페이스는 객체를 생성 할 수 없으므로, 에러가 발생한다. Kotlin: Interface Inter1 does not have constructors interface Inter1 { fun inter1Method1 () { println ( "Inter1 의 interMethod1 입니다 ." ) } fun inter1Method2 () } class TestClass3: Inter1() { // Error } 인터페이스는 클래스가 아니므로 상속 받는것처럼 () 를 붙이면 안된다. Kotlin: Class 'TestClass3' is not abstract and doe

Kotlin 추상클래스 Abstract Class

Kotlin 추상클래스 추상 메서드는 구현되지 않은 메서드를 의미한다. 추상 클래스는 추상 메서드를 가지고 있는 클래스를 의미한다. 추상 클래스는 구현 되지 않은 추상메서드를 가지고 있기 때문에 완벽한 설계도라고 할 수 없다. 이 때문에 추상클래스를 통해서는 객체를 생성할 수 없다. 상속을 통해서 구현가능하다. 추상 클래스의 상속 추상 클래스는 완벽한 클래스가 아니기 때문에 객체를 생성할 수 없다. 객체를 생성하려면 추상 클래스를 상속받은 클래스를 만들고 추상 메서드를 구현하여 자식클래스를 통해 객체를 생성해야 한다. 추상 클래스의 목적은 자식 클래스에서 메서드를 Overriding 을 위한 클래스이다. fun main () { val obj1 = Super1() // 추상클래스는 직접 객체를 생성할 수 없으므로 여기서 에러가 발생한다. testFun1 (obj1) } open abstract class Super1 { fun method1 () { println ( "Super1 의 method1 입니다 ." ) } open abstract fun method2 () } Kotlin: Cannot create an instance of an abstract class 추상 클래스 사용 자식 클래스에서 메서드를 Overriding 을 강제하기 위해서 사용한다. 구현되지 않은 메서드를 추상 메서드라고 부르며, 추상 메서드를 가지고 있는 클래스를 추상 클래스라고 부른다. fun main () { val obj1 = Sub1() testFun1 (obj1) } open abstract class Super1 { fun method1 () { println ( "Super1 의 method1 입니다 ." ) } open abstract fun method2 () { println ( "Super1 의 me

Kotlin this, super

Kotlin this, super this 객체 자기 자신을 지칭한다. 멤버 변수와 메서드 내부의 변수를 구분할 때 사용한다. 멤버 메서드와 메서드 내부의 메서드를 구분할 떄 사용한다. 생성자에서 다른 생성자를 호출할 때 사용한다. fun main () { val obj1 = TestClass1() obj1.testMethod1() } class TestClass1 { var a1 = 100 fun testMethod1 () { var a1 = 200 println ( "a1 : $ a1 " ) println ( "this.a1 : $this .a1" ) } } this는 객체 자신을 의미하기때문에, 클래스 자체의 멤버변수 100 을 출력한다. 코틀린에서는 메서드 안에 메서드를 만드는게 가능하다. fun main () { val obj1 = TestClass1() obj1.testMethod1() } class TestClass1 { var a1 = 100 fun testMethod1 () { fun testMethod2 () { println ( "testMethod1 내부의 testMothod1" ) } testMethod2() // 내부 함수 호출 this .testMethod2() // 클래스 멤버의 메서드 호출 } fun testMethod2 () { println ( "testMethod2" ) } }  근데, 누가 이렇게 쓸까, 동일클래스에서 클래스 멤버변수랑 메서드 내부 멤버변수의 이름을 동일하게 하거나, 클래스 멤버 메서드랑 내부 멤버 메서드 이름을 동일하게 할 경우는 없을 것으로 생각된다.  아마 정적검사툴이나 보안체크툴에서

Kotlin Any

이미지
Kotlin Any  Kotlin 에서 사용하는 모든 클래스의 부모 클래스이다.  Kotlin은 클래스를 작성할 떄, 상속받지 않는다면 자동으로 Any 클래스를 상속받는다.   Any 클래스에는 모든 객체가 가지고 있어야할 메서드가 제공되고 있으며, 이 메서드들을 overriding 하여 각 클래스의 성격에 맞게 재 구현하여 사용 할 수 있다.  Kotlin 은 직간접적으로 Any를 상속 받고 있기때문에,  Any 가 가지고 있는 메서드를 사용할 수 있다. Kotlin Any 공식 메서드  https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-any/  따라서, Kotlin 의 모든 Class 는 toString, equals 같은 기본적인 class 의 메서드를 사용할수 있다.  모든 클래스는 Any 클래스를 상속받고 있기때문에, 부모클래스 참조 변수를 통해서 모든 클래스를 통합해서 매개변수로 받을 수 있게 된다.

Kotlin Overriding

Kotlin Overriding  Kotlin의 모든 객체는 부모 클래스형 참조 변수에 담을 수 있다. 부모 클래스형 참조 변수를 사용하면 부모 클래스에 정의되어 있는 멤버만 사용이 가능하다. fun main () { val obj1:SubClass1 = SubClass1() val obj2:SuperClass1 = obj1 println ( " ${ obj2. superA1 } " ) obj2.superMethod1() println ( " ${ obj2.subA1 } " ) // obj2 는 SuperClass 참조 변수이므로 , obj1 으로 선언을 했더라고 , 부모클래스의 멤버 변수 함수만 사용가능하다 . obj2.subMethod1() } open class SuperClass1{ var superA1 = 100 fun superMethod1 (){ println ( "SuerMethod1" ) } } class SubClass1 : SuperClass1() { var subA1 = 200 fun subMethod1 () { println ( "SubClass" ) } } Kotlin: Unresolved reference: subA1 Overriding  부모클래스가 가지고 있는 메서드를 자식 클래스에서 재 정의하는 개념이다. 부모가 가지고 있는 메서드의 이름, 매개 변수 형태 모두 동일해야 한다. fun main () { val obj1:SubClass1 = SubClass1() println (obj1. superA1 ) obj1.superMethod1() } open class SuperClass1{ var superA1

Kotlin 지연 초기화

Kotlin 지연 초기화  Kotlin은 변수를 선언할 때 값을 무조건 설정해야 하는데, 이를 지연시키는 것을 지연 초기화라고 한다. 변수 초기화  var v1 Kotlin: This variable must either have a type annotation or be initialized  코틀린은 변수를 초기화 하지 않고 그냥 선언만 하게 될 경우, 해당 변수에 어떤 타입이 들어올지 예상하지 못하므로, 타입을 기재를 해주던지, 초기화를 수행해주어야 한다. var v1:Int or var v1 = 100  으로 사용해주어야 한다. Property 초기화  main 함수 내에서는 타입만 지정해도 되지만, 클래스 내부에서는 변수가 Property 로 자동 지정이 되므로, 추상화또는 초기화를 해주어야 한다. fun main () { var a1:Int // No Error val obj = TestCalss1() } class TestCalss1{ var a1:Int // Error / Kotlin: Property must be initialized or be abstract } Kotlin: Property must be initialized or be abstract Class Init  init 메서드를 통해서 변수 초기화를 할 수 있다. 그러나, 변수 선언시 타입은 명시 해주어야 한다. fun main () { val obj1 = TestCalss1() println ( "obj1.a1 : ${ obj1. a1 } " ) } class TestCalss1{ var a1 = 100 // 타입 생략이 가능하다 . var a2 // 타입 생략이 불가능 하다 . 타입을 추론하지 못하기 때문에 init { a2 = 100 } } lateinit  var 로 선언된 변수의 초기화를 뒤로 미룰 수 있다.  변수의 값을 사용하기 전에 반드시 초기화가