'In which situation val/var is necessary in Kotlin constructor parameter?
Right code:
class MainActHandler(val weakActivity: WeakReference<Activity>): Handler() {
override fun handleMessage(msg: Message?) {
val trueAct = weakActivity.get() ?: return
if (msg?.what == ConversationMgr.MSG_WHAT_NEW_SENTENCE){
val sentence = msg.obj as String?
trueAct.conversation.text = sentence
}
super.handleMessage(msg)
}
}
cannot be resolved code:
class MainActHandler(weakActivity: WeakReference<Activity>): Handler() {
override fun handleMessage(msg: Message?) {
val trueAct = weakActivity.get() ?: return
if (msg?.what == ConversationMgr.MSG_WHAT_NEW_SENTENCE){
val sentence = msg.obj as String?
trueAct.conversation.text = sentence
}
super.handleMessage(msg)
}
}
cannot be resolved code screenshot
The only difference is the "val" has been deleted and cannot be resolve.
Which might be important is that it's a inner class.
BUT
This one class without "val/var" in constructor parameter is working:
class BookInfo(convrMgr: ConversationMgr, id: String, queue: RequestQueue, queueTag:String) {
val TAG = "BookInfo"
var title: String? = ""
init {
val url = "https://api.douban.com/v2/book/$id"
// Request a string response from the provided URL.
val stringRequest = StringRequest(Request.Method.GET, url,
Response.Listener<String> { response ->
Log.d(TAG + " Response", response.substring(0))
// Parse JSON from String value
val parser = Parser()
val jsonObj: JsonObject =
parser.parse(StringBuilder(response.substring(0))) as JsonObject
// Initial book title of book properties.
title = jsonObj.string("title")
Log.d(TAG + " Book title", title)
convrMgr.addNewMsg(title)
},
Response.ErrorListener { error -> Log.e(TAG + " Error", error.toString()) })
// Set the tag on the request.
stringRequest.tag = queueTag
// Add the request to the RequestQueue.
queue.add(stringRequest)
}
}
And if I add var/val before "queue: RequestQueue", I'll get suggestion:
"Constructor parameter is never used as a property less. This inspection reports primary constructor parameters that can have 'val' or 'var' removed. Unnecessary usage of 'val' and 'var' in primary constructor consumes unnecessary memory."
I am just confused about it.
Solution 1:[1]
When you write val
/var
within the constructor, it declares a property inside the class. When you do not write it, it is simply a parameter passed to the primary constructor, where you can access the parameters within the init
block or use it to initialize other properties. For example,
class User(val id: Long, email: String) {
val hasEmail = email.isNotBlank() //email can be accessed here
init {
//email can be accessed here
}
fun getEmail(){
//email can't be accessed here
}
}
Constructor parameter is never used as a property
This suggestion is saying that you do not use this property in place apart from the initialization. So, it suggests you to remove this property from the class.
Solution 2:[2]
Constructor parameters must use var
or val
when they are used as a property elsewhere in the class. They do not need to be properties if they are only used for class initialization.
In the example below, the parameter must be a property (var
or val
) because it is used in a method:
class A(val number: Int) {
fun foo() = number
}
In this other example, the parameter is only used to initialize the class, so it does not need to be a property:
class B(number: Int): A(number) {
init {
System.out.println("number: $number")
}
}
Solution 3:[3]
This might be a late answer but the magic lies under the hood:
Based on @BakaWaii's
answer:
Putting var/val will make the variable a property of the class and not putting it will make it a parameter of only the constructor function.
So what does it mean, to understand lets look into some code:
class Test(a: Int){}
Now Lets see the decompiled java code:
public final class Test {
public Test(int a) {
}
}
So now if I try to access a
using the object of Test()
like the below code:
Test t = new Test(10);
t.a //Error
It will give me error. Unresolved reference: a
. Why because a
is a parameter of the constructor only.
Now if we put var/val in the paramater like below:
class Test(var a: Int){}
The decompliked Java code will become:
public final class Test {
private int a;
public final int getA() {
return this.a;
}
public final void setA(int var1) {
this.a = var1;
}
public Test(int a) {
this.a = a;
}
}
Thus it will not only give you a class property but also give you getter/setters for setting the values.
Now the next question arises if the field a
is private
how can it be accessed. Simple answer in Java you cannot, i.e. if you are calling the KT class from a Java you will not be able to assign value of a
like Test(1).a = 10
but will have to use Test(1).setA(5)
.
But as kotlin internally handles getters/setters Test(1).a = 5 will be ok.
Solution 4:[4]
For @Parcelize to work you need to open up the super's properties and override them in the child:
abstract class Goal(open var number: Int, open var name: String) : Parcelable
@Parcelize
class OperationalGoal(override var number: Int, override var name: String, var description: String) : Goal(number, name)```
Solution 5:[5]
In very simple terms, use var
or val
in class constructor parameters when you want to use that variable, say, inside a method within that class.
class User(var name: String, age: Int) {
var str = "John"
var num = 18
//name = str //this will result in a compile error if you uncomment it
fun setName(){
name = str //due to using var on class constructor parameter, we access constructor variable *name* inside a method
}
fun setAge(){
//age = num //this will result in a compile error if you uncomment it, because var wasn't used in the *age* parameter within the class constructor, which means we can't access *age*
}
}
Run this Kotlin Playground code to get a clearer idea of what's going on.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | nikhil bansal |
Solution 2 | Paulo Merson |
Solution 3 | |
Solution 4 | Abhilash Das |
Solution 5 | M.Ed |