纵有疾风起
人生不言弃

Java 泛型

一、基本概念
概念:泛型就是参数化类型,使用广泛的类型。
起因:数据类型不明确。
装入数据的类型都被当作Object对待,从而”丢失”自己的实际类型。
获取数据时往往需要转型,效率低,容易产生错误。
作用:
安全:在编译的时候检查类型安全。
省心:所有的强制转换都是自动和隐式的,提高代码的重用率。

二、未使用泛型

package Genericity;

public class Student {
    private Object  englishScore;
    private Object  mathsScore;

    public Object getEnglishScore() {
        return englishScore;
    }
    public void setEnglishScore(Object englishScore) {
        this.englishScore = englishScore;
    }
    public Object getMathsScore() {
        return mathsScore;
    }
    public void setMathsScore(Object mathsScore) {
        this.mathsScore = mathsScore;
    }
    public Student(Object englishScore, Object mathsScore) {
        super();
        this.englishScore = englishScore;
        this.mathsScore = mathsScore;
    }
    public Student() {
        super();
    }
}
package Genericity;

/** * 获取值: * 1、强制类型转换 * 2、手动类型检查:避免转换错误 java.lang.ClassCaseException * @author liguodong * */
public class Demo01 {
    public static void main(String[] args) {
        Object obj=80;
        //JDK6以前 Object-->Integer-->自动拆箱
        int score01 = (Integer)obj;

        //JDK7 以后 Object-->Integer-->自动拆箱
        int score02 = (int)obj;

        System.out.println("score01:"+score01+",\nscore02:"+score02+"。");

        //存入整数:int-->Integer-->Object
        Student stu = new Student(80,90);

        int engScore = (Integer)stu.getEnglishScore();

        String mathsScore = null;
        if(stu.getMathsScore() instanceof String){
            mathsScore = (String) stu.getMathsScore();
        }       
        System.out.println("English分数为:"+engScore+",\nMaths分数为:"+mathsScore+"。");

    }
}

运行结果:

score01:80score02:80English分数为:80,
Maths分数为:null

三、自定义泛型
1.泛型类

package Genericity;
/** * * 泛型类:声明时使用泛型 * 字母: * T 表示类型Type。 * K V分别代表键值中的Key Value。 * E 代表Element。 * * 使用时确定类型 * 注意泛型只能是引用类型,不能使基本类型。 * 泛型声明时 不能使用在静态类型或静态方法上。 * * @author liguodong * * @param <T> */
public class Student<T1,T2> {
    private T1 id;
    private T2 name;
    public T1 getId() {
        return id;
    }
    public void setId(T1 id) {
        this.id = id;
    }
    public T2 getName() {
        return name;
    }
    public void setName(T2 name) {
        this.name = name;
    }


    public Student(T1 id, T2 name) {
        super();
        this.id = id;
        this.name = name;
    }
    public Student() {
    }
    public static void main(String[] args) {
        //使用时指定类型(引用类型)
        Student<Integer, String> student01 = new Student<Integer, String>(1001, "德玛西亚");

        Student<Integer,String> student02 = new Student<>();
        //1、安全:类型检查(编译时)
        student02.setId(1003);
        student02.setName("堕落天使");
        //2、省心:类型转换
        int id = student01.getId();//自动拆箱
        System.out.println(id);//1001
    }

}

2.泛型接口

package Genericity;
/** * 接口中泛型类型字母只能使用在方法中,不能使用在全局变量中 * @author liguodong * * @param <T> */
public interface Comparator<T> {
    //T a = 2; xxx java接口中属性:final static
    void compare(T t);
}

3.泛型方法

package Genericity;

import java.io.Closeable;

/** * 泛型方法<> 返回类型前面 * 只能访问对象的信息,不能修改信息。 * @author liguodong * */
public class Method {
    //泛型方法
    public static <T> void test(T t)
    {
        System.out.println(t);
    }
    //extends <= T...表示可变参数
    public static <T extends Closeable> void test(T... t)
    {
        System.out.println(t);
        for (T temp : t) {
            try {
                if(null != temp){
                    temp.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        test("df");//T-->String //df
    }
}

4.泛型继承擦除

package Genericity;

/** * 父类为泛型类 * 1.属性 * 2.方法 * 要么同时擦除,要么子类大于父类的类型 * 不能子类擦除,父类泛型 * 1.属性类型 * 在父类中,随父类而定 * 在子类中,随子类而定 * 2.方法重写 * 全部随父类而定 * */
public abstract class Father<T,T1>
{
    T t;
    public abstract void test(T t);
}

/** * 子类声明时指定具体类型 * 属性类型为具体类型 * 方法类型也为具体类型 */
class Child1 extends Father<String,Integer>
{
    Integer t1;
    @Override
    public void test(String t1){
        this.t = t1;//t->String
        this.t1 = 100; //t1->int
    }
}

/** * 子类为泛型,类型在使用时确定 * 要么同时擦除,要么子类大于父类的类型(顺序可以交换) */
class Child2<T1,T> extends Father<T,T1>
{
    T t2;
    @Override
    public void test(T t2)
    {       
    }
}

/** * 子类为泛型类,父类不指定类型->泛型的擦除,使用Object替换,此时Father为Object类型 */
class child3<T1,T2> extends Father
{
    T1 abc;
    @Override
    public void test(Object t) {
    }   
}


/** * 子类与父类同时擦除,使用Object替换,此时Father为Object类型 */
class Child4 extends Father{
    String t4;
    @Override
    public void test(Object t4) {   
    }
}

/** *错误: 子类擦除,父类使用泛型 */
/*class Child5 extends Father<T> { @Override public void test(T t5) { } }*/

5.泛型接口擦除

package Genericity;

/** * 泛型接口:与继承同理 * 重写方法随父类而定 * @author liguodong */

public interface Comparable<T> {
    void compare(T t);
}

//声明子类指定具体类型
class Comp implements Comparable<Integer> {
    @Override
    public void compare(Integer t) {    
    }
}

//同时擦除 
class Comp1 implements Comparable {
    @Override
    public void compare(Object t) {     
    }   
}

//父类擦除子类泛型
class Comp2<T> implements Comparable{
    @Override
    public void compare(Object t) { 
    }   
}

//子类泛型>=父类泛型
class Comp3<T,T1> implements Comparable<T> {
    @Override
    public void compare(T t) {
    }   
}

//父类泛型,子类擦除 错误 同 声明子类具体类型 区别开
/*class Comp4 implements Comparable<T> { @Override public void compare(T t) { } } */

6.泛型擦除情况

package Genericity;
/** * 泛型的擦除情况 * 1.继承或实现声明不指定类型 * 2.使用时不指定类型 * * 统一Object对待 * 1.编译器的警告 消除警告使用Object * 2.不完全等同于Object 编译时不会自动类型检查 */

public class Hero<T> {
    private T id;
    private T name;
    public Hero() {
    }
    public Hero(T id, T name) {
        super();
        this.id = id;
        this.name = name;
    }
    //泛型声明时不能使用静态属性
    public T getId() {
        return id;
    }
    public void setId(T id) {
        this.id = id;
    }
    public T getName() {
        return name;
    }
    public void setName(T name) {
        this.name = name;
    }

    public static void main(String[] args) {                
        //消除警告使用Object 
        Hero<Object> stu = new Hero<Object>();//不叫擦除
        stu.setName("fds");//以Object对待

        Hero stu1 = new Hero();//stu1相当于Object

        //test(stu);//不叫擦除,会类型检查,会报错

        //擦除 不会类型检查
        //stu1相当于Object 但是不完全等同于Object
        test(stu1);

        test1(stu);
        test1(stu1);
    }

    //不完全等同于Object,编译时不会自动类型检查 
    public static void test(Hero<Integer> a)    {       
    }   

    public static void test1(Hero<?> a) {       
    }
}

7.泛型没有多态

package Genericity;

/** * 多态的两种形式 * 1.形参使用多态 * 2.返回类型使用多态 */
class Fruit {
}

public class Apple extends Fruit{

    //形参使用多态
    public static void test(Fruit f){       
    }   
    //返回类型使用多态
    public static Fruit test2() {

        return new Apple();
    }
    public static void main(String[] args) {    
        Apple f = new Apple();
        test(f);
        test2();
    }
}

Java 泛型插图

解决泛型没有多态,使用通配符。

8.通配符
Java 泛型插图1

?可以接收泛型的任意类型。只能接收和输出,不能修改。

9.泛型的嵌套

package Genericity;

public class Demo02<T> 
{
    T hero;
    public static void main(String[] args) {
        //泛型的嵌套
        Demo02<Hero<String>> demo02= new Demo02<Hero<String>>();

        //从外到内拆分
        demo02.hero = new Hero<String>();

        Hero<String> student = demo02.hero; 
        student.setName("盲僧");
        String name  = student.getName();
        System.out.println(name);
    }
}

10.没有泛型数组

package Genericity;

/** * 没有泛型数组 * 声明可以使用,但是创建失败 */

public class Array {
    public static void main(String[] args) {
        Integer[] integer = new Integer[4];     
        //Hero<String>[] arr01 = new Hero<String>[10];//报错 不能使用泛型数组
        //Hero<?>[] arr02 = new Hero<Object>[10];//报错
        Hero<?>[] hero = new Hero[10];//声明可以使用,但是没啥意义

        MyArrayList<String> strArrayList = new MyArrayList<String>();
        strArrayList.add(0, "a");
        String string  = strArrayList.getElem(0);
        System.out.println(string);//a

        MyArrayList<Integer> intArrayList = new MyArrayList<Integer>();
        intArrayList.add(1, 1001);
        int data  = intArrayList.getElem(1);
        System.out.println(data);//1001
    }
}

class MyArrayList<E>
{
    Object[] cap = new Object[10];

    public void add(int index,E e)
    {
        cap[index] = e;
    }

    @SuppressWarnings("unchecked")
    public E[] getAll()
    {
        return (E[]) cap;
    }

    @SuppressWarnings("unchecked")
    public E getElem(int index)
    {
        return (E) cap[index];
    }
}

没有泛型数组,但是可以巧妙的运用类来自己转换。
例如:ArrayList<E>源码

JDK7以前使用泛型
List<String> arrlist = new ArrayList<String>();
JDK7中使用泛型改进
List<String> arrlist = new ArrayList<>();

四、泛型与容器
1、Iterator与List

package Genericity;
import java.util.Iterator;
/** * 迭代器原理 * @author liguodong */

@SuppressWarnings("all")
public class MyArray {
    private String[] arr = {"a","b","c","d","d","e","e","f","g"};

    private int size = arr.length;

    public static void main(String[] args) {
        MyArray list = new MyArray();

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

    private class MyIt implements Iterator<String>{
        private int cursor = -1;        
        /** * 判断是否存在下一个元素 * @return */
        public boolean hasNext(){
            return cursor+1<size;
        }       
        /** * 获取下一个元素 */
        public String next(){
            cursor++;//移动一次
            return arr[cursor];
        }       
        /** * 删除元素 */
        public void remove(){
            //没有实现
        }       
    }   
    public Iterator<String> iterator(){
        return new MyIt();
    }   
}
package Genericity;

import java.util.Iterator;

public class MyArrayAnonymous implements java.lang.Iterable<String>{

    String[] elem = {"a","b","c","d","e"};  
    int size = elem.length; 
    /** * 匿名内部类实现简单迭代器 * @return * * 对比AbstractList类源码 */
    public Iterator<String> iterator()
    {
        return new Iterator<String>()
        {
            private int cursor = -1;

            public boolean hasNext()
            {
                return cursor+1<size;
            }

            public String next()
            {
                cursor++;
                return elem[cursor];
            }       
            public void remove(){           
            }           
        };
    }   
    public static void main(String[] args) {
        MyArrayAnonymous list = new MyArrayAnonymous();

        Iterator<String> it = list.iterator();
        while(it.hasNext())
        {
            System.out.print(it.next()+" ");
        }
        System.out.println();
        //增强for,必须实现java.lang.Iterable接口,重写iterator方法。 
        for(String temp:list)
        {
            System.out.print(temp+" ");
        }
    }   
}

2、HashMap+分拣思路

package Genericity.Map;

public class Letter {
    private String name;
    private int count;
    public Letter() {
    }   
    public Letter(String name, int count) {
        super();
        this.name = name;
        this.count = count;
    }   
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getCount() {
        return count;
    }
    public void setCount(int count) {
        this.count = count;
    }
}
package Genericity.Map;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/** * 每个单词存储的次数 * Key:string * Value:自定义类型 * * "分拣"思路 * 1. 为所有的key创建容器,之后容器中存放对应value * 2. 第一次创建容器,并存放值 * 第二次直接使用容器存放值 */

public class Demo01 {
    public static void main(String[] args) {         
        test1();
    }

    //思路一
    public static void test1()
    {
        String str= "this is a cat and that is a mice and where is the food";
        //分割字符串
        String[] strArray = str.split(" ");
        Map<String, Letter> letters = new HashMap<>();

        /*for(String temp:strArray) { //1.为所有的key创建容器,之后容器中存放对应value if(!letters.containsKey(temp)) { letters.put(temp,new Letter()); } } for(String temp:strArray) { Letter col = letters.get(temp);//直接使用容器 col.setCount(col.getCount()+1); //col.setName(temp); }*/     
        //上面合并在一起
        for(String temp:strArray)
        {
            //1.为所有的key创建容器,
            if(!letters.containsKey(temp))
            {
                letters.put(temp,new Letter());
            }
            //2.之后容器中存放对应value
            Letter col = letters.get(temp);//直接使用容器
            col.setCount(col.getCount()+1);
        }
        //输出Map的值
        Set<String> keys = letters.keySet();
        for (String key:keys) {
            Letter col = letters.get(key);
            System.out.println("字母"+key+",次数"+col.getCount());
        }       
    }

    //思路二
    public static void test2()
    {
        String str= "this is a cat and that is a mice and where is the food";
        //分割字符串
        String[] strArray = str.split(" ");
        Map<String, Letter>  letters  = new HashMap<>();

        for(String temp:strArray)
        {
            /* //1.为所有的key创建容器, if(!letters.containsKey(temp)) { Letter col = new Letter(); col.setCount(1);//存放第一次的值 letters.put(temp,col); } else { //2第二次直接使用容器中存放对应value Letter col = letters.get(temp);//直接使用容器 col.setCount(col.getCount()+1); }*/     

            Letter col = null;
            if(null==(col =letters.get(temp)))
            {
                col = new Letter();
                col.setCount(1);
                letters.put(temp,col);
            }
            else {
                col.setCount(col.getCount()+1);
            }
        }   
        //输出Map的值
        Set<String> keys = letters.keySet();
        for (String key:keys) {
            Letter col = letters.get(key);
            System.out.println("字母"+key+",次数"+col.getCount());
        }

    }   
}

运行结果:

字母mice,次数1
字母that,次数1
字母cat,次数1
字母is,次数3
字母food,次数1
字母a,次数2
字母the,次数1
字母where,次数1
字母this,次数1
字母and,次数2

3、分拣思路+面向对象组合

package Genericity.Map;
/** * 学生 * @author liguodong * */
public class Student {
    private String name;//姓名
    private String no;//班号
    private double score;//分数
    public Student(String name, String no, double score) {
        super();
        this.name = name;
        this.no = no;
        this.score = score;
    }
    public Student() {
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getNo() {
        return no;
    }
    public void setNo(String no) {
        this.no = no;
    }
    public double getScore() {
        return score;
    }
    public void setScore(double score) {
        this.score = score;
    }
    @Override
    public String toString() {
        // TODO Auto-generated method stub
        return "Student [name=" + name +  ", no="+ no+", score="+score+"]";
    }
}
package Genericity.Map;

import java.util.ArrayList;
import java.util.List;

/** * 班级 */
public class ClassRoom {
    private String no;//班号
    private List<Student> stus;//学生列表 里面包括班号
    private double total;//总分 
    public ClassRoom() {        
        stus = new ArrayList<>();
    }
    public ClassRoom(String no) {
        this();
        this.no = no;   
    }

    public String getNo() {
        return no;
    }
    public void setNo(String no) {
        this.no = no;
    }
    public List<Student> getStus() {
        return stus;
    }
    public void setStus(List<Student> stus) {
        this.stus = stus;
    }
    public double getTotal() {
        return total;
    }
    public void setTotal(double total) {
        this.total = total;
    }
}
package Genericity.Map;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

/** * 定义一个Student类,属性:name 姓名 no班号,score成绩。 * 现将若干Student对象放入List,请统计出每个班级的总分和平均分,分别打印出来. */
public class MapDemo {

    public static void main(String[] args) {
        //学生列表
        List<Student> list = new ArrayList<>();
        //放入学生对象
        exam(list);
        //统计
        Map<String, ClassRoom> rooms = new HashMap<String, ClassRoom>();

        count(rooms,list);
        //打印
        printScore(rooms);
    }

    /** * 打印平均分 * @param rooms * @param list */
    public static void printScore(Map<String, ClassRoom> rooms){
        Set<Map.Entry<String,ClassRoom>>  entrySet = rooms.entrySet();
        Iterator<Map.Entry<String, ClassRoom>> it = entrySet.iterator();
        while(it.hasNext())
        {
            Map.Entry<String, ClassRoom> entry = it.next();
            ClassRoom room = entry.getValue();
            double avg = room.getTotal()/room.getStus().size();
            System.out.println("班号"+room.getNo()+",总分"+room.getTotal()+",平均分"+avg);
        }
    }
    //统计分数
    public static void count(Map<String,ClassRoom> rooms,List<Student> list)    {
        for(Student stu:list)       {
            String no = stu.getNo();//得到学生班号
            double score = stu.getScore();//得到分数

            //根据班级编号查看Map是否存在该班级 分拣思路 value= get(Key);
            ClassRoom room = rooms.get(no);
            if(null==room)//第一次
            {
                room = new ClassRoom(no);
                rooms.put(no,room);  //Map put(key,value)
            }           
            //存储
            room.setTotal(room.getTotal()+score);//加入总分
            //stus已经在构造函数中初始化了,这里直接加入即可。
            room.getStus().add(stu);//加入学生 
        }
    }

    //将student放入对象List
    public static void exam(List<Student> list)
    {
        list.add(new Student("a","001",80));
        list.add(new Student("b","002",30));
        list.add(new Student("c","001",40));
        list.add(new Student("d","004",60));
        list.add(new Student("e","005",70));

    }
}

运行结果:

班号004,总分60.0,平均分60.0
班号005,总分70.0,平均分70.0
班号001,总分120.0,平均分60.0
班号002,总分30.0,平均分30.0

原文链接:https://blog.csdn.net/scgaliguodong123_/article/details/45716377

本站声明:网站内容来源于网络,如有侵权,请联系我们,我们将及时处理。

未经允许不得转载:起风网 » Java 泛型
分享到: 生成海报

评论 抢沙发

评论前必须登录!

立即登录