引言
泛型除了像前面两节所讲的在类名后进行定义外,也可以在单独的方法上进行定义。这次我们就讲下如何在方法进行泛型声明和使用
同样的,假设一个汽车改装厂的场景。延用上节中的Runnable接口、Ford类、Buick类。新增CarRefitFactory类(汽车改装工厂类)。
第一版
代码如下:
public interface Runnable {
public void run();
}
public class Buick implements Runnable {
@Override
public void run(){
System.out.println("buick run");
}
public void autoRun(){
System.out.println("buick auto-run");
}
}
public class Ford implements Runnable {
@Override
public void run(){
System.out.println("ford run");
}
public void fly(){
System.out.println("ford fly");
}
}
public class CarRefitFactory {
public static Runnable turnTo(Class<?> targetClass, Runnable srcCar) {
Runnable targetCar = null;
Object o;
try {
o = targetClass.newInstance();
if( o instanceof Runnable){
targetCar = (Runnable)o;
//执行改装过程...。例如获取源轿车(srcCar)的属性并赋值给新的车(targetCar),具体过程省略,非重点。
}
}
catch (InstantiationException e) {
e.printStackTrace();
}
catch (IllegalAccessException e) {
e.printStackTrace();
}
return targetCar;
}
public static void main(String[] args) {
/** 演示使用 */
Runnable runable = CarRefitFactory.turnTo(Buick.class, new Ford());
Buick newBuick = (Buick)runable;
newBuick.autoRun();
Ford newFord = (Ford)CarRefitFactory.turnTo(Ford.class, new Buick());
newFord.fly();
}
}
简单说下CarRefitFactory,其提供一个静态工厂方法turnTo,接收目标car的Class对象及源car对象参数,返回目标car对象。通俗讲就是将一辆车改装成另外一辆车。srcCar参数代表将被改装的车,targetClass代表改装成什么样的车的相关信息,这样说估计大家能理解了。main方法中演示了使用方法。
下面继续思考下turnTo方法的不足之处或别扭的地方。从使用示例可以看出,里面用到了强制类型转换,同样会出现由于人为写错因素造成ClassCastException(如将Ford.class错写成Buick.class),这种异常在编译期间不会被检出,当系统运行时就可能出错,因此在编程中应尽量避免不必要的强制类型转换。那有没有更好的方式?下面就看方法上的泛型使用。
第二版(只修改CarRefitFactory类)
public class CarRefitFactory {
public static <E extends Runnable> E turnTo(Class<E> targetClass, Runnable srcCar) {
E targetCar = null;
try {
targetCar = targetClass.newInstance();
//执行改装过程...。例如获取源轿车(srcCar)的属性并赋值给新的车(targetCar),具体过程省略,非重点。
}
catch (InstantiationException e) {
e.printStackTrace();
}
catch (IllegalAccessException e) {
e.printStackTrace();
}
return targetCar;
}
public static void main(String[] args) {
/** 演示使用 */
Buick newBuick = CarRefitFactory.turnTo(Buick.class, new Ford());
newBuick.autoRun();
Ford newFord = CarRefitFactory.turnTo(Ford.class, new Buick());
newFord.fly();
}
}
首先在trunTo方法上进行泛型声明<E extends Runnable>,限制E必须是Runnable的子类或Runnable自身。接着,修改参数targetClass类对象类型及返回值类型是E。这样将欲改装成的车类型(参数类型)跟实际返回的车类型(返回值类型)进行了统一,故而在使用turnTo方法时,编译器会自动识别类型,不需要手动进行强制转换。而且代码看上去也简单易懂。
上面演示了方法上声明和使用泛型及分析了泛型带给程序的易读性和安全性好处。细心的读者会发现,方法上泛型声明跟类上的泛型声明一致,使用也一样。下面就对这两种泛型情况进行下总结:
类上泛型跟方法上泛型对比
共同点:
一、都是先声明泛型后使用(感觉是废话,还是强调下要先声明泛型),泛型声明都是<E> 或<E extends Parent>形式(E只是一个类型标记,可以是其它大写字母,甚至小写字母)。都能声明多个泛型,比如Test<K, V, M>,多个泛型类型之间用逗号分隔。
二、声明后的E类型都看作具体JAVA类型使用。对于无限制的E类型(<E>声明方式),被当成Object类型对待(因为在类实例化之前或方法调用前都不知道会传哪个具体JAVA类型,所以只能当作一般化的Object处理,很好理解吧);对于有限制的E类型(<E extends Parent>声明方式),被当成Parent类型对待(因为E肯定是Parent的子类或自身,这个也很好理解)
不同点:
一、泛型声明的位置不同,类上泛型声明是在类名称后面进行声明(public class Driver<T extends Runnable>),方法上泛型声明是在方法返值类型的前面(public static <E extends Runnable> E,在E返回类型前面进行了声明)。实际上,所谓类上泛型跟方法上泛型就是根据泛型声明位置直观的划分,只是方便本人说明泛型的声明和使用,可能别的书籍或网上有不同的叫法,没有关系,只要大家能理解就行,还请大家不要过分纠结在某些概念上。
二、由于泛型声明位置不同,就带来了泛型作用范围的不同。类上声明的泛型,在整个类范围都是可见的;而方法上声明的泛型,只在当前方法体范围内有效。这个也是很自然的,没什么可多说的。
好了就总结这么多了,下面咱们来联系下实际,看下项目中经常用到的泛型。比如Map,List。
联系实际
Map接口和List接口是java.util包下的,大家在项目中经常用到。其典型使用如下:
Map<String, String> map = new HashMap<String, String>();
map.put("wz", "网站");
List<Integer> list = new ArrayList<Integer>();
list.add(1);
作为工具类,方便大家使用,可能大家已经习惯了这种写法,但实际上在JDK1.5之前,还没有出现泛型时,是这样使用的
Map oldMap = new HashMap();
oldMap.put("wz", "网站");
List oldList = new ArrayList();
oldList.add(1);
在JDK1.5之后,上面写法也可以,代码也能正常运行,只是IDE会出现警示。但我要说的是,作为一个有追求的程序员,绝不能按上面的写法去编写代码,JVM之所以在编译期及运行期仍支持这种写法,仅仅是向上兼容以前版本JDK,使基于老版本JDK的项目不需要修改仍能正常运行,仅此而已。
对于这种传统写法不好的地方,我觉得还需要再次申明下,除了不能获得编译期类型安全受检外,代码的可读性也大打折扣,让人不忍直视(no law to see)。
今天就码到这里,明天再共同学习下泛型比较复杂难懂的地方,比如?和super关键字的使用。
版权声明:本文为博主原创文章,未经博主允许不得转载。
分享到:
相关推荐
这些“java泛型学习全面页面下载资料”很可能包含以下内容: 1. **泛型的基本概念**:解释了泛型是什么,以及如何通过使用尖括号`<>`来定义泛型类、泛型接口和泛型方法。 2. **类型参数**:介绍如何定义类型参数,...
Java泛型是Java编程语言中的一个关键特性,它在2004年随着JDK 5.0的发布被引入,极大地增强了代码的类型安全性和重用性。泛型允许我们在编写类...通过深入学习和实践,我们可以更高效地利用泛型来设计和实现复杂系统。
Java泛型是Java编程语言中的一个关键特性,它在2004年随着JDK 5.0的发布被引入,极大地增强了代码的类型安全性和重用性。本篇文章将带你入门Java泛型,通过实例深入理解其核心概念。 1. **泛型的基本概念** - 泛型...
本压缩包包含了一些关于Java泛型的实例,旨在帮助学习者深入理解和应用这一特性。 泛型的主要目标是允许在编译时检查类型安全,并且所有的强制转换都是自动和隐式的,提高了代码的重用率。在Java中,泛型主要体现在...
Java泛型是Java编程语言中的一个关键特性,它在2004年随着JDK 5.0的发布被引入,极大地增强了类型安全性和代码可读性。...对于Java泛型的例子,可以通过运行和分析压缩包中的`generic`文件来加深理解和实践。
通过学习和练习这些内容,你可以深入理解Java集合框架的核心概念和泛型的应用,从而在编程实践中更加灵活和高效地处理数据。同时,不断的学习和实践是提升技能的关键,希望你能在Java世界中不断进步。
【Java 泛型】是Java编程语言中一个强大的...总之,这个压缩包包含的内容涉及了Java泛型、Java Web开发基础、以及现代Web应用中数据存储的几种方式,对于深入理解和实践Java编程,尤其是后端开发有着重要的参考价值。
通过阅读和理解`java泛型实例讲解代码`中的代码,你可以深入学习如何在实际编程中应用这些概念,以及它们如何提升代码的健壮性和可维护性。这个压缩包可能包含了各种示例,如泛型类、泛型方法、边界限制等,通过这些...
学习这部分内容对于Java开发者至关重要,因为理解并熟练掌握Java集合框架和泛型,能有效地提升代码质量和效率,减少运行时错误。此外,了解枚举类型有助于编写更安全、更整洁的代码。通过深入研究和实践,开发者能够...
Java IO流、XML和泛型是Java编程中的关键概念,对于任何Java开发者来说,理解和熟练掌握这些技术至关重要。本文将深入探讨这三个主题,并通过具体的例子进行学习。 首先,我们来看Java IO流。IO流在Java中是用来...
Java编程语言中的反射和泛型是两个非常重要的概念,它们为开发者提供了强大的工具来操作类、接口、对象以及参数类型。在"myreflect.rar"这个压缩包中,我们可以期待找到一系列关于这两个主题的源代码示例,这将有助...
《Java泛型与集合》一书不仅详细介绍了泛型的基本概念和高级特性,还深入探讨了集合框架的使用方法和最佳实践。通过学习本书,读者将能够掌握Java泛型的核心技术,提高代码的质量和可维护性,同时充分利用集合框架的...
在Java编程语言中,泛型是一种强大的工具,它允许我们在编写代码时指定类型参数,从而提高了类型安全性和代码重用性。在Java SE 1.5及更高...学习泛型需要时间和实践,但一旦掌握,将极大地提升代码质量和开发效率。
Java5.0泛型编程是Java开发中的一个重要里程碑,它引入了一种强大的类型系统机制,大大增强了代码的类型安全性,并减少了在编译期间和运行时...通过深入学习和实践,开发者可以编写出更加高效、安全且易于维护的代码。
Java泛型在运行时会被类型擦除,这意味着所有的泛型信息在编译后都会消失,替换为原始类型。因此,泛型主要在编译时提供类型检查,并不改变运行时的行为。 六、泛型与反射 由于类型擦除,泛型在反射中的使用需要...
Java泛型是Java编程语言中的一个关键特性,它允许在定义类、接口和方法时指定类型参数,从而增强了代码的类型安全性和重用性。在本小测试中,我们将探讨几个与Java泛型相关的概念:通配符(Wildcards)、消除...
Java泛型是自Java 5版本引入的一种强大的类型系统特性,它允许我们在编程时指定容器(如列表、集合等)所存储的数据类型。这增强了代码的类型安全性...通过不断学习和实践,我们可以更好地掌握Java泛型这一强大的工具。
在学习Java反射和泛型时,理解它们的概念和使用场景是非常重要的。反射提供了一种动态操控程序的能力,常用于框架开发、插件系统、元数据处理等。而泛型则提高了代码的可读性和安全性,减少了类型转换的工作。结合...
JAVA学习是每位初学者步入编程...以上就是JAVA学习笔记的主要内容,对于非计算机专业的人来说,逐步理解并实践这些知识点将有助于建立起坚实的JAVA编程基础。在学习过程中,不断练习和实际应用是巩固知识的最好方式。
在本月的“Java 理论和实践”中,Brian Goetz 分析了束缚第一次使用泛型的用户的常见陷阱。您可以通过讨论论坛与作者和其他读者分享您对本文的看法。(也可以单击本文顶端或底端的讨论来访问这个论坛。)