I find it can only access backing field in the set or get.Is there any way can access backing field in other place at class?
for example.
var width:Int=0
get() {
return field*10;
}
set(value) {
field=value/10;
}
I want to access the real value but not it multiple 10
when i using c#,there are no field keyword so always need to declare a new variable to store the real data.In the previous example it's will be something look like
private var _width=0;
var width:Int
get() {
return _width*10;
}
set(value) {
_width=value/10;
}
so if i want to access real value in the class,i can just access _value.
But in kotlin,is there have someway can just access backing field without these verbose declaration?
No. Your C# example works fine in Kotlin, it's called a backing property.
Kotlin, You can use backing properties
Backing Properties
If you want to do something that does not fit into this "implicit backing field" scheme, you can always fall back to having a backing property:
private var _table: Map<String, Int>? = null
public val table: Map<String, Int>
get() {
if (_table == null) {
_table = HashMap() // Type parameters are inferred
}
return _table ?: throw AssertionError("Set to null by another thread")
}
In all respects, this is just the same as in Java since access to private properties with default getters and setters is optimized so that no function call overhead is introduced.
Related
In java you can do the follwing:
public class Foo {
private String bar = "text";
public void method() {
// direct access (no logic)
System.out.println(this.bar);
}
// only if you access the object from the outside
// you are forced to use the getter with some logic in it
public String getBar() {
System.out.println(this.bar);
return this.bar;
}
}
But if you define a getter or a setter with logic in Kotlin you are forced to always execute this logic when accessing the field:
class Foo {
var bar: String = "text"
get() {
println(field)
return field
}
private set
fun method() {
// this also executes the getter
// Is it possible to skip the getter
// and directly access the field?
println(this.bar)
}
}
Is there a better way to access the field without executing the getter or setter logic than creating your own fun getBar() in Kotlin?
There is no possible way to skip a getter or a setter, they are intended to block the direct access of a property.
What you can do is make a multi-reference to same value (fake-referencing):
private var _bar: String = "text"
var bar
get() {
// some operations intercepting the getter
return _bar
}
// direct access
_bar
// intercepted access public field
bar
In Kotlin the backing fields (in your case the private variable) are not exposed by design. There are a few exceptions explained here: https://kotlinlang.org/docs/reference/properties.html#backing-fields
All access to val and var happens through implicit getters and setters. A val resolves to a property with a getter() while var resolves to a property with a getter and a setter: https://kotlinlang.org/docs/reference/properties.html#properties-and-fields
Currently I'm starting to learn Kotlin. I have a property like this:
var startTime: Int
get() = {
// read value from database
}
set(value) {
// save value to database
}
Here I always read and write the value every time I use the getter and setter.
Can this property be evaluated lazy? I want to read the value once the first time I use the getter and cache it for following calls. I know that values can be lazy but I found nothing about variables. What is the correct way in Kotlin to cache this property?
Kotlin offers lazy properties (https://kotlinlang.org/docs/reference/delegated-properties.html#lazy) that are computed on first access and cached.
val lazyValue: String by lazy {
println("computed!")
"Hello"
}
fun main(args: Array<String>) {
println(lazyValue)
println(lazyValue)
}
Will produce
computed!
Hello
Hello
What you need is not lazy evaluation, but a backing field:
private var _startTime: Int? = null
var startTime: Int
get() = {
if (_startTime != null) {
return _startTime!!
} else {
// read value from database and assign it to _startTime
}
}
set(value) {
_startTime = value
// save value to database
}
Alternatively you could declare _startTime as non-nullable and have an additional flag private var isStartTimeSet: Boolean = false used for checking if it has been fetched from database already.
In a Kotlin interface, does it matter if properties are declared with empty get/set statements?
For instance...
interface ExampleInterface {
// These...
val a: String
get
var b: String
get
set
// ...compared to these...
val c: String
var d: String
}
I'm having a hard time noticing a difference.
When implementing the interface, it doesn't seem to matter if I use getters/setters for the properties, or if I set the value directly.
When accessing these through java, the val's both have getters, and the var's both have getters and setters.
public void javaMethod(ExampleInterface e) {
e.getA();
e.getB();
e.setB();
e.getC();
e.getD();
e.setD();
}
The property declarations in your example are identical, get and set can be safely removed from there, because, as you correctly noted, the accessors are generated anyway. The syntax with get and set can, however, be used to provide an accessor implementation or to restrict its visibility.
Providing implementation:
interface ExampleInterface {
var b: String
get() = ""
set(value) { }
}
This example shows a default implementation of a property declared in an interface. This property can still be overriden inside the interface implementations.
class Example {
var b: String = ""
get() = "$field$field"
}
Here, get() = ... overrides the default getter behavior of a property with a backing field, whereas set is not mentioned, thus it behaves normally.
Visibility restriction:
class Example {
var s: String = "s"
private set
}
In this example, the setter visibility is private. The visibility of get is always the same to the visibility of the property, so there's no need to specify it separately. Interfaces cannot declare private members.
abstract class Example {
abstract var b: String
protected set // Restrict visibility
}
The setter of this property is restricted to this class and its subclasses. Interfaces cannot declare protected members.
Of course, an accessor implementation can be combined with visibility restriction:
class Example {
var s: String = "abc"
private set(value) { if (value.isNotEmpty()) field = value }
}
See also:
The Kotlin reference article about properties
Properties visibility explanation in another answer
I have been reading about properties in Kotlin, including custom getters and setters.
However, I was wondering if it is possible to create a custom getter with extra parameters.
For example, consider the following method in Java:
public String getDisplayedValue(Context context) {
if (PrefUtils.useImperialUnits(context)) {
// return stuff
} else {
// return other stuff
}
}
Note that the static method in PrefUtils has to have Context as a parameter, so removing this is not an option.
I would like to write it like this in Kotlin:
val displayedValue: String
get(context: Context) {
return if (PrefUtils.useImperialUnits(context)) {
// stuff
} else {
// other stuff
}
}
But my IDE highlights all of this in red.
I am aware I can create a function in my class to get the displayed value, but this would mean I would have to use .getDisplayedValue(Context) in Kotlin as well instead of being able to refer to the property by name as in .displayedValue.
Is there a way to create a custom getter like this?
EDIT: If not, would it be best to write a function for this, or to pass Context into the parameters of the class constructor?
As far as I know, property getter cannot have parameter. Write a function instead.
You can do this by having a property that returns an intermediate object that has a get and/or set operator with the parameters that you want, rather than returning the value directly.
Having that intermediate object be an inner class instance may be useful for providing easy access to the parent object. However, in an interface you can't use inner classes so in that case you might need to provide an explicit constructor parameter referencing the parent object when constructing your intermediate object.
For instance:
class MyClass {
inner class Foo {
operator fun get(context: Context): String {
return if (PrefUtils.useImperialUnits(context)) {
// return stuff
} else {
// return other stuff
}
}
}
val displayedValue = Foo()
}
...
val context : Context = whatever
val mc : MyClass = whatever
val y: String = mc.displayedValue[context]
You can do for example:
val displayedValue: String by lazy {
val newString = context.getString(R.string.someString)
newString
}
I want to define my own accessor for a field, like this:
var item: Item
get() {...}
set(value) {...}
I get an error because item is not initialized. I cant add lateinit because I define the get and set methods.
What I can choose is to declare another nullable field, and use that field to implement the item accessors, which is too stupid and redundant.
So I guess there must other ways to implement this requirement...
update:
Thanks for you reply.
I think I didnt express it clearly. And After I read the doc multiple times, I think the answer is NO.
My requirement is: Is there an easier alternative way to declare this?
private var _table: Map<String, Int>? = null
public val table: Map<String, Int>
get() {
if (_table == null)
_table = HashMap() // Type parameters are inferred
return _table ?: throw AssertionError("Set to null by another thread")
}
We have to declare a nullabe backing property so we can customize accessors and also leave the field uninitialized.
If you declare a property with a backing field, you need to initialize it. If you don't want do initialize it, you can declare custom getters and setters.
var item: String
get() = "my String"
set(value) {
log(value)
//do something with value
}
If you don't have a value to initialize the property with, declare it nullable and initialize it with null
var item: String? = null
get() = field
set(value) {
field = value
//do something with value
}
If this doesn't match your requirements, please update the question to clarify.