Java泛型详解,通俗易懂只需5分钟
Java的泛型详解(一)
Java的泛型详解(⼀)Java的泛型详解泛型的好处编写的代码可以被不同类型的对象所重⽤。
因为上⾯的⼀个优点,泛型也可以减少代码的编写。
泛型的使⽤简单泛型类public class Pair<T> {private T first;private T second;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 first) {this.first = first;}public void setSecond(T second) {this.second = second;}}上⾯例⼦可以看出泛型变量为T;⽤尖括号(<>)括起来,并放在类名后⾯;泛型还可以定义多个类型变量⽐如上⾯的例⼦ first和second不同的类型:public class Pair<T, U> {....}注: 类型变量的定义需要⼀定的规范:(1) 类型变量使⽤⼤写形式,并且要⽐较短;(2)常见的类型变量特别代表⼀些意义:变量E 表⽰集合类型,K和V表⽰关键字和值的类型;T、U、S表⽰任意类型;类定义的类型变量可以作为⽅法的返回类型或者局部变量的类型;例如: private T first;⽤具体的类型替换类型变量就可以实例化泛型类型;例如: Pair<String> 代表将上述所有的T 都替换成了String由此可见泛型类是可以看作普通类的⼯⼚泛型⽅法我们应该如何定义⼀个泛型⽅法呢?泛型的⽅法可以定义在泛型类,也可以定义在普通类,那如果定义在普通类需要有⼀个尖括号加类型来指定这个泛型⽅法具体的类型;public class TestUtils {public static <T> T getMiddle(T... a){return a[a.length / 2];}}类型变量放在修饰符(static)和返回类型的中间;当你调⽤上⾯的⽅法的时候只需要在⽅法名前⾯的尖括号放⼊具体的类型即可;String middle = TestUtils.<String>getMiddle("a", "b", "c");如果上图这种情况其实可以省略,因为编译器能够推断出调⽤的⽅法⼀定是String,所以下⾯这种调⽤也是可以的;String middle = TestUtils.getMiddle("a", "b", "c");但是如果是以下调⽤可能会有问题:如图:可以看到变意思没有办法确定这⾥的类型,因为此时我们⼊参传递了⼀个Double3.14 两个Integer1729 和0 编译器认为这三个不属于同⼀个类型;此时有⼀种解决办法就是把整型写成Double类型类型变量的限定有时候我们不能⽆限制的让使⽤者传递任意的类型,我们需要对我们泛型的⽅法进⾏限定传递变量,⽐如如下例⼦计算数组中最下的元素这个时候是⽆法编译通过的,且编译器会报错因为我们的编译器不能确定你这个T 类型是否有compareTo这个函数,所以这么能让编译器相信我们这个T是⼀定会有compareTo呢?我们可以这么写<T extends Comparable> 这⾥的意思是T⼀定是继承Comparable的类因为Comparable是⼀定有compareTo这个⽅法,所以T⼀定有compareTo⽅法,于是编译器就不会报错了因为加了限定那么min这个⽅法也只有继承了Comparable的类才可以调⽤;如果要限定⽅法的泛型继承多个类可以加extends 关键字并⽤&分割如:T extends Comparable & Serializable限定类型是⽤&分割的,逗号来分割多个类型变量<T extends Comparable & Serializable , U extends Comparable>类型擦除不论什么时候定义⼀个泛型类型,虚拟机都会提供⼀个相应的原始类型(raw type)。
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 泛型详解与范例⽬录⼀、泛型的使⽤⼆、泛型类的定义-类型边界三、类型擦除四、泛型类的使⽤-通配符五、泛型⽅法六、泛型的限制⼀、泛型的使⽤前⾯我们学集合的时候,简单的说过泛型的使⽤。
如下: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泛型
1 java中泛型Java中的泛型–泛型是Java SE 1.5的新特性,泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。
–这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口、泛型方法。
Java语言引入泛型的好处是安全简单Class ArrayList<E>:声明一个泛型类ArrayList,其中E可以使用任意一个具体类型替代,泛型类型往往使用一个大写字母表示。
public boolean add(E o):E是泛型,也就是说,使用add方法时,可以为其传递任意一种类型的参数。
其中此处的E是在类中定义的Java中泛型的作用:简单安全–在编译的时候检查类型安全,并且所有的强制转换都是自动和隐式的,提高代码的重用率。
–消除代码中的强制类型转换,同时获得一个附加的类型检查层,该检查层可以防止有人将错误类型的值保存在集合中泛型类指的是在定义一个类的时候,在类名处使用<E>的形式,标记该类中使用到泛型,也就是可以使用E来表示类中属性,方法参数等类型,使用时再具体指定是哪种具体类型。
声明类名后使用<E>(E可以是任何其他字母),即可以指定该类是一个泛型类类型参数可以在该类中需要数据类型的地方使用,如属性声明、方法声明等一个简单的泛型类泛型类最常见的应用是API中集合类。
public class Gen<E> {private E atr;public Gen(){}public E getAtr() {return atr;}public void setAtr(E atr) {this.atr = atr; }……方法也可以声明成泛型方法,只要在返回值前声明泛型参数列表即可泛型方法使得该方法能够独立于类而产生变化要定义泛型方法,只需将泛型参数列表置于返回值之前public <E> E getX(E x){return x;}注意:是否拥有泛型方法,与其所在的类是否泛型没有关系。
Java的泛型讲解
Java的泛型讲解本文由广州Java培训为你整理:今儿为大家讲解的是JDK5.0支持的新功能Java的泛型。
,JDK1.5 令我们期待很久,可是当他发布的时候却更换版本号为5.0.这说明Java已经有大幅度的变化。
1、Java泛型其实Java的泛型就是创建一个用类型作为参数的类。
就象我们写类的方法一样,方法是这样的method(String str1,String str2 ),方法中参数str1、str2的值是可变的。
而泛型也是一样的,这样写class Java_Generics,这里边的K和V就象方法中的参数str1和str2,也是可变。
1.1.泛型通配符下面我们先看看这些程序://Code list 2void TestGen0Medthod1(List l){for (Object o : l)System.out.println(o);}看看这个方法有没有异议,这个方法会通过编译的,假如你传入String,就是这样List.接着我们调用它,问题就出现了,我们将一个List当作List传给了方法,JVM会给我们一个警告,说这个破坏了类型安全,因为从List中返回的都是Object类型的。
1.2.编写泛型类要注意:1)在定义一个泛型类的时候,在"<>"之间定义形式类型参数,例如:"class TestGen",其中"K", "V"不代表值,而是表示类型。
2)实例化泛型对象的时候,一定要在类名后面指定类型参数的值(类型),一共要有两次书写。
例如:TestGent=new TestGen();3)泛型中,extends并不代表继承,它是类型范围限制。
2、泛型与数据类型转换2.1.消除类型转换在JDK5.0中我们完全可以这么做,这里我们使用泛化版本的HashMap,这样就不用我们来编写类型转换的代码了,类型转换的过程交给编译器来处理,是不是很方便,而且很安全。
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泛型机制详解带着问题阅读1、什么是Java泛型,有什么⽤处2、Java泛型的实现机制是什么3、Java泛型有哪些局限和限制Java泛型介绍引⼊泛型之前,试想编写⼀个加法器,为处理不同数字类型,就需要对不同类型参数进⾏重载,但其实现内容是完全⼀样的,如果是⼀个更复杂的⽅法,⽆疑会造成重复。
public int add(int a, int b) {return a + b;}public float add(float a, float b) {return a + b;}public double add(double a, double b) {return a + b;}⼀般的类和⽅法,只能使⽤具体的类型,要么是基本类型,要么是⾃定义的类。
如果要编写可以应⽤于多种类型的代码,这种刻板的限制对代码的束缚就会很⼤。
《Java编程思想》Java在1.5版本引⼊泛型,通过泛型实现的加法代码可简化为:public <T extends Number> double add(T a, T b) {return a.doubleValue() + b.doubleValue();}泛型的核⼼概念是参数化类型,使⽤参数指定⽅法类型,⽽⾮硬编码。
泛型的出现带给我们很多好处,其中最重要的莫过于对集合类的改进,避免了任意类型都可以丢到同⼀个集合⾥的不可靠问题。
然⽽Python和Go的集合可以容纳任意类型,这究竟是进步还是退步呢Java泛型使⽤简介泛型⼀般有三种使⽤⽅式:泛型类、泛型接⼝和泛型⽅法。
泛型类public class GenericClass<T> {private T member;}...// 初始化时指定泛型类型GenericClass<String> instance = new GenericClass<String>();泛型接⼝public interface GenericInterface<T> {void test(T param);}// 实现类指定泛型类型public class GenericClass implements GenericInterface<String> {@Overridepublic void test(String param) {...}}泛型⽅法如前⽂中加法代码的实现就是泛型⽅法。
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 泛型?Java 泛型实质就是⼀种语法约束,泛型是Java SE 1.5的新特性,泛型的本质是参数化类型,也就是说所操作的数据类型被指定为⼀个参数,这种参数类型可以⽤在类、接⼝和⽅法的创建中,分别称为泛型类、泛型接⼝、泛型⽅法。
⼆:泛型的核⼼原理是什么?泛型的核⼼原理其实就是泛型的 T 类型参数的原理,Java 编译器在编译阶段会将泛型代码转换为普通的⾮泛型代码,实质就是擦除类型参数 T 替换为限定类型(上限类型或者下限类型)(⽆限定类型替换为Object)且插⼊必要的强制类型转换操作,同时 java 编译器是通过先检查代码中泛型的类型然后再进⾏类型擦除,最后进⾏编译的。
编译器在编译时擦除所有类型相关信息,所以在运⾏时不存在任何类型相关信息,例如List在运⾏时仅⽤⼀个List来表⽰,这样做的⽬的是确保能和 Java 5 之前的版本开发⼆进制类库进⾏兼容,我们⽆法在运⾏时访问到类型参数,因为编译器已经把泛型类型转换成了原始类型。
三:泛型的好处是什么?泛型的好处其实就是约束,可以让我们编写的接⼝、类、⽅法等脱离具体类型限定⽽适⽤于更加⼴泛的类型,从⽽使代码达到低耦合、⾼复⽤、⾼可读、安全可靠的特点,避免主动向下转型带来的恶⼼可读性和隐晦的转换异常,尽可能的将类型问题暴露在 IDE 提⽰和编译阶段。
四:泛型类⼀般的类只能使⽤具体的类型,要么是基本类型,要么是⾃定义类型。
如果要编写可以⽤于多种类型的类呢?那么我们是不是可以想到⽤Object来定义类型,的确,⽤Object完全可以实现存储任何类型的对象,但是我们在使⽤容器的时候⼜想约束容器持有某种类型的对象。
因此,与其使⽤Object,我们更喜欢暂时不指定类型,⽽是稍后再决定具体使⽤什么类型。
要达到此⽬的,需要使⽤泛型参数,⽤尖括号括住,放在类名后⾯,然后在使⽤这个类的时候,再⽤实际的类型替换此参数类型即可public class FanXing<T> {public T t;public T getT() {return t;}public FanXing(T t) {this.t = t;}public static void main(String[] args) {FanXing<String> fx1 = new FanXing<>("a");FanXing<Integer> fx2 = new FanXing<>(1);System.out.println(fx1.getT().getClass()); //ng.StringSystem.out.println(fx2.getT().getClass()); //ng.Integer}}五:泛型接⼝public interface IFanXing<T1, T2> {T1 show1(T2 t);T2 show2(T1 t);}public class FanXing implements IFanXing<String, Integer> {@Overridepublic String show1(Integer t) {return String.valueOf(t);}@Overridepublic Integer show2(String t) {return Integer.valueOf(t);}public static void main(String[] args) {FanXing fanXing = new FanXing();System.out.println(fanXing.show1(1)); //1System.out.println(fanXing.show2("1")); //1}}六:泛型⽅法到⽬前为⽌,我们看到的泛型,都是应⽤于整个类上。
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泛型详解(转)1.为什么需要泛型转载请注明出处:泛型在Java中有很重要的地位,⽹上很多⽂章罗列各种理论,不便于理解,本篇将⽴⾜于代码介绍、总结了关于泛型的知识。
先看下⾯的代码:[java]1. List list = new ArrayList();2. list.add("CSDN_SEU_Calvin");3. list.add(100);4. for (int i = 0; i < list.size(); i++) {5. String name = (String) list.get(i); //取出Integer时,运⾏时出现异常6. System.out.println("name:" + name);7. }本例向list类型集合中加⼊了⼀个字符串类型的值和⼀个Integer类型的值(这样是合法的,因为此时list默认的类型为Object类型)。
在循环中,由于忘记了之前添加了Integer类型的值或其他原因,运⾏时会出现ng.ClassCastException。
为了解决这个问题,泛型应运⽽⽣。
2.泛型的使⽤Java泛型编程是JDK1.5版本后引⼊的。
泛型让编程⼈员能够使⽤类型抽象,通常⽤于集合⾥⾯。
只要在上例中将第1⾏代码改成如下形式,那么就会在编译list.add(100)时报错。
[java]1. List<String> list = new ArrayList<String>();通过List<String>,直接限定了list集合中只能含有String类型的元素,从⽽在上例中的第6⾏中,⽆须进⾏强制类型转换,因为集合能够记住其中元素的类型信息,编译器已经能够确认它是String类型了。
3.泛型只在编译阶段有效看下⾯的代码:[java]1. ArrayList<String> a = new ArrayList<String>();2. ArrayList b = new ArrayList();3. Class c1 = a.getClass();4. Class c2 = b.getClass();5. System.out.println(c1 == c2); //true上⾯程序的输出结果为true。
Java 中泛型的分析
Java 中泛型的分析Java泛型(generics)是JDK 5中引入的一个新特性,允许在定义类和接口的时候使用类型参数(type parameter)。
声明的类型参数在使用时用具体的类型来替换。
泛型最主要的应用是在JDK 5中的新集合类框架中。
对于泛型概念的引入,开发社区的观点是褒贬不一。
从好的方面来说,泛型的引入可以解决之前的集合类框架在使用过程中通常会出现的运行时刻类型错误,因为编译器可以在编译时刻就发现很多明显的错误。
而从不好的地方来说,为了保证与旧有版本的兼容性,Java泛型的实现上存在着一些不够优雅的地方。
当然这也是任何有历史的编程语言所需要承担的历史包袱。
后续的版本更新会为早期的设计缺陷所累。
开发人员在使用泛型的时候,很容易根据自己的直觉而犯一些错误。
比如一个方法如果接收List<Object>作为形式参数,那么如果尝试将一个List<String>的对象作为实际参数传进去,却发现无法通过编译。
虽然从直觉上来说,Object 是String的父类,这种类型转换应该是合理的。
但是实际上这会产生隐含的类型转换问题,因此编译器直接就禁止这样的行为。
本文试图对Java泛型做一个概括性的说明。
类型擦除正确理解泛型概念的首要前提是理解类型擦除(type erasure)。
Java中的泛型基本上都是在编译器这个层次来实现的。
在生成的Java字节代码中是不包含泛型中的类型信息的。
使用泛型的时候加上的类型参数,会被编译器在编译的时候去掉。
这个过程就称为类型擦除。
如在代码中定义的List<Object> 和List<String>等类型,在编译之后都会变成List。
JVM看到的只是List,而由泛型附加的类型信息对JVM来说是不可见的。
Java编译器会在编译时尽可能的发现可能出错的地方,但是仍然无法避免在运行时刻出现类型转换异常的情况。
类型擦除也是Java的泛型实现方式与 C++模板机制实现方式之间的重要区别。
Java泛型
Java泛型资料一:泛型是JAVA SE 1.5的新特性,泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。
这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口、泛型方法。
JAVA语言引入泛型的好处是安全简单。
在JAVA SE 1.5之前,没有泛型的情况的下,通过对类型Object的引用来实现参数的“任意化”,“任意化”带来的缺点是要做显式的强制类型转换,而这种转换是要求开发者对实际参数类型可以预知的情况下进行的。
对于强制类型转换错误的情况,编译器可能不提示错误,在运行的时候才出现异常,这是一个安全隐患。
泛型的好处是在编译的时候检查类型安全,并且所有的强制转换都是自动和隐式的,提高代码的重用率。
泛型在使用中还有一些规则和限制:1、泛型的类型参数只能是类类型(包括自定义类),不能是简单类型。
2、同一种泛型可以对应多个版本(因为参数类型是不确定的),不同版本的泛型类实例是不兼容的。
3、泛型的类型参数可以有多个。
4、泛型的参数类型可以使用extends语句,例如<T extends superclass>。
习惯上成为“有界类型”。
5、泛型的参数类型还可以是通配符类型。
例如Class<?> classType =Class.forName(ng.String);例一:使用了泛型:查看复制到剪切板打印1.public class Gen<T> {2.private T ob; //定义泛型成员变量3.4.public Gen(T ob) {5.this.ob = ob;6. }7.8.public T getOb() {9.return ob;10. }11.12.public void setOb(T ob) {13.this.ob = ob;14. }15.16.public void showTyep() {17. System.out.println("T的实际类型是: " + ob.getClass().getName());18. }19.}20.21.public class GenDemo {22.public static void main(String[] args){23.//定义泛型类Gen的一个Integer版本24. Gen<Integer> intOb=new Gen<Integer>(88);25. intOb.showTyep();26.int i= intOb.getOb();27. System.out.println("value= " + i);28.29. System.out.println("----------------------------------");30.31.//定义泛型类Gen的一个String版本32. Gen<String> strOb=new Gen<String>("Hello Gen!");33. strOb.showTyep();34. String s=strOb.getOb();35. System.out.println("value= " + s);36. }37.}例二:没有使用泛型时:查看复制到剪切板打印1.public class Gen2 {2.private Object ob; //定义一个通用类型成员3.4.public Gen2(Object ob) {5.this.ob = ob;6. }7.8.public Object getOb() {9.return ob;10. }11.12.public void setOb(Object ob) {13.this.ob = ob;14. }15.16.public void showTyep() {17. System.out.println("T的实际类型是: " + ob.getClass().getName());18. }19.}20.21.22.public class GenDemo2 {23.public static void main(String[] args) {24.//定义类Gen2的一个Integer版本25. Gen2 intOb = new Gen2(new Integer(88));26. intOb.showTyep();27.int i = (Integer) intOb.getOb();28. System.out.println("value= " + i);29.30. System.out.println("----------------------------------");31.32.//定义类Gen2的一个String版本33. Gen2 strOb = new Gen2("Hello Gen!");34. strOb.showTyep();35. String s = (String) strOb.getOb();36. System.out.println("value= " + s);37. }38.}运行结果:两个例子运行Demo结果是相同的,控制台输出结果如下:T的实际类型是: ng.Integervalue= 88----------------------------------T的实际类型是: ng.Stringvalue= Hello Gen!Process finished with exit code 0补充:实际上泛型可以用得很复杂,复杂到编写代码的人员自己也难以看懂。
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泛型使用详细分析一、泛型的简介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泛型探究一、概述。
前段时间,有同事说想要了解一下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中,泛型函数的定义需要在函数名之前使用尖括号<>来声明泛型参数。
泛型参数可以是任意合法的标识符,通常使用大写字母表示。
泛型参数可以在函数的参数列表、返回值类型和函数体中使用,用于表示某种未知的数据类型。
下面是一个简单的泛型函数的定义示例:```public <T> void printArray(T[] array) {for (T item : array) {System.out.println(item);}}```在上述代码中,`<T>`表示泛型参数,`printArray`函数的参数`array`是一个类型为`T`的数组。
在函数体中,可以使用`T`来表示数组中的元素类型。
二、泛型函数的使用泛型函数可以像普通函数一样被调用,但在调用时需要指定实际的类型参数。
可以使用尖括号<>在函数名后面传入实际的类型参数。
下面是一个使用泛型函数的示例:```Integer[] intArray = {1, 2, 3, 4, 5};String[] stringArray = {"Hello", "World"};printArray(intArray); // 调用printArray函数,传入Integer[]类型的参数printArray(stringArray); // 调用printArray函数,传入String[]类型的参数```在上述代码中,分别定义了一个整型数组`intArray`和一个字符串数组`stringArray`。
然后调用了`printArray`函数两次,分别传入了`intArray`和`stringArray`作为参数。
Java泛型详解(超详细的java泛型方法解析)
Java泛型详解(超详细的java泛型⽅法解析)⽬录2. 什么是泛型3. 使⽤泛型的好处4. 泛型的使⽤4.1 泛型类4.2 泛型⽅法4.3 泛型接⼝5. 泛型通配符5.1 通配符基本使⽤5.2 通配符⾼级使⽤6. 总结1. 为什么使⽤泛型早期的Object类型可以接收任意的对象类型,但是在实际的使⽤中,会有类型转换的问题。
也就存在这隐患,所以Java提供了泛型来解决这个安全问题。
来看⼀个经典案例:public static void main(String[] args) {//测试⼀下泛型的经典案例ArrayList arrayList = new ArrayList();arrayList.add("helloWorld");arrayList.add("taiziyenezha");arrayList.add(88);//由于集合没有做任何限定,任何类型都可以给其中存放for (int i = 0; i < arrayList.size(); i++) {//需求:打印每个字符串的长度,就要把对象转成String类型String str = (String) arrayList.get(i);System.out.println(str.length());}}运⾏这段代码,程序在运⾏时发⽣了异常:Exception in thread "main" ng.ClassCastException: ng.Integer cannot be cast to ng.String发⽣了数据类型转换异常,这是为什么?由于ArrayList可以存放任意类型的元素。
例⼦中添加了⼀个String类型,添加了⼀个Integer类型,再使⽤时都以String的⽅式使⽤,导致取出时强制转换为String类型后,引发了ClassCastException,因此程序崩溃了。
Java 泛型
泛型泛型的概念在集合中存储对象并在使用前进行类型转换是多么的不方便。
泛型防止了那种情况的发生。
它提供了编译期的类型安全,确保你只能把正确类型的对象放入集合中,避免了在运行时出现ClassCastException。
•不使用泛型/***这样做的一个不好的是Box里面现在只能装入String类型的元素,今后如果我们需要装入Integer等其他类型的元素,*还必须要另外重写一个Box,代码得不到复用,使用泛型可以很好的解决这个问题。
*/public class Box {private String object;public void set(String object) {this.object = object;}public String get(){return object;}}•使用泛型public class GenericBox<T> {// T stands for "Type"private T t;public void set(T t) { this.t = t; }public T get() { return t; }}限定通配符和非限定通配符•限定通配符限定通配符对类型进行了限制。
有两种限定通配符:一种是<? extends T>它通过确保类型必须是T及T的子类来设定类型的上界,另一种是<? super T>它通过确保类型必须是T及T的父类设定类型的下界。
泛型类型必须用限定的类型来进行初始化,否则会导致编译错误。
•非限定通配符<?>表示了非限定通配符,因为<?>可以用任意类型来替代。
public class BoundaryCharExample {//查找一个泛型数组中大于某个特定元素的个数public static <T> int countGreaterThan(T[] array,T elem){int count = 0;for (T e : array) {if (e > elem) { // compiler error++count;}}return count;}/** comliler error:但是这样很明显是错误的,* 因为除了short, int, double, long, float, byte, char等原始类型,* 其他的类并不一定能使用操作符" > "* 解决 --> 使用限定通配符/边界符* */}•使用限定通配符改进public class BoundaryCharExample2 {public static <T extends Comparable<T>> int countGreaterThan(T[] ar ray,T elem){//<T extends Comparable<T>>就是通配符,类型必须是 Comparable<T>及其子类int count = 0;for (T e : array) {if (e pareTo(elem)>0) {++count;}}return count;}}•面试题:List<? extends T> 和List <? super T>之间有什么区别 ?List<? extends T>可以接受任何继承自T的类型的List,List<? super T>可以接受任何T的父类构成的List。