【Java的集合框架工具类 泛型 30】

一、泛型:jdk1.5(或者5.0)出现的安全机制。

好处:
1)、将运行时期出现的问题ClassCastException转到编译时期,泛型技术是给编译器使用的技术,用于编译时期。确保了类型的安全
2)、避免了强制类型转换的麻烦

1、<>什么时候用?
当操作的引用数据类型确定的时候。就是用<>。将要操作的引用数据类型传入即可。其实<>就是一个用于接收具体引用数据类型的参数范围。
在程序中,只要用到了带有<>的类或者接口,就要明确传入具体的引用数据类型。
2、泛型的补偿擦除:运行时,会将泛型去掉,生成的class文件中是不带泛型的,这个称为泛型的擦除,为什么擦除呢?因为为了兼容运行的类加载器。
3、泛型的补偿:在运行时,通过获取元素的类型进行转换动作,不用使用者在强制转换了

--->在程序中,只要用到了带有<>的类或者接口,就要明确传入具体的引用数据类型。
--->泛型不可以往里面写基本数据类型:如:<int>  但是可以写成<Integer>
举例1:

package com.JavaStudy01.Generic;

import java.util.ArrayList;
import java.util.Iterator;

/**
 * @Author wufq
 * @Date 2020/8/10 09:57
 */
public class GenericDemo01 {
    public static void main(String[] args){

        //确定引用类型是String类型,那么在集合内只能存储String类型的数据,
        // 即:泛指是确定了引用类型(如:String),然后存储的也是特定的类型(如:String)
        ArrayList<String> al = new ArrayList<>();
        al.add("123");
        al.add("456");
//        al.add(123);只能存储String类型,不能存其他的类型,因为对ArrayList做了泛指

        Iterator<String> it = al.iterator();
        while (it.hasNext()){
            String str = it.next();
            System.out.println(str);
        }
    }
}

举例2:自定义类型的比较(通过年龄和姓名)

----->通过年龄排序:Personew类<-----------

package com.JavaStudy01.Bean;

/**
 * @Author wufq
 * @Date 2020/8/10 11:03
 */
//Comparable<T>接口用于实现对象的比较,比较时指定了对象则可实现指定对象的比较,如果不指定实现的是Object对象的比较
public class Personew implements Comparable<Personew>{
    private String name;
    private int age;

    public Personew() {
        super();
    }

    public Personew(String name, int age) {
        super();
        this.name = name;
        this.age = age;
    }

    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;
    }

    @Override
    public int compareTo(Personew per) {

        int temp = this.age-per.age;

        return temp==0?this.name.compareTo(per.name):temp;
    }
    /*
    public boolean equals(Object obj){}
    这个才是方法覆盖,如果是
    public boolean equals(Person p){}
    不是方法覆盖,因为equals是Object的方法,所以方法覆盖时参数”Object obj“不能修改。
     */

    //Comparable<Personew>泛指以后,IDEA直接用快捷方式:command+N来重写equals和hashCode
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Personew personew = (Personew) o;

        if (age != personew.age) return false;
        return name != null ? name.equals(personew.name) : personew.name == null;
    }

    @Override
    public int hashCode() {
        int result = name != null ? name.hashCode() : 0;
        result = 31 * result + age;
        return result;
    }
}

----->通过姓名排序:原始Personew类<-----------

package com.JavaStudy01.Bean;

/**
 * @Author wufq
 * @Date 2020/8/10 11:03
 */
//Comparable<T>接口用于实现对象的比较,比较时指定了对象则可实现指定对象的比较,如果不指定实现的是Object对象的比较
public class Personew {
    private String name;
    private int age;

    public Personew() {
        super();
    }

    public Personew(String name, int age) {
        super();
        this.name = name;
        this.age = age;
    }

    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;
    }
}

----->通过姓名排序:ComparatorByNamePers类实现姓名排序<-----------

package com.JavaStudy01.Bean;

import java.util.Comparator;

/**
 * @Author wufq
 * @Date 2020/8/10 14:51
 */
public class ComparatorByNamePers implements Comparator<Personew>{
    @Override
    public int compare(Personew o1, Personew o2) {

        int temp = o1.getName().compareTo(o2.getName());
        return temp==0?o1.getAge()-o2.getAge():temp;
    }
}

----->测试类:GenericDemo02类<-----------

package com.JavaStudy01.Generic;

import com.JavaStudy01.Bean.ComparatorByNamePers;
import com.JavaStudy01.Bean.Personew;

import java.util.Iterator;
import java.util.TreeSet;

/**
 * @Author wufq
 * @Date 2020/8/10 11:05
 */
public class GenericDemo02 {
    public static void main(String[] args){
        //通过age进行比较
        TreeSet<Personew> ts = new TreeSet<>();
        ts.add(new Personew("lisi1",21));
        ts.add(new Personew("lisi2",22));
        ts.add(new Personew("lisi10",28));
        ts.add(new Personew("lisi8",10));

        Iterator<Personew> it = ts.iterator();
        while (it.hasNext()){
            Personew p = it.next();
            System.out.println(p.getName()+"::"+p.getAge());
        }

        System.out.println("----------------");
        //通过name进行比较
        TreeSet<Personew> tsp = new TreeSet<>(new ComparatorByNamePers());
        tsp.add(new Personew("lisi1",21));
        tsp.add(new Personew("lisi2",22));
        tsp.add(new Personew("lisi10",28));
        tsp.add(new Personew("lisi8",10));

        Iterator<Personew> itp = tsp.iterator();
        while (itp.hasNext()){
            Personew p = itp.next();
            System.out.println(p.getName()+"::"+p.getAge());
        }

    }
}

二、泛型类、方法、接口

泛型类:

 1、如果一个工具类想对所有类进行操作,那么就可以定义一个Object

package com.JavaStudy01.GenericDefault;

/**
 * @Author wufq
 * @Date 2020/8/10 16:05
 */
public class Tool {
    private Object object;

    public Object getObject() {
        return object;
    }

    public void setObject(Object object) {
        this.object = object;
    }
}

2、用工具类调用学生类,需要往里面存一个学生和取一个学生

package com.JavaStudy01.Generic;

import com.JavaStudy01.GenericDefault.Tool;
import com.JavaStudy01.GenericUtil.Student;
import com.JavaStudy01.GenericUtil.Work;

/**
 * @Author wufq
 * @Date 2020/8/10 15:24
 */
public class GenericDemo03 {
    public static void main(String[] args){
        Tool tool = new Tool();

        //往里面存了一个学生
        tool.setObject(new Student());
        tool.setObject(new Work()); //什么对象都能往里面存,好处是扩展性强了,但是也有弊端那就是取对象时都必须的强转。所以需要改进Tool类

        //取出来一个学生,学生存进去以后就意味着向上转型了(即:Student向上转为Object),所以需要强制转换
        Student stu= (Student) tool.getObject();
    }
}

发现:由于工具类里面采用了Object,所以任何对象都可以往里面存,但是的需要强转

3、为了解决这个强转问题,也为了更安全,所以在工具类内引入了泛指类

package com.JavaStudy01.GenericDefault;

//使用泛型来接受类中要操作的引用数据类型
// 泛型类。什么时候用?当操作类中的引用类型不确定时,就采用泛型类
public class Tool<QQ>{
    private QQ q;

    public QQ getObject() {
        return q;
    }

    public void setObject(QQ q) {
        this.q = q;
    }
}

4、使用泛型后的引用

package com.JavaStudy01.Generic;

import com.JavaStudy01.GenericDefault.Tool;
import com.JavaStudy01.GenericUtil.Student;

/**
 * @Author wufq
 * @Date 2020/8/10 15:24
 */
public class GenericDemo03 {
    public static void main(String[] args){

      // 使用泛型类后的引用

        Tool<Student> tool = new Tool<>();
        tool.setObject(new Student());
        Student stu = tool.getObject();// ---->不需要在进行强转了,
    }
}

泛型方法

 将泛型定义在方法上,目的是为了对任何类型进行传入或操作

package com.JavaStudy01.GenericDefault;

//使用泛型来接受类中要操作的引用数据类型
// 泛型类。什么时候用?当操作类中的引用类型不确定时,就采用泛型类
public class Tool<QQ>{
    private QQ q;

    public QQ getObject() {
        return q;
    }

    public void setObject(QQ q) {
        this.q = q;
    }

    /*将泛型定义在方法上:目的是可以对任何类型进行传入或操作*/

    public <W> void show(W str){
        System.out.println(str);
    }

    public void print(QQ str){
        System.out.println(str);
    }

    /*
    * 当方法静态时,不能访问类上定义的泛型。
    * 如果静态方法使用泛型,只需要将泛型定义在方法上
    * */

    public static <W> void method(W w){
        System.out.println(w);
    }
}
package com.JavaStudy01.Generic;

import com.JavaStudy01.GenericDefault.Tool;

/**
 * @Author wufq
 * @Date 2020/8/14 09:41
 */
public class GenericDemo04 {
    public static void main(String[] args){
        Tool<String> tool = new Tool<>();

        //可以传入任意类型的值
        tool.show("123");
        tool.show(new Integer(888));
        tool.show(1.2);

        //print方法的参数是泛型类型,同样不能传入任何类型的值
        tool.print("567");
//        tool.print(new Integer(999)); //

        //静态方法使用泛型
        Tool.method(new Integer(123));
        Tool.method("456");


    }
}

 泛型接口

package com.JavaStudy01.Generic;

import com.sun.org.apache.xpath.internal.operations.String;

/**
 * @Author wufq
 * @Date 2020/8/18 16:55
 */
public class GenericDemo05 {
    public static void main(String[] args){

        Interclass1<Integer> ic2 = new Interclass1<>();
        ic2.method(123);

    }
}

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

//在定义类时不明确类型,但是在方法上是明确的
 class Interclass1 <K> implements Inter<K> {

    @Override
    public void method(K k) {
        System.out.println(k);
    }
}

 三、泛型限定(上下限定)

可以对类型进行限定:
 上限:? extend E:接收E类型或者E的子类型对象。

 下限: ? super E:接收E类型或者E的父类型。

1、举例:多个基本类型的集合迭代(上限)

package com.JavaStudy01.Generic;

import java.util.*;

/**
 * @Author wufq
 * @Date 2020/8/19 10:39
 * 泛型限定(上限)
 * 基本类型:多个集合的迭代
 */
public class GenericAdvanceDemo01 {
    public static void main(String[] args){
        ArrayList<String> al = new ArrayList<>();
        al.add("abc");
        al.add("bbb");


        LinkedList<String> al2 = new LinkedList<>();
        al2.add("abc");
        al2.add("bbb");

        HashSet<String> al3 = new HashSet<>();
        al3.add("abc");
        al3.add("bbb");

        printCollection(al);
        printCollection(al2);
        printCollection(al3);

        System.out.println("-----------");
        printCollection1(al);

        System.out.println("-----------");
        printCollection2(al);



    }

    //多个集合,并且每个集合的类型是不一样的,这时候就需要他们的一个父类的集合Collection
    public static void printCollection(Collection<String> al) {

        Iterator<String> it = al.iterator();
        while (it.hasNext()){
            String msg = it.next();
            System.out.println(msg);
        }
    }

    //不光集合是不同的,同样集合内的类型也是不同的并且是未知的-->可以用到通配符:?
    public static void printCollection1(Collection<?> al) {
        Iterator<?> it = al.iterator();
        while (it.hasNext()){
//            String msg = it.next();   -->通配符因为不知道是什么类型,所以不能赋值给特定的类型
            System.out.println(it.next());

        }

    }

    //指定了一个具体的类型,那么这个类型就可以被操作。所以和通配符的区别在于:通配符不能进行操作,而指定类型确可以操作
    public static <T> void printCollection2(Collection<T> al) {
        Iterator<T> it = al.iterator();
        while (it.hasNext()){
            T msg = it.next();
            System.out.println(msg);

        }

    }

}

2、举例:多个自定义类型的集合迭代(上限)

package com.JavaStudy01.Generic;

import com.JavaStudy01.Bean.Person;
import com.JavaStudy01.GenericUtil.Student;
import com.JavaStudy01.GenericUtil.Work;

import java.util.*;

/**
 * @Author wufq
 * @Date 2020/8/19 10:47
 * 自定义类型:多个集合的迭代
 */
public class GenericAdvanceDemo02 {
    public static void main(String[] args){
        ArrayList<Work> al = new ArrayList<>();
        al.add(new Work("张三",21));
        al.add(new Work("李四",22));

        LinkedList<Student> lk = new LinkedList<>();
        lk.add(new Student("张三",21));
        lk.add(new Student("李四",22));


        //打印容器中的元素 -->但是这个容器有个条件?只打印person的子类
        printCollectionAction(al);
        printCollectionAction(lk);
    }


    /*public static void printCollectionAction(Collection< Person> al)
         (Collection<Person> al = new ArrayList<Work>())  -->其实参数是这样的,引用和实体其实是泛型不匹配
    {
        Iterator<String> it = al.iterator();
        while (it.hasNext()){
            String msg = it.next();
            System.out.println(msg);
        }

    }*/

    //针对以上的错(仍然无法打印Person的子类),改进:只需要把通配符继承一下Person类
    public static void printCollectionAction(Collection<? extends Person> al) {

        Iterator<? extends Person> it = al.iterator();
        while (it.hasNext()){

            //用Person类接受,迭代器就可以对Person类里面的数据进行操作
            Person p = it.next();
            System.out.println(p.getName()+"::"+p.getAge());
        }
    }


}

2、举例:多个自定义类型的集合迭代(下限)

package com.JavaStudy01.Generic;

import com.JavaStudy01.Bean.Person;
import com.JavaStudy01.GenericUtil.Student;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedList;

/**
 * @Author wufq
 * @Date 2020/8/19 11:43
 * 泛型限定(下限)
 */
public class GenericAdvanceDemo03 {

    public static void main(String[] args){
        ArrayList<Person> al = new ArrayList<>();

        al.add(new Person("张三",21));
        al.add(new Person("李四",22));

        LinkedList<Student> lk = new LinkedList<>();
        lk.add(new Student("张三",21));
        lk.add(new Student("李四",22));

        //打印容器中的元素 -->但是这个容器有个条件?只打印person的子类
        printCollectionAction(al);
        printCollectionAction(lk);
    }


    public static void printCollectionAction(Collection<? super Student> al) {

        Iterator<? super Student> it = al.iterator();
        while (it.hasNext()){

            System.out.println(it.next());
        }
    }
}

 四、泛指上限、下限、通配符体现。

1、泛指上限:一般在存储元素的时候使用上限,因为这样去除都是按照上限类型来运算的。不会出现类型安全隐患

------->addAll(Collection<? extends E> c)<-------

addAll(Collection<? extends E> c)    将指定Collection中的所有元素都添加到此Collection种

package com.JavaStudy01.Generic;

import com.JavaStudy01.Bean.Person;
import com.JavaStudy01.GenericUtil.Student;
import com.JavaStudy01.GenericUtil.Work;

import java.util.ArrayList;
import java.util.LinkedList;

/**
 * @Author wufq
 * @Date 2020/8/24 10:49
 * 泛指上限高级应用
 * 一般在存储元素的时候使用上限,因为这样去除都是按照上限类型来运算的。不会出现类型安全隐患。
 * addAll(Collection<? extends E> c)  将指定Collection中的所有元素都添加到此Collection中
 */
public class GenericAdvanceDemo04 {
    public static void main(String[] args){

        ArrayList<Person> al = new ArrayList<>();
        al.add(new Person("张三",21));
        al.add(new Person("李四",22));

        LinkedList<Student> lk = new LinkedList<>();
        lk.add(new Student("张三1",21));
        lk.add(new Student("李四1",22));

        ArrayList<Work> al1 = new ArrayList<>();
        al1.add(new Work("张三2",21));
        al1.add(new Work("李四2",22));

        ArrayList al2 = new ArrayList();
        al2.add("uuu");


        al.addAll(al2);
        System.out.println(al.toString());

    }
}

class MyCollection<E>{
    public void add(E e){

    }

    public void addAll(MyCollection<? extends E> e){

    }
}
====执行结果====
[张三::21, 李四::22, uuu]

 

posted @ 2020-08-13 10:23  尘封~~  阅读(205)  评论(0编辑  收藏  举报