Kotlin is 100% interoperable with Java™and android™
In the previous chapters, we've learned about Kotlin's basic syntax, type systems, generics and collection classes, object-oriented and functional programming, and in the previous chapter we saw the lightweight concurrency programming model provided by Kotlin: the related content of the coprocessor.
From the beginning of this chapter to the later chapters, we will go into the actual combat of engineering code. We'll go through the topics of Kotlin Integration Springboot Development Server-side Web projects, using Kotlin to develop Android projects, and using Kotlin to write front-end JavaScript code.
The competitive advantage of Kotlin is that it is not completely isolated from the Java language. It is basically interoperable with Java 100%. In this way, Kotlin can stand on the shoulders of the entire Java ecological giants and move toward a greater future.
This chapter lets us learn how to interoperate with Java under Kotlin. Kotlin invoke Java sample
Kotlin is much like Java. It's not as strange as Clojure or Scala (admitting reality, both languages are strange). So we should learn kotlin quickly. The language is clearly written for Java developers.
Kotlin the interoperability with Java at the beginning of the design. We can invoke the existing Java code naturally from the Kotlin. For example, here's the code for a Kotlin call to the Okhttp library in Java:
package com.easy.kotlin import okhttp3.* import java.io.File import java.io.IOException Import Java.util.concurrent.TimeUnit object Okhttputils {fun get (url:string): String? {var result:string? = "" Val okhttp = Okhttpclient.builder (). ConnectTimeout (1, Timeunit . HOURS). ReadTimeout (1, timeunit.hours). WriteTimeout (1, timeunit.hours). b Uild () Val request = Request.builder (). URL (URL). Build () Val call = Okh Ttp.newcall (Request) try {val response = Call.execute () result = Response.body ()?.
String () Val f = File ("Run.log") F.appendtext (result!!)
F.appendtext ("\ n")} catch (E:ioexception) {e.printstacktrace ()} return result }
}
Kotlin calls Java code as fluent as groovy (but not "all right to write like groovy", but it's an error when it runs) because groovy is a dynamic type language and Kotlin is a strongly typed static type language. We basically don't need to change anything to directly use the API library in Java.
And the Kotlin code can also be invoked very smoothly in Java code:
Package Com.easy.kotlin;
Import Com.alibaba.fastjson.JSON;
public class Jsonutils {public
static String tojsonstring (Object o) {return
json.tojsonstring (o);
}
public static void Main (string[] args) {
String url = ' http://www.baidu.com ';
String result = OkhttpUtils.INSTANCE.get (URL);
SYSTEM.OUT.PRINTLN (result);
}
Because Kotlin and Java are two languages, there are special syntax when calling each other. The syntax for the object function that uses Java to invoke Kotlin is OkhttpUtils.INSTANCE.get (URL), and we see a INSTANCE here.
We can even mix programming in one project with both Kotlin and Java two languages. We can see in the next chapter that we have mixed development in a Springboot project using both Kotlin and Java two languages.
Let's continue with some of the details of Kotlin invoking Java code. Kotlin a collection class using Java
Many of the Kotlin collection class APIs are implemented directly using Java APIs. When we use, there is no Shong sense, natural Tiancheng:
@RunWith (junit4::class)
class Kotlinusingjavatest {
@Test fun testarraylist () {
val Source = Listof<int > (1, 2, 3, 4, 5)
//using Java ArrayList
val list = arraylist<int> () for
(item in source) {
List.add ( Item)//Arraylist.add ()
} for
(i in 0..source.size-1) {
list[i] = source[i]//Call Get and set
}
}
}
Kotlin Call getter and Setter in Java
This convention is followed in Java: The Getter method has no arguments and begins with get, setter method single parameters and starting with set. In Kotlin we can be represented directly as attributes. For example, we write a Java class with setters and getter:
Package Com.easy.kotlin;
Import java.util.Date;
public class Product {
Long id;
String name;
String category;
Date gmtcreated;
Date gmtmodified;
Public Long GetId () {return
ID;
}
public void SetId (Long id) {
this.id = ID;
}
Public String GetName () {return
name;
}
public void SetName (String name) {
this.name = name;
}
Public String GetCategory () {return
category;
}
public void Setcategory (String category) {
this.category = category;
}
Public Date getgmtcreated () {return
gmtcreated;
}
public void setgmtcreated (Date gmtcreated) {
this.gmtcreated = gmtcreated;
}
Public Date getgmtmodified () {return
gmtmodified;
}
public void setgmtmodified (Date gmtmodified) {
this.gmtmodified = gmtmodified;
}
}
Then, we can do get and set operations directly using the property name in Kotlin:
@RunWith (junit4::class)
class Producttest {
@Test fun testgettersetter () {
Val Product = product ()
Product.name = "account System"
product.category = "Financial Finance class"
product.gmtcreated = Date ()
product.gmtmodified = Date () C7/>println (jsonutils.tojsonstring (product))
Assert.asserttrue (product.getname () = "account System")
Assert.asserttrue (Product.name = = "Account System")
Assert.asserttrue (product.getcategory () = "Financial Finance class"
) Assert.asserttrue (Product.category = = "Financial Finance class")
}
Of course, we can also directly invoke getter and setter methods like Product.getname (), Product.setname ("Kotlin"), as in Java. calling a method that returns void in Java
If a Java method returns void, then the unit is returned from the Kotlin call.
public class Admin {
String name;
public void SetName (String name) {
this.name = name;
}
@Override public
String toString () {return
"admin{" +
"name= '" + name + ' \ ' +
'} ';
}
}
We call this
Val Setreturn = admin.setname ("root")
println (Setreturn)
Will output: Kotlin. Unit NULL Security and platform type
We know that any reference in Java can be null, so that we may have an empty security problem when we invoke an object from Java using Kotlin.
The type of the Java declaration is treated specifically in Kotlin and is called the platform type (platform types). This type of empty check is relaxed so that they are secured in the same security as in Java.
Take a look at the following example:
@RunWith (junit4::class)
class Callingjavanullsafe {
@Test fun Testcallingjavanullsafe () {
Val product = Product ()
//Product.name = null
product.category = "Financial Finance class"
product.gmtcreated = Date ()
product.gmtmodified = Date ()
println (jsonutils.tojsonstring (product))
val name = Product.name
println (" Product name is ${name} ")
val eqname = name = =" Account System "
println (eqname)
name.substring (1)
}
}
The code above can be compiled correctly. The Kotlin compiler relaxed the null check name.substring (1) for the null Value name (platform type) from Java. However, such null pointer exceptions are still thrown at run time.
Running the above code, we can see the output:
{"category": "Financial Finance Class", "gmtcreated": 1500050426817, "gmtmodified": 1500050426817}
The product name is null
false
NULL cannot being cast to non-null type java.lang.String
Kotlin. Typecastexception:null cannot is cast to non-null type java.lang.String at
Com.easy.kotlin.CallingJavaNullSafe.testCallingJavaNullSafe (callingjavanullsafe.kt:27)
We do not set the value of name, in Java it is null. We used this name to compute in the Kotlin code, and we can see that:
Val Eqname = name = = "Account System"
println (Eqname)
False can be output correctly. This indicates that Kotlin's judgment string is equal to the null situation, and such code should throw a null pointer exception if the Name.equals ("account System") is invoked in Java.
But when we call name.substring (1) directly using the value of name, the Kotlin compiler does not check for this empty exception, but the runtime still has an error: null cannot be cast to non-null type Java.lang.String.
If we do not want to see such an exception, but when name is null, the quiet output null, directly using the Kotlin in the empty security call. :
Name?. SUBSTRING (1)
This way, the runtime does not throw an exception, and returns null directly and silently. platform Type
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), so we use a mnemonic to represent them:
T! : Represents T or T?
(mutable) collection<t>! : "Java collection of T that can be mutable or immutable, nullable, or not nullable"
array< (out) t>! : A Java array representing "Nullable or non-null T (or subtype of T)" Kotlin and type mappings in Java
Kotlin Special handling part Java type. Such a type is not loaded "as is" from Java, but is mapped to the appropriate Kotlin type.
Mappings occur only during compilation, and runtime representations remain unchanged.
The native types of Java are mapped to the corresponding Kotlin types:
Java Type |
Kotlin Type |
Byte |
Kotlin. Byte |
Short |
Kotlin. Short |
Int |
Kotlin. Int |
Long |
Kotlin. Long |
Char |
Kotlin. Char |
Float |
Kotlin. Float |
Double |
Kotlin. Double |
Boolean |
Kotlin. Boolean |
Some of the built-in types in Java can also be mapped accordingly:
Java Type |
Kotlin Type |
Java.lang.Object |
Kotlin. any! |
Java.lang.Cloneable |
Kotlin. cloneable! |
Java.lang.Comparable |
kotlin.comparable! |
Java.lang.Enum |
Kotlin. Enum! |
Java.lang.Annotation |
Kotlin. annotation! |
java.lang.Deprecated |
Kotlin. deprecated! |
Java.lang.CharSequence |
Kotlin. charsequence! |
Java.lang.String |
Kotlin. string! |
Java.lang.Number |
Kotlin. number! |
Java.lang.Throwable |
Kotlin. throwable! |
The Java boxed raw type maps to the corresponding nullable Kotlin type:
Java Type |
Kotlin Type |
Java.lang.Byte |
Kotlin. A Byte? |
Java.lang.Short |
Kotlin. Short? |
Java.lang.Integer |
Kotlin. Int? |
Java.lang.Long |
Kotlin. Long? |
Java.lang.Character |
Kotlin. Char? |
Java.lang.Float |
Kotlin. Float? |
Java.lang.Double |
Kotlin. Double? |
Java.lang.Boolean |
Kotlin. A Boolean? |
In addition, the Java type used as a type parameter maps to the platform type in Kotlin:
For example,,list<java.lang.integer> will become a list<int!> in Kotlin.
Collection types can be read-only or mutable in Kotlin, so the Java collection type is mapped as follows:
(All Kotlin types in the following table are in the Kotlin.collections package):
Java type |
Kotlin read-only type |
Kotlin soft type |
loaded platform type |
Iterator |
Iterator |
Mutableiterator |
(mutable) iterator! |
Iterable |
Iterable |
Mutableiterable |
(mutable) iterable! |
Collection |
Collection |
Mutablecollection |
(mutable) collection! |
Set |
Set |
Mutableset |
(mutable) set! |
List |
List |
Mutablelist |
(mutable) list! |
Listiterator |
Listiterator |
Mutablelistiterator |
(mutable) listiterator! |
Map |
Map |
Mutablemap |
(mutable) map! |
Map.entry |
Map.entry |
Mutablemap.mutableentry |
(mutable) Map. (mutable) entry! |
Array mappings for Java:
Java Type |
Kotlin Type |
Int[] |
Kotlin. intarray! |
String[] |
Kotlin. array< (out) string>! |
generics using Java in Kotlin
Kotlin generics are a little different from Java. When you import Java types into Kotlin, we perform some transformations:
Kotlin of a generic type |
Java generics |
Description |
Foo! |
Foo |
Java wildcard characters are converted to type projections |
Foo |
Foo |
Kotlin and Arrays in Java
Unlike Java, arrays in Kotlin are invariant, that is, Kotlin does not allow us to assign a array<string> to a array<any>.
On the Java platform, arrays holding native data types avoid the cost of boxing/unboxing operations.
In Kotlin, there is a special class (Intarray, Doublearray, Chararray, etc.) for each native type of array to achieve the same function. They are independent of the array class and are compiled into Java native type arrays for optimal performance. Java Variable Parameters
Java classes sometimes declare a method with variable quantity parameters (VarArgs) to use the index.
public class Varargsdemo<t> {
static Varargsdemo Vad = new Varargsdemo ();
public static void Main (String ... agrs) {System.out.println (
vad.append ("A", "B", "C"));
System.out.println (Vad.append (1, 2, 3));
System.out.println (Vad.append (1, 2, "3"));
}
Public String Append (T ... element) {StringBuilder result
= new StringBuilder ();
for (T e:element) {
result.append (e);
}
return result.tostring ();
}
In Kotlin, we use the expand operator * to pass this varargs:
@RunWith (junit4::class)
class Varargsdemotest {
@Test fun Testvarargsdemo () {
val Varargsdemo = Varargsdemo<any?> ()
val array = arrayof (0, 1, 2, 3)
val result = Varargsdemo.append (*array)
println ( Result)
}
}
Run output: 0123 non-inspected exception
In Kotlin, all exceptions are not tested (non-checked exceptions), which means that the compiler does not force you to capture any of them. In Java, we are asked to catch exceptions, such as the following code:
In other words, we need to write a try catch code block similar to the following:
try {
jsonutils.parseobject ("{}");
} catch (Exception e) {
e.printstacktrace ();
}
In Kotlin, however, this is not the case: when we call a Java method that declares a client exception, Kotlin does not force you to do anything:
@Test Fun testnoncheckedexceptions () {
val jsonutils = jsonutils ()
jsonutils.parseobject ("{}")
}
However, when we run, we still throw the exception:
Com.easy.kotlin.CallingJavaNullSafe > Testnoncheckedexceptions FAILED
java.lang.Exception at Callingjavanullsafe.kt:34
The Kotlin exception is not inspected, which can also cause the runtime to throw an exception. On the handling of the exception, the treatment is still to be dealt with. Object Methods
The java.lang.Object definition in Java is as follows:
public class Object {private static native void Registernatives ();
static {registernatives ();
Public final native class<?> GetClass ();
public native int hashcode ();
public boolean equals (Object obj) {return (this = = obj);
Protected native Object clone () throws Clonenotsupportedexception;
Public String toString () {return getclass (). GetName () + "@" + integer.tohexstring (Hashcode ());
Public final native void Notify ();
Public final native void Notifyall ();
Public final native void wait (long timeout) throws interruptedexception;
Public final void Wait (long timeout, int nanos) throws Interruptedexception {...}
Public final void Wait () throws interruptedexception {wait (0); } protected void Finalize () throws Throwable {}}
When a Java type is imported into Kotlin, all references to the type java.lang.Object become any. The any only declares the toString (), Hashcode (), and Equals () functions. How can you use other members of the Java.lang.Object method? Let's take a look at the following. Wait ()/notify ()
The use of concurrency tools (concurrency utilities) instead of Wait () and notify () is recommended in article 69th of the effective Java. Therefore, the reference to type any does not provide these two methods.
If we really need to invoke them, we can convert them to Java.lang.Object to use:
(foo as Java.lang.Object). Wait ()
getclass ()
To get the Java class for the object, we can use the Java extended property on the class reference, which is the extended property of the Kotlin reflection class Kotlin.reflect.KClass.
Val Fooclass = Foo::class.java
The code above uses a binding class reference that is supported from Kotlin 1.1. We can also use Javaclass extended properties.
Val Fooclass = Foo.javaclass
Clone ()
To overwrite clone (), you need to inherit Kotlin. Cloneable:
Class Example:cloneable {
override Fun clone (): Any {...}}
Be careful to overwrite the Clone method. Finalize ()
To overwrite finalize (), we just need to declare it without having to write the override keyword:
Class C {
protected Fun Finalize () {
//terminating Logic
}
}
accessing static Members
A static member of a Java class forms the "companion object" for that class. We can explicitly access its members directly. For example:
A Java class with a static method
public class Jsonutils {public
static String tojsonstring (Object o) {return
json.tojsonstring (o);
}
}
We can call this directly in the Kotlin code:
@RunWith (junit4::class)
class Jsonutilstest {
@Test fun testjsonutils () {
val userservice = Userserviceimpl ()
val user = Userservice.findbyname ("admin")
assert.asserttrue (User.Name = = "Admin")
Val Userjson = jsonutils.tojsonstring (user)
println (Userjson)
assert.asserttrue (Userjson = "{\" name\ ": \" Admin\ ", \" password\ ": \" Admin\ "}"}
}
As we mentioned above, if you call it in turn, Java calls the function in the object class in Kotlin, you need to use the object name for object. INSTANCE to invoke the function. Kotlin and Java reflection
We can use Instance::class.java, Classname::class.java, or instance.javaclass to access Java through Java.lang.Class Reflection Class Java.lang.Class, we can then use the features of reflection in Java.
code example:
@RunWith (Junit4::class) class Refectclasstest {@Test fun Testgettersetter () {Val pr Oduct = Product () val pclz = Product::class.java println (pclz.canonicalname) pclz.declaredfields.f Oreach {println