




已阅读5页,还剩26页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
JDK最新版本下载及JDK安装与配置 2009-07-07 16:10 佚名 苇帛开发 我要评论() Java语言的基本开发工具是SUN公司免费提供的JDK。本文介绍JDK最新版本以及JDK下载、安装和配置。“工欲善其事,必先利其器”。进行程序开发,首先要安装开发相关的软件,并且熟悉这些工具软件的基本使用。本章介绍一下两类开发工具的使用,重点是JDK最新版本以及JDK下载、安装和配置。基础开发工具基础开发工具是进行程序设计的基础,包含开发中需要的一些基本功能,例如编译、运行等,是其它开发工具的基础。Java语言的基本开发工具是SUN公司免费提供的JDK。实际开发中,为了方便和程序开发的效率,一般不直接使用基础开发工具,所以对于很多基础开发工具,只需要掌握其基本的使用即可。集成开发环境(IDE)集成开发环境是指将程序设计需要的很多功能,例如代码编辑、代码调试、程序部署等等一系列功能都整合到一个程序内部,方便程序开发,并提高实际的开发效率,简化了程序设计中的很多操作。Java语言的集成开发环境很多,常见的有Eclipse、JBuilder、NetBeans等等。由于实际开发中,基本都是使用集成开发环境进行开发,所以在学习中必须熟练掌握该类工具的使用。一般集成开发环境的使用都很类似,在学习时只要熟练掌握了其中一个的使用,其它的工具学习起来也很简单。本文以Eclipse为例来介绍集成开发环境的基本使用。JDK开发环境JDK(Java Developers Kit),Java开发者工具包,也称J2SDK(Java 2 Software Development Kit),是SUN公司提供的基础Java语言开发工具,该工具软件包含Java语言的编译工具、运行工具以及执行程序的环境(即JRE)。JDK现在是一个开源、免费的工具。JDK是其它Java开发工具的基础,也就是说,在安装其它开发工具以前,必须首先安装JDK。对于初学者来说,使用该开发工具进行学习,可以在学习的初期把精力放在Java语言语法的学习上,体会更多底层的知识,对于以后的程序开发很有帮助。但是JDK未提供Java源代码的编写环境,这个是SUN提供的很多基础开发工具的通病,所以实际的代码编写还需要在其它的文本编辑器中进行。其实大部分程序设计语言的源代码都是一个文本文件,只是存储成了不同的后缀名罢了。常见的适合Java的文本编辑器有很多,例如JCreator、Editplus、UltraEdit等。下面依次来介绍JDK的下载、安装、配置和使用。1 JDK的下载如果需要获得JDK最新版本,可以到SUN公司的官方网站上进行下载,下载地址为:/javase/downloads/index.jsp下载最新版本的“JDK 6 Update 6”,选择对应的操作系统,以及使用的语言即可。在下载Windows版本时,有两个版本可供下载,,分别是:Windows Online Installation:在线安装版本,每次安装时都从网络上下载安装程序,在下载完成以后,进行实际的安装。Windows Offline Installation:离线安装版本,每次安装时直接进行本地安装。通常情况下,一般下载离线安装版本。其实如果不需要安装JDK最新版本的话,也可以在国内主流的下载站点下载JDK的安装程序,只是这些程序的版本可能稍微老一些,这些对于初学者来说其实问题不大。2 JDK的安装Windows操作系统上的JDK安装程序是一个exe可执行程序,直接安装即可,在安装过程中可以选择安装路径以及安装的组件等,如果没有特殊要求,选择默认设置即可。程序默认的安装路径在C:Program FilesJava目录下。3 JDK的配置JDK安装完成以后,可以不用设置就进行使用,但是为了使用方便,一般需要进行简单的配置。由于JDK提供的编译和运行工具都是基于命令行的,所以需要进行一下DOS下面的一个设定,把JDK安装目录下bin目录中的可执行文件都添加到DOS的外部命令中,这样就可以在任意路径下直接使用bin目录下的exe程序了。配置的参数为操作系统中的path环境变量,该变量的用途是系统查找可执行程序所在的路径。配置步骤为:1、“开始”“设置”“控制面板”“系统”如果控制面板的设置不是经典方式,那么可以在控制面板的“性能和维护”中找到“系统”。当然,也可以选择桌面上的“我的电脑”,点击鼠标右键,选择“属性”打开。2、在“系统属性”窗口中,选择“高级”属性页中的“环境变量”按钮。3、在“环境变量”窗口中,选择“系统变量”中变量名为“Path”的环境变量,双击该变量。4、把JDK安装路径中bin目录的绝对路径,添加到Path变量的值中,并使用半角的分号和已有的路径进行分隔。例如JDK的安装路径下的bin路径是C:Program FilesJavajdk1.6.0_04bin,则把该路径添加到Path值的起始位置,则值为:C:Program FilesJavajdk1.6.0_04bin;C:Program FilesPC Connectivity Solution;C:Program FilesJavajdk1.6.0_04bin;C:j2sdk1.4.2_11bin;%SystemRoot%system32;%SystemRoot%;%SystemRoot%System32Wbem以上路径在不同的计算机中可能不同。配置完成以后,可以使用如下格式来测试配置是否成功:1、 打开“开始”“程序”“附件”“命令提示符”2、 在“命令提示符”窗口中,输入javac,按回车执行如果输出的内容是使用说明,则说明配置成功。如果输出的内容是“javac不是内部或外部命令,也不是可执行的程序或批处理文件。”,则说明配置错误,需要重新进行配置。常见的配置错误为:1)JDK的安装和配置路径错误,路径应该类似C:Program FilesJavajdk1.6.0_04bin。2)分隔的分号错误,例如错误的打成冒号或使用全角的分号以jdk1.4.2_09为例,你可以根据你的jdk版本号及安装路径进行相应的修改在这里我将jdk1.4.2_09直接安装在C盘下,即C:j2sdk1.4.2_09下面为详细配置:1.JAVA_HOMEJAVA_HOME指向的是JDK的安装路径在该路径下你应该能够找到bin、lib等目录如我的设置就应该为JAVA_HOME=C:j2sdk1.4.2_09;2.PATH设置PATH的目的是为了指向JDK的bin目录在bin目录下放的是各种编译执行命令如我的设置就应该为PATH=C:j2sdk1.4.2_09bin;C:j2sdk1.4.2_09jrebin;需要说明,系统本身就有PATH环境变量,只要把C:j2sdk1.4.2_09bin;C:j2sdk1.4.2_09jrebin;直接放到后面即可,中间使用;隔开3.CLASSPATHCLASSPATH设置类的路径,也最为重要如我的设置就应该为CLASSPATH=.;C:j2sdk1.4.2_09lib;C:j2sdk1.4.2_09libtools.jar;最前面加上.和;,意为首先在当前目录中查找以上配置均是在我的JDK安装目录为C:j2sdk1.4.2_09前提下进行的你可以根据实际的安装目录进行相应的修改配置方法:右击我的电脑属性,在弹出的系统属性选项面板中选择高级选项卡,点击环境变量按钮,弹出环境变量面板,在用户变量或者系统变量中进行相应的配置即可注意:用户变量只对当前登录本机的用户有效,而系统变量对所有登录本机的用户均有效,你可以根据自己的喜好在相应的变量环境中进行配置所有环境变量配置好后,在命令窗口中直接执行java或者javac命令,出现了相应的信息,说明配置成功volatile, 用更低的代价替代同步为什么 使用volatile比同步代价更低?同步的代价, 主要由其覆盖范围决定, 如果可以降低同步的覆盖范围, 则可以大幅提升程序性能.而volatile的覆盖范围仅仅变量级别的. 因此它的同步代价很低.volatile原理是什么?volatile的语义, 其实是告诉处理器, 不要将我放入工作内存, 请直接在主存操作我.(工作内存详见java内存模型)因此, 当多核或多线程在访问该变量时, 都将直接 操作 主存, 这从本质上, 做到了变量共享.volatile的有什么优势?1, 更大的程序吞吐量2, 更少的代码实现多线程3, 程序的伸缩性较好4, 比较好理解, 无需太高的学习成本volatile有什么劣势?1, 容易出问题2, 比较难设计volatile运算存在脏数据问题volatile仅仅能保证变量可见性, 无法保证原子性.volatile的race condition示例:Java代码 1. publicclassTestRaceCondition 2. privatevolatileinti=0; 3. 4. publicvoidincrease() 5. i+; 6. 7. 8. publicintgetValue() 9. returni; 10. 11. public class TestRaceCondition private volatile int i = 0; public void increase() i+; public int getValue() return i; 当多线程执行increase方法时, 是否能保证它的值会是线性递增的呢?答案是否定的.原因:这里的increase方法, 执行的操作是i+, 即 i = i + 1;针对i = i + 1, 在多线程中的运算, 本身需要改变i的值.如果, 在i已从内存中取到最新值, 但未与1进行运算, 此时其他线程已数次将运算结果赋值给i.则当前线程结束时, 之前的数次运算结果都将被覆盖.即, 执行100次increase, 可能结果是 100.一般来说, 这种情况需要较高的压力与并发情况下, 才会出现.如何避免这种情况?解决以上问题的方法:一种是 操作时, 加上同步.这种方法, 无疑将大大降低程序性能, 且违背了volatile的初衷.第二种方式是, 使用硬件原语(CAS), 实现非阻塞算法从CPU原语上, 支持变量级别的低开销同步.Volatile修饰的成员变量在每次被线程访问时,都强迫从主内存中重读该成员变量的值。而且,当成员变量发生变化时,强迫线程将变化值回写到主内存。这样在任何时刻,两个不同的线程总是看到某个成员变量的同一个值。Java语言规范中指出:为了获得最佳速度,允许线程保存共享成员变量的私有拷贝,而且只当线程进入或者离开同步代码块时才与共享成员变量的原始值对比。这样当多个线程同时与某个对象交互时,就必须要注意到要让线程及时的得到共享成员变量的变化。而volatile关键字就是提示VM:对于这个成员变量不能保存它的私有拷贝,而应直接与共享成员变量交互。使用建议:在两个或者更多的线程访问的成员变量上使用volatile。当要访问的变量已在synchronized代码块中,或者为常量时,不必使用。由于使用volatile屏蔽掉了VM中必要的代码优化,所以在效率上比较低,因此一定在必要时才使用此关键字。java关键字Transient转自/blog/static/348849612007614494492/翻译自/tips/Tip/13726。Java的serialization提供了一种持久化对象实例的机制。当持久化对象时,可能有一个特殊的对象数据成员,我们不想用serialization机制来保存它。为了在一个特定对象的一个域上关闭serialization,可以在这个域前加上关键字transient。transient是Java语言的关键字,用来表示一个域不是该对象串行化的一部分。当一个对象被串行化的时候,transient型变量的值不包括在串行化的表示中,然而非transient型的变量是被包括进去的。注意static变量也是可以串行化的首先,让我们看一些Javaserialization的代码:publicclassLoggingInfoimplementsjava.io.SerializableprivateDateloggingDate=newDate();privateStringuid;privatetransientStringpwd;LoggingInfo(Stringuser,Stringpassword)uid=user;pwd=password;publicStringtoString()Stringpassword=null;if(pwd=null)password=NOTSET;elsepassword=pwd;returnlogoninfo:n+user:+uid+nloggingdate:+loggingDate.toString()+npassword:+password;现在我们创建一个这个类的实例,并且串行化(serialize)它,然后将这个串行化对象写如磁盘。LoggingInfologInfo=newLoggingInfo(MIKE,MECHANICS);System.out.println(logInfo.toString();tryObjectOutputStreamo=newObjectOutputStream(newFileOutputStream(logInfo.out);o.writeObject(logInfo);o.close();catch(Exceptione)/dealwithexceptionToreadtheobjectback,wecanwritetryObjectInputStreamin=newObjectInputStream(newFileInputStream(logInfo.out);LoggingInfologInfo=(LoggingInfo)in.readObject();System.out.println(logInfo.toString();catch(Exceptione)/dealwithexception如果我们运行这段代码,我们会注意到从磁盘中读回(readback(de-serializing)的对象打印password为NOTSET。这是当我们定义pwd域为transient时,所期望的正确结果。现在,让我们来看一下粗心对待transient域可能引起的潜在问题。假设我们修改了类定义,提供给transient域一个默认值,代码如下:publicclassGuestLoggingInfoimplementsjava.io.SerializableprivateDateloggingDate=newDate();privateStringuid;privatetransientStringpwd;GuestLoggingInfo()uid=guest;pwd=guest;publicStringtoString()/sameasabove现在,如果我们穿行化GuestLoggingInfo的一个实例,将它写入磁盘,并且再将它从磁盘中读出,我们仍然看到读回的对象打印password为NOTSET。当从磁盘中读出某个类的实例时,实际上并不会执行这个类的构造函数,而是载入了一个该类对象的持久化状态,并将这个状态赋值给该类的另一个对象。java类继承总结一 父类类型与子类类型之间的转化问题 默认分类 2008-05-27 19:46:16 阅读18 评论0 字号:大中小 本文将通过一个实例描述父类类型与子类类型之间的转化问题,这个很特殊的问题常常会导致一些潜在的危险,让你整整一个晚上都在调试程序以解决一个让人抓狂的java.lang.ArrayStoreException异常。1. 子类数组的引用可以装换为超类数组的引用2. 子类的引用child可以转换为父类的引用parent(这里假设parent是父类对象,child是子类对象),但却不可以通过 parent调用child的特有方法 classEtectedStringname;protectedlongsalary;publicEmployee(StringaName).=aName;publicvoidsetSalary(longaSalary).this.salary=aSalary;publiclonggetSalary().returnthis.salary;classManagerextendsEtectedlongbonus;publicManager(StringaName).super(aName);publicvoidsetBonus(longaBonus).this.bonus=aBonus;publiclonggetSalary().returnsuper.getSalary()+this.bonus;publicstaticvoidmain(Stringargs)./注意,这时managers和employees引用的是同一个数组Managermanagers=newManager10;Employeeemployees=managers;/(a)注意,下面三条语句是可以通过的,但运行时会抛出异常employees0=newEmployee(Abel);/运行时此处抛出java.lang.ArrayStoreException异常managers0.setSalary(1000);managers0.setBonus(500);/(b)这样的语句编译和运行都没有问题employees0=newManager(Abel);employees0.setSalary(1000);managers0.setSalary(1000);managers0.setBonus(500); 总结:1. 在java中,对象变量是多态的,一个employee既可以引用Employee类型的实例,也可以引用子类Manager类型的实例,但一个manager不能引用一个Employee类型的实例,例如: (1) Employee e = new Manager(Abel) 是合法的 (2)Manager m = new Employee(Abel) 是不合法的 原因很容易理解,manager与employee是is-a的关系,任何一个manager都是一个emplpyee,如(1)所示,一个Employee类型的引用e可以引用Manager类型的实例,这意味着可以通过e使用Manager中任何继承自Employee的方法(注意,e不能使用Manager的特有方法,如e.setBonus(1000)是不合法的),Employee e = new Manager(Abel)的潜台词就是说,e从Employee的角度描述Manager,e就是一个Employee,不管e引用的是什么,编译器就把它当一个Employee来看。2. 对于上面(a)的代码,不能运行是可以理解的, employees0虽然在声明时是Employee类型,但Employee employees = managers;规定了employeesi指向的必须是Manager类型的实例,因此employees0 = new Employee(Abel); 这条语句必然会引发异常。 (a)处的代码employees0 = new Employee(Abel);可以通过编译似乎也情有可原,因为employees声明的类型是Employee, 那么employees0自然可以接受一个Employee类型的引用,但实际上 Employee employees = managers;赋值的过程中又规定了employees接受的必须是Manager类型,从上面的例子可以看出,运行的时候会做这样的检查,但编译的时候不会检查的这么深入,只会检查变量的声明类型,看来java编译器还不够智能啊 :)3. 在实际编程的过程中,使用对象变量的多态性时一定要注意(尤其是使用数组的时候),否则编译通过,但运行报错,这个错误很可能让你调试一个晚上才能找出问题所在!Java方法继承、方法重载、方法覆盖小总结1、方法继承:利用extends关键字一个方法继承另一个方法,而且只能直接继承一个类。 * 当Sub类和Base类在同一个包时Sub类继承Base类中的public/protected/默认级别的变量个方法 * 在不同包时继承public/protected级别的变量和方法。2、方法重载:如果有两个方法的方法名相同,但参数不一致,哪么可以说一个方法是另一个方法的重载。 * 方法名相同 * 方法的参数类型,个数顺序至少有一项不同 * 方法的返回类型可以不相同 * 方法的修饰符可以不相同 * main方法也可以被重载3、方法覆盖:如果在子类中定义一个方法,其名称、返回类型及参数签名正好与父类中某个方法的名称、返回类型及参数签名相匹配,那么可以说,子类的方法覆盖了父类的方法。 * 子类的方法名称返回类型及参数签名 必须与父类的一致 * 子类方法不能缩小父类方法的访问权限 * 子类方法不能抛出比父类方法更多的异常 * 方法覆盖只存在于子类和父类之间,同一个类中只能重载 * 父类的静态方法不能被子类覆盖为非静态方法 * 子类可以定义于父类的静态方法同名的静态方法,以便在子类中隐藏父类的静态方法(满足覆盖约束), * 而且Java虚拟机把静态方法和所属的类绑定,而把实例方法和所属的实例绑定。 * 父类的非静态方法不能被子类覆盖为静态方法 * 父类的私有方法不能被子类覆盖 * 父类的抽象方法可以被子类通过两种途径覆盖(即实现和覆盖)(P169) * 父类的非抽象方法可以被覆盖为抽象方法4、Super关键字:super和this关键字都可以用来覆盖Java语言的默认作用域,使被屏蔽的方法或变量变为可见(三种情况下的不可见P171)。 * 父类的成员变量和方法为private使用super访问编译出错 * 在类的构造方法种,通过super语句调用这个类的父类的构造方法 * 在子类种访问父类的被屏蔽的方法和属性 * 只能在构造方法或实例方法内使用super关键字,而在静态方法和静态代码块内不能使用super5、多态: * 对于一个引用类型的变量,Java编译器按照它的声明的类型来处理 * 对于一个引用类型的变量,运行时Java虚拟机按照它的实际引用的对象来处理 * 运行时环境中,通过引用类型变量来访问所引用对象的方法和属性时,Java虚拟机采用以下绑定规则 1)实例方法与引用变量实际引用的对象的方法绑定,属于动态绑定 2)静态方法与引用变量所声明的类型的方法绑定,属于静态绑定 3)成员变量(包括静态和实例变量)与引用变量所声明的类型的成员变量绑定,属于静态绑定Java代码 1. classSuper 2. staticintstat=1; 3. intnonStat=2; 4. 5. staticintstatMethod() 6. return3; 7. 8. 9. intnonStatMethod() 10. return4; 11. 12. 13. 14. publicclassSubextendsSuper 15. staticintstat=10; 16. intnonStat=20; 17. 18. staticintstatMethod() 19. return30; 20. 21. 22. intnonStatMethod() 23. return40; 24. 25. 26. publicstaticvoidmain(Stringargs) 27. Supers=newSub(); 28. System.out.println(Staticis+s.stat); 29. System.out.println(Non-Staticis+s.nonStat); 30. System.out.println(Staticmethodis+s.statMethod(); 31. System.out.println(Non-Staticmethodis+s.nonStatMethod(); 32. 33. Subsub=(Sub)s; 34. System.out.println(Staticis+sub.stat); 35. System.out.println(Non-Staticis+sub.nonStat); 36. System.out.println(Staticmethodis+sub.statMethod(); 37. System.out.println(Non-Staticmethodis+sub.nonStatMethod(); 38. 39. 40. 41. 输出结果是: 42. 43. Staticis1 44. Non-Staticis2 45. Staticmethodis3 46. Non-Staticmethodis40 47. Staticis10 48. Non-Staticis20 49. Staticmethodis30 50. Non-Staticmethodis40 一 泛型简介什么是泛型?泛型(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 值。这可以让您消除代码中的强制类型转换,同时获得一个附加的类型检查层,该检查层可以防止有人将错误类型的键或值保存在集合中。这就是泛型所做的工作。泛型的好处Java 语言中引入泛型是一个较大的功能增强。不仅语言、类型系统和编译器有了较大的变化,以支持泛型,而且类库也进行了大翻修,所以许多重要的类,比如集合框架,都已经成为泛型化的了。这带来了很多好处:类型安全。 泛型的主要目标是提高 Java 程序的类型安全。通过知道使用泛型定义的变量的类型限制,编译器可以在一个高得多的程度上验证类型假设。没有泛型,这些假设就只存在于程序员的头脑中(或者如果幸运的话,还存在于代码注释中)。Java 程序中的一种流行技术是定义这样的集合,即它的元素或键是公共类型的,比如“String 列表”或者“String 到 String 的映射”。通过在变量声明中捕获这一附加的类型信息,泛型允许编译器实施这些附加的类型约束。类型错误现在就可以在编译时被捕获了,而不是在运行时当作 ClassCastException 展示出来。将类型检查从运行时挪到编译时有助于您更容易找到错误,并可提高程序的可靠性。消除强制类型转换。 泛型的一个附带好处是,消除源代码中的许多强制类型转换。这使得代码更加可读,并且减少了出错机会。尽管减少强制类型转换可以降低使用泛型类的代码的罗嗦程度,但是声明泛型变量会带来相应的罗嗦。比较下面两个代码例子。该代码不使用泛型:List li = new ArrayList();li.put(new Integer(3);Integer i = (Integer) li.get(0);该代码使用泛型:List li = new ArrayList();li.put(new Integer(3);Integer i = li.get(0);在简单的程序中使用一次泛型变量不会降低罗嗦程度。但是对于多次使用泛型变量的大型程序来说,则可以累积起来降低罗嗦程度。潜在的性能收益。 泛型为较大的优化带来可能。在泛型的初始实现中,编译器将强制类型转换(没有泛型的话,程序员会指定这些强制类型转换)插入生成的字节码中。但是更多类型信息可用于编译器这一事实,为未来版本的 JVM 的优化带来可能。由于泛型的实现方式,支持泛型(几乎)不需要 JVM 或类文件更改。所有工作都在编译器中完成,编译器生成类似于没有泛型(和强制类型转换)时所写的代码,只是更能确保类型安全而已。泛型用法的例子泛型的许多最佳例子都来自集合框架,因为泛型让您在保存在集合中的元素上指定类型约束。考虑这个使用 Map 类的例子,其中涉及一定程度的优化,即 Map.get() 返回的结果将确实是一个 String:Map m = new HashMap();m.put(key, blarg);String s = (String) m.get(key);如果有人已经在映射中放置了不是 String 的其他东西,上面的代码将会抛出 ClassCastException。泛型允许您表达这样的类型约束,即 m 是一个将 String 键映射到 String 值的 Map。这可以消除代码中的强制类型转换,同时获得一个附加的类型检查层,这个检查层可以防止有人将错误类型的键或值保存在集合中。下面的代码示例展示了 JDK 5.0 中集合框架中的 Map 接口的定义的一部分:public interface Map public void put(K key, V value);public V get(K key);注意该接口的两个附加物:类型参数 K 和 V 在类级别的规格说明,表示在声明一个 Map 类型的变量时指定的类型的占位符。在 get()、put() 和其他方法的方法签名中使用的 K 和 V。为了赢得使用泛型的好处,必须在定义或实例化 Map 类型的变量时为 K 和 V 提供具体的值。以一种相对直观的方式做这件事:Map m = new HashMap();m.put(key, blarg);String s = m.get(key);当使用 Map 的泛型化版本时,您不再需要将 Map.get() 的结果强制类型转换为 String,因为编译器知道 get() 将返回一个 String。在使用泛型的版本中并没有减少键盘录入;实际上,比使用强制类型转换的版本需要做更多键入。使用泛型只是带来了附加的类型安全。因为编译器知道关于您将放进 Map 中的键和值的类型的更多信息,所以类型检查从执行时挪到了编译时,这会提高可靠性并加快开发速度。向后兼容在 Java 语言中引入泛型的一个重要目标就是维护向后兼容。尽管 JDK 5.0 的标准类库中的许多类,比如集合框架,都已经泛型化了,但是使用集合类(比如 HashMap 和 ArrayList)的现有代码将继续不加修改地在 JDK 5.0 中工作。当然,没有利用泛型的现有代码将不会赢得泛型的类型安全好处。二 泛型基础类型参数在定义泛型类或声明泛型类的变量时,使用尖括号来指定形式类型参数。形式类型参数与实际类型参数之间的关系类似于形式方法参数与实际方法参数之间的关系,只是类型参数表示类型,而不是表示值。泛型类中的类型参数几乎可以用于任何可以使用类名的地方。例如,下面是 java.util.Map 接口的定义的摘录:public interface Map public void put(K key, V value);public V get(K key);Map 接口是由两个类型参数化的,这两个类型是键类型 K 和值类型 V。(不使用泛型)将会接受或返回 Object 的方法现在在它们的方法签名中使用 K 或 V,指示附加的类型约束位于 Map 的规格说明之下。当声明或者实例化一个泛型的对象时,必须指定类型参数的值:Map map = new HashMap();注意,在本例中,必须指定两次类型参数。一次是在声明变量 map 的类型时,另一次是在选择 HashMap 类的参数化以便可以实例化正确类型的一个实例时。编译器在遇到一个 Map 类型的变量时,知道 K 和 V 现在被绑定为 String,因此它知道在这样的变量上调用 Map.get() 将会得到 String 类型。除了异常类型、枚举或匿名内部类以外,任何类都可以具有类型参数。命名类型参数推荐的命名约定是使用大写的单个字母名称作为类型参数。这与 C+ 约定有所不同(参阅 附录 A:与 C+ 模板的比较),并反映了大多数泛型类将具有少量类型参数的假定。对于常见的泛型模式,推荐的名称是:K 键,比如映射的键。 V 值,比如 List 和 Set 的内容,或者 Map 中的值。 E 异常类。 T 泛型。泛型不是协变的关于泛型的混淆,一个常见的来源就是假设它们像数组一样是协变的。其实它们不是协变的。List 不是 List 的父类型。如果 A 扩展 B,那么 A 的数组也是 B 的数组,并且完全可以在需要 B 的地方使用 A:Integer intArray = new Integer10; Number numberArray = intArray;上面的代码是有效的,因为一个 Integer 是 一个 Number,因而一个 Integer 数组是 一个 Number 数组。但是对于泛型来说则不然。下面的代码是无效的:List intList = new ArrayList();List numberList = intList; / invalid最初,大多数 Java 程序员觉得这缺少协变很烦人,或者甚至是“坏的(broken)”,但是之所以这样有一个很好的原因。如果可以将 List 赋给 List,下面的代码就会违背泛型应该提供的类型安全:List intList = new ArrayList();List numberList = intList; / invalidnumberList.add(new Float(3.1415);因为 intList 和 numberList 都是有别名的,如果允许的话,上面的代码就会让您将不是 Integers 的东西放进 intList 中。但是,正如下一屏将会看到的,您有一个更加灵活的方式来定义泛型。类型通配符假设您具有该方法:void printList(List l) for (Object o : l) System.out.println(o); 上面的代码在 JDK 5.0 上编译通过,但是如果试图用 List 调用它,则会得到警告。出现警告是因为,您将泛型(List)传递给一个只承诺将它当作 List(所谓的原始类型)的方法,这将破坏使用泛型的类型安全。如果试图编写像下面这样的方法,那么将会怎么样?void printList(List l) for (Object o : l) System.out.println(o); 它仍然不会通过编译,因为一个 List 不是 一个 List(
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 乐理考试题听力及答案
- 2025年中国沙发绳数据监测研究报告
- 口腔影像考试题及答案
- 课件时间进度
- 开平话考试题及答案
- 2025年教师招聘之《小学教师招聘》通关练习试题及答案详解(名校卷)
- 军事投弹考试题及答案
- 菊花台考试题及答案
- 静脉知识考试题及答案
- 汽车冲压生产线操作工理念考核试卷及答案
- 装饰工程保修单
- IInterlib区域图书馆集群管理系统-用户手册
- EnglishDrama英语戏剧写作及表演技巧课件
- DB11T 827-2019 废旧爆炸物品销毁处置安全管理规程
- 社会组织管理概论全套ppt课件(完整版)
- 轧机设备安装施工方案
- DB31∕T 926-2015 城镇供水管道水力冲洗技术规范
- (完整版)IATF16949新版过程乌龟图的编制与详解课件
- 制药企业仓库温湿度分布的验证
- 满堂脚手架工程施工方案
- LY∕T 2705-2016 樟脑磺酸
评论
0/150
提交评论