Strong 감자의 공부

Ch02_ 코틀린에서는 모든것이 객체이다. 본문

문법_Kotlin

Ch02_ 코틀린에서는 모든것이 객체이다.

ugyeong 2023. 7. 19. 19:27

책 : 개발자를 위한 Kotlin 프로그래밍 A to Z 

 

읽다가 헷갈리는 문법들에 대해선 링크 달아두었습니당!

링크 단것들에 대해 다 설명을 달려다가,,, 글이 너무 길어지기도하고 후반부에도 다룰것이므로 링크만 걸어둡니당!

 

실습은 Intelij로 하였습니다. 

build.gradle.kts 파일 -> dependencies 블록 안에 아래한줄 추가해야 코틀린 객체 확인이 가능했습니다.

dependencies {
...
    implementation(kotlin("reflect"))
}

1 . 객체

  • 코틀린은 모든것을 객체로 처리하고 객체에는 해당하는 클래스가 있다.
    • 객체의 클래스를 확인하는 방법
    class Exp {
    	val h = "hello"
    }
    
    fun main() {
    	val c = Exp().h
    	println(c.javaClass.kotlin)
    }

✔️ 안드로이드 스튜디오에서 kotlin으로 액티비티를 넘길때 ::class.java로 하는 이유

더보기

::class는 코틀린에서 사용되는 KClass를 반환한다. 그래서

::class.java라고 해야 자바에서 사용되는 Class로 반환해 줍니다.

✔️ kotlin :: (더블클론, 리플렉션)

더보기

객체를 통해 클래스의 정보를 분석해 내는 프로그래밍 기법

구체적인 클래스 타입을 알지 못해도 그 클래스의 메소드, 타입, 변수들에 접근할 수 있다.

즉, 컴파일 시간이 아니라 런타임에 동적으로 특정 클래스의 정보를 객체화하여 분석 및 추출해낼 수 있는 프로그래밍 기법이다.

->리플렉션을 왜 사용하는지

정적 언어로의 한계점(구체적인 틀래스를 모르면 해당 클래스 정보에 접근이 불가)을 보완 구체적인 클래스를 알지 못해도 런타임 도중 해당 클래스의 정보에 접근할 수 있도록 해주는 것이 Reflection 이다.

https://velog.io/@spdlqjfire/Reflection → 나중에 다시 읽어보기 

https://medium.com/harrythegreat/코틀린의-더블콜론-참조-73ff25484586

 

2. 객체 표현과 주석

 

🔶객체 표현

  • 숫자 100, 문자 ‘가’등은 리터럴 표기법으로 작성하면 객체이면서 값으로 사용한다.
  • 정수는 기본이 Int클래스의 객체이다. / Long클래스의 객체 표현: 100L(혹은 l)
  • 실수는 기본이 Double클래스의 객체이다. / float 클래스의 객체 표현 : 100.0F
  • 코틀린은 각 클래스의 자료형을 별도로 관리한다
  • 메서드 : 클래스 내부에 정의한 함수고 객체가 점연산자로 접근해 실행
  • 함수 : 함수이름과 호출자로 실행
  • 연산자 : 예) + -… 100+100 이렇게 표기해도 내부에선 해당 메서드 100.plus(100)으로 변환해 처리

🔶주석

🔶 문자열

  • charArrayOf('가', '을').contentToString()
    • charArrayOf(문자들 ):문자를 인자로 받아 배열을 만듦
    • .contentToString() :배열 내부 원소 출력
    • var str = String(charArrayOf('가', '을' ))
fun main() {
	println('가'.javaClass.kotlin)
	println(charArrayOf('가','을').contentToString())
	var str =String(charArrayOf('가','을'))
	println(str)
}

  • 문자열 탬플릿을 사용해서 문자열로 변환해 출력
fun main() {
	val date = "20200101"
	val a = 100
	val b = 200
	println("날짜 :$date")
	println("100 +200 = ${a + b}")
}

  • 이스케이프 문자 (\이용)
  • (예를 들어 “” ‘’ 는 각각 문자열, 문자로 인식을 할 수있는데 \이스케이프 문자를 통해 “는 문자 자체라는걸 알려줄 수 있다.)
    • \’ : 작은 따옴표 표현
    • \” : 큰따옴표
    • \/ : 슬래시
    • \\ : 역슬래시
fun main() {
	val date = "20200101"
	println("날짜\\ :$date")

}

  • \n : 다음줄 이동
  • \r: 캐리지 리턴이라고 하는데 \r 앞에 단어들이 다 사라지는거 같다.
fun main() {
	val date = "20200101"
	println("날짜\r :$date")

}

  • \t: 탭
  • \b: 백스페이스
fun main() {
	val date = "20200101"
	println("날짜\b :$date")

}

 

  • 원시 문자열 처리
    • “”” “”” 를 이용하면 이스케이프 문자들을 그대로 인식함.
    • “”” “”” 안에 문자열 탬플릿${} 기능 추가 가능
fun main() {
	val date = "20200101"
	println("""\n날짜 :$date""")

}

  • 형식문자 포매팅
    • $s : 문자열 처리
    • %d : 정수처리
    • % f : 실수 처리
    • %e : 실수를 지수로 표기
    • %x : 정수를 16진수로 표기
    • %6.2f : 전체 실수는 6자리, 그중 소수점 이하는 2자리
      • format이용한 코드
fun main() {
	val float =123.4
	val int =100
	val string = "문자열"
	val edec= 10e5 // 지수 표현 10*10^5
	val hex = 0xffff // 16진수

	println("float = %6.2f, int =%6d, string = %10s".format(float,int,string))
	println("edec = %e , hex= %x".format(edec, hex))
}

 

03.값을 저장하는 변수와 상수

 

  • 변수는
    • 예약어 val, var 사용
    • 변수이름을 작성시 소문자나 _스코어로 시작
    • 카멜표기법 예 ) firstWord 두번째단어는 대문자
  • 상수는
    • const val예약어 사용
    • 패키지나 objeect 예약어를 사용하는 곳에서만 정의 가능
    • 변수와 구별하기 위해 상수 이름은 모두 대문자
  • 파스칼표기법( 예) StudentFragment(첫글자, 다시 시작하는 단어의 첫글자 대문자) → 클래스, Object, 인터페이스 명을 지을떄
  • 스네이크 표기법 예) const val GLOBAL_SCORE : 보통 상수는 모두 대문자로 쓰지만 ,단어 연결시 _이용하기도 한다.
  • 지역변수와 전역변수
    • 전역변수 : 코틀린은 패키지 단위로 관리하므로 패키지단위에 정의된 최상위 변수
      • var 로 선언된 전역변수는 {} 지역영역 즉 함수내부나 for순환내부 등에서 변경할 수 있다.
    • 지역변수: 함수코드 블록인 {} 사이에 정의해서 사용하는 변수
      • 외부에서 참조 할 수 없다. = 서로 다른 코드블록안에 같은 이름의 지역변수를 만들 수 있고 각각 안에서 참조된다.
fun main() {
    for(i in 1.. 2){
	val localVal = 100
	println("for 지역변수" + localVal)
    }
    
    for(i in 1.. 2){
	val localVal = 200
	println("for 지역변수" + localVal)
    }
}

위의 사진처럼 지역변수는 외부에서 참조 할 수 없지만 클로저 환경을 구성할 땐 외부 접근 허용

(클로저 환경이란?https://jaeyeong951.medium.com/java-클로저-vs-kotlin-클로저-c6c12da97f94 )

  • 변수 정의 시 자료형
    • 예) val a : String =”abc”
    • 자료형에는 클래스, 추상클래스, 인터페이스가 올 수 있다.
    • 자료형 지정하지 않으면 처음 할당된 값을 보고 자료형을 확정한다.
    • 두번째 할당될 경우 같은 자료형이 아니면 예외를 발생
  • 변수와 속성의 차이
    • 코틀린에서 지역변수만 변수이고 나머진 다 속성이다
    • 이 말은 자바엔 getter와 setter가 있는데 코틀린은 자동으로 getter와 setter가 구현돼 있다는 말같다. (하지만 상황에 따라 getter, setter 정의 가능하다.)
    • +Object
class Exp {
	val memberVal: Int =100 //  클래스 속성
}
object Obj{
	val objval =100 // 객체 속성
}

fun main() {
	val k = Exp()
	println(k.memberVal) // 객체 인스턴스 생성 후 접근
	println(Obj.objval) // 객체 이름으로 접근 
}

https://www.bsidesoft.com/8187

 

[kotlin] Companion Object (1) - 자바의 static과 같은 것인가? - Bsidesoft co.

개요 코틀린(Kotlin)의 Companion object는 단순히 자바(Java)의 static 키워드를 대체하기 위해서 탄생했을까요? 이 갑작스러운 질문은 코틀린에서 왜 static을 안 쓰게 되었는지 이해하는 데 큰 도움이 될

www.bsidesoft.com

https://medium.com/depayse/kotlin-%ED%81%B4%EB%9E%98%EC%8A%A4-10-object-%ED%82%A4%EC%9B%8C%EB%93%9C%EC%9D%98-%EC%82%AC%EC%9A%A9-d7fe736a3dcb

 

[Kotlin] 클래스 10— object 키워드의 사용

Kotlin에서 object 키워드의 의미와 여러 가지 사용, 그리고 상수를 정의하고 사용하는 방법에 대해 다룹니다.

medium.com

  • 타입변환
    • 기본 자료형인 숫자나 문자열에 자료형 변환 메서드가 있어 이를 사용해 타입을 변환할 수 있다.
fun main() {
	var number = 10000
	var longNumber= 10L
	longNumber = number.toLong()
	println(longNumber.javaClass.kotlin)
}

  • 다른 객체인 경우 as 예약어를 통해 자료형을 변환한다.
  • 일반적으로 캐스트가 불가능한 경우 캐스트 연산자는 예외를 발생시킨다. 따라서 안전하지 않다고 한다. 코틀린의 안전하지 않은 캐스트는 중위 연산자 as에 의해 수행된다. 예외를 방지하려면 as?와 같이 사용한다. 실패 시 null을 리턴한다.
  • https://yiyj1030.tistory.com/248
 

[코틀린 Kotlin] 여러가지 형변환 및 is, as 사용법

is : 자료형 체크 as : 자료형 변환 val input1:Any = "안녕" if ( input1 is String){ // is로 자료형 체크,Int, Float, String 등이 사용가능, // !is String은 String이 아닌 자료형을 의미! val output2:String = input1 as String //

yiyj1030.tistory.com

  • 정수 자료형이 다른 경우에도 리터럴 표기법에서 계산 가능
  • 대신 계산한 값이 상위 자료형이므로 변수에 할당하면 최종 처리된 결과인 자료형으로 확정
fun main() {
	var number = 10000
	var longNumber = 10L
	var result = number + longNumber

	println(result.javaClass.kotlin)
}

 

04. 계산 연산자

  • 사칙 연산처리
  • 표현식                                   내부적 실행 
    a+b a.plus(b)
    a-b a.minus(b)
    a*b a.times(b)
    a/b a.div(b)
    a%b a.rem(b) , a.mod(b)
  • 할당복합
  • 연산자표현식                                  내부적 실행
    a+=b a.plusAssign(b)
    a-=b a.minusAssign(b)
    a*=b a.timesAssign(b)
    a/=b a.divAssign(b)
    a%=b a.modAssign(b)
  • 단항 연산자
  • 연산자                      표현식                               메서드전환
    + +a a.unaryPlus()
    - -a a.unaryMinus()
    ! !a a.not()
    ++ ++a a.inc()
    —a a.dec()
    (안드로이드스튜디오에서 변수명.inc()로 한줄로 깔끔하게 쓰는거 같아서 알아둬야할거같다.
  • 예 )_currentWordCount.value = _currentWordCount.value?.inc() )
  • 연산자를 추가로 사용하는 경우
    •  연산자오버로딩 -> operator 예약어 추가해야함  
      • 문자열 등에도 덧셈연산자를 사용할 수 있다. 이때 덧셈연산자는 문자열을 결합하는 용도로 사용할 수 있다.
      • 아래는 덧셈연산자가 문자열에 재정의 되어있어 문자열에서 연산자 사용한 예이다.
fun main() {
	val start = "온고"
	val middle = "지신"
	val end= "-공자"
	val result = start+middle+end
	println(result)
}

 

fun main() {
	val number =listOf("one","two")
	val plusList = number+"five"
	val minusList= number-listOf("one")
	println(plusList)
	println(minusList)
}

  • 사용자 정의 클래스를연산자의 메서드 이름으로 재정의 하면 연산자 기호를 사용할 수 있다.
    •  plus를 - 로 재정의 하였다.
    • 이때 재정의 함수는 클래스의 멤버 여야한다. 
import kotlin.math.min

class Exp(val fir:Int){
}
operator fun Exp.plus(sec:Int) : Int = fir-sec // 재정의

fun main() {
	val exp : Exp = Exp(5)
	val result :Int = exp + 3 // 값은 5-3
	print(result)
}

  • 비트 연산자 처리
연산자 설명
shl 이진수를 왼쪽으로 이동
shr 이진수를 오른쪽으로 이동
ushr 부호없는 이진수 오른쪽이동
and(&) 같을 때 1 다르면 0
or(\) 하나라도 1 이면 1
xor(^) 서로다르면 1 같으면 0
inv 비트를 반전시키는 연산
   
fun main() {
    val bit1 :Int =17
    val bit2 :Int = 0b1111
    println(bit1.toString(2))
    println("${bit1} xor ${bit2} = "+( bit1 xor bit2))
    println((bit1 xor bit2).toString(2))
}

fun main() {
	val bit1 :Int =17
	val bit2 :Int = 0b1111
	println("bit 1 이진수 "+bit1.toString(2))
	println("${bit1} xor ${bit2} = "+( bit1 xor bit2))
	println("${bit1} xor ${bit2} = "+(bit1 xor bit2).toString(2))
	println("bit1 shiftLeft = ${bit1.shl(2).toString(2)}")
	println("bit1 shiftRight = ${bit1.shr(2).toString(2)}")
}

🌻 .shr() : 이동으로 인한 빈자리는 부호값으로 채움(음수인 경우 1, 양수인경우 0)

.ushr() : 이동으로 인한 빈자리를 부호관계없이 0으로 채움

→ 부호관련은 오른쪽으로 비트 이동할때만 있어서 ushr만 존재

 

https://codedragon.tistory.com/7998

 

Kotlin - 시프트 연산자 종류, 비트연산의 특징

Kotlin - 시프트 연산자 종류 Kotlin Java 의미 shr .shr(bits) >> · Right shift 연산 · 왼쪽 시프트 연산자 · bit값을 오른쪽으로 이동. · 부호를 유지하면서 지정한 수만큼 비트를 전부 오른쪽으로 이동시킵

codedragon.tistory.com

 

05.식별자 알아보기

  • 코틀린은 패키지 단위로 파일에 작성된 코드를 관리. 파일이 달라도 패키지명이 동일하면 동일한 패키지로 관리= 패키지가 다르면 같은 이름으로 클래스 등 지정 가능
  • as : 패키지 별칭 사용
    • 패키지는 다르지만, 이름이 같을경우 import하면 이름의 충돌이 발생할 수 있다.
    • import kotlin.math.PI as circleRatio
    • import kotlin.math.cos as cosine
    • println(circleRatio)
  • 코틀린에서는 일부 예약어를 식별자로 사용할 수 있다. 
fun main() {
	val main_ ={print("hello")}
//	println(main) // 에러
	println(::main) // 메인함수 참조
	println(main_)  // 변수할당된 람다 표현식 참조
}

  • 표준입출력
    • 입력함수 : readline
    • 출력함수 : print, println
fun main() {
// readline()으로 스트링형 입력받고 " " 단위로 분리 후 int형으로 변환, it은 값
	val input=readLine()!!.split(" ").map{it.toInt()}
	var sum=0
	for(i in (0untilinput.size))
		sum+=input[i]
	println(sum)
}

map과 같은 고차함수에 대해

https://developer.android.com/codelabs/basic-android-kotlin-compose-higher-order-functions?hl=ko#2

 

컬렉션을 사용한 고차 함수  |  Android Developers

Kotlin에서 컬렉션과 함께 일반적인 고차 함수를 사용하는 방법을 알아보세요.

developer.android.com

 


🌻🌻 스터디 후기 🌻🌻

스터디원들에게 나온 질문들과 멘토님 피드백

 

1️⃣

  • 코틀린은 모든 것을 객체로 본다.
    • JVM으로 실행되어 자바와 동일하게 Primitive사용
    • 컴파일 처리할 때 까지 모든 객체는 해당 클래스가 있다.

JVM내에서 컴파일 시 Kotlin -> Java로 바뀌는 과정에서 코틀린의 객체들이
Primitive으로 바뀔 수 있는건 바뀌는게 맞을까요?

예상 : 
val num: Int = 10 // 컴파일 시 Primitive
val user: User = User() // 컴파일 시 Reference 

 

코틀린 코드 디컴파일

IntelliJ -> tools->kotlin->show kotlin Bytecode ->새로운 창에서 Decompile한 결과이다.

코틀린 파일 

class Exp {
    var a = 12
}

fun main() {
    var exp = Exp()

    println(exp)
    println(exp.a)
}

자바 디컴파일 결과 

public final class ExpKt {
   public static final void main() {
      Exp exp = new Exp();
      System.out.println(exp);
      int var1 = exp.getA();
      System.out.println(var1);
   }
   ...
   public final class Exp {
   private int a = 12;

   public final int getA() {
      return this.a;
   }

   public final void setA(int var1) {
      this.a = var1;
   }
}

질문출처 : (https://github.com/jiwon2724/TIL/blob/main/%EA%B0%9C%EB%B0%9C%EC%9E%90%EB%A5%BC%20%EC%9C%84%ED%95%9C%20%EC%BD%94%ED%8B%80%EB%A6%B0%20%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D/CHAPTER%2002%20%EC%BD%94%ED%8B%80%EB%A6%B0%EC%97%90%EC%84%9C%EB%8A%94%20%EB%AA%A8%EB%93%A0%20%EA%B2%83%EC%9D%B4%20%EA%B0%9D%EC%B2%B4%EC%9D%B4%EB%8B%A4.md)

 

2️⃣ 비트 연산자는 개발시 어디에 쓰이는가?

안드로이드스튜디오에서 gravity줄 때 top & right, rop&left 처럼 동시에 줄 때 비트연산자 and, or, xor 이용할 수 있다.  
추가로 수학적 연산이 들어갈때 쓴다고 하셨는데 거의 안쓰인다고 하셨다. 

 

3️⃣

연산자가 a-b가 있고 이에 대응하는 메소드가 a.minus(b)인데 후자와 같이 메소드를 쓰면 null Safe Call할 때 좋다.

 

fun main() {
	var a :Int ?=4
	val b :Int =3
	a= null

//	println(a-b) // 오류 
	println(a?.minus(b)) // 결과값 : null
    	println(a?.minus(b) ?: 4) // 결과값 : 4 
}