Kotlin二级构造函数参数为何不允许使用val?
val on secondary constructor parameters in Kotlin? Great question! This error boils down to how Kotlin differentiates between primary and secondary constructors, and their distinct roles in class initialization. Let’s break it down clearly:
1. Primary constructors are designed to define class properties
The primary constructor (the one declared right after the class name: class Person(val name: String)) has a special core purpose: it’s the single source of truth for defining a class’s member properties. When you add val or var to a primary constructor parameter, Kotlin automatically:
- Creates a corresponding read-only (
val) or mutable (var) class property - Generates the appropriate getter (and setter for
var) for that property
In your original code, val name: String is already a read-only class property—this is the official name value your class uses everywhere.
2. Secondary constructors exist only for supplementary initialization logic
Secondary constructors are not meant to define new properties—they’re just there to provide alternative ways to initialize the class, building on the primary constructor’s setup. Their parameters are temporary variables used solely during the initialization process.
Kotlin blocks you from adding val/var to these parameters for two key reasons:
- Ambiguity: Would the
val namein your secondary constructor create a new class property (conflicting with the primary constructor’sname), or just mark the parameter as read-only? The compiler can’t safely infer your intent here. - Design consistency: Kotlin’s design prioritizes keeping property definitions centralized in the primary constructor. Scattering property definitions across multiple constructors makes code harder to read, maintain, and reason about.
Also, a quick side note: all function parameters (including secondary constructor parameters) are implicitly read-only in Kotlin by default. You don’t need to add val to make them immutable—the name parameter in your secondary constructor can’t be modified anyway, so adding val is redundant at best.
3. The simple fix for your code
You don’t need to add val to the secondary constructor’s name parameter at all. The primary constructor already handles defining the name class property, and your secondary constructor just passes the parameter value to the primary constructor via this(name).
Here’s your original valid code (which works perfectly for your use case):
class Person(val name: String) { private var surname: String = "Unknown" constructor(name: String, surname: String) : this(name) { this.surname = surname } }
内容的提问来源于stack exchange,提问作者Jan Slominski




