不同Java泛型构造函数的详解

1.概述

我们之前讨论过Java Generics的基础知识。在本文中,我们将了解Java中的通用构造函数。
泛型构造函数是至少需要有一个泛型类型参数的构造函数。我们将看到泛型构造函数并不都是在泛型类中出现的,而且并非所有泛型类中的构造函数都必须是泛型。

2.非泛型类

首先,先写一个简单的类:Entry,它不是泛型类:

public class Entry {
private String data;
private int rank;
}

在这个类中,我们将添加两个构造函数:一个带有两个参数的基本构造函数和一个通用构造函数。

2.1 基本构造器

Entry第一个构造函数:带有两个参数的简单构造函数:

public Entry(String data, int rank) {
this.data = data;
this.rank = rank;
}

现在,让我们使用这个基本构造函数来创建一个Entry对象

@Test
public void givenNonGenericConstructor_whenCreateNonGenericEntry_thenOK() {
Entry entry = new Entry("sample", 1);
assertEquals("sample", entry.getData());
assertEquals(1, entry.getRank());
}

2.2 泛型构造器

接下来,第二个构造器是泛型构造器:

public <E extends Rankable & Serializable> Entry(E element) {
this.data = element.toString();
this.rank = element.getRank();
}

虽然Entry类不是通用的,但它有一个参数为E的泛型构造函数。

泛型类型E是受限制的,应该实现Rankable和Serializable接口。

现在,让我们看看Rankable接口,下面是其中一个方法:

public interface Rankable {
public int getRank();
}

假设我们有一个实现Rankable接口的类——Product

public class Product implements Rankable, Serializable {
private String name;
private double price;
private int sales;
public Product(String name, double price) {
this.name = name;
this.price = price;
}
@Override
public int getRank() {
return sales;
}
}

然后我们可以使用泛型构造函数和Product创建Entry对象:

@Test
public void givenGenericConstructor_whenCreateNonGenericEntry_thenOK() {
Product product = new Product("milk", 2.5);
product.setSales(30);
Entry entry = new Entry(product);
assertEquals(product.toString(), entry.getData());
assertEquals(30, entry.getRank());
}

3.泛型类

接下来,我们看一下泛型类:GenericEntry

public class GenericEntry<T> {
private T data;
private int rank;
}

我们将在此类中添加与上一节相同的两种类型的构造函数。

3.1 基础构造器

首先,让我们为GenericEntry类编写一个简单的非泛型构造函数:

public GenericEntry(int rank) {
this.rank = rank;
}

尽管GenericEntry是泛型类,但这是一个简单的,没有任何参数的构造函数。
现在,我们可以使用此构造函数来创建GenericEntry:

@Test
public void givenNonGenericConstructor_whenCreateGenericEntry_thenOK() {
GenericEntry<String> entry = new GenericEntry<String>(1);
assertNull(entry.getData());
assertEquals(1, entry.getRank());
}

3.2 泛型构造器

接下来,在类中添加第二个构造函数:

public GenericEntry(T data, int rank) {
this.data = data;
this.rank = rank;
}

这是一个泛型构造函数,它有一个泛型类型T的数据参数。注意,我们不需要在构造函数声明中添加,因为它是隐含的。
现在,让我们测试一下通用构造函数:

@Test
public void givenGenericConstructor_whenCreateGenericEntry_thenOK() {
GenericEntry<String> entry = new GenericEntry<String>("sample", 1);
assertEquals("sample", entry.getData());
assertEquals(1, entry.getRank());
}

4.不同类型的泛型构造函数

在泛型类中,还有一个构造函数,其泛型类型与类的泛型类型不同:

public <E extends Rankable & Serializable> GenericEntry(E element) {
this.data = (T) element;
this.rank = element.getRank();
}

GenericEntry构造函数有类型为E的参数,该参数与T类型不同。让我们看看它的实际效果:

@Test
public void givenGenericConstructorWithDifferentType_whenCreateGenericEntry_thenOK() {
Product product = new Product("milk", 2.5);
product.setSales(30);
GenericEntry<Serializable> entry = new GenericEntry<Serializable>(product);
assertEquals(product, entry.getData());
assertEquals(30, entry.getRank());
}

注意:在示例中,我们使用Product(E)创建Serializable(T)类型的GenericEntry,只有当类型E的参数可以转换为T时,我们才能使用此构造函数。

5.多种泛类型

接下来,我们有两个泛型类型参数的泛型类MapEntry:

public class MapEntry<K, V> {
private K key;
private V value;
public MapEntry(K key, V value) {
this.key = key;
this.value = value;
}
}

MapEntry有一个两个参数的泛型构造函数,每个参数都是不同的类型。让我们用一个简单的单元测试测试一下:

@Test
public void givenGenericConstructor_whenCreateGenericEntryWithTwoTypes_thenOK() {
MapEntry<String,Integer> entry = new MapEntry<String,Integer>("sample", 1);
assertEquals("sample", entry.getKey());
assertEquals(1, entry.getValue().intValue());
}

6.通配符

最后,我们可以在泛型构造函数中使用通配符:

public GenericEntry(Optional<? extends Rankable> optional) {
if (optional.isPresent()) {
this.data = (T) optional.get();
this.rank = optional.get().getRank();
}
}

在这儿,我们在GenericEntry构造函数中使用通配符来绑定Optional类型:

@Test
public void givenGenericConstructorWithWildCard_whenCreateGenericEntry_thenOK() {
Product product = new Product("milk", 2.5);
product.setSales(30);
Optional<Product> optional = Optional.of(product);
GenericEntry<Serializable> entry = new GenericEntry<Serializable>(optional);
assertEquals(product, entry.getData());
assertEquals(30, entry.getRank());
}

请注意,我们应该能够将可选参数类型(Product示例)转换为GenericEntry类型(Serializable示例)。

7.结束语

在本文中,我们学习了如何在泛型和非泛型类中定义和使用泛型构造函数。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • 简单理解java泛型的本质(非类型擦除)

    背景 之前在网上发现这个问题 public class GenericTest { //方法一 public static <T extends Comparable<T>> List<T> sort(List<T> list) { return Arrays.asList(list.toArray((T[]) new Comparable[list.size()])); } //方法二 public static <T extends Compara

  • 详解Java泛型及其应用

    引出泛型 我们通过如下的示例,引出为什么泛型的概念. public class Test { public static void main(String[] args) { List list = new ArrayList(); list.add("abc"); list.add(2); for (int i = 0; i < list.size(); i++) { String name = (String) list.get(i); // error System.out

  • java泛型基本知识及通用方法

    泛型的基本使用 泛型是Java SE 1.5的新特性, 泛型的本质是参数化类型, 也就是说所操作的数据类型被指定为一个参数. 这种参数类型可以用在类.接口和方法的创建中, 分别称为泛型类.泛型接口.泛型方法.  Java语言引入泛型的好处是安全简单. 今天就从以下几个方面介绍一下java的泛型: 基础, 泛型关键字, 泛型方法, 泛型类和接口. 基础: 通过集合的泛型了解泛型的基本使用 public void testBasis(){ List<String> list = new Array

  • Java构造函数与普通函数用法详解

    函数也被称为方法! 函数的作用及特点: 1.用于定义功能,将功能封装. 2.可以提高代码的复用性. 函数注意事项: 1.不能进行函数套用(不可以在函数内定义函数). 2.函数只有被调用才能被执行. 3.基本数据类型(String.int.-.)修饰的函数类型,要有return返回值. 4.void修饰的函数,函数中的return语句可以省略不写. 5.函数名可以根据需求进行命名. 代码示例:(有无函数/方法的区别) 无函数/方法代码例子: public class NoFunc { public

  • Java构造函数的相互调用代码示例

    在Java中,当为一个类创建了多个构造函数时,有时想在一个构造函数中调用另一个构造函数以减少代码量.这时可以使用this关键字来实现. 有关构造函数的相关内容,大家可以参阅:Java编程中的构造函数详细介绍 通常,当使用this关键字时,它意味着"这个对象"或者"当前对象",并且它自身产生对当前对象的引用.在一个构造函数中,当给传递给它一个参数列表时,它就有了不同的意义. 它将直接的调用能够匹配这个参数列表的构造函数.因此,我么可以直接的调用其它构造函数: pack

  • 深入理解Java中的构造函数引用和方法引用

    JDK 8 见证了一个特殊特性的出现:构造函数引用和方法引用.在本文中, Adrian D. Finlay 探讨了开发人员如何释放构造函数引用的真正潜力. 方法引用的一些背景 如果你还不知道 Java 构造函数本身就是特殊的方法,那么阅读方法引用的基本示例将对读者有所帮助,通过了解这些内容,可以了解构造函数引用是什么. 「方法引用为已经有名称的方法提供易读的 lambda 表达式.」 「它们提供了一种无需执行就可以引用方法的简单方式.」 以上引自<Java 8 编程参考官方教程(第 9 版)>

  • Java中泛型总结(推荐)

    Java 泛型(generics)是 JDK 5 中引入的一个新特性, 泛型提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型. 泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数. 泛型类 范例:泛型类的基本语法 class MyClass<T> { T value1; } 尖括号 <> 中的 T 被称作是类型参数,用于指代任何类型.实际上这个T你可以任意写,但出于规范的目的,Java还是建议我们用单个大写字母来代表类型参数.常见的如: T 代表

  • 不同Java泛型构造函数的详解

    1.概述 我们之前讨论过Java Generics的基础知识.在本文中,我们将了解Java中的通用构造函数. 泛型构造函数是至少需要有一个泛型类型参数的构造函数.我们将看到泛型构造函数并不都是在泛型类中出现的,而且并非所有泛型类中的构造函数都必须是泛型. 2.非泛型类 首先,先写一个简单的类:Entry,它不是泛型类: public class Entry { private String data; private int rank; } 在这个类中,我们将添加两个构造函数:一个带有两个参数的

  • Java 泛型总结及详解

    一. 泛型概念的提出(为什么需要泛型)? 首先,我们看下下面这段简短的代码: public class GenericTest { public static void main(String[] args) { List list = new ArrayList(); list.add("qqyumidi"); list.add("corn"); list.add(100); for (int i = 0; i < list.size(); i++) { S

  • java枚举类的构造函数实例详解

    java枚举类的构造函数实例详解 首先,给出一个例题如下: enum AccountType { SAVING, FIXED, CURRENT; private AccountType() { System.out.println("It is a account type"); } } class EnumOne { public static void main(String[]args) { System.out.println(AccountType.FIXED); } } T

  • java反射之通过反射了解集合泛型的本质(详解)

    本文接上文"java反射之方法反射的基本操作方法",利用反射了解下java集合中泛型的本质 1.初始化两个集合,一个使用泛型,一个不使用 ArrayList list1 = new ArrayList(); ArrayList<String> list2 = new ArrayList<String>(); 2.有定义类型可得在list2中添加int类型会报错 list2.add("Hello"); list2.add(20); //报错 3

  • Java中泛型的示例详解

    目录 泛型概述 使用泛型的好处 泛型的定义与使用 定义和使用含有泛型的类 含有泛型的方法 含有泛型的接口 泛型通配符 通配符基本使用 通配符高级使用----受限泛型 泛型概述 我们都知道集合中是可以存放任意对象的,只要把对象存储集合后,那么这时他们都会被提升成Object类型.当我们在取出每一个对象,并且进行相应的操作,这时必须采用类型转换. 大家观察下面代码: public class GenericDemo { public static void main(String[] args) {

  • Java RandomAccessFile的用法详解

    RandomAccessFile RandomAccessFile是用来访问那些保存数据记录的文件的,你就可以用seek( )方法来访问记录,并进行读写了.这些记录的大小不必相同:但是其大小和位置必须是可知的.但是该类仅限于操作文件. RandomAccessFile不属于InputStream和OutputStream类系的.实际上,除了实现DataInput和 DataOutput接口之外(DataInputStream和DataOutputStream也实现了这两个接口),它和这两个类系毫

  • Java中初始化块详解及实例代码

    Java中初始化块详解 在Java中,有两种初始化块:静态初始化块和非静态初始化块. 静态初始化块:使用static定义,当类装载到系统时执行一次.若在静态初始化块中想初始化变量,那仅能初始化类变量,即static修饰的数据成员. 非静态初始化块:在每个对象生成时都会被执行一次,可以初始化类的实例变量. 非静态初始化块会在构造函数执行时,且在构造函数主体代码执行之前被运行. 括号里的是初始化块,这里面的代码在创建Java对象时执行,而且在构造器之前执行! 其实初始化块就是构造器的补充,初始化块是

  • Java中的HashSet详解和使用示例_动力节点Java学院整理

    第1部分 HashSet介绍 HashSet 简介 HashSet 是一个没有重复元素的集合. 它是由HashMap实现的,不保证元素的顺序,而且HashSet允许使用 null 元素. HashSet是非同步的.如果多个线程同时访问一个哈希 set,而其中至少一个线程修改了该 set,那么它必须 保持外部同步.这通常是通过对自然封装该 set 的对象执行同步操作来完成的.如果不存在这样的对象,则应该使用 Collections.synchronizedSet 方法来"包装" set.

  • java 归并排序的实例详解

    java 归并排序的实例详解 归并排序 归并排序,指的是将两个已经排序的序列合并成一个序列的操作. 归并操作的过程如下: 申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列 设定两个指针,最初位置分别为两个已经排序序列的起始位置 比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置 重复步骤3直到某一指针到达序列尾 将另一序列剩下的所有元素直接复制到合并序列尾 Java代码 /** * 归并排序 * * @param ts */ @SuppressWa

  • Java File类的详解及简单实例

    Java File类的详解及简单实例 1. File():构造函数,一般是依据文件所在的指定位置来创建文件对象.  CanWrite():返回文件是否可写. CanRead():返回文件是否可读. CompareTo(File pathname):检查指定文件路径间的顺序. Delet():从文件系统内删除该文件. DeleteOnExit():程序顺利结束时从系统中删除文件. Equals(Object obj):检查特定对象的路径名是否相等. Exists():判断文件夹是否存在. GetA

随机推荐