侧边栏壁纸
  • 累计撰写 58 篇文章
  • 累计创建 67 个标签
  • 累计收到 1 条评论

Java 基础|泛型

lihaocheng
2019-03-03 / 0 评论 / 0 点赞 / 507 阅读 / 1,592 字
温馨提示:
晚上记得开启夜间模式哦

泛型是Java中允许程序员在强校验下定义某些可变部分,以达到代码复用的目的。

一、为什么要使用泛型?

假设我们有一个烤箱,烤箱可以用来烤面包、烤鱼甚至烤红薯。

假设面包、鱼这些食物在Java中都是一个个类,这个些类都继承于Food这个父类。

我们在烤箱类的烘烤方法中使用泛型,传入对应的类的实例就可以实现烘烤它的功能。

二、怎样使用泛型?

1.泛型类

HashMap 就是一个泛型类,通过传入的参数来定义 Key,Value 的数据类型。这里的 Key 和 Value 可以是 Java 已经提供的类型,如: String;也可以是你自己定义的类。

/ *
* <K> – the type of keys maintained by this map
* <V> – the type of mapped values
* /
public class HashMap<K,V> extends AbstractMap<K,V>
    implements Map<K,V>, Cloneable, Serializable {
}

例如,我们可以通过HashMap<String,String>来定义一个 key 和 value 都是 String 类型的 HashMap。
泛型类中的方法可以直接使用传入的泛型参数 K 和 V,下面的代码是 HashMap 中 get 方法的源码

public V get(Object key) {
        Node<K,V> e;
        return (e = getNode(hash(key), key)) == null ? null : e.value;
    }

由此可见在泛型类中我们可以直接使用 K 和 V 两个泛型参数,而不用像下面的泛型方法一样还是需要在方法名定义泛型。

2.泛型方法

直接使用泛型方法,下面我们定义的了一个烤的泛型方法,可以传入所有 Food 的子类。

    public <T extends Food>void kao(T a){
        T foodname=a;
        System.out.println(a+"被烤了");
    }

可以看到,泛型方法中的泛型 T 需要在方法的返回值(void)前面进行定义,泛型类中的方法不需要这样做。

3.泛型接口

public interface Map<K,V> {
}

上面展示了 Map 接口是如何定义泛型的,泛型接口的定义和泛型类十分相似。这里就不在赘述了。

总结

  1. 尖括号里的 ? 都指代一种未知类型
  2. 尖括号的位置非常讲究,必须在类名之后或方法返回值之前
  3. 泛型在定义处只具备执行Object方法的能力

当然Java语言中的泛型可以说是一种伪泛型,他仅仅是一种编写代码的语法检查,在编译时就可以看到他的原型。下面我们就来讨论一下,什么是伪泛型?

三、泛型原理

我们可以通过查看编译之后的 Java 字节码来查看泛型是如何被实现的。
既然 Java 中的所有类都继承自 Object 类,那么为什么不直接使用 Object 来定义泛型呢?
其实 Java 内部就是这样实现泛型的,Java 编译器会将 T 擦出,使用 Object,并加上必要的类型转换。
而 Java 虚拟机在运行时是完全不知道泛型这回事的。

至于为什么不直接使用 Object 类,本质上还是——如果使用 Object 类来描述泛型的话代码就更复杂了。
其次,使用 Java 泛型可以在编译前就发现问题。
也可以说,Java 为我们提供了一种简单的定义泛型的方式。

参考资料

[1] 《Java编程的逻辑》
[2] 《码出高效——Java开发手册》
[3] 极客时间 《Java核心技术36讲》

0
博主关闭了当前页面的评论