首页 Java java教程 Java--泛型

Java--泛型

Jun 27, 2017 am 09:13 AM
泛型

 

类型参数

 

在定义泛型类或声明泛型类的变量时,使用尖括号来指定形式类型参数。形式类型参数与实际类型参数之间的关系类似于形式方法参数与实际方法参数之间的关系,只是类型参数表示类型,而不是表示值。

命名类型参数

推荐的命名约定是使用大写的单个字母名称作为类型参数。这与 C++ 约定有所不同(参阅 附录 A:与 C++ 模板的比较),并反映了大多数泛型类将具有少量类型参数的假定。对于常见的泛型模式,推荐的名称是:

K —— 键,比如映射的键。 
V —— 值,比如 List 和 Set 的内容,或者 Map 中的值。 
E —— 异常类。 
T —— 泛型

方法签名由方法名称和一个参数列表(方法的参数的顺序和类型)组成。
登录后复制

 

1.为什么要用泛型

     1.对放进去的元素没有限制,放进两种不同的对象,可能会引起异常。

      2.把对象丢进集合,集合丢失了对象的状态信息,集合只知道它盛放的是Object、因此取出集合元素后通常还需要进行强制转换

2.什么是泛型

    Java的参数化类型被称为泛型,允许程序在创建集合的时候指定集合元素的类型

3.泛型的菱形语法

后面只需要带一对菱形括号,不需要再带泛型

4.创建带泛型声明的自定义类,为该类定义构造器时,构造器名还是原来的类名,不要增加泛型声明。

5.从泛型类派生子类,继承的时候必须为父类传入实际的参数

public class A extends Apple{}

里面所有重写父类的方法变成相应的类型

也可以不传入实际的参数

public class A extends Apple{}

当成Obejct类型处理

6.并不存在泛型类

  不管泛型的实际类型参数是什么,他们在运行时总有同样的类。不管泛型的类型形参传入哪一种类型实参,(在于Java中的泛型这一概念提出的目的,导致其只是作用于代码编译阶段,在编译过程中,对于正确检验泛型结果后,会将泛型的相关信息擦出,也就是说,成功编译过后的class文件中是不包含任何泛型信息的。泛型信息不会进入到运行时阶段。)对于Java来说,他们依然被当成同一个类处理,在内存中也占一块内存空间9,因此在静态方法,静态初始化块或者静态变量的声明和初始化中不允许使用类型形参

           解释:

静态变量是被泛型类所有实例所共享的。对于声明为MyClass的类,访问其中的静态变量的方法仍然是MyClass.myStaticVar。不管是通过new MyClass还是new MyClass创建的对象,都是共享一个静态变量。假设允许类型参数作为静态变量的类型。那么考虑下面一种情况:

 

 

 

MyClass class1 = new MyClass();

 

MyClass class2 = new MyClass();

 

class1.myStaticVar = "hello";

 

class2.myStaticVar = 5;

 

由于泛型系统的类型擦除(type erasure)。myStaticVar被还原成Object类型,然后当调用class1.myStaticVar= "hello"; 编译器进行强制类型转换,即myStaticVar = (String)"hello";接着调用class2.myStaticVar语句时,编译器继续进行强制类型转换,myStaticVar = (Integer)Integer.valueOf(5); 此时myStaticVar是String类型的,当然该语句会在运行时抛出ClassCastException异常,这样一来存在类型安全问题。因此泛型系统不允许类的静态变量用类型参数作为变量类型。

 

    系统中不会真正生成泛型类,因此instanceod运算符后不能使用泛型类,因为根本不存在!

7.类型通配符

 注意的是,如果Foo是Bar的一个子类型,而G是具有泛型声明的类或接口,G并不是G的子类型。

假设List在逻辑上可以视为List的父类,那么a.test(list)将不会有错误提示了,那么问题就出来了,通过getData()方法取出数据时到底是什么类型呢?Integer? Float? 还是Object?且由于在编程过程中的顺序不可控性,导致在必要的时候必须要进行类型判断,且进行强制类型转换。显然,这与泛型的理念矛盾,因此,在逻辑上List不能视为List的父类

为了表示各种泛型集合的父类,可以使用类型通配符,类型通配符是一个问号,他可以匹配任何类型:

类型通配符一般是使用 ? 代替具体的类型实参。注意了,此处是类型实参,而不是类型形参!且List在逻辑上是List、List>...等所有List<具体类型实参>的父类。由此,我们依然可以定义泛型方法,来完成此类需求。

 

不管list的真实类型是什么,包含的都是Object

注意:带通配符的仅仅表示它是各种泛型集合的父类,并不能把元素加入其中

 

 

并不知道c集合中元素的类型,不能向其中添加对象

7.1 设置通配符上限

 

因为List 并不是List 的子类型,所以编译出错

这回收可以用被限制的泛型通配符

7.2 设置类型形参的上限

 

8.泛型方法

定义类、接口时没有使用类型形参,定义方法时想自己定义

独立的泛型静态方法,在不考虑多线程的情况下,同一时间点,只会被初始化并调用一次,不会出现重叠初始化并错误调用,不会出现类似数据库中读脏数据的情况,所以不会出现强制类型转换的代码错误。

方法声明中定义的形参只能在该方法里使用。

与类、接口不同,方法中的泛型无需显示传入实际类型参数

一定不能让编译器迷惑你传入的到底是什么类型

比如test a, Collection b>

你传进去一个String类型的,一个Object类型的,编译器不知道你这T到底是啥类型的

可以改成 a, Collection b>

泛型方法

(在 类型参数 一节中)您已经看到,通过在类的定义中添加一个形式类型参数列表,可以将类泛型化。方法也可以被泛型化,不管它们定义在其中的类是不是泛型化的。

泛型类在多个方法签名间实施类型约束。在 List 中,类型参数 V 出现在 get()、add()、contains() 等方法的签名中。当创建一个 Map 类型的变量时,您就在方法之间宣称一个类型约束。您传递给 add() 的值将与 get() 返回的值的类型相同。

类似地,之所以声明泛型方法,一般是因为您想要在该方法的多个参数之间宣称一个类型约束。例如,下面代码中的 ifThenElse() 方法,根据它的第一个参数的布尔值,它将返回第二个或第三个参数:

public T ifThenElse(boolean b, T first, T second) {
return b ? first : second;
}

注意,您可以调用 ifThenElse(),而不用显式地告诉编译器,您想要 T 的什么值。编译器不必显式地被告知 T 将具有什么值;它只知道这些值都必须相同。编译器允许您调用下面的代码,因为编译器可以使用类型推理来推断出,替代 T 的 String 满足所有的类型约束:

String s = ifThenElse(b, "a", "b");

类似地,您可以调用:

Integer i = ifThenElse(b, new Integer(1), new Integer(2));

但是,编译器不允许下面的代码,因为没有类型会满足所需的类型约束:

String s = ifThenElse(b, "pi", new Float(3.14));

为什么您选择使用泛型方法,而不是将类型 T 添加到类定义呢?(至少)有两种情况应该这样做:

当泛型方法是静态的时,这种情况下不能使用类类型参数。

当 T 上的类型约束对于方法真正是局部的时,这意味着没有在相同类的另一个 方法签名中使用相同 类型 T 的约束。通过使得泛型方法的类型参数对于方法是局部的,可以简化封闭类型的签名。


有限制类型

在前一屏 泛型方法 的例子中,类型参数 V 是无约束的或无限制的 类型。有时在还没有完全指定类型参数时,需要对类型参数指定附加的约束。

考虑例子 Matrix 类,它使用类型参数 V,该参数由 Number 类来限制:

public class Matrix { ... }

编译器允许您创建 Matrix 或 Matrix 类型的变量,但是如果您试图定义 Matrix 类型的变量,则会出现错误。类型参数 V 被判断为由 Number 限制 。在没有类型限制时,假设类型参数由 Object 限制。这就是为什么前一屏 泛型方法 中的例子,允许 List.get() 在 List 上调用时返回 Object,即使编译器不知道类型参数 V 的类型。

9.泛型方法和类型通配符的区别

如果某个方法中的一个形参(a)的类型或返回值的类型依赖于另一个形参(b)的类型,则形参(b)的类型声明不应该使用通配符,只能考虑使用在方法签名中声明类型形参,也就是泛型方法。

我理解的是类型通配符是不需要添加、修改集合里面的元素,并且是依附于别人而不是别人依附于他,使用

类型通配符既可以在方法签名定义形参的类型,也可以用于定义变量的类型,泛型方法中的类型形参必须在对应方法中显示声明。

10.擦拭和转换

当把一个具有泛型信息的对象赋给另个一个没有泛型信息的变量时,所有在尖括号之间的类型信息都会被扔掉。

 

将li赋给List的时候,编译器会擦拭掉前者的泛型信息,即丢失掉list集合里元素的类型信息。

Java又允许直接把list对象赋给一个List的变量,所以程序可以编译通过,只是发出“未经检查的转换”(将逻辑上的父类直接赋给子类),但对list变量实际上引用的是list集合,所以当试图把该集合里的元素当成String类型的对象取出时,将会引发运行时异常

11.泛型和数组

java泛型有一个很重要的设计原则---如果一段代码在编译时没有提出“未经转换的异常”警告,程序不会引起ClassCastException异常,基于这个原因,所有数组元素的类型不能包含类型变量或者类型形参,除非是无上限的类型通配符,但可以声明元素类型包含类型变量或类型形参的数组

假设能通过,将不会引起任何警告,但会引发异常

改成如下格式:

第一行会有“未经检查的转换”警告,最后一行也会引发异常

创建无上限的通配符泛型数组

编译不会发出任何警告,但是运行时候会引发异常,因为程序需要将lsa的第一个数组元素的第一个集合元素强制转换成String类型,所以程序应该通过instanceof运算符来保证它的数据类型

于此类似,创建元素类型是类型变量的数组对象也将导致编译错误

T[] makeArray(Collection coll)

{ return new T[cool.size()]

}

类型变量在运行时不存在,编译器无法确定实际类型是什么

 

以上是Java--泛型的详细内容。更多信息请关注PHP中文网其他相关文章!

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
2 周前 By 尊渡假赌尊渡假赌尊渡假赌
仓库:如何复兴队友
1 个月前 By 尊渡假赌尊渡假赌尊渡假赌
Hello Kitty Island冒险:如何获得巨型种子
4 周前 By 尊渡假赌尊渡假赌尊渡假赌

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

泛型函数在Golang中解决可变参数类型的问题吗? 泛型函数在Golang中解决可变参数类型的问题吗? Apr 16, 2024 pm 06:12 PM

Go中的泛型函数解决了可变参数类型的问题:泛型函数允许使用类型参数,在运行时指定。这使得编写可以处理不同类型参数的函数成为可能。例如,Max函数是一个泛型函数,它接受两个可比较参数并返回较大值。通过使用泛型函数,我们可以编写更灵活通用的代码,可处理不同类型的参数。

探讨Golang中泛型的优势和用途 探讨Golang中泛型的优势和用途 Apr 03, 2024 pm 02:03 PM

答案:Golang泛型是提高代码可复用性、灵活性、类型安全性和可扩展性的强大工具。详细描述:优势:代码可复用性:通用算法和数据结构灵活性:运行时创建特定类型实例类型安全性:编译时类型检查可扩展性:易于扩展和自定义用途:通用函数:排序、比较等通用数据结构:列表、映射、堆栈等类型别名:简化类型声明约束泛型:确保类型安全性

Java 函数泛型的上限和下限是什么?如何使用? Java 函数泛型的上限和下限是什么?如何使用? Apr 26, 2024 am 11:45 AM

Java函数泛型允许设置上限和下限。上限(extends)指定函数接受或返回的数据类型必须是指定类型的子类型,例如。下限(super)指定函数接受或返回的数据类型必须是指定类型的超类型,例如。泛型使用可提高代码的可重用性和安全性。

泛型函数在Golang中的限制是什么? 泛型函数在Golang中的限制是什么? Apr 16, 2024 pm 05:12 PM

Go泛型函数的限制:仅支持类型参数,不支持值参数。不支持函数递归。不能显式指定类型参数,由编译器推断。

如何在 Java 泛型方法中限制类型参数? 如何在 Java 泛型方法中限制类型参数? Apr 30, 2024 pm 01:30 PM

为了在Java泛型方法中限制类型参数,需使用语法,其中Bound为类型或接口。如此,参数仅接受继承自Bound类型或实现Bound接口的类型。例如,限制T为可与自身比较的类型。

golang中泛型的具体应用场景 golang中泛型的具体应用场景 May 04, 2024 am 11:45 AM

泛型在Go中的应用场景:集合操作:创建适用于任何类型的集合操作,例如过滤。数据结构:编写通用的数据结构,如队列,栈和映射,可存储和操作各种类型的数据。算法:编写通用的算法,如排序,搜索和归约,可处理不同类型的数据。

Java 泛型在 Android 开发中的应用 Java 泛型在 Android 开发中的应用 Apr 12, 2024 pm 01:54 PM

泛型在Android开发中的应用加强了代码的可重用性、安全性和灵活性。其语法包括声明一个类型变量T,该变量可用于操作类型参数化的数据。泛型实战案例包括自定义数据适配器,允许适配器适应任何类型的自定义数据对象。Android还提供了泛型列表类(如ArrayList)和泛型方法,允许操作不同类型的参数。使用泛型的好处包括代码可重用性、安全性和灵活性,但需要注意指定正确的界限并适度使用,以确保代码的可读性。

Golang泛型对函数签名和参数的影响是什么? Golang泛型对函数签名和参数的影响是什么? Apr 17, 2024 am 08:39 AM

泛型对Go函数签名和参数的影响包括:类型参数:函数签名可包含类型参数,指定函数可使用的类型。类型约束:类型参数可具有约束,指定其必须满足的条件。参数类型推断:编译器可推断未指定类型参数的类型。指定类型:可显式指定参数类型以调用泛型函数。这提高了代码的可重用性和灵活性,允许编写可与多种类型一起使用的函数和类型。

See all articles