728x90

코틀린 강의 시리즈는 이미 자바 문법을 어느정도 안다는 가정하에서 진행을 한다.

따라서 자바 문법을 모르는 상태에서 코틀린의 강의를 들을 수 없으므로 자바부터 배워오길 바란다.

또한 강의의 전반적인 내용은 코틀린에 대한 새로운 문법을 소개하며 자바와 어떻게 다른지를 비교한다.

코틀린은 자바와 같은 jvm족이므로 둘의 협업역시 중요하므로 둘이 어떻게 호환이 되는지도 다루게 된다.

그리고 이 강의는 코틀린 강의지 안드로이드 강의가 아니다. 안드로이드 강의는 알아서하고 코틀린을 적용시키는건 본인 재량이다.


필자는 강의시 원래 IDE에 대한 설명을 최대한 배제하려한다.

필자 블로그의 카테고리는 programming과 usage 둘로 나뉘어 있다.

따라서 프로그래밍은 programming에, IDE및 사용법들은 usage에 나뉘는 방식으로 포스팅을 해왔다.

그런데 코틀린은 조금 상황이 다른게 이미 자바를 알고 있고 자바와 협업한다는 가정하에서 포스팅을 하기에

주변상황에 대한 설명이 들어갈 확률이 매우 높다고 할 수 있다.

따라서 IDE나 사용법에 대한 설명을 같이 포스팅한 경우가 많다. 물론 보는 입장에선 이게 더 도움은 될것이다.

필자가 사용하는 IDE는 IntelliJ가 될것이다. 자바든 코틀린이든 둘다 IntelliJ로 하게 될것이다.


참고:

코틀린 컴파일러 콘솔로 실행하기

코틀린 프로젝트만들기 - InteliiJ

코틀린 프로젝트만들기 - Eclipse


코틀린의 변수는 자바의 변수와 뭐 기본적으로는 똑같이 컴파일 될거지만 쓰는 방법이 조금 다르다.

일단 코틀린은 아무래도 2014년도에 생긴 언어이고 새로운 트렌드를 따르고 있다.

즉 자바의 경우 타입형을 적어주는게 문법적으로 강제되는 성향이 큰편이다.

그러나 코틀린의 경우에는 그렇지는 않다. 단 조금 애매한 포지션이라는 느낌은 받는다.

뭐 다른 언어를 접해보지 않았다면 그런 애매한 포지션이라는 느낌을 받지는 않겠지만..

다른언어들과 조금 비교를 해보자.


public static void func(){
int a = 10;
a = "배고프다";
}

위 코드는 자바의 메소드이다. 이러한 문법이 가능한가? 당연하지만 불가능하다.

왜냐하면 a는 우리가 int형으로 선언했고 자바에서는 왼쪽과 오른쪽의 균형을 항상 맞춰야 하므로 위 코드는 성립되지 않는다.

function test() {
var a=10;
a = "배고프다";
}

위 코드는 자바스크립트의 함수이다. 이 코드는 가능한가? 물론 가능하다.

자바스크립트에서는 int형이나 float형같은 것이 없다. 즉 왼쪽 변수의 타입은 신경쓸 필요가 없다.

어떤 변수이던 오른쪽 변수의 타입을 담을 수 있는 그릇이 된다. 자바로 설명하자면 Object타입, C로 따지면 void*인 것이다.

fun func() {
var a = 10
a = "배고프다"
}

그럼 코틀린 코드에서는 위와같이 사용하는 것이 가능한가?

코틀린 역시 표기하는 방법은 자바스크립트와 똑같음을 알 수 있다.

결론 부터 말하자면 불가능하다. 이는 코틀린이 아무래도 jvm을 선택하는 jvm족 언어라 그런거 같다.(아닐 수 도 있음)


일단 코틀린의 변수들은 다 납득이 될만한 규칙이 있긴 하다.

필자가 알고있는 규칙은 아래와 같다.

코틀린 규칙


1.field의 경우 반드시 초기화 시켜준다. 이는 문법적으로 강제

2.method의 변수의 경우 초기화는 필수가 아니다.

3.변수는 무조건 적으로 타입을 알 수 있게 기술한다. 이 타입은 선언한 시점에서 결정되 바뀌지 않는다.

1)var a = 10 같은 경우 a는 자동으로 Int형이 된다. 그 후에 변경 불가

2)var a:Int 같은 경우 a가 초기화 되진 않지만 Int형이 된다. 그 후에 변경 불가

3)var a:Int = 10 같은 형태로도 쓸 수는 있다. 단 그럴필요가 없을 뿐.

또한 코틀린에서는 새로운 문법이 있다. ?문법이다.

자바에서는 두가지종류의 변수가 있는데 하나는 프리미티브타입(기본형)이 있고 다른 하나는 레퍼런스 타입(객체형)이 있다.

코틀린에서는 이 모든게 통합됬다. 즉 레퍼런스 타입밖에 없다.

사실 자바도 프리미티브타입을 쓰지 않고 코딩할 수 있다. 그 이유는 래퍼클래스가 존재하기 때문이다.

이제 왜 변수가 int가 아니라 Int인지 알겠는가? 코틀린에선느 모든것이 객체이다.

그리고 자바족에서 객체의 네이밍룰은 첫글자는 무조건 대문자를 쓸것이다. 따라서 Int형으로 바뀐것이다.


이제 ?문법을 설명토록하자. 래퍼런스 타입들의 장점이자 단점은 null을 가질 수 있다는 것이다.

이는 코딩적으로 유연한 코딩이 가능하게 해준다. 예를들어서 자바의 경우 int형이 아니라 Integer형을 사용할경우를 보자.

알고리즘 구현시 초기화를 시켜줘야하는데 숫자를 넣는건 결국 잠재적인 오류를 발생할 수 있다.

따라서 int를 해서 임의의 숫자(주로 잘 안쓸것같은)를 넣는것보다. null을 넣는게 훨씬 좋다. 적어도 논리적 오류는 안생기니까.

그러나 래퍼런스타입들은 항상 NPE(Null Pointer Exception)을 일으킬 문제가 있다.

그럼 거꾸로 생각해보면 int형같은 경우에는 NPE가 일어나지 않는게 코딩시 보장이되므로 그런걸 신경쓸 필요가 없다.


그래서 나온게 ?문법이다. 아래의 예시를보자.

fun func(){
var name:String?=null
var gender:String=null
}

두 사례에서 null을 붙혔다. 자바에서는 둘다 되는 코드이다.

그러나 코틀린에서는 위만 된다. 그 이유는 ?를 붙혀야만 null을 쓸 수 있는 것이다.

따라서 NPE를 일으키기 싫다면 아래를 사용하고 NPE가능성이 있더라도 null을 써야한다면 위를 사용하면 된다.


접근제한자


자바에는 총 4가지의 접근제한자가 있었고 디폴트가 package접근제한자였다.

코틀린도 마찬가지로 총 4가지의 접근제한자기 있다. 단 디폴트는 public이다.

package shape

class Shape(x: Int, y: Int) {
private var x: Int = x
private var y: Int = y
private var width: Int = 0
private var height: Int = 0

init {
println("생성자 호출")
}

constructor(x: Int, y: Int, width: Int, height: Int) : this(x, y) {
this.width = width
this.height = height
}

fun setSize(width: Int, height: Int) {
this.width = width
this.height = height
}

fun getArea(): Int {
return width * height
}
}

접근 제한자를 선언하는 방식은 자바와 동일하다. 더 해볼것도 없다. 단 디폴트가 public이므로 앞으로 public키워드는 볼일이 없다.

그런데 문제는 internal의 경우이다. 이 경우에는 조금 특별하다. 기본적으로 package와 상당히 유사하지만 같다고보긴 좀 애매하다.

먼자 코틀린 코드를 자바에서 사용할 경우 어떤형식이 될지를 생각해보자.

코틀린에서는 접근자와 설정자를 따로 만들어줄 필요가 없다. 오히려 거꾸로 접근자 설정자를 제한하는 방식으로 사용한다.

class Shape(x: Int, y: Int) {
var x: Int = x
var y: Int = y
var width: Int = 0
var height: Int = 0

init {
println("생성자 호출")
}

constructor(x: Int, y: Int, width: Int, height: Int) : this(x, y) {
this.width = width
this.height = height
}

fun setSize(width: Int, height: Int) {
this.width = width
this.height = height
}

fun getArea(): Int {
return width * height
}
}

위 Shape클래스를 컴파일한 결과를 눈으로 확인해보자.



보면 자바코드로 보면 알겠지만 자동으로 getter와 setter가 생긴다.

그리고 자바에서 변수명으로 접근하려고 하면 접근이 안된다.

그러면 필드를 모두 private를 걸어놓고 사용하여보자.



private를 사용할경우 필드의 모든 접근자와 설정자가 사라진다.

코틀린코드에서 public이 가지는 의미는 접근자 설정자를 모두 만든다는 의미이며

private가 가지는 의미는 접근자와 설정자를 모두 만들지 않는다는 의미이고

이제 internal이 가지는 의미는 접근자와 설정자를 모듈안에서 호출한다는 의미이다.

여기서 말하는 모듈은 좀 범위가 넓은데 자바에서 package는 정말 그 패키지내에서를 의미하지만

코틀린에서는 프로젝트 자체를 의미한다. 즉 jar파일 자체에서 전체를 공유하므로

프로젝트 내부에서는 마치 public처럼 사용할 수 있는 것이다.



보면 아시겠는가? 자바에서 $의 표시는 특정 네임스페이스에 귀속됬음을 의미한다.

코틀린도 jvm족이니까 마찬가지일 것이다. 즉 StartKotlin 네임스페이스에 귀속됬음을 알 수있다.

따라서 이를 jar파일을 만들어서 배포하면 얘들은 private처럼 사용할 수 없는것이다.


여기서 kotlin을 jar파일을 만들어서 java에서 써보면 알 수 있는 점은 필드에 직접접근할 수 없다는 것이다.

즉 우리가 코틀린에서 public으로 필드를 생성해도 자바에서 접근해보면 private로 막혀있다.

사실 이는 코틀린도 똑같다. 위에서 설명했지만 public의 의미는 설정자와 접근자를 막는것이라고 하였다.

즉 코틀린에서도 사실은 접근자와 설정자로 우회를 해서 접근하는 것이다.

이 문법의 특징은 닷넷족의 property문법과 거의 유사하다고 볼 수 있다.

그러면 난 setter만 쓰고 싶은데? 혹은 getter만 쓰고싶은데? 이렇게 생각할 수 있다.

당연히 그러한 문법도 제공한다. 코틀린에서는 기본적으로 필드의 setter를하나하나씩 지우는 방향으로 사용한다.

package shape

class Shape(x: Int, y: Int) {
var x: Int = x
private set
var y: Int = y
var width: Int = 0
var height: Int = 0

init {
println("생성자 호출")
}

constructor(x: Int, y: Int, width: Int, height: Int) : this(x, y) {
this.width = width
this.height = height
}

fun setSize(width: Int, height: Int) {
this.width = width
this.height = height
}

fun getArea(): Int {
return width * height
}
}

보면 변수 x밑에  private set이라고 되어있다.

이 경우 getter는 열리지만 setter는 닫힌다. 따라서 외부에서 수정이 불가능하게 된다.

getter의 경우 특이하게 private를 걸 수 없다. 이유를 모르겠다. getter를 private을 걸려면 아예 변수를 private로 해야한다.

만약 getter와 setter를 내가 만들고 싶은 형태로 만들고 싶다면?

그것도 가능은 하다. 쓸지는 모르겟지만.

package shape

class Shape(x: Int, y: Int) {
var x: Int = x
get() = field
set(x) { field = x }
var y: Int = y
var width: Int = 0
var height: Int = 0

init {
println("생성자 호출")
}

constructor(x: Int, y: Int, width: Int, height: Int) : this(x, y) {
this.width = width
this.height = height
}

fun setSize(width: Int, height: Int) {
this.width = width
this.height = height
}

fun getArea(): Int {
return width * height
}
}

보면 처음보는 지시자가 등장한다. 바로 field인데 field는 쉽게 말하면 자기자신을 의미한다.

일반적으로 우리가 접근자와 설정자를 오버로딩히지 않는다면

 get() = field가 호출되고 set(x)={field=x}가 호출된다.

이걸 우리가 입맛에 따라 바꿔주면된다. 물론 필자는 이 둘을 입맛에 따라 바꿔본적은 없다.


변수와 상수


자바에서는 기본이 변수고 상수는 final을 붙혀서 표시했다. 코틀린에서는 변수는 var로 상수는 val로 표시한다.

아래의 예제를 보자.

fun method(){
var a = 10
val b = 10
a = 20
b = 20
}

이 코드의 경우 a의 사용은 가능하지만 b의 사용은 불가능하다.

왜냐하면 a는 변수이고 b는 상수이기 때문이다.

'Programming > Kotlin' 카테고리의 다른 글

[Kotlin-06]상속(abstract class)  (0) 2017.11.10
[Kotlin-05]상속(open class)  (0) 2017.11.10
[Kotlin-04]open  (0) 2017.11.10
[Kotlin-02]Kotlin Class 와 생성자  (0) 2017.11.07
[Kotlin-01]Kotlin File  (0) 2017.11.07

+ Recent posts