////////////////////////////////////////////////// // object expressions, anonymous (inner) class, Local class 와 같은 용어들이 있는데 여기서는 모두 같은 것으로 간주할 수 있습니다.
sealed class Person(var name: String, var age: Int) { ////////////////////////////////////////////////// // 유형: Nested class open class Student(name: String, age: Int, var grade: Int) : Person(name, age) {}
class Baby(name: String, age: Int, var parent: Person) : Person(name, age) {} class Worker(name: String, age: Int, var company: String) : Person(name, age) {} class Senior(name: String, age: Int, var welfareCenter: String) : Person(name, age) {}
////////////////////////////////////////////////// // 유형: Inner class inner class PersonInner { var name = this@Person.name }
////////////////////////////////////////////////// // 유형: Anonymous (inner) class, 클래스 내부의 object expression, Local class, 익명 객체 // 예제에서는 Anonymous inner class와 Annonymous class를 구분했지만 둘 다 sealed class가 생성되었을 때만 작동합니다. 즉 동작에 차이가 없으므로 별도로 구분할 필요는 없을 것 같습니다.
// public/inner: public으로 선언된 익명 객체는 type으로 사용할 수 없음 var objAnonymousInner = object { var name1: String = this@Person.name var age1: Int = this@Person.age }
// public: public으로 선언된 익명 객체는 type으로 사용할 수 없음 var objAnonymous = object { var name1: String = "Person::objAnonymous anonymous" var age1: Int = 10 }
// private: private으로 선언된 익명 객체는 지역 및 private 영역에서 type으로 사용될 수 있음 private var objAnonymousPrivate = object { var name1: String = "Person::objAnonymous anonymous" var age1: Int = 10 }
// private/inner: private으로 선언된 익명 객체는 지역 및 private 영역에서 type으로 사용될 수 있음 private var objAnonymousInnerPrivate = object { var name1: String = this@Person.name var age1: Int = this@Person.age }
fun testAccessPublicAnonymousObject () { // public으로 선언되어 type으로 사용할 수 없음. 따라서 멤버에 접근할 수 없음 //objAnonymousInner.name1; // compile error //objAnonymous.name1; // compile error
// private으로 선언된 익명 객체는 지역 및 private 영역에서 type으로 사용될 수 있음 objAnonymousInnerPrivate.name1 objAnonymousPrivate.name1 }
////////////////////////////////////////////////// // 유형: Anonymous (inner) class, 클래스 내부의 object expression, Local class, 익명 객체 // Local class에서 sealed class를 상속할 수 없습니다. // sealed class 는 sealed class를 상속 받아 개념을 분류하는 하위 클래스의 타입을 반드시 참조해야 하므로 정확한 타입을 참조할 수 없는 object에 상속을 허용하는 것은 sealed class의 무결성을 깨는 것이므로 적절하지 않습니다.
// inherits sealed class //var objAnonymousHasSealedClassSuperType = object: Person("test", 10) { //var name1: String = "Person::objAnonymous anonymous" //var age1: Int = 10 // }
// inherits sealed class/inner // Anonymous inner class, 클래스 내부의 object expressions, Local class //var objAnonymousHasSealedClassSuperType1 = object : Person("test", 10) { //var name1: String = this@Person.name //var age1: Int = this@Person.age //}
////////////////////////////////////////////////// // 유형: Anonymous (inner) class, 클래스 내부의 object expression, Local class, 익명 객체 // Local class에서 sealed class의 하위 클래스도 상속할 수 없습니다. // 생성자 호출이 재귀적으로 되어 컴파일 에러가 발생합니다.
// inherits sealed's subclass/inner //var objAnonymousInheritedSealedChildType = object: Person.Student("K", 17, 10) { // var name1: String = name // var name2: String = this@Person.name // var age1: Int = age //}
////////////////////////////////////////////////// // 유형: object declarations // singleton으로 처리되므로 qualified this syntax로 Outer(Person)를 참조할 수 없습니다. 따라서 object declarations는 inner class와 관련이 없습니다. object PersonObject : Person("PersonObject", 10) { var name1: String = "PersonObject static" var age1: String = "0"// + this@Person.age // error }
////////////////////////////////////////////////// // 유형: 멤버 함수 안에서 사용한 object expression( anonymous class, local class )
// private/func/inner: private으로 선언된 익명 객체는 지역 및 private 영역에서 type으로 사용될 수 있음 private fun returnPrivateAnonymousObject() = object { var name: String = "Person::anonymous " + this@Person.name // 멤버 접근 var age: Int = 10 }
// public/func/inner: public으로 선언된 익명 객체는 type으로 사용할 수 없음. 단 익명 객체가 상속을 받은 경우 상속 받은 타입으로는 사용할 수 있음 fun returnAnonymousObjectSuperType(): Person.Student = object : Person.Student("anonymous", 10, 3) { // sealed class의 하위 클래스를 상속 받는 것이 허용됩니다.(멤버 함수 내부여서 재귀호출이 발생하지 않습니다.) //override var name: String = "anonymous has super type" //override var age: Int = 10 var name1: String = "anonymous has super type..." + this@Person.name var age1: Int = 10 }
// inherits sealed class/public/func/inner // 재귀호출이 발생하지 않아 허용될 것 같지만, 역시 Local class에서 sealed class는 상속받지 못합니다. // fun returnAnonymousObjectSuperType1(): Person = // object : Person("anonymous", 10) { // //override var name: String = "anonymous has super type" // //override var age: Int = 10 // var name: String = "anonymous has super type..." + this@Person.name // var age1: Int = 10 // }
fun testAnonymousObjectAccess() { println("testAnonymousObjectAccess") //println(objAnonymous.name) // error: public으로 선언되어 로컬, private 영역을 벗어날 수 있는 익명 객체는 type으로 사용할 수 없음 println(returnPrivateAnonymousObject().name) // private 멤버 함수에서 리턴하는 object는 영역 내에서 type으로 사용 가능 println(returnAnonymousObjectSuperType().name) // public이지만 super type이 있는 경우 type( super type 한정 )으로 사용 가능 //returnAnonymousObjectSuperType().name1 // error: anonymous object를 전달 받은 후 anonymous object만의 멤버에는 접근 불가능 } }
var objAnonymous1 = object { var name1: String = "anonymous global" var age1: Int = 10 }
fun main(args: Array<String>) { var person: Person = Person.Worker("Max", 30, "Mad Company")
if (person is Person.Worker) println("${person.name} ${person.age} ${person.company}") else println("${person.name} ${person.age}")
var objNum = when (person) { // when 식에서 sealed class의 모든 경우(타입)를 명시했다면 else 생략 가능 is Person.Student -> 1 is Person.Baby -> 2 is Person.Worker -> 3 is Person.Senior -> 4 is Person.PersonObject -> 5 // 새로운 하위 타입이 추가될 경우 when 식이 완전하지 않게 되므로 에러가 발생함 } println(objNum) var objAnonymous = object { // 일반 함수 내에서 익명 클래스 선언 및 객체 생성 var name1: String = person.name // 지역 변수 접근 var age: Int = person.age } println(objAnonymous) person.testAnonymousObjectAccess() person.returnAnonymousObjectSuperType().name } |