Java泛型详解

合集下载

java 泛型的三种定义与使用方法

java 泛型的三种定义与使用方法

java 泛型的三种定义与使用方法Java中的泛型主要有三种定义方式,分别是:类型参数、类型参数化类和类型参数化方法。

下面是它们的定义和使用方法:1. 类型参数:类型参数是泛型的主要形式,它允许我们在定义类、接口或方法时指定一个或多个类型参数。

这些类型参数在类、接口或方法的实现中被用作类型占位符,以便在运行时确定实际类型。

定义类型参数的方法是在类、接口或方法的名称后面加上尖括号<>,并在其中指定一个或多个类型参数。

例如:```javapublic class Box<T> {private T content;public Box(T content) {= content;}public T getContent() {return content;}}```在上面的例子中,我们定义了一个名为Box的泛型类,它有一个类型参数T。

我们可以使用任何类型来实例化Box对象,例如Box<Integer>、Box<String>等。

2. 类型参数化类:类型参数化类是将一个类作为泛型参数。

这种定义方式主要用于集合框架中的类,例如List、Set、Map等。

定义类型参数化类的方法是在类名后面加上尖括号<>,并在其中指定一个或多个类型参数。

例如:```javaList<String> list = new ArrayList<>();Set<Integer> set = new HashSet<>();Map<String, Integer> map = new HashMap<>();在上面的例子中,我们定义了三个类型参数化类:List、Set和Map,并使用它们创建了三个不同类型的对象。

这些对象在运行时会自动处理实际类型的匹配。

3. 类型参数化方法:类型参数化方法是在方法中使用泛型。

Java泛型总结

Java泛型总结

Java泛型总结1. 什么是泛型?泛型(Generic type 或者generics)是对Java 语言的类型系统的一种扩展,以支持创建可以按类型进行参数化的类。

可以把类型参数看作是使用参数化类型时指定的类型的一个占位符,就像方法的形式参数是运行时传递的值的占位符一样。

可以在集合框架(Collection framework)中看到泛型的动机。

例如,Map 类允许您向一个Map 添加任意类的对象,即使最常见的情况是在给定映射(map)中保存某个特定类型(比如String)的对象。

因为Map.get() 被定义为返回Object,所以一般必须将Map.get() 的结果强制类型转换为期望的类型,如下面的代码所示:Map m = new HashMap();m.put("key", "blarg");String s = (String) m.get("key");要让程序通过编译,必须将get() 的结果强制类型转换为String,并且希望结果真的是一个String。

但是有可能某人已经在该映射中保存了不是String 的东西,这样的话,上面的代码将会抛出ClassCastException。

理想情况下,您可能会得出这样一个观点,即m 是一个Map,它将String 键映射到String 值。

这可以让您消除代码中的强制类型转换,同时获得一个附加的类型检查层,该检查层可以防止有人将错误类型的键或值保存在集合中。

这就是泛型所做的工作。

2. 泛型的好处Java 语言中引入泛型是一个较大的功能增强。

不仅语言、类型系统和编译器有了较大的变化,以支持泛型,而且类库也进行了大翻修,所以许多重要的类,比如集合框架,都已经成为泛型化的了。

这带来了很多好处:类型安全。

泛型的主要目标是提高Java 程序的类型安全。

通过知道使用泛型定义的变量的类型限制,编译器可以在一个高得多的程度上验证类型假设。

java 方法的泛型

java 方法的泛型

java 方法的泛型Java方法的泛型泛型(Generics)是Java语言中一个强大的特性,它允许我们在编译时期检测类型的一致性,并且提供了更加灵活和安全的代码重用方式。

泛型在Java 5中引入,成为Java语言的一大亮点。

在本文中,我将介绍Java方法中的泛型的使用方法和注意事项。

一、泛型方法的定义和语法泛型方法是一种在方法中使用泛型类型参数的方法。

在方法的返回类型之前使用尖括号,尖括号中指定泛型类型参数。

例如,下面是一个简单的泛型方法的定义:```javapublic <T> void printArray(T[] arr) {for (T element : arr) {System.out.print(element + " ");}System.out.println();}```在上面的例子中,泛型方法printArray使用了一个类型参数T,它表示任意类型。

方法的参数arr是一个泛型数组,类型为T[]。

在方法的实现中,我们可以像操作普通数组一样遍历和处理泛型数组。

二、调用泛型方法调用泛型方法时,可以明确指定泛型类型参数,也可以根据方法参数的类型推断出泛型类型参数。

例如,下面是两种调用泛型方法的方式:```javaString[] strArr = {"Java", "Python", "C++"};printArray(strArr); // 调用泛型方法,类型参数自动推断为StringInteger[] intArr = {1, 2, 3, 4, 5};this.<Integer>printArray(intArr); // 显式指定泛型类型参数为Integer```从上面的例子中可以看出,我们既可以根据参数类型推断出泛型类型参数,也可以显式指定泛型类型参数。

这使得泛型方法在使用时非常灵活。

java泛型的理解

java泛型的理解

java泛型的理解摘要:1.泛型的概念2.泛型的作用3.泛型的使用4.泛型的注意事项正文:一、泛型的概念Java 泛型是Java 语言在1.5 版本引入的一种新的特性,它的出现使得Java 在面向对象编程上更加强大和灵活。

泛型是一种将类型抽象化的手段,它允许我们编写可以适用于多种类型的代码,同时避免了强制类型转换所带来的潜在错误。

二、泛型的作用泛型的主要作用有以下几点:1.提高代码的复用性:使用泛型可以编写一次代码,然后在不同的类型情况下重复使用,避免了重复编写代码的繁琐。

2.类型安全:泛型可以在编译时检查类型是否匹配,避免了运行时的类型转换错误。

3.提高代码的可读性:通过使用泛型,可以使代码更加简洁明了,减少了类型相关的繁琐描述。

三、泛型的使用在Java 中,泛型的使用非常简单。

只需要在类名或者方法名后面跟上尖括号<>,其中尖括号内是一个或多个类型参数。

例如:```javaList<String> list = new ArrayList<>(); // 使用泛型创建一个字符串列表list.add("hello");```四、泛型的注意事项在使用泛型时,需要注意以下几点:1.泛型擦除:Java 中的泛型实际上是一种“伪泛型”,它只在编译时起作用。

在运行时,泛型信息会被擦除,因此无法通过泛型类型实例化对象。

2.类型参数的限制:泛型的类型参数必须继承自一个共同的基类,或者实现一个共同的接口。

3.不能实例化泛型类型:由于泛型擦除,我们不能创建泛型类型的实例,只能通过泛型类型来创建具体的类型实例。

Java泛型详解与范例

Java泛型详解与范例

Java 泛型详解与范例⽬录⼀、泛型的使⽤⼆、泛型类的定义-类型边界三、类型擦除四、泛型类的使⽤-通配符五、泛型⽅法六、泛型的限制⼀、泛型的使⽤前⾯我们学集合的时候,简单的说过泛型的使⽤。

如下:1ArrayList<Integer> list = new ArrayList<>();那么使⽤是这样的简单,该注意什么?尖括号⾥的类型,只能写引⽤类型基础数据类型的话,就需要写相应的包装类型泛型只是编译时期的⼀种机制,在运⾏时是没有泛型的概念的。

⼆、泛型类的定义-类型边界泛型还有⼀个点就是:泛型的上界。

(类型形参 extends 类型边界)有如下代码:1234public class Algorithm<T extends Comparable<T>> { public T findMax(T[] array) { }}以上代码中,⽅法的作⽤就是传递⼀个数组进去,要求返回这个数组中的最⼤值。

这个时候问题就来了,泛型是T 类型,当调⽤这个⽅法的时候,传递过去的参数类型不⼀定就是简单数据类型啊。

那么这个时候该怎么进⾏判断⼤⼩呢此时这样的泛型写法的作⽤就是:T extends Comparable, 就叫做泛型的上界,当传递参数类型的时候,必须传递过去的参数类型必须是实现了Comparable 接⼝的类型才可以。

换句话说,传递过去的类型必须是可以进⾏⽐较的。

当我们⾃⼰定义的⼀个类Node ,然后实现Comparable 接⼝,就能调⽤如上的⽅法。

切记,这样写的泛型,传递过去的参数类型,必须是实现了Comparable 接⼝的,当然也可以传递Comparable 接⼝本⾝。

三、类型擦除类型擦除值得是:代码编译后,会将泛型T ,全部擦除为Object 类型。

如下代码:上⾯这⼀⾏代码,虽然此时写的是Integer 类型的,但是在编译之后,JVM 会⾃动地将Integer 擦除为Object 。

java 泛型详解

java 泛型详解

java 泛型详解1. 概述泛型在java中有很重要的地位,在面向对象编程及各种设计模式中有非常广泛的应用。

什么是泛型?为什么要使用泛型?泛型,即“参数化类型”。

一提到参数,最熟悉的就是定义方法时有形参,然后调用此方法时传递实参。

那么参数化类型怎么理解呢?顾名思义,就是将类型由原来的具体的类型参数化,类似于方法中的变量参数,此时类型也定义成参数形式(可以称之为类型形参),然后在使用/调用时传入具体的类型(类型实参)。

泛型的本质是为了参数化类型(在不创建新的类型的情况下,通过泛型指定的不同类型来控制形参具体限制的类型)。

也就是说在泛型使用过程中,操作的数据类型被指定为一个参数,这种参数类型可以用在类、接口和方法中,分别被称为泛型类、泛型接口、泛型方法。

2.一个栗子一个被举了无数次的例子:List arrayList = new ArrayList();arrayList.add("aaaa");arrayList.add(100);for(int i = 0; i< arrayList.size();i++){String item = (String)arrayList.get(i);Log.d("泛型测试","item = " + item);}毫无疑问,程序的运行结果会以崩溃结束:ng.ClassCastException:ng.Integer cannot be cast to ng.String。

ArrayList可以存放任意类型,例子中添加了一个String类型,添加了一个Integer类型,再使用时都以String的方式使用,因此程序崩溃了。

为了解决类似这样的问题(在编译阶段就可以解决),泛型应运而生。

我们将第一行声明初始化list的代码更改一下,编译器会在编译阶段就能够帮我们发现类似这样的问题。

List<String> arrayList = new ArrayList<String>();...//arrayList.add(100); 在编译阶段,编译器就会报错3.特性泛型只在编译阶段有效。

java 泛型的用法

java 泛型的用法

java 泛型的用法摘要:1.泛型的概念2.泛型的优点3.泛型类型参数4.泛型擦除5.泛型使用实例正文:泛型是Java 中一种强大的功能,它允许我们编写可以处理不同类型的代码,从而提高代码的复用性和类型安全性。

泛型的优点在于它可以让我们的代码更加灵活,不需要针对每个类型都编写特定的方法或类。

在Java 中,泛型是通过在类型后面跟上尖括号<>,然后跟一个或多个类型参数来定义的。

这些类型参数通常使用大写字母表示,如T、E、K、V 等。

类型参数可以有一个或多个,用逗号分隔。

当我们使用泛型时,Java 编译器会进行泛型擦除。

这意味着在编译时,泛型类型参数将被替换为实际的类型。

这样一来,运行时的类型信息就与使用泛型之前一样。

这种擦除可以防止在运行时出现类型不匹配的问题。

下面我们通过一个简单的例子来说明泛型的用法。

假设我们有一个Box 类,用于存储和操作不同类型的对象。

我们可以使用泛型来定义这个类,从而使其可以处理多种类型的数据。

```javapublic class Box<T> {private T content;public Box() {}public Box(T content) {this.content = content;}public T getContent() {return content;}public void setContent(T content) {this.content = content;}}```在上面的代码中,我们定义了一个名为Box 的泛型类,泛型类型参数为T。

Box 类包含一个泛型类型的成员变量content,以及相应的构造函数、getter 和setter 方法。

我们可以使用这个泛型Box 类来存储和操作不同类型的数据,例如:```javaBox<String> stringBox = new Box<>();stringBox.setContent("Hello, world!");String stringContent = stringBox.getContent();System.out.println(stringContent);Box<Integer> integerBox = new Box<>();integerBox.setContent(42);int integerContent = integerBox.getContent();System.out.println(integerContent);```通过使用泛型,我们可以在编译时检查类型安全,并在运行时获得正确的类型信息。

什么是Java泛型有什么作用

什么是Java泛型有什么作用

什么是Java泛型有什么作用在 Java 编程的世界里,泛型是一个非常重要的概念。

对于许多初学者来说,可能一开始会觉得它有些复杂和难以理解,但一旦掌握,就能为我们的编程带来极大的便利和效率。

那么,究竟什么是 Java 泛型呢?简单来说,泛型就是一种在定义类、接口或方法时使用的类型参数。

它允许我们在编写代码的时候,不指定具体的类型,而是在使用的时候再确定。

比如说,我们如果没有使用泛型来定义一个集合,就像这样:```javaList list = new ArrayList();listadd("Hello");listadd(123);```在这个例子中,我们可以向这个集合添加任何类型的对象,这可能会导致一些问题。

比如,当我们从集合中取出元素时,我们不知道它到底是什么类型,需要进行大量的类型转换和检查,这不仅麻烦,还容易出错。

但是,如果我们使用泛型来定义这个集合,就像这样:```javaList<String> list = new ArrayList<>();listadd("Hello");// listadd(123);//这行代码会报错,因为类型不匹配```这样,我们就明确地指定了这个集合只能存储字符串类型的元素。

在取出元素的时候,我们就不需要再进行繁琐的类型检查和转换了,因为我们知道它一定是字符串类型。

泛型的作用主要体现在以下几个方面:增强类型安全泛型最大的作用之一就是增强了程序的类型安全。

通过在代码中明确指定类型参数,编译器可以在编译时就进行类型检查,确保我们不会将错误类型的对象添加到集合或进行其他不匹配的操作。

这可以帮助我们在开发过程中尽早发现类型错误,而不是在运行时才出现难以调试的错误。

避免类型转换在没有泛型的情况下,当我们从集合中取出元素时,通常需要进行类型转换。

例如:```javaObject obj = listget(0);String str =(String) obj;```这种类型转换不仅繁琐,而且如果转换的类型不正确,在运行时会抛出 ClassCastException 异常。

java 泛型详解

java 泛型详解

JAVA 协变性逆变性在面向对象的计算机程序语言中,经常涉及到类型之间的转换,例如从具体类小猫到动物之间的类型转换(上行转换),或者从形状向三角形之间的转换(下行转换)。

我们之前往往都比较关注类型本身,却常常忽略类型转换的性质。

最近在拜读《thinking in java》看到一些关于类型转换性质的比较抽象理论的内容,仔细研究一下,分享给大家。

我们将围绕如下三个核心名词:协变性(covariance)、逆变性(contravariance)和无关性(invariant)。

他们都是用来描述类型转换的性质的术语,形式化的描述如下:如果A和B是类型,f表示类型转换,≤表示子类型关系,(例如A≤B,表示A是B 的子类)那么:如果A≤B 则f(A) ≤ f(B) 那么 f是协变的如果A≤B 则f(B) ≤ f(A) 那么 f 是逆变的如果上面两种都不成立,那么f是无关的例如java中,f(A) = List<A> ,这里List声明如下:class List<T>{…}我们可以理解泛型类List输入一个类型参数T,然后将T转换成类型List<T>,这个过程本身是一个类型转换f。

我们举例A = Object,B=String,经过类型变换f以后f(A)=List<Object>,f(B) =List<String>。

String ≤ Object 但是 f(A) ≤ f(b)却不成立。

所以上面的类型转换是无关的。

在Java语言中,有一些语法可以用协变性和逆变性来理解。

数组例如 A = String, B = Object 我们这里有A≤Bf(A) = String[], f(B) = Object[]. 因为Object[] objects = new String[n]. 所以我们可以认为数组具有协变性。

X = Y1. 协变返回值在面向对象语言中,一个协变返回值方法是一个在子类覆盖该方法的时候,方法的返回值可以被一个“更窄”的类型所替代。

Java 泛型总结

Java 泛型总结

Java 泛型1、泛型方法你可以写一个泛型方法,该方法在调用时可以接收不同类型的参数。

根据传递给泛型方法的参数类型,编译器适当地处理每一个方法调用。

下面是定义泛型方法的规则:1.1所有泛型方法声明都有一个类型参数声明部分(由尖括号分隔),该类型参数声明部分在方法返回类型之前(在下面例子中的<E>)。

1.2每一个类型参数声明部分包含一个或多个类型参数,参数间用逗号隔开。

一个泛型参数,也被称为一个类型变量,是用于指定一个泛型类型名称的标识符。

1.3类型参数能被用来声明返回值类型,并且能作为泛型方法得到的实际参数类型的占位符。

1.4泛型方法体的声明和其他方法一样。

注意类型参数只能代表引用型类型,不能是原始类型(像int、double、char 等)。

2、java 中泛型标记符2.1E - Element (在集合中使用,因为集合中存放的是元素)2.2T - Type(Java 类)2.3K - Key(键)2.4V - Value(值)2.5N - Number(数值类型)2.6?- 表示不确定的 java 类型3、泛型类泛型类的声明和非泛型类的声明类似,除了在类名后面添加了类型参数声明部分。

和泛型方法一样,泛型类的类型参数声明部分也包含一个或多个类型参数,参数间用逗号隔开。

一个泛型参数,也被称为一个类型变量,是用于指定一个泛型类型名称的标识符。

因为他们接受一个或多个参数,这些类被称为参数化的类或参数化的类型。

4、类型通配符4.1、类型通配符一般是使用? 代替具体的类型参数。

例如List<?> 在逻辑上是List<String>,List<Integer> 等所有List<具体类型实参> 的父类。

4.2类型通配符上限通过形如List来定义,如此定义就是通配符泛型值接受Number及其下层子类类型。

java 泛型的用法

java 泛型的用法

java 泛型的用法【原创实用版】目录1.Java 泛型的概念2.Java 泛型的好处3.Java 泛型的使用方法4.Java 泛型的注意事项正文【1.Java 泛型的概念】Java 泛型是 Java 语言中一种重要的特性,它允许程序员在编译时检查类型安全,从而提高代码的可靠性和可维护性。

泛型是一种抽象概念,它允许我们创建一组具有相同类型约束的类或方法。

在 Java 中,泛型通常用尖括号(<T>)表示,其中 T 是类型参数。

【2.Java 泛型的好处】Java 泛型的主要优点是类型安全和代码重用。

类型安全意味着在编译时检查类型,从而减少运行时的错误。

代码重用指的是使用泛型可以创建一组具有相同类型约束的类或方法,从而减少重复代码。

【3.Java 泛型的使用方法】要使用 Java 泛型,首先需要创建一个泛型类或方法。

以下是一些使用泛型的示例:1) 创建泛型类```javapublic class Box<T> {private T content;public Box() {}public Box(T content) {this.content = content;}public T getContent() {return content;}public void setContent(T content) {this.content = content;}}```2) 创建泛型方法```javapublic class GenericsExample {public static <T> void printList(List<T> list) { for (T item : list) {System.out.println(item);}}public static void main(String[] args) {List<String> stringList = new ArrayList<>();stringList.add("Hello");stringList.add("World");printList(stringList);}}```【4.Java 泛型的注意事项】在使用 Java 泛型时,需要注意以下几点:1) 泛型擦除:Java 泛型在运行时会被擦除,即类型参数会被替换为实际类型。

java泛型语法

java泛型语法

java泛型语法Java泛型语法是Java编程语言中的一个重要特性,它允许我们编写更加通用和灵活的代码。

通过使用泛型,我们可以在编译时期检测类型错误,并在运行时期避免类型转换异常。

本文将介绍Java泛型的基本语法和使用方法。

一、泛型的定义和作用泛型是Java中的一种参数化类型,它允许我们在定义类、接口和方法时使用类型参数。

通过使用泛型,我们可以将类型作为参数传递给类、接口和方法,从而实现代码的复用和灵活性。

泛型的作用主要有以下几个方面:1. 类型安全:通过使用泛型,我们可以在编译时期检测类型错误,避免类型转换异常。

2. 代码复用:通过定义泛型类、接口和方法,我们可以实现对多种类型的支持,从而提高代码的复用性。

3. 简化代码:通过使用泛型,我们可以减少冗余的类型转换代码,使代码更加简洁。

4. 提高性能:通过使用泛型,我们可以避免使用Object类型,从而减少了装箱和拆箱的开销,提高了代码的执行效率。

二、泛型的基本语法Java中的泛型通过使用尖括号<>来定义类型参数。

在定义类、接口和方法时,我们可以将类型参数放在尖括号中,并在后续的代码中使用该类型参数。

1. 泛型类的定义:```public class GenericClass<T> {private T data;public T getData() {return data;}public void setData(T data) {this.data = data;}}```在上面的代码中,泛型类GenericClass使用了类型参数T。

我们可以在创建GenericClass对象时指定具体的类型,例如:```GenericClass<String> genericString = new GenericClass<>(); genericString.setData("Hello, World!");String data = genericString.getData();```上面的代码中,我们创建了一个GenericClass对象genericString,并指定了类型参数为String。

java泛型语法

java泛型语法

java泛型语法Java泛型是Java语言中的一个重要特性,它允许我们在定义类、接口和方法时使用类型参数,从而增加代码的灵活性和复用性。

本文将对Java泛型语法进行详细介绍,并探讨其使用场景和注意事项。

一、泛型的基本概念泛型(Generics)是Java SE 5中引入的特性,用于在编译时期检查数据类型的安全性。

通过使用泛型,我们可以在类或方法中指定一种或多种类型参数,并在代码中使用这些参数来增加代码的通用性。

泛型的基本语法如下:```class ClassName<T>{// 类体}interface InterfaceName<T>{// 接口体}public class ClassName<T>{// 类体}public <T> void methodName(T t){// 方法体}```在上述语法中,`<T>`表示类型参数,可以是任意标识符。

在类或接口的定义中,我们可以使用类型参数来定义属性、方法和构造函数等。

在方法的定义中,我们可以使用类型参数来定义参数类型、返回值类型和局部变量类型。

二、泛型的使用场景泛型主要用于以下几个方面:1. 容器类:通过使用泛型,我们可以定义各种类型的容器类,如List、Set、Map等。

通过指定类型参数,我们可以限制容器中存储的元素类型,从而提高代码的安全性和可读性。

2. 算法类:通过使用泛型,我们可以定义一些通用的算法类,如排序、查找等。

通过指定类型参数,我们可以提供通用的算法实现,从而减少代码的重复编写。

3. 接口和抽象类:通过使用泛型,我们可以定义一些通用的接口和抽象类,从而使得实现类可以灵活地指定具体的类型。

这样一来,我们可以提供可复用的接口和抽象类,同时保证类型安全。

4. 类型转换:通过使用泛型,我们可以实现类型的自动转换,从而减少代码的冗余和错误。

通过指定类型参数,我们可以在编译时期检查类型的合法性,从而避免类型转换错误。

java泛型详解

java泛型详解

Java 泛型详解泛型是Java中一个非常重要的知识点,在Java集合类框架中泛型被广泛应用。

本文我们将从零开始来看一下Java 泛型的设计,将会涉及到通配符处理,以及让人苦恼的类型擦除。

泛型基础泛型类我们首先定义一个简单的Box类:public class Box { private String object; public void set(String object) { this.object = object; } public String get() { return object; }}这是最常见的做法,这样做的一个坏处是Box里面现在只能装入String类型的元素,今后如果我们需要装入Integer等其他类型的元素,还必须要另外重写一个Box,代码得不到复用,使用泛型可以很好的解决这个问题。

public class Box { // T stands for 'Type' private T t; public void set(T t) { this.t = t; } public T get() { return t; }}这样我们的Box类便可以得到复用,我们可以将T替换成任何我们想要的类型:Box integerBox = new Box();Box doubleBox = newBox();Box stringBox = new Box();泛型方法看完了泛型类,接下来我们来了解一下泛型方法。

声明一个泛型方法很简单,只要在返回类型前面加上一个类似的形式就行了:public class Util { public static boolean compare(Pair p1, Pair p2) { returnp1.getKey().equals(p2.getKey()) &&p1.getValue().equals(p2.getValue()); }}public classPair { private K key; private V value; publicPair(K key, V value) { this.key = key;this.value = value; } public void setKey(K key){ this.key = key; } public void setValue(V value){ this.value = value; } public K getKey() { return key; } public V getValue() { return value; }}我们可以像下面这样去调用泛型方法:Pair p1 = new Pair(1, 'apple');Pair p2 = new Pair(2,'pear');boolean same = pare(p1, p2);或者在Java1.7/1.8利用type inference,让Java自动推导出相应的类型参数:Pair p1 = new Pair(1, 'apple');Pair p2 = new Pair(2,'pear');boolean same = pare(p1, p2);边界符现在我们要实现这样一个功能,查找一个泛型数组中大于某个特定元素的个数,我们可以这样实现:public static int countGreaterThan(T[] anArray, T elem) { int count = 0; for (T e : anArray) if (e > elem) // compiler error ++count; return count;}但是这样很明显是错误的,因为除了short, int, double, long, float, byte, char等原始类型,其他的类并不一定能使用操作符>,所以编译器报错,那怎么解决这个问题呢?答案是使用边界符。

java泛型原理

java泛型原理

java泛型原理Java泛型是在JDK 5引入的新特性,它的原理是通过类型参数化来实现程序的通用性和安全性。

泛型的使用可以将类型的确定延迟到编译时,从而减少类型转换的错误。

下面是Java泛型的一些原理解释。

1. 类型参数化泛型的关键概念就是类型参数化,通过在类名后面添加尖括号和类型参数,使类中的字段、方法或者参数具有通用性。

例如,在List接口中定义了一个泛型方法,可以使用不同类型的元素进行参数化。

2. 类型擦除虽然Java在编译时会对泛型进行类型检查,但在运行时会擦除泛型的具体类型信息。

换句话说,泛型在编译时是一个安全的类型检查机制,但在运行时是一个未知的类型。

这是由于Java的泛型是通过类型擦除来实现的。

3. 类型擦除后的替代当泛型被类型擦除之后,会使用类型变量的上限或者Object类型来替代相应的参数类型。

例如,List<String>会被擦除为List<Object>,而List<T extends Comparable>会被擦除为List<Comparable>。

4. 泛型边界在泛型中,可以通过使用通配符和类型边界来限制类型参数的范围。

边界可以是类、接口或者类型变量。

例如,下面的泛型方法会使用Comparable接口来限制类型参数T的范围。

```javapublic <T extends Comparable<T>> int compare(T a, T b) {return pareTo(b);}```5. 泛型的通配符通配符是一种特殊的类型用法,用于在某些情况下不关心具体类型的情况下使用。

通配符使用`?`来表示,可以用于声明变量、方法参数或者返回类型。

例如,使用通配符声明一个List:```javaList<?> list = new ArrayList<>();```以上就是Java泛型的一些原理解释,通过对类型参数化和类型擦除的理解,我们可以更好地使用泛型来提高程序的通用性和安全性。

Java泛型详解

Java泛型详解

Java泛型详解一. 泛型概念的提出(为什么需要泛型)?首先,我们看下下面这段简短的代码:复制代码复制代码1 public class GenericTest {23 public static void main(String[] args) {4 List list = new ArrayList();5 list.add("qqyumidi");6 list.add("corn");7 list.add(100);89 for (int i = 0; i < list.size(); i++) {10 String name = (String) list.get(i); // 111 System.out.println("name:" + name);12 }13 }14 }复制代码复制代码定义了一个List类型的集合,先向其中加入了两个字符串类型的值,随后加入一个Integer 类型的值。

这是完全允许的,因为此时list默认的类型为Object类型。

在之后的循环中,由于忘记了之前在list中也加入了Integer类型的值或其他编码原因,很容易出现类似于//1中的错误。

因为编译阶段正常,而运行时会出现“ng.ClassCastException”异常。

因此,导致此类错误编码过程中不易发现。

在如上的编码过程中,我们发现主要存在两个问题:1.当我们将一个对象放入集合中,集合不会记住此对象的类型,当再次从集合中取出此对象时,改对象的编译类型变成了Object类型,但其运行时类型任然为其本身类型。

2.因此,//1处取出集合元素时需要人为的强制类型转化到具体的目标类型,且很容易出现“ng.ClassCastException”异常。

那么有没有什么办法可以使集合能够记住集合内元素各类型,且能够达到只要编译时不出现问题,运行时就不会出现“ng.ClassCastException”异常呢?答案就是使用泛型。

Java泛型使用详细分析

Java泛型使用详细分析

Java泛型使用详细分析一、泛型的简介1、为什么要使用泛型?一般使用在集合上,比如现在把一个字符串类型的值放入到集合里面,这个时候,这个值放到集合之后,失去本身的类型,只能是object类型。

这时,如果想要对这个值进行类型转换,很容易出现类型转换错误,怎么解决这个问题,可以使用泛型来解决。

2、在泛型里面写是一个对象,String 不能写基本的数据类型比如int,要写基本的数据类型对应的包装类二、在集合上如何使用泛型-常用集合list set map-泛型语法:集合<String> 比如list<String>//泛型在list上的使用@Testpublic void testList() {List<String> list = new ArrayList<String>();list.add("aaa");list.add("bbb");list.add("ccc");//for循环for (int i = 1;i<list.size();i++) {String s = list.get(i);System.out.println(s);}System.out.println("=================");//增强for循环for (String string : list) {System.out.println(string);}//迭代器Iterator<String> it = list.iterator();while (it.hasNext()){System.out.println(it.next());}}//泛型在set上的使用@Testpublic void testSet() {Set<String> set = new HashSet<String>();set.add("www");set.add("qqq");set.add("zzz");//使用增强for循环for (String s2 : set) {System.out.println(s2);}System.out.println("=============");//使用迭代器Iterator<String> iterator = set.iterator();while (iterator.hasNext()) {System.out.println(iterator.next());}}//在map上使用泛型@Testpublic void testMap() {Map<String,String> map = new HashMap<String, String>(); map.put("aaa","111");map.put("bbb","222");map.put("ccc","333");//遍历map,有两种//1、获取所有的key,通过key得到value,使用get方法//2、获取key和value的关系//使用第一种方式遍历//获取所有的keySet<String> sets = map.keySet();//遍历所有的keyfor (String key : sets) {String value = map.get(key);System.out.println(key+":"+value);}System.out.println("========");//使用第二种方式遍历//得到key和value的关系Set<Map.Entry<String,String>> sets1 = map.entrySet();//遍历sets1for (Map.Entry<String,String> entry :sets1) {String keyv = entry.getKey();String valuev = entry.getValue();System.out.println(keyv+":"+valuev);}}三、在方法上使用泛型定义一个数组,实现指定位置上数组元素的交换方法逻辑相同,只是数据类型不同,这个时候使用泛型方法/** 使用泛型方法需要定义一个类型使用大小字母表示T:T表示任意的类型* 写在返回值之前void之前* =========表示定义了一个类型,这个类型是T* 在下面就可以使用类型* */public static <T> void swap(T[] arr,int a,int b) {T temp = arr[a];arr[a] = arr[b];arr[b] = temp;}四、泛型在类上的使用public class TestDemo04<T> {//在类里面可以直接使用T的类型T aa;public void test1(T bb) {}//写一静态方法,在类上面定义的泛型,不能在静态方法里面使用,需重新定义泛型public static <A> void test2(A cc) {}}。

Java泛型详解_刘永雷_2017.3.13

Java泛型详解_刘永雷_2017.3.13

Java泛型探究一、概述。

前段时间,有同事说想要了解一下Java中的泛型相关知识,想想自己对泛型也不是特别了解,只是简单的应用而已,作为一个有追求的工程师,怎么能够这个样子呢。

正好借此机会,也了解了一下,并抽时间整理出来,也能使自己记得更牢一些。

二、知识点。

1.概念。

泛型是JDK1.5中引入的,在代码编译期就会对代码进行检查,后会将泛型去掉(擦除),Class文件中是不包含泛型信息的,不进入运行阶段。

常用的英文符合有T、E、K、V、N,其中T为Type,泛指所有Java类型中的某一种,也是我们最常见最常用的一种,;E为Element,常用在集合类中,集合中存放的都是元素;K为Key,键值对中的key,V为Value,键值对中的value;N为Number,常用作数值类型。

另外我们也可以自定义,如S、U等。

泛型个人理解就是通过泛型,我们可以将类型动态化,不在局限于一种,举个例子,我们在开发过程中定义一个方法:private void setPrice(int price){},方法参数中price 的数据类型为int类型,它是不可变的,这时候如果我们添加一种需求就是这个产品的价格也可能是float类型的,按照我们通常的开发习惯估计80%的人就会重载一个setPrice(float price)的方法。

但是有了泛型,这个问题就简单了,我们可以这样定义一个方法:public<T extends Number>void set(T price){}这样我们就可以实现,一个方法又可以传int 又可以传float,看一下代码:public<T extends Number>void set(T price){System.out.println("Log_"+price);}Main m = new Main();m.set(11);m.set(11.11);输出:Log_11Log_11.11我们通过泛型实现了在一个方法中传递不同数据类型的数据,编译器不报错。

java 泛型的使用规则

java 泛型的使用规则

java 泛型的使用规则Java 泛型是Java 5 引入的一项重要特性,可以让我们在编写代码时更加灵活和安全地处理数据类型。

本文将介绍 Java 泛型的使用规则和一些常见的应用场景。

一、泛型的基本概念泛型是一种参数化类型的机制,它可以让我们在定义类、接口和方法时使用类型参数,从而实现代码的重用和类型的安全检查。

通过使用泛型,我们可以在编译时期检测出类型错误,避免在运行时出现类型转换异常。

二、泛型类的定义和使用在定义一个泛型类时,需要在类名后面加上尖括号(<>),然后在尖括号中指定类型参数。

比如,我们可以定义一个泛型类Box,用来存放任意类型的对象:```public class Box<T> {private T data;public void setData(T data) {this.data = data;}public T getData() {return data;}}```在使用泛型类时,我们需要在实例化对象时指定具体的类型。

例如,我们可以创建一个存放整数的 Box 对象:```Box<Integer> box = new Box<>();box.setData(123);int data = box.getData();```三、泛型方法的定义和使用除了可以在类中定义泛型,我们还可以在方法中使用泛型。

在定义一个泛型方法时,需要在返回值前面加上类型参数。

例如,我们可以定义一个泛型方法 swap,用来交换数组中两个元素的位置:```public <T> void swap(T[] array, int i, int j) {T temp = array[i];array[i] = array[j];array[j] = temp;}```在调用泛型方法时,我们可以显式指定类型参数,也可以通过类型推断自动推断出类型参数。

例如,我们可以交换一个整数数组中两个元素的位置:```Integer[] array = {1, 2, 3, 4, 5};swap(array, 1, 3);```四、通配符的使用通配符是泛型的一种特殊用法,它可以用来表示未知类型或某个范围内的类型。

java泛型用法

java泛型用法

java泛型用法
Java中的泛型是一种参数化类型的机制,它允许在定义类、接口和方法时使用类型参数,以增加代码的通用性和安全性。

泛型的用法包括以下几个方面:
1. 泛型类:使用`<T>`或其他类型参数来定义一个类,T表示类型参数,可以在类中的字段、方法的参数和返回值等地方使用T来表示一个具体的类型。

例如:`class MyGenericClass<T> {}`
2. 泛型接口:与泛型类类似,可以使用类型参数来定义接口。

例如:`interface MyGenericInterface<T> {}`
3. 泛型方法:在方法的返回类型之前使用`<T>`或其他类型参数来定义一个方法,该方法可以在调用时指定具体的类型参数。

例如:`<T> T myGenericMethod(T parameter) {}`
4. 通配符:使用`?`作为类型参数,表示不确定的类型。

例如:`List<?> list`表示可以存储任何类型的元素的列表。

5. 上界限定和下界限定:通过使用`extends`和`super`关键字,可以对泛型类型进行上界限定(只能是某个特定类型或其子类型)或下界限定(只能是某个特定类型或其父类型)。

6. 类型擦除:泛型在编译时会进行类型擦除,即泛型类型会被擦除为其上界或Object类型。

这意味着在运行时无法获取泛型的具体类型信息。

使用泛型可以提高代码的灵活性和安全性,能够在编译时进行类型检查,减少类型转换的错误和异常。

同时,它也使得代码更具有可读性和可维护性。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

Java 泛型1 什么是泛型 (2)2 泛型类跟接口及泛型方法 (3)2.1 泛型类跟接口及继承 (3)2.1.1泛型类 (3)2.1.2继承 (3)2.1.3接口 (3)2.2 泛型方法 (3)2.2.1 方法 (3)2.2.2 类型推断 (4)3 泛型实现原理 (5)4 泛型数组 (6)5边界 (7)6通配符 (8)7 泛型的问题及建议 (9)7.1问题 (9)7.2 建议 (9)1 什么是泛型从jdk1.5开始,Java中开始支持泛型了。

泛型是一个很有用的编程工具,给我们带来了极大的灵活性。

在看了《java核心编程》之后,我小有收获,写出来与大家分享。

所谓泛型,我的感觉就是,不用考虑对象的具体类型,就可以对对象进行一定的操作,对任何对象都能进行同样的操作。

这就是灵活性之所在。

但是,正是因为没有考虑对象的具体类型,因此一般情况下不可以使用对象自带的接口函数,因为不同的对象所携带的接口函数不一样,你使用了对象A的接口函数,万一别人将一个对象B传给泛型,那么程序就会出现错误,这就是泛型的局限性。

所以说,泛型的最佳用途,就是用于实现容器类,实现一个通用的容器。

该容器可以存储对象,也可以取出对象,而不用考虑对象的具体类型。

因此,在学习泛型的时候,一定要了解这一点,你不能指望泛型是万能的,要充分考虑到泛型的局限性。

下面我们来探讨一下泛型的原理以及高级应用。

首先给出一个泛型类:public class Pair<T>{public Pair() { first = null; second = null; }public Pair(T first, T second) { this.first = first; this.second = second; }public T getFirst() { return first; }public T getSecond() { return second; }public void setFirst(T newValue) { first = newValue; }public void setSecond(T newValue) { second = newValue; }private T first;private T second;}我们看到,上述Pair类是一个容器类(我会多次强调,泛型天生就是为了容器类的方便实现),容纳了2个数据,但这2个数据类型是不确定的,用泛型T来表示。

关于泛型类如何使用,那是最基本的内容,在此就不讨论了。

2 泛型类跟接口及泛型方法2.1 泛型类跟接口及继承2.1.1泛型类泛型可以继承自某一个父类,或者实现某个接口,或者同时继承父类并且实现接口泛型也可用于匿名内部类匿名内部类2.1.2继承泛型类也可以继承Public Class A<T,A> extendsPublic Class A<T,A,B> extends ,2.1.3接口泛型也可以用于接口Public interface A<T>{}2.2 泛型方法2.2.1 方法是否拥有泛型方法跟其所在的类是否是泛型没有关系。

原则:无论何时只要你能做到,你就尽可能的使用泛型方法。

对于static方法你只能使用泛型方法。

在调用泛型方法时,通常不必指明参数类型因为编译器会为我找出具体类型,这称之为类型推断。

泛型方法也能跟可变参数共存: public static <T> void f(T…arg){}2.2.2 类型推断编译器能根据推断出返回的类型类型推断只能对赋值语句有效:这句不能被编译在范型方法中你可以显示指明类型,要指明类型必须在 点操作符与方法名之间插入尖括号,然后把类型置于尖括号中,如果是在类中的方法中使用必须加this.<type> 如果是static 方法需要加上类名。

3 泛型实现原理下面我们来讨论一下Java 中泛型类的实现原理。

在java 中,泛型是在编译器中实现的,而不是在虚拟机中实现的,虚拟机对泛型一无所知。

因此,编译器一定要把泛型类修改为普通类,才能够在虚拟机中执行。

在java 中,这种技术称之为“擦除”,也就是用Object 类型替换泛型。

上述代码经过擦除后就变成如下形式: public class Pair { public Pair(Object first, Object second) { this .first = first; this .second = second;}public Object getFirst() { return first; }public Object getSecond() { return second; }public void setFirst(Object newValue) { first = newValue; }public void setSecond(Object newValue) { second = newValue; }private Object first;private Object second;}大家可以看到,这是一个普通类,所有的泛型都被替换为Object类型,他被称之为原生类。

每当你用一个具体类去实例化该泛型时,编译器都会在原生类的基础上,通过强制约束和在需要的地方添加强制转换代码来满足需求,但是不会生成更多的具体的类(这一点和c++完全不同)。

我们来举例说明这一点:Pair<Employee> buddies = new Pair<Employee>();//在上述原生代码中,此处参数类型是Object,理论上可以接纳各种类型,但编译器通过强制约束//你只能在此使用Employee(及子类)类型的参数,其他类型编译器一律报错buddies.setFirst(new Employee("张三"));//在上述原生代码中,getFirst()的返回值是一个Object类型,是不可以直接赋给类型为Employee的buddy的//但编译器在此做了手脚,添加了强制转化代码,实际代码应该是Employee buddy = (Employee)buddies.getFirst();//这样就合法了。

但编译器做过手脚的代码你是看不到的,他是以字节码的形式完成的。

Employee buddy = buddies.getFirst();4 泛型数组你不能这样创建泛型数组T[] array = new T[size]; 因为编译器无法确定T 实际类型ArrayList<String>[] array = new ArrayList<String>[ size]; 这条语句同样也是不能编译的原因是数组将将跟踪它们的实际类型,而这个类型是在数组创建时确定的。

然而由于擦除泛型的类型信息被移除了,数组就无法保证ArrayList的实际类型.但是你可以这样ArrayList<String>[] array = (ArrayList<String>[]) new ArrayList[1] 编译器确保你只能向数组中添加ArrayList<String>() 对象而不能添加ArrayList<Integer>等其他类型。

创建泛型数组的二种方式:第一种:只能用数组接受因为泛型数组在运行时只能是第二种:该数组运行时类型是确切的类型5边界泛型就像字面意思表达的那样,你可以将代码运用到任何类型 既然是任何类型那么你就不能在类型上调用任何方法。

但是Object 中的方法是可以的,因为编译器知道这个类型至少是一个Object ,任何类就直接或者间接继承了Object 类。

如果什么方法都不能调那么你能用来干什么能,所以如果你想要调用方法那么你就需要边界就像下面这表示只要是和任何它的子类都可以。

那么现在你可以调用getColor()方法了,因为编译器知道T 至少是HasColor 类型,擦除也会擦除到边界这里是HasColor 如果没有设定边界那么默认会擦除到Object 。

如何你想要限定多个边界那么你只需在后面加上&符号即可。

6通配符数组的协变:如果B是A的子类那么A[] = new B[size] 是可以的。

Number[] num = new Integer[size] 那么如果向num数组中加入Double类型呢?(既然是Number类型那么你就没有理由阻止放入Number类型)你向Integer数组中加入Double这肯定导致错误,数组是Java内置类型他能在编译期跟运行进行检查错误。

所以我们无需担心。

那么我们来看看这条语句ArrayList<Number> arr = new ArrayList<Integer>();这条语句不能编译,原因是因为泛型不能协变,如果你允许的话那么你就可以往里面加入Number子类如Double 而你引用的却是ArrayList<Integer>类型,这违反了泛型的初衷编译期类型安全。

所以如果我们要想实现向数组那样协变那么就要用到通配符,<? extends Number> 表示我不知道是什么类型为了协办我也不关心。

它只要是Number 的子类或者Number就行。

我们知道即使你向上转型了(协变),你也不能保证类型安全。

所以泛型向上转型之后你就丢失了向其中添加任何东西的能力,即使Ojbect也不行.但是添加null是可以的。

因为null是任何对象的引用但没有实际意义。

就是你即使往Numer 数组中添加null一样它并不会报错。

Get()方法能够能行是编译器至少知道?至少是一个Numberpublic static void test(ArrayList<? extends Number> arr) {// arr.add(new Integer(2)); 不能编译arr.add(null);//OKNumber obj = arr.get(0);}如果你想向其中添加内容那么你可以使用<? Supper Number >表示我不知道是什么类型为了协办我也不关心。

它只要是Number或者Number的子类就行,add()方法只能添加Number或者Number的子类。

为什么现在添加内容是安全的呢?因为编译器至少知道Number类型或者Number的父类型,所以向里添加子类是安全的如:ArrayList<Object> 你可以添加任何类型。

这当然包括Number或者其子类啦,但你却不能再添加其他的类型了Number的父类(Object)也不行,如果可以的那么就可添加非Number类型了。

相关文档
最新文档