泛型的实质是将数据的类型参数化,在类、接口、方法中定义后,分别被称为:泛型类、泛型接口、泛型方法。泛型类、泛型接口和泛型方法在定义时都是在名字后面加
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());
}
}
在实例化泛型类的过程中,必须使用引用数据类型。
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);
}
}
(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());
}
}
}
在此方法中<?>通配符的使用,使参数的类型没有任何限制。
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、泛型的好处(转载自博客园:https://tech.souyunku.com/blueGao/p/10220753.html)
(1)提高了程序性能,避免了强制类型转换
对值类型使用非泛型集合类,在把值类型转换为引用类型,和把引用类型转换为值类型时,需要进行装箱和拆箱操作。装箱和拆箱的操作虽然不需要手动实现,但是性能损失较大。假如使用泛型,就可以避免装箱和拆箱操作。
ArrayList list=new ArrayList();
list.Add(20); //装箱,list存放的是object类型元素,须将值类型转化为引用类型
int i=(int)list[0]; //拆箱,list[0]的类型是object,要赋值就得把引用类型转化为值类型
如果换成泛型编程,就不会有装箱和拆箱的性能损失。
List<T> list=new List<int>();
list.Add(20); //因为指定了用int来实例化,因此不必装箱
int i=list[0]; //同样地,访问时也不需要拆箱
(2)把运行时期的问题提前到了编译期间 ,提高了代码的安全性
与ArrayList类一样,如果使用对象,可以在这个集合中添加任意类型。
如果使用非泛型编程,如下代码,就有可能在某些情况下会发生异常,因为list数组只要是对象就能存储但是并没有对对象的类型进行限制:
ArrayList list=new ArrayList();
list.Add(20);
list.Add("string");
list.Add(new MyClass());
foreach(int i in list)
{
Console.WriteLine(i); //这里会有个异常,因为并不是集合中的所有元素都可以转化为int
}
如果该用泛型编程,则可以避免这种异常,让编译器检查出错误。
List<int> list=new List<int>();
list.Add(20);
lsit.Add(”string”); //编译时报错,只能报整数类型添加到集合中
list.Add(new MyClass()); //同上