【Java基础】泛型的一些总结

时间:2023-03-09 06:33:06
【Java基础】泛型的一些总结

什么是泛型

泛型其实可以理解为一种广泛的类型,啥类型都型,当然,这种泛是指定义时可以广泛,但是使用时必须确定类型。也就是说,当不清楚未来使用哪种类型时,定义为泛型。可以支持泛型类,泛型接口,泛型方法,泛型成员变量。

泛型的好处

  1. 泛型可以将类型作为参数进行传递,即类型可以像参数一样实现参数化。
  2. 泛型能提高代码的重用。
  3. 在编译的时候检查类型安全,把运行期的问题提前展现出来。
  4. 泛型中的强制转换都是自动和隐式的

下面用几个示例来表明这几种好处:

下面的代码表示的是代码重用的案例,几个传入不同类型的a都可以用泛型T表示。

    public void show(int a){
System.out.println(a);
} public void show(Boolean a){
System.out.println(a);
}
public void show(String a){
System.out.println(a);
} public void show(T a){
System.out.println(a);
}

下面这段代码在编译期间是不会出错的,因为集合中可以传入任何对象,但是一运行就会出错,因为后面遍历时进行强制转换为Integer,String是不能强转为Integer的。

        List s = new ArrayList();
s.add(1);
s.add(2);
s.add("hello");
Iterator it = s.iterator();
int sum = 0;
while (it.hasNext()){
Integer i = (Integer) it.next();
sum += i;
}

但是由于ArrayList是泛型类,如果在定义的时候提前确定将来要存储在List中的类型,则可以提前提示出错误,这个就类似我们定义数组,刚开始就确定了数组的类型。

【Java基础】泛型的一些总结

自动强制用的最多的地方就是在Iterator时规定了迭代的类型,所以在遍历时不用做强转工作,会自动强转。

        List<Integer> s = new ArrayList();

        s.add(1);
s.add(2);
// s.add("hello");
Iterator<Integer> it = s.iterator();
int sum = 0;
while (it.hasNext()){
// Integer i = (Integer) it.next();
sum += it.next();//由于Integer中规定了类型,这里会自动强制转换
}

泛型类(Object和泛型类的区别--思考引入泛型的原因)

Object也可以代替任何类型,那Object是否可以取代泛型呢?接下来看一个示例程序:

public class Test {
public static void main(String[] args) {
Animal animal = new Animal();
animal.setAttr(3);
Integer age = (Integer) animal.getAttr();
System.out.println(age); System.out.println("---------------------");
animal.setAttr("dog");
String kind = (String) animal.getAttr();
System.out.println(kind); System.out.println("---------------------");
animal.setAttr("kity");
Integer name = (Integer) animal.getAttr();//不按常规出牌,编译不报错
System.out.println(name); }
} class Animal {
private Object attr; public Animal() {
} public Object getAttr() {
return attr;
} public void setAttr(Object attr) {
this.attr = attr;
}
}

  明显Test中最后一段设置姓名是String,但是做强转可能没搞清楚,偏偏转到Integer了,但是这个时候是不会报错的,因为编译期间Object是可以向子类Integer向下转型的。但是运行时就会报错,所以利用Object来写这种程序是不安全的。但是如果将Object替换为泛型,则会在编译期间就会报错。

  上述代码,如果将Animal定义为泛型类,即将Object都替换为泛型支持,并在Animal后面加上尖括号<T>,于此同时保持测试代码不变,依然编译期间不会报错,这说明,如果不指定T的类型,默认应该还是将T换成了Object。

  但是,泛型类的使用规则是需要你定义的时候就规定将来的类型的,在定义时讲T确定为Integer后,上述代码有三行编译出错。

public class Test {
public static void main(String[] args) {
Animal<Integer> animal = new Animal<>();
animal.setAttr(3);
Integer age = (Integer) animal.getAttr();
System.out.println(age); System.out.println("---------------------");
animal.setAttr("dog");//编译不通过
String kind = (String) animal.getAttr();//编译不通过
System.out.println(kind); System.out.println("---------------------");
animal.setAttr("kity");//编译不通过
Integer name = (Integer) animal.getAttr();
System.out.println(name); }
} class Animal<T> {
private T attr; public Animal() {
} public T getAttr() {
return attr;
} public void setAttr(T attr) {
this.attr = attr;
}
}

泛型方法

  泛型类有一个特点,就是需要在实例化类的时候明确泛型的类型,不然有警告(不然就是当作Object),一旦定义了,接下来类中的所有泛型的T都确定了。也就是说如果实例化的时候将T定义为String,则类中所有的T都是String,这样不是太灵活。所以引入了泛型方法。

  泛型方法的定义特征:public static <T> List<T> asList(T... a)

这里用Arrays中的asList方法来举例说明,泛型方法是将以前泛型类中的<T>放到了方法返回值前面。这样asList方法以后可以接受任何类型的传参了。

ps:这篇文章对泛型方法进行了更深入的总结http://www.cnblogs.com/iyangyuan/archive/2013/04/09/3011274.html

泛型接口

泛型接口和泛型类类似,只是实现泛型接口的类一般也是继续泛型下去,如若不然,则泛型接口的灵活性就没有被突显了。

public interface Animal<T> {
public abstract void show(T a);
}
public class Dog<T> implements Animal<T>{

    @Override
public void show(T a) {
System.out.println(a);
}
}

泛型的高级运用-通配符

 1. ?:            任意类型,如果没有明确,那么就是Object以及任意的Java类了
2. ? extends E: 向下限定,E及其子类
3. ? super E: 向上限定,E极其父类
public class GenericDemo {
public static void main(String[] args) {
// 泛型如果明确的写的时候,前后必须一致
Collection<Object> c1 = new ArrayList<Object>();
// Collection<Object> c2 = new ArrayList<Animal>();
// Collection<Object> c3 = new ArrayList<Dog>();
// Collection<Object> c4 = new ArrayList<Cat>(); // ?表示任意的类型都是可以的
Collection<?> c5 = new ArrayList<Object>();
Collection<?> c6 = new ArrayList<Animal>();
Collection<?> c7 = new ArrayList<Dog>();
Collection<?> c8 = new ArrayList<Cat>(); // ? extends E:向下限定,E及其子类
// Collection<? extends Animal> c9 = new ArrayList<Object>();
Collection<? extends Animal> c10 = new ArrayList<Animal>();
Collection<? extends Animal> c11 = new ArrayList<Dog>();
Collection<? extends Animal> c12 = new ArrayList<Cat>(); // ? super E:向上限定,E极其父类
Collection<? super Animal> c13 = new ArrayList<Object>();
Collection<? super Animal> c14 = new ArrayList<Animal>();
// Collection<? super Animal> c15 = new ArrayList<Dog>();
// Collection<? super Animal> c16 = new ArrayList<Cat>();
}
} class Animal {
} class Dog extends Animal {
} class Cat extends Animal {
}