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 异常。

  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类型了。

相关文档
最新文档