Java常见错误解决

合集下载

java三种异常处理方法

java三种异常处理方法

java三种异常处理方法Java是一种流行的编程语言,但是在编写程序时常常会遇到各种异常。

为了使程序更加健壮和稳定,我们需要使用异常处理机制。

Java中有三种异常处理方法:1. try-catch语句try-catch语句是最常用的异常处理方法。

它的基本语法如下: ```try {// 可能会抛出异常的代码} catch (Exception e) {// 异常处理代码}```在try块中,我们编写可能会抛出异常的代码。

如果这些代码抛出了异常,那么程序就会跳转到catch块中。

catch块中的代码会处理异常,可以输出异常信息,也可以进行其他操作。

2. throws关键字throws关键字可以将异常抛给调用该方法的上一级方法处理。

它的语法如下:```public void method() throws Exception {// 可能会抛出异常的代码}```在方法声明中使用throws关键字,表明该方法可能会抛出某种异常。

如果抛出了异常,异常将会被抛给该方法的调用者处理。

3. finally关键字finally关键字用于编写一段无论是否发生异常都会被执行的代码块。

它的语法如下:```try {// 可能会抛出异常的代码} catch (Exception e) {// 异常处理代码} finally {// 无论是否发生异常都会执行的代码}```在try-catch语句中使用finally块,可以确保无论是否发生异常,finally块中的代码都会被执行。

通常,finally块中会释放资源或者进行一些清理操作。

以上是Java中三种常见的异常处理方法。

在编写程序时,我们应该根据具体情况选择合适的方法处理异常,以保证程序的健壮性和稳定性。

java实验报告上机过程遇到的问题及解决方法

java实验报告上机过程遇到的问题及解决方法

java实验报告上机过程遇到的问题及解决方法Java实验报告上机过程遇到的问题及解决方法在进行Java实验时,往往会遇到各种问题,这些问题可能与代码编写、调试、环境配置等方面有关。

在本文中,我将分享一些我在实验过程中遇到的常见问题以及相应的解决方法,希望能够帮助读者更好地进行Java实验。

1. 编译错误在编写Java代码时,经常会碰到编译错误。

编译错误可能是由于语法错误、缺少库文件、命名冲突等问题导致的。

解决这类问题的方法有:- 仔细检查代码,确保语法正确且符合Java语法规范。

常见的错误包括缺少分号、拼写错误等。

- 确保所使用的库文件已正确导入,并在代码中进行正确的引用。

- 对于命名冲突问题,可以尝试修改变量名或使用全限定名来解决。

2. 运行时错误在代码编译通过后,运行程序时可能会出现各种错误。

空指针异常、数组越界等。

解决这类问题的方法有:- 对于空指针异常,可以通过添加空指针判断来避免。

使用if语句判断对象是否为null再进行操作。

- 对于数组越界错误,需要确保访问数组元素时的索引值在合法范围内。

可以使用条件语句或循环来进行检查。

3. 调试问题在调试Java程序时,可能遇到程序无法正常运行或结果不符合预期的情况。

以下是一些解决方法:- 使用调试工具,如Eclipse、IntelliJ IDEA等,设置断点进行代码逐行调试。

通过观察变量的值和程序执行流程,可以找到问题所在。

- 添加日志输出语句,可以帮助我们查看程序在执行过程中的状态,从而找到错误原因。

- 使用try-catch块捕获异常,并在异常处理代码中添加适当的逻辑,以保证程序的正常运行。

4. 环境配置问题在进行Java实验时,可能需要进行一些环境配置,如设置类路径、引入第三方库等。

解决环境配置问题的方法有:- 确认所使用的开发工具是否已正确配置,并且已安装Java JDK和相应版本的JRE。

- 检查类路径是否正确设置,确保能够正确引用所需的库文件。

java的oom解决方法

java的oom解决方法

java的oom解决方法Java的OOM(Out of Memory)错误是指在程序运行过程中,JVM(Java Virtual Machine)的堆内存不足以分配对象所需的内存空间,导致程序无法继续执行的错误。

在Java开发中,OOM错误是一个常见的问题,尤其是在处理大数据量、复杂算法或者并发请求等场景下。

为了解决OOM 错误,我们可以采取一系列的措施来优化代码,增加内存的使用效率。

本文将分步介绍如何解决Java的OOM问题。

第一步:找出内存泄漏的原因内存泄漏是造成OOM错误的主要原因之一,因此首先需要找出内存泄漏的具体原因。

我们可以通过一些工具来帮助我们分析程序的内存使用情况,比如使用Java自带的jmap、jstat、jvisualvm等工具,或者使用一些第三方的内存分析工具,比如Eclipse Memory Analyzer等。

这些工具可以帮助我们检测出程序中存在的内存泄漏,并给出相应的提示和建议。

第二步:调整堆内存大小一旦确定了程序存在内存泄漏的问题,我们可以尝试调整JVM的堆内存大小来缓解OOM错误。

默认情况下,JVM的堆内存大小是有限制的,可以通过-Xms和-Xmx参数来指定。

其中,-Xms参数用于指定JVM的初始堆内存大小,-Xmx参数用于指定JVM的最大堆内存大小。

我们可以根据程序对内存的需求,适当调整这些参数的值。

通常情况下,增大堆内存大小能够缓解OOM错误,但也需要注意不要设置得过大,避免浪费资源。

第三步:优化代码逻辑除了调整堆内存大小,我们还可以通过优化代码逻辑来减少内存的占用。

在编写代码的过程中,我们应该尽量避免创建过多的对象,尤其是一些大对象。

例如,在循环中创建对象的操作应该尽量避免,可以考虑将对象的创建操作移到循环外部,或者重用已经创建好的对象。

另外,对于一些大容量的数据结构,如集合类,可以根据实际需求选择合适的集合类型,避免不必要的内存占用。

第四步:优化垃圾回收垃圾回收是JVM中重要的一环,对内存占用的优化有着关键的作用。

java中遇到的问题和解决方案

java中遇到的问题和解决方案

java中遇到的问题和解决方案
目录
1. Java中遇到的问题
1.1 内存溢出问题
1.2 死锁问题
2. 解决方案
2.1 内存溢出问题的解决方案
2.2 死锁问题的解决方案
Java中遇到的问题
在Java编程过程中,经常会遇到各种各样的问题,其中两个比较常见的问题是内存溢出和死锁问题。

内存溢出问题是指程序在运行过程中申请的内存超过了系统能够分配给它的内存大小,导致程序崩溃。

这种问题通常发生在程序中频繁创建大量对象或者持续运行时间过长的情况下。

死锁问题则是指多个线程互相持有对方所需要的资源,导致彼此无法继续执行,进而导致程序无法正常运行。

死锁问题通常发生在多线程编程中,处理不当时很容易出现。

解决方案
针对内存溢出问题,可以通过一些方法来解决,比如增加堆内存大小、优化程序代码以减少内存占用、及时释放不再使用的对象等。

另外,可以使用一些工具来监控程序内存使用情况,及时发现并解决潜在的内存溢出问题。

对于死锁问题,可以通过合理地设计程序逻辑、避免使用过多的同步代码块、避免嵌套锁等方法来预防死锁的发生。

此外,可以使用一些工具来帮助检测程序中潜在的死锁问题,并及时处理。

综上所述,如果在Java编程过程中遇到内存溢出或死锁问题,可以通过上述方法来解决,确保程序的稳定运行。

java的常见问题及解决方法

java的常见问题及解决方法

1."mons.collections.SequencedHashMap"'s signer information does not match signer information of other classes in the same package这是由于struts提供的commons-beanutils.jar和hibernate提供的commons-collections.jar冲突成的,可以从spring提供的lib中找到这个两个jarng.IllegalStateException: No data type for node:org.hibernate.hql.ast.tree.IdentNode用hql 时,忘了给表名加别名,如select p from Position,应该是select p from Position p3.The Server didn 't send back a proper XML response用FCKEditor时原因:解析不了xml文件解决方法:情况一:web.xml的配置是否正确,具体查看《FCKEditor使用指南.pdf》,还有fckeditor自带的几个jar 包情况二:加入serializer.jar,xalan.jar情况三:把项目下的fckeditor包删了,重新加入一遍.eclipse.swt.SWTError: No more handles [Unknown Mozilla path (MOZILLA_FIVE_HOME not set)]SWTError:没有更多的处理[未知Mozilla的路径(MOZILLA_FIVE_HOME未设置)]环境:linux下运行swt程序(我出现此问题是,在linux下嵌套浏览器)原因:firefox版本不一致解决:重装一个firefox,并设置相关变量5.Exception in thread "main" org.eclipse.swt.SWTError: No more handles [Could not detect registered XULRunner to use]环境:用XULRunner 在java application中嵌套浏览器原因:没有注册XULRunner解决:window下环境中,在程序中加入,如(第二个参数是下载解压后的存放路径):static{System.setProperty("org.eclipse.swt.browser.XULRunnerPath", "C:\\xulrunner");}6.Exception in thread "main" ng.UnsatisfiedLinkError: noswt-win32-3536 or swt-win32 in swt.library.path, java.library.path or the jar file环境:用DJ Natvie Swing时,在java application中嵌套浏览器,且在windows环境下运行正常,但在linux下却包此异常原因:windows下与linux下使用的swt jar包不一样解决:在windows下用swt-3.5M6-win32-win32-x86.jar,在linux下用swt-3.5.1-gtk-linux-x86.jar7.Exception in thread "main" .ProtocolException:cannot write to a URLConnection if doOutput=false - call setDoOutput(true)环境:用URLConnection送某url发送数据时原因:doOutput=false时,不能发送数据解决:如urlConnection.setDoOutput(true).SocketException: Connection resetat .SocketInputStream.read(SocketInputStream.java:168)at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:264)at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:306)at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:158)at java.io.InputStreamReader.read(InputStreamReader.java:167)at java.io.BufferedReader.fill(BufferedReader.java:136)at java.io.BufferedReader.readLine(BufferedReader.java:299)at java.io.BufferedReader.readLine(BufferedReader.java:362)at com.eagle.service.AutoUpdate.run(AutoUpdate.java:43)环境:j2se socket编程时,服务器端报错原因1:服务器端用BufferedReader,时,没有读到一行解决:客户端用PrintWriter, pw.println(),不能用pw.print(),因为br.readLine()是读一行环境:j2se socket编程时,服务器端/客户端在br.readLine()时报错原因2:服务器端用BufferedReader,br.readLine()时,客户端/服务器已经退出,但是并未通过服务器/客户端,即服务器端/客户端的socket还没有关闭,当用br.readLine()时就会出现这种情况解决:在关闭客户端时要socket.close(),同时还要向服务器发送一条退出的信息,这样让服务器知道某个客户端已经关闭,它就可以终止对此客户端的线程了,反之服务器也是一样.hibernate.PropertyAccessException: Null value was assigned toa property of primitive type setter of er环境:hibernate原因:oolean类型的值为null,boolean类型的值必须是true/false解决:save or update时给boolean类型的值赋true/false10.用占位符查询时出现空指针ng.NullPointerExceptionatorg.hibernate.hql.ast.ParameterTranslationsImpl.getNamedParameterExpectedType(ParameterTranslat ionsImpl.java:63)at org.hibernate.engine.query.HQLQueryPlan.buildParameterMetadata(HQLQueryPlan.java:245)at org.hibernate.engine.query.HQLQueryPlan.<init>(HQLQueryPlan.java:95)at org.hibernate.engine.query.HQLQueryPlan.<init>(HQLQueryPlan.java:54)at org.hibernate.engine.query.QueryPlanCache.getHQLQueryPlan(QueryPlanCache.java:71)at org.hibernate.impl.AbstractSessionImpl.getHQLQueryPlan(AbstractSessionImpl.java:133)at org.hibernate.impl.AbstractSessionImpl.createQuery(AbstractSessionImpl.java:112)at org.hibernate.impl.SessionImpl.createQuery(SessionImpl.java:1583)at .struts.action.LoginAction.execute(LoginAction.java:72)at org.apache.struts.action.RequestProcessor.processActionPerform(RequestProcessor.java:419)at org.apache.struts.action.RequestProcessor.process(RequestProcessor.java:224)at org.apache.struts.action.ActionServlet.process(ActionServlet.java:1194)at org.apache.struts.action.ActionServlet.doPost(ActionServlet.java:432)at javax.servlet.http.HttpServlet.service(HttpServlet.java:709)at javax.servlet.http.HttpServlet.service(HttpServlet.java:802)at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:252)at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:173)at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:213)at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:178)at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:126)at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:105)at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:107)at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:148)at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:869)atorg.apache.coyote.http11.Http11BaseProtocol$Http11ConnectionHandler.processConnection(Http11Ba seProtocol.java:664)at .PoolTcpEndpoint.processSocket(PoolTcpEndpoint.java:527)at .LeaderFollowerWorkerThread.runIt(LeaderFollowerWorkerThread.java:80) at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:684)at ng.Thread.run(Thread.java:595)环境:hibernate原因:HQL 不能解析解决:错误写法:String hql = "select m from com.eagle.oa.model.Message m where m.ids like: id";正确写法:String hql = "select m from com.eagle.oa.model.Message m where m.ids like:id";ng.IndexOutOfBoundsException: Remember that ordinal parameters are 1-based!原因:在使用hibernate的session.createQuery(.....)时设置参数的下标应该从0开始解决:如:return session.createQuery("from User u where erName = ? and password = ?").setParameter(0, name).setParameter(1, password).uniqueResult();.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: com.wxj.entities.Group环境:hibernate原因:某个实例的属性一个对象,这个对象没有保存,还是暂态的对象解决:先保存这个对象,或是在另一端加inverse = true13.ORA-01461: can bind a LONG value only for insert into a LONG column环境:oracle原因:jar冲突解决:换成classes12.jar包即可14.ERROR LazyInitializationException:19 - could not initialize proxy - the owning Session was closed环境:SSH原因:当一个类或属性设置了lazy="true",操作对象时,session已经关闭了解决:使用Spring的过滤器openSessionInView.springframework.dao.InvalidDataAccessApiUsageException: Write operations are not allowed in read-only mode (FlushMode.NEVER/MANUAL): Turn your Session into MIT/AUTO or remove 'readOnly' marker from transaction definition.环境:SSH原因:这个异常产生的主要原因是DAO采用了Spring容器的事务管理策略,如果操作方法的名称和事务策略中指定的被管理的名称不能够匹配上,spring 就会采取默认的事务管理策略(PROPAGATION_REQUIRED,read only).如果是插入和修改操作,就不被允许的,所以包这个异常解决:修改spring配置文件中相关事务管理部分mon.beans.ProbeException: There is no READABLE property named 'eid' in class 'com.wxj.entity.Student'环境:ibatis原因:在给对象做操作,设置参数时,指定的参数不是对象中有的属性,就会抛出此异常解决:核对对象的属性ng.OutOfMemoryError: PermGen space环境:很多,如ssh整合时原因:不断的更新class,造成应用重启,最终造成代码区的内存空间满了解决:方法很多,1重启,2增加代码区的大小,3少更新class,4有时可能是log4j造成的问题,建议使用common-loggin.jar 5,优化代码以下来自CSDN的jinhuiyu:在JVM中如果98%的时间是用于GC且可用的Heap size 不足2%的时候将抛出此异常信息,可以用如下方法解决(根据你的实际情况设置大小),但是这只是临时的解决方法,更重要的是改造你的CODE1.可以在windows 更改系统环境变量加上JAVA_OPTS=-Xms64m -Xmx512m2,如果用的tomcat,在windows下,可以在C:\tomcat5.5.9\bin\catalina.bat 中加上:set JAVA_OPTS=-Xms64m -Xmx256m位置在: rem Guess CATALINA_HOME if not defined 这行的下面加合适.3.如果是linux系统Linux 在{tomcat_home}/bin/catalina.sh的前面,加set JAVA_OPTS='-Xms64 -Xmx512'18.在客户端使用dwr时,即跨域访问时,出现“拒绝访问“及“找不到某个属性”的问题(在服务器端调用时却正常)环境:在客户端使用dwr原因:1。

error invoking main method

error invoking main method

error invoking main method“Error invoking main method”是一个常见的Java错误,它通常表示在尝试运行Java 程序时遇到了问题。

这个错误可能有多种原因,下面是一些可能的原因和解决方案:1. 类路径问题确保你的CLASSPATH环境变量设置正确。

如果你在运行一个jar文件,确保使用正确的命令,例如:java -cp yourfile.jar com.yourpackage.YourClass2. 主类找不到确保你指定的主类存在,并且拼写正确。

确保主类在指定的包中。

3. 方法签名问题主方法(main方法)的签名必须是public static void main(String[] args)。

确保你没有在main方法中抛出任何未检查的异常。

4. 依赖问题如果你的程序依赖于其他库,确保这些库都在类路径中。

如果你使用的是构建工具(如Maven或Gradle),确保所有依赖都已正确解析。

5. 环境问题确保你的Java环境安装正确,并且JAVA_HOME环境变量设置正确。

尝试在不同的环境或计算机上运行你的程序,以确定问题是否与特定环境相关。

6. 代码问题检查你的代码是否有语法错误或其他问题。

使用IDE(如Eclipse或IntelliJ IDEA)可以帮助你更容易地找到和修复代码中的错误。

7. 权限问题确保你有足够的权限来运行Java程序。

如果你在类Unix系统中,确保文件具有可执行权限。

总结解决“Error invoking main method”错误通常需要仔细检查你的代码、环境和命令。

确保所有东西都设置正确,并且遵循Java的标准和最佳实践。

如果你不确定问题的根源在哪里,尝试一步一步地排查,或者寻求社区的帮助。

java常见异常处理方案

java常见异常处理方案

JAVA常见异常1. ng.nullpointerexception这个异常大家肯定都经常遇到,异常的解释是&quot;程序遇上了空指针&quot;,简单地说就是调用了未经初始化的对象或者是不存在的对象,这个错误经常出现在创建图片,调用数组这些操作中,比如图片未经初始化,或者图片创建时的路径错误等等。

对数组操作中出现空指针,很多情况下是一些刚开始学习编程的朋友常犯的错误,即把数组的初始化和数组元素的初始化混淆起来了。

数组的初始化是对数组分配需要的空间,而初始化后的数组,其中的元素并没有实例化,依然是空的,所以还需要对每个元素都进行初始化(如果要调用的话)2. ng.classnotfoundexception这个异常是很多原本在jb等开发环境中开发的程序员,把jb下的程序包放在wtk下编译经常出现的问题,异常的解释是&quot;指定的类不存在&quot;,这里主要考虑一下类的名称和路径是否正确即可,如果是在jb下做的程序包,一般都是默认加上package的,所以转到wtk下后要注意把package的路径加上。

3. ng.arithmeticexception这个异常的解释是&quot;数学运算异常&quot;,比如程序中出现了除以零这样的运算就会出这样的异常,对这种异常,大家就要好好检查一下自己程序中涉及到数学运算的地方,公式是不是有不妥了。

4. ng.arrayindexoutofboundsexception这个异常相信很多朋友也经常遇到过,异常的解释是&quot;数组下标越界&quot;,现在程序中大多都有对数组的操作,因此在调用数组的时候一定要认真检查,看自己调用的下标是不是超出了数组的范围,一般来说,显示(即直接用常数当下标)调用不太容易出这样的错,但隐式(即用变量表示下标)调用就经常出错了,还有一种情况,是程序中定义的数组的长度是通过某些特定方法决定的,不是事先声明的,这个时候,最好先查看一下数组的length,以免出现这个异常。

JAVA异常及解决方法

JAVA异常及解决方法

java异常及解决方法1:.BindException:Address already in use解决方法在网络编程中,特别是在短时间内new的网络连接太多,经常出现.BindException:Address already in use: JVM_Bind的异常,网络有很多介绍此异常的,通常都是在说是要使用的端口被别的程序已经使用,但有时并不是这个原因,通过仔细查找,找到一些很好的资料,在此将其一一记录下来。

短时间内new socket操作过多而socket.close()操作并不能立即释放绑定的端口而是把端口设置为TIME_WAIT状态过段时间(默认240s)才释放(用netstat-na可以看到)最后系统资源耗尽(windows上是耗尽了pool of ephemeral ports这段区间在1024-5000之间)Socket Remember that TCP guarantees all data transmitted will be delivered,if at all possible.When you close a socket,the server goes into aTIME_WAIT state,just to be really really sure that all the data hasgone through.When a socket is closed,both sides agree by sending messages to each other that they will send no more data.This,itseemed to me was good enough,and after the handshaking is done,the socket should be closed.The problem is two-fold.First,there is no2:.BindException:Address already in use:connect的问题大概原因是短时间内new socket操作很多,而socket.close()操作并不能立即释放绑定的端口,而是把端口设置为TIME_WAIT状态,过段时间(默认240s)才释放,(用netstat-na可以看到),最后系统资源耗尽(windows上是耗尽了pool of ephemeral ports,这段区间在1024-5000之间;)避免出现这一问题的方法有两个,一个是调高你的web服务器的最大连接线程数,调到1024,2048都还凑合,以resin 为例,修改resin.conf中的thread-pool.thread_max,如果你采用apache连resin的架构,别忘了再调整apache;另一个是修改运行web服务器的机器的操作系统网络配置,把time wait的时间调低一些,比如30s。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

第1部分 语法 程序员们总是被层出不穷的复杂问题所困扰假如我们最基本的开放工具—— 设计和编写程序的语言本身就是复杂的而非它们的解决方案了并借鉴了Objective C Smalltalkµ±Ê¹ÓÃÆäËûÓïÑԵijÌÐòԱתÓÃJava来编程时因此这些程序员通常会认为这些特性在Java中和在以前所使用的语言中表现一致这些想法在C++程序员中尤其普遍绊倒本部分包括以下10个单元什么时候 方法并非真的被覆盖了Item 2==”本单元解释了这两种方法比较字符串的不同之处第1部分语法Item 3本单元解释了基本类型的转换和提升的规则Item 4本单元给出了一个经典的当我们培训新的Java学员时编译器怎么会没发现它不能访问被覆盖的方法读完以后Item 6Òþ²Ø±äÁ¿³ÉÔ±本单元讨论了这一最常见的陷阱并且和this引用一起讨论提前引用提前引用以及如何去避免它设计可继承的构造函数对于每一个想开发可重用Java类的程序员来说Item 9本单元对从C++转换到Java的程序员特别有价值Item 10¶Ì·本单元解释了Java编程中另一个常见的陷阱单元中也举了一个使用短路运算符的清晰例子被覆盖的我承认虽然它的本意并非欺骗你想必你已经阅读了一两本这样的Java书籍封装理解这3个概念对于领会Java语言来说至关重要覆盖实例方法会在Item 5谈到如果你还不明白两者的区别假如你已经急不可待地喊出那么不过Item 1: 什么时候方法并非真的被覆盖了这个例子摘自Java语言规范8.4.8.5节Goodnight, Dick要是你得出了同样的输出结果如果你的结果和答案不一致我们先分析一下各个类Sub类继承了Super类Test类只有一个main方法第1部分语法在Test类的第5行中在这里虽然变量s的数据类型为Super类如果你对此有些迷惑变量s是一个被强制转换为Super型的Sub类的实例加上一个字符串紧随其后的是()的返回值还是Sub类的方法两个类中的name()方法都不是静态方法因为Sub类继承了Super类所以Sub类中的name()方法覆盖了Super类中的name()方法这样一来Dick至此现在我们需要判断被调用的greeting()方法究竟是Super 类的还是Sub类的两个类中的greeting()方法都是静态方法尽管事实上Sub类的greeting()方法具有相同的返回类型以及相同的方法参数由于变量s被强制转换为Super型因此s.greeting()的返回值为请记住这条规则静态方法被隐藏”²»Äܸ²¸Ç¾²Ì¬·½·¨µÄ¶ÁÕßÖ®Ò»现在你可能会问”È»¶øÊµ¼ÊÉÏÎÒÃǸոÕÔÚÕâ¸öSuper/Sub类的例子中已经解释了两者的不同即使变量s是Sub类的一个实例我们仍旧能够将s强制转换为Super型与被隐藏的方法不同除了覆盖它们的类之外这就是为何变量s调用的是Sub类的本单元简要解释了Java语言中一个不时引起混淆的问题理解隐藏静态方法和覆盖实例方法的区别的最佳方式再重复一次规则被覆盖的方法只有覆盖它们的类才能访问它们现在你终于明白标题里问题的答案了吧答案就是另外请谨记Item 2: String.equals( )方法与运算符的用法比较l试图用子类的静态方法隐藏父类中同样标识的实例方法是不合法的l试图用子类的实例方法覆盖父类中同样标识的静态方法也是不合法的l静态方法和最终方法不能被覆盖l抽象方法必须在具体类1中被覆盖=== =ÕâÖÖÀ§»óÖ÷ÒªÊÇString.equals(...)方法和= =运算符的混淆然而实际上看看下面的例子其中两个被赋值以常量表达式“Programming”ʹÓÃequals(...)方法和“= =”运算符进行比较s0.equals(s1): trues0.equals(s2): trues0 == s1: falses0 == s2: true1具体类也就是抽象方法所属抽象类的非抽象子类第1部分语法String.equals()方法比较的是字符串的内容会对字符串中的所有字符如果完全相等在这种情况下个字符串都是相同的我们得到的返回值均为trueÔÚÕâÖÖÇé¿öÏÂs0和s1并不是同一个String实例读者也许会问这个问题的答案来自于Java语言规范中关于字符串常量的章节“Programming”它们在编译期就被确定了例如s2Java确保一个字符串常量只有一份拷贝Java会设置两个变量的引用为同一个常量的引用constant pool Java会跟踪所有的字符串常量并被保存在已编译的.class文件中的一些数据类当然还有字符串常量的信息变量s0和s2被确定constant pool resolution¸ÃÏî²Ù×÷Õë¶Ô×Ö·û´®µÄ´¦Àí¹ý³ÌÕª×ÔJVM规范5.4节n如果另一个常量池入口被标记为CONSTANT_String2ͬÑùµÄUnicode字符序列已经被确定n否则那么这项操作的结果就是那个相同String实例的引用一个新的String实例会被创建这个String实例就是该项操作的结果当常量池第一次确定一个字符串在常量池中都会得到之前创建的String实例它创建了字符串常量的一份拷贝到另一个String实例中对s0和s1的引用的比较结果是falseÕâ¾ÍÊÇΪºÎs0==s1的操作在某些情况下与s0.equals(s1)不同而s0.equals(s1)实际上执行的是字符串内容的比较字符串常量由0个或多个包含在双引号之内的字符组成escape sequence 2 它在.class内部使用Item 2: String.equals( )方法与运算符的用法比较存在于.class文件中的常量池并且可以扩充当针对一个String实例调用了intern()方法因为实例已经存在所以已存在的实例的引用被加入到该常量池01: import java.io.*;02:03: public class StringExample204: {05: public static void main (String args[])06: {07: String sFileName = "test.txt";08: String s0 = readStringFromFile(sFileName);09: String s1 = readStringFromFile(sFileName);10:11: System.out.println("s0 == s1: " + (s0 == s1));12: System.out.println("s0.equals(s1): " + (s0.equals(s1)));13:14: s0.intern();15: s1.intern();16:17: System.out.println("s0 == s1: " + (s0 == s1));18: System.out.println("s0 == s1.intern(): " +19: (s0 == s1.intern()));20: }21:22: private static String readStringFromFile (String sFileName)23: {24: //…read string from file…25: }26: }这个例子没有设置s0和s1的值为字符串常量并把值分配给readStringFromFile(...)方法创建的String实例程序对两个被新创建为具有同样字符值的String实例进行处理你会再次注意到但它们的内容是相同的第1部分语法s0 == s1: falses0.equals(s1): trues0 == s1: falses0 == s1.intern(): true第14行所做的是将String实例的引用s0存入常量池对s1.intern()方法的调用这样一来正是我们所期望的s0与s1仍旧是截然不同的两个String实例而s1.intern()返回的是常量池中的引用值假如我们希望将实例s1存入常量池中然后请求垃圾回收器回收被指向s0的String实例s1.intern()方法的调用总的来说equality comparisonÓ¦¸ÃʼÖÕʹÓÃString.equals(...)方法如果你还是习惯性地使用==运算符因为当n和m均为String实例的引用时假如你打算充分利用常量池的优势Item 3: Java是强类型语言 每个Java开发人员都需要很好地理解Java所支持的基本数据类型它们与你以前所使用的语言有什么不同呢Java是强类型的这些基本数据类型算得上是构造对象的了Java编译器能够及时地在开发过程中捕捉到许多简单细微的错误不过在Java中仍然有一些微妙之处Java的基本数据类型始终被描述在JVM中这就使得位运算得以较安全地执行boolean型是不可转换的Java不允许你编写在boolean型和非boolean型之间转换的代码那么你可能编写过一些诸如0等于false或非0等于true的“优雅”的代码Item 3: J ava是强类型语言在C语言中编写代码检查一个函数的返回值类似的代码在Java中是不能编译的所以你必须给它一个这样的值由于基本数据类型的转换可以隐性地发生以及如何工作而且一般来说loss of precision±àÒëÆ÷»áÏòÄã·¢³ö¾¯¸æarithmetic operation´ó¶àÊý¿ª·¢ÈËÔ±¶¼Ôø¾-д¹ýµ¼ÖÂÊý¾ÝÒâÍâÇжÏ的代码下面的Truncation类的第10行将会输出“2.0”01: public class Truncation02: {03: static void printFloat (float f)04: {05: System.out.println ("f = " + f);06: }07:08: public static void main (String[] args)09: {10: printFloat (12 / 5); // data lost!11: printFloat ((float) 12 / 5);12: printFloat (12 / 5.0f);13: }14: }因为12和5都是integer型因此小数部分丢失了当printFloat方法并没有得到期望的float型参数时修复很简单那么另一个也会被提升为float型第11行和12行操作正常转换操作会自动发生第1部分语法况下的转换被称作是因为它们都会被转换成能够存储较大数据的类型可以为int变量分配一个byte值图1.1展示了扩展转换当一个类型被转换为具有更多比特数的类型时图1.1 扩展转换注意或者把一个long型转换成为double 型换句话说就是一些最不重要的位可能会丢失下面这个例子的输出结果发生的精度损失对扩展转换有更详细的描述但是基本类型之间的扩展转换永远不会导致运行期异常narrowing¼´Èκβ»Í¬ÓÚͼ1.1中从左到右顺序的转换例如包括float型和double型包括shortoverflow¶¼»áµÃµ½±àÒëÆÚ´íÎócast可以避免这种错误“我清楚我在干什么Item 3: Java是强类型语言隐性类型转换顾名思义而是自动发生的为了方便short或char型且表达式的值一定为int型时当然不能超过变量类型的数值范围程序TypeConversion的第7行中的赋值可以编译通过范围-128到127但是第8行无法编译通过01: public class TypeConversion02: {03: static void convertArg (byte b) { }04:05: public static void main (String[] args)06: {07: byte b1 = 127;08: // byte b2 = 128; // won't compile09:10: // convertArg (127); // won't compile11: convertArg ((byte)127);12:13: byte c1 = b1;14: // byte c2 = -b1; // won't compile15: int i = ++b1; // overflow16: System.out.println ("i = " + i);17: }18: }隐性类型转换能够在3种情况下发生方法调用和算术运算假如表达式两边的类型不同类似地参数也有可能需要被转换类型Math.pow()方法期望的参数是double型由于这是一个扩展转换不过请注意隐性的窄化转换不支持方法调用上面例子的第10行不能被编译即对参数进行显性的强制转换第3种情况被称之为算术运算假如你希望将一个int型和一个float型相加求和其中较窄的类型总是被转换成较宽的类型第1部分语法同理但非全部诸如第14行的一元减法运算符所有的byte×ÜÊÇÖÁÉÙ±»ÌáÉýΪint型将会得到下面的错误信息然后警告你int型的值无法赋值给byte变量你可能预料到第15行中byte型的值在增量操作时那么第16行代码将会输出“i = 128”吧由于溢出的发生“i = -128”ÓÉÓÚÒ»¸ö¼òµ¥µÄ´íÎóÒýÆðµÄBugÕâÑùµÄBug的特征就在于或许你会因此困扰几个小时看看你要花费多长时间解决它Item 4: 那是构造函数吗这个IntAdder类相当简单3个private属性分别为x一个构造函数以及main方法在第21行位于第7行的构造函数设置了属性x²¢½«ËüÃǵĺ͸³¸øzÎÒÃǵ÷ÓÃprintResults方法执行IntAdder类后的输出结果应该是如果你认为没有问题实际的输出应该是你是否找出了问题所在呢好吧第21行第7行的IntAdder类构造函数设置了属性x和y的值难道这个构造函数没有工作吗就会明白它实际上是一个方法刚才你一定错误地将带有“void”返回类型的IntAdder方法当成了IntAdder类的构造函数了你也许会问那么当初始化实例ia时调用的构造函数是什么因为代码中没有构造函数这个默认的构造函数不用实现但其功能就和下面的这个构造函数一致在第21行被创建的对象ia的属性x当第22行的printResults 方法被调用时The value of 'z' is '0'.这个“简单”的小Bug还揭示了几个关键的问题我们注意到但编译并运行它的时候也就是说但是不推荐使用这样的命名这点很容易理解只有构造函数的名字才能和类名相同假如有和类同名的方法从另一个角度来说同样违背了命名规范并且首字母应该小写类名一般应该为名词或者名词短语关于命名规范在第1部分语法这个例子中在一个类中假如没有显式的构造函数存在而且这个构造函数是空的假如类中已经存在了一个带任意参数的构造函数Item 5: 不能访问被覆盖的方法 设想一下而这个编辑器支持RTF文件在这个应用程序自己的代码中或者通过访问编辑器的DocumentManager对象来打开新的文档一个Document对象被返回文法检查等等你接到了客户的电话你觉得实现这个需求没什么问题而且因为所有新加入的特性都被放置在Document类的一个名为HTMLDocument的子类中无需修改而且当需要的Document对象被DocumentManager类返回后以便使用HTMLDocument类的新特性你拿着新版本的编辑器以及一些利用新的HTML特性的代码这个新功能将在一个月内实现当你还自我感觉良好时上面指出了关于拼写检查程序的一个问题但是你自认为是一个聪明的Java程序员让它使用Doucment类的spellCheck()方法厂商已经声明了Document类的代码未被改动你就尝试着总去调用Document类的spellCheck()方法还是声明一个局部Document类型的变量并赋值为传入的Document对象所有的结果都将是失败的厂商的技术支持也明确地告诉你Document类没有被修改过并最终在8.4.6.1章节中看到了下面这段话Item 5: 不能访问被覆盖的方法“可以通过包含关键字super的方法调用表达式来访问被覆盖的方法尝试用全局名或强制转换为父类型都是无效的一切都清楚了这第三方文本编辑器的类库总是创建一个HTMLDocument型的对象强制转换而不是所期望的Document类的spellCheck()方法当你创建了一个覆盖了父类实例方法的子类时就是使用super关键字永远不能调用父类的这些被覆盖的实例方法01: class DocumentManager02: {03: public Document newDocument()04: {05: return (new HTMLDocument());06: }07: }08:09: class Document10: {11: public boolean spellCheck()12: {13: return (true);14: }15: }16:17: class HTMLDocument extends Document18: {19: public boolean spellCheck()20: {21: System.out.println("Trouble checking these darn hyperlinks!");22: return (false);23: }24: }25:26: public class OverridingInstanceApp27: {28: public static void main (String args[])29: {30: DocumentManager dm = new DocumentManager();第1部分语法31: Document d = dm.newDocument();32: boolean spellCheckSuccessful = d.spellCheck();33: if (spellCheckSuccessful)34: System.out.println("No spelling errors where found.");35: else36: System.out.println("Document has spelling errors.");37: }38: }在第32行中然而所以这个例子的输出结果是这样的无法访问父类中被子类覆盖的方法的原则也就是非静态方法并非真的覆盖参见Item1ËüÃÇÈÔ¾ÉÄܱ»·ÃÎʽ«µÚ11行和第19行的代码替换为下面这行public static boolean spellCheck(Document d)然后再将第32行代码替换为下面这行boolean spellCheckSuccessful = d.spellCheck(d);最后执行修改后的程序No spelling errors where found.你也许会质疑这里所举的例子是否真实地发生过这个例子是虚构的通常来说也就是父类但是实际上它们得到的是新类的实例JavaSoft有一个不错的例子在旧版本的JDK中例如paint(...)和update(...)它们在新版的JDK中传递的都是Graphics2D对象Graphics2D类覆盖了Graphics类中的一些实例方法draw3DRect()假设在Graphics2D类中的draw3DRect()方法有一个BugÄÇôÕýÈçÄãµÄÅжÏItem 6: 避免落入的陷阱尽管在子类的外部无法访问父类中被覆盖的实例方法假如你怀疑你所使用的某个对象实际上是一个子类的实例又如果你是编写增加了新功能的子类的程序员或者保证在编写程序时而不是覆盖父类方法实现的隐藏变量成员与理解方法是如何被覆盖同等重要的就是假如你认为自己已经理解了方法是如何被覆盖的那么你最好仔细地读读本节无意地隐藏了一个变量成员或者错误地认为已经“覆盖”了一个变量成员01: public class Wealthy02: {03: public String answer = "Yes!";04: public void wantMoney()05: {06: System.out.println("Would you like $1,000,000? > "+ answer);07: }08: public static void main(String[] args)09: {10: Wealthy w = new Wealthy();11: w.wantMoney();12: }13: }输出结果为Wealthy类具有一个名为answer的实例变量以及一个main方法一个Wealthy类的实例w被创建输出了一个问题以及作为回答的实例变量answer的值现在让我们来看看一个没有正确回答这个问题的例子第1部分语法01: public class Poor02: {03: public String answer = "Yes!";04: public void wantMoney()05: {06: String answer = "No!"; // hides instance variable answer07: System.out.println("Would you like $1,000,000? > " + answer);08: }09: public static void main(String[] args)10: {11: Poor p = new Poor();12: p.wantMoney();13: }14: }输出结果为本例输出中的回答已经变成了“No局部变量answer隐藏了实例变量answer »Ø´ðµÄ½á¹û¾ÍÊǾֲ¿±äÁ¿µÄÖµÒ²ÏÔ¶øÒ×¼û产生了意想不到的结果在许多复杂的环境下为了避免“数据隐藏”所带来的问题l不同类型的Java变量l何种变量能被隐藏l如何访问被隐藏的变量不同类型的Java变量Java一共有6种变量类型实例变量构造函数参数以及局部变量实例变量是在类体中声明的非静态变量方法参数是用来传入一个方法体的Item 6: 避免落入的陷阱的最后下面的例子声明了各种类型的变量在这个代码块中简名是一个变量的专一标识符实例变量x的简名就是“x”±äÁ¿³ÉÔ±x和y的作用范围就是Types类的类体构造函数参数的作用范围就是整个构造函数体局部变量的作用范围就是它被声明的所在代码块它在第11行也就是createURL方法中被声明第1部分语法何种变量能被隐藏实例变量和类变量能被隐藏假如用一个同名的局部变量去隐藏一个参数同样地编译器也会报错第5行的局部变量不能和方法参数args同名第7行的局部变量s也会引起编译器错误实例变量和类变量如何被隐藏同名的局部变量或者同名的参数变量成员也能被子类的同名变量成员隐藏将在其作用范围内与一个变量成员同名的方法参数与一个变量成员同名的构造函数参数依此类推将在catch语句块中隐藏掉这个变量成员Item 6: 避免落入的陷阱方法输出的type变上例中System.out.println量的值将是构造函数参数type的值子类的变量成员将会隐藏掉父类中同名的变量成员Bike类中的实例变量type×ÓÀàµÄÀà±äÁ¿½«»áÒþ²Ø¸¸ÀàÖÐÓë֮ͬÃûµÄÀà±äÁ¿ºÍʵÀý±äÁ¿×ÓÀàµÄʵÀý±äÁ¿Ò²»áÒþ²Ø¸¸ÀàÖÐÓë֮ͬÃûµÄÀà±äÁ¿ºÍʵÀý±äÁ¿04: }01: public class Line02: {03: int x;04: }01: public class MultiLine extends Line implements Stretchable02: {03: public MultiLine()04: {05: System.out.println("x = " + x);06: }07: }上例的程序可以编译通过那么MultiLine类将无法通过编译 第1部分语法如何访问被隐藏的变量通过全局名关键字“this”可以限定一个正被局部变量隐藏的实例变量类变量也可以被限定01: public class Wealthy02: {03: public String answer = "Yes!";04: public void wantMoney()05: {06: String answer = "No!";07: System.out.println("Do you want to give me $1,000,000? > " +08: answer);09: System.out.println("Would you like $1,000,000? > " +10: this.answer);11: }12: public static void main(String[] args)13: {14: Wealthy w = new Wealthy();15: w.wantMoney();16: }17: }输出结果为Wealthy类具有一个名为answer的实例变量为了对wantMoney方法中的每个问题都给出正确的回答也需要访问实例变量answer我们告知编译器而非局部变量answerµÚÒ»¸öÎÊÌâµÄ»Ø´ðÊǾֲ¿±äÁ¿answer的值它被关键字“this”限定了01: public class StillWealthy extends Wealthy02: {03: public String answer = "No!";Item 6: 避免落入的陷阱04: public void wantMoney()05: {06: String answer = "maybe?";07: System.out.println("Did you see that henway? > " + answer);08: System.out.println("Do you want to give me $1,000,000? > " +09: this.answer);10: System.out.println("Would you like $1,000,000? > " + s uper.answer);11: }12: public static void main(String[] args)13: {14: Wealthy w = new Wealthy();15: w.wantMoney();16: }17: }输出结果为上例中第7行问题的回答第8行问题的回答它被关键字“this”限定了输出的是父类Wealthy的实例变量变量隐藏与方法覆盖的区别隐藏变量和覆盖方法有许多区别一个类的实例或者强制转换自己为其父类的类型01: public class Wealthier extends Wealthy02: {03: public void wantMoney()04: {05: System.out.println("Would you like $2,000,000? > " + answer);06: }07: public static void main(String[] args)08: {09: Wealthier w = new Wealthier();10: w.wantMoney();11: ((Wealthy)w).wantMoney();12: }13: }第1部分语法输出结果为Wealthier类继承了Wealthy类main方法创建了Wealthier类的一个实例w×¢Òâ½Ó×Å并再次调用它的wantMoney()方法上面的例子说明是无法访问父类中被覆盖的方法的一个被隐藏的变量与一个被覆盖的方法的区别强制转换子类的实例为父类类型后01: public class Poorer extends Wealthier02: {03: String answer = "No!";04: public void wantMoney()05: {06: System.out.println("Would you like $3,000,000? > " + answer);07: }08: public static void main(String[] args)09: {10: Poorer p = new Poorer();11: ((Wealthier)p).wantMoney();12: System.out.println("Are you sure? > " + ((Wealthier)p).answer);13: }14: }输出结果为main方法创建了一个Poorer类的实例pÕýÈçÔÚǰһ¸öÀý×ÓÖнâÊ͵Äͨ¹ýÇ¿ÖÆ×ª»»Òò´ËËüµÄ»Ø´ðÊÇ“No!”main方法又问到这个问题答案就不再是子类变量的值这种情况的出现Item 7: 提前引用仅仅“隐藏”了父类的变量成员只要将子类实例强制转换为父类类型数据隐藏与方法覆盖的另外一个不同而静态变量相同地而变量成员却可以隐藏父类同名变量成员通过理解本节讨论的知识点会帮助应用程序得到你所期望的结果Item 7: 提前引用 类变量以及静态初始化块是在类被加载进JVM时执行初始化操作的“静态初始化块和类变量是按照其在代码中出现的顺序依次执行初始化操作的换句话说一般来说看看下面的代码将会得到一个如下的错误即使变量first和second都处在同一个作用范围内而且编译器会捕捉到这个错误绕开这个保护措施还是有可能的而且方法内部对类变量的访问不会按照这个原则被检查01: public class ForwardReferenceViaMethod02: {03: static int first = accessTooSoon();05:06: static int accessTooSoon()07: {第1部分语法08: return (second);09: }10:11: public static void main (String[] args)12: {13: System.out.println ("first = " + first);14: }15: }然而由于在初始化second之前那么方法得到的是second的默认值输出结果first的值为0问题并非这么简单那么你必须保证Item 8: 设计可继承的构造函数 包括Java在内代码容易被复用就是继承它不幸的是软件开发过程中举例来说你经常会发现代码是如此复杂且难以维护当程序原本就比较容易扩展时一般来说代价就要小得多了你可能会遭遇到许多阻碍甚至是抵触扩展性的陷阱那么当你设计类以及编写代码时我所见过的最常见的陷阱之一不论你的方法设计得多么完美其它开发人员在继承你的类时因为构造函数是不能被覆盖的子类都必须承受它那么它的任何子类都一定会做同样的工作在编写子类的开发人员无权访问父类的源代码时举例来说01: import java.awt.*;02: import java.awt.event.*;03: import java.io.*;04: import java.util.*;Item 8: 设计可继承的构造函数05:06: import javax.swing.*;07: import javax.swing.event.*;08:09: public class ListDialog extends JDialog10: implements ActionListener, ListSelectionListener11: {12: JList model;13: JButton selectButton;14: LDListener listener;15: Object[] selections;16:17: public ListDialog (String title,18: String[] items,19: LDListener listener)20: {21: super ((Frame)null, title);22:23: JPanel buttonPane = new JPanel ();24: selectButton = new JButton ("SELECT");25: selectButton.addActionListener (this);26: selectButton.setEnabled (false);//nothing selected yet27: buttonPane.add (selectButton);28:29: JButton cancelButton = new JButton ("CANCEL");30: cancelButton.addActionListener (this);31: buttonPane.add (cancelButton);32:33: this.getContentPane().add (buttonPane, BorderLayout.SOUTH);34:35: this.listener = listener;36: setModel (items);37: }38:39: void setModel (String[] items)40: {41: if (this.model != null)42: this.model.removeListSelectionListener (this);43: this.model = new JList (items);44: model.addListSelectionListener (this);45:46: JScrollPane scroll = new JScrollPane (model);47: this.getContentPane().add (scroll, BorderLayout.CENTER);48: this.pack();49: }50:51: /** Implement ListSelectionListener. Track user selections. */52:53: public void valueChanged (ListSelectionEvent e)54: {55: selections = model.getSelectedValues();第1部分语法56: if (selections.length > 0)57: selectButton.setEnabled (true);58: }59:60: /** Implement ActionListener. Called when the user picks the 61: * SELECT or CANCEL button. Generates the LDEvent. */62:63: public void actionPerformed (ActionEvent e)64: {65: this.setVisible (false);66: String buttonLabel = e.getActionCommand();67: if (buttonLabel.equals ("CANCEL"))68: selections = null;69: if (listener != null)70: {71: LDEvent lde = new LDEvent (this, selections);72: listener.listDialogSelection (lde);73: }74: }75:76: public static void main (String[] args) // self-testing code 77: {78: String[] items = (new String[]79: {"Forest", "Island", "Mountain", "Plains", "Swamp"});80: LDListener listener =81: new LDListener()82: {83: public void listDialogSelection (LDEvent e)84: {85: Object[] selected = e.getSelection();86: if (selected != null) // null if user cancels87: for (int i = 0; i < selected.length; i++)88: System.out.println (selected[i] .toString());89: System.exit (0);90: }91: };92:93: ListDialog dialog =94: new ListDialog ("ListDialog", items, listener);95: dialog.show();96: }97: }出于程序完整性的考虑01: public interface LDListener02: {03: public void listDialogSelection (LDEvent e);04: }01: import java.util.EventObject;Item 8: 设计可继承的构造函数02:03: public class LDEvent extends java.util.EventObject04: {05: Object source;06: Object[] selections;07:08: public LDEvent (Object source, Object[] selections)09: {10: super (source);11: this.selections = selections;12: }13:14: public Object[] getSelection()15: {16: return (selections);17: }18: }ListDialog类看上去写得相当不错假设你需要开发一个向用户显示一列声音文件的菜单能够听到相应的声音所以你决定提供一个简单的API²¢²â¶¨¸Ã·¾¶ÏµÄÉùÒôÎļþÁбí¾ÍÄܹ»ÊµÏÖÕâ¸öÄ¿µÄÁË以便播放用户选择的声音你可以调用上例第44行显示的addListSelectionListener(...)方法来解决而且没有任何访问它的方法而且你恐怕要从头开始做起了一切都还不错当你尝试去继承ListDialog类上例第一部分的第17行然而你并没有这个资源由于构造函数第一件要做的事就是调用super(...)语句 问题出现了去翻翻Javadoc文档它似乎可以提供帮助你首先在子类构造函数中试着实例化一个items参数为空的ListDialog类调用setModel(...)方法第1部分语法05: String[] items = getItems (path);06: setModel (items);07: model.addListSelectionListener (this);08: model.setSelectionMode (ListSelectionModel.SINGLE_SELECTION);09: }这个解决方法看上去合情合理将会得到下面的错误你找到了错误的关键导致了意想不到的结果你终于判定尝试调用一个没有item的JList对象的pack()方法那么现在该如何是好呢你还算幸运的因此你可以用自定义的同名方法覆盖掉它01: import java.applet.*;02: import java.awt.*;03: import java.io.*;04: import .*;05:06: import javax.swing.*;07: import javax.swing.event.*;08:09: public class SoundDialog extends ListDialog10: implements FilenameFilter, ListSelectionListener11: {12: String selection;13:14: public SoundDialog (String title, LDListener ldl, String path)15: {16: super (title, null, ldl);17: String[] items = getItems (path);18: setModel (items);19: }Item 8: 设计可继承的构造函数20:21: public void setModel (String[] items)22: {23: if (items != null)24: {25: super.setModel (items);26: model.addListSelectionListener (this);27: model.setSelectionMode28: (ListSelectionModel.SINGLE_SELECTION);29: }30: }31:32: public String[] getItems (String path)33: {34: File file = new File (path);35: File soundFiles[] = file.listFiles (this);36: String[] items = new String [soundFiles.length];37: for (int i = 0; i < soundFiles.length; i++)38: items = soundFiles.getName();39: return (items);40: }41:42: // implement FilenameFilter43: public boolean accept (File dir, String name)44: {45: return (name.endsWith (".aiff") ||46: name.endsWith (".au") ||47: name.endsWith (".midi") ||48: name.endsWith (".rmf") ||49: name.endsWith (".wav"));50: }51:52: // implement ListSelectionListener53: public void valueChanged (ListSelectionEvent e)54: {55: super.valueChanged (e);6: JList items = (JList) e.getSource();57: String fileName = items.getSelectedValue().toString();58: if (!fileName.equals (selection))59: {60: selection = fileName;61: play (selection);62: }63: }64:65: private void play (String fileName)66: {67: try68: {69: File file = new File (fileName);70: URL url = new URL ("file://" + file.getAbsolutePath());第1部分语法71: AudioClip audioClip = Applet.newAudioClip (url);72: if (audioClip != null)73: audioClip.play();74: }75: catch (MalformedURLException e)76: {77: System.err.println (e + ": " + e.getMessage());78: }79: }80:81: public static void main (String[] args) // self-test82: {83: LDListener listener =84: new LDListener()85: {86: public void listDialogSelection (LDEvent e)87: {88: Object[] selected = e.getSelection();89: if (selected != null) // null if user cancels90: for (int i = 0; i < selected.length; i++)91: System.out.println (selected[i].toString());92: System.exit (0);93: }94: };95: SoundDialog dialog =96: new SoundDialog ("SoundDialog", listener, ".");97: dialog.show();98: }99: }回味一下那么上述这些工作都是不需要的调用了一个private方法请确信你这么做是必要的因为它也许会为其它不太复杂的构造函数提供一个便利的实现那么你就要考虑增加额外版本的构造函数如果你能够提供一个无参数的构造函数那就再好不过了例如你必须仔细地检查其它方法没有使用仍未被实例化的变量那么你就应该考虑限制访问它了当然但是你可以不用担心其它开发人员使用它创建一些无效的对象了。

相关文档
最新文档