JEP's Diary

2. 자바와 비교해 보는 코틀린 1 본문

Development/Kotlin

2. 자바와 비교해 보는 코틀린 1

지으니88 2018. 8. 31. 18:37

2. 자바와 비교해 보는 코틀린


기본 자료형

코틀린은 모든 타입을 객체로 표현하므로 원시 타입(int, double)과 래퍼 클래스(Integer, Double)를 구분하지 않는다.

kotlin.Byte

kotlin.Short

kotlin.Int

kotlin.Long

kotlin.Char

kotlin.Float

kotlin.Double

kotlin.Boolean


- 숫자

: 숫자와 타입, 진법을 함께 표현하기 위해 사용하는 리터럴 표기법은 자바와 대부분 동일하다.

: Long타입은 대문자만 지원한다. 

1
2
val longValue: Long = 100L
 
cs


- 연산자

: 숫자 연산자는 자바보다 더 직관적이다.

: and, or, xor, inv, shl, shr, ushr


- 문자

: 코틀린에서는 문자만 대입할 수 있다.

1
2
val ch : Char = 'A'
 
cs


- 문자열

: 문자열 내 특정 문자에 접근하기 위해 get()  또는 []를 사용한다.

1
2
3
4
5
val foo : String = "Hello"
// 3번째 문자 'l'
val ch1 : Char = foo.get(3)
val ch2 : Char = foo[3]
 
cs


- 배열

: 타입 인자를 갖는 Array클래스로 표현한다.

1
2
val items : Array<String> = arrayOf("aaa""bbb""ccc")
 
cs


: 자바로 작성된 코드에서 배열을 인자로 받거나 가변인자를 사용하는경우, 스프레드연산자(*)를 함께 사용해야 코틀린의 배열을 인자로 전달 할 수 있다.

: 코틀린으로 작성된 함수는, 가변인자에 배열을 전달하는 경우에믄 스프레드 연산자(*)를 사용한다.



클래스 및 인터페이스


- 클래스와 인터페이스의 선언 및 인스턴스 생성

: 클래스와 인터페이스 선언 방법은 자바와 거의 동일하며, 접근제한자를 지정 하지 않은 경우는 public으로 간주한다.

: 선언된 내용이 없는 경우는 클래스 이름만으로도 선언 할 수 있다.

1
2
3
4
class Bar {
}
 
class Foo
cs


1
2
3
4
interface Bar {
}
 
interface Foo
cs


: 클래스의 선언은 new를 사용하지 않는다.

1
2
3
4
5
// new 키워드 없음
val foo: Foo = Foo()
 
// 인자 하나를 받는 생성자로 인스턴스 생성
val bar: Bar = Bar(1)
cs


: 추상 클래스의 생성과 선언은 다음과 같다.

1
2
3
4
5
6
7
8
9
10
11
12
// 추상 클래스 선언 
abstract class Foo {
    abstract fun bar()
}
 
// 추상 클래스의 인스턴스 생성 
// object: [생성자] 
val foo = object: Foo() {
    override fun bar() {
    // 함수 구현 
    }
}
cs


: 인스턴스의 생성과 선언은 다음과 같다.

1
2
3
4
5
6
7
8
9
10
11
12
13
// 인터페이스 선언
interface Bar {
    fun baz()
}
 
// 인터페이스의 인스턴스 생성
// object: [인터페이스 이름] 
val bar = object: Bar {
 
    override fun baz() {
    // 함수 구현
    }
}
cs



- 프로퍼티

: 프로퍼티는 자료를 저장 할 수 있는 필드와 이에 상응하는 Getter/Setter 메서드를 함께 제공한다.

: 프로퍼티는 값(val) 혹은 변수(var) 중 하나로 선언한다.

: var는 Getter/Setter 모두 존재하지만, val는 Getter만 존재한다.

: 프로퍼티는 초깃값을 명시적으로 지정해야하며, 생성자에서 값을 할당해도 된다.

: 프로퍼티 선언 시점이나 생성자 호출 시점에 값을 할 당 할 수 없는 경우에는 lateinit 키워드를 사용해서 프로퍼티의 값이 나중에 할당 될 것임을 명시해야 한다.

: 프로퍼티에 초깃값을 할당하는 시점에서 타입을 추론할 수 있다면, 타입 선언 생략 가능

1
2
3
4
5
6
7
8
class Person {
    val name : String= null // 값을 읽기만 가능
    var address : String= null // 값을 읽기/쓰기가 가능, null은 타입 추론이 불가능하여 타입 
 
    lateinit var address2 : String// 추후에 값 할당
 
    val name = "No Name" // 타입 생략 
}
cs



- 접근 제한자

: 접근 제한자로 클래스와 함수, 프로퍼티의 가시성을 제어한다.

: 제한자가 없으면 public으로 간주하므로, 생략하는 것을 권장한다.

: internal 접근 제한자는 동일한 모듈 내에 있는 클래스들로의 접근을 제한한다.


- 생성자

: 자바와 달리 좀더 명확한 방법으로 생성자를 정의한다.

: init 블록을 사용하여 기본 생성자를 대체한다. 

: 생성자에 인자가 필요한 경우 인자를 받을 수 있고, 이를 주생성자(primary Constructor)라 부르며, 여기서 받은 인자는 init 블록에서도 사용가능하다.

: 생성자의 인자를 통해 바로 클래스 내부의 프로퍼티에 값을 할당 할 수 있다.

: 주생성자 외에 다른 생성자가 필요할 때는 contructor 키워드를 사용하여 추가 생성자를 생성하고, 이때는 반드시 주생성자를 호출해야 한다.

: 생성자의 가시성을 변경하려면 private constructor 형태로 지정하며, 주생성자는 생략했던 contructor 키워드를 추가하고 접근제한자를 추가해야한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 주생성자
class Foo(a:Int) {
 
    init {
        // 생성자에서 수행할 작업들
        Log.d("Foo""Number = $a")
    }
}
 
// 생성자 인자로 프로퍼티 값 할당
class Foo(val a: Int, var b: Int) {
 
    // 다른 생성자 형태, -> 주생성자 호출해야함
    constructor(a: Int) : this(a,0)
 
    // 접근제한자 추가 
    private constructor() : this(0,0)
 
}
cs



- 함수

: 코틀린에서는 함수(function)로 표현한다.

: 특별한 값을 반환하지 않는 함수는 Unit타입을 반환하며, 생략 가능하다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Foo(a:Int) {
    // 반환 타입 없는 함수
    fun foo() : Unit {
    }
 
    // 반환 타입 생략 
    fun foo2() {
    }
 
    // Int 형 반환 함수
    private fun bar() : Int {
        return 0
    }
}
cs



- 상속 및 인터페이스

: 콜론(:) 뒤에 상속한 클래스나 구현한 인터페이스를 표기한다.

: 클래스를 상속하는 경우 반드시 부모 클래스의 생성자를 호출해야한다

: 부모클래스의 생성자가 여러형태일 경우, 별도의 생성자 선언에서 부모 클래스의 생성자를 호출하는 것도 가능하다.

: 상속받거나 구현한 함수의 앞에 무조건 override 키워드를 붙인다.

: open 키워드를 붙인 클래스나 함수가 아니라면 클래스를 상속하거나 함수 및 프로퍼티 값을 재정의할 수 없습니다. (자바에서의 final 개념)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 콜론으로 상속및 인터페이스 implements
class MainActivity : AppCompatActivity(), View.OnClickListener {
 
    // 메서드 상속
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
    }
 
     // 인터페이스 
     override fun onClick(v: View) {
    }
}
 
// 별도의 생성자에서 부모클래스의 생성자 호출
class MyView : View {
 
    contructor(context: Context) : super(context) {
 
    }
}
cs


- this

: 자바에서와 거의 비슷하며, 클래스를 명시할 때는 this@{클래스이름}으로 표기한다.

1
this@MyActivity
cs


- 정적필드 및 메서드

: 클래스 내에 선언했던 정적 필드나 메서드는 패키지 단위로 선언 할 수 있다.

: 패키지 단위로 선언한 값이나 함수는 클래스가 아닌 패키지에 종속되므로, import문에서 {패키지이름}.{값 혹은 함수이름}으로 사용한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// Foo.kt
package foo.bar
 
// 값 FOO
const val FOO = 123
 
// 함수 foo
fun foo() {}
 
class FOO {
    
    // 함수 bar는는 Foo 인스턴스를 생성해야 사용가능하다.
    fun bar() {}
}
cs


1
2
3
4
5
6
7
8
9
10
11
12
13
14
// Bar.kt
import foo.bar.FOO
import foo.bar.foo
 
class Bar {
 
    fun bar() {
        // foo.bar 패키지 내의 값 FOO의 값을 참조
        val foo = FOO
 
        // foo.bar 패키지 내의 함수 foo를 
        foo()
    }
}
cs


: 동반객체(companion object)는 클래스별로 하나씩 클래스의 인스턴스 생성 없이 사용 할 수 있는 오브젝트를 정의할 수 있는 것을 말한다.

: 코틀린은 클래스 내에 정적 필드나 정적 함수를 둘수 없으므로 동반객체를 이용한다.


- 싱글톤

: 싱글톤은 단 하나의 인스턴스만 생성되도록 제약을 둔 디자인패턴이다.

: 오브젝트(object)를 사용하여 간편하게 선언 할 수 있다.

: 오브젝트 내 선언된 값이나 함수는 자바의 정적 멤버와 동일한 방법으로 사용한다.

1
2
3
4
5
6
7
8
9
object Foo {
    val FOO = "foo"
    
    fun foo() {}
}
 
// 
val fooValue = Foo.FOO
Foo.foo()
cs


- enum 클래스

: 자바의 enum 타입과 동일한 역할이며, 선언 형태만 약간 다르다

1
2
3
4
5
6
7
enum class Direction {
    NORTH, SOUTH, WEST, EAST 
}
 
enum class Direction(val label: String) {
    NORTH, SOUTH, WEST, EAST 
}
cs


- 중첩클래스 

: 코틀린은 정적 중첩 클래스(static nested class)를 선언하기 위해 별도의 키워드가 필요하지 않다.

: 비 정적 중첩 클래스를 선언하기 위해 inner 키워드를 추가한다.

1
2
3
4
5
6
7
8
9
10
11
12
class Outer {
 
    // 정적 중첩 클래스
    class StaticNested {}
 
    // 비 정적 중첩 클래스
    inner class NonStaticNested {}
}
 
val staticInstance = Outer.StaticNested()
 
val NonStaticInstance = Outer().NonStaticNested()
cs





참고 : 차세대 안드로이드 개발자를 위한 커니의 코틀린