泛型

1、泛型的概念

泛型的出现,可以让我们少些代码,它的主要作用是解决类型的安全问题,不会因为将对象置于某个容器中而失去其类型。在泛型出现之前,Java提供了对Object类型引用的任意操作,即向上转型和向下转型,上转型没问题,但是向下转型这种强制类型转换是存在隐患的,因此Java提供了泛型机制。

Java泛型(generics)是JDK5中引入的一个新特性, 泛型提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型。泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。

泛型并不是一种数据类型,而是一种特殊语法,对接收的数据类型进行了规定。如Map<String,String> map = new HashMap()。只允许字符串类型数据作为Map集合的value值,不接受其他数据类型。使用泛型的好处是在代码书写过程中可提高效率和数据类型安全,规避因数据类型不符合要求而造成的编译错误,最突出的是避免了数据对象强制转换,支持动态下确定数据类型。通常在集合中使用泛型。

以一个例子说明。

定义一个实体类:

public class T1 {

    private Object obj;

    public Object getObj() {
        return obj;
    }

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

}

测试:

    public static void main(String[] args) {
        T1 t = new T1();
        // 上转型
        t.setObj(new Boolean(true));
        System.out.println(t.getObj());
        T1 t2 = new T1();
        t2.setObj(new Float(25.5));
        // 强制转换
        Integer res = (Integer) t2.getObj();
        System.out.println(res);
    }

执行,控制台:
在这里插入图片描述
类型转换错误,Float类型不能强制转换成Integer类型,这是不允许的,但是编译的时候并没有报错,这时候可以用泛型有效的解决这种向下转型的类型安全问题。

2、定义泛型类

泛型类的定义很简单,语法如下:

类名 <T>

使用泛型的好处就是不用再进行强制转换了,也就不存在发生类型转换错误。以下用例子说明。

定义一个泛型类T2:

/*
 * 定义泛型类
 * 类型用T表示
 */
public class T2<T> {

    // 这个obj没有定义成具体类型
    private T obj;

    public T getObj() {
        return obj;
    }

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

}

测试:

    public static void main(String[] args) {
        // 传入Boolean类型作为参数
        T2<Boolean> t0 = new T2<>();
        t0.setObj(true);
        Boolean b = t0.getObj();
        System.out.println(b);
        // 传入Float类型作为参数
        T2<Float> t2 = new T2<>();
        t2.setObj(25.5f);
        Float f = t2.getObj();
        System.out.println(f);
    }

控制台:
在这里插入图片描述

3、声明多个类型

在定义泛型类的时候,可以同时声明多个类型,语法如下:

类名 <类型1,类型2>

以下代码说明:

public class T3<Integer, Boolean> {

    private Boolean single;

    private Integer age;

    public Boolean getSingle() {
        return single;
    }

    public void setSingle(Boolean single) {
        this.single = single;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

}

测试:

    public static void main(String[] args) {
        T3<Integer, Boolean> t = new T3<>();
        t.setSingle(true);
        t.setAge(25);
        System.out.println("年龄:" + t.getAge());
        System.out.println("是单身吗?" + t.getSingle());
    }

控制台:
在这里插入图片描述

4、声明数组类型

在定义泛型的时候可以声明为数组类型,但是不能使用泛型机制来建立数组实例。代码如下:

public class T4<T> {

    //这个数组的类型为T
    private T[] arrays;

    public T[] getArrays() {
        return arrays;
    }

    public void setArrays(T[] arrays) {
        this.arrays = arrays;
    }

}

测试:

    public static void main(String[] args) {
        T4<Integer> t = new T4<>();
        Integer[] num = new Integer[] {1, 4, 3, 123, 45 };
        t.setArrays(num);
        System.out.println("数组中的元素如下:");
        for (Integer i : t.getArrays()) {
            System.out.print(i + "\t");
        }
        System.out.println();
        System.out.println("--------------------------------");
        T4<String> t2 = new T4<>();
        String[] str = new String[] {"yan", "cheng", "zhi", "yun" };
        t2.setArrays(str);
        System.out.println("数组中的元素如下:");
        for (String s : t2.getArrays()) {
            System.out.print(s + "\t");
        }
    }

控制台:
在这里插入图片描述

5、声明集合类的容器元素

可以使用K代表键,V代表值。如下:

public class T5<K, V> {

    public Map<K, V> map = new HashMap<>();

    // 设置put方法
    public void put(K k, V v) {
        map.put(k, v);
    }

    // 设置get方法
    public V get(K k) {
        return map.get(k);
    }

    public Map<K, V> getMap() {
        return map;
    }

    public void setMap(Map<K, V> map) {
        this.map = map;
    }

}

测试:

    public static void main(String[] args) {
        T5<String, Integer> t = new T5<>();
        for (int i = 1; i <= 5; i++) {
            t.put("第" + i + "个元素", i);
        }
        Set<Entry<String, Integer>> set = t.getMap().entrySet();
        for (Entry<String, Integer> entry : set) {
            System.out.println(entry.getKey() + "\t" + entry.getValue() + "\n");
        }
    }

控制台:
在这里插入图片描述
事实上,这种是多余的,因为Java的集合框架已经泛型化了,直接使用就行了,不用这么麻烦的定义。

6、限制泛型可用类型

默认的可以使用任何的类型来实例化一个泛型对象,但是也可以做出限制,规定可以使用哪些类型来实例化对象。语法如下:

类名 <T extends 类型>

使用泛型限制以后,只有继承了规定的类型或实现了这个接口的类才能作为泛型的参数,以下代码说明:

/*
 * 限制泛型参数类型
 */
public class T6<T extends List> {

    public static void main(String[] args) {
        // ArrayList实现了List接口,可以作为泛型参数
        T6<ArrayList> t = new T6<>();
        // LinkedList实现了List接口,可以作为泛型参数
        T6<LinkedList> t2 = new T6<>();
        // Vector实现了List接口,可以作为泛型参数
        T6<Vector> t3 = new T6<>();
        // 不接受Integer类型作为泛型参数
        // T6<Integer> t4 = new T6<>();
        // 不接受String类型作为泛型参数
        // T6<String> t4 = new T6<>();
    }

}

7、使用类型通配符

在泛型机制中,提供类的通配符?。通配符应用较少,有需求时才使用,不必要时可不用,采用泛型可满足要求即可。

    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("yan");
        list.add("cheng");
        list.add("zhi");
        List<?> list2 = list;
        System.out.println("list2集合大小为:" + list2.size());
        for (Object o : list2) {
            System.out.print(o.toString() + "\t");
        }
        System.out.println();
        List<Integer> list3 = new ArrayList<>();
        System.out.println("list3集合大小为:" + list3.size());
        //list2集合会被覆盖掉
        list2 = list3;
        System.out.println("list2集合大小为:" + list2.size());
    }

在这里插入图片描述

8、泛型接口

也可以定义泛型的接口,像定义泛型类一样。如下:

/*
 * 定义泛型接口
 */
public interface TestDao<T> {
    
    void save(T t);

}

接口的实现类:

public class TestDaoImpl<T> implements TestDao<T> {

    @Override
    public void save(T t) {
        // TODO Auto-generated method stub

    }

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值