美文网首页
kotlin-学习-语法4-在工程中混用 Java 与 Kotl

kotlin-学习-语法4-在工程中混用 Java 与 Kotl

作者: 牵手生活 | 来源:发表于2021-12-15 10:02 被阅读0次
    image.png

    文章

    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.

    image.png

    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.

    image.png

    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.

    image.png

    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.

    image.png

    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.

    image.png image.png

    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.


    image.png

    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.

    image.png

    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.

    image.png

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

    image.png

    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.

    image.png

    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.

    image.png

    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.

    image.png

    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.

    image.png

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

    image.png

    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.

    image.png

    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.

    image.png

    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.

    image.png

    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.

    image.png

    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.

    image.png

    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.

    image.png

    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.


    image.png

    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.

    image.png

    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.

    image.png

    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.


    image.png

    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.

    image.png

    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--

    image.png

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

    image.png

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

    image.png

    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.

    image.png

    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.


    image.png

    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.

    image.png

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


    image.png

    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.

    image.png

    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.

    image.png

    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.

    image.png

    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.

    image.png

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

    image.png

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

    image.png

    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.

    image.png

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

    image.png

    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.

    image.png

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


    image.png

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

    image.png

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


    image.png

    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.

    image.png

    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.

    image.png

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

    image.png

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

    image.png

    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.

    image.png

    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.

    image.png

    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.

    image.png

    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--

    image.png

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

    image.png

    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.

    image.png

    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.

    image.png

    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.

    image.png

    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.

    image.png

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

    image.png

    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.

    image.png image.png

    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.

    image.png

    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.

    image.png

    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.

    image.png

    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.

    image.png

    And similarly ,for the you need variable names.

    image.png

    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.

    image.png

    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.

    image.png

    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.


    image.png

    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

    相关文章

      网友评论

          本文标题:kotlin-学习-语法4-在工程中混用 Java 与 Kotl

          本文链接:https://www.haomeiwen.com/subject/unvcfrtx.html