Java那些事:泛型(二)

2014-11-23 23:26:23 · 作者: · 浏览: 2
umer),则使用 。这一点对于设计出优秀强大的泛型代码是一个不错的原则!

这里需要说明一下任意通配符---- ,初看起来好像 和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