skip to content

KClass & ::class References

::class gives you a KClass, from which you can read names, get an object's singleton instance, enumerate sealed subclasses, and test subtyping. The sealedSubclasses accessor is the one people find genuinely useful in real code.

part ofKotlinoverview, primer and where to startread it →
on this pageshow

questions

5

How do you obtain a KClass in Kotlin, and what is the difference between writing `instance::class` and `String::class`?

level: juniorimportance: must knowfreq 70%

answer

  1. ::class operator returns KClass
  2. Type::class = static declared class
  3. instance::class = runtime class of the value
  4. simpleName / qualifiedName are nullable
  5. generics erased -> use typeOf for KType

basics

~20 s

Use ::class. On a value like x::class you get the real runtime type of that object. On a type name like String::class you get that exact declared class. Both give a KClass, Kotlin's reflection handle for a class.

solid answer

~40 s

Kotlin exposes a class reference through the `::class` operator, producing a `kotlin.reflect.KClass<T>`. There are two forms. `Type::class` (a class literal on a type name, e.g. `String::class`) resolves statically to that exact declared class and has type `KClass<String>`. `instance::class` (a bound class reference on an expression) returns the *runtime* class of the object the expression evaluates to, so for `val a: Any = "hi"; a::class` you get `String::class`, not `Any`. The instance form is non-null and evaluates its receiver. Common members you read off a KClass include `simpleName`, `qualifiedName`, and `isInstance()`. The full member set (e.g. `members`, `objectInstance`) requires the `kotlin-reflect` dependency at runtime, but `simpleName`/`qualifiedName` and basic identity work from the stdlib alone.

code

kotlin · 8 lines
kotlin
open class Animal
class Dog : Animal()

fun main() {
    val a: Animal = Dog()
    println(Animal::class.simpleName) // Animal (static)
    println(a::class.simpleName)      // Dog    (runtime)
}

go deeper

for a junior

Knows ::class yields a KClass and can read simpleName/qualifiedName.

for a middle

Distinguishes Type::class (static) from instance::class (runtime) and explains the out-projection.

for a senior

Connects to erasure (no generics on KClass) and notes which members need kotlin-reflect vs stdlib.

for a principal

Reasons about where to use bound vs literal references in framework/registry code and the cost/erasure trade-offs.

## What a KClass is `KClass<T>` (from `kotlin.reflect`) is Kotlin's reflection representation of a class or interface — the entry point for inspecting a type at runtime (its name, members, supertypes, whether it is an object, etc.). It is the Kotlin analogue of Java's `java.lang.Class`, but richer (it knows about Kotlin concepts like `object` singletons, sealed subclasses, and nullability of members). ## Two ways to get one with `::class` ### 1. Class literal on a type — `Type::class` ```kotlin val k: KClass<String> = String::class // statically resolved ``` Here `String` is a *type name*, so the compiler resolves the class at compile time. The static type is `KClass<String>`. Use this when you know the type literally. ### 2. Bound class reference on an instance — `expr::class` ```kotlin val a: Any = "hi" val k = a::class // KClass<out Any> at compile time, String::class at runtime println(k.simpleName) // String ``` Here the receiver expression is *evaluated*, and you get the **actual runtime class** of the resulting object, regardless of the declared static type. This is polymorphic dispatch for types. The compile-time type is `KClass<out T>` (a projection, because the runtime type may be a subtype). ## Key consequence: static vs runtime - `SomeType::class` ignores any runtime value — it is the declared type. - `value::class` follows the object, so a `List<*>` reference might report `ArrayList`. ## Reading basic info ```kotlin String::class.simpleName // "String" String::class.qualifiedName // "kotlin.String" String::class.isInstance("x") // true ``` `simpleName` and `qualifiedName` are nullable (`String?`) because anonymous and local classes have no such names. ## Generics are erased Because of JVM type erasure, `listOf(1,2)::class` is just `ArrayList::class`; the element type `Int` is gone. To capture full generic type info you use `typeOf<...>()`/`KType` instead — that is a separate mechanism. ## Interop note A `KClass` is stdlib-level for names and identity, but the full reflective surface needs the `kotlin-reflect` artifact on the classpath at runtime.

  • What is the compile-time type of `a::class` when `a: Animal`?
    `KClass<out Animal>` — an out-projection, since the runtime class is some subtype of Animal.
  • Can `simpleName` ever be null?
    Yes, for anonymous objects and certain local classes that have no source name.

Type::class is asking 'what does the label say', instance::class is asking 'what is this thing actually made of'.

saying these in an interview costs you the question

  • Claiming `instance::class` returns the declared/static type rather than the runtime type
  • Saying `::class` gives a `java.lang.Class` directly (that needs `.java`)
  • Believing generic type arguments survive on a KClass
  • Thinking `qualifiedName` is always non-null

context

open as a page

What does `KClass.objectInstance` return, and how does it behave for objects vs regular classes?

level: middleimportance: should knowfreq 45%

basics

~10 s

objectInstance gives you the single shared instance of a Kotlin object (a singleton). If the KClass is for an object declaration it returns that instance; for an ordinary class it returns null.

open as a page

What does `KClass.sealedSubclasses` give you, and what are its limitations for non-sealed or deeply nested hierarchies?

level: middleimportance: should knowfreq 40%

basics

~10 s

sealedSubclasses lists the direct subtypes of a sealed class or interface as KClass objects. For a non-sealed class it is empty. It only returns the immediate children, not grandchildren.

open as a page

How do `isSubclassOf()` / `isSuperclassOf()` work on KClass, and how do they differ from `isInstance()` and the `is` operator?

level: seniorimportance: should knowfreq 35%

basics

~20 s

a.isSubclassOf(b) checks whether class a is the same as or descends from class b — a class-to-class relationship. isInstance(x) and is check whether a value belongs to a type. The first compares two KClasses; the others test an object.

open as a page

Explain `simpleName` vs `qualifiedName` on a KClass, when each can be null, and how they behave for nested, local, and anonymous classes.

level: seniorimportance: nice to knowfreq 30%

basics

~10 s

simpleName is the short class name; qualifiedName is the full dotted name including package. Both are nullable: anonymous objects and local classes have no real name, so they return null.

open as a page