This question already has answers here:
What is the equivalent of Java static final fields in Kotlin?
(4 answers)
Closed 2 years ago.
Perhaps it was bad practice but in Java I would often create something like:
public class MyService extends Service {
public static final String ACTION_CONNECTED = "blablabla";
...
}
And reference it in another class like:
MyService.ACTION_CONNECTED
This was great. I could keep my constants nicely associated with their class.
I can't seem to find an equivalent in Kotlin. I see solutions flying around suggesting people create constants files (objects) but I don't think that's very elegant. I want there to be some way to expose a top-level const val BLAB outside its file so I can keep my ClassName.CONSTANT syntax going but it doesn't look like it's in the cards.
Is there (and what is it) a Kotlin equilivant to the good old public static final with regard to sharing constants between classes?
class MyService {
companion object {
#JvmStatic const val ACTION_CONNECTED = "blablabla"
}
}
MyService.ACTION_CONNECTED
This will be the equivalent of public static final for kotlin
If you want to create a final variable in kotlin, use val instead of using var
val LastCount = 1
and for creating a static variable use companion object key
companion object{
val lastCount = 1
}
now you want to have access to this variable in other classes.
so create a new class like this:
class Counter{
companion object{
val lastCount = 1
}
}
and then use it all over the project like this
Counter.lastCount
According to Jetbrains in this video:
https://www.coursera.org/learn/kotlin-for-java-developers/lecture/85GKr/objects-object-expressions-companion-objects
There are 3 ways to create static methods or functions for a class:
Declare static members at the top level (Default approach)
Declare them inside objects (Singletons)
Declare them inside companion objects
Using method 1 should be the easiest approach for you if you want to mimic the experience in Java as close as possible. You will be able to access the members using either the getter under the hood or using direct access. Here's an example:
MyService.kt will be the name of your Kotlin file.
val ACTION_CONNECTED = "blablabla"
class MyService :Service{
//your other class details
}
You can access it like this from another Kotlin file or Activity:
val myAction=ACTION_CONNECTED
It would also be better if you mark it as const, since it is a constant value like this:
const val ACTION_CONNECTED = "blablabla"
Related
I have some Kotlin code like this
object NativeInterface {
// Used to load the 'native-lib' library on application startup.
public val effectDescriptionMap: Map<String, EffectDescription>
and I'm trying to access from Java like this:
Effect it = NativeInterface.effectDescriptionMap[menuItem.title];
But it keeps saying that effectDescriptionMap is private, even though I explicitly placed public on it. From Kotlin I can access but not from Java.
The NativeInterface is an object not a class. You have to access the INSTANCE
NativeInterface.INSTANCE.getEffectDescriptionMap()
Short question
Can I modify the visibility of a Kotlin object's INSTANCE (for Java interop) to internal or lower?
Long question
I'm writing a library and I want to have an API file / class, written in Kotlin, that exposes a function to be called from either Java or Kotlin like this:
Kotlin:
API.function()
Java:
API.function();
I can achieve this by writing it like this:
Kotlin:
object API {
#JvmStatic
fun function() = TODO()
}
However, now I can also do this:
Java:
API.INSTANCE.function();
I want to prevent this access to INSTANCE to keep my API surface to a minimum for simplicity.
Can I modify the visibility of INSTANCE to internal or lower?
It's probably not possible, because any call to API (from Kotlin) returns the object's instance and that should probably be hidden too for this to be possible. However, I'm curious to see if it is without major hacks.
A solution using Java would be to write API in Java:
public final class API {
private API() {
}
public static void function() {
}
}
However, I'm looking for a solution written in Kotlin.
The closest I could come up with was something like this:
Create a file API.kt in a package com.example.api. Add your functions directly into that file, like this:
#file:JvmName("API")
package com.example.api
fun function() {
// ...
}
Kotlin:
You can import that function anywhere you need to use your api:
import com.example.api.function
Though you can't use your syntax API.function anymore.
Java:
The generated class would look something like this (no singleton, just static methods, but no private constructor):
public final class API {
public static final void function() {
// ...
}
}
Which then allows you to call it like API.function();
By specifiying #file:JvmName("API") you instruct kotlin to name the created class API.
I have a library, I have to tag a class with certain field dynamically (code generation) and I don't want the meta-data field names I generate to clash with user-defined field names.
Using JavaScript, we can use ES6 Symbols to do this. We can create getters/setters and retrieve fields using Symbols and in this way prevent name-clashing.
So using JS, it might look like:
export class Foo {
static libraryDefinedField = Symbol('lib.defined')
userDefinedField = 'whatev';
setLibraryDefinedField(v){
this[Foo.libraryDefinedField] = v;
}
getLibraryDefinedField(v){
return this[Foo.libraryDefinedField];
}
}
is there a way to do this with Java somehow - create instance or static fields on a class that won't conflict with user-defined fields?
Note that using JS, if there were user-generated static field properties and we wanted to prevent nameclashing, we might do this:
// put the symbol outside the class, so even static properties won't conflict
const libraryDefinedField = Symbol('lib.defined');
export class Foo {
userDefinedField = 'whatev';
setLibraryDefinedField(v){
this[libraryDefinedField] = v;
}
getLibraryDefinedField(v){
return this[libraryDefinedField];
}
}
Java has no notion of symbols the way ES6 has.
If you simply want to "tag" a class, why not consider making the class implement an (possibly empty) interface? Class and interface names are unique.
I need to create some extension methods in my Java code. I've read some posts here in SO and people suggest XTend or Scala in order to achieve this.
Now, my question would be.. if i write kind of an Adapter layer in Scala (adding there my extension methods) and then using that project as a dependency for my own Java project, are those extended methods available for me to use, or they are defined just for the 'scope of Scala project' and then the JVM output cannot provide those new methods to the other project using it?
EDIT:
What i need to do is to extend a full hierarchy of classes in a given library and give some new functionality. As for Java's first approach I should extend every class in that hierarchy creating my own hierarchy of extended classes adding the new method there. I would like to avoid this and give the final user the sense of native functionality in the original hierarchy.
Regards.
As mentioned above in the comments, it is very close to C# but not exactly there because of the type erasure. For example, this works fine:
object myLibExtensions {
implicit class TypeXExtension( val obj: TypeX ) extends AnyRef {
def myCustomFunction( a: String ): String = {
obj.someMethod(a)
}
}
}
It will act somewhat similar to C# extension methods, i.e. create static method wrappers in reasonable cases (but not always).
The only thing I am missing in Scala is that you can't (or at least I couldn't figure out how to) return the values of the types being extended. For example, assume I want to have something like an extension method "withMeta" that works as follows:
class TypeY extends TypeX { def methodOfY(...) ...}
var y: TypeY = ....
y.withMeta(...).methodOfY(...)
The following didn't work for me:
object myLibExtensions {
private val something = ....
implicit class Extension[T<:TypeX]( val obj: T ) extends AnyRef {
def withMeta( meta: Meta[T] ): T = {
something.associateMeta(obj,meta)
val
}
}
}
... because T is being erased to TypeX. So effectively you will have to write extensions for all specific leaf classes of the hierarchy in this case, which is sad.
I want to load a resource in a top level function using Class.getResourceAsStream().
Is there any way to get a reference to the class that the top level function will be compiled into so that I can write, for example
val myThing = readFromStream(MYCLASS.getResourceAsStream(...))
Another way I found is to declare a local class or an anonymous object inside a top level function and to get its enclosingClass:
val topLevelClass = object{}.javaClass.enclosingClass
Note: to work, this declaration should be placed on top level or inside a top-level function.
Then you can use the topLevelClass as a Class<out Any>:
fun main(args: Array<String>) {
println(topLevelClass) // class MyFileNameKt
}
With Java 7 you can get a reference to the current Java class from a top level function using
MethodHandles.lookup().lookupClass()
No, there is no syntax to reference that class. You can access it using Class.forName(). For example, if the file is called "Hello.kt" and is located in the package "demo", you can obtain the class by calling Class.forName("demo.HelloKt").
In the absence of a way to get a reference directly, I've fallen back on creating an anonymous object in the current package
val myThing = object: Any() {}.javaClass.getResourceAsStream(...)
As linters like detekt would flag anonymous classes as EmptyClassBlock you could also use something like
internal object Resources
fun resourceStream(name: String): InputStream {
return Resources.javaClass.getResourceAsStream(name)
}