写点什么

Java 入门视频教程!Kotlin(2)- 泛型与集合

发布于: 3 小时前

前言

Linux 网络协议栈是根据 TCP/IP 模型来实现的,TCP/IP 模型由应用层、传输层、网络层和网络接口层,共四层组成,每一层都有各自的职责。



应用程序要发送数据包时,通常是通过 socket 接口,于是就会发生系统调用,把应用层的数据拷贝到内核里的 socket 层,接着由网络协议栈从上到下逐层处理后,最后才会送到网卡发送出去。


而对于接收网络包时,同样也要经过网络协议逐层处理,不过处理的方向与发送数据时是相反的,也就是从下到上的逐层处理,最后才送到应用程序。


网络的速度往往跟用户体验是挂钩的,那我们又该用什么指标来衡量 Linux 的网络性能呢?以及如何分析网络问题呢?


这次,我们就来说这些。


  • 修饰符

  • 空指针问题

正文

重难点

Kotlin 泛型

类型擦除

我们在编码 java 的时候,写一个泛型类,可能是这样的


class Plate<T>{    T t;   Plate(T t){        this.t = t;    }        T get(){        return t;    }        void set(T t){        this.t =            t;    }}
复制代码


以上是 java 代码。


Java 泛型是伪泛型,在编译之后,所有的泛型写法都会被移除,而会用实际的类型去替换。


mian 函数运行的时候,<T> 被移除。而原来的 T,就变成了 Object。


所以,Plate 的字节码反编译过来就应该是


class Plate{    Object t;   Plate(Object t){        this.t = t;    }        Object get(){        return t;    }        void set(Object t){        this.t = t;    }}
复制代码


那么既然运行的时候,泛型限制全都没有了。那么怎么保证 泛型的作用呢?


答案:编码的时候,编译器帮我们进行校验。


strList.add(123);//报错
复制代码

PECS 法则 和 上下边界的问题

public class Panzi<T> {    T mT;    public Panzi(T t) { mT = t;}    public T get() { return mT; }    public void set(T t) {  mT = t; }}
class Fruit {}class Banana extends Fruit {}class Apple extends Fruit {}
复制代码


 Panzi<Apple> applePanzi = new Panzi<>(new Apple()); Panzi<Fruit> fruitPanzi = new Panzi<>(new Fruit()); fruitPanzi = applePanzi;
复制代码


虽然 Apple 和 Fruit 是父子继承关系。但是 Panzi<Apple> 和 Panzi<Fruit>是半毛钱关系都没有,如果你想 fruitPanzi = applePanzi ,把后者赋值给前者,是会报编译错误的。


如果想让装水果的盘子和 装 苹果的盘子发生一点关系,能够后者赋值给前者.


Panzi<Apple> applePanzi = new Panzi<>(new Apple());Panzi<? extends Fruit> fruitPanzi = new Panzi<>(new Fruit());fruitPanzi = applePanzi;
复制代码


那就必须使用到上下边界的关键字 extends


extends 在泛型中表示指定上界,也就是说,实际类型都必须在 Fruit 之下(包括 Fruit 自己)。那么既然 apple 也是 Fruit 的子类,那么赋值就可以做到。


  • PECS 法则

  • 刚才说到了上边界 extends。而下边界是 super 关键字


  Panzi<? extends Fruit> extendsFruit = new Panzi<>(new Apple());  Panzi<? super Fruit> superFruit = new Panzi<>(new Fruit());
复制代码


super 关键字,在泛型中表示定义下界,实际类型必须在 Fruit 之上,同时也在 Object 之下(包括 Fruit 和 Object)


所以会出现这么一个情况:


  Panzi<? extends Fruit> extendsFruit = new Panzi<>(new Apple());  Panzi<? super Fruit> superFruit = new Panzi<>(new Object());
复制代码


我们有这么两个 Panzi,前者是 Fruit 作为泛型上界,一个是 Fruit 作为下界。


现在,我们从 Panzi 中去调用 get/set 方法。会发现。


PE:


   extendsFruit.set(new Apple()); // 编译报错!   Fruit fruit2 = extendsFruit.get();// 编译正常
复制代码


为何?因为 Fruit 作为上界,我 get 出来的类型可以确定一定是 Fruit 类型的。但是我 set 进去的时候,JVM 无法判定实际类型(因为泛型被擦除,JVM 只人为 set(Object t) 的参数是一个 Object),JVM 要求是 Object,但是你却给了一个 Apple,编译器无法处理。所以干脆 java 的泛型,? extends 定义了上界,只允许 get,不允许 set。这就是 PECS 中的 PE,意思就是 Pruducer Extends ,生产者 Extends,只取不存。


相对应:


CS: 则是 Cunsumer super 消费者只存不取。


  Object object = superFruit.get(); //get,get出来虽然不报错,但是没有任何意义。因为不能确定类型,只知道是一个Object,无法调用API  superFruit.set(new Fruit());// 但是set进去的时候,可以确定一定是一个Fruit的
复制代码


 这就是java泛型的   **PECS法则**. 
复制代码

kotlin 泛型使用实例

java 泛型里面比较纠结的难点就是类型擦除和 PECS 法则了。


那么 kotlin 泛型,原理上和 java 泛型和没有区别。只是写法上有了区别。


open class Fruitclass Apple : Fruit()class Banana : Fruit()class Panzi<T>(t: T) {    var t: T = t    fun get(): T {        return t    }    fun set(t: T) {        this.t = t    }}
复制代码


    fun test1() {        // 试试能不能相互赋值        var fruitPanzi: Panzi<Fruit> = Panzi(Fruit()) //一个水果盘子        var applePanzi: Panzi<Apple> = Panzi(Apple()) //一个苹果盘子        //试试相互赋值    //        fruitPanzi = applePanzi  // 编译报错    //        applePanzi = fruitPanzi  // 编译报错        //双方完全是不相干的类,不能相互赋值 ,    }
/** * 加边界之后再赋值 */ fun test2() { //如果你非要认为苹果盘子归属于水果盘子,那么可以这样 var fruitPanzi2: Panzi<out Fruit> = Panzi(Fruit()) //一个水果盘子 var applePanzi2: Panzi<Apple> = Panzi(Apple()) //一个苹果盘子
fruitPanzi2 = applePanzi2 //那么这就是out决定泛型上边界的案例 }
/** * PECS法则,OUT表示 ? extends 决定上界,上界生产者只取不存 */ fun test3() { //看一下get set方法 // 决定上界之后的泛型,只取不存 var fruitPanzi2: Panzi<out Fruit> = Panzi(Fruit()) fruitPanzi2.get() // fruitPanzi2.set(Apple()) // 这里编译报错,和java泛型的表现一样 }
/** * PECS法则,IN表示 ? super 决定下界,下界消费者,只存不取 */ fun test4() { //试试泛型下界 in var fruitPanzi: Panzi<in Fruit> = Panzi(Fruit()) fruitPanzi.set(Fruit())//可以set,但是看看get val get = fruitPanzi.get()//不会报错,get出来的类型就完全不能确定了,只知道是 顶级类Any? 的子类,获得它也没有意义
}
复制代码



集合操作

Kotlin 的集合,并没有重新开创一套规则,它的底层依然是 java 的 Collection。Kotlin 提供了可变集合和不可变集合的接口。


  • 不可变集合:List,Set,Map (内部元素不可以 增减 或者 修改,在定义的时候就已经将容量和内部元素定死)

  • 不可变集合: MutableList , MutableSet , MutableMap (声明的时候可以随意指定初始值,后续可以随意增删和修改内部元素)


集合操作分为:对象的创建api 的调用

对象的创建

方式有多种,以不可变集合 List 为例,kotlin 的 List 底层和 Java 的 List 一致,底层数据结构是数组。


静态指定元素值


fun main() {    val listOf = listOf<String>("str1", "str2", "str3")    listOf.forEach { print("$it ") }}
复制代码


执行结果:


str1 str2 str3
复制代码


通过动态创建过程来指定元素值


fun main() {
val list = List(3) { "str$it" } list.forEach { print("$it ") }}
复制代码


执行结果:


str0 str1 str2 
复制代码

api 的调用

总结

这份面试题几乎包含了他在一年内遇到的所有面试题以及答案,甚至包括面试中的细节对话以及语录,可谓是细节到极致,甚至简历优化和怎么投简历更容易得到面试机会也包括在内!也包括教你怎么去获得一些大厂,比如阿里,腾讯的内推名额!


某位名人说过成功是靠 99%的汗水和 1%的机遇得到的,而你想获得那 1%的机遇你首先就得付出 99%的汗水!你只有朝着你的目标一步一步坚持不懈的走下去你才能有机会获得成功!


成功只会留给那些有准备的人!资料免费领取方式:戳这里



用户头像

VX:vip204888 领取资料 2021.07.29 加入

还未添加个人简介

评论

发布
暂无评论
Java入门视频教程!Kotlin(2)-泛型与集合