文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

怎么理解Java/Scala泛型

2023-06-16 14:46

关注

本篇内容介绍了“怎么理解Java/Scala泛型”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

泛型(Generics)是强类型编程语言中经常使用的一种技术。很多框架的代码中都会大量使用到泛型,比如在Java中我们经常看到的:

List<String> strList = new ArrayList<String>();List<Double> doubleList = new LinkedList<Double>();

在这段代码中,ArrayList就是一个泛型类,List就是一个泛型接口类,他们提供给开发者一个放置不同类型的集合容器,我们可以向这个集合容器中添加String、Double以及其他各类数据类型。无论内部存储的是什么类型,集合容器提供给开发者的功能都是相同的,比如添加add,get等。有了泛型,我们就没必要创建StringArrayList、DoubleArrayList等集合了,否则代码量太大,维护起来成本极高。

在Java中,泛型一般有三种使用方式:泛型类,泛型方法和泛型接口类。一般使用尖括号<>来接收泛型参数。

Java泛型类

假如我们自己定义一个支持泛型的MyArrayList,这个列表类可以简单支持初始化和数据写入。只要在类名后面加上就可以让这个类支持泛型,类内部的一些属性和方法都可以使用泛型类型T。当然我们给这个类也可以添加多个泛型参数,比如

public class MyArrayList<T> {    private int size;    T[] elements;    public MyArrayList(int capacity) {        this.size = capacity;        this.elements = (T[]) new Object[capacity];    }    public void set(T element, int position) {        elements[position] = element;    }    @Override    public String toString() {        String result = "";        for (int i = 0; i < size; i++) {            result += elements[i].toString();        }        return result;    }    public static void main(String[] args){        MyArrayList<String> strList = new MyArrayList<String>(2);        strList.set("first", 0);        strList.set("second", 1);        System.out.println(strList.toString());    }}

我们也可以从父类中继承并扩展泛型,比如Flink源码中有这样一个类定义,子类继承了父类的T,同时自己增加了泛型KEY:

public class KeyedStream<T, KEY> extends DataStream<T> {  ...}

Java泛型接口类

Java泛型接口类的定义和Java泛型类基本相同。下面的代码展示了List接口中定义subList方法,该方法截取原来列表的一部分。

public interface List<E> {    ...    public List<E> subList(int fromIndex, int toIndex);}

继承并实现这个接口类的代码如下:

public class ArrayList<E> implements List<E> {    ...    public List<E> subList(int fromIndex, int toIndex) {        subListRangeCheck(fromIndex, toIndex, size);        return new SubList(this, 0, fromIndex, toIndex);    }}

Java泛型方法

泛型方法可以存在于泛型类(包括接口类)中,也可以存在于普通的类中。

public class MyArrayList<T> {    ...    // public关键字和返回值E之间的<E>表明这是一个泛型方法    // 泛型方法中的类型E和泛型类中的类型T可以不一样  public <E> E processElement(E element) {        ...        return E;    }}

从上面的代码示例可以看出,public或private关键字和方法返回值之间的尖括号表示这是一个泛型方法。泛型方法的类型E和泛型类中的T可以不一样,或者说,如果泛型方法是泛型类的一个成员,泛型方法既可以继续使用类中的T,也可以自己定义新的类型E。

通配符

除了用表示泛型外,还有 这种形式。 被称为通配符,用来适应各种不同的泛型。

泛型小结

对Java的泛型总结下来发现,虽然它的语法有时候让人有些眼花缭乱,其本质是为了接受不同的数据类型,增强代码的复用性。

我们可以在一个类里使用多个泛型,每个泛型一般使用大写字母表示。Java为此提供了一些大写字母使用规范:

Java的泛型给开发者提供了不少便利,尤其是保证了底层代码简洁性,因为这些底层代码通常被封装为一个框架,会有各种各样的上层应用调用这些底层代码进行特定的业务处理,每次调用都可能涉及泛型问题。比如,大数据框架Spark和Flink中都需要开发者基于泛型进行数据处理。

以上只对泛型做了一个简单的介绍,实际上在具体使用时还有一些细节需要注意。

类型擦除

Java的泛型有一个遗留问题,那就是类型擦除(Type Erasure)。我们先看一下下面的代码:

Class<?> strListClass = new ArrayList<String>().getClass();Class<?> intListClass = new ArrayList<Integer>().getClass();// 输出:class java.util.ArrayListSystem.out.println(strListClass);// 输出:class java.util.ArrayListSystem.out.println(intListClass);// 输出:trueSystem.out.println(strListClass.equals(intListClass));

虽然声明时我们分别使用了String和Integer,但运行时关于泛型的信息被擦除了,我们无法区别strListClass和intListClass这两个类型。这是因为,泛型信息只存在于代码编译阶段,当程序运行到JVM上时,与泛型相关的信息会被擦除掉。类型擦除对于绝大多数应用系统开发者来说关系不太大,但是对于一些框架开发者来说,必须要注意。比如,Spark和Flink的开发者都使用了一些办法来解决类型擦除问题,对于API调用者来说,受到的影响不大。

Scala中的泛型

对Java的泛型有了基本了解后,我们接着来了解一下Scala中的泛型。相比而言,Scala的类型系统更复杂,本文只介绍一些简单语法,帮助读者能够读懂一些源码。

Scala中,泛型放在了中括号[]中。或者我们可以简单地理解为,原来Java的泛型类,现在改为[T]即可。

我们创建一个Stack[T]的泛型类,并实现了两个简单的方法,类中各成员和方法都可以使用泛型T。我们也定义了泛型方法,形如isStackPeekEquals[T],方法中可以使用泛型T。

object MyStackDemo {  // Stack泛型类  class Stack[T] {   private var elements: List[T] = Nil   def push(x: T) { elements = x :: elements }   def peek: T = elements.head  }  // 泛型方法,检查两个Stack顶部是否相同  def isStackPeekEquals[T](p: Stack[T], q: Stack[T]): Boolean = {   p.peek == q.peek  }  def main(args: Array[String]): Unit = {    val stack = new Stack[Int]    stack.push(1)    stack.push(2)    println(stack.peek)    val stack2 = new Stack[Int]    stack2.push(2)    val stack3 = new Stack[Int]    stack3.push(3)    println(isStackPeekEquals(stack, stack2))    println(isStackPeekEquals(stack, stack3))  }}

“怎么理解Java/Scala泛型”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注编程网网站,小编将为大家输出更多高质量的实用文章!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     801人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     348人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     311人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     432人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     220人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯