Annotations & Reflection

Annotations are metadata labels you attach to code, and reflection is the ability of a program to inspect its own classes, functions, and properties at runtime.

Learn Annotations & Reflection in our free Kotlin course — a beginner-friendly interactive lesson with worked examples, a practice exercise and a quick…

Part of the free Kotlin course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.

In this lesson you'll declare your own annotations, use built-in ones like @Deprecated and @JvmStatic , and read type information with ::class and KClass .

What You'll Learn in This Lesson

1️⃣ Declaring and Applying Annotations

You declare an annotation with the annotation class keyword. Its constructor parameters become the data the annotation carries. You then apply it with an @ in front of a declaration. Crucially, an annotation does nothing on its own — it just sits there as metadata until a tool, framework, or reflection reads it.

2️⃣ Built-in Annotations

Kotlin ships with useful annotations. @Deprecated marks a declaration as outdated and produces a compiler warning (with an optional ReplaceWith auto-fix). @JvmStatic makes a companion-object member callable as a real static from Java. Others you'll meet include @JvmOverloads and @Throws .

Notice the deprecated function still executes — annotations don't block code, they inform the compiler and tooling. The IDE will draw a strikethrough over sayHi and offer to replace it.

3️⃣ Reflection with ::class and KClass

Reflection lets your program inspect itself while running. The ::class reference gives you a KClass — an object describing a type. From an instance use value::class ; from a type use TypeName::class . A KClass exposes simpleName , qualifiedName , and members .

We sorted the property names so the output is predictable. In real code, full members reflection on the JVM needs the kotlin-reflect dependency.

Your turn. Fill in the ___ blanks, then run and compare.

Declare a no-parameter annotation, apply it to a class, then use reflection to print that class's name.

📋 Quick Reference — Annotations & Reflection

Practice quiz

What is an annotation in Kotlin?

  • A type of loop
  • A way to throw exceptions
  • Metadata attached to code that does nothing on its own
  • A collection operator

Answer: Metadata attached to code that does nothing on its own. An annotation carries metadata; it only matters when a tool or reflection reads it.

Which keyword declares your own annotation?

  • annotation class
  • data class
  • object
  • sealed class

Answer: annotation class. You declare one with the annotation class keyword.

What does @Deprecated do to a function it marks?

  • Deletes the function
  • Makes it private
  • Stops it from compiling
  • Produces a compiler warning but the function still runs

Answer: Produces a compiler warning but the function still runs. @Deprecated only warns; the deprecated function still executes.

What does @Target control for an annotation?

  • How long it survives
  • Where the annotation may be applied
  • Its default arguments
  • Whether it is public

Answer: Where the annotation may be applied. @Target lists the AnnotationTargets allowed, like CLASS or FUNCTION.

Which @Retention is needed so reflection can read an annotation at runtime?

  • RUNTIME
  • SOURCE
  • BINARY
  • COMPILE

Answer: RUNTIME. RUNTIME keeps the annotation available so reflection can read it.

How do you get a KClass from an instance named r?

  • r.getClass()
  • KClass(r)
  • r::class
  • r.kclass

Answer: r::class. Use the ::class reference on the instance, e.g. r::class.

What does KClass.simpleName return?

  • The full package path
  • The class name as a String
  • The number of members
  • A list of properties

Answer: The class name as a String. simpleName is just the class name; qualifiedName includes the package.

What value must an annotation argument be?

  • Any runtime variable
  • A lambda
  • A mutable list
  • A compile-time constant such as a literal or const val

Answer: A compile-time constant such as a literal or const val. Annotation arguments must be compile-time constants.

When is reflection most appropriate?

  • For all ordinary application logic
  • When you genuinely cannot know the types ahead of time
  • To replace every interface
  • To speed up loops

Answer: When you genuinely cannot know the types ahead of time. Reflection is slow and bypasses safety; use it only when types are unknown ahead of time.

What does @JvmStatic do?

  • Makes a function run faster in Kotlin
  • Marks a class as final
  • Generates a real JVM static member for Java interop
  • Adds null safety

Answer: Generates a real JVM static member for Java interop. @JvmStatic helps Java call companion members as real statics; no effect from Kotlin.