zoukankan      html  css  js  c++  java
  • Java 泛型(一) 泛型使用基础

    泛型Generics

      

      所谓泛型,就是变量类型的参数化。

      泛型是JDK1.5中一个最重要的特征。通过引入泛型,我们将获得编译时类型的安全和运行时更小的抛出ClassCastException的可能。

      在JDK1.5中,你可以声明一个集合将接收/返回的对象的类型。

      使用泛型时如果不指明参数类型,即泛型类没有参数化,会提示警告,此时类型为Object。

    为什么使用泛型

      使用泛型的典型例子,是在集合中的泛型使用。

      在使用泛型前,存入集合中的元素可以是任何类型的,当从集合中取出时,所有的元素都是Object类型,需要进行向下的强制类型转换,转换到特定的类型

      比如:

    List myIntList = new LinkedList(); // 1
    
    myIntList.add(new Integer(0)); // 2
    
    Integer x = (Integer) myIntList.iterator().next(); // 3   

      第三行的这个强制类型转换可能会引起运行时的错误。

      泛型的思想就是由程序员指定类型,这样集合就只能容纳该类型的元素。

      使用泛型:

    List<Integer> myIntList = new LinkedList<Integer>(); // 1'
    
    myIntList.add(new Integer(0)); // 2'
    
    Integer x = myIntList.iterator().next(); // 3'

      将第三行的强制类型转换变为了第一行的List类型说明,编译器会为我们检查类型的正确性。这样,代码的可读性和健壮性也会增强。

    泛型使用基础

      例如:

    public interface List <E> 
    {
        void add(E x);
        Iterator<E> iterator();
    }
    
    public interface Iterator<E> 
    {
        E next();
        boolean hasNext();
    }

      尖括号中包含的是形式类型参数formal type parameters),它们就如同一般的类型一样,可以在整个类的声明中被使用。

      当类被使用时,会使用具体的实际类型参数actual type argument代替。

      比如前面的例子中的List<Integer>,那么所有的E将会被Integer类型所代替。

      泛型类型参数只能被类或接口类型赋值,不能被原生数据类型赋值,原生数据类型需要使用对应的包装类。

      形式类型参数的命名:尽量使用单个的大写字母(有时候多个泛型类型时会加上数字,比如T1,T2),比如许多容器集合使用E,代表element(元素),Map中用K代表键keys,V代表值。

    泛型容器的实现讨论

      不能用new的形式来创建一个泛型数组。 

      如下:

    public class SimpleCollection<T>
    {
       private T[] objArr;
       private int index = 0;
    
       public SimpleCollection()
       {
          //Error: Cannot create a generic array of T
          objArr = new T[10];   
       }
    }

      会报错。

      如何创建一个数组让它接受所有可能的类型呢?

    public class SimpleCollection<T>
    {
        private T[] objArr;
        
        private int index = 0;
        public SimpleCollection()
        {
            //Error: Cannot create a generic array of T
            //objArr = new T[10];
            
            //Warning: Unchecked cast from Object[] to T[]
            objArr = (T[]) new Object[10];
            
        }
    
    }

      这个形式虽然可以做到,但是会产生一个警告

      查看ArrayList中的实现,可以发现它是使用了一个Object类型的数组:

    private transient Object[] elementData;

      在取出的时候(get方法中)使用了类型转换:

    (E) elementData[index];

    泛型和子类

    List<String> ls = new ArrayList<String>(); // 1
    
    List<Object> lo = ls; // 2

      一个String类型的List是一个Object类的List吗?

      不可以,Java编译器将会在第二行产生一个编译错误,因为它们的类型不匹配。

      这样就避免了如果lo引入加入Object类型的对象,而ls引用试图将其转换为String类型而引发错误。所以编译器阻止了这种可能。

    继承泛型类别

      直接用例子说明:

      父类:

    public class Parent<T1,T2>
    {
        private T1 foo1;
        private T2 foo2;
        
        public T1 getFoo1()
        {
            return foo1;
        }
        public void setFoo1(T1 foo1)
        {
            this.foo1 = foo1;
        }
        public T2 getFoo2()
        {
            return foo2;
        }
        public void setFoo2(T2 foo2)
        {
            this.foo2 = foo2;
        }    
    
    }

      子类继承父类:

    public class Child<T1, T2, T3> extends Parent<T1, T2>
    {
        private T3 foo3;
    
        public T3 getFoo3()
        {
            return foo3;
        }
    
        public void setFoo3(T3 foo3)
        {
            this.foo3 = foo3;
        }
        
    }

    实现泛型接口

      见例子:

      泛型接口:

    public interface ParentInterface<T1,T2>
    {
        public void setFoo1(T1 foo1);
        public void setFoo2(T2 foo2);
        public T1 getFoo1();
        public T2 getFoo2();
    
    }

      子类实现泛型接口:

    public class ChildClass<T1,T2> implements ParentInterface<T1, T2>
    {
        private T1 foo1;
        private T2 foo2;
        
        @Override
        public void setFoo1(T1 foo1)
        {
            this.foo1 = foo1;
            
        }
        @Override
        public void setFoo2(T2 foo2)
        {
            this.foo2 = foo2;
        }
        @Override
        public T1 getFoo1()
        {
            return this.foo1;
        }
        @Override
        public T2 getFoo2()
        {
            return this.foo2;
        }
    
    }

    参考资料:

      圣思园张龙老师Java SE视频教程。

      The Java Tutorials : Lesson: Generics (Updated)

      http://docs.oracle.com/javase/tutorial/java/generics/index.html

      Lesson: Generics

      http://docs.oracle.com/javase/tutorial/extra/generics/index.html

  • 相关阅读:
    PAT 解题报告 1009. Product of Polynomials (25)
    PAT 解题报告 1007. Maximum Subsequence Sum (25)
    PAT 解题报告 1003. Emergency (25)
    PAT 解题报告 1004. Counting Leaves (30)
    【转】DataSource高级应用
    tomcat下jndi配置
    java中DriverManager跟DataSource获取getConnection有什么不同?
    理解JDBC和JNDI
    JDBC
    Dive into python 实例学python (2) —— 自省,apihelper
  • 原文地址:https://www.cnblogs.com/mengdd/p/2869778.html
Copyright © 2011-2022 走看看