泛型<E>
泛型,我们以前已经接触过了,其实就是我们创建集合是的那个<E>
他的意思就是这个<E>
可以是任意引用数据类型(现在的JDK都支持自动装箱自动拆箱,所以基本数据类型大部分情况也可以啦)。
定义和使用含有泛型的类
我们在官方的Java API文档中,看到很多的类都是附带泛型的,那么我们自己如何定义含有泛型的类呢?
泛型是一个未知的数据类型,我们不确定使用什么数据类型的时候,使用泛型。而且泛型的类型的确定是在创建对象的时候确定的。
为了更好的引出泛型的概念,我们先定义一个普通的类:
public class Student {
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
private String name;
private int age;
}
我们看到了,这就是个简单到极点的学生类。但是他的年龄是int
类型啊。
但是某些逗比就是想往里面输入汉字怎么办,比如说 年龄:“十八岁”。这就很头疼,如何用泛型改写一下这个类呢?
public class Student<E> {
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public E getAge() {
return age;
}
public void setAge(E age) {
this.age = age;
}
private String name;
private E age;
}
是的,泛型就是这么简单,就是把你想要在创建对象时才确定的数据元素都变成E
,然后再类定义后面加一个<E>
就行了!
是不是很简单,我们下面来使用这个有泛型的类吧。
这样我们就成功使用了泛型在对象创建的时候才动态的决定其中某些数据成员的数据类型。这就是泛型最大的好处。
public class Main{
public static void main(String[] args){
Student<String> aStu=new Student<String>();
aStu.setAge("十八岁");
System.out.println(aStu.getAge());
System.out.println("============================");
Student<Integer> aStu2=new Student<Integer>();
aStu2.setAge(18);
System.out.println(aStu2.getAge());
}
}
运行结果如下:
定义接口时使用泛型
定义类的时候使用泛型我们会了,那么定义接口的时候使用泛型呢?当然是一样的啊,我们说接口其实就是用来放一堆抽象方法的类,泛型的自然也就和类一样了,这里之所以要拿出来,是因为(继承)实现接口的时候对于泛型有两种情况。当接口定义了泛型的时候,可以
1.实现(继承)时,保留接口(父类)的<E>
,这样相当于实现类(子类)也使用了泛型,在创建对象的时候确定泛型的数据类型。
2.实现(jiig)时,直接把接口(父类)的<E>
写成想要实现的数据类型。
接口使用泛型
public interface MyInterFace<E> {
public abstract E func1();
public abstract E func2();
public abstract E func3();
}
实现时指定<E>
是什么数据类型
public class MyImple implements MyInterFace<String> {
public String func1(){
System.out.println("fun1");
}
public String func2(){
System.out.println("fun2");
}
public String func3(){
System.out.println("fun3");
}
}
或者实现类依旧带泛型
public class MyImple<E> implements MyInterFace<E> {
public E func1(){
System.out.println("fun1");
return null;
}
public E func2(){
System.out.println("fun2");
return null;
}
public E func3(){
System.out.println("fun3");
return null;
}
}
使用多个泛型
怎么使用多个泛型呢?
非常简单,只需要把原来的<E>
变成<E,T,...>
就行了。其中泛型的名字可以随便起的。但不建议过多
public interface MyInterFace<E,I,Q,QW>{
public abstract E func1();
public abstract Q func2();
public abstract QW func3();
}
泛型通配符
这个概念大家不用太过于死扣。我们用一个例子来讲解
我现在想写一个可以遍历所有LinkedList<E>
的方法,就是说不管你泛型是什么我都可以遍历。这时候怎么办呢?
public class Main{
public static void main(String[] args){
LinkedList<Integer> list1=new LinkedList<>();
LinkedList<String> list2=new LinkedList<>();
list1.add(1);
list1.add(0);
list2.add("黄蓉");
list2.add("靖哥哥");
list2.add("阿珂");
list2.add("韦小宝");
list2.add("周芷若");
list2.add("无忌哥哥");
list2.add("小龙女");
list2.add("尹志平");
printLinked(list1);
printLinked2(list2);
}
public static void printLinked(LinkedList<Integer> list){
}
public static void printLinked2(LinkedList<String> list){
}
}
看见现在只能用两个函数来分别调用对应泛型的LinkedList
,很麻烦,而我使用泛型通配符就可以这样:
public class Main{
public static void main(String[] args){
LinkedList<Integer> list1=new LinkedList<>();
LinkedList<String> list2=new LinkedList<>();
list1.add(1);
list1.add(0);
list2.add("黄蓉");
list2.add("靖哥哥");
list2.add("阿珂");
list2.add("韦小宝");
list2.add("周芷若");
list2.add("无忌哥哥");
list2.add("小龙女");
list2.add("尹志平");
printLinked(list1);
System.out.println("================================");
printLinked(list2);
}
public static void printLinked(LinkedList<?> list){
Iterator<?> it=list.iterator();
while(it.hasNext()){
System.out.printf("%s说:只有%s才能让我快乐!\n",it.next(),it.next());
}
}
}
所以所谓泛型通配符,就是一个<?>,可以实现动态的泛型传参。
执行结果如下: