【泛型】Generic

参考:

http://blog.csdn.net/lonelyroamer/article/details/7864531#comments

http://blog.csdn.net/lonelyroamer/article/details/7868820#comments

http://blog.csdn.net/LonelyRoamer/article/details/7927212#comments

关于泛型的一些重要知识点

泛型由来:早期Java版本(1.4及之前)如果要代指某个泛化类对象,只能使用Object,这样写出来的代码需要增加强转,而且缺少类型检查,代码缺少健壮性。在1.5之后,Java引入了泛型的概念,提供了一套抽象的类型表示方法。

简单来说,泛型是JDK1.5中出现的安全机制。

好处:将运行时期的ClassCastException问题转到了编译时期,避免了强制转换的麻烦。

什么时候用:当操作的引用数据类型不确定的时候,就使用<>,将要操作的引用数据类型传入即可。

其实<>就是一个用于接收具体引用数据类型的参数范围。

在程序中,只要用到了带有<>的类或者接口,就要明确传入的具体引用数据类型。

泛型技术是给编译器使用的技术,用于编译时期。确保了类型的安全。

运行时,会将泛型去掉,生成的class文件中是不带泛型的,这个称为泛型的擦除。

为什么擦除呢?因为为了兼容运行的类加载器。

泛型的补偿:在运行时,通过获取元素的类型进行转换动作。这样就不用再手动强制转换了。

泛型的通配符【?】未知类型。

泛型的限定:

  • 【? extends E】接收E类型或者E的子类型对象。上限。一般存储对象的时候用。比如 添加元素 addAll。
  • 【? super E】接收E类型或者E的父类型对象。下限。一般取出对象的时候用。比如比较器。

利用泛型,我们可以:

  • 1、表示多个可变类型之间的相互关系:HashMap<T,S>表示类型T与S的映射,HashMap<T, S extends T>表示T的子类与T的映射关系。
  • 2、细化类的能力:ArrayList<T> 可以容纳任何指定类型T的数据,当T代指人,则是人的有序列表,当T代指杯子,则是杯子的有序列表,所有对象个体可以共用相同的操作行为。
  • 3、复杂类型被细分成更多类型:List<People>和List<Cup>是两种不同的类型,这意味着List<People> listP = new ArrayList<Cup>()是不可编译的。这种检查基于编译时而非运行时,所以说是不可编译并非不可运行,因为运行时ArrayList不保留Cup信息。另外要注意,即使People继承自Object,List<Object> listO = new ArrayList<People>()也是不可编译的,应理解为两种不同类型。因为listO可以容纳任意类型,而实例化的People列表只能接收People实例,这会破坏数据类型完整性。

泛型的基本概念

泛型的定义:泛型是JDK 1.5的一项新特性,它的本质是参数化类型 ParameterizedType,即带有类型参数的类型。也就是说所操作的数据类型被指定为一个参数,在用到的时候再指定具体的类型。如:List<T>、Map<Integer, String>、List<? extends Number>。

public interface java.lang.reflect.ParameterizedType extends Type

GenericDeclaration接口是声明类型变量的所有实体的公共接口,也就是说,只有实现了该接口才能在对应的实体上声明类型变量。这些实体目前只有三个:Class、Construstor、Method。当这种参数化类型用在类、接口和方法的创建中时,分别称为泛型类、泛型接口和泛型方法。

注意:因为直接实现子类没有Field类,所以在属性上面不能定义类型变量。

public interface java.lang.reflect.GenericDeclaration
所有已知实现类:Class、Constructor、Method

泛型思想早在C++语言的模板(Templates)中就开始生根发芽,在Java语言处于还没有出现泛型的版本时,只能通过 "Object是所有类型的父类" 和 "类型强制转换" 两个特点的配合来实现类型泛化。例如在哈希表的存取中,JDK 1.5之前使用HashMap的get()方法,返回值就是一个Object对象,由于Java语言里面所有的类型都继承于java.lang.Object,那Object转型为任何对象成都是有可能的。但是也因为有无限的可能性,就只有程序员和运行期的虚拟机才知道这个Object到底是个什么类型的对象。在编译期间,编译器无法检查这个Object的强制转型是否成功,如果仅仅依赖程序员去保障这项操作的正确性,许多ClassCastException的风险就会被转嫁到程序运行期之中。

泛型技术在C#和Java之中的使用方式看似相同,但实现上却有着根本性的分歧,C#里面泛型无论在程序源码中、编译后的IL中(Intermediate Language,中间语言,这时候泛型是一个占位符)或是运行期的CLR中都是切实存在的,比如 List<int> 与 List<String> 就是两个不同的类型,它们在系统运行期生成,有自己的虚方法表和类型数据,这种实现称为类型膨胀,基于这种方法实现的泛型被称为真实泛型。

Java语言中的泛型则不一样,它只在程序源码中存在,在编译后的字节码文件中,就已经被替换为原来的原始类型(Raw Type,也称为裸类型)了,并且在相应的地方插入了强制转型代码,因此对于运行期的Java语言来说,ArrayList<int> 与 ArrayList<String> 就是同一个类型。所以说泛型技术实际上是Java语言的一颗语法糖,Java语言中的泛型实现方法称为类型擦除,基于这种方法实现的泛型被称为伪泛型。

使用泛型机制编写的程序代码要比那些杂乱的使用Object变量,然后再进行强制类型转换的代码具有更好的安全性和可读性。泛型对于集合类来说尤其有用。

泛型程序设计(Generic Programming)意味着编写的代码可以被很多不同类型的对象所重用。

实例分析

在JDK1.5之前,Java泛型程序设计是用继承来实现的。因为Object类是所用类的基类,所以只需要维持一个Object类型的引用即可。就比如ArrayList只维护一个Object引用的数组:

public class ArrayList{
    public Object get(int i){......}
    public void add(Object o){......}
    ......
    private Object[] elementData;
} 

这样会有两个问题:

  • 没有错误检查,可以向数组列表中添加任何类的对象
  • 在取元素的时候,需要进行强制类型转换

这样,很容易发生错误,比如:

/**jdk1.5之前的写法,容易出问题*/
ArrayList arrayList1=new ArrayList();
arrayList1.add(1);
arrayList1.add(1L);
arrayList1.add("asa"); 

int i=(Integer) arrayList1.get(1);//因为不知道取出来的值的类型,类型转换的时候容易出错  

这里的第二个元素是一个长整型,而你以为是整形,所以在强转的时候发生了错误。

所以。在JDK1.5之后,加入了泛型来解决类似的问题。例如在ArrayList中使用泛型:

/** jdk1.5之后加入泛型*/
ArrayList<String> arrayList2=new ArrayList<String>();  //限定数组列表中的类型
//arrayList2.add(1); //因为限定了类型,所以不能添加整形
//arrayList2.add(1L);//因为限定了类型,所以不能添加整长形
arrayList2.add("asa");//只能添加字符串
String str=arrayList2.get(0);//因为知道取出来的值的类型,所以不需要进行强制类型转换  

还要明白的是,泛型特性是向前兼容的。尽管 JDK 5.0 的标准类库中的许多类,比如集合框架,都已经泛型化了,但是使用集合类的现有代码(没有加泛型的代码)可以继续不加修改地在 JDK 1.5 中工作。

泛型的使用

泛型的参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口和泛型方法。下面看看具体是如何定义的。

泛型类:类名后面

泛型类就是在声明类时,定义了一个或多个类型变量的类。

泛型类中定义的类型变量的作用范围为当前泛型类中。

泛型类中定义的类型变量用于,在多个方法签名间实施类型约束。例如,当创建一个 Map<K, V> 类型的对象时,您就在方法之间宣称一个类型约束,您 put() 的值将与 get() 返回的值的类型相同。

public class HashMap<K,V> {
    public V put(K key, V value) {...}
    public V get(Object key) {...}
    ...
}

定义一个泛型类十分简单,只需要在类名后面加上<>,再在里面加上类型参数:

public class Pair<T> {
	private T value;

	public Pair(T value) {
		this.value = value;
	}

	public T getValue() {
		return value;
	}

	public void setValue(T value) {
		this.value = value;
	}
}

现在我们就可以使用这个泛型类了:

public static void main(String[] args) throws ClassNotFoundException {
	Pair<String> pair = new Pair<String>("Hello");//注意,"="号左边和右边都要使用<>指定泛型的实际类型
	String str = pair.getValue();
	pair.setValue("World");
}

泛型类可以有多个类型变量,例如:

class Pair<T, S, P, U, E> { }

注意:类型变量使用大写形式,且比较短,这是很常见的。在Java库中,使用变量E表示集合的元素类型,K和V分别表示关键字与值的类型。需要时还可以用临近的字母U和S表示“任意类型”。

泛型接口

泛型接口和泛型类差不多:

interface Show<T,U>{
    void show(T t,U u);
} 

实现类

public class ShowTest implements Show<String, Date> {
	@Override
	public void show(String t, Date u) {
		System.out.println(t + "  " + u.getTime());
	}

}

测试一下:

Show<String, Date> show = new ShowTest();
show.show("包青天", new Date());

泛型方法:返回值之前

泛型方法就是在声明方法时,定义了一个或多个类型变量的方法。

泛型方法中定义的类型变量的作用范围为当前泛型方法中。

泛型方法中定义的类型变量用于,在该方法的多个参数之间,或在该方法的参数与返回值之间,宣称一个类型约束。

class Person<S> {
	public <W> void show(W w) {//这里的【W】完全等价于Object
		if (w != null) System.out.println(w.toString());
	}

	public static <Y> void staticShow(Y y) {
		if (y != null) System.out.println(y.toString());
		//静态方法不能访问在类声明上定义的类型变量
		//S s;//错误提示:Cannot make a static reference to the non-static type S
	}
}

泛型变量的类型限定

对于上面定义的泛型变量,因为在编译之前,也就是我们还在定义这个泛型方法的时候,我们并不知道这个泛型类型 T 到底是什么类型,所以,只能默认T为原始类型Object,所以它只能调用来自于Object的那几个方法。

如果我们想限定类型的范围,比如必须是某个类的子类,或者某个接口的实现类,这时可以使用类型限定对类型变量T设置限定(bound)来实现。

类型限定在泛型类、泛型接口和泛型方法中都可以使用,不过要注意下面几点:

  • 无限定的泛型变量等价于Object(白哥添加)
  • 不管该限定是类还是接口,统一都使用关键字 extends
  • 可以使用 & 符号给出多个限定
  • 如果限定既有接口也有类,那么类必须只有一个,并且放在首位置

比如:

public static <T extends Comparable> T get(T t1,T t2)  //继承或实现都用extends
public static <T extends Comparable & Serializable> T get(T t1,T t2)  //使用 & 符号给出多个限定
public static <T extends Object & Comparable & Serializable> T get(T t1,T t2)  //继承的类Object必须放在首位

通配符?的使用

通配符有三种:

  • 无限定通配符  形式<?>
  • 上边界限定通配符 形式< ? extends Number>
  • 下边界限定通配符    形式< ? super Number>

1、泛型中的?通配符

如果定义一个方法,该方法用于打印出任意参数化类型的集合中的所有数据,如果这样写

public static void main(String[] args) throws Exception {
	List<Integer> listInteger = new ArrayList<Integer>();
	printCollection(listInteger);//报错 The method printCollection(Collection<Object>) in the type Test is not applicable for the arguments (List<Integer>)
}

public static void printCollection(Collection<Object> collection) {
	for (Object obj : collection) {
		System.out.println(obj);
	}
}

语句printCollection(listInteger);报错,这是因为泛型的参数是不考虑继承关系的,就直接报错。

这就得用?通配符

public static void printCollection(Collection<?> collection) {...}

在方法 printCollection 中不能出现与参数类型有关的方法,比如:

collection.add(new Object());//The method add(capture#1-of ?) in the type Collection<capture#1-of ?> is not applicable for the arguments (Object)

因为程序调用这个方法的时候传入的参数不知道是什么类型的。

但是可以调用与参数类型无关的方法比如 collection.size();

总结:使用?通配符可以引用其他各种参数化的类型,?通配符定义的变量的主要用作引用,可以调用与参数化无关的方法,不能调用与参数化有关的方法。

2、?通配符的扩展:界定通配符的上边界

List<? extends S> x = new ArrayList<T>();

类型S指定一个数据类型,那么类型T就只能是类型S或者是类型S的子类

List<? extends Number> x = new ArrayList<Integer>();//正确
List<? extends Number> y = new ArrayList<Object>();//错误  Type mismatch: cannot convert from ArrayList<Object> to List<? extends Number>

3、?通配符的扩展:界定通配符的下边界

List<? super S> x = new ArrayList<T>();

类型S指定一个数据类型,那么类型T就只能是类型S或者是类型S的父类

List<? super Number> y = new ArrayList<Object>();//正确
List<? super Number> x = new ArrayList<Integer>();//错误  Type mismatch: cannot convert from ArrayList<Integer> to List<? super Number>

提示:限定通配符总是包括自己

类型擦除

前面已经说了,Java的泛型是伪泛型。为什么说Java的泛型是伪泛型呢?因为,在编译期间,所有的泛型信息都会被擦除掉。正确理解泛型概念的首要前提是理解类型擦出(type erasure)。

Java中的泛型基本上都是在编译器这个层次来实现的。在生成的Java字节码中是不包含泛型中的类型信息的。使用泛型的时候加上的类型参数,会在编译器在编译的时候去掉。这个过程就称为类型擦除。

如在代码中定义的List<object>和List<String>等类型,在编译后都会变成List。JVM看到的只是List,而由泛型附加的类型信息对JVM来说是不可见的。Java编译器会在编译时尽可能的发现可能出错的地方,但是仍然无法避免在运行时刻出现类型转换异常的情况。类型擦除也是Java的泛型实现方法与C++模版机制实现方式之间的重要区别。

可以通过两个简单的例子,来证明java泛型的类型擦除。

案例一:

ArrayList<String> list1 = new ArrayList<String>();
ArrayList<Integer> list2 = new ArrayList<Integer>();
System.out.println((list1.getClass() == list2.getClass()) + "  " + (list1.getClass() == ArrayList.class));//true  true

在这个例子中,我们定义了两个ArrayList集合,不过一个是ArrayList<String>泛型类型,只能存储字符串。一个是ArrayList<Integer>泛型类型,只能存储整形。最后,我们通过两个ArrayList对象的getClass方法获取它们的类的信息,最后发现两者相等,且等于ArrayList.class。说明泛型类型String和Integer都被擦除掉了,只剩下了原始类型。

案例二:

List<Integer> list = new ArrayList<Integer>();
list.add(10086);
Method method = list.getClass().getMethod("add", Object.class);
//运行时利用反射机制调用集合的add方法,跳过编译时的泛型检查
method.invoke(list, "虽然集合中对元素限定的泛型是Integer,但是也能通过反射把字符串添加到集合中");
Object object = list.get(1);
System.out.println(object.getClass().getSimpleName() + "  " + (object.getClass() == String.class));//String  true
try {
    System.out.println(((Object) list.get(1)).getClass());//class java.lang.String
    System.out.println(list.get(1).getClass());//如果不指定list.get(1)的类型,则会默认将其强制转换为集合上指定的泛型类型
} catch (Exception e) {
    e.printStackTrace();//java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
}

因为泛型只在编译的时候起作用,在运行的时候,你得ArrayList已经不受泛型的控制了,也就是说跟已经没有泛型限定的ArrayList没有任何区别了。而反射直接获得了add方法的字节码,跳过编译层在运行时直接添加,这样就骗过了编译。

类型擦除后保留的原始类型

在上面,两次提到了原始类型,什么是原始类型?原始类型(raw type)就是擦除去了泛型信息,最后在字节码中的类型变量的真正类型。无论何时定义一个泛型类型,相应的原始类型都会被自动地提供。类型变量被擦除(crased),并使用其限定类型(无限定的变量用Object)替换。

例如:

class Pair<T> {
    private T value;
    public T getValue() {
        return value;
    }
    public void setValue(T  value) {
        this.value = value;
    }
} 

Pair<T>的原始类型为:

class Pair {
    private Object value;
    public Object getValue() {
        return value;
    }
    public void setValue(Object  value) {
        this.value = value;
    }
} 

因为在Pair<T>中,T是一个无限定的类型变量,所以用Object替换。其结果就是一个普通的类,如同泛型加入java编程语言之前已经实现的那样。在程序中可以包含不同类型的Pair,如Pair<String>或Pair<Integer>,但是,擦除类型后它们就成为原始的Pair类型了,原始类型都是Object。

从上面的那个例2中,我们也可以明白ArrayList<Integer>被擦除类型后,原始类型也变成了Object,所以通过反射我们就可以存储字符串了。

如果类型变量有限定,那么原始类型就用第一个边界的类型变量来替换。

比如Pair这样声明:

public class Pair<T extends Comparable& Serializable> { ... } 

那么原始类型就是Comparable

如果Pair这样声明

public class Pair<T extends Serializable & Comparable> 

那么原始类型就用Serializable替换,而编译器在必要的时要向 Comparable 插入强制类型转换。为了提高效率,应该将标签接口(即没有方法的接口)放在边界限定列表的末尾。


要区分原始类型和泛型变量的类型

在调用泛型方法的时候,可以指定泛型,也可以不指定泛型。

  • 在不指定泛型的时候,泛型变量的类型为 该方法中的几种类型的同一个父类的最小级,直到Object。
  • 在指定泛型的时候,该方法中的几种类型必须是该泛型实例类型或者其子类。
public class Test {
	public static void main(String[] args) {
		/**不指定泛型的时候,泛型变量的类型为 该方法中的几种类型的同一个父类的最小级,直到Object*/
		int i = Test.add(1, 2); //这两个参数都是Integer,所以T为Integer类型
		Number f = Test.add(1, 1.2);//这两个参数一个是Integer,一个是Float,所以取同一父类的最小级,为Number
		Object o = Test.add(1, "asd");//这两个参数一个是Integer,一个是Float,所以取同一父类的最小级,为Object

		/**指定泛型的时候,该方法中的几种类型必须是该泛型实例类型或者其子类*/
		int a = Test.<Integer> add(1, 2);//指定了Integer,所以只能为Integer类型或者其子类
		//int b = Test.<Integer> add(1, 2.2);//编译错误,指定了Integer,不能为Float
		Number c = Test.<Number> add(1, 2.2); //指定为Number,所以可以为Integer和Float
	}

	public static <T> T add(T x, T y) {
		return y;
	}
}

其实在泛型类中,不指定泛型的时候也差不多,只不过这个时候的泛型类型为Object,就比如ArrayList中,如果不指定泛型,那么这个ArrayList中可以放任意类型的对象。

附加:GenericDeclaration 接口

public interface java.lang.reflect.GenericDeclaration

所有已知实现类:Class、Constructor、Method

声明类型变量的所有实体的公共接口。

可以声明类型变量的实体的公共接口,也就是说,只有实现了该接口才能在对应的实体上声明(定义)类型变量,这些实体目前只有三个:Class、Construstor、Method。

注意:因为直接实现子类没有Field类,所以属性上面不能定义类型变量。

方法

  • TypeVariable<?>[]  getTypeParameters() 返回声明顺序的 TypeVariable 对象的数组,这些对象表示由此 GenericDeclaration 对象表示的一般声明声明的类型变量。
    • 返回:表示由此一般声明声明的类型变量的 TypeVariable 对象的数组
    • 如果底层的一般声明未声明任何类型变量,则返回一个 0 长度的数组。
public static <T extends Person, U> void main(String[] args) throws Exception {
    Method method = Test.class.getMethod("main", String[].class);
    TypeVariable<?>[] tvs = method.getTypeParameters();//返回声明顺序的 TypeVariable 对象的数组
    System.out.println("声明的类型变量有:" + Arrays.toString(tvs));//[T, U]

    for (int i = 0; i < tvs.length; i++) {
        GenericDeclaration gd = tvs[i].getGenericDeclaration();
        System.out.println("【GenericDeclaration】" + gd);//public static void com.bqt.Test.main(java.lang.String[]) throws java.lang.Exception
        System.out.println(gd.getTypeParameters()[i] == tvs[i]);//true。    GenericDeclaration和TypeVariable两者相互持有对方的引用

        System.out.println(tvs[i] + "  " + tvs[i].getName() + "  " + Arrays.toString(tvs[i].getBounds()));//T  T  [class com.bqt.Person] 和 U  U  [class java.lang.Object]
    }
}

2017-9-4

来自为知笔记(Wiz)

时间: 2024-11-12 21:58:44

【泛型】Generic的相关文章

Java基础之Comparable接口, Collections类,Iterator接口,泛型(Generic)

一.Comparable接口, Collections类 List的常用算法: sort(List); 排序,如果需要对自定义的类进行排序, 那就必须要让其实现Comparable接口, 实现比较两个类大小的方法 shuffle(List); 随机排列 void reverse(List); 逆序排列(Linked效率较高) copy(); 复制集合, 前提是size()相同(长度, 和容量的区别) fill(List, Object);使用某个对象填充整个List binarySearch()

JAVA学习笔记(五十六)- 泛型 Generic Types

泛型 Generic Types import java.util.ArrayList; import java.util.List; /* * 泛型 Generic Types * 集合泛型 * 类泛型 * 方法泛型 */ public class Test01 { public static void main(String[] args) { // 1.集合泛型,保证集合中元素的类型安全 List<Integer> nums = new ArrayList<Integer>(

Java之集合初探(二)Iterator(迭代器),collections,打包/解包(装箱拆箱),泛型(Generic),comparable接口

Iterator(迭代器) 所有实现了Collection接口的容器都有一个iterator方法, 用来返回一个实现了Iterator接口的对象 Iterator对象称作迭代器, 用来方便的实现对容器内的元素的遍历 迭代器是一种设计模式,它是一个对象,它可以遍历并选择序列中的对象,而开发人员不需要了解该序列的底层结构.迭代器通常被称为"轻量级"对象,因为创建它的代价小. Java中的Iterator功能比较简单,并且只能单向移动: (1) 使用方法iterator()要求容器返回一个I

C#泛型(Generic)

一.什么是泛型 泛型(Generic)是C#语言2.0.通用语言运行时(CLR)2.0..NET Framework2.0推出来的新特性. 泛型为.NET框架引入类型参数(Type Parameters)的概念.类型参数使得设计类和方法时,不必确定一个或多个参具体数. 具体的参数类型可延迟到声明和使用时再确定.避免了运行时类型转换或装箱操作的代价和风险. 二.泛型的使用和对比 2.1.CommandMethod(普通方法) 1 /// <summary> 2 /// 打印一个Int值 3 //

泛型 Generic 类型擦除引起的问题及解决方法

参考:http://blog.csdn.net/lonelyroamer/article/details/7868820#comments 因为种种原因,Java不能实现真正的泛型,只能使用类型擦除来实现伪泛型,这样虽然不会有类型膨胀的问题,但是也引起了许多新的问题.所以,Sun对这些问题作出了许多限制,避免我们犯各种错误. 1.先检查,再编译,以及检查编译的对象和引用传递的问题 既然说类型变量会在编译的时候擦除掉,那为什么我们往ArrayList<String> arrayList=new

java 泛型(Generic)

java泛型(generic) 2016-07-11 问题 向集合存储元素存在安全性问题,即很可能不知道已有的集合中已经存储的元素的类型是什么,这时就不应该向该集合随便添加元素,否则与集合的设计的初衷相悖,因为集合存储的是同类型的元素,而且以后取集合中的元素不知道该转为什么类型. 从集合中获取元素需要强制类型转换,可能出现ClassCastException问题 未使用泛型举例: 说明:任何Object子类均可以存入Object集合,但是从集合中获取元素,则是Object对象,需要强制转换,可能

泛型(Generic)

1.定义:一种特殊的变量,保存的是引用变量的类型 2.好处:避免数据类型的转换;将运行时期ClassCastException提前到编译时期 3.自定义带泛型的类:     public class A<泛型名>{ }     注:类中凡是使用到数据类型的地方,都可以使用泛型名代替;         泛型名自定义,但是将来使用者只能传递引用数据类型; 1 代码实现: 2 //自定义泛型类和泛型方法: 3 class A<MM>{ 4 private MM name; 5 priva

1、(知识篇)泛型Generic

泛型的使用: public class Test { public static void main(String[] args) { DoWork<Person> doWork = new DoWork<>(); doWork.doSth(new Person()); DoEat<Man> doEat = new DoEat<>(); doEat.doSth(new Man()); } // 普通类 public static class Person {

Java泛型Generic - Thinking in Java读书笔记

1.什么是泛型? 泛型就是可适用于很多的类,它实现了参数化类型type parameter的概念,参数化类型指可使用多种类型. 多态是一种泛化机制. 例如方法 A(Base b){}//Base是一个基类 这样方法A就可以接受从这个基类Base的任何子类作为参数.方法的参数也可以是一个接口,但是由于类的单继承体系和接口的约束( An interface still requires that your code works with that particular interface. ),不能

1.泛型(Generic)

一.泛型 泛型就是封装,将重复的工作简单化 1.泛型方法 public static void Show<T>(T tParameter) { Console.WriteLine("This is {0}, parameter = {1}, type = {2}", typeof(CommonMethod).Name, tParameter.GetType(), tParameter); } 2.泛型类 public class GenericClass<T>{