2024年鸿蒙最新游戏开始?Kotlin 版本鱿鱼游戏,最后一战_kotlin 游戏,2024年最新HarmonyOS鸿蒙开发面试技巧

img
img

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

a) abc

b) Unresolved reference: a

c) Nothing, it won’t compile

d) null

答案:D

这个问题是Kotlin implementing的一个比较让人困扰的地方,所以,我们来分析下Kotlin生成的Java代码。

public static class Parent {  
  
    private final String a;  
  
    public String getA() {  
        return this.a;  
    }  
  
    Parent(String a) {  
        super();  
        this.a = a;  
        System.out.print(this.getA());  
    }  
}  
  
public static final class Children extends Parent {  
    private final String a;  
  
    public String getA() {  
        return this.a;  
    }      
  
    Children(String a) {  
        super(a);  
        this.a = a;  
    }  
}  

As you can see, to get a we use getA method which references a. The only problem is that it is overriten in Child so it actually references a from Child which is not set yet at this point. It is because parent is always initialized first.

可以看见,Parent中的a,在Child中被重写了,所以它实际上引用了Child中的a,而这个a在此时还没有被设置,因为父类总是先被初始化。所以,在使用Kotlin的简化构造函数时,一定要注意属性的覆写。

Child apply

open class Node(val name: String) {  
    fun lookup() = "lookup in: $name"  
}  
  
class Example : Node("container") {  
    fun createChild(name: String): Node? = Node(name)  
  
    val child1 = createChild("child1")?.apply {  
        println("child1 ${lookup()}")  
    }  
  
    val child2 = createChild("child2").apply {  
        println("child2 ${lookup()}")  
    }  
}  
  
调用:  
Example()  


A) child1 lookup in: child1; child2 lookup in: child2

B) child1 lookup in: child1; child2 lookup in: container

C) child1 lookup in: container; child2 lookup in: child2

D) none of the above

答案:B

由于createChild返回nullable,所以在child2的apply中,我们收到的context是Node?。我们不能在没有unpack的情况下直接调用lookup。如果我们想这样做,我们应该使用this?.lookup()。由于我们没有这样做,编译器会搜索它可以使用的lookup,并在Example上下文中找到它的实现。

Negative numbers

print(-1.inc())  
print(", ")  
print(1 + -(1))

a) 0, 0

b) Won’t compile in line 4

c) 0, 2

d) -2, 0

答案:D

在这两种情况下,我们在Int类型上使用unaryMinus操作。当你输入-1时,它与1.unaryMinus()相同。这就是为什么1 + -(1)能正确工作。-1.inc()返回-2,因为inc用在了运算符之前。这个表达式等同于1.inc().unaryMinus()。为了解决这个问题,你应该使用小括号(-1).inc()。

Copy

data class Container(val list: MutableList<String>)  
  
val list = mutableListOf("one", "two")  
val c1 = Container(list)  
val c2 = c1.copy()  
list += "oops"  
  
println(c2.list.joinToString())  


a) one, two

b) one, two, oops

c) UnsupportedOperationException

d) will not compile

答案:B

data class的copy()方法只做了一个浅层拷贝,即只复制了对字段的引用。如果要实现深拷贝,可以使用不可变data class来避免这个问题。

Covariance

class Wrapper<out T>  
  
val instanceVariableOne : Wrapper<Nothing> = Wrapper<Any>()//Line A  
val instanceVariableTwo : Wrapper<Any> = Wrapper<Nothing>()//Line B

a) Both lines A and B compile

b) Lines A and B do not compile

c) Line A compiles; Line B does not

d) Line B compiles; Line A does not

答案:D

这道题考察的是kotlin的协变,Wrapper是Wrapper的一个子类型,因为Nothing是Any的一个子类型。Wrapper的子类型与T的子类型相同。B行是好的。A行不能编译。它把超类型分配给一个子类型。

Receivers wars

fun foo() {  
    println("Top-level rule")  
}  
  
class Foo {  
    fun foo() {  
        println("Extension receiver rule")  
    }  
}  
  
class Test {  
    fun foo() {  
        println("Dispatch receiver rule")  
    }  
  
    fun Foo.foo() {  
        println("Member extension function rule")  
    }  
  
    fun Foo.test() {  
        foo()  
    }  
  
    fun testFoo() {  
        Foo().test()  
    }  
}  
  
调用:  
Test().testFoo()  


a) Top-level rule

b) Extension receiver rule

c) Dispatch receiver rule

d) Member extension function rule

答案:B

当我们有一个extension receiver (Foo)时,它的方法总是比dispatch receiver(同一类中的方法)有更高的优先级。

而当Member extension和extension receiver冲突时,extension receiver一定会被调用,所以Member extension的优先级是最低的。

Int plus-plus

var i = 0  
println(i.inc())  
println(i.inc())  
  
var j = 0  
println(j++)  
println(++j)  


  


a) 0, 1, 0, 1

b) 0, 1, 0, 2

c) 1, 1, 0, 2

d) 1, 2, 0, 1

答案:C

这个问题从C++就开始存在了,又想起了谭浩强的支配。前缀运算符++(++j)增加数字并返回新值,后缀运算符也增加属性,但返回前值。

但会令人疑惑的部分是,前缀和后缀都是对Kotlin函数inc的引用,你从ide中点击++i和i++,都会跳到inc的引用,inc返回了一个新值,但是未被赋值。

Return in function literal

fun f1() {  
    (1..4).forEach {  
        if (it == 2) return  
        println(it)  
    }  
}  
  
fun f2() {  
    (1..4).forEach(  
        fun(it) {  
            if (it == 2) return  
            println(it)  
        })  
}  
  
调用:  
f1()  
f2()  

a) 134134

b) 1134

c) 1341

d) Doesn’t compile

答案:B

当我们想在lambda表达式中使用return时,我们需要使用return@forEach这样的标签,否则它会跳出整个lambda。

而因为for-each是内联函数,所以在f2中,实际上使用了一个匿名函数,这里return就可以退出函数,而不是lambda。

WTF with labels

val j = wtf@ { n: Int -> wtf@ (wtf@ n + wtf@ 2) }(10)  
println(j)

a) It won’t compile

b) 10

c) 2

d) 12

答案:D

标签在这里毫无作用,不要被他迷惑了。

Order of nullable operators

val x: Int? = 2  
val y: Int = 3  
  
val sum = x?:0 + y  
  
println(sum)  


a) 3

b) 5

c) 2

d) 0

答案:C

Elvis operator的优先级比+低,所以加号先被执行,就变成了x?:3,答案是2,可以通过加括号的方式(x3:0)来改变优先级。

Extended enums

enum class Color {  
    Red, Green, Blue  
}  
  
fun Color.from(s: String) = when (s) {  
    "#FF0000" -> Color.Red  
    "#00FF00" -> Color.Green  
    "#0000FF" -> Color.Blue  
    else -> null  
}  
  
调用:  
println(Color.from("#00FF00"))  


a) Green

b) Color.Green

c) null

d) will not compile

答案:D

对Color的扩展函数只适用于Color的实例,例如,Color.Blue.from(),对枚举本身的扩展函数只有在它有一个Companion object时才能进行。

enum class Color {  
  Red, Green, Blue;  
  companion object   
}  
  
fun Color.Companion.from(...)

这又是一个骚操作。

Hello blocks

fun hello(block: String.() -> Unit) {  
    "Hello1".block()  
    block("Hello2")  
}  
  
调用:  
hello { println(this) }  

a) Hello1

b) Hello2

c) Hello1Hello2

d) will not compile

答案:C

这道题的重点是分清楚哪个是lambda,哪个是带接收器的拓展函数。

I am this

data class IAm(var foo: String) {  
    fun hello() = foo.apply {  
        return this  
    }  
}  
  
调用:  
println(IAm("bar").hello())  

a) IAm

b) IAm(foo=bar)

c) bar

d) Will not compile

img
img

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

data class IAm(var foo: String) {
fun hello() = foo.apply {
return this
}
}

调用:
println(IAm(“bar”).hello())


a) IAm


b) IAm(foo=bar)


c) bar


d) Will not compile


[外链图片转存中...(img-oRV08UcN-1715749095565)]
[外链图片转存中...(img-6aiSw7hv-1715749095565)]

**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**[需要这份系统化的资料的朋友,可以戳这里获取](https://bbs.csdn.net/topics/618636735)**


**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

  • 5
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值