접근 제어
자바와 코틀린의 가시성 제어
- Java
- public: 모든 곳에서 접근 가능
- protected: 같은 패키지 또는 하위 클래스에서만 접근 가능
- default: 같은 패키지에서만 접근 가능
- private: 선언된 클래스 내에서만 접근 가능
- Kotlin
- public: 모든 곳에서 접근 가능
- protected: 선언된 클래스 또는 하위 클래스에서만 접근 가능
- internal: 같은 모듈에서만 접근 가능
- private: 선언된 클래스 내에서만 접근 가능
코틀린에서는 패키지를 접근 제어에 활용하지 않는다.
자바의 기본 접근 지시어는 default이고 코틀린은 public 이다.
모듈
한 번에 컴파일 되는 Kotlin 코드
- IDEA Module
- Maven Project
- Gradle Source Set
- 등등
코틀린 파일의 접근 제어
코틀린 파일에는 .kt 파일에 변수, 함수, 클래스 등 여러 개를 바로 만들 수 있다.
1
2
3
4
5
6
7
| val g = 3
fun add(a: Int, b: Int): Int {
return a + b
}
class Cat()
|
클래스 등이 아닌 이러한 파일에서의 접근 제어는 어떤지 보자.
- public(기본): 어디서든 접근할 수 있다.
- protected: 파일 최상단에는 사용 불가능
- internal: 같은 모듈에서만 접근 가능
- private: 같은 파일 내에서만 접근 가능
생성자, 프로퍼티 접근 제어
1
2
3
4
5
6
7
8
9
10
| class Bus private constructor(
val price: Int
)
class Car(
private val name: String,
_price: Int
) {
var price = _price
private set
|
- 동일하지만 생성자에 접근제어를 붙이고 싶다면 constructor 키워드를 붙여주어야 한다.
- 프로퍼티에 접근제어를 걸어 getter, setter를 한 번에 접근 지시어를 정할 수 있다.
- Setter 등에 추가로 가시성을 부여할 수도 있다.
자바와 코틀린을 함께 사용할 때 주의할 점
- Internal은 바이트 코드 상 public이 된다.
- 따라서 Java 코드에서는 Kotlin 모듈의 Internal 코드를 가져올 수 있다.
- Kotlin의 protected와 Java의 protected는 다르다.
- Java는 같은 패키지의 Kotlin protected 멤버에 접근할 수 있다.
object 키워드
static 함수와 변수
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| public class JavaPerson {
private static final int MIN_AGE = 1;
public static JavaPerson newBaby(String name) {
return new JavaPerson(name, MIN_AGE);
}
private String name;
private int age;
private JavaPerson(String name, int age) {
this.name = name;
this.age = age;
}
}
|
1
2
3
4
5
6
7
8
9
10
11
| class Person private constructor(
var name: String,
var age: Int,
) {
companion object {
private const val MIN_AGE = 1
fun newBaby(name: String): Person {
return Person(name, MIN_AGE)
}
}
}
|
- static
- 클래스가 인스턴스화 될 때 새로운 값이 복제되는 것이 아닌 정적으로 인스턴스끼리 값을 공유한다.
- 코틀린에서는 static이 존재하지 않고 대신 companion object를 사용한다.
- companion object
- 클래스와 동행하는 유일한 오브젝트라고 생각하자.
- private const val MIN_AGE
- private val MIN_AGE로 사용한다면 런타임 시에 변수가 할당된다.
- const를 붙여주면 컴파일 시 변수가 할당된다.
- 사용법은 자바와 동일하다. (Person.newBaby(“Lee”))
자바와의 차이점
- companion object라는 이 동반객체도 하나의 객체로 간주된다.
- 따라서 이름을 붙일 수도 있고, interface를 구현할 수도 있다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| class Person private constructor(
private val name: String,
private val age: Int,
) {
companion object Factory : Log {
private const val MIN_AGE = 0
fun newBaby(name: String): Person {
return Person(name, MIN_AGE)
}
override fun log() {
println("LOG")
}
}
}
|
companion object에 유틸성 함수를 넣어도 되지만, 최상단 파일을 활용하는 것을 추천한다.
싱글톤
1
2
3
4
5
6
7
8
9
| public class JavaSingleton {
private static final JavaSigleton INSTANCE = new JavaSingleton();
private JavaSingleton() {}
public static JavaSingleton getInstance() {
return INSTANCE;
}
}
|
1
2
3
| object Singleton {
var a: Int = 0
}
|
1
2
3
4
5
6
7
8
| fun main() {
println(Singleton.a)
Singleton.a += 10
println(Singleton.a)
}
// 0
// 10
|
익명 클래스
특정 인터페이스나 클래스를 상속받은 구현체를 일회성으로 사용할 때 쓰는 클래스.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| public static void main(String[] args) {
moveSomething(new Movable() {
@Override
public void move() { System.out.println("움직");}
@Override
public void fly() { System.out.println("파닥");}
});
}
private static void moveSomething(Movable movable) {
movable.move();
movable.fly();
}
|
1
2
3
4
5
6
7
8
9
10
11
| fun main() {
moveSomething(object : Movable) {
override fun move() { ~~ }
override fun fly() { ~~ }
})
}
private fun moveSomething(movable: Movable) {
movable.move()
movable.fly()
}
|
- new 키워드 대신 object : 를 사용했다.
- Movable을 상속받는 object를 만든 것이다.
정리
- 코틀린에서는 패키지를 접근 제어에 활용하지 않는다.
- 자바의 static 변수와 함수 기능을 코틀린에서 구현하기 위해서는 companion object를 사용한다.
- companion object도 하나의 객체로 간주되어 이름을 붙이거나 상속받을 수 있다.
- 코틀린에서 싱글톤 클래스를 만드는 방법은 object 키워드를 붙이는 것이다.
- 코틀린에서 익명 클래스를 만들 때 object : 타입 을 사용한다.