Java泛型方法与泛型类的使用------------(五)

  泛型的本质就是将数据类型也参数化, 普通方法的输入参数的值是可以变的,但是类型(比如: String)是不能变的,它使得了在面对不同类型的输入参数的时候我们要重载方法才行. 泛型就是将这个数据类型也搞成跟参数的值一样可以变的.

  泛型分为泛型接口,泛型类和泛型方法. 泛型接口,泛型类大家都比较熟悉了,应该都用过List, ArrayList. List就是泛型接口,ArrayList就是泛型类,我们经常看到List <E>的声明, new ArrayList<E>()的定义, 这里面的E可以是String, 也可以自己定义的类. 我感觉泛型类就JDK提供的就基本够用了,自定义使用的场景非常少了. 反而是泛型方法,对与解析自定义数据结构非常有用, 类似于toString这种场景是百试不爽.

 

-----------------------------------------------------------泛型方法应用实例--------------------------------------------

泛型方法不一定要在泛型类里面

定义:

1. 函数上的泛型定义

          当函数中使用了一个不明确的数据类型,那么在函数上就可以进行泛型的定义。

          public <泛型的声明> 返回值类型  函数名( 泛型 变量名  ){
          
          
          }

 

 例如:

package Test;

import org.junit.Test;

public class fanxing {

    /**
     * 定义一个泛型方法,泛型方法也可以声明为static
     *@param t1
     */
//    public static <T> void testFanxing(T t1){
    public <T> void testFanxing(T t1){
        System.out.println(t1);
    }
    
    
    //测试泛型类
    @Test
    public void test1(){
        fanxing fx=new fanxing();
        fx.testFanxing(2);
        fx.testFanxing("字符串");
        fx.testFanxing(new User("1", "QLQ"));
    }
}

//用于测试泛型类的类
class User{
    private String id;
    private String name;
    public String getId() {
        return id;
    }
    public void setId(String id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    protected User(String id, String name) {
        super();
        this.id = id;
        this.name = name;
    }
    @Override
    public String toString() {
        return "User [id=" + id + ", name=" + name + "]";
    }
    
}

 结果:

 

 -----------------------------------------------------------泛型类应用实例--------------------------------------------

package Test;

import org.junit.Test;

//可以有一个,也可以有多个
public class fanxinglei<T, T2> {
    // 泛型属性
    private T t1;

    public T getT1() {
        return t1;
    }

    public void setT1(T t1) {
        this.t1 = t1;
    }

    // 泛型方法
    public void testFanxing(T2 t2) {
        System.out.println(t2);
        System.out.println(this.getT1());
    }

    public static void main(String[] args) {
        fanxinglei<String, Integer> fanxinglei = new fanxinglei<String, Integer>();
        fanxinglei.setT1("泛型类");
        fanxinglei.testFanxing(4);
    }
}

 

 测试:

 -----------------------------------泛型接口应用实例------------

public class Demo8 {
    public static void main(String[] args) {
        MyInter<String> my = new MyInter<String>();
        my.print("泛型");

        MyInter2 my2 = new MyInter2();
        my.print("只能传字符串");
    }
}

interface Inter<T> {
    void print(T t);
}

// 实现不知为何类型时可以这样定义
class MyInter<T> implements Inter<T> {
    public void print(T t) {
        System.out.println("myprint:" + t);
    }
}
//使用接口时明确具体类型。
class MyInter2 implements Inter<String> {

    @Override
    public void print(String t) {
        System.out.println("myprint:" + t);

    }

}

 

 -----------------------------------泛型通配符应用实例------------------------

需求:

定义一个方法,接收一个集合对象(该集合有泛型),并打印出集合中的所有元素。

例如集合对象如下格式:

Collection<Person> coll = new ArrayList<Person>();
        coll.add(new Person("jack", 20));
        coll.add(new Person("rose", 18));
        Collection<Object> coll2 = new ArrayList<Object>();
        coll2.add(new Object());
        coll2.add(new Object());
        coll2.add(new Object());

        Collection<String> coll3 = new ArrayList<String>();
        coll3.add("abc");
        coll3.add("ddd");
        coll3.add("eee");

 

分析,集合对象中的元素的类型是变化的,方法的形参的那么泛型类型就只能定义为Object类型.

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;

public class Demo9 {
    public static void main(String[] args) {
        ArrayList<Object> arr = new ArrayList<Object>();
        arr.add(new Object());
        arr.add("String");
        print(arr);
        
        //将集合的泛型设置类String类型,是Object子类
        HashSet<String> hs = new HashSet<String>();
        hs.add("hello");
        hs.add("jack");
        //由于print方法接收的集合进行了元素限定,只接受限定为Object类型的集合,编译不通过
        //print(hs);
    }

    public static void print(Collection<Object> coll) {
        Iterator<Object> it = coll.iterator();
        while (it.hasNext()) {
            Object next = it.next();
            System.out.println(next);
        }
    }
}

 

但是,由于print方法接收的集合进行了元素限定,只接受限定为Object类型的集合,编译不通过该问题如何解决?

可以把方法的形参的泛型去掉,那么方法中就把集合中的元素当做Object类型处理.

也可以使用使用泛型通配符

public class Demo9 {
    public static void main(String[] args) {
        ArrayList<Object> arr = new ArrayList<Object>();
        arr.add(new Object());
        arr.add("String");
        print(arr);

        // 将集合的泛型设置类String类型,是Object子类
        HashSet<String> hs = new HashSet<String>();
        hs.add("hello");
        hs.add("jack");
        // 使用泛型通配符,编译通过。
        print(hs);
    }

    public static void print(Collection<?> coll) {
        Iterator<?> it = coll.iterator();
        while (it.hasNext()) {

            Object next = it.next();
            System.out.println(next);
        }
    }
}

 

上述就使用了泛型通配符

通配符:?
public void show(List<?> list)
{
}
可以对类型进行限定范围。
?extends E: 接收E类型或者E的子类型。
? super E: 接收E类型或者E的父类型。

 

限定泛型通配符的边界

限定通配符的上边界:

extends

接收Number 类型或者Number的子类型

正确:Vector<? extends Number> x = new Vector<Integer>();
错误:Vector<? extends Number> x = new Vector<String>();

 

限定通配符的下边界

super

接收Integer 或者Integer的父类型

正确:Vector<? super Integer> x = new Vector<Number>();
错误:Vector<? super Integer> x = new Vector<Byte>();

 

总结:

  JDK5中的泛型允许程序员在编写集合代码时,就限制集合的处理类型,从而把原来程序运行时可能发生问题,转变为编译时的问题,以此提高程序的可读性和稳定

注意:

  泛型是提供给javac编译器使用的,它用于限定集合的输入类型,让编译器在源代码级别上,即挡住向集合中插入非法数据。但编译器编译完带有泛形的java程序后,生成的class文件中将不再带有泛形信息,以此使程序运行效率不受到影响,这个过程称之为“擦除”。

 

泛型的基本术语,以ArrayList<E>为例:<>念着typeof

  ArrayList<E>中的E称为类型参数变量

  ArrayList<Integer>中的Integer称为实际类型参数

  整个称为ArrayList<E>泛型类型

  整个ArrayList<Integer>称为参数化的类型ParameterizedType

 

 

posted @ 2017-08-01 18:33  QiaoZhi  阅读(892)  评论(0编辑  收藏  举报