diff --git a/docs/topics/concepts/Classes and objects/Object expressions and declarations/README.md b/docs/topics/concepts/Classes and objects/Object expressions and declarations/README.md index f40b37a2e60..38c83f7af17 100644 --- a/docs/topics/concepts/Classes and objects/Object expressions and declarations/README.md +++ b/docs/topics/concepts/Classes and objects/Object expressions and declarations/README.md @@ -1,7 +1,3 @@ -* 👀Ways to create an object / slight modification of some class, without declaring explicitly a new subclass 👀 - * object expressions - * object declarations - # Object expressions * TODO: @@ -16,8 +12,7 @@ * TODO: ## Data objects * TODO: -## Companion objects -* TODO: + # Code Examples * Mirror the examples added, to run it locally diff --git a/docs/topics/concepts/Classes and objects/Object expressions and declarations/object-declarations.md b/docs/topics/concepts/Classes and objects/Object expressions and declarations/object-declarations.md index 8f6e4ccb2fc..17fb4aaa075 100644 --- a/docs/topics/concepts/Classes and objects/Object expressions and declarations/object-declarations.md +++ b/docs/topics/concepts/Classes and objects/Object expressions and declarations/object-declarations.md @@ -1,10 +1,12 @@ [//]: # (title: Object expressions and declarations) -Sometimes you need to create an object that is a slight modification of some class, without explicitly declaring a new -subclass for it. Kotlin can handle this with _object expressions_ and _object declarations_. +* 👀Ways to create an object / slight modification of some class & NOT new subclass 👀 + * object expressions + * object declarations ## Object expressions +* TODO: _Object expressions_ create objects of anonymous classes, that is, classes that aren't explicitly declared with the `class` declaration. Such classes are useful for one-time use. You can define them from scratch, inherit from existing classes, or implement interfaces. Instances of anonymous classes are also called _anonymous objects_ because they are defined by @@ -284,71 +286,34 @@ fun main() { ### Companion objects -An object declaration inside a class can be marked with the `companion` keyword: +* := object declaration | class / marked with `companion` -```kotlin -class MyClass { - companion object Factory { - fun create(): MyClass = MyClass() + ``` + class ClassName { + companion object ObjectName { + CompanionObjectMembers + } + classMembers } -} -``` - -Members of the companion object can be called simply by using the class name as the qualifier: - -```kotlin -val instance = MyClass.create() -``` - -The name of the companion object can be omitted, in which case the name `Companion` will be used: - -```kotlin -class MyClass { - companion object { } -} - -val x = MyClass.Companion -``` - -Class members can access the private members of the corresponding companion object. - -The name of a class used by itself (not as a qualifier to another name) acts as a reference to the companion -object of the class (whether named or not): - -```kotlin -class MyClass1 { - companion object Named { } -} - -val x = MyClass1 - -class MyClass2 { - companion object { } -} - -val y = MyClass2 -``` - -Note that even though the members of companion objects look like static members in other languages, at runtime those -are still instance members of real objects, and can, for example, implement interfaces: - -```kotlin -interface Factory { - fun create(): T -} - -class MyClass { - companion object : Factory { - override fun create(): MyClass = MyClass() - } -} - -val f: Factory = MyClass -``` - -However, on the JVM you can have members of companion objects generated as real static methods and fields if you use -the `@JvmStatic` annotation. See the [Java interoperability](java-to-kotlin-interop.md#static-fields) section -for more detail. + ``` + * ways to refer to `companion` object + * ⚠️if ObjectName (name of the companion object) is omitted -> `ClassName.Companion` ⚠️ + * ⚠️if ObjectName is declared -> `ClassName.ObjectName` ⚠️ + * `ClassName.Companion` NOT valid here + * 👁️1! companion object allowed / class 👁️ + * `classMembers` -- can access to -- private `CompanionObjectMembers` + * `ClassName` is used as reference to the companion object -- `print(companionObject)`-- + * `CompanionObjectMembers` + * seem statics + * ⚠️ are instances of real objects | runtime ⚠️ + * == own state & behavior + implement interfaces + * == companion objects == objects +* `ClassName.CompanionObjectMember` + * way to call companion object’s members + * ONLY valid if `CompanionObjectMember` is public + * 👁️!= `instanceClassName.CompanionObjectMember`, does NOT work 👁️ +* `@JvmStatic CompanionObjectMembers` -> real static members | JVM + * Check [Java interoperability](java-to-kotlin-interop.md#static-fields) ### Semantic difference between object expressions and declarations diff --git a/docs/topics/concepts/Classes and objects/Object expressions and declarations/objectDeclaration.kt b/docs/topics/concepts/Classes and objects/Object expressions and declarations/objectDeclaration.kt index 6fa56820abb..59bfd9f898c 100644 --- a/docs/topics/concepts/Classes and objects/Object expressions and declarations/objectDeclaration.kt +++ b/docs/topics/concepts/Classes and objects/Object expressions and declarations/objectDeclaration.kt @@ -62,11 +62,73 @@ object ObjectDeclarationWithSuperTypes : MyMouseAdapter() { } }*/ +// 4. companion objects +class MyClass { + // NO objectname for the companion + companion object { + var number = 3 + private val privateNumber = 4 + } + + // class member can get access to a private member of a companion object + fun sampleFunction() { + println(privateNumber) + } + // ONLY allowed 1! companion object / class -> Next companion object declaration throws an erro + /*companion object another { + val anotherNumber = 4 + }*/ +} +class AnotherClass { + // name for the companion + companion object nameToCompanionObject{ + var number = 3 + } +} + // 4.4 companion objects | runtime == real objects +interface Greeter { + fun greet(): String +} + +class ClassCheckCompanionObjectsAreLikeObjects { + companion object : Greeter { // companion object / NO name, implementing an interface + override fun greet(): String { + return "Hello from the companion object!" + } + fun show() { + println("This is a companion object method.") + } + } +} + fun main() { // 2. Initialize an object declaration CounterObject.incrementCounter() var objectInitialized = CounterObject.getCounter() println("objectInitialized::class.simpleName ${objectInitialized::class.simpleName} whose value is $objectInitialized") - + // 4. companion object + val myClass = MyClass() + // 4.1 `instanceClassName.CompanionObjectMember` NOT valid + /*println("myClass.privateNumber ${myClass.privateNumber}") + println("myClass.number ${myClass.number}")*/ + // 4.2 `ClassName.CompanionObjectMember` just if member is public + println("MyClass.number ${MyClass.number}") + //println("MyClass.privateNumber ${MyClass.privateNumber}") NOT valid because it's private + // 4.3 companion object / name omitted -> refer to it via `ClassName.Companion` + val companionReference = MyClass.Companion + println("companionReference ${companionReference}") // ClassName is print as reference to the companion object + println("companionReference.number ${companionReference.number}") + // companion object / name -> refer to it via it's name + val anotherCompanionReferenceByName = AnotherClass.nameToCompanionObject + println("anotherCompanionReferenceByName ${anotherCompanionReferenceByName}") // ClassName is print as reference to the companion object + // val anotherCompanionReference = AnotherClass.Companion NOT valid to refer by Companion + //println("anotherCompanionReference ${anotherCompanionReference}") + // 4.4 companion objects | runtime == objects + // reference of type Greeter / -- assigned to -- ClassCheckCompanionObjectsAreLikeObjects == reference to the companion object + val greeter: Greeter = ClassCheckCompanionObjectsAreLikeObjects + println(greeter.greet()) // call from this reference to the method -> proving companion object is a real object + + // Checking the runtime type + println("Is companion object an instance of Greeter? ${ClassCheckCompanionObjectsAreLikeObjects is Greeter}") } \ No newline at end of file