上一节介绍了泛型类和泛型方法,下面着重介绍泛型接口。
接口:表示纯粹抽象的行为,不能有构造函数和字段,成员是隐式公有的(不能使用修饰符),接口名一般以大写字母 I 开头。
注意:虽然接口不能实例化,但可以声明接口类型的变量并使用实现接口的非抽象类或结构体实例化(抽象类可以使用非抽象子类实例化)。
泛型接口:在接口名后面加上 <T> 声明,也可以在后面添加约束。
1、方法的协变与抗变
协变:方法的参数是基类时,可以使用子类的对象来代替。
抗变:方法的返回值是基类时,不能赋值给子类的引用。
下面给出示例:
public class BaseC
{
}
public class SubC:BaseC
{
}
public class Test
{
public static BaseC GetType(BaseC obj)
{
return null;
}
}
调用方法:
BaseC obj = new SubC();
// 协变:使用子类的实例化对象代替参数
Test.GetType(obj);
// 抗变:返回值是基类类型时不能赋值给子类引用
BaseC obj1 = Test.GetType(new SubC());
2、泛型接口的协变与抗变
协变:使用 out 关键字修饰,形式 :< out T >,类型 T 只能作为接口成员的返回类型,用子类指定的泛型接口对象可以赋值给用基类指定的泛型接口引用。
抗变:使用 in 关键字修饰,形式: < in T >,类型 T 只能用作方法的输入,用基类指定的泛型接口对象可以赋值给用子类指定的泛型接口引用。
下面给出示例:
public class BaseC
{
}
public class SubC:BaseC
{
}
// out 修饰:类型 T 只能用作方法的返回
public interface ITestOut<out T>
{
T GetCurrType();
}
// 用来测试协变
public class TestOut:ITestOut<SubC>
{
public SubC GetCurrType()
{
return new SubC();
}
// 返回该类的一个实例
public static TestOut GetITestOut()
{
return new TestOut();
}
}
// in 修饰:类型 T 只能用作方法的输入
public interface ITestIn<in T>
{
void GetCurrType(T obj);
}
// 用来测试抗变
public class TestIn:ITestIn<BaseC>
{
public void GetCurrType(BaseC obj)
{
}
}
调用示例:
// 1、泛型接口协变:子类指定的对象赋值给基类指定的引用
ITestOut<SubC> subC = TestOut.GetITestOut(); // 该方法得到一个 TestOut 类的实例
ITestOut<BaseC> baseC = subC;
// 2、泛型接口抗变:基类指定的对象赋值给子类指定的引用
ITestIn<BaseC> baseC1 = new TestIn(); // 接口可以用实现他的类的实例去实例化
ITestIn<SubC> subC1 = baseC1;
抽象类和接口的区别: 点击打开链接