这里需要说明一下任意通配符---- ,初看起来好像 和Object的区别不大(实际情况也是会被擦除为Object),但是如果你List ,那么将不可以插入任何值(除了null,但是这个没有什么意义)。这里的 是告诉编译器,我不知道将会接受什么类型,但是请使用Java泛型机制来处理它!但是,实际上有多大,只有合适的情况才能发挥它的才能了。
与之相关的便是----类型捕获,参考下面的代码:
//这里是有任意通配符,函数调用后随即捕获了?的类型信息
publicstatic void swap(List
list,int i,int j){
swapHelper(list,i, j);
}
//这里在由于helper知道E的类型,所以可以列表时安全的
privatestatic
void swapHelper(List
list,int i,int j){ list.set(i,list.set(j, list.get(i))); }
Java通配符确实对Java的泛型的强壮起到了十分关键的作用,如何优雅的使用通配符,除了牢记上面的PECS原则,更加需要经验和眼光!
5.其他的一些忠告
1.不要再新代码中使用原生类型
Java就是为了兼容才将泛型做成目前的状况,以后也不会再出现使用原生类型的代 码,最最重要的是:Java的泛型出现的一点原因是消除原生态可能产生的 ClassCastException异常,实现安全,如果你使用了原生,你就浪费了Java对你的一片心 意。
但是有些地方必须使用原生类型:
1.类文字
2.静态方法或者域的使用
2.消除警告
Java对你的代码进行警告,表示这个代码是有可能出现问题,代码中警告越多,出现问题的可能性越大,想到解决警告的办法是最好,如果无法消除,那么可以使用注解@SuppressWarnings来消除,但是必须在那里证明自己消除的警告是类型安全的,是实际不会出现问题的。
对于@SuppressWarnings应该在尽可能小的范围内使用,千万别误将范围扩大而消 除了本来十分危险的警告。另外需要注意的一点:@SuppressWarnings是不能被注解在 return语句之上的。
3.类表有限于数组
数组是在运行时确定信息,更容易出现问题,相对于类型安全的列表来说,有时候 牺牲一点性能而换来更多的安全和方便也是一个不错的选择。
4.优先考虑泛型
泛型代码的好处之一就是模板,代码可复用,这正是设计者们所追求的,但是只有在有充分的理由(代码能够跨越多个类进行工作时)来使用泛型,否则不要使用泛型! 相对于泛型类,优先使用泛型方法则显得更加的灵活。
5.优先考虑类型安全的异构容器
核心思想就是:将键(key)参数化而不是将容器参数化。
如下代码实现Map存放不同的key类型
publicclass Eight {
publicstatic void main(String[] args) {
YiGouRongQiy = new YiGouRongQi();
y.put(String.class,"leon");
y.put(Integer.class,20);
System.out.println(y.get(String.class)+ " is " + y.get(Integer.class) + " years old!");
}
}
class YiGouRongQi{
privateMap
,Object> hm = new HashMap<>();
public
boolean put(Class
type,T instance){ if(type== null){ System.out.println("空指针异常"); returnfalse; } elseif(hm.containsKey(type)){ System.out.println("已经存在了键"); returnfalse; } hm.put(type,instance); returntrue; } // @SuppressWarnings("unchecked") public
T get(Class
type){ //返回语句不能加注解 // return(T)hm.get(type); returntype.cast(hm.get(type)); } }
集合API说明了泛型的一般应发,限制你每个容器只能有固定数目的类型参数。这 里展示了你可以将类型参数放在键上而不是容器上来避开这一限制。对于这种类型安全的异构容器,你可以使用Class对象作为键。
6.泛型的反思
经常提起Java泛型,人们大多数时候总是在提它的诟病,暂且搁置开Java的历史原因,说说到底什么是泛型。就像C++中泛型又被称为模板,是的,泛型是对普通方法更加泛化的实现,这种泛型类是适用于所有类或者部分类,一般情况下是使用与部分类。对这些类会存在某些限制,而泛型类并不关心类的具体类型是什么,而在乎它是否可以执行某个方法!
这便是“潜在的类型机制”。所以,一般泛型类会要求参数类型实现了某个方法或者存在某个方法,使用实现接口或者反射式完全可以反映泛型的特点,也就是说实现“类型潜在机制”。泛型,泛型,其内部本来就不应该保存类的具体信息,因为一旦是针对某个具体类进行泛型类的编写,那么这个泛型类就完全没有必要写出泛型类。所以说,虽然Java泛型机制给开发者带来了诸多的不便,比较遗憾的一点是没有支持泛型数组,但是反过来看,擦除内部参数类型信息,利用接口和反射实现潜在类型机制,到也不失为一种还算优雅的方式。
简单代码如下:
public class Four {
publicstatic void main(String[] args) {
//客户类,调用泛型方法,传入实现规定接口的类
GenericTest.doIt(newTestClass());
System.out.println("------------------------------");
GenericTest.doIt(newTestClass2());
}
}
interface testInterface {
/**
* 这个接口规定了需要做什么事情
*/
publicvoid doSomething();
}
/**
* 以下两个类是使用了接口的特点,针对接口进行编程 要实现泛型的潜在类型机制----“我不关心这里使用的类型,只要它具有这些方法即可”
* 也可以使用反射进行实现,不需要依赖接口的方式
*@author leon
*
*/
class TestClass implements testInterface {
@Override
publicvoid doSomething() {
System.out.println("I'mLeon,I'll do some thing here!");
}
}
class TestClass2 implements testInterface {
@Override
publicvoid doSomething() {
System.out.println("I'mDiana,I'll do other thing here!");
}
}
cla