Java泛型编程指南
- 格式:doc
- 大小:206.50 KB
- 文档页数:27
Java中的泛型编程技巧Java 中的泛型编程技巧随着软件系统规模的不断扩大,代码的维护成本也愈来愈高。
泛型编程(Generics Programming)正是为了解决这个问题而生的。
Java 作为一门比较成熟的编程语言,自 J2SE 5.0 版本起加入了泛型机制,使得 Java 的类型安全性得到进一步提高。
本文将介绍一些Java 中的泛型编程技巧,帮助大家编写更加清晰、简洁、安全、可复用的代码。
一、泛型基础1.1 泛型类泛型类(Generic Class)是指可以在类定义时指定类型参数的类。
泛型类可以包含普通成员变量和普通成员方法。
类型参数可以是任意类型,包括基本数据类型和引用类型。
例如:```public class MyGenericClass<T> {private T value;public void setValue(T value) {this.value = value;}public T getValue() {return value;}}```上面的代码中,T 是一个类型参数,可以被任意类型替代。
在实例化泛型类时会指定实际的类型参数,如下所示:```MyGenericClass<String> generic = new MyGenericClass<>();generic.setValue("Hello, World!");String value = generic.getValue();```1.2 泛型接口泛型接口(Generic Interface)与泛型类类似,可以在接口定义时指定类型参数。
泛型接口可以被实现为泛型类、非泛型类以及其他泛型接口。
例如:```public interface MyGenericInterface<T> {void setValue(T value);T getValue();}```可以将泛型接口用于实现非泛型类:```public class MyGenericClass<T> implements MyGenericInterface<T> {private T value;public void setValue(T value) {this.value = value;}public T getValue() {return value;}}```也可以将泛型接口用于实现其他泛型接口:```public interface MyGenericInterface2<U> extends MyGenericInterface<U> {void setOtherValue(U value);U getOtherValue();}```1.3 泛型方法泛型方法(Generic Method)是指可以在方法定义时指定类型参数的方法。
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方法的泛型泛型(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 泛型详解与范例⽬录⼀、泛型的使⽤⼆、泛型类的定义-类型边界三、类型擦除四、泛型类的使⽤-通配符五、泛型⽅法六、泛型的限制⼀、泛型的使⽤前⾯我们学集合的时候,简单的说过泛型的使⽤。
如下: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. 类型参数在使用泛型时,我们需要使用类型参数来指定具体的类型。
类型参数使用尖括号(<>)表示,放在类名或方法名后面。
例如,下面是一个泛型类的定义:```javapublic class Box<T> {private T value;public T getValue() {return value;}public void setValue(T value) {this.value = value;}}```在上述代码中,`T`是一个类型参数,可以在类的内部表示任意类型。
我们可以通过`T`来定义成员变量、方法参数、返回值等。
2. 类型通配符有时,我们需要在泛型中处理多个不同类型的对象。
这时,可以使用通配符(`?`)来表示任意类型。
例如,我们可以声明一个接收任意类型参数的方法:```javapublic void process(Box<?> box) {// 处理逻辑}```在上述代码中,`Box<?>`表示一个可以处理任意类型参数的`Box`对象。
3. 泛型方法除了在类中使用泛型,我们还可以在方法中使用泛型。
使用泛型方法可以使方法更通用、更具灵活性。
例如,下面是一个泛型方法的定义:```javapublic <T> T getValue(Box<T> box) {return box.getValue();}```在上述代码中,`<T>`表示一个类型参数,它可以在方法内部表示任意类型。
java 泛型创建实体对象并调用方法下载提示:该文档是本店铺精心编制而成的,希望大家下载后,能够帮助大家解决实际问题。
文档下载后可定制修改,请根据实际需要进行调整和使用,谢谢!本店铺为大家提供各种类型的实用资料,如教育随笔、日记赏析、句子摘抄、古诗大全、经典美文、话题作文、工作总结、词语解析、文案摘录、其他资料等等,想了解不同资料格式和写法,敬请关注!Download tips: This document is carefully compiled by this editor. I hope that after you download it, it can help you solve practical problems. The document can be customized and modified after downloading, please adjust and use it according to actual needs, thank you! In addition, this shop provides you with various types of practical materials, such as educational essays, diary appreciation, sentence excerpts, ancient poems, classic articles, topic composition, work summary, word parsing, copy excerpts, other materials and so on, want to know different data formats and writing methods, please pay attention!Java 泛型:创建实体对象并调用方法1. 引言在现代编程中,泛型是一种强大的工具,它允许我们编写通用的代码,从而提高代码的重用性和可读性。
"Java泛型"是一种在Java编程语言中定义泛型类型的方法。
它是一种用于编写灵活且可重用代码的技术,使得代码能够处理不同的数据类型。
泛型可以让你编写可以处理多种数据类型的代码,而不需要为每种数据类型编写新的代码。
Java泛型的用法主要包括以下步骤:
1. 定义泛型类型:使用尖括号<>来定义泛型类型,并在尖括号中指定泛型类型参数。
例如,List<E>是一个泛型类型,其中E是类型参数。
2. 创建泛型对象:使用泛型类型参数来创建对象。
例如,List<String> list = new ArrayList<String>();创建了一个String类型的List对象。
3. 使用泛型方法:在方法定义中使用泛型类型参数,以便在方法内部使用该参数来操作不同类型的对象。
例如,public static <T> T method(T arg) {return arg;}定义了一个名为method的泛型方法,它接受一个类型为T的参数并返回一个类型为T的对象。
4. 使用通配符:使用通配符来表示未知的泛型类型,以便编写更加灵活的代码。
例如,List<?> list = new ArrayList<String>();表示list 是一个未知类型的List对象,但实际上它是一个String类型的List对象。
总之,Java泛型是一种强大的工具,可以帮助你编写更加灵活、可重用和易于维护的代码。
此系列文章译自SUN的泛型编程指南, 看不懂译文的请看原文/j2se/1.5/pdf/generics-tutorial.pdfJava泛型编程指南一、绪言JDK1.5对JAVA语言进行了做了几个扩展,其中一个就是泛型。
本指南旨在介绍泛型。
如果你熟悉其它语言的构造类似的东西,特别是C++的模板(template),你会很快发现它们之间的相同点及重要的不同点;如果你在其他地方没看到过类似的东西,那反而更好,那样你就可以开始全新的学习,用不着去忘掉那些(对JAVA泛型)容易产生误解的东西。
泛型允许你对类型进行抽象。
最常见的例子是容器类型,比如那些在Collection层次下的类型。
下面是那类例子的典型用法:List myIntList = new LinkedList();//1myIntList.add(new Integer(0));//2Integer x = (Integer) myIntList.iterator().next();//3第3行里的强制类型转换有点烦人,程序通常都知道一个特定的链表(list)里存放的是何种类型的数据,但却一定要进行类型转换。
编译器只能保证迭代器返回的是一个对象,要保证对Integer类型变量的赋值是类型安全的话,必须进行类型转换。
类型转换不但会引起程序的混乱,还可能会导致运行时错误,因为程序员可能会犯错误。
如果程序员可以如实地表达他们的意图,即标记一个只能包含特定数据类型的链表,那会怎么样呢?这就是泛型背后的核心思想。
下面是前面代码的泛型写法:List<Integer> myIntList = new LinkedList<Integer>();//1'myIntList.add(new Integer(0));//2'Integer x = myIntList.iterator().next();//3'请注意变量myIntList的类型声明,它指明了这不仅仅是一个任意的List,还是一个Integer类型的List,写作List<Integer>。
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中的一种参数化类型,它允许我们在定义类、接口和方法时使用类型参数。
通过使用泛型,我们可以将类型作为参数传递给类、接口和方法,从而实现代码的复用和灵活性。
泛型的作用主要有以下几个方面: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。
此系列文章译自SUN的泛型编程指南, 看不懂译文的请看原文/j2se/1.5/pdf/generics-tutorial.pdfJava泛型编程指南一、绪言JDK1.5对JAVA语言进行了做了几个扩展,其中一个就是泛型。
本指南旨在介绍泛型。
如果你熟悉其它语言的构造类似的东西,特别是C++的模板(template),你会很快发现它们之间的相同点及重要的不同点;如果你在其他地方没看到过类似的东西,那反而更好,那样你就可以开始全新的学习,用不着去忘掉那些(对JAVA泛型)容易产生误解的东西。
泛型允许你对类型进行抽象。
最常见的例子是容器类型,比如那些在Collection层次下的类型。
下面是那类例子的典型用法:List myIntList = new LinkedList();//1myIntList.add(new Integer(0));//2Integer x = (Integer) myIntList.iterator().next();//3第3行里的强制类型转换有点烦人,程序通常都知道一个特定的链表(list)里存放的是何种类型的数据,但却一定要进行类型转换。
编译器只能保证迭代器返回的是一个对象,要保证对Integer类型变量的赋值是类型安全的话,必须进行类型转换。
类型转换不但会引起程序的混乱,还可能会导致运行时错误,因为程序员可能会犯错误。
如果程序员可以如实地表达他们的意图,即标记一个只能包含特定数据类型的链表,那会怎么样呢?这就是泛型背后的核心思想。
下面是前面代码的泛型写法:List<Integer> myIntList = new LinkedList<Integer>();//1'myIntList.add(new Integer(0));//2'Integer x = myIntList.iterator().next();//3'请注意变量myIntList的类型声明,它指明了这不仅仅是一个任意的List,还是一个Integer类型的List,写作List<Integer>。
我们说List是一个接受类型(在这个例子是Integer)参数的泛华的接口,在创建链表对象的时候,我们也指定了一个类型参数。
另外要注意的是在第3'行的类型转换已经不见了。
现在你可能会想,我们所做的全部都是为了把混乱消除。
我们没有在第3行把类型转换为Integer,而是在第1'行加了Integer类型参数;非也非也,这里面差别很大,编译器现在能够在编译期间检测程序的类型正确性。
当我们把myIntList声明为类型List<Integer>的后,就意味着变量myIntList在何时何地的使用都是正确的,编译器保证了这一点。
相反,类型转换只是告诉我们程序员认为它在程序的某个地方是正确的。
实际的结果是,程序(特别是大型的程序)的可读性和健壮性得到了提高。
免费linux公开课,,现在报名!二、定义简单的泛型下面是java.util包里的List和Iterator接口定义的一个小小的引用:public interface List<E>{void add(E x);Iterator<E> iterator();}public interface Iterator<E>{E next();boolean hasNext();}除了尖括号里的东西,这里所有的都应该很熟悉了。
那是List和Iterator接口的规范类型参数的声明。
类型参数可以用在任何的泛型声明中,就像使用普通的类型一样(虽然有一些很重要的限制;看第7部分)。
在绪言中,我们看到了List泛型声明的调用,比如List<Integer>。
在调用里面(通常称为参数化类型),所有出现规范类型参数(这里是E)的全部都用实际的类型参数(这里是Integer)所代替。
你可以想象成List<Integer>代表所有E都用Integer代替了的List:public interface IntegerList{void add(Integer x)Iterator<Integer> iterator();}这种想法是有所帮助的,但也会造成误解。
它是有所帮助的,是因为参数化类型List<integer>有看起来像这种扩展的方法。
它会造成误解,是因为泛型的声明实际上不会像那样去扩展;在源代码中、二进制文件中、硬盘和内在里,都没有代码的多个拷贝。
如果你是一个C++程序员,你会明白这跟C++的模板(template)很不同。
泛型声明是一次编译,永远使用,它会变成一个单独的class文件,就像一个普通的类或接口声明。
类型参数跟用在方法或构造函数里的普通的参数类似,就像一个方法具有描述它运算用到的值的类型的规范值参一样,泛化声明具有规范类型参数。
当一个方法被调用的时候,实际的参数将会被规范参数所代替而对方法求值。
当一个泛化声明被调用的时候,实际类型参数将会代替规范类型参数。
命名惯例要注意的一个地方。
我们建议你用一些简炼(如果可以的话只用一个字符)但却映眼的名字作为规范类型参数名。
在那些名字中最后避免小写字母,这样可以很容易把规范类型参数和普通的类或接口区分开来。
就像前面的例子一样,很多容器类型使用E。
我们将会在后面的例子里看到其他的惯例。
免费linux公开课,,现在报名!三、泛型和子类化我们来测试一下对泛型的理解,下面的代码是否正确呢?List<String> ls = new ArrayList<String>();//1List<Object> lo = ls;//2第1行肯定是正确的,问题的难点在于第2行;这样就归结为这个问题:一个字符串(String)链表(List)是不是一个对象链表?大部分人的直觉是:“肯定了!”那好,看一下下面这两行:lo.add(new Object());//3String s = ls.get(0);//4:企图把一个对象赋值给字符串!在这里我们把ls和lo搞混淆了。
我们通过别名lo来访问字符串链表ls,插入不确定对象;结果就是ls不再存储字符串,当我们尝试从里面取出数据的时候就会出错。
Java编译器当然不允许这样的事情发生了,所以第2行肯定会编译出错。
一般来说,如果Foo是Bar的子类型(子类或子接口),而G又是某个泛型声明的话,G<Foo>并不是G<Bar>的子类型。
这可能是学习泛型的时候最难的地方,因为它与我们的深层直觉相违背。
直觉出错的问题在于它把集合里的东西假想为不会改变的,我们的本能把这些东西看作是不变的。
举个例子,假设汽车公司为人口调查局提供一份驾驶员的列表,这看上去挺合理。
假设Driver是Person的一个子类,则我们认为List<Driver>是一个List<Person>。
而实际上提交的是一份驾驶员登记表的一个副本。
否则的话,人口调查局将可以驾驶员的人加入到那份列表中去,汽车公司的纪录受到破坏。
为了解决这类问题,我们需要考虑一些更灵活的泛型,到现在为止碰到的规则太受约束了。
四、通配符考虑一下写一个程序来打印一个集合对象(collection)里的所有元素。
在旧版的语言里面,你可以会像下面那样写:void printCollection(Collection c){Iterator i = c.iterator();for (k = 0; k < c.size(); k++){System.out.println(i.next());}}下面尝试着用泛型(和新的for循环语法)来写:void printCollection(Collection<Object> c){for (Object e : c) {System.out.println(e);}}这样的问题是新版本的代码还没旧版本的代码好用。
就像我们刚示范的一样,Collection<Object>并不是所有类型的集合的父类型,所以它只能接受Collection<Object>对象,而旧版的代码却可以把任何类型的集合对象作为参数来调用。
那么,什么才是所有集合类型的父类型呢?这个东西写作Collection<?>(读作“未知集合”),就是元素类型可以为任何类型的集合。
这就是它为什么被称为“通配符类型”的原因。
我们可以这样写:void printCollection(Collection<?> c){for (Object e : c) {System.out.println(e);}}现在,我们就可以以任何类型的集合对象作为参数来调用了。
注意,在printCollection() 方法里面,我们仍然可以从c对象中读取元素并赋予Object类型;因为无论集合里实际包含了什么类型,它肯定是对象,所以是类型安全的。
但对它插入任意的对象的话则是不安全的:Collection<?> c = new ArrayList<String>();c.add(new Object());//编译错误由于我们并不知道c的元素类型是什么,因此我们不能对其插入对象。
add()方法接受类型E,即集合的元素类型的参数。
当实际的类型参数是?的时候,就代表是某未知类型。
任何传递给add方法的参数,其类型必须是该未知类型的子类型。
因为我们并不知道那是什么类型,所以我们传递不了任何参数。
唯一的例外就是null,因为它是任何(对象)类型的成员。
另外,假设有一个List<?>,我们可以调用get()方法并使用其返回结果。
结果类型是一个未知类型,但我们都知道它是一个对象。
因此把get()方法的返回结果赋值给对象类型,或者把它作为一个对象参数传递都是类型安全的。
四、1-有界通配符考虑一个简单的画图程序,它可以画长方形和圆等形状。
为了表示这些形状,你可能会定义这样的一个类层次结构:public abstract class Shape{public abstract void draw(Canvas c);}public class Circle extends Shape{private int x, y, radius;public void draw(Canvas c) { ... }public class Rectangle extends Shape {private int x, y, width, height;public void draw(Canvas c) { ... }}这些类可以在canvas上描画:public class Canvas {public void draw(Shape s) {s.draw(this);}}任何的描画通常都包括有几种形状,假设它们用一个链表来表示,那么如果在Canvas里面有一个方法来画出所有的形状的话,那将会很方便:public void drawAll(List<Shape> shapes) {for (Shape s: shapes) {s.draw(this);}}但是现在,类型的规则说drawAll()方法只能对确切的Shape类型链表调用,比如,它不能对List<Circle>类型调用该方法。