亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Kotlin中協變、逆變和不變的示例分析

發布時間:2021-07-26 14:22:17 來源:億速云 閱讀:166 作者:小新 欄目:移動開發

小編給大家分享一下Kotlin中協變、逆變和不變的示例分析,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!

前言

Kotlin 泛型的基本語法類似于 Java ,不過出于型變安全,不支持 Java 中的<? extends T>,<?super T> 通配符型變約束,而是采用類似 C# 的 in,out 用于支持協變和逆變,這同時避免了處理子類型化,父類化的問題(即Java泛型中典型的List<T> 不是 List<Object>的子類型的問題);

基本的泛型語法可以參考官方中文文檔:https://www.kotlincn.net/docs/reference/

泛型實參的繼承關系對泛型類型的影響

協變:泛型類型與實參的繼承關系相同

逆變:泛型類型與實參的繼承關系相反

不變:泛型類型沒有關系

協變點:返回值類型是泛型參數類型

逆變點:入參類型是泛型參數類型

@UnsafeVariance:協變點違例,告訴編譯器,沒事,你就按照我的意思執行

1、泛型

什么是泛型?泛化的類型或者是類型的抽象,鴨子類型(看起來像鴨子,走起來也像鴨子,就是鴨子類型)在靜態語言中的一種靜態實現

1、抽象類,是這個類的本質,它是什么

2、接口,關心類能夠做什么,行為能力

舉兩個例子

兩個數的比較大小

// 需要有對比的功能,沒有的話就會報錯a<b
//加入限制 Comparable 具有對比的功能
fun<T:Comparable<T>> maxOf(a:T,b:T):T{
 return if (a<b) b else a
}

方法調用

val a=2
val b=3
val maxOf = maxOf(2, 3)
 println("shiming "+maxOf)

輸出結果

 shiming 3

讓一個類具備對比的能

data class Complex(val a:Double,val b:Double):Comparable<Complex>{
 override fun compareTo(other: Complex): Int {
 return (value()-other.value()).toInt()
 }
 fun value():Double{
 return a*a+b*b
 }

 override fun toString(): String {
 return "$a*$a+$b*$b="+(a*a+b*b)
 }
}

方法調用

 val Complex1=Complex(4.0,5.0)
 val Complex2=Complex(5.0,6.0)
 println("shiming Complex1="+Complex1)
 println("shiming Complex2="+Complex2)
 println("shiming"+Complex1.compareTo(Complex2))

輸出結果

04-16 11:22:10.824 26429-26429/com.kotlin.demo I/System.out: shiming Complex1=4.0*a+5.0*b=41.0
04-16 11:22:10.824 26429-26429/com.kotlin.demo I/System.out: shiming Complex2=5.0*a+6.0*b=61.0
04-16 11:22:10.824 26429-26429/com.kotlin.demo I/System.out: shiming-20

通過Demo的測試的結果的發現:泛型不管你到底是什么,它只管你能夠做什么事情

定義多個泛型參數

kotlin中的例子

 (1..2).map { println("shiming $it=="+it) }

/**
 * Returns a list containing the results of applying the given [transform] function
 * to each element in the original collection. 
 (1..2).map調用的底層的方法
 */
public inline fun <T, R> Iterable<T>.map(transform: (T) -> R): List<R> {
 return mapTo(ArrayList<R>(collectionSizeOrDefault(10)), transform)
}
/** A function that takes 22 arguments. function中最多的參數22.一共有23個方法 */
public interface Function22<in P1, in P2, in P3, in P4, in P5, in P6, in P7, in P8, in P9, in P10, in P11, in P12, in P13, in P14, in P15, in P16, in P17, in P18, in P19, in P20, in P21, in P22, out R> : Function<R> {
 /** Invokes the function with the specified arguments. */
 public operator fun invoke(p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7, p8: P8, p9: P9, p10: P10, p11: P11, p12: P12, p13: P13, p14: P14, p15: P15, p16: P16, p17: P17, p18: P18, p19: P19, p20: P20, p21: P21, p22: P22): R
}

kotlin中的類傳入泛型

data class ComplexNumber< T : Number>(val a:T,val b:T){
 override fun toString(): String {
 return "$a*$a+$b*$b"
 }
}

泛型的實現的機制

何為偽泛型(Java 、Kotlin)?編譯完了,泛型就沒有了(真正的原因就是最開始寫Java編譯器的幾個人偷懶取巧,留下了歷史問題,Martin Odersky爆料。Martin Odersky是Typesafe的聯合創始人,也是Scala編程語言的發明者。)

//按照重載的定義這兩個方法應該編譯的過的,但是Java和kotlin編譯完了成了object或者是沒有
fun needList(list:List<Double>){
}
fun needList(list:List<Int>){
}

通過反編譯可以看到,臥槽我的泛型沒有了

 public static final void needList(@NotNull List list) {
  Intrinsics.checkParameterIsNotNull(list, "list");
 }

 public static final void needList(@NotNull List list) {
  Intrinsics.checkParameterIsNotNull(list, "list");
 }

Kotlin中協變、逆變和不變的示例分析

沒有編譯通過

何為真泛型(C#)?編譯完了,還在

如果把以上的代碼放在C#中,就不會報錯,原因是C#的泛型不僅存在于編譯器,也存在運行期

java1.5才有的泛型特性,迫于現實的需求!用的人太多,但是C#第一個版本也沒有泛型,但是用的人少,所以C#使用的是真泛型

但是有一種方式可以在編譯器得到泛型類型:

reified讓泛型參數具體化,定義在inline中 ,kotlin實現為偽泛型,需要這個關鍵字植入到調用出才可以

//inline inline可用內聯函數(inline function)消除這些額外內存開銷,
//說白了就是在調用處插入函數體代碼,以此減少新建函數棧和對象的內存開銷!
inline fun<reified T> getT(){
 println("shiming"+T::class.java)
}

調用

getT<String>()
getT<Double>()
//通過反編譯得到的結果,說白了,其實就是打印了,這樣永遠都不會丟失
  String var21 = "shiming" + String.class;
  System.out.println(var21);
  var21 = "shiming" + Double.class;
  System.out.println(var21);

得到

04-16 15:28:59.775 31782-31782/com.kotlin.demo I/System.out: shimingclass java.lang.String
04-16 15:28:59.775 31782-31782/com.kotlin.demo I/System.out: shimingclass java.lang.Double

在實際工作中可以這樣用

data class Person(val name:String,val age:Int){
 //重寫,得到json字符串
 override fun toString(): String {
  return "{name="+"\""+name+"\","+"age="+age+"}"
 }
}

//例子 通過inline把這個前面的代碼植入到后面
// reified讓泛型參數具體化,定義在inline中 ,kotlin實現為偽泛型,需要這個關鍵字植入到調用出才可以
inline fun <reified T> Gson.fromJson(json:String):T=fromJson(json,T::class.java)
//模擬網絡請求返回的json數據,得到bean類
 val person=Person("shiming",20)
 println("shiming "+person)
 val toString = person.toString()
 val person1= Gson().fromJson<Person>(toString)
 println("shiming person1"+person1)

//上面一段代碼的反編譯的結果,和java是一樣的,執行的流程
  Person person = new Person("shiming", 20);
  String toString = "shiming " + person;
  System.out.println(toString);
  toString = person.toString();
  Gson $receiver$iv = new Gson();
  Person person1 = (Person)$receiver$iv.fromJson(toString, Person.class);
  String var25 = "shiming person1" + person1;
  System.out.println(var25);

具體的關系

f(?)是逆變(contravariant)的,當A≤B時有f(B)≤f(A)成立;

f(?)是協變(covariant)的,當A≤B時有成立f(A)≤f(B)成立;

f(?)是不變(invariant)的,當A≤B時上述兩個式子均不成立,即f(A)與f(B)相互之間沒有繼承關系。

協變

在kotlin中List不是Java中的List,它只是只讀的,查看源碼如下List<out E> ,看見Out就是協變的,只讀類型,List中根本沒有add的方法,不可添加元素

//out 協變 Number 是Int的父類,協變點函數得返回類型
val numberList:List<Number> = listOf<Int>(1,58)
 public interface List<out E> : Collection<E> {
 // Query Operations
 override val size: Int

 override fun isEmpty(): Boolean
 //告訴編譯器 我知道,你不要管我知道怎么搞
 override fun contains(element: @UnsafeVariance E): Boolean
 override fun iterator(): Iterator<E>

 // Bulk Operations
 override fun containsAll(elements: Collection<@UnsafeVariance E>): Boolean

 // Positional Access Operations
 /**
  * Returns the element at the specified index in the list.、
  返回值的類型是E
  */
 public operator fun get(index: Int): E

 // Search Operations
 /**
  * Returns the index of the first occurrence of the specified element in the list, or -1 if the specified
  * element is not contained in the list.
  */
 public fun indexOf(element: @UnsafeVariance E): Int

 /**
  * Returns the index of the last occurrence of the specified element in the list, or -1 if the specified
  * element is not contained in the list.
  */
 public fun lastIndexOf(element: @UnsafeVariance E): Int

 // List Iterators
 /**
  * Returns a list iterator over the elements in this list (in proper sequence).
  */
 public fun listIterator(): ListIterator<E>

 /**
  * Returns a list iterator over the elements in this list (in proper sequence), starting at the specified [index].
  */
 public fun listIterator(index: Int): ListIterator<E>

 // View
 /**
  * Returns a view of the portion of this list between the specified [fromIndex] (inclusive) and [toIndex] (exclusive).
  * The returned list is backed by this list, so non-structural changes in the returned list are reflected in this list, and vice-versa.
  *
  * Structural changes in the base list make the behavior of the view undefined.
  */
 public fun subList(fromIndex: Int, toIndex: Int): List<E>
}

逆變:Comparable接口

  //in 逆變 ,泛型的繼承關系相反 逆變點就是函數參數的類型 Any是Int的父類
 val intComparable:Comparable<Int> = object :Comparable<Any>{
      override fun compareTo(other: Any): Int {
        return 0
      }
    }

public interface Comparable<in T> {
  public operator fun compareTo(other: T): Int
}

不變:MutableList相當于Java中的|ArrayList,可讀可寫,不可變,泛型沒有in 或者是out ,泛型的繼承關系也沒有具體的關系,前面是后面的子類或者是后面是前面的子類,都是不成立。

Kotlin中協變、逆變和不變的示例分析

public interface MutableList<E> : List<E>, MutableCollection<E> {
  override fun add(element: E): Boolean
  override fun remove(element: E): Boolean
  override fun addAll(elements: Collection<E>): Boolean
  public fun addAll(index: Int, elements: Collection<E>): Boolean
  override fun removeAll(elements: Collection<E>): Boolean
  override fun retainAll(elements: Collection<E>): Boolean
  override fun clear(): Unit
  public operator fun set(index: Int, element: E): E
  public fun add(index: Int, element: E): Unit
  public fun removeAt(index: Int): E
  override fun listIterator(): MutableListIterator<E>
  override fun listIterator(index: Int): MutableListIterator<E>
  override fun subList(fromIndex: Int, toIndex: Int): MutableList<E>
}

星投影:始終找最安全的解決方法,安全方式是定義泛型類型的這種投影,該泛型類型的每個具體實例化將是該投影的子類型

如果泛型類型具有多個類型參數,則每個類型參數都可以單獨投影。
例如,如果類型被聲明為 interface Function <in T, out U> ,可以想象以下星投影:

Function<*, String> 表示 Function<in Nothing, String>

Function<Int, > 表示 Function<Int, out Any?>

Function<, *> 表示 Function<in Nothing, out Any?>

可用的星投影的地方

 //out 協變 Number 是Int的子類,協變點函數得返回類型
    val numberList:List<*> = listOf<Int>(1,58)
    val any = numberList[1] //星投影,去找父類
    //in 逆變 ,泛型的繼承關系相反 逆變點就是函數參數的類型
    val intComparable:Comparable<*> = object :Comparable<Any>{
      override fun compareTo(other: Any): Int {
        return 0
      }
    }
    //星投影,去找父類 Nothing
    intComparable.compareTo()

fun <T> hello(){

}
open class Hello<T>{

}
//這樣 就可以使用星投影
class Hello33<T>
//這樣也可以使用星投影
class Hello2:Hello<Hello<*>>()
class Hello332:Hello<Hello33<*>>()

在kotlin中調用java的類

//這樣也可以使用星投影
 val raw:Raw<*> = Raw.getRaw()
public class Raw<T> {
  @Override
  public String toString() {
    return "老子是Raw";
  }
  public static Raw getRaw(){
    return new Raw();
  }
}

不可以使用星投影的地方

//不變的話,就根本沒有繼承關系,沒有任何的關系 原因是這樣不安全
//    val list1:MutableList<Number> = mutableListOf<Int>(1,5,4)
    list1.add(BigDecimal(1244444444))
//    val list2:MutableList<Int> = mutableListOf<Number>(1,5,4)

    //泛型的實參不要使用星號
//    val numberList11d:List<*> = listOf<*>(1,58)
//
//    hello<*>()
//
//    val hello: Any = Hello<*>()
fun <T> hello(){

}
open class Hello<T>{

}

安卓中一個MvpDemo,使用到了星投影和協變!

package com.kotlin.demo.star_demo
import org.jetbrains.annotations.NotNull
import java.lang.reflect.ParameterizedType

/**
 * author: Created by shiming on 2018/4/14 15:08
 * mailbox:lamshiming@sina.com
 */
//Mvp 中的V層 超級接口
interface IView<out P:Ipresenter<IView<P>>>{
  val presenter:P
}
//P層的超級接口
interface Ipresenter<out V:IView<Ipresenter<V>>>{
//  @NotNull
//  IView getView();
  val view:V
}

abstract class BaseView<out P:BasePresenter<BaseView<P>>>:IView<P>{
  override val presenter:P

  init {
    presenter= findPresenterClass().newInstance()
    presenter.view=this
  }

  /**
   * 得到相對于的Class的文件
   */
  private fun findPresenterClass():Class<P>{
    //不知道,使用星投影去接收 相當于 Class thisClass = this.getClass();
    var thisClass:Class<*> = this.javaClass
//    while(true) {
//      Type var10000 = thisClass.getGenericSuperclass();
//      if(!(var10000 instanceof ParameterizedType)) {
//        var10000 = null;
//      }
//      ParameterizedType var5 = (ParameterizedType)var10000;
//      if(var5 != null) {
//        Type[] var6 = var5.getActualTypeArguments();
//        if(var6 != null) {
//          var10000 = (Type)ArraysKt.firstOrNull((Object[])var6);
//          if(var10000 != null) {
//            Type var2 = var10000;
//            if(var2 == null) {
//              throw new TypeCastException("null cannot be cast to non-null type java.lang.Class<P>");
//            }
//
//            return (Class)var2;
//          }
//        }
//      }
//    }
    //以下的代碼相當于上面的代碼
    while (true){
      (thisClass.genericSuperclass as? ParameterizedType)
          ?.actualTypeArguments
          ?.firstOrNull()
          ?.let {
            return it as Class<P>
          }?.run{
              thisClass=thisClass.superclass ?:throw IllegalAccessException()
            }
          }
    }

  }


abstract class BasePresenter<out V:IView<BasePresenter<V>>>:Ipresenter<V>{
  //lateinit 延遲初始化
  //@UnsafeVariance 告訴編譯器 我很安全 不要管我
  override lateinit var view:@UnsafeVariance V
}

class MainView:BaseView<MainPresenter>()

class MainPresenter:BasePresenter<MainView>()

class Mvp{
  init {
    MainView().presenter.let(::println)
    //相當于下面的代碼
//    BasePresenter var1 = (new MainView()).getPresenter();
//    System.out.println(var1);
    MainView().presenter.let { println("shiming P="+it) }
    //相當于下面的代碼
//    var1 = (new MainView()).getPresenter();
//    MainPresenter it = (MainPresenter)var1;
//    String var3 = "shiming P=" + it;
//    System.out.println(var3);
//    (new MainPresenter()).getView();

  }
}

輸出的結果是:shiming P=com.kotlin.demo.star_demo.MainPresenter@fc35795

以上是“Kotlin中協變、逆變和不變的示例分析”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業資訊頻道!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

独山县| 镇雄县| 塘沽区| 施甸县| 巴青县| 广水市| 廊坊市| 新安县| 白水县| 菏泽市| 黎平县| 北川| 五台县| 新余市| 定日县| 南汇区| 富民县| 定襄县| 铁岭县| 偏关县| 黔南| 报价| 板桥市| 台南县| 永平县| 象州县| 垦利县| 大连市| 宁陕县| 辉县市| 丰镇市| 雷州市| 额济纳旗| 金阳县| 南京市| 旺苍县| 博野县| 武汉市| 唐海县| 平湖市| 舞钢市|