One of the key differences between the object-oriented model in Kotlin and Java is the definition of static methods and classes. Generally speaking, a static class doesn’t have to be instantiated in order to be used. Similarly, to invoke a static method, we just have to know its name, not to instantiate an object of the class where such a method is defined. Show
In Java, classes may easily declare static fields or methods. However, the definition of a static class is a bit more
complex. Kotlin, on the other hand, greatly simplifies the job with native constructs such as package-level functions, In this article, we are first going to look at the legacy Java way of declaring static classes and methods. Secondly, we’ll see how the same thing can be achieved, with much less effort, in Kotlin. Then, we’ll compare the benefits of Kotlin’s way with respect to code reusability. Table of contents:
Static classes and methods in JavaIn object-oriented programming (OOP), static methods and fields are useful to model common values or operations that do not need to be tied to an
instance of a class. For example, the public final class Math { public static final double E = 2.7182818284590452354; public static final double PI = 3.14159265358979323846; public static int max(int a, int b) { ... } public static int min(int a, int b) { ... } } Static classes, on the other hand, are more tricky to define. In Java, only nested classes (that is, classes defined within another class) can be declared static. They do not need a reference to the outer class (the class they’re declared within). Hence, while we may not instantiate non-static nested classes without an instance of the outer class, static classes are independent. Furthermore, the class loader loads the code of static classes when they are first used and not when the enclosing class gets loaded. This allows us to reduce the memory footprint of our application. For example, we may want to use static classes to implement a thread-safe singleton class without paying the price of synchronizing the public class Singleton { private Singleton(){ } private static class SingletonHolder { private static final Singleton INSTANCE = new Singleton(); } public static Singleton getInstance() { return SingletonHolder.INSTANCE; } // … } In the example above, using a static class to hold a reference to the singleton instance gives us some nice properties:
Besides performance reasons, static classes are often used to improve the readability and the maintainability of the code, as we can use them to move components closer to where they are used. Static classes in KotlinAs Java, Kotlin allows us to define nested classes in our code. In Kotlin, however, a nested class is static by default. That is, by default nested classes in Kotlin do not hold a reference to the enclosing class: class Car(val model: String) { class Engine(val fuel: String) } fun main() { val engine = Car.Engine("Gasoline") val car = Car("SomeModel") println(engine.fuel) println(car.model) } In the example above, we defined a nested class Static classes in Kotlin can access the properties of the companion
object of the enclosing class. We’ll see more about companion If we want to define a nonstatic nested class in Kotlin we have to declare it as class Car(val model: String) { inner class Engine(val fuel: String) { val forModel = [email protected] } } fun main() { val engine = Car("SomeModel").Engine("Gasoline") println("${engine.forModel} - ${engine.fuel}") } Now that Similar to Java, nested classes can be declared also in the scope of a method of the enclosing class. In this case, the new class would be a local type. The main benefit of Kotlin’s approach is that it limits the risks of memory leaks, by default. In Java, it is easier to overlook the fact that a given nested class holds a reference to the enclosing class. In Kotlin, on the other hand, such a reference does not exist by default. Whether to use an inner class or a static one largely depends on the way we’re modeling our domain. Surely, static classes allow for greater code reusability, as we do not need to instantiate the enclosing class, while letting us define (possibly) dependent components close to one another. Static methods in KotlinKotlin greatly simplifies how we can define static methods or variables. In particular, it does so using (companion) Package-level functionsKotlin is not exclusively an object-oriented language because it also supports the functional programming paradigm: this is where package-level functions come from. As the name suggests, they are functions (or members) that do not belong to a given class but are instead defined within a package. Often, they are utility functions that are independent of any other class. For example, we can use them to implement handy functions to initialize a class. Assume we have a class named package com.logrocket.blog class Point(val x: Int, val y: Int) { override fun toString(): String = "Point($x, $y)" } Then, in a different package, we might define the following functions: // In file factory.kt package com.logrocket.blog.utils import com.logrocket.blog.Point val centerPoint = Point(x = 0, y = 0) fun onXAxis(x: Int) = Point(x, y = 0) fun onYAxis(y: Int) = Point(x = 0, y) We can then use the functions and values above just by importing them: package com.logrocket.blog import com.logrocket.blog.utils.centerPoint import com.logrocket.blog.utils.onXAxis fun main() { val point = onXAxis(5) println(centerPoint) println(point) } The main function above prints the strings Note how we defined two package-level functions in the Package-level functions and values are syntactic sugar for static fields and methods in Java. What the Kotlin compiler does is generate a Java class named after the Kotlin file, with static methods and fields in it. For example, the functions in package com.logrocket.blog.utils // Generated class class FactoryKt { public static Point centerPoint = new Point(0, 0); public static Point onXAxis(int x) { return new Point(x, 0); } public static Point onYAxis(int y) { return new Point(0, y); } } If we wanted to change the name of the
generated Java class, we could use the Lastly, if we want more utility functions to be compiled into the same generated Java class, or if we already have a file named ObjectsBy declaring an For example, we could define the following object PointFactory { val center = Point(x = 0, y = 0) fun onXAxis(x: Int) = Point(x, y = 0) fun onYAxis(y: Int) = Point(x = 0, y) } Then, differently than before, we have to
specify the name of the val point = PointFactory.onYAxis(5) As there’s only one instance of each Kotlin More great articles from LogRocket:
Companion objectsIn the example above, class Point(val x: Int, val y: Int) { companion object { val center = Point(x = 0, y = 0) fun onXAxis(x: Int) = Point(x, y = 0) fun onYAxis(y: Int) = Point(x = 0, y) } override fun toString(): String = "Point($x, $y)" } With companion val point = Point.onYAxis(5) A comparisonKotlin provides us with three different solutions to define static methods or fields. Package-level functions and values are the most idiomatic way. Often there’s no need to scope utility methods inside a class. In such cases, package-level members are a fine choice allowing for greater reusability of the code. As a matter of fact, most of the standard library is implemented using them. However, ConclusionStrictly speaking, in a pure object-oriented programming mindset, everything is better defined inside of a class. However, as we saw above, often we need methods that are different to place in an existing class. This can happen, for example, with utility methods that operate on a class but do not represent the behavior of that class. In languages like Java, the normality is to define Kotlin, on the hand, is not just an object-oriented language. It supports other programming paradigms, such as the functional one. Hence, it does not take the object orientation as strictly as Java, allowing us, for example, to define functions that are not tied to any class. On the one hand, this improves the reusability and the maintainability of the code. Furthermore, we can use the package structure and the visibility keywords to choose which portion of our codebase can use a given function or
As is common with modern programming languages, we have a number of ways to model the same thing and achieve the same result. Hence, it is always a matter of experience and sensibility to figure out what the right construct is and to use it appropriately. LogRocket: Full visibility into your web and mobile appsLogRocket is a frontend application monitoring solution that lets you replay problems as if they happened in your own browser. Instead of guessing why errors happen, or asking users for screenshots and log dumps, LogRocket lets you replay the session to quickly understand what went wrong. It works perfectly with any app, regardless of framework, and has plugins to log additional context from Redux, Vuex, and @ngrx/store. In addition to logging Redux actions and state, LogRocket records console logs, JavaScript errors, stacktraces, network requests/responses with headers + bodies, browser metadata, and custom logs. It also instruments the DOM to record the HTML and CSS on the page, recreating pixel-perfect videos of even the most complex single-page and mobile apps. Try it for free. Do static methods belong to the class?A static method belongs to the class rather than object of a class. A static method can be invoked without the need for creating an instance of a class.
Can static methods be called with instances?A static method cannot access a class's instance variables and instance methods, because a static method can be called even when no objects of the class have been instantiated.
Why can't this be used in static methods?The "this" keyword is used as a reference to an instance. Since the static methods doesn't have (belong to) any instance you cannot use the "this" reference within a static method.
Which of the following type of method Cannot access any nonIn the static method, the method can only access only static data members and static methods of another class or same class but cannot access non-static methods and variables.
|