澳门至尊网站-首页

您的位置:澳门至尊网站 > 免费资源 > 泛型的多种应用

泛型的多种应用

2019-10-19 07:14

本篇小说首要介绍泛型的选拔。

指标与泛型

泛型是.NET Framework 2.0 版类库就早已提供的语法,首要用于抓实代码的可重用性、类型安全性和功用。

目录

  • 1.对象
    1.1 无名类与指标
    1.2 静态类成员与伴生对象
  • 2.泛型
    2.1 型变
    2.2 类型投影
    2.3 泛型函数
    2.4 泛型约束

泛型的定义

1.对象

上面定义了一个普通类和贰个泛型类,我们得以鲜明看见泛型类和平时类最大的分别正是多了二个<T>。

1.1 无名氏类与指标表达式

Java中有无名类那个概念,指的是在成立类时不需求钦赐类的名字。在Kotlin中也许有功效相似的“佚名类”,叫做对象,比方:

Java匿名类

public class Login {

    private String userName;

    public Login(String userName) {
        this.userName = userName;
    }

    public void printlnUserName() {
        System.out.println(userName);
    }
}

public class JavaActivity extends AppCompatActivity {
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        printlnUserName(new Login("Czh") {
            @Override
            public void printlnUserName() {
                super.printlnUserName();
            }
        });
    }

    public void printlnUserName(Login login) {
        login.printlnUserName();
    }
}

Kotlin实现地方的代码,要用关键字object创立三个一而再自有些(或一些)类型的无名类的靶子,如下所示:

class KotlinActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        //object是一个对象,该对象继承自上面的Login
        printlnUserName(object : Login("Czh") {
            override fun printlnUserName() {
            }    
        })
    }

    fun printlnUserName(login: Login) {
        login.printlnUserName()
    }
}

对象object仍为能够兑现接口,如下所示:

//View.OnClickListener是一个interface
button.setOnClickListener(object : View.OnClickListener {
    override fun onClick(v: View?) {
    }
})

对象和类同样,只好有四个父类,但足以兑现三个接口,多个超类型跟在冒号:后边用逗号,分隔。
一旦只想创设一个对象,不继继续留任何类,不贯彻任何接口,能够那样写:

fun foo(){
    val abc = object {
            var a = 1
            var b = 2
    }
    Toast.makeText(this, "${abc.a}${abc.b}", Toast.LENGTH_SHORT).show()
}

运作代码,查看结果:

图片 1

请留意,无名对象足以视作只在地面和个人功能域中声称的体系。即便您利用无名氏对象作为国有函数的回到类型可能作为公有属性的品类,那么该函数或品质的实际上类型会是无名对象注解的超类型,假如你未曾声明任殷亚吉类型,就能够是 Any。在无名氏对象中充分的成员将不能够访谈。如下所示:

class User {
    // 私有函数,所以其返回类型是匿名对象类型
    private fun getUserName() = object {
        val userName = "Czh"
    }

    // 公有函数,所以其返回类型是 Any
    fun getAge() = object {
        val age = 22
    }

    fun get() {
        getUserName().userName
        //getAge().age //编译错误
    }
}
  • 中间类访问成效域内的变量

就如 Java 无名内部类同样,Java能够用final注脚变量,使无名内部类能够选择来源包括它的效用域的变量。如下所示:

final int age = 22;
printlnUserName(new Login() {
    @Override
    public void printlnUserName() {
        //因为age用final声明,所以不能修改
        if (age == 22){
            return;
        }
  }
});

而Kotlin在无名氏对象中得以大肆探问或改造变量age,如下所示:

var age = 22
printlnUserName(object : Login() {
    override fun printlnUserName() {
        age = 23
        Toast.makeText(this@MainActivity, "$age", Toast.LENGTH_SHORT).show()
    }
})

运营代码,查看结果:

图片 2

进而,这么些<T>就标记了,这一个类是泛型类。此中这几个T,也能够写成A,B,C,D或此外字符。

1.2 伴生对象

Java中有静态类成员,而Kotlin中并未有,要促成像静态类成员的作用,将在动用伴生对象。

Java静态分子:

class User {
    static User instance = new User();

    public void printlnUser() {
    }
}
//调用
User.instance.printlnUser()

Kotlin类内部的目的表明能够用 companion 关键字标志:

class User {
    companion object {
        var instance = User()
    }

    fun printlnUser() {
    }
}
//调用
User.instance.printlnUser()

public class Generic
{
    public String Name;
}

public class Generic<T>
{
    public T Name;
}

泛型

泛型,看名就能猜到其意义,正是泛指的体系。好比男人,女生,黄种人,黄人,能够泛称为【人】。

2.1型变

Java泛型

public class Box<T> {
    public T value;

    public Food(T t) {
        value = t;
    }
}

new Box<String>("123");
new Box<Integer>(1);

对应的Kotlin泛型

class Box<T>(t: T) {
    var value = t
}
var box: Box<String> = Box("123")
var box2: Box<Int> = Box(123)

能够看到Java跟Kotlin定义泛型的方式皆以大半的,不一致的是Java中的泛型有通配符,而Kotlin未有。比方:

List<String> strings = new ArrayList<String>();
List<Object> objects = strings;//编译错误

Java编写翻译器不认为List<String>是List<Object>的子类,所以编写翻译不经过。那大家换种写法:

List<String> strings = new ArrayList<String>();
List<Object> objects = new ArrayList<Object>();
objects.addAll(strings);//编译通过

为什么调用addAll()方法就能够编写翻译通过呢,看一下他的源码:

boolean addAll(Collection<? extends E> c);

Java泛型提供了问号?通配符,下边包车型客车<? extends E>代表此办法接受 E 可能 E 的 一些子类型对象的集合。所以能够因而addAll()方法把List<String>赋值给List<Object>。

Kotlin的泛型未有提供通配符,替代它的是outin修饰符。先举个例证:

//用out修饰T
class Box<out T> {
}

图片 3

(浅豆绿波浪线标志处为编写翻译错误)

//用in修饰T
class Box<in T> {
}

图片 4

(中湖蓝波(英文名:lán bō)浪线标志处为编写翻译错误)

相比较上边两段代码能够看看,用out来修饰T,只可以源消开支T类型,不能够回来T类型;
用in来修饰T,只好回到T类型,无法源消开支T类型。轻易的话正是 in 是客商, out 是劳动者。

但品种只好是三个项目。 那么泛型和体系之间是何许关联吧?

2.2 类型投影

上边聊到了outin修饰符,假如我们毫不他们来修饰泛型,会现出这种场馆:

class Box<T> {
}

图片 5

编写翻译不经过,因为Array<T>对于类型T是不可变的,所以Box<Any>和Box<String>什么人也不是哪个人的子类型,所以编写翻译不通过。对于这种情景,大家照旧得以用outin修饰符来搞定,但不是用来修饰Box<T>,如下所示:

fun test(strs: Box<Any>) {
    var objects: Box<in String> = strs
    //编译通过
}

fun test2(strs: Box<String>) {
    var objects: Box<out Any> = strs
    //编译通过
}

上边的减轻方法叫做类型投影,Box<out Any>也正是 Java 的 Box<? extends Object>、博克斯<in String>也便是 Java 的 Box<? super Object>。

实在非常的粗略,泛型在概念的时候,是泛指类型;在采纳的时候,就须求被钦定,到底使用哪个品种。

2.3 泛型函数

不仅仅类能够有项目参数。函数也得以有。类型参数要放在函数名称从前:

fun <T> singletonList(item: T): List<T> {
    // ……
}

//调用
val l = singletonList<Int>(1)
singletonList(l)

就像于Java的泛型方法:

public <T> T singletonList(T item) {
    // ……
}

//调用
singletonList(1);

即,使用时,就不在是泛指类型,而是一定类型。

2.4 泛型约束

泛型约束能够范围泛型参数允许利用的品种,如下所示:

Kotlin代码

fun <T : Comparable<T>> sort(list: List<T>) {
}

sort(1) //编译错误
sort(listOf(1)) //编译通过

上述代码把泛型参数允许使用的系列限制为 List<T>

Java中也会有周边的泛型约束,对应的代码如下:

public static <T extends Comparable> List<T> sort(List<T> list){
}

倘使未有一点名泛型约束,Kotlin的泛型参数暗许类型上界是Any,Java的泛型参数默许类型上界是Object


打比如,定义时,定义了一人。但在运用时,必得领悟内定,到底是白人照旧黄种人。

总结

本篇小说相比较了Java无名类、静态类与Kotlin对象的写法和两种语言中对泛型的采取。相对来说,Kotlin依然在Java的基础上作了一些革新,扩张了一些语法糖,越来越灵敏也更安全。

参考文献:
Kotlin语言中文站、《Kotlin程序开采入门精要》

推荐介绍阅读:
从Java到Kotlin(一)为啥采纳Kotlin
从Java到Kotlin(二)基本语法
从Java到Kotlin(三)类和接口
从Java到Kotlin(五)函数与Lambda表达式
从Java到Kotlin(六)扩充与寄托
从Java到Kotlin(七)反射和注释
从Java到Kotlin(八)Kotlin的其余技艺
Kotlin学习材料集聚


更多美貌小说请扫描下方二维码关心微信民众号"AndroidCzh":这里将长时间为您分享原创小说、Android开拓经历等!
QQ交流群: 705929135

图片 6

泛型的行使

泛型类跟普通类的应用方法相同,都亟需实例化对象,再由对象来调用内部的特性或艺术。

下边代码实例化了泛型Generic,实例化时,还点名了该泛型Generic的钦命项目为String。

因而要给泛型Generic的性质Name赋值,就需求赋值字符串类型的值。

public static void Excute()
{
    Generic<String> gs = new Generic<String>();
    gs.Name = "Kiba518";
}

下边代码定义了叁个Int类型的泛型Generic。

public static void Excute()
{
    Generic<int> gs = new Generic<int>();
    gs.Name = 518;
}

泛型的暗中同意值

泛型的默许值,如下边代码所示。必要采取default(T)来赋值。

任由泛型到底是String,int,bool也许是一个Class类型,都可以被机关赋值。

public static void Excute()
{
    Generic<int> gs = new Generic<int>();
    gs.Name = 518;
    Generic<Task> gsTask = new Generic<Task>();
    gsTask.Name = new Task(()=> {
        Console.WriteLine("Kiba518");
    });
}

public class Generic<T>
{
    public T Name = default(T); 
}

泛型的羁绊

在泛型类中,有个特别的自律可供大家选取。

当大家不出示的注解时,那个约束不设有。但当大家体现的扬言的时候,这些约束就能够实行。

上面,大家来看看这些特意的羁绊。

public static void Excute()
{ 
    Generic<FanXing> gFanXing = new Generic<FanXing>();
    Generic<Base> gFanXingBase = new Generic<Base>();
    //Generic<string> gs = new Generic<string>(); 这样定义会报错
} 
public class Generic<T> where T : Base
{
    public T Name = default(T); 
} 
public class Base  
{
    public string Name { get; set; }
}
public class FanXing : Base
{
    public new string Name { get; set; }
}

如上面代码所示,【where T : Base】正是以此特地的自律。

当呈现注解那些约束的时候,定义会限制泛型的体系。

如何是限量泛型的品类呢?

比很粗略,泛型T,是泛指某二个系列。大家在概念泛型类时,还需出示的内定项目,此时我们体现内定的档案的次序,要受那么些界定。

以此界定就是指【where T : Base】。

它的界定是,供给大家钦点的类型T必需是Base,恐怕该类型承继自Base,如FanXing类。

泛型的函数

在C#中,泛型不只可以够用来类,还是能直接用于函数。

实际应用办法如下:

 public static void Excute()
 {
     GenericFunc gf = new GenericFunc();
     gf.FanXingFunc<FanXing>(new FanXing() { Name="Kiba518"});
 }
 public class GenericFunc
 {
     public void FanXingFunc<T>(T obj)
     {
         Console.WriteLine(obj.GetType());
     }
 }

很轻便,调用泛型函数的时候,钦点泛型函数的[钦命项目]即可。

然则,这里我们发掘三个主题材料,这就是,在泛型函数里,使用泛型对象的时候,大家开掘目的都以object类型的。

那大家只要想使用泛型对象里的质量和章程时,要如何是好吧?

也极粗略,反射就足以了。

上边大家抬高中二年级个反射函数GetPropertyValue,专门用来得到属性。

public class GenericFunc
{
    public void FanXingFunc<T>(T obj)
    { 
        var name = GetPropertyValue(obj, "Name");
        Console.WriteLine(name); 
    }
    public object GetPropertyValue(object obj, string name)
    {
        object drv1 = obj.GetType().GetProperty(name).GetValue(obj, null);
        return drv1;
    }
}

出口结果如下:

图片 7

如此大家就获得了大家想要的结果,如若想行使泛型类里的函数,道理也一律,只供给用反射来调用就能够。

结语

见到此间,有个别同学可能会感到泛型很复杂,连使用其指标下的质量,都得反射,太繁缛了,还比不上不用呢。

有那般主见的同学,心里研讨就好了,倘若对老车手那样说,他迟早会内心默默的微笑,然后对你说,你想的不利。

下一场,你就从未有过然后了。

泛型的接纳,开篇已经说了,主要用在提升代码的可重用性、类型安全性和频率上。

假定只是概念多少个类,调用壹特性质,那泛型的存在正是鸡肋。

但其实,我们的系统永恒独有更复杂,更头晕目眩,更目眩神摇。因而泛型才有了用武之地。

C#语法——委托,架构的血液

C#语法——元组类型

C#语法——await与async的正确性打开药格局


注:此小说为原创,迎接转发,请在篇章页面显著地方给出此文链接!
若您认为那篇小说还不易,请点击下右下角的【推荐】,特别谢谢!

本文由澳门至尊网站发布于免费资源,转载请注明出处:泛型的多种应用

关键词: