http://www.web008.net

泛型的多种应用

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

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

看见此间,有个别同学可能会认为泛型很复杂,连使用其指标下的属性,都得反射,太繁琐了,还不比不用吗。

对象与泛型

那大家只要想利用泛型对象里的性质和艺术时,要怎么做吧?

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()
}

运作代码,查看结果:

美高梅163888 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()
    }
})

运维代码,查看结果:

美高梅163888 2

很简短,调用泛型函数的时候,钦点泛型函数的[点名项目]即可。

目录

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

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

泛型

怎么是限制泛型的门类呢?

1.对象

public class Generic
{
    public String Name;
}

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

2.2 类型投影

地点聊到了outin修饰符,假使我们不用他们来修饰泛型,会油可是生这种境况:

class Box<T> {
}

美高梅163888 3

编写翻译不经过,因为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>、Box<in String>也就是 Java 的 Box<? super Object>。

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); 
}

1.2 伴生对象

美高梅163888,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 static void Excute()
{
    Generic<String> gs = new Generic<String>();
    gs.Name = "Kiba518";
}

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


下边大家增多叁个反射函数GetPropertyValue,特意用来获得属性。

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

美高梅163888 4

(石青波浪线标志处为编写翻译错误)

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

美高梅163888 5

(浅莲灰波浪线标识处为编写翻译错误)

对待下边两段代码能够看出,用out来修饰T,只好花费T类型,不可能回来T类型;
用in来修饰T,只可以回到T类型,不可能花费T类型。轻便的话正是 in 是花费者, out 是劳动者。

C#语法——await与async的不易展开药格局

总结

本篇小说比较了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

美高梅163888 6

那些限制就是指【where T : Base】。

泛型的概念

下边定义了多少个普通类和多少个泛型类,大家能够明显见到泛型类和平常类最大的界别正是多了一个<T>。

事实上很轻易,泛型在概念的时候,是泛指类型;在应用的时候,就必要被钦赐,到底使用哪个项目。

它的限定是,须要我们内定的类型T必得是Base,只怕该项目承接自Base,如FanXing类。

在C#中,泛型既能够用于类,仍能一直用来函数。

有这么主张的同桌,心里探讨就好了,假若对老鸟那样说,他一定会内心默默的微笑,然后对您说,你想的正确。

结语

所以要给泛型Generic的质量Name赋值,就要求赋值字符串类型的值。

注:此小说为原创,迎接转发,请在小说页面显然地点给出此文链接!
若您认为这篇小说还能够,请点击下右下角的【推荐】,非常感激!

泛型类跟普通类的选用方法同样,都亟需实例化对象,再由对象来调用内部的习性或格局。

泛型的函数

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

好比,定义时,定义了一位。但在动用时,必需明显内定,到底是白种人照旧黄人。

出口结果如下:

泛型的牢笼

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

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

郑重声明:本文版权归美高梅163888所有,转载文章仅为传播更多信息之目的,如作者信息标记有误,请第一时间联系我们修改或删除,多谢。