kotlin-學習-語法4-在工程中混用 Java 與 Kotlin 文章 出品 視頻

文章

kotlincn-在工程中混用 Java 與 Kotlin
簡書-使用kotlin和Java混合開發Android項目爬坑記錄
csdn-Android開發者快速上手Kotlin(九) 之 Kotlin與Java混合開發

出品

Nicole Borelli(女):
Murat Yener():

WenBo Zhu(華人):

視頻

android developer -Java ❤️ Kotlin, Happy Together 🎵 (Android Dev Summit '19)

android developer -Kotlin under the hood: Understand the internals (Google I/O'19)本會話將幫助您更好地理解這些特性和擴展在內部的作用。


Nicole Borelli:
Hi So this is Kotlin Programming Language Loves Java.

I'm Nicole Borelli, developer programs engineer on Android.

Murat Yener:
I 'm Murat . I'm developer advocate on Android.

WenBo Zhu:
I'm Wenbo . I'm a Android developer on the Google Home Apps team.

--
Nicole Borelli:
And yeah -- so we're going to be chatting to you about Kotlin and Java interop.

Murat Yener:
Yep-- so as if we didn't have one language and it wasn't enough ,now we have two languages. And even though if you don't have any intention to use them together, you might be using you library,which is written in the other language. So you might be using two at the same time.

Before I start,to be compliant with the new Android Logo, Let me put on my Android hat.

So we have lots of slides. So let's jump in first with calling Java programming language from Kotlin. So first thing--nullability. I'm pretty sure this brings lots of question marks ,literally.

Well,because two language are different, Jave has default nullability for values and Kotlin doesn't. So if you're calling a Java function from Kotlin, Kotlin has no idea if the function can return or receive null values. That's why ,basically ,you need to add question marks or explanation marks ,to basically tell Kotlin that a null value can happen.

And this really makes you feel bad, like you're doing something terribly wrong. And suddenly you end up with question marks all over your code base.
Luckly,this is actually very easy to fix. What do you need to do is basically annotate all the public APIs ,whcih are non-primitive parameters, fields and returns ,and annotate them to tell Kotlin that they can they are not null.

We have a list of nullability annotations. We usually use JetBrain annotations. Android's annotations are also fine. JSR-305 is discouraged. And you need a flag to make it work with the Java 9 module system.

Let's see an example. So here,we have a method which receives a collection of string elements and returns a set off strings.
And in this case,Kotlin has no clue if the input or the output can be null.
And to call this function from Kotlin ,you need to tell --Ok,I'm expecting null in this case.

If we go ahead and add not null annotations, then calling this function from Kotlin becomes very nicer.

Next ,we have property prefixes, which are getters and setters.


So if you're using Java bean style,basically you don't have much issues here. If you have null argument method which starts with get, Kotlin knows ,this is the getter. And you can accesss it over the property name.

Similarly ,if you have a single argument method,which the name starts with set, Kotlin knows,this is the setter. And you can ,again,set over the property name.

And as expected ,is works a similar way. So just follow the Java bean style. And everything should work.

Next ,the keywords --well,language have result words and that's perfectly normal. Actually ,Java didi a very goog job with not introducing a new keyword and not breaking the previous code.
Java 9 and 10 aside,the last breaking change to happen was edition of enum keyword with Java 5 ,which was in 2005. And the change before that was a third key word wiht Jave 1.4, which was in 2002.

But Kotlin is a new language. And it has its own keywords ,such as fun, is ,in. And these keywords are valid in Java but not in Kotlin.
So if you have a function or a parameter which uses these keywords ,you might have some issues calling it from Kotlin . Let's see an example.

Let's imagine you have a method called is, which is a terrible name ,but valid in Java.
So techniclly ,you can do that. But if you want to call this from Kotlin, then you have some issues,because is is a result word.

Well, the best thing you can do is rename you method. In this case ,yes,it's definitely the best case.

But in the end ,you might have a widely-adapted and used library. And you might not be able to rename your functions.

In that case,what happens is a caller from Kotlin will not be able to call without [inaudible ]

So your users need that [inaudible] to be able to access your result word keyboards.
So that's definitely an option. And it's not really breaking your users.

But we really spend a lot of time getting rid of the semicolon. So please ,don't introduce a new character just to make your libraries work.
As long as you can rename ,go with that.

Next,we have another topic. Try to avoid using the names on any on extension functions and extension properties. Actually ,member methods and parameters take precedence. But it's still very confusing. And it's really hard to follow how the code runs.

Next topic--operator overloading . Well again, Java did not have operator overloading . And Kotlin has. And this might have some side effects. Let's first see how operator overloading works.

So what Kotlin actually does is Kotlin translates the operator into a function name. In this case ,let's say, plus becomes a method ,plus, and receives another object.

To give an example on this ,let's imagine we have a object called Roman numeral,which represents a number value in string in Roman numerals. And we want to add two together by using plus sign without calling a new method.

In order to do that,we implement a plus method,which receive another Roman numeral then converts them into a number and adds them together-converts them back. And if you use plus from Kotlin side.

And if you use plus from Kotlin side,Kotlin knows which method to call and do operation. So make sure ,if you're using the same method names--plus, minus,or other operator names-- make sure they are compatible with operators and you are not basically invoking thme by mistake.

And another thing about operator overloading is -- Jave ,at the time didn't have operator overloading for a specific reason. Because operator overloading can be easily abused and overused. Make sure you have a valid use case to overwrite the operators.

Next ,we have SAM ,which stands for Single Abstract Method,which means a functional interface with one method. Jave takes an anonymous implementation and oonverts it to the interface required.


And Kotlin supports SAM. Function literals are auto-converted as long as the parameter types match.

If the parameter,which is eligible for SAM conversion--it's part of the method call -- the parameter should be the last. And let's see what happens.

So let's imagine we have an operation,which is eligible for SAM conversion and two parameters ,which are two numbers. To call this from Kotlin ,what we need to do is ,first ,askt the lamdba, then the two numbers. Howerver,if we change the order of parmeters, suddenly the call from Kotlin becomes way nicer.

And apparently ,what I talked about SAM was not enough. So Wenbo has more to add from his real-life experience from Google Home app.


Wenbo zhu:
So thank you,Murat. So speaking of SAM conversion ,I think there's something you should know. A SAM conversion only works for Java and Kotlin.

So what this means is that, if we have defined a interface in Kotlin with a single matter and a function that takes in an instance of this interface--

if we try to invoke this using SAM conversion, we will get a compile time error.

To make this work,we can pass in the instance of an anonymous class, which implements this interface.

So the reason that SAM conversion is not supported in Kotlin is that Kotlin supports function types as first-calss citizens ,so SAM conversion is not needed.

So if we change the previous function to take in a function type ,then we can invoke this the same way as if we were using a SAM conversion.

But what if the interface is defined in Java and the function is still in Kotlin ?Does this count as Java Interop? The answer is still no ,because at this moment, you're still coding a Kotlin function,which has the option to taking a function type.
Therefore ,SAM conversion is still not supported.

And next Nicole will talk about calling Kotlin from Java.


Nicole borelli:

Thanks ,Wenbo.
So yes --Kotlin and calling Kotlin from Java. Yes --that makes sense.
So when we initially announced Kotlin as a supported language , we recommended doing conversion in steps.
I mean,if you were interested in re-writing your app in Kotlin all at once--awsome. But most of the time ,we couldn't do that. So we recommended doing little bits at a time. But now,converting utility classes might be someting that you would want to do.

So let's say that we have our utils.java class. And we want to go and convert this to Kotlin.


So we do this. And in this example ,we pulled out our one mehod and we put in a extension dates.kt.
And we just made it into an extension method. And it is great . But if we wanted to call this from the Jave programming language ,it needs to put it into a class.

And so it will call itself dates.kt--which we either need to refactor all of our Java programming language code or we need to do something here.
And fortunately ,Kotlin supports this JVM name.

So from Kotlin ,we don't have to worry, because we're just going to use the extension mehtod.
From the java programming language,we can change the class that gets generated to utils. We also might have other methods that were in this utils class. So we might have string methods or various numbers and that sort of thing.

And we might want to have more than one these called utils.

So what we can also do is add this JVM multi file class. And it will combine all of this by code together to create one class called utils.class at the end.

And thne with this in place ,our Java code stays exactly the same.

Another greate thing in Kotlin are data classes. And we heard a little bit earlier that we shouldn't worry about getters and setters.


But if we were using these classes ,directly accessing the field ,and we converted them to data classes, we would have these getters and setters.

And so from the Java programming language, we need to call these through getters. What we can do instead is we can update them to use Jvmfield.

And this will expose the field directly without creating getters and setters.

We can do these for other things. This won't actually work,because it has a function behind it. So there is no field to expose.

Lateinits are automatically actually exposed as fields and so are consts.


So there's reason to use a Jvmfield on these.

Ok,so we have another data class. And because of the getters and setters ,when we compile this,


it will create getters and setters. And this is greate. So we have name. And we have getName,setName. We have likesPink,because we want to know if our users like the color pink.
But it makes this get likesPink,rather than just being able to use it drectly. So what we might want to do is we might want to add in a couple of these annotations.

So again,we can use JvmName. And we can say ,for likesPink,we just want to reference our getter as likesPink. Also ,let's say that instead of setNmae, we would like it to be called changeName.

So again ,we can use the same annotation, put it on our setter.

And then when Kotlin generates our byu code for this, we have changeName and just likesPink.

Oh, so Wenbo,this look like your code.


Wenbo zhu:
Yeah--sorrry for jumping in like is .These are my slides. I'd really like to talk about JVM static annotation because ,for me,this is one of the first things that I needed for calling Kotlin from Java.

So say I have a service calss defined in Java and a static method to allow me to schedule this service.

I try to convert this class into Kotlin.

The auto conversion tool would just put the static method into the companion object. But this is not good enough if we are tring t ocall this method from Jave ,because I cannot use the idiomatic static method call. But rather ,I need to use the instance method call on the componion object.

And luckly,Kotlin provides JvmStatic annotaion, which is a way to tell Kotlin compiler to generate a static method after enclosing class. But one note here is that you won't be able to get performance scan using thsi annotation. But rather ,you will end up generating one more method.

And JvmStatic annotation can be applied to companion objects, named objects ,and also companion objects of interfaces as well.
Back to you ,Nicole.


Nicole borelli:
Thanks. So let's see--

Ok ,so Kotlin does someting really,really fun ,which is we can have default parameters.

Default parameters aren't suppoerted directly from the Jave programming language. So right here,we're using our utils class,which we generated before. But we're not passing in that interpolator's value. So it's going to be a compiler error.

But we can put this JvmOverloads. And now this will ask the Kotlin compiler to generate overloads for each of their optional parameters, going from left to right.

It still won't alow you pick and choose which parameters to put in like you could in Kotlin with name parameters. But it allows this to work.

We can also use our JvmName here. So instead of ,in Kotlin having a bitmap.resize make sense,from the Jave programming language ,it might makes more sense to have it called resizeBitmap.

Kotlin doesn't have checked exceptions ,which is great, because you don't have to put everything in a try catch block.

But if we're using this from the Java programming language, then it will give us an error. And it will tell us that the exception is not thrown.

And so what we can do though is we can go into our Kotlin code. And we can add a throws annotation. So then it will add this to the generated by code.


And then the compiler will reluctantly accept that this is happening .

Oh -- so it looks like there's one more thing that Wenbo would like to talk to you about.

Wenbo zhu:

So there's one last thing I'd like to mention. It's the feature leak prevention. So if we take a look at the Kotlin function, the generated code will look like this.

And we can see that the name of the function parameter is passed in this intrinsic tracks as a string. And basically ,this check here to make sure that the value passed in by the parameter in not null, because we won't be able to guarantee that from Java Color.

Since this name is passed in as a string ,unlike a class name or function names, it's not going to be obfuscated by ProGuard. And therefore,if someone were to tear down your APK ,they will see the string there.

And therefore ,I do not recommend puting anything sensitive inside your function parameter name.

And similarly ,for the you need variable names.

They are also used by intrinsic checks to make sure they are initialized properly and ,therefore, can potentially leak your feature as well.

Another example is the extension function name.

So as Nicole has shown in previous slides, extension functions are resolved to static methods, where a receive type is passed as a parameter. And the name of the parameter will be generated as dollar sign-- this dollar sign function name.

And therefore ,you also need to watch out the extension function name to make sure there's no secret in it . Thre are actually a lot of other intrinsic checks. And I think a good way to learn about them is to check out the source code of the intrinsics class.

One last note --other than just renaming everything, you can also choose to use this assumenosideeffects ProGuard rule to let ProGuard remove this intrinsics check for you .

But I recomment,at least leave these checks in for double testing environment so that ,if something really goes wrong ,it can fail fast.


Nicole borelli:
Cool --thanks. Yeah,so we talked about a lot of really awesome thing. And Kotlin is awesome . Java is great. And calling them from each other is supported both ways.
so yeah-- I think,great .

=========12:03====22:50

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章