再谈泛型java---上

泛型入门

在JDK1.5以前是没有泛型的,那么我们通常是怎么做的呢?

public class LessJDK5Demo {
    public static void main(String[] args) {
        List list=new ArrayList();
        User user=new User(1,"zhangsan");
        list.add(user);
        User u=(User)list.get(0);
        System.out.println(u);
    }
}

可以看得出来,每次从list里取数据的时候,需要强制转换,所以这里就很容易报异常:ClassCastException.

1

编译时不检查类型的异常

public static void main(String[] args) {
        List list=new ArrayList();
        list.add("Java后端技术栈");
        list.add(1);
        System.out.println((String) list.get(1));
    }

运行:

Exception in thread "main" java.lang.ClassCastException: 
  java.lang.Integer cannot be cast to java.lang.String
  at com.lawt.swaggerdemo.generic.LessJDK5Demo.main(LessJDK5Demo.java:18)

2

使用泛型

JDK1.5以后引入了“参数化类型”的概念,运行程序在创建集合的时候指定集合元素的类型,比如:List<String> 说明这个list只能存放字符类型的对象,Java的参数化类型被称为泛型

public class LessJDK5Demo {
    public static void main(String[] args) {
        List<String> list=new ArrayList<String>();
        list.add("Java后端技术栈");
        list.add(1);
        list.forEach(str-> System.out.println(str.length()));
    }
}

这样就保证了不会出现类型强转异常。

3

增强的菱形语法

在JDK1.7以前,如果使用带泛型的接口、类定义变量,那么调用构造器创建对象时构造器的后面必须带泛型,这样有点闲的多余,比如以下两个使用案例:

List<String> strings=new ArrayList<String>();
Map<String ,Integer> map=new HashMap<String ,Integer>(2);

从JDK1.7开始,上面的两个使用案例可以改写成:

//Java自动推断出ArrayList的<>里应该是String
List<String> strings=new ArrayList<>();
Map<String ,Integer> map=new HashMap<>(2);

以上把两个尖括号并排放在一起非常想菱形,所以这里也就被称之为“菱形”语法。

JDK1.8对菱形语法做了增加,它甚至允许在创建匿名内部类的时候使用菱形语法,Java课根据上下问推断匿名内部类中泛型的类型,比如:

interface Foo<T>{
   void  test(T t);
}
public class Test {
    public static void main(String[] args) {
        Foo<String> f=new Foo<String>() {
            @Override
            public void test(String s) {
                System.out.println(s);
            }
        };
        Foo<?> foo1=new Foo<Object>() {
            @Override
            public void test(Object o) {
                System.out.println(o);
            }
        };
        Foo<? extends Number> fn=new Foo<Number>() {
            @Override
            public void test(Number number) {
                System.out.println(number);
            }
        };
    }
}

深入泛型

所谓泛型:就是允许在定义类、接口、方法时使用类型参数,这个类型参数(泛型)将在声明变量、创建对象、调用方法时动态指定(即时传入实际的类型参数)。

1

定义泛型接口、类

以下是JDK1.5版本改写后List/Set/Map的代码片段:

//定义接口时指定了一个泛型形参,该形参为E
public interface List<E> {
  //在该接口里,E可作为类型使用
   Iterator<E> iterator();
    <T> T[] toArray(T[] a);
    //...
}
public interface Set<E> {
   boolean add(E e);
   //.....
}
public interface Map<K,V> {
  V put(K key, V value);
  //....
}

上面三个接口声明是比较简单的,除了尖括号中内容---这就是泛型的实质:允许在定义接口、类时声明泛型形参,泛型形参在整个接口、类体重可当成类型使用,几乎所有可使用普通类型的地方都可以使用这种泛型参型。

比如:前面的List类型时,,如果E形参传入String类型实参,则可以理解为产生了一个新类:List<String>类型,或者可以想象成生成了一个逻辑上的子类。比如:

public interface ListString  extends List{
    void add(String str);
    //.....
}

这里只是逻辑上子类,并不是物理上的。

注意

包含泛型声明的类型可以在定义变量、创建对象时传入一个类型实参,从而可以动态低生成多个逻辑上的子类,但是这种子类在物理上并不存在。

2

从泛型派生子类

public class Person<T> {
    private T info;

    public Person(T info) {
        this.info = info;
    }
    //get set ....
}

第一种方式:原始类型

public class Sub extends Person {
    public Sub(Object info) {
        super(info);
    }
}

就是说不为其指定类型也是可以的。

第二种:指定泛型参数

public class Doc extends Person<String> {
    public Doc(String info) {
        super(info);
    }
}

以上是指定泛型类型为String类型。

3

并不存在泛型类

前面说过List<String>,可以理解为List生成了一个子类List<String>,事实上也很像一个特殊List类,该List只能添加Sting的集合。但是实际上系统根本没有生成什么子类class文件,而且也不把List<String>当做一个新类来处理。为什么呢?下面的代码就是很好解释:

 List<String> strings=new ArrayList<>();
 List<Integer> integers=new ArrayList<>();
 System.out.println(strings.getClass()==integers.getClass());

如果真的生成了一个新class类,那么,上面应该输出false,但是实际上输出的是true。

全部写完篇幅会很长,所以留到《再谈Java泛型---下》中继续扯;

既然在看了,就点一下吧!!

本文分享自微信公众号 - Java后端技术栈(t-j20120622),作者:Java后端技术栈

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-06-09

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 如何更规范的写Java代码

    如何更规范化编写Java 代码的重要性想必毋需多言,其中最重要的几点当属提高代码性能、使代码远离Bug、令代码更优雅。

    用户4143945
  • 99%的java程序员都遇到过的笔试题

    这里咱们忽略空格,所以答案就是B,主要的是本道题考察的是Java语言中传参方式和不可变类的知识。

    用户4143945
  • 再谈Java泛型---下

    表面上看起来没什么问题,这个方法声明确实没有任何问题,但问题是调用该方法传入的实际参数时可能不是我们所期望的,例如:

    用户4143945
  • 使用Apache Common CSV读写CSV文件

    jar包下载地址:http://commons.apache.org/proper/commons-csv/,点击Download进行下载!

    卡尔曼和玻尔兹曼谁曼
  • 聊聊nacos client的MetricsMonitor

    nacos-1.1.3/client/src/main/java/com/alibaba/nacos/client/monitor/MetricsMonitor...

    codecraft
  • 聊聊nacos client的MetricsMonitor

    nacos-1.1.3/client/src/main/java/com/alibaba/nacos/client/monitor/MetricsMonitor...

    codecraft
  • 【J2SE快速进阶】——Java中的equals和==的区别

    版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/huyuyang6688/article/...

    DannyHoo
  • 企业API接口设计(token、timestamp、sign)之具体实现

    Token:访问令牌access token, 用于接口中, 用于标识接口调用者的身份、凭证,减少用户名和密码的传输次数。一般情况下客户端(接口调用方)需要先向...

    lyb-geek
  • 设计模式之观察者模式及典型应用

    微信公众号有服务号、订阅号和企业号之分。以我的公众号为例,我的公众号类型是订阅号,名称是 "小旋锋",专注于大数据,Java后端类技术分享。目前主要是分享学习笔...

    小旋锋
  • Java 泛型

    1、泛型的由来   我们先看下面这段代码: List list = new ArrayList(); list.add(24...

    IT可乐

扫码关注云+社区

领取腾讯云代金券