java泛型的理解

最近在看视频,看到比较经典的比大小问题。输入两个数,返回大的数,类型可以为int,long,float等。

通常的教程中用这个例子引入了构造函数以及重载的概念,在学习完泛型后,我想到能不能写一个泛型的方法,用以实现比较。

为了完成这个任务,我们首先需要了解一下泛型。

什么的泛型

泛型是java语言系统的一种扩展,支持创建可以按照类型进行参数化的类。

泛型的好处

泛型的好处也是显而易见的,

首先可以扩充代码的通用性,通过泛型可以使方法支持更多的类型。

泛型有助于增强类型安全,编译器可以对类型进行比较准确的解读。

泛型有助于减少类型强制转换,减少出错机会。

我们需要掌握泛型哪些用法

需要掌握泛型接口、泛型类、泛型类中泛型方法、非泛型类中泛型方法、类型通配符、类型通配符的上下限这几个用法。

泛型接口

泛型接口的一个比较好的例子是java.util.List.class,<E>中的E为类型形参,可以接收具体类型的实参。接口中出现E的地方,均为接收到的具体类型的实参。

package java.util;

public abstract interface List<E> extends Collection<E>
{
  public abstract int size();

  public abstract boolean isEmpty();

  public abstract boolean contains(Object paramObject);

  public abstract Iterator<E> iterator();

  public abstract Object[] toArray();

  public abstract <T> T[] toArray(T[] paramArrayOfT);

  public abstract boolean add(E paramE);

  public abstract boolean remove(Object paramObject);

  public abstract boolean containsAll(Collection<?> paramCollection);

  public abstract boolean addAll(Collection<? extends E> paramCollection);

  public abstract boolean addAll(int paramInt, Collection<? extends E> paramCollection);

  public abstract boolean removeAll(Collection<?> paramCollection);

  public abstract boolean retainAll(Collection<?> paramCollection);

  public abstract void clear();

  public abstract boolean equals(Object paramObject);

  public abstract int hashCode();

  public abstract E get(int paramInt);

  public abstract E set(int paramInt, E paramE);

  public abstract void add(int paramInt, E paramE);

  public abstract E remove(int paramInt);

  public abstract int indexOf(Object paramObject);

  public abstract int lastIndexOf(Object paramObject);

  public abstract ListIterator<E> listIterator();

  public abstract ListIterator<E> listIterator(int paramInt);

  public abstract List<E> subList(int paramInt1, int paramInt2);
}

泛型类

泛型类的定义方法类似于接口

public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
    private static final long serialVersionUID = 8683452581122892189L;

    /**
     * The array buffer into which the elements of the ArrayList are stored.
     * The capacity of the ArrayList is the length of this array buffer.
     */
    private transient Object[] elementData;

    public ArrayList(Collection<? extends E> c) {
    elementData = c.toArray();
    size = elementData.length;
    // c.toArray might (incorrectly) not return Object[] (see 6260652)
    if (elementData.getClass() != Object[].class)
        elementData = Arrays.copyOf(elementData, size, Object[].class);
    }
    
    public E set(int index, E element) {
    RangeCheck(index);

    E oldValue = (E) elementData[index];
    elementData[index] = element;
    return oldValue;
    }    
}

泛型类中泛型方法

以上文中set方法为例,使用时,直接用E表示其代表的类型实参。

非泛型类中泛型方法

泛型的声明需要在方法修饰符之后,返回值之前。

class test{
    public <T> void paly(T a){
        System.out.println(a.getClass());
    }
}

类型通配符

通过下面的测试方法可以比较好的反应出类型通配符的使用方法:

Box.java

public class Box<T>{

    private T box;
    
    public T getBox() {
        return box;
    }

    public void setBox(T box) {
        this.box = box;
    }

    public Box(T a) {
        setBox(a);
    }

}

BoxMain.java

public class BoxMain {

    /**
     * @param args
     */
    public static void main(String[] args) {
        Box<Integer> test1 = new Box<Integer>(111);
        Box<String> test2 = new  Box<String>("aaa");
        
        show3(test1);
        show4(test2);
        
        show1(test1);
        show1(test2);
        
        show2(test1);
        show2(test2);
    }
    
    public static <T> void show1(Box<T> a){
        System.out.println(a.getBox());        
    }
    
    public static void show2(Box<?> a){
        System.out.println(a.getBox());    
    }
    
    public static void  show3(Box<Integer> a) {
        System.out.println(a.getBox());
    }
    
    public static void  show4(Box<String> a) {
        System.out.println(a.getBox());
    }
}

其中,show1方法是非泛型类中的泛型方法,show2用了类型通配符,show3和show4是什么都没有用的情况。可以看出,使用类型通配符可以取代show3和show4方法,比较方便。

类型通配符的上下限

在该使用类型通配符的地方,如果需要考虑其类型的安全,我们有时需要提出这样的限制:类型通配符代表的类型需要有一个限制,如,必须是Test或者Test的子类,必须是Test或者Test的父类等。

这里就用到了

? extends Test

? super Test

这两种写法,其中? extends Test表示必须是Test或者Test的子类,称为类型通配符的上限。

? super Test表示必须是Test或者Test的父类,称为类型通配符的下限。

 

至此,我们完成了泛型的学习,下面我们完成一开始提出的问题,用泛型比较大小。

ReturnBig.java

package com.fan;

public class ReturnBig <T extends Comparable<T>>{
    public T a;
    public T b;
    
    public T getA() {
        return a;
    }
    public void setA(T a) {
        this.a = a;
    }

    public T getB() {
        return b;
    }
    public void setB(T b) {
        this.b = b;
    }
    public int compareTo(T o) {
        return a.compareTo(o);
    }
    
    public ReturnBig(T a,T b){
        setA(a);
        setB(b);
    }
    
    public T returnBigT(){
        if (compareTo(b)>0) {
            return a;
        }else{
            return b;
        }
    }
}

FanMain.java

package com.fan;

public class FanMain {


    public static void main(String[] args) {
        //比较大小相对而言限制的比较多一点,如果是判等,简单的多。
        ReturnBig<Integer> returnBig = new ReturnBig<Integer>(11,22);
        System.out.println("the big num is:" + returnBig.returnBigT());
        
        ReturnBig<Float> returnBig1 = new ReturnBig<Float>(11.11f,22.11f);
        System.out.println("the big num is:" + returnBig1.returnBigT());
    }
    
}

这里用到了Comparable接口,需要注意的是实现Comparable接口的类是有限的,随便两个对象的比较本身也是没有意义的事。只有特定类型的比较才有意义。

posted @ 2015-09-08 16:54  wee616  阅读(209)  评论(0编辑  收藏  举报