JAVA基础再回首(十六)——泛型的概述、使用、泛型类、泛型方法、泛型接口、泛型高级(通配符)

时间:2022-06-27 19:25:24

JAVA基础再回首(十六)——泛型的概述、使用、泛型类、泛型方法、泛型接口、泛型高级(通配符)

版权声明:转载必须注明本文转自程序员杜鹏程的博客:http://blog.csdn.net/m366917


周末是提升自己的最好时间,不容错过,所以我们来继续学习,今天来学习泛型。

泛型的概述

说到泛型,我们先来回顾一下之前我们做过的一个练习

public class GenericDemo {
public static void main(String[] args) {
// 创建
ArrayList array = new ArrayList();

// 添加元素
array.add("hello");
array.add("world");
array.add("java");
//添加int类型的元素
array.add(10); // JDK5以后的自动装箱
// 等价于:array.add(Integer.valueOf(10));

// 遍历
Iterator it = array.iterator();
while (it.hasNext()) {
String s = (String) it.next();
System.out.println(s);
}
}
}

我们运行程序,看看会出现怎样的输出结果
JAVA基础再回首(十六)——泛型的概述、使用、泛型类、泛型方法、泛型接口、泛型高级(通配符)

哦,千那!怎么报错了。它报的就是类型的异常,我们要怎么去解决?
这就要用我们今天要学的一个知识点泛型来解决这个问题了。

我们先来了解一下泛型

  • 泛型
    • JDK1.5以后出现的机制
    • 是一种把类型明确的工作推迟到创建对象或者调用方法的时候才去明确的特殊的类型。
  • 好处
    • 提高了程序的安全性
    • 把运行时期的问题提前到了编译期间
    • 避免了强制类型转换

泛型的使用

我们使用泛型前,先来了解它的格式。

  • 格式
    • <数据类型>
    • 此处的数据类型只能是引用类型。

泛型在哪些地方使用呢?
看API,如果类,接口,抽象类后面跟的有< E >就说要使用泛型。一般来说就是在集合中使用。

我们用泛型修改上面例子中的错误

public class GenericDemo {
public static void main(String[] args) {
// 创建
ArrayList<String> array = new ArrayList<String>();

// 添加元素
array.add("hello");
array.add("world");
array.add("java");
//array.add(10); // JDK5以后的自动装箱
// 等价于:array.add(Integer.valueOf(10));

// 遍历
Iterator<String> it = array.iterator();
while (it.hasNext()) {
// ClassCastException
// String s = (String) it.next();
String s = it.next();
System.out.println(s);
}
}
}

泛型就是这样使用的,你会了吗?

泛型类

  • 把泛型定义在类上
  • 格式:public class 类名<泛型类型1,…>
  • 注意:泛型类型必须是引用类型

早期的时候,我们使用Object来代表任意的类型。
向上转型是没有任何问题的,但是在向下转型的时候其实隐含了类型转换的问题。
也就是说这样的程序其实并不是安全的。所以Java在JDK5后引入了泛型,提高程序的安全性。
下面我们就来学习泛型类是怎么回事

/*
* 泛型类:把泛型定义在类上
*/

public class ObjectTool<T> {
private T obj;

public T getObj() {
return obj;
}

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

/*
* 泛型类的测试
*/

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

ObjectTool<String> ot = new ObjectTool<String>();
ot.setObj(new String("李宗伟"));
String s = ot.getObj();
System.out.println("姓名是:" + s);

ObjectTool<Integer> ot2 = new ObjectTool<Integer>();
ot2.setObj(new Integer(34));
Integer i = ot2.getObj();
System.out.println("年龄是:" + i);
}
}

输出结果:
姓名是:李宗伟
年龄是:34

可以看出传递什么类型的元素完全由你来控制,是不是很方便。

泛型方法

  • 把泛型定义在方法上
  • 格式:public <泛型类型> 返回类型 方法名(泛型类型 .)

上面我们把泛型定义在了类中,现在我们也可以把泛型定义在方法中,来一起学习

/*
* 泛型方法:把泛型定义在方法上
*/

public class ObjectTool {
public <T> void show(T t) {
System.out.println(t);
}
}

public class ObjectToolDemo {
public static void main(String[] args) {
// 定义泛型方法后
ObjectTool ot = new ObjectTool();
ot.show("hello");
ot.show(100);
ot.show(true);
}
}

这样我们就可以传递任意类型的参数了

泛型接口

  • 把泛型定义在接口上
  • 格式:public interface 接口名<泛型类型1…>
/*
* 泛型接口:把泛型定义在接口上
*/

public interface Inter<T> {
public abstract void show(T t);
}

//实现类在实现接口的时候,我们会遇到两种情况
//第一种情况:已经知道是什么类型的了
public class InterImpl implements Inter<String> {
@Override
public void show(String t) {
System.out.println(t);
}
}
//第二种情况:还不知道是什么类型的
public class InterImpl<T> implements Inter<T> {

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

public class InterDemo {
public static void main(String[] args) {
// 第一种情况的测试
Inter<String> i = new InterImpl();
i.show("hello");

// 第二种情况的测试
Inter<String> i = new InterImpl<String>();
i.show("hello");

Inter<Integer> ii = new InterImpl<Integer>();
ii.show(100);
}
}

类、方法、接口他们的区别很明显,结构都很相似,所以很容易掌握

泛型高级(通配符)

  • 泛型通配符 < ?>
    • 任意类型,如果没有明确,那么就是Object以及任意的Java类了
  • ? extends E
    • 向下限定,E及其子类
  • ? 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 {
}

仔细观察一下上面的通配符有什么区别,你会很快的学会通配符的使用


好了,我们泛型方面的知识就学到这里,要会用它还得多练习。

欢迎有兴趣的同学加我朋友的QQ群:点击直接加群555974449 请备注:java基础再回首我在群里等你。