泛型

分类:泛型类、泛型接口、泛型方法

  注意:1.泛型中T不能为简单类型

     2.不能对确切的泛型类型使用instanceof操作  -----》if(ex_num instanceof Generic){ }   //编译报错

   =============================================================================

  泛型接口:

    public interface Generator{

      public T next();

    }

    实现类的两种情况:

      a.实现类中接口未传入实参   

    /**
     * 未传入泛型实参时,与泛型类的定义相同,在声明类的时候,需将泛型的声明也一起加到类中
     * 即:class FruitGenerator implements Generator{
     * 如果不声明泛型,如:class FruitGenerator implements Generator,编译器会报错:"Unknown class"
     */
class FruitGenerator implements Generator{
            @Override
            public T next() {
               return null;
            }
          }

      b.当实现类中接口传入泛型实参
      /**
       * 传入泛型实参时:
       * 定义一个生产器实现这个接口,虽然我们只创建了一个泛型接口Generator
       * 但是我们可以为T传入无数个实参,形成无数种类型的Generator接口。
       * 在实现类实现泛型接口时,如已将泛型类型传入实参类型,则所有使用泛型的地方都要替换成传入的实参类型
       * 即:Generator,public T next();中的的T都要替换成传入的String类型。
       */      
       public class FruitGenerator implements Generator {
          private String[] fruits = new String[]{"Apple", "Banana", "Pear"};

          @Override
          public String next() {
             Random rand = new Random();
             return fruits[rand.nextInt(3)];
          }
       }
   =============================================================================
通配符:
    问题:用于解决T之间存在继承关系的场景
    例子:Generic Generic Integer的父类是Number,但是Generic在作为参数时不能将Generic作为实参传入
    解决方案:使用通配符 ?
     ************注意: 此处’?’是类型实参,而不是类型形参
************
     ************此处的?和Number、String、Integer一样都是一种实际的类型,可以把?看成所有类型的父类。是一种真实的类型。************
  =============================================================================   
泛型方法:
   调用时机:泛型类,是在实例化类的时候指明泛型的具体类型;泛型方法,是在调用方法的时候指明泛型的具体类型。
   泛型特点:在public/private 后加/,参数可以是无数多个,表明是泛型方法,否则是普通方法。
      public  T genericMethod(Class tClass)throws InstantiationException ,IllegalAccessException{
            T instance = tClass.newInstance();
            return instance;
      }
    Object obj = genericMethod(Class.forName("com.test.test"));

   //这不是一个泛型方法,这也是一个普通的方法,只不过使用了泛型通配符?
//同时这也印证了泛型通配符章节所描述的,?是一种类型实参,可以看做为Number等所有类的父类
  public void showKeyValue2(Generic obj){
   Log.d("泛型测试","key value is " + obj.getKey());
  }
    //泛型方法与可变参数
    public void printMsg( T... args){
    for(T t : args){
     Log.d("泛型测试","t is " + t);
     }
    }
=============================================================================
 静态方法与泛型
   //静态方法可以声明为泛型方法,
    public static void show(T t){
  }
   //静态方法如果不是泛型方法,方法内不能有泛型参数T ---> 所以如果static方法要使用泛型能力,就必须使其成为泛型方法。
    例如:
public static void show(T t){..} 此时编译器会提示错误信息:"StaticGenerator cannot be refrenced from static context"
=============================================================================
 泛型上下边界
    例如:类型实参只准传入某种类型的父类或某种类型的子类。为泛型添加上边界,即传入的类型实参必须是指定类型的子类型
    public void showKeyValue1(Genericextends Number> obj){
        Log.d("泛型测试","key value is " + obj.getKey());
    }
    Generic generic1 = new Generic("11111");
    Generic generic2 = new Generic(2222);

    //showKeyValue1(generic1); //这一行代码编译器会提示错误,因为String类型并不是Number类型的子类
    showKeyValue1(generic2);

 
//在泛型方法中添加上下边界限制的时候,必须在权限声明与返回值之间的上添加上下边界,即在泛型声明的时候添加
   //public  T showKeyName(Generic container),编译器会报错:"Unexpected bound"
    public extends Number> T showKeyName(Generic container){
        System.out.println("container key :" + container.getKey());
        T test = container.getKey();
        return test;
    }
=============================================================================

    泛型数组:

 
 

         在java中是”不能创建一个确切的泛型类型的数组”的。

 
 
    List[] ls = new ArrayList[10];  //编译异常  Not really allowed
    List[] ls = new ArrayList[10]; //使用通配符创建泛型数组是可以的
    List[] ls = new ArrayList[10];   //这样也可以
    List[] lsa = new List[10]; // Not really allowed.    
    Object o = lsa;    
    Object[] oa = (Object[]) o;    
    List li = new ArrayList();    
    li.add(new Integer(3));    
    oa[1] = li; // Unsound, but passes run time store check    
    String s = lsa[1].get(0); // Run-time error: ClassCastException.

    这种情况下,由于JVM泛型的擦除机制,在运行时JVM是不知道泛型信息的,所以可以给oa[1]赋上一个ArrayList而不会出现异常,     但是在取出数据的时候却要做一次类型转换,所以就会出现ClassCastException,如果可以进行泛型数组的声明,     上面说的这种情况在编译期将不会出现任何的警告和错误,只有在运行时才会出错。     而对泛型数组的声明进行限制,对于这样的情况,可以在编译期提示代码有类型安全问题,比没有任何提示要强很多。


    下面采用通配符的方式是被允许的:数组的类型不可以是类型变量,除非是采用通配符的方式,因为对于通配符的方式,最后取出数据是要做显式的类型转换的。

    List[] lsa = new List[10]; // OK, array of unbounded wildcard type.     Object o = lsa;     Object[] oa = (Object[]) o;     List li = new ArrayList();     li.add(new Integer(3));     oa[1] = li; // Correct.     Integer i = (Integer) lsa[1].get(0); // OK


你可能感兴趣的:(泛型)