C#语法——泛型的各类用到

作者:编程技术

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

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

图片 1

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

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

图片 2

(红棕波浪线标识处为编写翻译错误)

相对来说下面两段代码能够看出,用out来修饰T,只可以花费T类型,不能够重临T类型;
用in来修饰T,只好回到T类型,不能够源消花费T类型。简单的话就是 in 是开支者, out 是生产者。

default关键字

上边定义了三个普通类和二个泛型类,大家得以分明看见泛型类和平常性类最大的分别正是多了二个<T>。

目录

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

类企图好通晓后,我们得以起来定义我们的泛型了:

泛型,以偏概全,正是泛指的项目。好比匹夫,女人,白人,黄人,能够泛称为【人】。

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

运行代码,查看结果:

图片 3

请留意,佚名对象能够用作只在地头和村办效能域中宣称的花色。假诺您采用无名对象作为国有函数的回到类型或然当做公有属性的连串,那么该函数或性质的骨子里类型会是无名对象申明的超类型,借使您未有注解任关昊类型,就能是 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在无名氏对象中能够Infiniti制会见或涂退换量age,如下所示:

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

运作代码,查看结果:

图片 4

T可以是轻巧的标示符,只要服从命名法规就能够。

无论是泛型到底是String,int,bool大概是一个Class类型,都能够被自动赋值。

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);
#region Animal 虚基类 有一个name属性 Feed方法和一个虚方法MakeANoise
    //虚基类 有一个name属性 Feed方法和一个虚方法MakeANoise
    public abstract class Animal
    {
        protected string name;

        public string Name
        {
            get
            {
                return name;
            }
            set
            {
                name = value;
            }
        }

        public Animal()
        {
            name = "The animal with no name";
        }

        public Animal(string newName)
        {
            name = newName;
        }

        public void Feed()
        {
            Console.WriteLine("{0} has been fed.", name);
        }

        public abstract void MakeANoise();
    }
    #endregion

//Cow Animal的子类,实现虚方法
    public class Cow:Animal
    {
        public Cow(string name) :
            base(name)
        {
        }
        public override void MakeANoise()
        {
            Console.WriteLine("{0} says 'moo!'", name);
        }
    }

//Chicken类,Animal子类
    public class Chicken:Animal
    {
        public Chicken(string name)
            : base(name)
        { }
        public override void MakeANoise()
        {
            Console.WriteLine("{0} says 'cluck'", name);
        }
    }

//Cow的子类,有一个自己的方法Fly
    class SuperCow : Cow
    {
        public SuperCow(string name) : base(name) 
        {
        }

        public void Fly()
        {
            Console.WriteLine("{0} is flying!", name);
        }

        public override void MakeANoise()
        {
            Console.WriteLine("{0} says 'I am supercow!'", name);
        }

    }

而是,这里大家开掘三个标题,那就是,在泛型函数里,使用泛型对象的时候,大家发掘指标都是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

图片 5

上面给出一些可用的自律

泛型的函数

2.2 类型投影

上边说起了outin修饰符,如果我们决不他们来修饰泛型,晤面世这种景观:

class Box<T> {
}

图片 6

编译不经过,因为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
    //编译通过
}

上边的缓和格局叫做类型投影,博克斯<out Any>约等于 Java 的 Box<? extends Object>、Box<in String>也等于 Java 的 Box<? super Object>。

                                where T:interface                                  内定类型T必需兑现是接口也许完成了接口

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

对象与泛型

                                        约束                                                                  说明

当展现注明这一个约束的时候,定义会限制泛型的类型。

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


class MyGenericClass<T1, T2> where T1 : constraint1 where T2 : constraint
{
    ...
}

就此,那个<T>就标记了,那些类是泛型类。在那之中这一个T,也能够写成A,B,C,D或其余字符。

泛型

public MyGenericClass()
{
    t1Object = default(T1);
}

以此限制就是指【where T : Base】。

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

能够把项目用在类成员的回到类型,方法参数类型等,例如:

很轻便,泛型T,是泛指某一个类型。大家在概念泛型类时,还需出示的钦点项目,此时我们来得内定的体系,要受这几个范围。

class MyGenericClass<T1, T2, T3>
{
    private T1 t1Object;

    public MyGenericClass(T1 item)
    {
        t1Object = item;
    }

    public T1 T1Object
    {
        get
        {
            return t1Object;
        }
    }
}
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;
    }
}
System.Nullable<int> nullableInt;

上面代码定义了多个Int类型的泛型Generic。

class Program
    {
        static void Main(string[] args)
        {
            Farm<Animal> farm = new Farm<Animal>();
            farm.Animals.Add(new Cow("Jack"));
            farm.Animals.Add(new Chicken("Vera"));
            farm.Animals.Add(new Chicken("Sally"));
            farm.Animals.Add(new SuperCow("Kevin"));
            farm.MakeNoises();

            Farm<Cow> dairyFarm = farm.GetCows();
            dairyFarm.FeedTheAnimals();

            foreach (Cow cow in dairyFarm)
            {
                if (cow is SuperCow)
                {
                    (cow as SuperCow).Fly();
                }
            }
            Console.ReadKey();
        }
    }

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

下边结合以上文化给个实例:(PS不要看到代码多 其实非常的粗略的 耐心看下去

实则相当粗略,泛型在概念的时候,是泛指类型;在选取的时候,就须要被钦赐,到底使用哪个项目。

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

因为大家不知情T1是不是有国有的暗中同意构造函数。

如下边代码所示,【where T : Base】就是其一极其的自律。

constraint定义了自律,多少个约束用逗号隔绝,假设有两个连串:

但骨子里,大家的种类恒久独有更复杂,更目眩神摇,更目迷五色。因而泛型才有了用武之地。

设若是值类型就赋值0,引用类型就赋值null。

什么是限量泛型的品种呢?

 

这我们如若想利用泛型对象里的性质和方法时,要怎么做吧?

泛型定义好了,我们用写代码来调用它:

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

倘诺我们定义了一个泛型的字段,我们想在构造函数中开端化它,可是大家不亮堂它的援引类型恐怕值类型,那么default就派上用场了:

泛型类跟普通类的应用形式同样,都急需实例化对象,再由对象来调用内部的个性或方法。

                                where T:base-class                               钦点类型T必需是基类大概派生于基类

泛型是.NET Framework 2.0 版类库就已经提供的语法,主要用来进步代码的可重用性、类型安全性和功用。

                               where T:new()                                       钦点类型T必得有贰个私下认可构造函数

但品种只可以是叁个品种。 那么泛型和体系之间是如何关联吗?

                                where T:calss                                       类约束钦点,类型T必需是引用类型

它的范围是,需要大家钦赐的类型T必得是Base,可能该项目承继自Base,如FanXing类。

在.NET中泛型使用十三分频繁,在调控台应用程序中,暗中同意的引入了System.Collection.Generics名称空间,在那之中就提供了我们经常选用的泛型:List<T>和Dictionary<T>,相信用过它们的都明白它们的强盛。还会有一种大家平日使用的简便的泛型:System.Nullable<T>,就能够空类型。大家能够:

泛型的暗中认可值

下边重点介绍一下怎么样自定义泛型。

下边,大家来寻访这一个极度的羁绊。

声称二个可空的int类型,由于C#语法对那么些做了简化平日大家都不那样写,而是那样写:

输出结果如下:

 

泛型的定义

//继承了迭代器接口,这样方便使用Foreach 约束它的类型为Animal及其子类
    public class Farm<T>:IEnumerable<T> where T : Animal
    {
        private List<T> animals = new List<T>();

        public List<T> Animals
        {
            get 
            {
                return animals;    
            }
        }
        //迭代器
        public IEnumerator<T> GetEnumerator()
        {
            return animals.GetEnumerator();
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return animals.GetEnumerator();
        }

        //执行所有animal的MakeANoise()
        public void MakeNoises()
        {
            foreach (T animal in animals)
            {
                animal.MakeANoise();
            }
        }
        //执行所有animal的Feed()
        public void FeedTheAnimals()
        {
            foreach (T animal in animals)
            {
                animal.Feed();
            }
        }
        //获得animals中的cow
        public Farm<Cow> GetCows()
        {
            Farm<Cow> cowFarm = new Farm<Cow>();
            foreach (T animal in animals)
            {
                if (animal is Cow)
                {
                    cowFarm.Animals.Add(animal as Cow);
                }
            }
            return cowFarm;
        }
    }

泛型的施用,开篇已经说了,首要用在进步代码的可重用性、类型安全性和效能上。

概念泛型类

切切实进行使办法如下:

自律类型

非常粗略,调用泛型函数的时候,钦点泛型函数的[钦点项目]即可。

创设泛型类是须要在类定义中用尖括号语法:

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

先定义多个类Animal、Cow 、Chicken和SuperCow

泛型的封锁

class MyGenericClass<T1> where T : constraint1,constraint
{
    ...
}
 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());
     }
 }

图片 7

C#语法——元组类型

在概念泛型的时候大家能够对品种举行封锁,通过where关键字贯彻:

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

                                                         ——Stay hungry!Stay foolish!

这么大家就猎取了我们想要的结果,假设想利用泛型类里的函数,道理也一致,只供给用反射来调用就能够。

 

public class Generic
{
    public String Name;
}

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

与上述同类多个泛型就OK了。


                                where T:struct                                     使用结构约束,类型T必需是值类型

泛型的默许值,如下边代码所示。须求采纳default(T)来赋值。

 

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

class MyGenericClass<T1, T2, T3>
{
    private T1 t1Object;

    public MyGenericClass()
    {
        t1Object = new T1();
    }
}

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

结果:

本篇文章首要介绍泛型的使用。

int? nullableInt

若是只是概念贰个类,调用壹性子格,那泛型的存在就是鸡肋。

 

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

结语

泛型的利用

当大家不展现的宣示时,这一个约束子虚乌有。但当我们展现的宣示的时候,那个约束就能够实行。

也很粗大略,反射就可以了。

举个例子,定义时,定义了一位。但在动用时,必需明确钦命,到底是黄人照旧白种人。

在泛型类中,有个特地的束缚可供大家利用。

下边大家加多叁个反射函数GetPropertyValue,特意用来博取属性。

所以要给泛型Generic的习性Name赋值,就需求赋值字符串类型的值。

C#语法——await与async的科学张开形式

有诸有此类想方设法的同窗,心里商量就好了,借使对老驾车员那样说,他一定会内心默默的微笑,然后对你说,你想的正确。

图片 8

本文由分分快三计划发布,转载请注明来源

关键词: 分分快三计划 日记本 Kotlin .NET基础 C#泛型