﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-ahwen-文章分类-Java技术</title><link>http://www.blogjava.net/ahwen/category/7713.html</link><description /><language>zh-cn</language><lastBuildDate>Fri, 02 Mar 2007 06:47:31 GMT</lastBuildDate><pubDate>Fri, 02 Mar 2007 06:47:31 GMT</pubDate><ttl>60</ttl><item><title>java面试题 </title><link>http://www.blogjava.net/ahwen/articles/33911.html</link><dc:creator>ahwen</dc:creator><author>ahwen</author><pubDate>Mon, 06 Mar 2006 12:16:00 GMT</pubDate><guid>http://www.blogjava.net/ahwen/articles/33911.html</guid><wfw:comment>http://www.blogjava.net/ahwen/comments/33911.html</wfw:comment><comments>http://www.blogjava.net/ahwen/articles/33911.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/ahwen/comments/commentRss/33911.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/ahwen/services/trackbacks/33911.html</trackback:ping><description><![CDATA[<FONT color=#ff0000>第一，谈谈final, finally, finalize的区别。</FONT> <BR>final 用于声明属性，方法和类，分别表示属性不可变，方法不可覆盖，类不可继承。 finally是异常处理语句结构的一部分，表示总是执行。finalize是Object类的一个方法，在垃圾收集器执行的时候会调用被回收对象的此方法，可以覆盖此方法提供垃圾收集时的其他资源回收，例如关闭文件等。 <BR><FONT color=red>第二，Anonymous Inner Class (匿名内部类)是否可以extends(继承)其它类，是否可以implements(实现)interface(接口)? </FONT><BR>可以继承其他类或完成其他接口，在swing编程中常用此方式。 <BR><FONT color=red>第三，Static Nested Class 和 Inner Class的不同， </FONT><BR>说得越多越好(面试题有的很笼统)。Static Nested Class是被声明为静态（static）的内部类，它可以不依赖于外部类实例被实例化。而通常的内部类需要在外部类实例化后才能实例化。 <BR><FONT color=red>第四，&amp;和&amp;&amp;的区别。 </FONT><BR>&amp;是位运算符，表示按位与运算，&amp;&amp;是逻辑运算符，表示逻辑与（and）. <BR><FONT color=red>第五，HashMap和Hashtable的区别。 </FONT><BR>HashMap是Hashtable的轻量级实现（非线程安全的实现），他们都完成了Map接口，主要区别在于HashMap允许空（null）键值（key）,由于非线程安全，效率上可能高于Hashtable. <BR><FONT color=red>第六，Collection 和 Collections的区别。</FONT> <BR>　　Collection是集合类的上级接口，继承与他的接口主要有Set 和List.Collections是针对集合类的一个帮助类，他提供一系列静态方法实现对各种集合的搜索、排序、线程安全化等操作。 <BR><FONT color=red>第七，什么时候用assert。 </FONT><BR>1.4新增关键字（语法），用于测试boolean表达式状态，可用于调试程序。使用方法 assert <BOOLEAN&#34920;&#36798;&#24335;>，表示如果表达式为真（true）,则下面的语句执行，否则抛出AssertionError。另外的使用方式assert &lt; boolean表达式&gt;:<OTHER&#34920;&#36798;&#24335;>，表示如果表达式为真，后面的表达式忽略，否则后面表达式的值用于AssertionError的构建参数。注意编译时要增加-source 1.4 参数，否则报错。]运行时要增加 -ea参数，否则assert行被忽略 <BR><FONT color=red>第八，GC是什么? 为什么要有GC? </FONT><BR>　　GC是垃圾收集的意思（Gabage Collection）,内存处理是编程人员容易出现问题的地方，忘记或者错误的内存回收会导致程序或系统的不稳定甚至崩溃，Java提供的GC功能可以自动监测对象是否超过作用域从而达到自动回收内存的目的，Java语言没有提供释放已分配内存的显示操作方法。 <BR><FONT color=red>第九，String s = new String("xyz");创建了几个String Object? </FONT><BR>两个 <BR><FONT color=red>第十，Math.round(11.5)等於多少? Math.round(-11.5)等於多少? </FONT><BR>Math.round(11.5)==12 <BR>Math.round(-11.5)==-11 <BR>round方法返回与参数最接近的长整数，参数加1/2后求其floor. <BR><FONT color=red>第十一，short s1 = 1; s1 = s1 + 1;有什么错? short s1 = 1; s1 += 1;有什么错? </FONT><BR>short s1 = 1; s1 = s1 + 1; （s1+1运算结果是int型，需要强制转换类型） <BR>short s1 = 1; s1 += 1;（可以正确编译） <BR><FONT color=red>第十二，sleep() 和 wait() 有什么区别? </FONT><BR>sleep是线程类（Thread）的方法，导致此线程暂停执行指定时间，给执行机会给其他线程，但是监控状态依然保持，到时后会自动恢复。调用sleep不会释放对象锁。wait是Object类的方法，对此对象调用wait方法导致本线程放弃对象锁，进入等待此对象的等待锁定池，只有针对此对象发出notify方法（或notifyAll）后本线程才进入对象锁定池准备获得对象锁进入运行状态。 <BR><FONT color=red>第十三，Java有没有goto? </FONT><BR>没有 <BR><FONT color=red>第十四，数组有没有length()这个方法? String有没有length()这个方法？ </FONT><BR>数组没有length()这个方法，有length的属性。 String有有length()这个方法。 <BR><FONT color=red>第十五，Overload和Override的区别。Overloaded的方法是否可以改变返回值的类型? </FONT><BR>方法的重写Overriding和重载Overloading是Java多态性的不同表现。重写Overriding是父类与子类之间多态性的一种表现，重载Overloading是一个类中多态性的一种表现。如果在子类中定义某方法与其父类有相同的名称和参数，我们说该方法被重写 (Overriding)。子类的对象使用这个方法时，将调用子类中的定义，对它而言，父类中的定义如同被"屏蔽"了。如果在一个类中定义了多个同名的方法，它们或有不同的参数个数或有不同的参数类型，则称为方法的重载(Overloading)。Overloaded的方法是可以改变返回值的类型。 <BR><FONT color=red>第十六，Set里的元素是不能重复的，那么用什么方法来区分重复与否呢? 是用==还是equals()? 它们有何区别? </FONT><BR>Set里的元素是不能重复的，那么用iterator()方法来区分重复与否。equals()是判读两个Set是否相等。equals()和==方法决定引用值是否指向同一对象equals()在类中被覆盖，为的是当两个分离的对象的内容和类型相配的话，返回真值。 <BR><FONT color=red>第十七，给我一个你最常见到的runtime exception。 </FONT><BR>ArithmeticException, ArrayStoreException, BufferOverflowException, BufferUnderflowException, CannotRedoException, CannotUndoException, ClassCastException, CMMException, ConcurrentModificationException, DOMException, EmptyStackException, IllegalArgumentException, IllegalMonitorStateException, IllegalPathStateException, IllegalStateException, ImagingOpException, IndexOutOfBoundsException, MissingResourceException, NegativeArraySizeException, NoSuchElementException, NullPointerException, ProfileDataException, ProviderException, RasterFormatException, SecurityException, SystemException, UndeclaredThrowableException, UnmodifiableSetException, UnsupportedOperationException <BR><FONT color=red>第十八，error和exception有什么区别? </FONT><BR>error 表示恢复不是不可能但很困难的情况下的一种严重问题。比如说内存溢出。不可能指望程序能处理这样的情况。exception 表示一种设计或实现问题。也就是说，它表示如果程序运行正常，从不会发生的情况。 <BR><FONT color=red>第十九，List, Set, Map是否继承自Collection接口? </FONT><BR>List，Set是Map不是 <BR><FONT color=red>第二十，abstract class和interface有什么区别? </FONT><BR>声明方法的存在而不去实现它的类被叫做抽象类（abstract class），它用于要创建一个体现某些基本行为的类，并为该类声明方法，但不能在该类中实现该类的情况。不能创建abstract 类的实例。然而可以创建一个变量，其类型是一个抽象类，并让它指向具体子类的一个实例。不能有抽象构造函数或抽象静态方法。Abstract 类的子类为它们父类中的所有抽象方法提供实现，否则它们也是抽象类为。取而代之，在子类中实现该方法。知道其行为的其它类可以在类中实现这些方法。接口（interface）是抽象类的变体。在接口中，所有方法都是抽象的。多继承性可通过实现这样的接口而获得。接口中的所有方法都是抽象的，没有一个有程序体。接口只可以定义static final成员变量。接口的实现与子类相似，除了该实现类不能从接口定义中继承行为。当类实现特殊接口时，它定义（即将程序体给予）所有这种接口的方法。然后，它可以在实现了该接口的类的任何对象上调用接口的方法。由于有抽象类，它允许使用接口名作为引用变量的类型。通常的动态联编将生效。引用可以转换到接口类型或从接口类型转换，instanceof 运算符可以用来决定某对象的类是否实现了接口。 <BR><FONT color=red>第二十一，abstract的method是否可同时是static,是否可同时是native，是否可同时是synchronized? </FONT><BR>都不能 <BR><FONT color=red>第二十二，接口是否可继承接口? 抽象类是否可实现(implements)接口? 抽象类是否可继承实体类(concrete class)? </FONT><BR>接口可以继承接口。抽象类可以实现(implements)接口，抽象类是否可继承实体类，但前提是实体类必须有明确的构造函数。 <BR><FONT color=red>第二十三，启动一个线程是用run()还是start()? </FONT><BR>启动一个线程是调用start()方法，使线程所代表的虚拟处理机处于可运行状态，这意味着它可以由JVM调度并执行。这并不意味着线程就会立即运行。run()方法可以产生必须退出的标志来停止一个线程。 <BR><FONT color=red>第二十四，构造器Constructor是否可被override? </FONT><BR>构造器Constructor不能被继承，因此不能重写Overriding，但可以被重载Overloading。 <BR><FONT color=red>第二十五，是否可以继承String类? </FONT><BR>String类是final类故不可以继承。 <BR><FONT color=red>第二十六，当一个线程进入一个对象的一个synchronized方法后，其它线程是否可进入此对象的其它方法? </FONT><BR>不能，一个对象的一个synchronized方法只能由一个线程访问。 <BR><FONT color=red>第二十七，try {}里有一个return语句，那么紧跟在这个try后的finally {}里的code会不会被执行，什么时候被执行，在return前还是后? </FONT><BR>会执行，在return前执行。 <BR><FONT color=red>第二十八，编程题: 用最有效率的方法算出2乘以8等於几? </FONT><BR>2 &lt;&lt; 3 <BR><FONT color=red>第二十九，两个对象值相同(x.equals(y) == true)，但却可有不同的hash code，这句话对不对? </FONT><BR>不对，有相同的hash code。 <BR><FONT color=red>第三十，当一个对象被当作参数传递到一个方法后，此方法可改变这个对象的属性，并可返回变化后的结果，那么这里到底是值传递还是引用传递? </FONT><BR>是值传递。Java 编程语言只由值传递参数。当一个对象实例作为一个参数被传递到方法中时，参数的值就是对该对象的引用。对象的内容可以在被调用的方法中改变，但对象的引用是永远不会改变的。 <BR><FONT color=red>第三十一，swtich是否能作用在byte上，是否能作用在long上，是否能作用在String上? </FONT><BR>switch（expr1）中，expr1是一个整数表达式。因此传递给 switch 和 case 语句的参数应该是 int、 short、 char 或者 byte。long,string 都不能作用于swtich。 <BR><FONT color=red>第三十二，编程题: 写一个Singleton出来。 </FONT><BR>Singleton模式主要作用是保证在Java应用程序中，一个类Class只有一个实例存在。 <BR>一般Singleton模式通常有几种种形式: <BR>第一种形式: 定义一个类，它的构造函数为private的，它有一个static的private的该类变量，在类初始化时实例话，通过一个public的getInstance方法获取对它的引用,继而调用其中的方法。 <BR>public class Singleton { <BR>　　private Singleton(){} <BR>　　//在自己内部定义自己一个实例，是不是很奇怪？ <BR>　　//注意这是private 只供内部调用 <BR>　　private static Singleton instance = new Singleton(); <BR>　　 //这里提供了一个供外部访问本class的静态方法，可以直接访问　　 <BR>　　public static Singleton getInstance() { <BR>　　　　return instance; 　　 <BR>　　 } <BR>} <BR>第二种形式: <BR>public class Singleton { <BR>　　private static Singleton instance = null; <BR>　　public static synchronized Singleton getInstance() { <BR>　　//这个方法比上面有所改进，不用每次都进行生成对象，只是第一次　 <BR>　　 　　　//使用时生成实例，提高了效率！ <BR>　　if (instance==null) <BR>　　　　instance＝new Singleton(); <BR>return instance; 　　} <BR>} <BR>其他形式: <BR>定义一个类，它的构造函数为private的，所有方法为static的。 <BR>一般认为第一种形式要更加安全些 <BR><img src ="http://www.blogjava.net/ahwen/aggbug/33911.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/ahwen/" target="_blank">ahwen</a> 2006-03-06 20:16 <a href="http://www.blogjava.net/ahwen/articles/33911.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关于Java的classpath和package概念！</title><link>http://www.blogjava.net/ahwen/articles/33358.html</link><dc:creator>ahwen</dc:creator><author>ahwen</author><pubDate>Fri, 03 Mar 2006 01:29:00 GMT</pubDate><guid>http://www.blogjava.net/ahwen/articles/33358.html</guid><wfw:comment>http://www.blogjava.net/ahwen/comments/33358.html</wfw:comment><comments>http://www.blogjava.net/ahwen/articles/33358.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/ahwen/comments/commentRss/33358.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/ahwen/services/trackbacks/33358.html</trackback:ping><description><![CDATA[<DIV class=post><A id=%E8%B7%A8%E8%BF%9Bjava%E7%9A%84%E9%97%A8%E7%A5%A8_%E5%AE%9E%E4%BE%8B%E8%AF%A6%E8%A7%A3classpath%E5%8F%8Apackage name=%E8%B7%A8%E8%BF%9Bjava%E7%9A%84%E9%97%A8%E7%A5%A8_%E5%AE%9E%E4%BE%8B%E8%AF%A6%E8%A7%A3classpath%E5%8F%8Apackage></A>
<H2 class=storytitle id=跨进java的门票_实例详解classpath及package><A href="http://blog.matrix.org.cn/page/Sarkuya?entry=%E8%B7%A8%E8%BF%9Bjava%E7%9A%84%E9%97%A8%E7%A5%A8_%E5%AE%9E%E4%BE%8B%E8%AF%A6%E8%A7%A3classpath%E5%8F%8Apackage"><FONT color=#5c6c7d>跨进Java的门票 - 实例详解classpath及package</FONT></A></H2>
<P class=meta>Java很诱人，但对于刚跨入Java门槛的初学者来说，编译并运行一个无比简单的Java程序简直就是一个恶梦。明明程序没错，但各种各样让人摸不着头脑的错误信息真的让你百思不得其解，许多在Java门口徘徊了很久的初学者就这样放弃了学习Java的机会，很是可惜。笔者也经历过这个无比痛苦的阶段，感觉到编译难的问题就出在classpath的设置及对package的理解之上。本文以实例的方式，逐一解决在编译过程中所出现的各种classpath的设置问题。本文实例运行的环境是在Windows XP + JDK 1.5.0。对其他的环境，读者应该很容易进行相应的转换。<BR><BR>1. 下载并安装JDK1.5.0，并按默认路径，安装到C:\Program Files\Java\jdk1.5.0中。<BR><BR>2. 用鼠标单击WindowsXP的“开始”-&gt;“运行”，在弹出的运行窗口中输入cmd，按确定或回车，打开一个命令行窗口。<BR><BR>3. 在命令行中输入：<BR><BR>java<BR><BR>有一列长长的洋文滚了出来，这是JDK告诉我们java这个命令的使用方法。其中隐含了一个重要信息，即JDK安装成功，可以在命令行中使用java此命令了。<BR><BR>4. 在命令行中输入<BR><BR>javac<BR><BR>屏幕显示：<BR><BR>"javac"不是内部或外部命令，也不是可运行的程序或批处理文件。<BR><BR>这是由于windows找不到javac这个命令的原因。这就不明白了，java与javac都是JDK在同一个子目录里面的两个文件，为什么可以直接运行java而不能直接运行javac呢？原来，Sun公司为了方便大家在安装完JDK后马上就可以运行Java类文件，在后台悄悄地将java命令加入了Path的搜索路径中，因此我们可以直接运行java命令(但我们是看不到它到底是在哪设置的，无论是在用户的Path或系统的Path设置中均找不到这个java存放的路径)。但Sun所做的到此为止，其他JDK的命令，一概不管，需要由用户自己添加到搜索路径中。<BR><BR>5. 既然如此，那我们自己添加Path的搜索路径吧。对“我的电脑”按右键，选“属性”，在“系统属性”窗口中选“高级”标签，再按“环境变量”按钮，弹出一个“环境变量”的窗口，在用户变量中新建一个变量，变量名为“Path”，变量值为"C:\Program Files\Java\jdk1.5.0\bin;%PATH%"。最后的%PATH%的意思是说，保留原有的Path设置，且将目前的Path设置新加到其前面。一路按“确定”退出(共有3次)。关掉原来的命令行窗口，依照第2步，重新打开一个新的命令行窗口。在此窗口中输入<BR><BR>javac<BR><BR>长长的洋文又出现了，这回是介绍javac的用法。设置成功。<BR><BR>6. So far so good. 到目前为止，我们已经可以编程了。但是，这不是一个好办法。因为随着以后我们深入学习Java，我们就会用到JUnit、Ant或NetBeans等应用工具，这些工具在安装时，都需要一个名为指向JDK路径的“JAVA_HOME”的环境变量，否则就安装不了。因此，我们需要改进第5步，为以后作好准备。依照第5步，弹出“环境变量”的窗口，在用户变量中新建一个变量，变量名为“JAVA_HOME”，变量值为"C:\Program Files\Java\jdk1.5.0"。注意，这里的变量值只到jdk1.5.0，不能延伸到bin中。确定后，返回“环境变量”的窗口，双击我们原先设定的Path变量，将其值修改为“%JAVA_HOME%\bin;%PATH%”。这种效果与第5步是完全一样的，只不过多了一个JAVA_HOME的变量。这样，以后当我们需要指向JDK的路径时，只需要加入“%JAVA_HOME%”就行了。至此，Path路径全部设置完毕。一路确定退出，打开新的命令行窗口，输入<BR><BR>javac<BR><BR>如果长长的洋文出现，Path已经设置正确，一切正常。如果不是，请仔细检查本步骤是否完全设置正确。<BR><BR>7. 开始编程。在C盘的根目录中新建一个子目录，名为“JavaTest”，以作为存放Java源代码的地方。打开XP中的记事本，先将其保存到JavaTest文件夹中，在“文件名”文本框中输入"Hello.java"。注意，在文件名的前后各加上一个双引号，否则，记事本就会将其存为"Hello.java.txt"的文本文件。然后输入以下代码：<BR><BR>public class Hello {<BR>public static void main(String[] args) {<BR>System.out.println("Hello, world");<BR>}<BR>}<BR><BR>再次保存文件。<BR><BR>8. 在命令行窗口中输入<BR><BR>cd C:\JavaTest<BR><BR>将当前路径转入JavaTest中。然后，输入<BR><BR>javac Hello.java<BR><BR>JDK就在JavaTest文件夹中编译生成一个Hello.class的类文件。如果出现“1 error”或“XX errors”的字样，说明是源代码的输入有误，请根据出错提示，仔细地按第7步的代码找出并修正错误。请读者注意甄别代码输入有误的问题与classpath设置有误的问题。因为本文是关于如何正确设置classpath及package的，因此，这里假设读者输入的代码准确无误。到目前为此，由于我们是在源代码的当前路径下编译，因此，不会出现classpath设置有误的问题。<BR><BR>9. 在命令行窗口中输入<BR><BR>java Hello<BR><BR>屏幕出现了<BR><BR>Hello world<BR><BR>成功了，我们已经顺利地编译及运行了第一个Java程序。<BR>但是，第8步及第9步是不完美的，因为我们是在JavaTest这个存放源码的文件夹中进行编译及运行的，因此，一些非常重要的问题并没有暴露出来。实际上，第8步的“javac Hello.java”及第9步的“java Hello”涉及到两个问题，一是操作系统如何寻找“javac”及“java”等命令，二是操作系统如何寻找“Hello.java”及“Hello.class”这些用户自己创建的文件。对于“javac”及“java”等命令，由于它们均是可执行文件，操作系统就会依据我们在第6步中设置好的Path路径中去寻找。而对于“Hello.java”及“Hello.class”这些文件，Path的设置不起作用。由于我们是在当前工作路径中工作，java及javac会在当前工作路径中寻找相应的java文件(class文件的寻找比较特殊，详见第11步)，<BR>因此一切正常。下面我们开始人为地将问题复杂化，在非当前工作路径中编译及运行，看看结果如何。<BR><BR>10. 在命令行窗口中输入<BR><BR>cd C:\<BR>转入到C盘根目录上，当前路径离开了存放源码的工作区。输入<BR><BR>javac Hello.java<BR><BR>屏幕出现：<BR><BR>error: cannot read: Hello.java<BR>1 error<BR><BR>找不到Hello.java了。我们要给它指定一个路径，告诉它到C:\JavaTest去找Hello.java文件。输入<BR><BR>javac C:\JavaTest\Hello.java<BR><BR>OK，这回不报错了，编译成功。<BR><BR>11. 输入<BR><BR>java C:\JavaTest\Hello<BR><BR>这回屏幕出现：<BR><BR>Exception in thread "main" java.lang.NoClassDefFoundError: C:\JavaTest\Hello<BR><BR>意思为在“C:\JavaTest\Hello”找不到类的定义。明明C:\JavaTest\Hello是一个.class文件，为什么就找不到呢？原来，Java对待.java文件与.class文件是有区别的。对.java文件可以直接指定路径给它，而java命令所需的.class文件不能出现扩展名，也不能指定额外的路径给它。<BR><BR>那么，如何指定路径呢？对于Java所需的.class文件，必须通过classpath来指定。<BR><BR>12. 依照第5步，弹出“环境变量”窗口，在用户变量中新建一个变量，变量名为“classpath”，变量值为"C:\JavaTest"。一路按“确定”退出。关闭原命令行窗口，打开新的命令行窗口，输入<BR><BR>java Hello<BR><BR>“Hello world”出来了。由此可见，在“环境变量”窗口中设置classpath的目的就是告诉JDK，到哪里去寻找.class文件。这种方法一旦设置好，以后每次运行java或javac时，在需要调用.class文件时，JDK都会自动地来到这里寻找。因此，这是一个全局性的设置。<BR><BR>13. 除了这种在环境变量”窗口中设置classpath的方法之外，还有另一种方法，即在java命令后面加上一个选项classpath，紧跟着不带扩展名的class文件名。例如，<BR><BR>java -classpath C:\JavaTest Hello<BR><BR>JDK遇到这种情况时，先根据命令行中的classpath选项中指定的路径去寻找.class文件，找不到时再到全局的classpath环境变量中去寻找。这种情况下，即使是没有设置全局的classpath环境变量，由于已经在命令行中正确地指定类路径，也可以运行。<BR><BR>为了在下面的例子中更好地演示classpath的问题，我们先将全局的classpath环境变量删除，而在必要时代之以命令行选项-classpath。弹出“环境变量”窗口，选中“classpath”的变量名，按“删除”键。<BR><BR>此外，java命令中还可以用cp，即classpath的缩写来代替classpath，如java -cp C:\JavaTest Hello。特别注意的是，JDK 1.5.0之前，javac命令不能用cp来代替classpath，而只能用classpath。而在JDK 1.5.0中，java及javac都可以使用cp及classpath。因此，为保持一致，建议一概使用classpath作为选项名称。<BR><BR>14. 我们再次人为地复杂化问题。关闭正在编辑Hello.java的记事本，然后将JavaTest文件夹名称改为带空格的“Java Test”。在命令行中输入<BR><BR>javac C:\Java Test\Hello.java<BR><BR>长长的洋文又出来了，但这回却是报错了：<BR><BR>javac: invalid flag: C:\Java<BR><BR>JDK将带有空格的C:\Java Test分隔为两部分"C:\Java"及"Test\Hello.java"，并将C:\Java视作为一个无效的选项了。这种情况下，我们需要将整个路径都加上双引号，即<BR><BR>javac "C:\Java Test\Hello.java"<BR><BR>这回JDK知道，引号里面的是一个完整的路径，因此就不会报错了。同样，对java命令也需要如此，即<BR><BR>java -classpath "C:\Java Test" Hello<BR><BR>对于长文件名及中文的文件夹，XP下面可以不加双引号。但一般来说，加双引号不容易出错，也容易理解，因此，建议在classpath选项中使用双引号。<BR><BR>15. 我们再来看.java文件使用了其他类的情况。在C:\Java Test中新建一个Person.java文件，内容如下：<BR><BR>public class Person {<BR>private String name;<BR><BR>public Person(String name) {<BR>this.name = name;<BR>}<BR><BR>public String getName() {<BR>return name;<BR>}<BR>}<BR><BR>然后，修改Hello.java，内容如下：<BR><BR>public class Hello {<BR>public static void main(String[] args) {<BR>Person person = new Person("Mike");<BR>System.out.println(person.getName());<BR>}<BR>}<BR><BR>在命令行输入<BR><BR>javac "C:\Java Test\Hello.java"<BR><BR>错误来了：<BR><BR>C:\Java Test\Hello.java:3: cannot find symbol<BR>symbol: class Person<BR><BR>JDK提示找不到Person类。为什么javac "C:\Java Test\Hello.java"在第14步中可行，而在这里却不行了呢？第14步中的Hello.java文件并没有用来其他类，因此，JDK不需要去寻找其他类，而到了这里，我们修改了Hello.java，让其使用了一个Person类。根据第11步，我们需要告诉JDK，到哪里去找所用到的类，即使这个被使用的类就与Hello.java一起，同在C:\Java Test下面！输入<BR><BR>javac -classpath "C:\Java Test" "C:\Java Test\Hello.java"<BR><BR>编译通过，JDK在C:\Java Test文件夹下同时生成了Hello.class及Person.class两个文件。实际上，由于Hello.java使用了Person.java类，JDK先编译生成了Person.class，然后再编译生成Hello.class。因此，不管Hello.java这个主类使用了多少个其他类，只要编译这个类，JDK就会自动编译其他类，很方便。输入<BR><BR>java -classpath "C:\Java Test" Hello<BR><BR>屏幕出现了<BR><BR>Mike<BR><BR>成功。<BR><BR>16. 第15步说明了在Hello.java中如何使用一个我们自己创建的Person.java，而且这个类与Hello.java是同在一个文件夹下。在这一步中，我们将考查Person.java如果放在不同文件夹下面的情况。<BR><BR>先将C:\Java Test文件夹下的Person.class文件删除，然后在C:\Java Test文件夹下新建一个名为DF的文件夹，并将C:\Java Test文件夹下的Person.java移动到其下面。在命令行输入<BR><BR>javac -classpath "C:\Java Test\DF" "C:\Java Test\Hello.java"<BR><BR>编译通过。这时javac命令没有什么不同，只需将classpath改成C:\Java Test\DF就行了。<BR><BR>在命令行输入<BR><BR>java -classpath "C:\Java Test" Hello<BR><BR>这时由于Java需要找在不同文件夹下的两个.class文件，而命令行中只告诉JDK一个路径，即C:\Java Test，在此文件夹下，只能找到Hello.class，找不到Person.class文件，因此，错误是可以预料得到的：<BR><BR>Exception in thread "main" java.lang.NoClassDefFoundError: Person<BR>at Hello.main(Hello.java:3)<BR><BR>果真找不到Person.class。在设置两个以上的classpath时，先将每个路径以双引号引起来，再将这些路径以“;”号隔开，并且每个路径与“;”之间不能带有空格。因此，我们在命令行重新输入：<BR><BR>java -classpath "C:\Java Test";"C:\Java Test\DF" Hello<BR><BR>编译成功。但也暴露出一个问题，如果我们需要用到许多分处于不同文件夹下的类，那这个classpath的设置岂不是很长！有没有办法，对于一个文件夹下的所有.class文件，只指定这个文件夹的classpath，然后让JDK自动搜索此文件夹下面所有相应的路径？有，只要使用package。<BR><BR>17. package简介。Java中引入package的概念，主要是为了解决命名冲突的问题。比如说，在我们的例子中，我们设计了一个很简单的Person类，如果某人开发了一个类库，其中恰巧也有一个Person类，当我们使用这个类库时，两个Person类出现了命名冲突，JDK不知道我们到底要使用哪个Person类。更有甚者，当我们也开发了一个很庞大的类库，无可避免地，我们的类库中与其他人开发的类库中命名冲突的情况就会越来越多。总不能为了避免自己的类名与其他人开发的类名相同，而让每个编程人员都绞尽脑汁地将一个本应叫Writer的类强行改名为SarkuyaWriter，MikeWriter, SmithWriter吧？<BR><BR>现实生活中也是如此。假如你名叫张三，又假如与你同一单位的人中有好几个都叫张三，那你的问题就来了。某天单位领导在会上宣布，张三被任命为办公室主任，你简直不知道是该哭还是该笑。但如果你的单位中只有你叫张三，你才不会在乎全国叫张三的人有多少个，因为其他张三都分布在全国各地、其他城市，你看不见他们，摸不着他们，自然不会担心。<BR><BR>Sun从这个“张三问题”受到了很大的启发，为解决命名冲突问题，就采取了“眼不见心不烦”的策略：将每个类都归属到一个特定的区域中，在同一个区域中的所有类，都不允许同名；而不同区域的类，由于相互看不到，则允许有同名的类存在。这样，就解决了命名冲突的问题，正如北京的张三与上海的张三毕竟不是同一人。这个区域在Java中就叫package。由于package在Java中非常重要，如果你没有定义自己的package，JDK将会你的类都归到一个默认的无名package中。<BR><BR>自定义package的名称可以由各个程序员自由创建。作为避免命名冲突的手段，package的名称最好足以与其他程序员的区别开来。在互联网上，每个域名都是唯一的，因此，Sun推荐将你自己的域名倒写后作为package的名称。如果你没有自己的域名，很可能只是因为囊中羞涩而不去申请罢了，并不见得你假想的域名与其他域名发生冲突。例如，笔者假想的域名是sarkuya.com，目前就是唯一的，因此我的package就可以定名为com.sarkuya。谢谢Java给了我们一个免费使用我们自己域名的机会，唯一的前提是倒着写。当然，每个package下面还可以带有不同的子package，如com.sarkuya.util，com.sarkuya.swing，等等。<BR><BR>定义package的方式是在相应的.java文件的第一行加上“package packagename;”的字样，而且每个.java文件只能有一个package。实际上，Java中的package的实现是与计算机文件系统相结合的，即你有什么样的package，在硬盘上就有什么样的存放路径。例如，某个类的package名为com.sarkuya.util，那么，这个类就应该必须存放在com/sarkuya/util的路径下面。至于这个com/sarkuya/util又是哪个文件夹的子路径，第18步会谈到。<BR><BR>package除了有避免命名冲突的问题外，还引申出一个保护当前package下所有类文件的功能，主要通过为类定义几种可视度不同的修饰符来实现：public, protected, private, 另外加上一个并不真实存在的friendly类型。<BR><BR>对于冠以public的类、类属变量及方法，包内及包外的任何类均可以访问；<BR>protected的类、类属变量及方法，包内的任何类，及包外的那些继承了此类的子类才能访问；<BR>private的类、类属变量及方法，包内包外的任何类均不能访问；<BR>如果一个类、类属变量及方法不以这三种修饰符来修饰，它就是friendly类型的，那么包内的任何类都可以访问它，而包外的任何类都不能访问它(包括包外继承了此类的子类)，因此，这种类、类属变量及方法对包内的其他类是友好的，开放的，而对包外的其他类是关闭的。<BR><BR>前面说过，package主要是为了解决命名冲突的问题，因此，处在不同的包里面的类根本不用担心与其他包的类名发生冲突，因为JDK在默认情况下只使用本包下面的类，对于其他包，JDK一概视而不见：“眼不见心不烦”。如果要引用其他包的类，就必须通过import来引入其他包中相应的类。只有在这时，JDK才会进行进一步的审查，即根据其他包中的这些类、类属变量及方法的可视度来审查是否符合使用要求。如果此审查通不过，编译就此卡住，直至你放弃使用这些类、类属变量及方法，或者将被引入的类、类属变量及方法的修饰符改为符合要求为止。如果此审查通过，JDK最后进行命名是否冲突的审查。如果发现命名冲突，你可以通过在代码中引用全名的方式来显式地引用相应的类，如使用<BR><BR>java.util.Date date = new java.util.Date();<BR><BR>或是<BR><BR>java.sql.Date date = new java.sql.Date();<BR><BR>package的第三大作用是简化classpath的设置。还记得第16步中的障碍吗？这里重新引用其java命令：<BR><BR>java -classpath "C:\Java Test";"C:\Java Test\DF" Hello<BR><BR>我们必须将所有的.class文件的路径一一告诉JDK，而不管DF其实就是C:\Java Test的子目录。如果要用到100个不同路径的.class文件，我们就得将classpath设置为一个特别长的字符串，很累。package的引入，很好地解决了这个问题。package的与classpath相结合，通过import指令为中介，将原来必须由classpath完成的类路径搜索功能，很巧妙地转移到import的身上，从而使classpath的设置简洁明了。我们先看下面的例子。<BR><BR>18. 先在Hello.java中导入DF.Person。代码修改如下：<BR><BR>import DF.Person;<BR><BR>public class Hello {<BR>public static void main(String[] args) {<BR>Person person = new Person("Mike");<BR>System.out.println(person.getName());<BR>}<BR>}<BR><BR>再将DF子文件夹中的Person.java设置一个DF包。代码修改如下：<BR><BR>package DF;<BR><BR>public class Person {<BR>private String name;<BR>public Person(String name) {<BR>this.name = name;<BR>}<BR><BR>public String getName() {<BR>return name;<BR>}<BR>}<BR><BR>好了，神奇的命令行出现了：<BR><BR>javac -classpath "C:\Java Test" "C:\Java Test\Hello.java"<BR>java -classpath "C:\Java Test" Hello<BR><BR>尽管这次我们只设置了C:\Java Test的classpath，但编译及运行居然都通过了！事实上，Java在搜索.class文件时，共有三种方法：<BR>一是全局性的设置，详见第12步，其优点是一次设置，每次使用；<BR>二是在每次的javac及java命令行中自行设置classpath，这也是本文使用最多的一种方式，其优点是不加重系统环境变量的负担；<BR>三是根据import指令，将其内容在后台转换为classpath。JDK将读取全局的环境变量classpath及命令行中的classpath选项信息，然后将每条classpath与经过转换为路径形式的import的内容相合并，从而形成最终的classpath. 在我们的例子中，JDK读取全局的环境变量classpath及命令行中的classpath选项信息，得到C:\Java Test。接着，将import DF.Person中的内容，即DF.Person转换为DF\Person, 然后将C:\Java Test与其合并，成为C:\Java Test\DF\Person，这就是我们所需要的Person.class的路径。在Hello.java中有多少条import语句，就自动进行多少次这样的转换。而我们在命令行中只需告诉JDK最顶层的classpath就行了，剩下的则由各个类中的import指令代为操劳了。这种移花接木的作法为我们在命令行中手工地设置classpath提供了极大的便利。<BR><BR>应注意的一点是，import指令是与package配套使用的，只有在某类通过“package pacakgename;”设定了包名后，才能给其他类通过import指令导入。如果import试图导入一个尚未设置包的类，JVM就会报错。<BR><BR>19. 我们接下来看，当使用JDK类库时，classpath如何设置。<BR><BR>20. 修改Hello.java，内容如下：<BR><BR>import DF.Person;<BR>import java.util.Date;<BR><BR>public class Hello {<BR>public static void main(String[] args) {<BR>Date date = new Date();<BR>System.out.println(date);<BR><BR>Person person = new Person("Mike");<BR>System.out.println(person.getName());<BR>}<BR>}<BR><BR>21. JDK类库存放于C:\Program Files\Java\jdk1.5.0\jre\lib\rt.jar文件中。关于jar文件的介绍，已经超出了本文的范围，感兴趣的读者可以阅读Horstmann写的Core Java一书。<BR><BR>jar文件可以用WinRar打开。用WinRar打开后，可以看到里面有一些文件夹，双击其中的java文件夹，再双击util的文件夹，可以在看到Date.class文件就在其中。如果你看过Data.java或其他JDK类库的源码(在C:\Program Files\Java\jdk1.5.0\src.zip文件中)，你就会发现，像java、util这些文件夹均是package。这也是Hello.java第2行中使用了import指令的原因。<BR><BR>我们可以通过WinRar的查找功能来定位某个类所在的包。在“查找文件”的窗口中的“要查找的文件名”文本框中输入Date.class，就会查找出在rt.jar文件中存在两个Date.class文件，一个是java\sql\Date.class，另一个是java\util\Date.class。其中，sql下面的Date.class文件与数据库有关，并非我们这里所需，java\util\Date.class才是我们所要的。<BR><BR>rt.jar文件就像本文中的C:\Java Test中一样，是JDK类库的唯一入口。我们可以在命令行的classpath选项指定.jar文件。需要注意，.jar文件的classpath设置有些特珠。在以前的例子中，我们设置classpath时都是设置了路径就行了，而对于.jar文件，我们必须将.jar文件名直接加到classpath中。<BR><BR>22. 在命令行输入<BR><BR>javac -classpath "C:\Program Files\Java\jdk1.5.0\jre\lib\rt.jar";"C:\Java Test" "C:\Java Test\Hello.java"<BR>java -classpath "C:\Program Files\Java\jdk1.5.0\jre\lib\rt.jar";"C:\Java Test" Hello<BR><BR>这样当然没有问题，因为我们指定了rt.jar文件及C:\Java Test两个classpath。但且慢，在命令行输入：<BR><BR>javac -classpath "C:\Java Test" "C:\Java Test\Hello.java"<BR>java -classpath "C:\Java Test" Hello<BR><BR>不可思议的是，编译及运行成功了！令人惊讶的是在我们将classspath只设置为C:\Java Test的情况下，JDK如何得出java.util.Date的classpath？<BR><BR>原因在于，就像java的Path路径已经悄悄在后台设置好一样，rt.jar的classpath路径也悄悄地在后台设置了。因此，我们不必多此一举手工设置其classpath了。<BR><BR>23. 最后一点需要谈到的是，如果主类恰好也在一个package中(在大型的开发中，其实这才是一种最常见的现象)，那么java命令行的类名前面就必须加上包名。<BR><BR>在C:\Java Test下面新建一个文件夹，名为NF。将C:\Java Test下面的Hello.class删除，将Hello.java移到NF文件夹下。打开NF文件夹下的Hello.java，为其设置package属性。<BR><BR>package NF;<BR><BR>import DF.Person;<BR>import java.util.Date;<BR><BR>public class Hello {<BR>public static void main(String[] args) {<BR>Date date = new Date();<BR>System.out.println(date);<BR><BR>Person person = new Person("Mike");<BR>System.out.println(person.getName());<BR>}<BR>}<BR><BR>编译与以前没啥区别，只不过是修正一下改过之后的路径。<BR><BR>javac -classpath "C:\Java Test" "C:\Java Test\NF\Hello.java"<BR><BR>而java命令行却有了变化<BR><BR>java -classpath "C:\Java Test" NF.Hello<BR><BR>上面命令行语句中，NF.Hello告诉JDK，Hello.class在NF的package下面。<BR><BR>至此，本文有关classpath及package的问题的讨论已经全部结束。由此可见，Java的入门的确非常不易。如果初学Java的程序员一见到Java的编译竟是如此的复杂，多半就会抽身而退。因此，笔者认为，Sun在J2SE的Tutorial中故意将编译的问题尽量简单化，以吸引更多的Java初学者。一旦品尝了Java的香醇可口的美味后，就不用担心他们退出了，因为咖啡是非常容易让人上瘾的。</P>
<P class=postfeedback><A class=permalink title=此blog条目的永久链接 href="http://blog.matrix.org.cn/page/Sarkuya?entry=%E8%B7%A8%E8%BF%9Bjava%E7%9A%84%E9%97%A8%E7%A5%A8_%E5%AE%9E%E4%BE%8B%E8%AF%A6%E8%A7%A3classpath%E5%8F%8Apackage"><FONT color=#5c6c7d>Permalink</FONT></A> <A class=commentslink href="http://blog.matrix.org.cn/page/Sarkuya?entry=%E8%B7%A8%E8%BF%9Bjava%E7%9A%84%E9%97%A8%E7%A5%A8_%E5%AE%9E%E4%BE%8B%E8%AF%A6%E8%A7%A3classpath%E5%8F%8Apackage"><FONT color=#5c6c7d>留言 [1]</FONT></A> </P></DIV>
<DIV class=trackbackUrl>反向跟踪 URL: http://blog.matrix.org.cn/trackback/Sarkuya/Weblog/%E8%B7%A8%E8%BF%9Bjava%E7%9A%84%E9%97%A8%E7%A5%A8_%E5%AE%9E%E4%BE%8B%E8%AF%A6%E8%A7%A3classpath%E5%8F%8Apackage </DIV><img src ="http://www.blogjava.net/ahwen/aggbug/33358.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/ahwen/" target="_blank">ahwen</a> 2006-03-03 09:29 <a href="http://www.blogjava.net/ahwen/articles/33358.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>一个使用Proxy的简单例子</title><link>http://www.blogjava.net/ahwen/articles/33346.html</link><dc:creator>ahwen</dc:creator><author>ahwen</author><pubDate>Fri, 03 Mar 2006 00:49:00 GMT</pubDate><guid>http://www.blogjava.net/ahwen/articles/33346.html</guid><wfw:comment>http://www.blogjava.net/ahwen/comments/33346.html</wfw:comment><comments>http://www.blogjava.net/ahwen/articles/33346.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/ahwen/comments/commentRss/33346.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/ahwen/services/trackbacks/33346.html</trackback:ping><description><![CDATA[<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US>Java</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">反射包中的</SPAN><SPAN lang=EN-US>Proxy</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">类通过创建一个类的代理，让我们轻松地拦截该类实例的方法，甚至可以改变方法的行为。下面是使用</SPAN><SPAN lang=EN-US>Proxy</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">的一个简单例子。</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US><?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /><o:p>&nbsp;</o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">主要有</SPAN><SPAN lang=EN-US>4</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">步：</SPAN></P>
<OL style="MARGIN-TOP: 0cm" type=1>
<LI class=MsoNormal style="MARGIN: 0cm 0cm 0pt; mso-list: l1 level1 lfo1; tab-stops: list 36.0pt"><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">定义接口</SPAN> 
<LI class=MsoNormal style="MARGIN: 0cm 0cm 0pt; mso-list: l1 level1 lfo1; tab-stops: list 36.0pt"><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">实现接口</SPAN> 
<LI class=MsoNormal style="MARGIN: 0cm 0cm 0pt; mso-list: l1 level1 lfo1; tab-stops: list 36.0pt"><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">定义拦截处理器</SPAN> 
<LI class=MsoNormal style="MARGIN: 0cm 0cm 0pt; mso-list: l1 level1 lfo1; tab-stops: list 36.0pt"><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">创建代理对象</SPAN></LI></OL>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US><o:p>&nbsp;</o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 18pt; TEXT-INDENT: -18pt; mso-list: l0 level1 lfo2; tab-stops: list 18.0pt"><B style="mso-bidi-font-weight: normal"><SPAN lang=EN-US style="mso-fareast-font-family: 'Times New Roman'"><SPAN style="mso-list: Ignore">1.<SPAN style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></SPAN></SPAN></B><B style="mso-bidi-font-weight: normal"><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">定义接口</SPAN><SPAN lang=EN-US><o:p></o:p></SPAN></B></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US>public interface Student {</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </SPAN>public void study();</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US>}</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US><o:p>&nbsp;</o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 18pt; TEXT-INDENT: -18pt; mso-list: l0 level1 lfo2; tab-stops: list 18.0pt"><B style="mso-bidi-font-weight: normal"><SPAN lang=EN-US style="mso-fareast-font-family: 'Times New Roman'"><SPAN style="mso-list: Ignore">2.<SPAN style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></SPAN></SPAN></B><B style="mso-bidi-font-weight: normal"><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">实现接口</SPAN><SPAN lang=EN-US><o:p></o:p></SPAN></B></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US>public class StudentImpl implements Student {</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </SPAN>public void study() {</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>System.out.println("I'm studying.");</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </SPAN>}</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US>}</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US><o:p>&nbsp;</o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 18pt; TEXT-INDENT: -18pt; mso-list: l0 level1 lfo2; tab-stops: list 18.0pt"><B style="mso-bidi-font-weight: normal"><SPAN lang=EN-US style="mso-fareast-font-family: 'Times New Roman'"><SPAN style="mso-list: Ignore">3.<SPAN style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></SPAN></SPAN></B><B style="mso-bidi-font-weight: normal"><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">定义拦截处理器</SPAN><SPAN lang=EN-US><o:p></o:p></SPAN></B></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US>import java.lang.reflect.InvocationHandler;</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US>import java.lang.reflect.Method;</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US><o:p>&nbsp;</o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US>public class StudentInvocationHandler implements InvocationHandler {</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US><SPAN style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>//</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">一般来讲，</SPAN><SPAN lang=EN-US>handler</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">需要负责持有被代理对象的引用</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </SPAN>private Student target;</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </SPAN></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </SPAN>/** Creates a new instance of MyHandler */</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </SPAN>public StudentInvocationHandler(Student target) {</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>this.target = target;</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </SPAN>}</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US><o:p>&nbsp;</o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </SPAN>public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>System.out.println("adding somthing before the method " + method.getName());</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>method.invoke(target, args);</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>System.out.println("adding somthing after the method " + method.getName());</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>return null;</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </SPAN>}</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </SPAN></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US>}</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US><o:p>&nbsp;</o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 18pt; TEXT-INDENT: -18pt; mso-list: l0 level1 lfo2; tab-stops: list 18.0pt"><B style="mso-bidi-font-weight: normal"><SPAN lang=EN-US style="mso-fareast-font-family: 'Times New Roman'"><SPAN style="mso-list: Ignore">4.<SPAN style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></SPAN></SPAN></B><B style="mso-bidi-font-weight: normal"><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">创建代理对象</SPAN><SPAN lang=EN-US><o:p></o:p></SPAN></B></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US>public class ProxyTest {</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </SPAN>public static void main(String[] args) {</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>Student student = (Student) Proxy.newProxyInstance(Student.class.getClassLoader(),</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>new Class[] { Student.class },<SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>//</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">必须为接口</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN>new StudentInvocationHandler(new StudentImpl()));<SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>//</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">传进被代理对象</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>student.study();</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </SPAN>}</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US>}</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US><o:p>&nbsp;</o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US>Proxy</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">通过静态方法</SPAN><SPAN lang=EN-US>newProxyInstance</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">为我们创建了一个</SPAN><SPAN lang=EN-US>student</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">的代理类，当调用此类实例的方法时，</SPAN><SPAN lang=EN-US>StudentInvocationHandler</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">进行了拦截，并在调用其</SPAN><SPAN lang=EN-US>study()</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">方法之前与之后分别输出了一行字。</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US><o:p>&nbsp;</o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">而对于用户代码来讲，其只是要求调用</SPAN><SPAN lang=EN-US>student</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">的</SPAN><SPAN lang=EN-US>study()</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">方法，根本不知道此方法已被拦截，甚至不知道此方法已被修改。如果更彻底，通过以下的工厂方法来产生一个</SPAN><SPAN lang=EN-US>student</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">，那么用户就不会怀疑所返回的</SPAN><SPAN lang=EN-US>student</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">竟然不会他所要的</SPAN><SPAN lang=EN-US>:</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US><o:p>&nbsp;</o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US>Student student = StudentFactory.getStudent();</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US><o:p>&nbsp;</o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">工厂类：</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US>public class StudentFactory() {</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US><SPAN style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>public static Student getStudent() {</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 31.5pt; mso-para-margin-left: 3.0gd"><SPAN lang=EN-US>return (Student) Proxy.newProxyInstance(Student.class.getClassLoader(),</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>new Class[] { Student.class },</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>new StudentInvocationHandler(new StudentImpl()));</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US><SPAN style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>}</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US>}</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US><o:p>&nbsp;</o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">我想到了一个场景：我让我的男秘书帮我去把我相中的姑娘带回来，而实际上，他带给我的却是她的孪生妹妹。以后的事实证明，我爱的姑娘跟他私奔了！</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US><o:p>&nbsp;</o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US><o:p>&nbsp;</o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'"><STRONG>结论</STRONG>：</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">因此，通过</SPAN><SPAN lang=EN-US>Proxy</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">，我们可以在运行时动态地改变类的行为。而活用工厂模式，将产生一个类实例的时间从编译时延缓到运行时，将使我们的类更加灵活。</SPAN></P><img src ="http://www.blogjava.net/ahwen/aggbug/33346.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/ahwen/" target="_blank">ahwen</a> 2006-03-03 08:49 <a href="http://www.blogjava.net/ahwen/articles/33346.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>