java8泛型

目录

  • 1,泛型中的相关操作符
  • 2,泛型基本使用示例
  • 3,通配符
    • 3.1, T和?的区别
    • 3.2,上下界通配符
  • 4, 附加约束(&)

?

泛型,也就是将类型参数化,然后在使用类或者方法的时候可以传入类型,在不需要创建新类型实现的前提下可以通过泛型控制形参的类型。泛型可以用在类,方法和接口中。

1,泛型中的相关操作符

? 在使用泛型的代码中经常可以看到一些泛型相关的符号,它们的作用如下表所示:

类型 功能
T,E,K,V 泛型标识,可以写人任意标识,不同字母更多是一种约定,等同于< T extends Object>
? 无限制通配符,表示不确定类型,等同于< ? extends Object>
extend 上界通配符
super 下界通配符
& 附加约束(AdditionalBound, tjls8-4.4)

2,泛型基本使用示例

public class GenericDemo<C> { //泛型类

    public static void main(String[] args) {
        //泛型类用Integer初始化,所以C相关的方法属性必须是Integer
        GenericDemo<Integer> gd = new GenericDemo<Integer>();
        gd.classPrint(1);
        gd.setX(2);
        //----------------------
        //泛型方法,与调用的类型保持一致,参数类型得为String
        GenericDemo.<String>methodPrint("abc");
        //---------------------
        //泛型接口,与初始化时候传入的类型保持一致,参数类型得是Double
        IFC<Double> ifc = new IFC<Double>() {};
        ifc.interfacePrint(2.9);
    }

    private C c;

    public void setX(C c) {
        this.c = c;
    }
        public void classPrint(C c) {
        System.out.println(c.getClass());
    }

    //泛型方法,前面的<T>是为了标识这是一个泛型方法
    public static <T> void methodPrint(T t) {
        System.out.println(t.getClass());
    }

    interface IFC<I> { //泛型接口
        default void interfacePrint(I i) { System.out.println(i.getClass());}
    }
}

3,通配符

3.1, T和?的区别

基本泛型T是用于定义,将数据类型参数化,不能用于实例化。而 ? 则是在实例化对象时不确定泛型具体参数类型的时候泛指Object的所有子类型。

类型 特点
T < T extends Object>,用于定义
? < ? extends Object>,用于实例化

?不能和Object等效,?是类型实参而不是类型形参,它用于泛指各种类型实参,当具体类型不确定的时候就可以使用?,示例如下:

public class test6 {
    public static void main(String[] args) {
        List<String> list1 = new ArrayList<>();
        List<Integer> list2 = new ArrayList<>();
        test(list1);
        test(list2);
    }

    public static void test(List<?> list) {
        System.out.println(list);
    }
}

3.2,上下界通配符

上下界通配符其实涉及到java 的多态属性,上下转型的可行性,子类实例可以转换成父类实例,但是父类实例却不一定能转换成子类实例,只有本身就是该子类实例向上转型的父类实例才可以向下转型为子类实例。

<? extends T> 表示类型范围为T以及其子类,<? super T>表示类型范围为T及其父类。

界限通配符在应用于集合的时候会影响集合的读写行为:

上界<? extends T> 限制了类型上限,只能向上转型,可以读,但是没法写,因为子类型不确定,没法向下转型;

下界<? super T>限制类型的下限,只能向下转型,可以写,但是没法读,因为父类型不确定,没法向上转型。

示例:

public class test {

    public static void main(String[] args) {
        //<? extends B> 范围: A类或者A的子类
        //由于下限不确定,所以无法向下转型至具体类型
        List<? extends B> list1 = new ArrayList<B>(){{add(new B());}};
//        list1.add(new B()); //无法添加该类型, 向下转型无法确定目标类型
//        list1.add(new C());
        A a = list1.get(0); //正常向上转型

        //<? super B> 范围: B类或者B的父类
        //由于上限不确定,所以B类和B类的子类均可以加入,但是B类的父类不行
        List<? super B> list2 = new ArrayList<>();
//        list2.add(new A()); //无法向下转型
        list2.add(new B()); //正常向上转型
        list2.add(new C());
//        C c = list2.get(0);//无法向下转型,不加强制转换会报错
        C c = (C)list2.get(0);
    }
    //   A -> B -> C
    static class A {};
    static class B extends A {};
    static class C extends B {};
}

4, 附加约束(&)

AdditionalBound 的语法如下:

TypeBound:
extends ClassOrInterfaceType {AdditionalBound}
AdditionalBound:
& InterfaceType

也就是说extends后面可以在加个额外约束,具体为接口类型,可以I1 & I2 & I3这样连排,注意必须是接口类型,不能是class或者类型变量,这里额外约束的作用是限制类型必须实现相关的接口,示例如下:

public class test {

    public static void main(String[] args) {
        test1(1); test1("1");
        test2(2); test2("2");
//        test3(3);  //test3方法String类型才满足额外约束
        test3("3");
    }

    public static <T extends Object> void test1(T t) {
        System.out.println(t.getClass());
    }
    //得同时实现Serializable和Comparable接口
    public static <T extends Object & Serializable & Comparable> void test2(T t) {
        System.out.println(t.getClass());
    }
    //得同时实现Serializable,CharSequence和Comparable接口
    public static <T extends Object & Serializable & CharSequence & Comparable> void test3(T t) {
        System.out.println(t.getClass());
    }
}

此外,附加约束还可用于类型强制转换:

public class test12 {
    public static void main(String[] args) {
        System.out.println(test());
    }
    public static Object test() {
//        return (Object & Number)"abced"; //编译不通过
//        return (Object)"abced"; //编译通过
        return (Object & CharSequence & Comparable)"abcde"; //编译通过
    }
}

在一些类型转换的场景可以通过附加约束控制类型转换的范围。

参考链接:

https://codeday.me/bug/20190313/767875.html

https://juejin.im/post/5b614848e51d45355d51f792

https://www.cnblogs.com/whatlonelytear/p/11055126.html

https://blog.csdn.net/s10461/article/details/53941091

https://blog.csdn.net/claram/article/details/51943742

原文地址:https://www.cnblogs.com/cord/p/11616353.html

时间: 2024-10-20 21:32:46

java8泛型的相关文章

java8 泛型声明 The diamond operator (&quot;&lt;&gt;&quot;) should be used

The diamond operator ("<>") should be used Java 7 introduced the diamond operator (<>) to reduce the verbosity of generics code. For instance, instead of having to declare a List's type in both its declaration and its constructor, yo

java8之stream

lambda表达式是stream的基础,初学者建议先学习lambda表达式,http://www.cnblogs.com/andywithu/p/7357069.html 1.初识stream 先来一个总纲: 东西就是这么多啦,stream是java8中加入的一个非常实用的功能,最初看时以为是io中的流(其实一点关系都没有),让我们先来看一个小例子感受一下: @Before public void init() { random = new Random(); stuList = new Arr

【java代码之美】---Java8 Stream

Stream 第一次看到Stream表达式就深深把我吸引,用它可以使你的代码更加整洁而且对集合的操作效率也会大大提高,如果你还没有用到java8的Stream特性,那就说明你确实out啦. 一.概述 1.什么是Stream Stream是一种可供流式操作的数据视图有些类似数据库中视图的概念它不改变源数据集合如果对其进行改变的操作它会返回一个新的数据集合. 总的来讲它有三大特性:在之后我们会对照着详细说明        1.stream不存储数据        2.stream不改变源数据    

Java8基础之泛型

泛型工作原理 Java中的泛型都是编译器层面来完成的,在生成的Java字节码中是不包含任何泛型中的类型信息的.使用泛型时加上的类型参数,会在编译时被编译器去掉.也就是说Java中的泛型,只在编译阶段有效.在编译过程中,正确检验泛型结果后,会将泛型的相关信息擦出,并且在对象进入和离开方法的边界处添加类型检查和类型转换的方法. 测试一下 原文地址:https://www.cnblogs.com/feiqiangsheng/p/11125726.html

Java8基础知识(九)泛型

泛型 在增加泛型类前,泛型程序设计是用继承实现的,要将方法参数和域的类型设计为Object,通过强制类型转换实现设计.由于Object在编译阶段几乎不会报错,所以很难通过静态类型检查发现这种设计下隐藏的错误. 使用类型参数后,通过编译器就可以检测提供的参数类型是否错误,使程序具有更好的可读性和安全性. 但实现泛型类也存在一定的困难,因为设计的方法同样要对所有的类型都能够编译且正确运行. // 已知在ArrayList中设计addAll方法来向当前list中添加另一个list的所有元素 Array

Java8基础知识(十)泛型的约束与局限性

泛型的约束与局限性 由于泛型是通过类型擦除.强制类型转换和桥方法来实现的,所以存在某些局限(大多来自于擦除). 不能使用基本类型实例化类型参数 类型参数都是类,要用包装器将基本类型包装才可以作为类型参数(原因在于擦除类型后Object类不能存储基本类型的值).当包装器类不能接受类型参数替换时,可以使用独立的类和方法进行处理. 运行时类型查询只适用于原始类型 由于虚拟机中的对象都有特定的原始类型,所以类型查询只能查询原始类型. // 只能测试a是否为某种Pair类型 if (a instanceo

java5、java6、java7、java8的新特性

Java5: 1.泛型 Generics:        引用泛型之后,允许指定集合里元素的类型,免去了强制类型转换,并且能在编译时刻进行类型检查的好处. Parameterized Type作为参数和返回值,Generic是vararg.annotation.enumeration.collection的基石. A.类型安全 抛弃List.Map,使用List<T>.Map<K,V>给它们添加元素或者使用Iterator<T>遍历时,编译期就可以给你检查出类型错误 B

Java泛型学习

先引用一段Java编程思想中的一段话 Java泛型的核心概念:告诉编译器你想使用什么类型,然后编译器帮你处理一切细节. 关于类型推断: 类型推断只对赋值操作有效,其他时候并不起作用.如果你见过一个泛型方法调用的结果 作为参数传递给另一个方法,这时编译器不会执行类型推断.在这种情况下,编译器认为:调用泛型 方法后,其返回值被付给了一个Object变量.当然现在在Java8先已经可以了

java8 十大新特性

这篇文章是对Java 8中即将到来的改进做一个面向开发者的综合性的总结,JDK的这一特性将会在2013年9月份发布. 在写这篇文章的时候,Java 8的开发工作仍然在紧张有序的进行中,语言特新和API仍然有可能改变,我会尽我最大的努力保持这份文档跟得到Java 8的改动. Java 8的预览版,也就是 “Project Lambda”,现在可以从java.net下载到. 我使用了IntelliJ的预览版做我的IDE,在我看来他是目前支持java 8特性最好的一个IDE,你可以从这里下载到. 由于