Java 泛型示例 - 泛型方法,类,接口
java genrics 是 java 5 中引入的最重要的功能之一。
如果您一直在使用java collections并使用版本 5 或更高版本,那么我确定您已经使用过它。
java 中具有集合类的泛型非常容易,但是它提供了比仅创建集合类型更多的功能。
我们将在本文中尝试学习泛型的功能。如果我们使用专业术语,对泛型的理解有时会变得混乱,因此,我将尽量保持其简单易懂。
1. java 中的泛型
java 5 中添加了泛型,以提供编译时类型检查,并消除了classcastexception
使用集合类时常见的风险。整个收集框架都进行了重写,以使用泛型进行类型安全。让我们看看泛型如何帮助我们安全地使用集合类。
list list = new arraylist(); list.add("abc"); list.add(new integer(5)); for(object obj : list){ string str=(string) obj; }
上面的代码可以很好地编译,但是在运行时会引发classcastexception,因为我们试图将列表中的对象强制转换为string,而其中一个元素是integer类型。在java 5之后,我们使用如下收集类。
list<string> list1 = new arraylist<string>(); // java 7 ? list<string> list1 = new arraylist<>(); list1.add("abc"); //list1.add(new integer(5)); //编译错误 for(string str : list1){ //no type casting needed, avoids classcastexception }
请注意,在创建列表时,我们已指定列表中元素的类型为string。因此,如果我们尝试在列表中添加任何其他类型的对象,则该程序将引发编译时错误。还要注意,在循环中中,我们不需要列表中元素的类型转换,因此在运行时删除了classcastexception。
2. java通用类
我们可以使用泛型类型定义自己的类。泛型类型是通过类型进行参数化的类或接口。我们使用尖括号(<>)来指定类型参数。
为了了解其好处,我们假设有一个简单的类:
package com.journaldev.generics; public class genericstypeold { private object t; public object get() { return t; } public void set(object t) { this.t = t; } public static void main(string args[]){ genericstypeold type = new genericstypeold(); type.set("pankaj"); string str = (string) type.get(); //type casting, error prone and can cause classcastexception } }
请注意,在使用此类时,我们必须使用类型转换,并且它可以在运行时产生classcastexception。现在,我们将使用java通用类替换如下所示的相同类。
package com.journaldev.generics; public class genericstype<t> { private t t; public t get(){ return this.t; } public void set(t t1){ this.t=t1; } public static void main(string args[]){ genericstype<string> type = new genericstype<>(); type.set("pankaj"); //valid genericstype type1 = new genericstype(); //raw type type1.set("pankaj"); //valid type1.set(10); //valid and autoboxing support } }
注意main方法中genericstype类的使用。我们不需要进行类型转换,并且可以在运行时删除classcastexception。如果我们在创建时未提供类型,则编译器将发出警告,“ genericstype是原始类型。
泛型类型genericstype
还要注意,它支持java自动装箱。 comparable接口是接口中泛型的一个很好的例子,它写为: 以类似的方式,我们可以在java中创建通用接口。我们也可以像map界面具有多个类型参数。同样,我们也可以为参数化类型提供参数化值,例如 java通用类型命名约定可以帮助我们轻松理解代码,并且具有命名约定是java编程语言的最佳实践之一。因此,泛型也带有自己的命名约定。通常,类型参数名称是单个大写字母,以可以实现与java变量区分开。最常用的类型参数名称为: 有时我们不希望整个类都被参数化,在这种情况下,我们可以创建java泛型方法。由于构造函数是一种特殊的方法,因此我们也可以在构造函数中使用泛型类型。 这是一个显示java泛型方法示例的类。 注意_的isequal_方法签名显示了在方法中使用泛型类型的语法。另外,请注意如何在我们的java的程序中使用这些方法。我们可以在调用这些方法时指定类型,也可以像普通方法一样调用它们。java编译器足够聪明,可以确定要使用的变量的类型,这种功能称为类型变量。 假设我们要限制可以在参数化类型中使用的对象的类型,例如在比较两个对象的方法中,并且我们要确保接受的对象是可比较的。要声明一个有界的类型参数,请列出类型参数的名称,然后列出扩展关键字,再加上其上限,以下下面的方法。 这些方法的调用与*方法类似,不同之处在于,如果我们尝试使用任何非comparable的类,则引发编译时错误。 绑定类型参数可以与方法以及类和接口一起使用。 java泛型也支持多个范围,即<t扩展a&b&c>。在这种情况下,a可以是接口或类。如果a是类,则b和c应该是接口。在多个范围内,我们不能有多个类。 我们知道,如果a是b的子类,则java继承允许我们将变量a分配给另一个变量b。因此,我们可能认为可以将a的任何泛型类型分配给b的泛型类型,但事实并非如此。让我们用一个简单的程序看看。 我们可以通过扩展或实现来泛型一个通用类或接口。一个类或接口的类型参数与另一类或接口的类型参数之间的关系由extend和实现子句确定。 例如,arraylist
只要不更改type参数,子类型关系就会保留,下面显示了多个type参数的示例。 list
问号(?)是泛型中的通配符,表示未知类型。通配符可以用作参数,字段或局部变量的类型,有时还可以用作返回类型。在调用通用方法或实例化通用类时,不能使用通配符。在以下各节中,我们将学习上界通配符,下界通配符和通配符捕获。 9.1)java泛型上界通配符 上限通配符用于在方法中放宽对变量类型的限制。假设我们要编写一个将返回列表中数字总和的方法,那么我们的实现将是这样的。 现在,上述实现的问题在于它不适用于integers或doubles,因为我们知道list
可以像下面的程序一样修改上面的实现。 就像按照接口编写代码一样,在上述方法中,我们可以使用上限类号码的所有方法。请注意,对于上界列表,除空之外,我们不允许将任何对象添加到列表中。如果我们尝试在sum方法内将元素添加到列表中,则该程序将无法编译。 9.2)java泛型无限制通配符 有时,我们希望通用方法适用于所有类型,在这种情况下,可以使用*通配符。与使用<?extends object>。 我们可以为_printdata_方法提供list
9.3)java泛型下界通配符 假设我们要在方法中将整体添加到整数列表中,我们可以将参数类型保持为listobject
,因此它允许string和integer对象。但是,我们应始终尝试避免这种情况,因为在处理可能产生运行时错误的原始类型时,我们必须使用类型转换。3. java通用接口
package java.lang;
import java.util.*;
public interface comparable<t> {
public int compareto(t o);
}
new hashmap<string, list<string>>();
有效。4. java通用类型
5. java通用方法
package com.journaldev.generics;
public class genericsmethods {
//java generic method
public static <t> boolean isequal(genericstype<t> g1, genericstype<t> g2){
return g1.get().equals(g2.get());
}
public static void main(string args[]){
genericstype<string> g1 = new genericstype<>();
g1.set("pankaj");
genericstype<string> g2 = new genericstype<>();
g2.set("pankaj");
boolean isequal = genericsmethods.<string>isequal(g1, g2);
//above statement can be written simply as
isequal = genericsmethods.isequal(g1, g2);
//this feature, known as type inference, allows you to invoke a generic method as an ordinary method, without specifying a type between angle brackets.
//compiler will infer the type that is needed
}
}
6. java泛型绑定类型参数
public static <t extends comparable<t>> int compare(t t1, t t2){
return t1.compareto(t2);
}
7. java泛型和继承
package com.journaldev.generics;
public class genericsinheritance {
public static void main(string[] args) {
string str = "abc";
object obj = new object();
obj=str; // works because string is-a object, inheritance in java
myclass<string> myclass1 = new myclass<string>();
myclass<object> myclass2 = new myclass<object>();
//myclass2=myclass1; // compilation error since myclass<string> is not a myclass<object>
obj = myclass1; // myclass<t> parent is object
}
public static class myclass<t>{}
}
8. java通用类和子类型
interface mylist<e,t> extends list<e>{
}
9. java通用通配符
public static double sum(list<number> list){
double sum = 0;
for(number n : list){
sum += n.doublevalue();
}
return sum;
}
package com.journaldev.generics;
import java.util.arraylist;
import java.util.list;
public class genericswildcards {
public static void main(string[] args) {
list<integer> ints = new arraylist<>();
ints.add(3); ints.add(5); ints.add(10);
double sum = sum(ints);
system.out.println("sum of ints="+sum);
}
public static double sum(list<? extends number> list){
double sum = 0;
for(number n : list){
sum += n.doublevalue();
}
return sum;
}
}
public static void printdata(list<?> list){
for(object obj : list){
system.out.print(obj + "::");
}
}
上一篇: WPF布局容器
下一篇: 用数组实现数据记录的批量录入方法