泛型的实质是将数据的类型参数化,在类、接口、方法中定义后,分别被称为:泛型类、泛型接口、泛型方法。泛型类、泛型接口和泛型方法在定义时都是在名字后面加<T>。

如:集合框架

1、泛型类

public class FanXing<T> {// 定义泛型类,在后面加<T>,T是类型参数
    private T obj;

    public T getObj() {//泛型方法
        return obj;
    }

    public void setObj(T obj) {
        this.obj = obj;
    }

}
public class FanXingDemo {
public static void main(String[] args) {
    FanXing<String>name=new FanXing<String>();//创建泛型类FanXing<T>对象
    FanXing<Integer>age=new FanXing<Integer>();
    name.setObj("Tom");
    age.setObj(21);//自动装箱
    System.out.println(name.getObj());//自动拆箱
    System.out.println(age.getObj());
}
}

泛型(泛型类、方法、通配符、泛型的限定)_java

在实例化泛型类的过程中,必须使用引用数据类型。与方法的参数不同,泛型的参数可以在方法、类和接口中。

 

 

 2、泛型方法

定义遍历数组的泛型方法:

package pers.zhb;

public class Way {
public <E> void show(E[] list){
    for(int i=0;i<list.length;i++){
        System.out.println(list[i]+"  ");
    }
}
}

测试类:

package pers.zhb;

public class Test {
    public static void main(String[] args) {

        Integer[] num = { 1, 23, 465, 12, 0 };
        String[] str = { "xx", "qw" };
        Way way = new Way();
        way.show(num);
        way.show(str);
    }

}

泛型(泛型类、方法、通配符、泛型的限定)_泛型_02

(3)通配符(?)

package pers.zhb.fx;

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

public class Fx {

    public static void main(String[] args) {
        ArrayList<String> array = new ArrayList<String>();

        HashSet<Integer> set = new HashSet<Integer>();

        array.add("java");
        array.add("hellow");

        set.add(71);
        set.add(20);

        iterator(array);
        iterator(set);
    }
    public static void iterator(Collection<?> coll) {
        Iterator<?> it = coll.iterator();//获取集合的实现类对象,病调用集合的iterator()
        while (it.hasNext()) {
            System.out.println(it.next());
        }
    }
}

泛型(泛型类、方法、通配符、泛型的限定)_类型参数_03

在此方法中<?>通配符的使用,使参数的类型没有任何限制。

4、泛型的限定:

定义Animal抽象类:

package pers.zhb.limit;

abstract class Animal {
    public String food;
    public String colour;

    abstract void eat();

    abstract void colour();

    public Animal(String food, String colour) {
        this.food = food;
        this.colour = colour;
    }
}

定义Rabbit、Sheep类,实现Animal接口:

package pers.zhb.limit;

public class Rabbit extends Animal {

    public void eat() {
        System.out.println("小兔子爱吃" + this.food);

    }

    public void colour() {

        System.out.println("小兔子是" + this.colour + "");
    }

    public Rabbit(String food, String colour) {
        super(food, colour);
    }

}
package pers.zhb.limit;

public class Sheep extends Animal{

    public Sheep(String food, String colour) {
        super(food, colour);
    }


    void eat() {
    System.out.println("羊爱吃"+this.food);    
        
    }

    void colour() {
    System.out.println("羊的颜色是"+this.colour);
    }

}

定义测试类:

package pers.zhb.limit;

import java.util.ArrayList;
import java.util.Iterator;

public class Test {
    public static void main(String[] args) {
        ArrayList<Rabbit> r = new ArrayList<Rabbit>();
        ArrayList<Sheep> s = new ArrayList<Sheep>();
        Rabbit r1 = new Rabbit("", "白色");
        Rabbit r2 = new Rabbit("胡萝卜", "黑色");
        Rabbit r3 = new Rabbit("白萝卜", "灰色");

        r.add(r1);
        r.add(r2);
        r.add(r3);

        Sheep s1 = new Sheep("青草", "白色");
        Sheep s2 = new Sheep("树叶", "白色");

        s.add(s1);
        s.add(s2);
        Test.showAnimal(r);
        Test.showAnimal(s);//ArrayList<? extends Animal> 对传入的参数进行限定,集合存储的只能是Animal类的对象,或者他的子类对象
    }

    public static void showAnimal(ArrayList<? extends Animal> array) {
        Iterator<? extends Animal> it = array.iterator();
        while (it.hasNext()) {
            Animal a = it.next();
            a.eat();
            a.colour();
        }

    }
}

在这个例子中,如果没有对传入迭代器的参数进行限定,那么传入的数据类型是任意的,对程序的安全性构成威胁。

上限通配为:?extends T

下限通配为:?  super T

 

5、泛型的好处

(1)把运行时期的问题提前到了编译期间 ,提高了代码的安全性

在定义集合的时候如果不指定泛型可以添加任意类型的数据,安全性是不足的,例如:在定义泛型的时候将泛型定义为Student类型的,那么该集合就只能存储Student类型的集合

如果使用非泛型编程,如下代码,就有可能在某些情况下会发生异常,因为list数组只要是对象就能存储但是并没有对对象的类型进行限制:

泛型(泛型类、方法、通配符、泛型的限定)_泛型类_04
 ArrayList list=new ArrayList();
 list.Add(20);
 list.Add("string");
 list.Add(new MyClass());
 
  foreach(int i in list)
 {
        Console.WriteLine(i);    //这里会有个异常,因为并不是集合中的所有元素都可以转化为int
  }
泛型(泛型类、方法、通配符、泛型的限定)_泛型类_04

如果该用泛型编程,则可以避免这种异常,让编译器检查出错误。

 List<> list=new ArrayList<Integer>();
 list.Add(20);
 lsit.Add(”string”);   //编译时报错,只能报整数类型添加到集合中
 list.Add(new MyClass());   //同上

 (2)不需要强制类型转换

如果用Object代表任意类型,向下转型要使用强制类型转换,此外,如果向List集合中存储一个String,存储Integer也是没有问题的,因为它是Object类型的

(3)泛型能够将参数的数据类型参数化,在编程中能够实现代码的复用,如:一个方法可以传递Student类型的对象,在使用泛型后也可以传递Teacher类型的对象,就不用写两个方法了

 

每个人都会有一段异常艰难的时光 。 生活的压力 , 工作的失意 , 学业的压力。 爱的惶惶不可终日。 挺过来的 ,人生就会豁然开朗。 挺不过来的 ,时间也会教你 ,怎么与它们握手言和 ,所以不必害怕的。 ——杨绛