听说Java泛型很难?我不信!

作为一个曾被泛型弄得死去活来的小辣鸡,这篇文章将致力于给大家以最清新舒服的方式来把泛型讲的清清爽爽~

首先我想以集合来为泛型开个头,现在咱们这里有一个需求:集合里面有字符串类的数据,我们要把它打印出来,代码很简单

public class TestDemo {
    public static void main(String[] args) {
        
        
        ArrayList a=new ArrayList();
        a.add("java01");//添加
        a.add("java02");
        a.add("java03");//a:java01,java02,java03
                //a.add(4);//加入一个整形
        Iterator it=a.iterator();
        while(it.hasNext())
        {
            String s=(String)it.next();
            sop(s);
            
        }
    }
    static void sop(Object e) {
        System.out.println(e);
    }
}

一天有一个好事者一不小心加入了一个整形变量,编译没有问题,但是在运行时会打印错误(把上文代码中的注释去掉,编译

java01
java02
java03
Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
    at TestDemo.main(TestDemo.java:21)

代码抛了一个异常,问题在于Integer类型不能强转为String类型

问题来了,集合作为一个容器对于所有的对象都统统接收,那么我们能不能对容器加以限制,比如说,我们就要String类型的,其他的都统统的不接受?
答案是肯定可以的,主jio登场~(BGM ing.....

泛型

泛型能够限制传进来的类型
可能说起来有些抽象,我们还是用上面那个例子来说明,见代码

ArrayList a=new ArrayList();

修改一下

ArrayList<String> a=new ArrayList<String>();

这个时候,我们再试着添加整型4,编译报错

Multiple markers at this line
    - The method add(int, String) in the type ArrayList<String> is not applicable for the arguments 
     (int)
    - Type safety: The method add(Object) belong

意思大概是int类型的不能应用类型是String的添加方法

我们已经成功的用泛型来限定了传进去的类型了,在创建对象时<>中传入合适的类型

问题来了,使用泛型需要什么条件呢?

我们来看看ArrayList的JDK文档

Class ArrayList<E>

在ArrayList后面添加了<E>
我们在看看类中的方法

ArrayList中的方法.jpg

比如说add(E e)中参数的类型和Class ArrayList<E>中的E是一致的

也就是说我们在限定我们创建ArrayList时候的类型参数和后面方法中的参数是一致的,这里的E其实也就是Element的含义
需要注意的是JDK中的Iterator也允许泛型

这里再给出完整的代码

public class TestDemo {
    public static void main(String[] args) {
        
        
        ArrayList<String> a=new ArrayList<String>();
        a.add("java01");//添加
        a.add("java02");
        a.add("java03");//a:java01,java02,java03
        
        Iterator<String> it=a.iterator();
        while(it.hasNext())
        {
                        //String s-(String)it.next();
            String s=it.next();
            sop(s);
            
        }
    }
    static void sop(Object e) {
        System.out.println(e);
    }
}

这里可以给出两个添加泛型后的小结论

1、限定容器中的元素的内容
2、避免获得容器中内容的元素时需要强转
这里提出一个问题,是否我们自己能够使用泛型?
答案是肯定的,接下来给大家介绍常见的情况下使用泛型

类中加泛型

类中所有用到类定义时使用的类型的方法
也就是说,方法中传入的参数只要和定义类时参数一致,那么创建对象时就确定了


public class Person<E> {
    void show(E e)
    {
        System.out.println("show-----"+e);
    }
    
}
import javax.print.attribute.standard.MediaSize.Other;

public class TestDemo {
    public static void main(String[] args) {
        Person<String> p=new Person<String>();
        String s="abc";
        p.show(s);
    }
    static void sop(Object e) {
        System.out.println(e);
    }
}

打印一下

show-----abc

Person<E>和show(E e)中的E是同一个E,传入的类型就被确定了

我想让方法中使用自己的泛型行不行?也就是方法中的泛型与类无关
聪明的JAVA会告诉你,答案肯定也是可以的

方法中添加泛型

格式:修饰符+<E>+返回类型+方法名+参数
见代码

//方法中单独设置泛型
public class Person<E> {
    void show(E e)
    {
        System.out.println("show-----"+e);
    }
    public <T> void method(T t)
    {
        System.out.println("method----"+t);
    }
    public static <R> void function(R r)
    {
        System.out.println("function----"+r);
    }
}
public class TestDemo {
    public static void main(String[] args) {
        Person<String> p=new Person<String>();
        String s="abc";
        p.show(s);
        int num=201314;
        p.method(num);
        Person.function(520);
    }
    static void sop(Object e) {
        System.out.println(e);
    }
}

打印一下

show-----abc
method----201314
function----520
又有同学举手手说:好像泛型在很多地方都能够加
答案是肯定的,接下来我们一起来看还有那些地方能够加

接口中设置泛型

格式:interface+接口名+<E>

interface Inter<M>{
    void show(M m);
    <M> void method(M m);
    
}
public class InterTest implements Inter<String>{

    @Override
    public void show(String m) {
        // TODO Auto-generated method stub
        System.out.println("show---"+m);
    }

    @Override
    public <M> void method(M m) {
        // TODO Auto-generated method stub
        System.out.println("method----"+m);
    }

}

到这里了,我们来做一个小总结

泛型的使用非常广泛,类、方法、接口都可以使用泛型作为限定类型,其实它的本质就是打破了Object的使用,并且很好的维持了多态(因为避免了强转)

好事者又不服,认为我们既然利用泛型在创建时限定了类型,那么我现在有一个需求:我有一个Person类,还有一个Person的子类Student,我想把这两个类都打印出他们的属性,我想用一个通用的办法来打印

这个需求提的很好

泛型限定符

泛型不光支持任何单一类型,还支持具有继承关系的类型
格式:<? extends 类型>允许某一种类型极其子类
那么这里的需求很好的可以满足

//创建吗一个基本Person类
public class Person {
    private String name;
    private int age;
    Person(String name,int age)
    {
        this.age=age;
        this.name=name;
    }
    void show()
    {
        System.out.println("person-----"+name+age);
    }
}
//Person类的子类
public class student extends Person {
    private String name;
    private int age;
    private String xuehao;
    student(String name, int age,String xuehao) {
        super(name, age);
        this.xuehao=xuehao;
        // TODO Auto-generated constructor stub
    }
    void show() {
        System.out.println("stu----"+name+age+xuehao);
    }
    
}
//需求:用一种通用的方法打印Person和student类的基本属性
public class TestDemo {
    public static void main(String[] args) {
        ArrayList<Person> per_al=new ArrayList<Person>();
        per_al.add(new Person("xiaoming01",14));
        per_al.add(new Person("xiaoming02",12));
        per_al.add(new Person("xiaoming03",13));
        per_al.add(new Person("xiaoming04",42));
        per_al.add(new Person("xiaoming05",16));
        ArrayList<student> stu_al=new ArrayList<student>();
        stu_al.add(new student("xiaoming01",14,"201514160101"));
        stu_al.add(new student("xiaoming02",14,"201514160102"));
        stu_al.add(new student("xiaoming03",14,"201514160103"));
        stu_al.add(new student("xiaoming04",14,"201514160104"));
        printColl(per_al);
        printColl(stu_al);
    }
    public static void printColl(ArrayList<? extends Person> al)
    {
        Iterator<? extends Person> it=al.iterator();
        while(it.hasNext())
            it.next().show();
    }
    static void sop(Object e) {
        System.out.println(e);
    }
}

打印一下

person-----xiaoming0114
person-----xiaoming0212
person-----xiaoming0313
person-----xiaoming0442
person-----xiaoming0516
stu----null0201514160101
stu----null0201514160102
stu----null0201514160103
stu----null0201514160104

这样子,Iterator中的泛型的类型就允许接收Person和Person的子类

我们不光可以接收类及其子类,我们还可以接收类及其父类

格式:<? super student>

总结

在创建类、方法、接口的时候利用了泛型限定符,我们可以定义单类型,类以及其父类,类以及子类三种形式

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。