Summary: This article continues to explore some of the more advanced aspects of Kotlin, having previously focused on Kotlin’s generics and generics variants. Now let’s take a look at Kotlin’s annotations. The annotations in Kotlin are 100% Java annotation-compatible and have a lot in common, but also some differences. Take a look
First, the nature of annotations
An annotation is essentially a code tag that acts on code. It allows you to annotate specific annotation code with additional information. However, this information can be retained at different times, such as source time, compile time, and run time. Then, at various times, the tag information can be retrieved in some way to process the actual code logic, often in what we call reflection.
2. Definition of annotations
The core concept of annotations in Kotlin, like In Java, is to provide metadata to code. And annotations do not directly affect code execution. An annotation allows you to associate additional metadata with a declaration, which can then be accessed in some way (such as runtime reflection and some source code tools).
3. Annotation declaration (label declaration)
Annotations are declared slightly differently in Kotlin than in Java, where they are declared primarily through the @interface keyword, In Kotlin, only the annotation class is declared. Note that in Kotlin, the compiler forbids specifying a class body for an annotation class because annotations are simply structures used to define the metadata associated with declarations and expressions.
- 1. Kotlin annotation declaration
package com.mikyou.annotation
// Just like a normal declaration, but with the annotation modifier in front of the class
annotation class TestAnnotation(val value: String)
Copy the code
- 2. Java annotation declarations
package com.mikyou.annotation;
Annotations in Java are defined by the @interface keyword, which is similar to an interface declaration, but with the @ prefix added
public @interface TestAnnotation {
String value(a);
}
Copy the code
Fourth, the application of annotations
- 1. Now that we know how to declare and define tags in the previous step, the next step is to use this tag and attach our defined tags to the specified code. Using annotations in Kotlin is the same as in Java. To apply an annotation it’s always the @ annotation class name.
@Target(AnnotationTarget.FUNCTION)
@Retention(value = AnnotationRetention.RUNTIME)
annotation class TestAnnotation(val value: Int)// Just like a normal declaration, but with the annotation modifier in front of the class
class Test {
@TestAnnotation(value = 1000)
fun test(a) {// Attach the TestAnnotation tag to the test function (add the TestAnnotation annotation)
/ /...}}Copy the code
- Annotations are used extensively in many common Java or Kotlin frameworks, such as our most common JUnit unit testing framework
class ExampleUnitTest {
@Test The @test annotation tells the JUnit framework that this is a Test method, as a Test call.
fun addition_isCorrect(a) {
assertEquals(4.2 + 2)}}Copy the code
- The annotation class in Kotlin can also have an annotation class as a parameter. Check out the @deprecated annotation source definition in Kotlin and see how it is used. The @deprecated annotation enhances a ReplaceWith feature on the original Java base. When an old API is in use, the compiler automatically replaces it with the new API in ReplaceWith. You can’t do this in Java; you have to click into the API to see the source code to use the new API properly.
// @deprecated annotations have more ReplaceWith functionality than Java, so when you call the remove method, the compiler will report an error. Using code prompts automatically IntelliJ IDEA not only prompts which function prompts to use to replace it, but also automatically fixes it quickly.
@Deprecated("Use removeAt(index) instead.", ReplaceWith("removeAt(index)"), level = DeprecationLevel.ERROR)// The level defined is ERROR, so that when you call the remove method, the compiler will report an ERROR.
@kotlin.internal.InlineOnly
public inline fun <T> MutableList<T>.remove(index: Int): T = removeAt(index)
Copy the code
Deprecated annotated remove function used
//Deprecated annotation usage
fun main(args: Array<String>) {
val list = mutableListOf("a"."b"."c"."d"."e")
list.remove(3)// An ERROR will be reported via the remove function annotation. The remove function is defined at the ERROR level, so the compiler will throw the ERROR directly
}
Copy the code
Finally, let’s look at the definition of the @deprecated annotation
@Target(CLASS, FUNCTION, PROPERTY, ANNOTATION_CLASS, CONSTRUCTOR, PROPERTY_SETTER, PROPERTY_GETTER, TYPEALIAS)
@MustBeDocumented
public annotation class Deprecated(
val message: String,
val replaceWith: ReplaceWith = ReplaceWith(""),// The constructor can use the annotation class as a function parameter
val level: DeprecationLevel = DeprecationLevel.WARNING
)
@Target()
@Retention(BINARY)
@MustBeDocumented
public annotation class ReplaceWith(val expression: String, vararg val imports: String)
Copy the code
Note: Annotation classes can only have parameters of the following types: primitive data types, strings, enumerations, class reference types, and other annotation classes (such as the Deprecated annotation class ReplaceWith annotation class)
Meta annotations in Kotlin
In Kotlin, as in Java, a Kotlin annotation class can itself be annotated, and annotation classes can be added. We call this kind of annotation a meta-annotation, and you can think of it as a basic annotation, you can think of it as a special label, a label for a label.
The Kotlin meta-annotation class is defined in the Kotlin. Annotation package. There are four meta-annotations: @Target, @Retention, @REPEATable and @MustbeAnnotation. @Target, @Retention, @REPEATable, @Documented, and @Inherited Are missing @Inherited meta-annotations.
@ $Target annotation
- 1, the introduction
Target is the name of the Target object, that is, the tag on the Target object in the code, you can specify more than one Target object.
- 2, source code definition
@Target(AnnotationTarget.ANNOTATION_CLASS)// You can label the tag by itself
@MustBeDocumented
// The annotation class constructor argument is a vararg modifier, so you can specify more than one target object at a time
public annotation class Target(vararg val allowedTargets: AnnotationTarget)
Copy the code
- 3. @target Specifies the Target of the @target meta-annotation
You can specify one or more Target objects in the @target annotation, so what Target objects are there? This leads to another AnnotationTarget enumeration class
public enum class AnnotationTarget {
CLASS, // Indicates that the object has classes, interfaces, object expressions, and annotation classes
ANNOTATION_CLASS,// indicates that the object has only annotation classes
TYPE_PARAMETER,// Indicates that the object is a generic type parameter (not yet supported)
PROPERTY,// indicates that the object is an attribute
FIELD,// Indicates that objects are fields, including fields behind attributes
LOCAL_VARIABLE,// indicates that the object is a local variable
VALUE_PARAMETER,// indicates that the object is an argument to a function or constructor
CONSTRUCTOR,// indicates that the object is a constructor, primary constructor or secondary constructor
FUNCTION,// indicates that the object is a function, excluding constructors
PROPERTY_GETTER,// Indicates that the object is a getter for the property
PROPERTY_SETTER,// indicates that the object is a setter function for the property
TYPE,// Indicates that the object is a type, such as class, interface, enumeration
EXPRESSION,// indicates that the object is an expression
FILE,// Indicates that the object is a File
@SinceKotlin("1.1")
TYPEALIAS// Indicates that the object is a type alias
}
Copy the code
@ Retention yuan note
- 1, the introduction
Retention is Retention when applied to a annotation. Both Java and Kotlin generally have three types of periods: SOURCE, BINARY, and RUNTIME.
- 2, source code definition
@Target(AnnotationTarget.ANNOTATION_CLASS)// The target object is the annotation class
public annotation class Retention(val value: AnnotationRetention = AnnotationRetention.RUNTIME)// Accepts a parameter with a default value, which is kept at run time
Copy the code
- 3. The value of @Retention meta annotation
The @retention meta-annotation value is mainly derived from the AnnotationRetention enumeration class
public enum class AnnotationRetention {
SOURCE,// SOURCE: Annotations are not stored in the output class bytecode
BINARY,// BINARY: Annotations are stored in the class bytecode, but not visible to reflection
RUNTIME// RUNTIME: Annotations are stored in class bytecode and are also visible to reflection. The default is RUNTIME
}
Copy the code
@ MustBeDocumented yuan note
- 1, the introduction
The simple purpose of this annotation is to annotate an annotation class as part of the public API and to ensure that the annotation exists in the generated API documentation.
- 2, source code definition
@Target(AnnotationTarget.ANNOTATION_CLASS)// The target object can only be an annotation class
public annotation class MustBeDocumented
Copy the code
@ the Repeatable yuan note
- 1, the introduction
This annotation determines that the annotation can be applied two or more times in a single annotation on a code element.
- 2, source code definition
@Target(AnnotationTarget.ANNOTATION_CLASS)// The target object can only be an annotation class
public annotation class Repeatable
Copy the code
Why did Kotlin remove the @Inherited meta-annotation in Java
- 1. Introduction to @Inherited meta-annotations in Java
Inheried inherits @inherited when a parent class is labeled with @inherited, when a child class doesn’t have any Inherited tags, it inherits annotations from the parent class. Similar to the following example:
@Inherited
@Retention(RetentionPolicy.RUNTIME)
public @interface TestAnnotation {
}
@TestAnnotation
class Animal {
/ /...
}
class Cat extends Animal{// Also has the @testannotation annotation from the parent Animal class
/ /...
}
Copy the code
- Why does Kotlin not need @Inherited
In fact, this question was raised in Discuss on Kotlin’s official website. For details, you can go to See Inherited Annotations and Other Reflections enchancements. Just to give you a sense of why, we all know that in Java, you can’t find out if a subclass method overrides a parent class method. Therefore, annotations from parent methods cannot be inherited. However, Kotlin does not currently need to support the @Inherited meta-annotation, because Kotlin can do this if reflection provides the Override flag and is easy to do.
Vi. Usage scenarios of annotations
- 1. Provide information to the compiler: the compiler can use annotations to handle things like warnings, errors, etc
- Compile time processing: Using annotation information to generate some code is very common in Kotlin. Some built-in annotations often use annotations to generate additional code at compile time for interoperability with Java apis.
- 3. Runtime processing: Some annotations can be used to process some program logic while the program is running, using reflection to retrieve annotation information.
Preset annotations in Kotlin
One of the biggest features of Kotlin is that it is extremely interoperability with Java. We know that Kotlin’s syntax is quite different from Java’s syntax, and that achieving compatibility with Java may require carrying some additional information for the compiler or runtime to do similar compatibility conversions. Annotations play a big role. There are many built-in annotations in Kotlin to solve some of the calling habits of The Kotlin API in Java and control API calls. They are annotations to Kotlin’s @JVM series, and let’s take a look at what they are.
@JvmDefault
The @jVMDefault annotation was added in Kotlin 1.2.40, and some experimental features were enhanced in later Kotlin 1.2.50.
- 1,
We all know that non-abstract members can be added to interfaces in Kotlin, so this annotation is the default method to generate non-abstract interface members.
Using -xJVM-default = enable generates default methods in the interface for each method annotated with the @jVMDefault annotation. In this mode, annotating an existing method with @jVMDefault could break binary compatibility, as it would effectively remove the method from the DefaultImpls class.
Using -xJVM-default = Compatibility generates compatibility accessors in addition to the default interface methods. In the DefaultImpls class, it calls the default interface method through a synthetic accessor. In this mode, existing methods using the @jVMDefault annotation are binary compatible, but more methods are generated in bytecode. Removing this annotation from the interface member changes the binary incompatibility in both modes.
- 2, source code definition
@SinceKotlin("1.2")// This annotation first appeared from Kotlin's 1.2 release
@RequireKotlin("1.2.40", versionKind = RequireKotlinVersionKind.COMPILER_VERSION)
@Target(AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY)// The target objects are functions and attributes
annotation class JvmDefault
Copy the code
- Decompile Java code before and after annotations
The @jVMDefault annotation is not used
interface ITeaching {
fun speak(a) = println("open the book")}class ChineseTeacher : ITeaching
fun main(args: Array<String>) {
ChineseTeacher().speak()
}
Copy the code
Decompile into Java code
public interface ITeaching {
void speak(a);
public static final class DefaultImpls {// You can see a static inner class DefaultImpls generated for the speak function on the interface
public static void speak(ITeaching $this) {
String var1 = "open the book"; System.out.println(var1); }}}public final class ChineseTeacher implements ITeaching {
public void speak(a) {
ITeaching.DefaultImpls.speak(this);// Note that this is a direct call to the speak method of the static inner class DefaultImpls in ITeaching.}}public final class JvmDefaultTestKt {
public static final void main(@NotNull String[] args) {
Intrinsics.checkParameterIsNotNull(args, "args");
(new ChineseTeacher()).speak();ChineseTeacher's speak method is called here}}Copy the code
Use the @jVMDefault annotation
interface ITeaching {
@JvmDefault-jvm-target=1.8 -xJVm-default =enable
fun speak(a) = println("open the book")}class ChineseTeacher : ITeaching
fun main(args: Array<String>) {
ChineseTeacher().speak()
}
Copy the code
Decompile into Java code
public interface ITeaching {
@JvmDefault
default void speak(a) {// The outer static inner class is removed after the annotation is added
String var1 = "open the book"; System.out.println(var1); }}public final class ChineseTeacher implements ITeaching {// There is no internal bridge delegate like the above speak method call
}
public final class JvmDefaultTestKt {
public static final void main(@NotNull String[] args) {
Intrinsics.checkParameterIsNotNull(args, "args");
(newChineseTeacher()).speak(); }}Copy the code
In summary, without the @jVMDefault annotation, Kotlin automatically generates a static inner class called DefaultImpl that holds the default implementation of static methods and uses its own sink type to simulate methods that belong to objects. Then, for each type that extends the interface, if the type does not implement the method itself, Kotlin will connect the method to the default implementation through a call at compile time.
One of the real benefits of this is the ability to define specific implementation methods on interfaces on JVMS prior to JDK1.8. But there are some problems:
First problem: For example, it is incompatible with current Java processing methods, which can lead to extreme interoperability loss. We can even in Java to invoke automatically generated DefaultImpls directly, like this call ITeaching. DefaultImpls. Speak (new ChineseTeacher ()); , so that the internal details can also be exposed to the external, so that the more will call a face meng force.
Second problem: One of the main reasons for default methods in Java 8 is the ability to add methods to an interface without invading every subclass. However, the Kotlin implementation does not support this because default calls must be generated on each concrete type. Adding new methods to the interface causes each implementer to have to be recompiled.
Kotlin introduced the @jVMDefault annotation based on these issues
@JvmField
- 1,
Can be applied to a field, exposing the property as a public Java field with no accessors; And the Companion Object.
- 2, source code definition
@Target(AnnotationTarget.FIELD)// Objects are fields, including fields behind attributes
@Retention(AnnotationRetention.BINARY)// The annotation retention period is the source phase
@MustBeDocumented
public actual annotation class JvmField
Copy the code
- 3. Use of annotations
Usage Scenario 1:
We know that in Kotlin, by default, the Kotlin class does not expose fields but rather attributes. Kotlin provides behind the scenes fields for attributes that store their values as fields. Let’s look at an example
The Person class defines an age property. The age property is public by default, but when decomcompiled into Java code, you can see the fields behind it.
class Person {
var age = 18
set(value) {
if (value > 0) field = value
}
}
Copy the code
Decompile into Java code
public final class Person {
private int age = 18;// The age field is private.
// External access is operated through setter and getter accessors. Because Kotlin automatically generates setter and getter accessors, external operations can be directly analogous to public property operations,
// It is actually implemented internally through setter and getter accessors
public final int getAge(a) {
return this.age;
}
public final void setAge(int value) {
if (value > 0) {
this.age = value; }}}Copy the code
But what if Kotlin needs to generate a public field? The @jVMField annotation automatically removes setter and getter accessors for that field and changes it to public
class Person {
@JvmField
var age = 18
}
Copy the code
Decompiled Java code
public final class Person {
@JvmField
public int age = 18;// The setter and getter accessors are eliminated, and the age field is public
}
Copy the code
Usage Scenario 2:
@jVMField Another commonly used scenario is for Companion Objects.
The @jVMField annotation is not used
class Person {
companion object {
val MAX_AGE = 120}}Copy the code
Decompile into Java code
public final class Person {
private static final int MAX_AGE = 120;// Note: the default is private MAX_AGE, so calls in Java cannot be made directly through the Person class name. Variable name access
public static final Person.Companion Companion = new Person.Companion((DefaultConstructorMarker)null);
public static final class Companion {
// Calls in Java cannot be made directly through the Person class name. Variable name access,
// It is accessed indirectly through the static Companion inner class getMAX_AGE, like person.panion.getmax_age ();
public final int getMAX_AGE(a) {
return Person.MAX_AGE;
}
private Companion(a) {}// $FF: synthetic method
public Companion(DefaultConstructorMarker $constructor_marker) {
this(a); }}}Copy the code
But if you use this annotation, you can pass the Person class name directly. Variable name access
class Person {
companion object {
@JvmField
val MAX_AGE = 120}}// call in Java
public static void main(String[] args) {
System.out.println(Person.MAX_AGE);// It can be called directly because it has become public
}
Copy the code
Decompile into Java code
public final class Person {
@JvmField
public static final int MAX_AGE = 120;// public MAX_AGE, external can call directly
public static final Person.Companion Companion = new Person.Companion((DefaultConstructorMarker)null);
public static final class Companion {
private Companion(a) {}// $FF: synthetic method
public Companion(DefaultConstructorMarker $constructor_marker) {
this(a); }}}Copy the code
@JvmMultifileClass
- 1,
The main purpose of this annotation is to generate multi-file classes
- 2, source code definition
@Target(AnnotationTarget.FILE)
@MustBeDocumented
@OptionalExpectation
public expect annotation class JvmMultifileClass(a)Copy the code
- 3. Use of annotations
Kotlin defines two top-level functions in two different files, using this annotation to combine class methods from multiple files into a single class.
// exists in the IOUtilA file
@file:JvmName("IOUtils")
@file:JvmMultifileClass
package com.mikyou.annotation
import java.io.IOException
import java.io.Reader
fun closeReaderQuietly(input: Reader?). {
try{ input? .close() }catch (ioe: IOException) {
// ignore}}// exists in the IOUtilB file
@file:JvmName("IOUtils")
@file:JvmMultifileClass
package com.mikyou.annotation
import java.io.IOException
import java.io.InputStream
fun closeStreamQuietly(input: InputStream?). {
try{ input? .close() }catch (ioe: IOException) {
// ignore}}// Used in Java
public class Test {
public static void main(String[] args) {
// Same class IOUtils for external Java calls, even if it exists in different files
IOUtils.closeReaderQuietly(null);
IOUtils.closeStreamQuietly(null); }}Copy the code
@JvmName
- 1,
Changes the Java method, field, or class name generated by Kotlin by default
- 2, source code definition
// The objects are: functions, property getter methods, property setter methods, files
@Target(AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER, AnnotationTarget.FILE)
@Retention(AnnotationRetention.BINARY)
@MustBeDocumented
public actual annotation class JvmName(actual val name: String)// There is a name argument that will generate the name passed in with the specified name
Copy the code
- 3. Use of annotations
class Student {
@get:JvmName(name = "getStudentName")// Change the name of the getter function for the property
@set:JvmName(name = "setStudentName")// Change the name of the setter function for the property
var name: String = "Tim"
@JvmName("getStudentScore")// Change the function name
fun getScore(a): Double {
return 110.5}}// Change the generated class name. By default, Kotlin generates the class name with the filename +Kt suffix
@file:JvmName("IOUtils")// Note: This annotation must be in the first line, at the top of the package
package com.mikyou.annotation
import java.io.IOException
import java.io.Reader
fun closeReaderQuietly(input: Reader?). {
try{ input? .close() }catch (ioe: IOException) {
// ignore}}Copy the code
Decompiled Java code
public final class Student {
@NotNull
private String name = "Tim";
@JvmName(name = "getStudentName")
@NotNull
// It has been changed to pass getStudentName
public final String getStudentName(a) {
return this.name;
}
@JvmName(name = "setStudentName")
// setStudentName is passed in
public final void setStudentName(@NotNull String var1) {
Intrinsics.checkParameterIsNotNull(var1, "
"
?>);
this.name = var1;
}
@JvmName(name = "getStudentScore")
// It has been modified to pass getStudentScore
public final double getStudentScore(a) {
return 110.5D; }}Copy the code
@JvmOverloads
- 1,
Instructs the Kotlin compiler to generate multiple overloaded functions for functions with default parameter values, including constructors.
- 2, source code definition
// The objects are functions and constructors
@Target(AnnotationTarget.FUNCTION, AnnotationTarget.CONSTRUCTOR)
@MustBeDocumented
@OptionalExpectation
public expect annotation class JvmOverloads(a)Copy the code
- 3. Use of annotations
The most common use of this annotation is for overloading functions with default values. In Android, when we customize a View, we usually overload multiple constructors, so we need to add this annotation. If you define only one constructor without default, then you will throw an exception when using the custom View directly in XML.
class ScrollerView @JvmOverloads constructor(
context: Context,
attr: AttributeSet? = null,
defStyle: Int = 0
) : View(context, attr, defStyle) {
/ /...
}
Copy the code
Decompiled Java code
public final class ScrollerView extends View {
@JvmOverloads
public ScrollerView(@NotNull Context context, @Nullable AttributeSet attr, int defStyle) {
Intrinsics.checkParameterIsNotNull(context, "context");
super(context, attr, defStyle);
}
// $FF: synthetic method
@JvmOverloads
public ScrollerView(Context var1, AttributeSet var2, int var3, int var4, DefaultConstructorMarker var5) {
if ((var4 & 2) != 0) {
var2 = (AttributeSet)null;
}
if ((var4 & 4) != 0) {
var3 = 0;
}
this(var1, var2, var3);
}
@JvmOverloads
public ScrollerView(@NotNull Context context, @Nullable AttributeSet attr) {
this(context, attr, 0.4, (DefaultConstructorMarker)null);
}
@JvmOverloads
public ScrollerView(@NotNull Context context) {
this(context, (AttributeSet)null.0.6, (DefaultConstructorMarker)null);
}
/ /...
}
Copy the code
@JvmPackageName
- 1,
Change the fully qualified name of the JVM package generated from the.class file annotated with this annotation. This does not affect how Kotlin clients view declarations in this file, but Java clients and other JVM language clients will see the class file as if it were declared in the specified package. If you annotate a file with this annotation, it can contain only function, attribute, and type declarations, but not.
- 2, source code definition
@Target(AnnotationTarget.FILE)// apply to the file
@Retention(AnnotationRetention.SOURCE)
@MustBeDocumented
@SinceKotlin("1.2")//Kotlin version 1.2 was added
internal annotation class JvmPackageName(val name: String)
Copy the code
- 3. Use of annotations
// Take Collection source code as an example
@file:kotlin.jvm.JvmPackageName("kotlin.collections.jdk8")
package kotlin.collections
Copy the code
You can see that the class is compiled to the package name kotlin.collections.jdk8
@JvmStatic
- 1,
Can be used on object declarations or Companion object methods to expose them as Java static methods
- 2, source code definition
// Functions, properties, setters and getters for properties
@Target(AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER)
@MustBeDocumented
@OptionalExpectation
public expect annotation class JvmStatic(a)Copy the code
- 3. Use of annotations
The @jVMStatic annotation is often used on methods of associated objects, to be called by Java code
class Data {
companion object {
fun getDefaultDataName(a): String {
return "default"}}}/ / call in Java, is only Data.Com panion. GetDefaultDataName () call
public class Test {
public static void main(String[] args) {
System.out.println(Data.Companion.getDefaultDataName()); }}Copy the code
Decompiled Java code
public final class Data {
public static final Data.Companion Companion = new Data.Companion((DefaultConstructorMarker)null);
public static final class Companion {
@NotNull
public final String getDefaultDataName(a) {
return "default";
}
private Companion(a) {}// $FF: synthetic method
public Companion(DefaultConstructorMarker $constructor_marker) {
this(a); }}}Copy the code
With the @jVMStatic annotation
class Data {
companion object {
@JvmStatic
fun getDefaultDataName(a): String {
return "default"}}}Data.getdefaultdataname () can be called directly from Java
public class Test {
public static void main(String[] args) {
System.out.println(Data.getDefaultDataName()); }}Copy the code
Decompiled Java code
public final class Data {
public static final Data.Companion Companion = new Data.Companion((DefaultConstructorMarker)null);
@JvmStatic
@NotNull
/ / note it will be automatically generated within the Data type of a getDefaultDataName, then within and through the Companion. GetDefaultDataName () to call.
public static final String getDefaultDataName(a) {
return Companion.getDefaultDataName();
}
public static final class Companion {
@JvmStatic
@NotNull
public final String getDefaultDataName(a) {
return "default";
}
private Companion(a) {}// $FF: synthetic method
public Companion(DefaultConstructorMarker $constructor_marker) {
this(a); }}}Copy the code
@ JvmSuppressWildcards and @ JvmWildcard
- 1,
Used to indicate whether the compiler generates or omits wildcards for type parameters, JvmSuppressWildcards for parameter generics and JvmWildcard for return value types
- 2, source code definition
// applies to classes, functions, attributes, and types
@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY, AnnotationTarget.TYPE)
@MustBeDocumented
@OptionalExpectation
// If you specify suppress to true, no wildcard will be generated. If false, no wildcard will be generated
public expect annotation class JvmSuppressWildcards(val suppress: Boolean = true)
@Target(AnnotationTarget.TYPE)
@Retention(AnnotationRetention.BINARY)
@MustBeDocumented
public actual annotation class JvmWildcard
Copy the code
- 3. Use of annotations
interface ICovert {
fun covertData(datas: ListThe < @JvmSuppressWildcards(suppress = false) String>)// @jVMSuppresswildCardsd Used for parameter types
fun getData(a): List<@JvmWildcard String>// @jvmwildcard is used to return the value type
}
Copy the code
class CovertImpl implements ICovert {
@Override
public void covertData(List<? extends String> datas) {// Parameter types generate wildcards
}
@Override
public List<? extends String> getData() {// The return value type generates wildcards
return null; }}Copy the code
@JvmSynthetic
- 1,
It marks the appropriate elements as synthesized in the generated class file, and any elements marked as synthesized by the compiler will not be accessible from the Java language.
- 2. What are Synthetic attributes?
The ACC_SYNTHETIC attribute of the JVM bytecode identifier is used to indicate that the element does not actually exist in the original source code, but is generated by the compiler.
- 3. What can composite properties do?
It is generally used to support code generation, allowing the compiler to generate fields and methods that should not be exposed to other developers but need to support the actual exposed interface. We can think of it as going beyond the private or protected level.
- 4, source code definition
Setters, getters, and fields for functions and properties
@Target(AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER, AnnotationTarget.FIELD)
@OptionalExpectation
public expect annotation class JvmSynthetic(a)Copy the code
- 5. Use of annotations
class Synthetic {
@JvmSynthetic
val name: String = "Tim"
var age: Int
@JvmSynthetic
set(value) {
}
@JvmSynthetic
get() {
return 18}}Copy the code
Decompiled Java code
public final class Synthetic {
// $FF: synthetic field
@NotNull
private final String name = "Tim";
@NotNull
public final String getName(a) {
return this.name;
}
// $FF: synthetic method// synthetic method is a synthetic method
public final int getAge(a) {
return 18;
}
// $FF: synthetic method
public final void setAge(int value) {}}Copy the code
If you decompile the code, you won’t see much, but you can look up the generated bytecode file description directly through javap -v xxx.class
public final int getAge(a);
descriptor: ()I
flags: ACC_PUBLIC, ACC_FINAL, ACC_SYNTHETIC// Add the ACC_SYNTHETIC identifier
Code:
stack=1, locals=1, args_size=1
0: bipush 18
2: ireturn
LocalVariableTable:
Start Length Slot Name Signature
0 3 0 this Lcom/mikyou/annotation/Synthetic;
LineNumberTable:
line 12: 0
public final void setAge(int);
descriptor: (I)V
flags: ACC_PUBLIC, ACC_FINAL, ACC_SYNTHETIC// Add the ACC_SYNTHETIC identifier
Code:
stack=0, locals=2, args_size=2
0: return
LocalVariableTable:
Start Length Slot Name Signature
0 1 0 this Lcom/mikyou/annotation/Synthetic;
0 1 1 value I
LineNumberTable:
line 9: 0
Copy the code
@Throws
- 1,
Functions in Kotlin, setters or getters for properties, constructor functions throw exceptions
- 2, source code definition
Getters, setters, constructors for functions, properties, etc
@Target(AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER, AnnotationTarget.CONSTRUCTOR)
@Retention(AnnotationRetention.SOURCE)
public annotation class Throws(vararg val exceptionClasses: KClass<out Throwable>)// Here is the exception class KClass indefinite parameter, can specify one or more exceptions at the same time
Copy the code
- 3. Use of annotations
@Throws(IOException::class)
fun closeQuietly(output: Writer?).{ output? .close() }Copy the code
@Transient
This annotation acts as a TRANSIENT keyword in Java
@Strictfp
This annotation acts as the StrictFP keyword in Java
@Synchronized
This annotation acts as the Synchronized keyword in Java
@Volatile
This annotation acts as the Volatile keyword in Java
Welcome to the Kotlin Developer Association, where the latest Kotlin technical articles are published, and a weekly Kotlin foreign technical article is translated from time to time. If you like Kotlin, welcome to join us ~~~
Welcome to Kotlin’s series of articles:
Kotlin Encounter Design Pattern collection:
- When Kotlin Meets Design Patterns perfectly singleton Patterns (PART 1)
Data Structure and Algorithm series:
- Binary Search for algorithms every Week (described by Kotlin)
- Weekly Linked List of Data structures (Kotlin description)
Translation series:
- What Kotlin said about the Companion Object
- Remember a Kotlin official document translation PR(inline type)
- Exploration of autoboxing and High performance for inline classes in Kotlin (ii)
- Kotlin inline class full resolution
- Kotlin’s trick of Reified Type Parameter
- When should type parameter constraints be used in Kotlin generics?
- An easy way to remember Kotlin’s parameters and arguments
- Should Kotlin define functions or attributes?
- How to remove all of them from your Kotlin code! (Non-empty assertion)
- Master Kotlin’s standard library functions: run, with, let, also, and apply
- All you need to know about Kotlin type aliases
- Should Sequences or Lists be used in Kotlin?
- Kotlin’s turtle (List) rabbit (Sequence) race
Original series:
- How do you fully parse the type system in Kotlin
- How do you make your callbacks more Kotlin
- Jetbrains developer briefing (3) Kotlin1.3 new features (inline class)
- JetBrains developer briefing (2) new features of Kotlin1.3 (Contract and coroutine)
- Kotlin/Native: JetBrains Developer’s Day (Part 1
- How to overcome the difficulties of generic typing in Kotlin
- How to overcome the difficulties of Generic typing in Kotlin (Part 2)
- How to overcome the difficulties of Generic typing in Kotlin (Part 1)
- Kotlin’s trick of Reified Type Parameter (Part 2)
- Everything you need to know about the Kotlin property broker
- Source code parsing for Kotlin Sequences
- Complete analysis of Sets and functional apis in Kotlin – Part 1
- Complete parsing of lambdas compiled into bytecode in Kotlin syntax
- On the complete resolution of Lambda expressions in Kotlin’s Grammar
- On extension functions in Kotlin’s Grammar
- A brief introduction to Kotlin’s Grammar article on top-level functions, infix calls, and destruct declarations
- How to Make functions call Better
- On variables and Constants in Kotlin’s Grammar
- Elementary Grammar in Kotlin’s Grammar Essay
Translated by Effective Kotlin
- The Effective Kotlin series considers arrays of primitive types for optimal performance (5)
- The Effective Kotlin series uses Sequence to optimize set operations (4)
- Exploring inline modifiers in higher-order functions (3) Effective Kotlin series
- Consider using a builder when encountering multiple constructor parameters in the Effective Kotlin series.
- The Effective Kotlin series considers using static factory methods instead of constructors (1)
Actual combat series:
- Use Kotlin to compress images with ImageSlimming.
- Use Kotlin to create a picture compression plugin.
- Use Kotlin to compress images.
- Simple application of custom View picture fillet in Kotlin practice article