黑马程序员技术交流社区

标题: 为什么用泛型的限定(一) [打印本页]

作者: x378320002    时间: 2013-6-10 22:56
标题: 为什么用泛型的限定(一)
本帖最后由 x378320002 于 2013-6-13 10:32 编辑

泛型通配符是,可以接受任一定义的引用参数类型,但是我们如果并不想使我么定义的方法接受所有的引用数据类型,
而是接受某一部分类型怎么办呢,此时我们就可以对泛型的进行限定,使我们定义的函数或类更加安全。

例如我们定义如下两个集合,a1a2(此处我们设定studentperson的子类)
       public static void main(String[] args) {

ArrayList<Person> a1 = new ArrayList<Person>();

a1.add(new Person("person1",3));
a1.add(new Person("person2",4));

ArrayList<Student> a2 = new ArrayList<Student>();

a2.add(new Student("stu1",1));
a2.add(new Student("stu2",2));
}
如果我们要定义一个方法(且不论这个方法是做什么的),既能接收a1又能接受a2,那么首先我们就会想到泛型通配符
那就就应该这么定义
public static void printCollection(Collection<?> al) {}    //此方法主函数调用时即可接受a1又可a2,

但是有时我们定义的方法要实现的功能又可能是在某一个特定的对象内的功能,例如我们定义的方法要用上面集合
person类内的特有方法getName()方法,那么此时我们就必须对这个函数接受的内容加以限定,否则就会变的
不再安全,因为这个public static void printCollection(Collection<?> al) {} 函数是什么类型内容的集合都可以接收,
如下面一个集合a3存的是字符串,它一样可以接收,但显然字符串里没有getName()方法,我们的程序会出错。
ArrayList<String> a3 = new ArrayList<String>();
a3.add("aaaa");
a3.add("bbbb");
这里我们对函数泛型类型加以限定就派上了用场,限定只接受person类或是其子类的对象集合,因为它们才有getName()
方法,才是我们要操作的对象,可以这么限定
public static void printCollection(Collection<? extends Person>   c){  }
此处的<? extends Person>即泛型的上限,只可接受personperson的子类,再往里传a3的值已经不行,编译就通不过。
还有<? super E>即泛型的下限,只可接受E或者E的父类,也是对函数的接受类型加以的限定,这就是泛型限定的来源,
以及为什么用泛型的限定。


作者: j816326    时间: 2013-6-11 00:04
可以通过反射来突破泛型的限制。通过反射获取构造方法,用反射获取的成员方法完成功能。
泛型就是把运行期间可能会出现的异常,提前到编译期间解决。比喻你你需要person对象,但你传入的是student对象,在编译期间可以通过。但是运行就会出现异常了。类型不匹配。
作者: 月时微    时间: 2013-6-18 13:36
1、泛型的类型参数只能是类类型(包括自定义类),不能是简单类型。
2、同一种泛型可以对应多个版本(因为参数类型是不确定的),不同版本的泛型类实例是不兼容的。
3、泛型的类型参数可以有多个。
4、泛型的参数类型可以使用extends语句,例如<T extends superclass>。习惯上称为“有界类型”。
5、泛型的参数类型还可以是通配符类型。例如Class<?> classType = Class.forName("java.lang.String");
泛型还有接口、方法等等,内容很多,需要花费一番功夫才能理解掌握并熟练应用。在此给出我曾经了解泛型时候写出的两个例子(根据看的印象写的),实现同样的功能,一个使用了泛型,一个没有使用,通过对比,可以很快学会泛型的应用,学会这个基本上学会了泛型70%的内容。
例子一:使用了泛型
class Gen<T> {
private T ob; //定义泛型成员变量
public Gen(T ob) {
this.ob = ob;
}
public T getOb() {
return ob;
}
public void setOb(T ob) {
this.ob = ob;
}
public void showType() {
System.out.println("T的实际类型是: " + ob.getClass().getName());
}
}
public class GenDemo {
public static void main(String[] args){
//定义泛型类Gen的一个Integer版本
Gen<Integer> intOb=new Gen<Integer>(88);
intOb.showType();
int i= intOb.getOb();
System.out.println("value= " + i);
System.out.println("----------------------------------");
//定义泛型类Gen的一个String版本
Gen<String> strOb=new Gen<String>("Hello Gen!");
strOb.showType();
String s=strOb.getOb();
System.out.println("value= " + s);
}
}
例子二:没有使用泛型
class Gen2 {
private Object ob; //定义一个通用类型成员
public Gen2(Object ob) {
this.ob = ob;
}
public Object getOb() {
return ob;
}
public void setOb(Object ob) {
this.ob = ob;
}
public void showTyep() {
System.out.println("T的实际类型是: " + ob.getClass().getName());
}
}
public class GenDemo2 {
public static void main(String[] args) {
//定义类Gen2的一个Integer版本
Gen2 intOb = new Gen2(new Integer(88));
intOb.showTyep();
int i = (Integer) intOb.getOb();
System.out.println("value= " + i);
System.out.println("---------------------------------");
//定义类Gen2的一个String版本
Gen2 strOb = new Gen2("Hello Gen!");
strOb.showTyep();
String s = (String) strOb.getOb();
System.out.println("value= " + s);
}
}
运行结果:
两个例子运行Demo结果是相同的,控制台输出结果如下:
T的实际类型是:
java.lang.Integer
value= 88
----------------------------------
T的实际类型是: java.lang.String
value= Hello Gen!
Process finished with exit code 0
看明白这个,以后基本的泛型应用和代码阅读就不成问题了。





欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2