Kotlin and Java Interop __java

Source: Internet
Author: User
Tags instance method modifier visibility java util

Interoperability is the interface that can invoke other programming languages in Kotlin, so long as they open the interface, Kotlin can invoke its member properties and member methods, which are unmatched by other programming languages. Also, the API interface in Kotlin can be invoked while Java programming is in progress.


Kotlin invoke Java


Kotlin is designed with Java interoperability in mind. You can naturally invoke existing Java code from Kotlin, and you can also invoke Kotlin code very smoothly in Java code. For example, the list library of Java util is invoked in Kotlin.



The basic interop behavior is as follows:


Property Read-write


Kotlin can automatically identify getter/setter functions in Java, while Getter/setter operations Kotlin properties can be used in Java.



The Java-contracted getter and setter methods (a parameterless method with the name beginning with Get and a single parameter method that begins with set) are represented as attributes in Kotlin. If the Java class has only one setter, it is not visible as a property in Kotlin because Kotlin does not currently support write-only (set-only) attributes.


Empty Security Type


The principle of Kotlin's empty security type is that Kotlin adds a function call during compilation to control parameter types or return types, and developers can limit Java Hollow value exceptions at development time by annotating @nullable and @notnull.


Any reference in Java may be null, which makes it impractical for Kotlin to perform rigorous, empty security checks on objects from Java. The types of Java declarations are called platform types in Kotlin and are treated in particular. The requirements for this type of empty check are relaxed so that they are secured in the same security as in Java.



When you call a method of a platform type variable, Kotlin does not report a nullability error at compile time, but the call at run time may fail because of a null pointer exception.



Platform types are not identifiable, which means that they cannot be explicitly identified in your code. When assigning a platform value to a Kotlin variable, you can rely on type inference (the variable has the inferred platform type, such as the type of item in the previous example), or the type we expect (either nullable or Non-null types).



If you select a non-empty type, the compiler triggers an assertion when it assigns a value, which prevents Kotlin variables from saving null values. An assertion is also triggered when the platform value is passed to a Kotlin function, such as expecting a non-null value. In general, the compiler tries to prevent the propagation of null values (sometimes this cannot be completely eliminated because of the generics reason).


platform Type identification method


As mentioned above, platform types cannot be explicitly expressed in a program, so there is no corresponding syntax in the language. However, the compiler and the IDE sometimes need to display them (in the error message, the parameter information Medium), and Koltin provides mnemonics to indicate that they:

T! That means "T or T?" ;


(mutable) collection! Represents "a Java set of variables that can be variable or immutable, nullable, or not nullable";


array< (out) t>! A Java array that represents "nullable or not nullable" t (or subtype of T).


Nullable Annotations


Because of the generics, Kotlin may have a null exception at compile time, and using empty annotations can be an effective solution to this situation. The compiler supports a variety of nullable annotations:


In the JetBrains:org.jetbrains.annotations package.

@Nullable and @NotNull;


Android:com.android.annotations and Android.support.annotations;


Jsr-305:javax.annotation;


FindBugs:edu.umd.cs.findbugs.annotations;


Eclipse:org.eclipse.jdt.annotation;


Lombok:lombok.NonNull;


JSR-305 Support


In JSR-305, the @Nonnull annotation defined to represent the nullability of the Java type.


If the @Nonnull (when = ...) value is when.always, the annotation type is considered non-null, When.maybe and when.never represent nullable types, and When.unknown coercion type is the platform type.


You can compile the library for JSR-305 annotations, but you do not need to specify the annotation widget (such as Jsr305.jar) as a compilation dependency for the consumer of the library. The Kotlin compiler can read JSR-305 annotations from the library and does not need the annotation to appear in the classpath.


Custom Nullable Qualifiers (KEEP-79) are also supported since Kotlin 1.1.50


Type qualifier


If a callout type is annotated with the @TypeQualifierNickname and JSR-305 @Nonnull (or its other nickname, such as @CheckForNull), then the annotation type itself will be used to retrieve the exact nullability. and has the same meaning as the nullable annotation.



type Qualifier Default value


@TypeQualifierDefault introduces annotations that define the default nullability within the scope of the annotated element when applied. These annotation types should themselves be annotated with a @Nonnull (or a nickname) and a @TypeQualifierDefault (...) annotation with one or more ElementType values.


Elementtype.method is used for the return value of the method;


Elementtype.parameter is used for value parameters;


Elementtype.field for fields;


Elementtype.type_use (from 1.1.60) applies to any type, including the type parameter, the upper bound of the type parameter, and the wildcard type.


The default nullability is used when the type does not annotate the nullable annotation, and the default value is determined by the element with the default annotation of the type qualifier with the ElementType that matches the type used in the inner layer callout.



Package-level default nullability is also supported:



@UnderMigration Annotations


The maintainer of the library can use @UnderMigration annotations (provided in a separate widget KOTLIN-ANNOTATIONS-JVM) to define the migration status of nullable type qualifiers.


The status value in the @UnderMigration (status = ...) specifies how the compiler handles the improper use of the annotation type in Kotlin (for example, using the type value of a @MyNullable callout as a non-null value):


Migrationstatus.strict makes annotations work like any pure nullable annotation, which complains about improper usage and affects the presentation of types in Kotlin in the annotation declaration;


For Migrationstatus.warn, improper usage is reported as warning rather than error, but the type in the annotation declaration is still the platform type;


Migrationstatus.ignore causes the compiler to completely ignore the nullable annotations.


The maintainer of the library can also add @UnderMigration state to the type qualifier alias and the type qualifier default value. For example:



Note: The migration state of the nullable annotation does not inherit from its type qualifier, but rather applies to the use of the default type qualifier. The state of the default type qualifier is used if the default type qualifier uses the type qualifier as a nickname, and they are all labeled with @UnderMigration.


method that returns void


If void is returned in Java, then Kotlin returns the unit. If void is returned at the time of the call, then Kotlin recognizes that the return value is void.


Use of annotations


@JvmField are annotations that are frequently encountered by Kotlin and Java interoperability attributes, @JvmStatic to compile object methods into Java static methods, @JvmOverloads primarily Kotlin to define default parameters to generate overloaded methods; @file: JVMNAME Specifies the name of the class that is generated after the Kotlin file is compiled.


Noarg and Allopen


The data class itself property has no default parameterless construction method, so Kotlin provides a noarg plug-in that supports JPA annotations such as @entity. Allopen is final for the annotated class to allow the class to be inherited and to support spring annotations such as @componet, and to support custom annotation types such as @poko.


generic type


Kotlin's generics are a bit different from Java's, and readers can refer to generic chapters in particular. Wildcard characters in Kotlin "" instead of in Java. Covariance and contravariance are changed from extends and Super in Java to out and in, such as ArrayList; there is no raw type in Kotlin, such as the list in Java corresponds to Kotlin or list<>.


Like Java, Kotlin does not preserve generics at run time, which means that objects do not carry the actual type of the type parameter in the constructor passed to them, i.e. ArrayList () and ArrayList () are indistinguishable. This allows the execution of the is check to take care of the generics, Kotlin only allow is to check for the generic type of the star projection.



Java Arrays


Unlike Java, arrays in Kotlin are invariant. This means that Kotlin does not allow us to assign an array to an array, thus avoiding possible run-time failures. Kotlin also prohibits us from passing an array of subclasses as an array of superclass to Kotlin methods, but for Java methods, this is allowed (through array< (out) string>! This form of platform type).


On the Java platform, arrays use native data types to avoid the overhead of boxing/unboxing operations. Because Kotlin hides these implementation details, a workaround is needed to interact with Java code. For each native type of array there is a special class (Intarray, Doublearray, Chararray, and so on) to handle the situation. They are independent of the array class and are compiled into Java native type arrays for optimal performance.


For example, suppose you have a Java method that accepts an int array index.



When you call the method in Kotlin, you can pass an array of primitive types like this.



When compiled into JVM byte code, the compiler optimizes access to the array so that no overhead is introduced.



Even when we use index positioning, we do not introduce any overhead:



Finally, there is no additional overhead for in-detection:



Java Variable Parameters


Java classes sometimes declare a method with variable quantity parameters (VarArgs) to use the index.



In this case, you need to use the expand operator * to pass the Intarray.



Currently, NULL cannot be passed to a method declared as a variable parameter.


Sam Transformation


Like Java 8, Kotlin supports Sam transformations, which means that the Kotlin value can be automatically converted into a Java interface with a Non-default method, as long as the parameter type of the method can match the parameter type of the Kotlin function.


First use Java to create a Saminjava class, and then invoke the interface in Java through Kotlin.



The Java interface is then invoked in Kotlin.



The results of the operation are:



If the Java class has multiple methods that accept functional interfaces, you can select the method that needs to be invoked by using an adapter function that converts a lambda expression to a specific Sam type.



Note: Sam transformations apply only to interfaces, not to abstract classes, even if these abstract classes have only one abstract method. This feature applies only to Java interop, because Kotlin has the appropriate function type, so it is not required to automatically convert the function to an implementation of the Kotlin interface, and therefore is not supported.


In addition, Kotlin calls Java there are a lot of content, readers can use the following links to understand: Kotlin invoke Java


Java call Kotlin


Java can easily invoke Kotlin code.


Property


The Kotlin property is compiled into the following Java elements:


Getter method whose name is obtained by prefixing get;


Setter method whose name is obtained by prefix set (only for VAR attributes);


A private field that is the same as the property name (applies only to properties that have behind-the-scenes fields).


For example, the Kotlin variable is compiled into a variable declaration in Java.



If the property name starts with IS, a different name mapping rule is used: the name of the getter is the same as the property name, and the name of the setter is obtained by replacing the is with set. For example, for attribute IsOpen, its getter is called IsOpen (), and its setter is called Setopen (). This rule applies to any type of attribute and is not limited to a Boolean.


Package-level functions


For example, all of the functions and properties declared in the Example.kt file in the Org.foo.bar package, including extension functions, are compiled into a static method of a Java class named Org.foo.bar.ExampleKt.


First, create a new Examplekt.kt file and create a new bar function:



Then, call this function in Java.



Of course, you can use the @jvmname annotation to modify the class name of the generated Java class. For example:



Then you need to modify the class name when invoking Java. For example:



It is often wrong to generate the same Java class name in multiple files (with the same package name and the same class name or with the same @jvmname annotation). However, the compiler is able to generate a single Java-skin class that has the specified name and contains all the declarations from all files that have that name. To generate such a look, use the @jvmmultifileclass annotation in all related files.



instance Fields


If you need to expose the Kotlin property as a field in Java, you need to annotate it with a @jvmfield annotation. After you use the @jvmfield annotation callout, the field will have the same visibility as the underlying property. If an attribute has a behind-the-scenes field (backing field), is not private, has no open/override, or a const modifier, and is not a delegated property, you can use @jvmfield to annotate the property.


First, create a new KT class and add the following code.



The code is then invoked in Java,



Deferred initialization properties (in Java) are also exposed as fields that have the same visibility as the Lateinit property's setter.


static fields


When you name an object or associated object, the declared Kotlin property contains a static behind-the-scenes field in the named object or in the class that contains the associated object. These fields are usually private, but can be exposed in one of the following ways.


@JvmField annotations;


Lateinit modifier;


The const modifier.


You can use a property of @JvmField annotation to make it a static field that has the same visibility as the property itself. For example:



Then, call the property in Java code.



A deferred initialization property in a named object or companion object has a static behind-the-scenes field with the same visibility as the property setter.



Then, use the field's properties in Java.



Attributes that are marked with const (in class and at the top level) become static fields in Java, creating a new kt file first.



You can then call the property directly in Java.



static Method


Kotlin represents a package-level function as a static method. If these functions are annotated with @jvmstatic, then Kotlin can also generate static methods for functions defined in named objects or associated objects. If you use this annotation, the compiler will either generate a static method in the class of the corresponding object or generate an instance method in the object itself. For example:



Now, foo () is static in Java, and bar () is not static.



For named objects, there is the same rule.



Used in Java.



@JvmStatic annotations can also be applied to the properties of an object or associated object so that its getter and setter methods are static members in that object or in the class that contains the companion object.


Visibility of


The visibility of Kotlin is mapped to Java code in the following ways.


Private members are compiled into private members;


Private top level declarations are compiled into packet-level local declarations;


Protected remains protected (note that Java allows access to protected members of other classes in the same package, while Kotlin cannot, so Java classes will access more extensive code);


The internal declaration becomes public in Java. Members of the internal class are decorated by name, making it more difficult to accidentally use in Java, and are allowed to overload members of the same signature according to the Kotlin rule, and are not visible to each other;


Public remains public.


Kclass


Sometimes you need to invoke a Kotlin method that has kclass type parameters. Because there is no automatic conversion from Class to Kclass, you must manually convert by calling the equivalent form of the Class.kotlin extended property. For example:



Signature Conflict


Sometimes we want a named function in a Kotlin to have another JVM name in the bytecode, the most prominent example being caused by type erasure.



These two functions cannot be defined in a class at the same time, because their JVM signatures are the same. If we really want them to use the same name in Kotlin, you can use @JvmName to label one or two of them, and specify different names as arguments. For example:



They can be accessed with the same name Filtervalid in Kotlin, and in Java, they are filtervalid and filtervalidint respectively. The same technique applies to attributes as well. For example:



Build Overload


In general, if you write a Kotlin function with a default parameter value, in Java there is only one way to complete the parameter signature with all parameters visible, and you can use @JvmOverloads annotations if you want to expose multiple overloads to the Java caller. This annotation can be used in constructors, static methods, but not in abstract methods and methods defined in interfaces.



For each parameter that has a default value, an extra overload is generated, which removes the parameter and all parameters to the right of it. In the example above, the following code is generated.



Note that if all constructor parameters of a class have a default value, then a public parameterless constructor is generated for the as follows constructor, even if no @JvmOverloads annotations are available at this time.


inspected Exception


As mentioned above, Kotlin has not been inspected for exceptions. So, normally the Java signature of the Kotlin function does not declare an exception thrown, so if we have a kotlin function like this. First, create a new kt file.



Then, when you call it in Java, you need to use try{}catch{} to catch the exception.



Because Foo () did not declare IOException, we got an error message from the Java compiler. To solve this problem, @Throws annotations are used in Kotlin.



NULL Security


When you call the Kotlin function from Java, there is no way to prevent null values from being passed in Kotlin. Kotlin, when running in a JVM virtual machine, checks all public functions to check for non-null values, which allows you to get a Non-empty value code in Java by NullPointerException.


the generic type of the variable


When Kotlin classes use declaration-type changes, you can see their usage in Java code in two ways. Let's assume that we have the following classes and two functions that use it:



Convert these two functions to Java code as follows:



The problem is that we can write Unboxbase (boxderived ("s") in Kotlin, but it doesn't work in Java, because class box in Java is invariant on its generic parameter T, so box is not a subclass of box. To make it work in Java, we define unboxbase as follows.



Here we use the Java wildcard character type (?). Extends Base) to simulate a declaration by using a place type change, because this is the only way in Java.


When it appears as a parameter, in order for the Kotlin API to work in Java, we generate box as box< for the covariant definition box. Extends super> (or generation foo< for the inverter-defined Foo;? Super bar>). When it is a return value, we do not generate wildcard characters because otherwise the Java client will have to deal with them (and it violates the common Java coding style). Therefore, the corresponding function in our example actually translates as follows:



Note: When the parameter type is final, generating the wildcard character is usually meaningless, so no matter where box is always converted to box. If we need wildcard characters where the wildcard is not generated by default, we can use the @JvmWildcard annotation:



On the other hand, if we don't need the default wildcard conversion at all, we can use @jvmsuppresswildcards.



Note: @JvmSuppressWildcards can be used not only for a single type parameter, but also for an integer

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.