interface Clickable {
fun click()
}
class Button : Clickable {
override fun click() = println("I was clicked")
}
public interface Clickable {
void click();
}
public class Button implements Clickable {
@Override
public void click() {
System.out.println("I was clicked");
}
}
class Button : Clickable, Focusable {
override fun click() = println("I was clicked")
override fun showOff() {
super<Clickable>.showOff() // java: Clickable.super.showOff()
super<Focusable>.showOff() // java: Focusable.super.showOff()
}
}
interface Clickable {
fun click()
fun showOff() = println("I'm clickable!")
}
interface Focusable {
fun setFocus(b: Boolean) =
println("I ${if (b) "got" else "lost"} focus.")
fun showOff() = println("I'm focusable!")
}
fun main(args: Array<String>) {
val button = Button()
button.showOff()
button.setFocus(true)
button.click()
}
// I'm clickable!
// I'm focusable!
// I got focus.
// I was clicked
NOTE -
Effective Java
상속을 위한 설계와 문서를 갖추거나, 그럴 수 없다면 상속을 금지하라.
변경자 | 이 변경자가 붙은 멤버는... | 설명 |
---|---|---|
final | 오버라이드할 수 없음 | 클래스 멤버의 기본 변경자다. |
open | 오버라이드할 수 있음 | 반드시 open을 명시해야 오버라이드할 수 있다. |
abstract | 반드시 구현해야함 | 추상 클래스의 멤버에만 이 변경자를 붙일 수 있다. |
override | 오버라이드하는 중 | 오버라이드하는 멤버는 기본적으로 open. 하위 클래스의 오버라이드를 금지하려면 final을 명시해야 한다. |
final
이 기본 설정override
, then open
변경자 | 클래스 멤버 | 최상위 선언 |
---|---|---|
public | 모든 곳에서 볼 수 있다. | 모든 곳에서 볼 수 있다. |
internal | 같은 모듈 안에서만 볼 수 있다. | 같은 모듈 안에서만 볼 수 있다. |
protected | 하위 클래스 안에서만 볼 수 있다. | (최상위 선언에 적용할 수 없음) |
private | 같은 클래스 안에서만 볼 수 있다. | 같은 파일 안에서만 볼 수 있다. |
public
이 기본 설정구분 | 바깥쪽 클래스에 대한 참조 | Java | Kotlin |
---|---|---|---|
중첩 클래스 (Nested Class) | 바깥쪽 클래스에 대한 참조 불가능 | static class NestedClass | class NestedClass |
내부 클래스 (Inner Class) | 바깥쪽 클래스에 대한 참조 가능. | class InnerClass | inner class InnerClass |
static class NestedClass
class NestedClass
public class OuterClass {
private static String staticProperty = "staticProperty";
private String property = "property";
static class NestedClass {
private static String nestedClassStaticProperty = "nestedClassStaticProperty";
private String nestedClassProperty = "nestedClassProperty";
public void test() {
System.out.println(nestedClassStaticProperty);
System.out.println(this.nestedClassProperty);
System.out.println(Solution.staticProperty);
// System.out.println(Solution.this.property); // Compile Error
}
}
public static void main(String[] args) {
new Solution.NestedClass().test();
}
}
class OuterClass {
val property: String = "property"
class InnerClass {
private val innerClassProperty: String = "innerClassProperty"
fun createOuterClassInstance() : OuterClass{
println(innerClassProperty)
return OuterClass()
}
}
}
fun main(args: Array<String>) {
println(OuterClass.InnerClass().createOuterClassInstance().property)
}
inner class
this@OuterClass
OuterClass.this
class InnerClass
inner class InnerClass
public class OuterClass {
private static String staticProperty = "staticProperty";
private String property = "property";
class InnerClass {
// private static String innerClassStaticProperty = "innerClassStaticProperty"; // Supported since Java 16
private String innerClassProperty = "innerClassProperty";
public void test() {
System.out.println(this.innerClassProperty);
System.out.println(Solution.this.property);
System.out.println(Solution.staticProperty);
}
}
public static void main(String[] args) {
new OuterClass().new InnerClass().test();
}
}
class OuterClass {
val property: String = "property"
inner class InnerClass {
private val innerClassProperty: String = "innerClassProperty"
fun getOuterReference() : OuterClass{
println(innerClassProperty)
println(this@OuterClass.property)
return this@OuterClass
}
}
}
fun main(args: Array<String>) {
println(OuterClass().InnerClass().getOuterReference().property)
}
sealed class
봉인된 클래스를 상속하는 하위 클래스 정의를 제한할 수 있다.
sealed 클래스의 하위 클래스를 정의할 때는 반드시 봉인된 클래스 안에서 정의되어야 한다.
sealed class
를 상속하려면, 그 클래스 안에 정의되어 있어야 한다.sealed class
는 기본적으로 open
이다.sealed class
는 private 생성자를 가진다. 클래스 내부에서만 호출 가능.sealed class Expr {
class Num(val value: Int) : Expr()
class Sum(val left: Expr, val right: Expr) : Expr()
}
fun eval(e: Expr): Int =
when (e) {
is Expr.Num -> e.value
is Expr.Sum -> eval(e.left) + eval(e.right)
// else 가 없어도 됨.
//else -> throw IllegalArgumentException("Illegal Expression")
}
fun main(args: Array<String>) {
println(eval(Expr.Sum(Expr.Sum(Expr.Num(1), Expr.Num(2)), Expr.Num(4)))) // 7
}
interface User {
val nickname: String
}
class PrivateUser(override val nickname: String) : User
class SubscribingUser(val email: String) : User {
override val nickname: String
get() = email.substringBefore('@')
}
class FacebookUser(val accountId: Int) : User {
override val nickname = getFacebookName(accountId)
}
field
field
를 사용하지 않고 커스텀 Getter, Setter를 구현했을 경우, 뒷받침 필드는 존재하지 않는다.class User(val name: String) {
var address: String = "unspecified"
set(value: String) {
println("""
Address was changed for $name:
"$field" -> "$value".""".trimIndent())
field = value
}
}
class LengthCounter {
var counter: Int = 0
private set
fun addWord(word: String) {
counter += word.length
}
}
fun main(args: Array<String>) {
val lengthCounter = LengthCounter()
lengthCounter.addWord("Hi!")
println(lengthCounter.counter) // 3
}
data class
data class Client(val name: String, val postalCode: Int)
fun main(args: Array<String>) {
val bob = Client("Bob", 973293)
println(bob.toString()) // Client(name=Bob, postalCode=973293)
println(bob == Client("Bob", 973293)) // true
println(bob.hashCode()) // 3049208
println(bob.copy(postalCode = 382555)) // Client(name=Bob, postalCode=382555)
println(bob === bob.copy()) // false
}
by
import java.util.HashSet
class CountingSet<T>(
val innerSet: MutableCollection<T> = HashSet<T>()
) : MutableCollection<T> by innerSet {
var objectsAdded = 0
override fun add(element: T): Boolean {
objectsAdded++
return innerSet.add(element)
}
override fun addAll(c: Collection<T>): Boolean {
objectsAdded += c.size
return innerSet.addAll(c)
}
}
fun main(args: Array<String>) {
val cset = CountingSet<Int>()
cset.addAll(listOf(1, 1, 2))
println("${cset.objectsAdded} objects were added, ${cset.size} remain")
}
object
import java.util.Comparator
data class Person(val name: String) {
object NameComparator : Comparator<Person> {
override fun compare(p1: Person, p2: Person): Int =
p1.name.compareTo(p2.name)
}
}
fun main(args: Array<String>) {
val persons = listOf(Person("Bob"), Person("Alice"))
println(persons.sortedWith(Person.NameComparator))
}
companion object
Companion
이라는 이름을 부여한다.interface JSONFactory<T> {
fun fromJSON(jsonString: String): T
}
class Person(val name: String) {
companion object JSONParser: JSONFactory<Person> {
override fun fromJSON(jsonString: String) : Person {
// ...
return Person("name")
}
}
}
fun main(args: Array<String>) {
val jsonString = """{"name": "John"}"""
Person.fromJSON(jsonString)
Person.JSONParser.fromJSON(jsonString)
}
fun getFacebookName(accountId: Int) = "fb:$accountId"
class User private constructor(val nickname: String) {
companion object {
fun newSubscribingUser(email: String) =
User(email.substringBefore('@'))
fun newFacebookUser(accountId: Int) =
User(getFacebookName(accountId))
}
}
fun main(args: Array<String>) {
val subscribingUser = User.newSubscribingUser("bob@gmail.com")
val facebookUser = User.newFacebookUser(4)
println(subscribingUser.nickname)
}
class Person(val name: String) {
companion object {} // 비어있는 동반 객체
}
// 동반객체의 확장함수 정의
fun Person.Companion.fromJSON(jsonString: String): Person {
// ...
}
fun main() {
val p = Person.fromJSON("....")
}