<?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-JavaCode--我爱你,芳儿-随笔分类-JavaBaseFiles</title><link>http://www.blogjava.net/yjjlovewjf/category/27837.html</link><description>JavaStudy--我爱你,芳儿</description><language>zh-cn</language><lastBuildDate>Thu, 03 Jan 2008 20:26:35 GMT</lastBuildDate><pubDate>Thu, 03 Jan 2008 20:26:35 GMT</pubDate><ttl>60</ttl><item><title>Java中的易混问题收集 --转</title><link>http://www.blogjava.net/yjjlovewjf/archive/2008/01/03/172609.html</link><dc:creator>wǒ愛伱--咾婆 </dc:creator><author>wǒ愛伱--咾婆 </author><pubDate>Thu, 03 Jan 2008 15:40:00 GMT</pubDate><guid>http://www.blogjava.net/yjjlovewjf/archive/2008/01/03/172609.html</guid><wfw:comment>http://www.blogjava.net/yjjlovewjf/comments/172609.html</wfw:comment><comments>http://www.blogjava.net/yjjlovewjf/archive/2008/01/03/172609.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/yjjlovewjf/comments/commentRss/172609.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yjjlovewjf/services/trackbacks/172609.html</trackback:ping><description><![CDATA[<br />
<font color="red">第一，final, finally, finalize的区别.</font><br />
<br />
final 修饰符（关键字）如果一个类被声明为final，意味着它不能再派生出新的子类，不能作为父类被继承。因此一个类不能既被声明为 abstract的，又被声明为final的。将变量或方法声明为final，<strong></strong>可以保证它们在使用中不被改变。被声明为final的变量必须在声明时给定初值，而在以后的引用中只能读取，不可修改。被声明为final的方法也同样只能使用，不能重载 <br />
<br />
finally 再异常处理时提供 finally 块来执行任何清除操作。如果抛出一个异常，那么相匹配的 catch 子句就会执行，然后控制就会进入 finally 块（如果有的话）。 <br />
finalize 方法名。Java 技术允许使用 finalize() 方法在垃圾收集器将对象从内存中清除出去之前做必要的清理工作。这个方法是由垃圾收集器在确定这个对象没有被引用时对这个对象调用的。它是在 Object 类中定义的，因此所有的类都继承了它。子类覆盖 finalize() 方法以整理系统资源或者执行其他清理工作。finalize() 方法是在垃圾收集器删除对象之前对这个对象调用的。 <br />
<br />
<font color="red">第二，Anonymous Inner Class (匿名内部类) 是否可以extends(继承)其它类，是否可以implements(实现)interface(接口)? </font><br />
<br />
匿名的内部类是没有名字的内部类。不能extends(继承) 其它类，但一个内部类可以作为一个接口，由另一个内部类实现。 <br />
<br />
<font color="red">第三，Static Nested Class 和 Inner Class的不同，说得越多越好</font><br />
Nested Class （一般是C++的说法），Inner Class (一般是JAVA的说法)。Java内部类与C++嵌套类最大的不同就在于是否有指向外部的引用上。具体可见http: //www.frontfree.net/articles/services/view.asp?id=704&amp;page=1 <br />
注： 静态内部类（Inner Class）意味着1创建一个static内部类的对象，不需要一个外部类对象，2不能从一个static内部类的一个对象访问一个外部类对象 <br />
<br />
<font color="red">第四，&amp;和&amp;&amp;的区别。</font><br />
<br />
&amp;是位运算符。&amp;&amp;是布尔逻辑运算符。 <br />
<br />
<font color="red">第五，HashMap和Hashtable的区别。</font><br />
<br />
都属于Map接口的类，实现了将惟一键映射到特定的值上。 <br />
HashMap 类没有分类或者排序。它允许一个 null 键和多个 null 值。 <br />
Hashtable 类似于 HashMap，但是不允许 null 键和 null 值。它也比 HashMap 慢，因为它是同步的。 <br />
<br />
<font color="red">第六，Collection 和 Collections的区别。</font> <br />
Collections是个java.util下的类，它包含有各种有关集合操作的静态方法。 <br />
Collection是个java.util下的接口，它是各种集合结构的父接口。 <br />
<br />
<font color="red">第七，什么时候用assert。 </font><br />
断言是一个包含布尔表达式的语句，在执行这个语句时假定该表达式为 true。如果表达式计算为 false，那么系统会报告一个 Assertionerror。它用于调试目的： <br />
assert(a &gt; 0); // throws an Assertionerror if a &lt;= 0 <br />
断言可以有两种形式： <br />
assert Expression1 ; <br />
assert Expression1 : Expression2 ; <br />
Expression1 应该总是产生一个布尔值。 <br />
Expression2 可以是得出一个值的任意表达式。这个值用于生成显示更多调试信息的 String 消息。 <br />
断言在默认情况下是禁用的。要在编译时启用断言，需要使用 source 1.4 标记： <br />
javac -source 1.4 Test.java <br />
要在运行时启用断言，可使用 -enableassertions 或者 -ea 标记。 <br />
要在运行时选择禁用断言，可使用 -da 或者 -disableassertions 标记。 <br />
要系统类中启用断言，可使用 -esa 或者 -dsa 标记。还可以在包的基础上启用或者禁用断言。 <br />
可以在预计正常情况下不会到达的任何位置上放置断言。断言可以用于验证传递给私有方法的参数。不过，断言不应该用于验证传递给公有方法的参数，因为不管是否启用了断言，公有方法都必须检查其参数。不过，既可以在公有方法中，也可以在非公有方法中利用断言测试后置条件。另外，断言不应该以任何方式改变程序的状态。 <br />
<br />
<font color="red">第八，GC是什么? 为什么要有GC? (基础)。</font><br />
<br />
GC是垃圾收集器。Java 程序员不用担心内存管理，因为垃圾收集器会自动进行管理。要请求垃圾收集，可以调用下面的方法之一： <br />
System.gc() <br />
Runtime.getRuntime().gc() <br />
<br />
<font color="red">第九，String s = new String("xyz");创建了几个String Object? </font><br />
<br />
两个对象，一个是&#8220;xyx&#8221;,一个是指向&#8220;xyx&#8221;的引用对象s。 <br />
<br />
<font color="red">第十，Math.round(11.5)等於多少? Math.round(-11.5)等於多少? </font><br />
<br />
Math.round(11.5)返回（long）12，Math.round(-11.5)返回（long）-11; <br />
<br />
<font color="red">第十一，short s1 = 1; s1 = s1 + 1;有什么错? short s1 = 1; s1 += 1;有什么错? </font><br />
<br />
short s1 = 1; s1 = s1 + 1;有错，s1是short型，s1+1是int型,不能显式转化为short型。可修改为s1 =(short)(s1 + 1) 。short s1 = 1; s1 += 1正确。 <br />
<br />
<font color="red">第十二，sleep() 和 wait() 有什么区别? 搞线程的最爱 </font><br />
sleep()方法是使线程停止一段时间的方法。在sleep 时间间隔期满后，线程不一定立即恢复执行。这是因为在那个时刻，其它线程可能正在运行而且没有被调度为放弃执行，除非(a)&#8220;醒来&#8221;的线程具有更高的优先级 <br />
(b)正在运行的线程因为其它原因而阻塞。 <br />
wait()是线程交互时，如果线程对一个同步对象x 发出一个wait()调用，该线程会暂停执行，被调对象进入等待状态，直到被唤醒或等待时间到。 <br />
<br />
<font color="red">第十三，Java有没有goto? </font><br />
Goto java中的保留字，现在没有在java中使用。 <br />
<br />
<font color="red">第十四，数组有没有length()这个方法? String有没有length()这个方法？</font> <br />
<br />
数组没有length()这个方法，有length的属性。 <br />
String有有length()这个方法。 <br />
<br />
<font color="red">第十五，Overload和Override的区别。Overloaded的方法是否可以改变返回值的类型? </font><br />
<br />
方法的重写Overriding和重载Overloading是Java多态性的不同表现。重写Overriding是父类与子类之间多态性的一种表现，重载Overloading是一个类中多态性的一种表现。如果在子类中定义某方法与其父类有相同的名称和参数，我们说该方法被重写 (Overriding)。子类的对象使用这个方法时，将调用子类中的定义，对它而言，父类中的定义如同被&#8220;屏蔽&#8221;了。如果在一个类中定义了多个同名的方法，它们或有不同的参数个数或有不同的参数类型，则称为方法的重载(Overloading)。Overloaded的方法是可以改变返回值的类型。 <br />
<br />
<font color="red">第十六，Set里的元素是不能重复的，那么用什么方法来区分重复与否呢? 是用==还是equals()? 它们有何区别? </font><br />
<br />
Set里的元素是不能重复的，那么用iterator()方法来区分重复与否。equals()是判读两个Set是否相等。 <br />
equals()和==方法决定引用值是否指向同一对象equals()在类中被覆盖，为的是当两个分离的对象的内容和类型相配的话，返回真值。 <br />
<br />
<font color="red">第十七，给我一个你最常见到的runtime exception。</font> <br />
ArithmeticException, ArrayStoreException, BufferOverflowException, BufferUnderflowException, CannotRedoException, CannotUndoException, ClassCastException, CMMException, ConcurrentModificationException, DOMException, EmptyStackException, IllegalArgumentException, IllegalMonitorStateException, IllegalPathStateException, IllegalStateException, <br />
ImagingOpException, IndexOutOfBoundsException, MissingResourceException, NegativeArraySizeException, NoSuchElementException, NullPointerException, ProfileDataException, ProviderException, RasterFORMatException, SecurityException, SystemException, UndeclaredThrowableException, UnmodifiableSetException, UnsupportedOperationException&nbsp; <a href="http://www.pass4sure.com/190-802.html">190-802</a>&nbsp;<a href="http://www.pass4sure.com/000-834.html">000-834</a>&nbsp;<a href="http://www.pass4sure.com/000-861.html">000-861</a>&nbsp;<a href="http://www.pass4sure.com/117-102.html">117-102</a>&nbsp;<a href="http://www.pass4sure.com/117-301.html">117-301</a>&nbsp;<a href="http://www.pass4sure.com/190-721.html">190-721</a><br />
<br />
<font color="red">第十八，error和exception有什么区别? </font><br />
error 表示恢复不是不可能但很困难的情况下的一种严重问题。比如说内存溢出。不可能指望程序能处理这样的情况。 <br />
exception 表示一种设计或实现问题。也就是说，它表示如果程序运行正常，从不会发生的情况。 <br />
<br />
<font color="red">第十九，List, Set, Map是否继承自Collection接口? </font><br />
List，Set是 <br />
<br />
Map不是 <br />
<br />
<font color="red">第二十，abstract class和interface有什么区别? </font><br />
<br />
声明方法的存在而不去实现它的类被叫做抽象类（abstract class），它用于要创建一个体现某些基本行为的类，并为该类声明方法，但不能在该类中实现该类的情况。不能创建abstract 类的实例。然而可以创建一个变量，其类型是一个抽象类，并让它指向具体子类的一个实例。不能有抽象构造函数或抽象静态方法。Abstract 类的子类为它们父类中的所有抽象方法提供实现，否则它们也是抽象类为。取而代之，在子类中实现该方法。知道其行为的其它类可以在类中实现这些方法。 <br />
接口（interface）是抽象类的变体。在接口中，所有方法都是抽象的。多继承性可通过实现这样的接口而获得。接口中的所有方法都是抽象的，没有一个有程序体。接口只可以定义static final成员变量。接口的实现与子类相似，除了该实现类不能从接口定义中继承行为。当类实现特殊接口时，它定义（即将程序体给予）所有这种接口的方法。然后，它可以在实现了该接口的类的任何对象上调用接口的方法。由于有抽象类，它允许使用接口名作为引用变量的类型。通常的动态联编将生效。引用可以转换到接口类型或从接口类型转换，instanceof 运算符可以用来决定某对象的类是否实现了接口。 <br />
<br />
<font color="red">第二十一，abstract的method是否可同时是static,是否可同时是native，是否可同时是synchronized? </font><br />
<br />
都不能 <br />
<br />
<font color="red">第二十二，接口是否可继承接口? 抽象类是否可实现(implements)接口? 抽象类是否可继承实体类(concrete class)? </font><br />
接口可以继承接口。抽象类可以实现(implements)接口，抽象类是否可继承实体类，但前提是实体类必须有明确的构造函数。 <br />
<br />
<font color="red">第二十三，启动一个线程是用run()还是start()? </font><br />
启动一个线程是调用start()方法，使线程所代表的虚拟处理机处于可运行状态，这意味着它可以由JVM调度并执行。这并不意味着线程就会立即运行。run()方法可以产生必须退出的标志来停止一个线程。 <br />
<br />
<font color="red">第二十四，构造器Constructor是否可被override? </font>构造器Constructor不能被继承，因此不能重写Overriding，但可以被重载Overloading。 <br />
<br />
<font color="red">第二十五，是否可以继承String类? </font><br />
String类是final类故不可以继承。 <br />
<br />
<font color="red">第二十六，当一个线程进入一个对象的一个synchronized方法后，其它线程是否可进入此对象的其它方法? </font><br />
不能，一个对象的一个synchronized方法只能由一个线程访问。 <br />
<br />
<font color="red">第二十七，try {}里有一个return语句，那么紧跟在这个try后的finally {}里的code会不会被执行，什么时候被执行，在return前还是后? </font><br />
<br />
会执行，在return前执行。 <br />
<br />
<font color="red">第二十八，编程题: 用最有效率的方法算出2乘以8等於几? </font><br />
<br />
有C背景的程序员特别喜欢问这种问题。 <br />
<br />
2 &lt;&lt; 3 <br />
<br />
<font color="red">第二十九，两个对象值相同(x.equals(y) == true)，但却可有不同的hash code，这句话对不对? </font><br />
不对，有相同的hash code。 <br />
<br />
<font color="red">第三十，当一个对象被当作参数传递到一个方法后，此方法可改变这个对象的属性，并可返回变化后的结果，那么这里到底是值传递还是引用传递? </font><br />
<br />
是值传递。Java 编程语言只由值传递参数。当一个对象实例作为一个参数被传递到方法中时，参数的值就是对该对象的引用。对象的内容可以在被调用的方法中改变，但对象的引用是永远不会改变的。 <br />
<br />
<font color="red">第三十一，swtich是否能作用在byte上，是否能作用在long上，是否能作用在String上? </font><br />
<br />
switch（expr1）中，expr1是一个整数表达式。因此传递给 switch 和 case 语句的参数应该是 int、 short、 char 或者 byte。long,string 都不能作用于swtich。 <br />
<br />
<font color="red">第三十二，编程题: 写一个Singleton出来。</font><br />
<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 />
<br />
<font color="red">第三十三 Hashtable和HashMap </font><br />
Hashtable继承自Dictionary类，而HashMap是Java1.2引进的Map interface的一个实现 <br />
<br />
HashMap允许将null作为一个entry的key或者value，而Hashtable不允许 <br />
<br />
还有就是，HashMap把Hashtable的contains方法去掉了，改成containsvalue和containsKey。因为contains方法容易让人引起误<strong></strong>解。 <br />
<br />
最大的不同是，Hashtable的方法是Synchronize的，而HashMap不是，在 <br />
多个线程访问Hashtable时，不需要自己为它的方法实现同步，而HashMap <br />
就必须为之提供外同步。 <br />
<br />
Hashtable和HashMap采用的hash/rehash算法都大概一样，所以性能不会有很大的差异。
<img src ="http://www.blogjava.net/yjjlovewjf/aggbug/172609.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yjjlovewjf/" target="_blank">wǒ愛伱--咾婆 </a> 2008-01-03 23:40 <a href="http://www.blogjava.net/yjjlovewjf/archive/2008/01/03/172609.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关于static变量对于内存分配的实际验证...</title><link>http://www.blogjava.net/yjjlovewjf/archive/2007/12/20/169151.html</link><dc:creator>wǒ愛伱--咾婆 </dc:creator><author>wǒ愛伱--咾婆 </author><pubDate>Thu, 20 Dec 2007 13:07:00 GMT</pubDate><guid>http://www.blogjava.net/yjjlovewjf/archive/2007/12/20/169151.html</guid><wfw:comment>http://www.blogjava.net/yjjlovewjf/comments/169151.html</wfw:comment><comments>http://www.blogjava.net/yjjlovewjf/archive/2007/12/20/169151.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.blogjava.net/yjjlovewjf/comments/commentRss/169151.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yjjlovewjf/services/trackbacks/169151.html</trackback:ping><description><![CDATA[<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">class</span><span style="color: #000000">&nbsp;Num<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">static</span><span style="color: #000000">&nbsp;Integer&nbsp;i&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">new</span><span style="color: #000000">&nbsp;Integer(</span><span style="color: #000000">520</span><span style="color: #000000">);<br />
};</span></div>
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">class</span><span style="color: #000000">&nbsp;Demo<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">static</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">void</span><span style="color: #000000">&nbsp;main(String[]&nbsp;args)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Num&nbsp;demo1&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">new</span><span style="color: #000000">&nbsp;Num();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Num&nbsp;demo2&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">new</span><span style="color: #000000">&nbsp;Num();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">if</span><span style="color: #000000">&nbsp;(demo1.i&nbsp;</span><span style="color: #000000">==</span><span style="color: #000000">&nbsp;demo2.i)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(</span><span style="color: #000000">"</span><span style="color: #000000">ture</span><span style="color: #000000">"</span><span style="color: #000000">);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">else</span><span style="color: #000000"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(</span><span style="color: #000000">"</span><span style="color: #000000">false</span><span style="color: #000000">"</span><span style="color: #000000">);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
}<br />
<br />
</span></div>
输出为:<span style="color: red">true</span>!表明demo1.i和demo2.i只有一分存储空间.虽然new了两个对象.但只有一份存储空间!<br />
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">class</span><span style="color: #000000">&nbsp;Num<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;Integer&nbsp;i&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">new</span><span style="color: #000000">&nbsp;Integer(</span><span style="color: #000000">520</span><span style="color: #000000">);<br />
};</span></div>
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><span style="color: #000000"><br />
</span><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">class</span><span style="color: #000000">&nbsp;Demo<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">static</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">void</span><span style="color: #000000">&nbsp;main(String[]&nbsp;args)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Num&nbsp;demo1&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">new</span><span style="color: #000000">&nbsp;Num();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Num&nbsp;demo2&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">new</span><span style="color: #000000">&nbsp;Num();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">if</span><span style="color: #000000">&nbsp;(demo1.i&nbsp;</span><span style="color: #000000">==</span><span style="color: #000000">&nbsp;demo2.i)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(</span><span style="color: #000000">"</span><span style="color: #000000">ture</span><span style="color: #000000">"</span><span style="color: #000000">);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">else</span><span style="color: #000000"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(</span><span style="color: #000000">"</span><span style="color: #000000">false</span><span style="color: #000000">"</span><span style="color: #000000">);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
}<br />
<br />
</span></div>
输出为false<br />
关于static变量或方法..只会创建一份空间..无论是否有对象去引用..<br />
下面是更深入的说明!!!<br />
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">class</span><span style="color: #000000">&nbsp;Num<br />
{<br />
&nbsp;</span><span style="color: #0000ff">static</span><span style="color: #000000">&nbsp;Integer&nbsp;i&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">new</span><span style="color: #000000">&nbsp;Integer(</span><span style="color: #000000">520</span><span style="color: #000000">);<br />
&nbsp;Integer&nbsp;j&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">new</span><span style="color: #000000">&nbsp;Integer(</span><span style="color: #000000">520</span><span style="color: #000000">);<br />
}</span></div>
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><span style="color: #000000"><br />
</span><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">class</span><span style="color: #000000">&nbsp;Demo<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">static</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">void</span><span style="color: #000000">&nbsp;main(String[]&nbsp;args)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Num&nbsp;demo1&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">new</span><span style="color: #000000">&nbsp;Num();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Num&nbsp;demo2&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">new</span><span style="color: #000000">&nbsp;Num();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">if</span><span style="color: #000000">&nbsp;(demo1.i&nbsp;</span><span style="color: #000000">==</span><span style="color: #000000">&nbsp;demo2.i)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(</span><span style="color: #000000">"</span><span style="color: #000000">ture</span><span style="color: #000000">"</span><span style="color: #000000">);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">else</span><span style="color: #000000"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(</span><span style="color: #000000">"</span><span style="color: #000000">false</span><span style="color: #000000">"</span><span style="color: #000000">);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">if</span><span style="color: #000000">&nbsp;(demo1.j&nbsp;</span><span style="color: #000000">==</span><span style="color: #000000">&nbsp;demo2.j)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(</span><span style="color: #000000">"</span><span style="color: #000000">ture</span><span style="color: #000000">"</span><span style="color: #000000">);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">else</span><span style="color: #000000"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(</span><span style="color: #000000">"</span><span style="color: #000000">false</span><span style="color: #000000">"</span><span style="color: #000000">);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(Num.i);<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
}<br />
<br />
</span></div>
下面一个例子:<br />
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">class</span><span style="color: #000000">&nbsp;F1<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">static</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">void</span><span style="color: #000000">&nbsp;main(String[]&nbsp;args)<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Integer&nbsp;i&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">new</span><span style="color: #000000">&nbsp;Integer(</span><span style="color: #000000">10</span><span style="color: #000000">);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Integer&nbsp;j&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">new</span><span style="color: #000000">&nbsp;Integer(</span><span style="color: #000000">10</span><span style="color: #000000">);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;k&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">20</span><span style="color: #000000">;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;l&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">20</span><span style="color: #000000">;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(k&nbsp;</span><span style="color: #000000">==</span><span style="color: #000000">l);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(i&nbsp;</span><span style="color: #000000">==</span><span style="color: #000000">&nbsp;j);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
};</span></div>
上面的例 子表明:对于通过new创建的两个对象的引用i&amp;j,他们所引用的值都相同为10.但是,两个10存储在不同的两个地方,两个引用不同哦.....<br />
上面例 子的结果为:<br />
ture<br />
false<br />
<img src ="http://www.blogjava.net/yjjlovewjf/aggbug/169151.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yjjlovewjf/" target="_blank">wǒ愛伱--咾婆 </a> 2007-12-20 21:07 <a href="http://www.blogjava.net/yjjlovewjf/archive/2007/12/20/169151.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java初学者容易混淆的几个问题详细解析 --转</title><link>http://www.blogjava.net/yjjlovewjf/archive/2007/12/09/166449.html</link><dc:creator>wǒ愛伱--咾婆 </dc:creator><author>wǒ愛伱--咾婆 </author><pubDate>Sun, 09 Dec 2007 07:16:00 GMT</pubDate><guid>http://www.blogjava.net/yjjlovewjf/archive/2007/12/09/166449.html</guid><wfw:comment>http://www.blogjava.net/yjjlovewjf/comments/166449.html</wfw:comment><comments>http://www.blogjava.net/yjjlovewjf/archive/2007/12/09/166449.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/yjjlovewjf/comments/commentRss/166449.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yjjlovewjf/services/trackbacks/166449.html</trackback:ping><description><![CDATA[<div class="postText">１.String类和StringBuffer类 <br />
<br />
<br />
它们都是处理字符串的类,但是它们有一个最大的区别,那就是,String对象是存储你不能改动的文本字符串,相反,如果你希望改动,则应使用StringBuffer类作为替换. <br />
<br />
<br />
eg1: <br />
<br />
　　 ...... <br />
<br />
　　 //omit some code <br />
<br />
　　 String s1="You are hired!"; <br />
<br />
　　 System.out.println(s1.replace(h,f));//用f把字串中的h替换了 <br />
<br />
　　 System.out.println(s1); <br />
<br />
　　 ...... <br />
<br />
　　 //omit some code <br />
<br />
　　 运行结果: <br />
<br />
　　 You are fired! <br />
<br />
　　 You are hired! <br />
　　 结果分析: <br />
<br />
　　 从结果,明显可知,s1的值并没有被改变,而第一行结果只是屏幕内容的替换. <br />
<br />
　　 eg2: <br />
<br />
　　 ...... <br />
<br />
　　 //omit some code <br />
<br />
　　 StringBuffer s2=new StringBuffer("Hello from Java!"); <br />
<br />
　　 s2.replace(6,10,"to"); <br />
<br />
　　 System.out.println(s2); <br />
<br />
　　 ...... <br />
<br />
　　 //omit some code<br />
<br />
<br />
　　 <br />
<br />
运行结果: <br />
<br />
Hello to Java! <br />
<br />
结果分析: <br />
<br />
显然,s2的值已改变. <br />
<br />
<br />
２.位逻辑与条件逻辑 <br />
<br />
<br />
首先声明, 为了与位逻辑更好区分开来,我把通常所说的逻辑取了个别名叫做条件逻辑. <br />
<br />
<br />
它们都有各自的操作符,位逻辑操作符有:&amp;(与运算),^(异或运算),|(或运算);条件逻辑操作符有:&amp;&amp;(并且),||(或者). <br />
<br />
位逻辑运算通常是针对两个数而言,实行位操作;而条件逻辑运算是针对两个条件表达式而言,实行条件操作.其实,位逻辑操作符一样可以实现条件操作,但是此时有一个重要的区别:用位操作符时,不管操作符两边的 <br />
<br />
条件表达式成不成立,它都要通通进行运算判断,而条件逻辑操作符不一样了,如果通过左侧的操作数就可以进行它们需要的判断,那么它就不会再计算右侧的操作数了,这种情况叫短路.废话少说!且看下例. <br />
<br />
<br />
eg1: <br />
<br />
　　 ...... <br />
<br />
　　 //omit some code <br />
<br />
　　 double value=0; <br />
<br />
　　 if(value!=0 &amp;&amp; 1/value&lt;1000){ <br />
<br />
　　 System.out.println("The value is not too small."); <br />
<br />
　　 } <br />
<br />
　　 else{ <br />
<br />
　　 System.out.println("The value is too small."); <br />
<br />
　　 } <br />
<br />
　　 ...... <br />
<br />
　　 //omit some code<br />
<br />
<br />
　　 <br />
<br />
运行结果: <br />
<br />
The value is too small. <br />
<br />
结果分析: <br />
<br />
照理说应会出现除数为0的错误,但是我刚才说了,由于条件逻辑操作符是短路操作符,显然,value!=0不成立,立即就可作出判断应执行else后的语句,所以它就不再会运算判断1/value&lt;1000了.如果不懂请再看一例: <br />
<br />
<br />
eg2: <br />
<br />
　　 ...... <br />
<br />
　　 //omit some code <br />
<br />
　　 double int1=0,int2=1,int3=1; <br />
<br />
　　 if(int1!=0 &amp; (int2=2)==1){} <br />
<br />
　　 System.out.println("int2="+int2); <br />
<br />
　　 if(int1!=0 &amp;&amp; (int3=2)==1){} <br />
<br />
　　 System.out.println("int3="+int3); <br />
<br />
　　 ...... <br />
<br />
　　 //omit some code<br />
<br />
<br />
运行结果: <br />
<br />
int2=2.0 <br />
<br />
int3=1.0 <br />
<br />
结果分析: <br />
<br />
我想不用我分析了,你应该懂了吧.<br />
<br />
<br />
<br />
<br />
３.实例变量与类变量 <br />
<br />
可以通过两种方法在类中存储数据───作为实例变量和类变量.实例变量是特定于对象的,如果你有两个对象(即一个类的两个实例),每一个对象中的实例变量独立于另一个对象中的实例变量的;另一方面,两个对象的类变量均指向相同的数据,并因此面保存相同的值,换句话说,类变量被类中的所有对象共享.差点忘了,它们在形式上的区别,类变量在声明时比实例变量多一个static. <br />
<br />
<br />
eg: <br />
<br />
　　 class data <br />
<br />
　　 public int intdata=0;//显然,intdata在这儿是实例变量 <br />
<br />
　　 } <br />
<br />
　　 public class exam <br />
<br />
　　 { <br />
<br />
　　 public static void main(String[] args) <br />
<br />
　　 { <br />
<br />
　　 data a,b; <br />
<br />
　　 a=new data(); <br />
<br />
　　 b=new data(); <br />
<br />
　　 a.intdata=1; <br />
<br />
　　 System.out.println("b.indata="+b.intdata); <br />
<br />
　　 } <br />
<br />
　　 }<br />
<br />
<br />
运行结果: <br />
<br />
b.intdata=0 <br />
<br />
结果分析: <br />
<br />
可以看出,a.intdata的值虽然变了,但并没有影响b.intdata.但是如果在data类中声明intdata时,在其前面加上static就变成类变量了(即:public static int intdata=0;),则此时运行结果会变为: <br />
<br />
b.intdata=1 <br />
<br />
这次a.intdata值的改变可把b.intdata影响了,事实上,对象a和b的类变量均指向相同的数据,所有值一样,这就是类变量的作用. <br />
<br />
<br />
４.实例方法,类方法,构造器方法 <br />
<br />
<br />
我们通常所说的方法系指实例方法,就像c语言中的函数一样,其具体方法我就不用说了,在这里我主要是用它来区分类方法和构造器方法.类方法与实例方法最大的区别是:在形式上类方法多一个static,在用法上,不必创建对象就可直接调用类方法(而实例方法却一定要先创建对象,再通过对象调用). <br />
<br />
<br />
eg: <br />
<br />
　　 class add <br />
<br />
　　 { <br />
<br />
　　 static int addem(int op1,int op2) <br />
<br />
　　 { <br />
　　 return op1+op2; <br />
<br />
　　 } <br />
<br />
　　 } <br />
<br />
　　 public class xxf <br />
<br />
　　 { <br />
<br />
　　 public static void main(String[] args) <br />
<br />
　　 { <br />
<br />
　　 System.out.println("addem(2,2)="+add.addem(2,2)); <br />
<br />
　　 } //直接用类名作为对象调用类方法 <br />
<br />
　　 }<br />
<br />
<br />
　　 <br />
<br />
注: 也可按通常的方法,即先创建对象,再调用方法,不过,这时static就无任何意义了. <br />
<br />
<br />
再说说构造器方法,它是用来初始化对象中的数据的一种方法,创建很容易,只需在类中加上一个与这个类同名的方法,不需要在前面加任何访问说明符或者返回类型,另外,构造器也一样可以向方法一样传递参数. <br />
<br />
<br />
eg: <br />
<br />
　 class data <br />
<br />
　　 { <br />
<br />
　　 private String data1;//事先声明 <br />
　　 data(String s) <br />
<br />
　　 { <br />
<br />
　　 data1=s; /*通过接收数据来初始化变量.(注:不能在构造器内 <br />
<br />
　　 声明变量,事先在外就要声明.)*/ <br />
<br />
　　 } <br />
<br />
　　 public String getdata() <br />
<br />
　　 { <br />
<br />
　　 return data1; <br />
<br />
　　 } <br />
<br />
　　 } <br />
<br />
　　 public class xxf <br />
<br />
　　 { <br />
<br />
　　 public static void main(String[] args) <br />
<br />
　　 { <br />
<br />
　　 System.out.println((new data("I love you")).getdata());<br />
/*通过传递参数调用构造器新建一个对象,再通过对象调用方法得到数据*/ <br />
<br />
　　 } <br />
<br />
　　 }<br />
<br />
<br />
５.接口与类 <br />
<br />
类是对一类特定对象的规格说明,我们可以类定义创建对象,通过创建对象来组合所有属于该类的组件,而接口不能这样做.而接口实质上就是一个常量和抽象方法的集合,要使用一个接口,就需要在类中实现这个接口,然后作为类定义的一部分,编写接口中声明的每一个方法,接口中的方法永远是public,abstract,接口中的常量永远是public static和final,因此不需要为它们说明属性.因为在Java中不支持多重继承,但是,可以用接口来实现类似的功能,这是接口的重要作用之一. <br />
<br />
<br />
eg: <br />
<br />
　　 interface anyone //定义一个接口 <br />
<br />
　　 { <br />
<br />
　　 final double PI=3.1416; <br />
<br />
　　 void setNumber(int number); <br />
<br />
　　 int getNumber(); <br />
<br />
　　 } <br />
<br />
　　 interface anyother //定义另一个接口 <br />
<br />
　　 { <br />
<br />
　　 void setString(String str); <br />
<br />
　　 String getString(); <br />
<br />
　　 } <br />
<br />
　　 class xxf implement anyone,anyother //定义一个类,并使用两个接口 <br />
<br />
　　 { <br />
<br />
　　 int number; <br />
<br />
　　 String str; <br />
<br />
　　 public xxf(){} <br />
<br />
　　 void setNumber(int number) <br />
<br />
　　 { <br />
<br />
　　 this.number=number; <br />
<br />
　　 } <br />
<br />
　　 void setString(String str) <br />
<br />
　　 { <br />
<br />
　　 this.str=str; <br />
<br />
　　 } <br />
<br />
　　 void int getNumber(){}//可以为一个空实现. <br />
<br />
　　 void String getString(){} <br />
<br />
　　 }<br />
<br />
<br />
//在类中必须实现接口中声明的所有方法.(当然也可不必,但是要用到适配器类或用抽象类)<br />
</div>
<img src ="http://www.blogjava.net/yjjlovewjf/aggbug/166449.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yjjlovewjf/" target="_blank">wǒ愛伱--咾婆 </a> 2007-12-09 15:16 <a href="http://www.blogjava.net/yjjlovewjf/archive/2007/12/09/166449.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>this与super的应用 --转</title><link>http://www.blogjava.net/yjjlovewjf/archive/2007/12/09/166442.html</link><dc:creator>wǒ愛伱--咾婆 </dc:creator><author>wǒ愛伱--咾婆 </author><pubDate>Sun, 09 Dec 2007 06:50:00 GMT</pubDate><guid>http://www.blogjava.net/yjjlovewjf/archive/2007/12/09/166442.html</guid><wfw:comment>http://www.blogjava.net/yjjlovewjf/comments/166442.html</wfw:comment><comments>http://www.blogjava.net/yjjlovewjf/archive/2007/12/09/166442.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/yjjlovewjf/comments/commentRss/166442.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yjjlovewjf/services/trackbacks/166442.html</trackback:ping><description><![CDATA[<div class="postText">通过用static来定义方法或成员，为我们编程提供了某种便利，从某种程度上可以说它类似于C语言中的全局函数和全局变量。但是，并不是说有了这种便利，你便可以随处使用，如果那样的话，你便需要认真考虑一下自己是否在用面向对象的思想编程，自己的程序是否是面向对象的。好了，现在开始讨论this&amp;super这两个关键字的意义和用法。<br />
　　在Java中，this通常指当前对象，super则指父类的。当你想要引用当前对象的某种东西，比如当前对象的某个方法，或当前对象的某个成员，你便可以利用this来实现这个目的，当然，this的另一个用途是调用当前对象的另一个构造函数，这些马上就要讨论。如果你想引用父类的某种东西，则非super莫属。由于this与super有如此相似的一些特性和与生俱来的某种关系，所以我们在这一块儿来讨论，希望能帮助你区分和掌握它们两个。<br />
　　在一般方法中<br />
　　最普遍的情况就是，在你的方法中的某个形参名与当前对象的某个成员有相同的名字，这时为了不至于混淆，你便需要明确使用this关键字来指明你要使用某个成员，使用方法是&#8220;this.成员名&#8221;，而不带this的那个便是形参。另外，还可以用&#8220;this.方法名&#8221;来引用当前对象的某个方法，但这时this就不是必须的了，你可以直接用方法名来访问那个方法，编译器会知道你要调用的是那一个。下面的代码演示了上面的用法：<br />
public class DemoThis<br />
{　<br />
private String name;　<br />
private int age;　<br />
DemoThis(String name,int age){　　<br />
setName(name); <br />
//你可以加上this来调用方法，像这样：this.setName(name);但这并不是必须的　　<br />
setAge(age);　　<br />
this.print(); br&gt; }　　 <br />
public void setName(String name){　　<br />
this.name=name;//此处必须指明你要引用成员变量　<br />
} <br />
public void etAge(int age){　 <br />
this.age=age;　<br />
}　<br />
public void print(){　　<br />
System.out.println("Name="+name+" ge="+age);<br />
//在此行中并不需要用this，因为没有会导致混淆的东西　<br />
}　<br />
public static void main(String[] args){　　<br />
DemoThis dt=new DemoThis("Kevin","22");<br />
　　这段代码很简单，不用解释你也应该能看明白。在构造函数中你看到用this.print(),你完全可以用print()来代替它，两者效果一样。下面我们修改这个程序，来演示super的用法。<br />
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><span style="color: #0000ff">class</span><span style="color: #000000">&nbsp;Person<br />
{　<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;c;　<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">private</span><span style="color: #000000">&nbsp;String&nbsp;name;　<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">private</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;age;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">protected</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">void</span><span style="color: #000000">&nbsp;setName(String&nbsp;name)<br />
&nbsp;&nbsp;&nbsp;&nbsp;{　　<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">this</span><span style="color: #000000">.name</span><span style="color: #000000">=</span><span style="color: #000000">name;　<br />
&nbsp;&nbsp;&nbsp;&nbsp;}　<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">protected</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">void</span><span style="color: #000000">&nbsp;setAge(</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;age)<br />
&nbsp;&nbsp;&nbsp;&nbsp;{　&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">this</span><span style="color: #000000">.age</span><span style="color: #000000">=</span><span style="color: #000000">age;<br />
　&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">protected</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">void</span><span style="color: #000000">&nbsp;print()<br />
&nbsp;&nbsp;&nbsp;&nbsp;{　　<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(</span><span style="color: #000000">"</span><span style="color: #000000">Name=</span><span style="color: #000000">"</span><span style="color: #000000">+</span><span style="color: #000000">name</span><span style="color: #000000">+</span><span style="color: #000000">"</span><span style="color: #000000">&nbsp;Age=</span><span style="color: #000000">"</span><span style="color: #000000">+</span><span style="color: #000000">age);&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
}<br />
</span><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">class</span><span style="color: #000000">&nbsp;DemoSuper&nbsp;</span><span style="color: #0000ff">extends</span><span style="color: #000000">&nbsp;Person<br />
{　<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">void</span><span style="color: #000000">&nbsp;print()<br />
&nbsp;&nbsp;&nbsp;&nbsp;{　　<br />
&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(</span><span style="color: #000000">"</span><span style="color: #000000">DemoSuper:</span><span style="color: #000000">"</span><span style="color: #000000">);　&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">super</span><span style="color: #000000">.print();&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}　<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">static</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">void</span><span style="color: #000000">&nbsp;main(String[]&nbsp;args)<br />
&nbsp;&nbsp;&nbsp;&nbsp;{　&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DemoSuper&nbsp;ds</span><span style="color: #000000">=</span><span style="color: #0000ff">new</span><span style="color: #000000">&nbsp;DemoSuper();　&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ds.setName(</span><span style="color: #000000">"</span><span style="color: #000000">kevin</span><span style="color: #000000">"</span><span style="color: #000000">);　&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ds.setAge(</span><span style="color: #000000">22</span><span style="color: #000000">);　&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ds.print();&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
}</span></div>
<br />
　　在DemoSuper中，重新定义的print方法覆写了父类的print方法，它首先做一些自己的事情，然后调用父类的那个被覆写了的方法。输出结果说明了这一点：<br />
　　DemoSuper:<br />
Name=kevin Age=22<br />
<br />
　　这样的使用方法是比较常用的。另外如果父类的成员可以被子类访问，那你可以像使用this一样使用它，用&#8220;super.父类中的成员名&#8221;的方式，但常常你并不是这样来访问父类中的成员名的。<br />
　　在构造函数中构造函数是一种特殊的方法，在对象初始化的时候自动调用。在构造函数中，this和super也有上面说的种种使用方式，并且它还有特殊的地方，请看下面的例子：<br />
<br />
　　<br />
class Person{　<br />
<br />
public static void prt(String s){　　<br />
System.out.println(s);　<br />
}　<br />
Person(){　 <br />
prt("A Person.");　<br />
} <br />
Person(String name){　<br />
　prt("A person name is:"+name);　<br />
<br />
}<br />
}<br />
public class Chinese extends Person{<br />
　Chinese(){　　<br />
super();　//调用父类构造函数（1）　 <br />
prt("A chinese.");//(4) <br />
}　<br />
Chinese(String name){　　<br />
super(name);//调用父类具有相同形参的构造函数（2）　　<br />
prt("his name is:"+name); <br />
} <br />
Chinese(String name,int age){　　<br />
this(name);//调用当前具有相同形参的构造函数（3）　 <br />
prt("his age is:"+age); <br />
} <br />
public static void main(String[] args){　 <br />
Chinese cn=new Chinese();　　<br />
cn=new Chinese("kevin");　 <br />
cn=new Chinese("kevin",22); <br />
}<br />
}<br />
　　在这段程序中，this和super不再是像以前那样用&#8220;.&#8221;连接一个方法或成员，而是直接在其后跟<br />
　　上适当的参数，因此它的意义也就有了变化。super后加参数的是用来调用父类中具有相同形式的<br />
　　构造函数，如1和2处。this后加参数则调用的是当前具有相同参数的构造函数，如3处。当然，在<br />
　　Chinese的各个重载构造函数中，this和super在一般方法中的各种用法也仍可使用，比如4处，你<br />
　　可以将它替换为&#8220;this.prt&#8221;(因为它继承了父类中的那个方法）或者是&#8220;super.prt&#8221;（因为它<br />
　　是父类中的方法且可被子类访问），它照样可以正确运行。但这样似乎就有点画蛇添足的味道<br />
　　了。<br />
　　最后，写了这么多，如果你能对&#8220;this通常指代当前对象，super通常指代父类&#8221;这句话牢记在<br />
　　心，那么本篇便达到了目的，其它的你自会在以后的编程实践当中慢慢体会、掌握。 </div>
<img src ="http://www.blogjava.net/yjjlovewjf/aggbug/166442.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yjjlovewjf/" target="_blank">wǒ愛伱--咾婆 </a> 2007-12-09 14:50 <a href="http://www.blogjava.net/yjjlovewjf/archive/2007/12/09/166442.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>理解Java ClassLoader机制 --转</title><link>http://www.blogjava.net/yjjlovewjf/archive/2007/12/09/166418.html</link><dc:creator>wǒ愛伱--咾婆 </dc:creator><author>wǒ愛伱--咾婆 </author><pubDate>Sun, 09 Dec 2007 03:32:00 GMT</pubDate><guid>http://www.blogjava.net/yjjlovewjf/archive/2007/12/09/166418.html</guid><wfw:comment>http://www.blogjava.net/yjjlovewjf/comments/166418.html</wfw:comment><comments>http://www.blogjava.net/yjjlovewjf/archive/2007/12/09/166418.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/yjjlovewjf/comments/commentRss/166418.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yjjlovewjf/services/trackbacks/166418.html</trackback:ping><description><![CDATA[当JVM（Java虚拟机）启动时，会形成由三个类加载器组成的初始类加载器层次结构：<br />
<br />
&nbsp; &nbsp;&nbsp; &nbsp; bootstrap classloader<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; |<br />
&nbsp; &nbsp;&nbsp; &nbsp; extension classloader<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; |<br />
&nbsp; &nbsp;&nbsp; &nbsp; system classloader<br />
<br />
bootstrap classloader －引导（也称为原始）类加载器，它负责加载Java的核心类。在Sun的JVM中，在执行java的命令中使用-Xbootclasspath选项或使用 - D选项指定sun.boot.class.path系统属性值可以指定附加的类。这个加载器的是非常特殊的，它实际上不是 java.lang.ClassLoader的子类，而是由JVM自身实现的。大家可以通过执行以下代码来获得bootstrap classloader加载了那些核心类库：<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; URL[] urls = sun.misc.Launcher.getBootstrapClassPath().getURLs();<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; for (int i = 0; i &lt; urls.length; i++) {<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; System.out.println(urls[i].toExternalForm());<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br />
在我的计算机上的结果为：<br />
文件:/C:/j2sdk1.4.1_01/jre/lib/endorsed/dom.jar<br />
文件:/C:/j2sdk1.4.1_01/jre/lib/endorsed/sax.jar<br />
文件:/C:/j2sdk1.4.1_01/jre/lib/endorsed/xalan-2.3.1.jar<br />
文件:/C:/j2sdk1.4.1_01/jre/lib/endorsed/xercesImpl-2.0.0.jar<br />
文件:/C:/j2sdk1.4.1_01/jre/lib/endorsed/xml-apis.jar<br />
文件:/C:/j2sdk1.4.1_01/jre/lib/endorsed/xsltc.jar<br />
文件:/C:/j2sdk1.4.1_01/jre/lib/rt.jar<br />
文件:/C:/j2sdk1.4.1_01/jre/lib/i18n.jar<br />
文件:/C:/j2sdk1.4.1_01/jre/lib/sunrsasign.jar<br />
文件:/C:/j2sdk1.4.1_01/jre/lib/jsse.jar<br />
文件:/C:/j2sdk1.4.1_01/jre/lib/jce.jar<br />
文件:/C:/j2sdk1.4.1_01/jre/lib/charsets.jar<br />
文件:/C:/j2sdk1.4.1_01/jre/classes<br />
这时大家知道了为什么我们不需要在系统属性CLASSPATH中指定这些类库了吧，因为JVM在启动的时候就自动加载它们了。<br />
<br />
extension classloader －扩展类加载器，它负责加载JRE的扩展目录（JAVA_HOME/jre/lib/ext或者由java.ext.dirs系统属性指定的）中JAR的类包。这为引入除Java核心类以外的新功能提供了一个标准机制。因为默认的扩展目录对所有从同一个JRE中启动的JVM都是通用的，所以放入这个目录的 JAR类包对所有的JVM和system classloader都是可见的。在这个实例上调用方法getParent()总是返回空值null，因为引导加载器bootstrap classloader不是一个真正的ClassLoader实例。所以当大家执行以下代码时：<br />
&nbsp; &nbsp;System.out.println(System.getProperty("java.ext.dirs"));<br />
&nbsp; &nbsp;ClassLoader extensionClassloader=ClassLoader.getSystemClassLoader().getParent();<br />
&nbsp; &nbsp;System.out.println("the parent of extension classloader : "+extensionClassloader.getParent());<br />
结果为：<br />
C:\j2sdk1.4.1_01\jre\lib\ext<br />
the parent of extension classloader : null<br />
extension classloader是system classloader的parent，而bootstrap classloader是extension classloader的parent，但它不是一个实际的classloader，所以为null。<br />
<br />
system classloader －系统（也称为应用）类加载器，它负责在JVM被启动时，加载来自在命令java中的-classpath或者java.class.path系统属性或者 CLASSPATH*作系统属性所指定的JAR类包和类路径。总能通过静态方法ClassLoader.getSystemClassLoader()找到该类加载器。如果没有特别指定，则用户自定义的任何类加载器都将该类加载器作为它的父加载器。执行以下代码即可获得：<br />
&nbsp; &nbsp;System.out.println(System.getProperty("java.class.path"));<br />
输出结果则为用户在系统属性里面设置的CLASSPATH。<br />
classloader 加载类用的是全盘负责委托机制。所谓全盘负责，即是当一个classloader加载一个Class的时候，这个Class所依赖的和引用的所有 Class也由这个classloader负责载入，除非是显式的使用另外一个classloader载入；委托机制则是先让parent（父）类加载器 (而不是super，它与parent classloader类不是继承关系)寻找，只有在parent找不到的时候才从自己的类路径中去寻找。此外类加载还采用了cache机制，也就是如果 cache中保存了这个Class就直接返回它，如果没有才从文件中读取和转换成Class，并存入cache，这就是为什么我们修改了Class但是必须重新启动JVM才能生效的原因。<br />
<br />
每个ClassLoader加载Class的过程是：<br />
1.检测此Class是否载入过（即在cache中是否有此Class），如果有到8,如果没有到2<br />
2.如果parent classloader不存在（没有parent，那parent一定是bootstrap classloader了），到4<br />
3.请求parent classloader载入，如果成功到8，不成功到5<br />
4.请求jvm从bootstrap classloader中载入，如果成功到8<br />
5.寻找Class文件（从与此classloader相关的类路径中寻找）。如果找不到则到7.<br />
6.从文件中载入Class，到8.<br />
7.抛出ClassNotFoundException.<br />
8.返回Class.<br />
<br />
其中5.6步我们可以通过覆盖ClassLoader的findClass方法来实现自己的载入策略。甚至覆盖loadClass方法来实现自己的载入过程。<br />
<br />
类加载器的顺序是：<br />
先是bootstrap classloader，然后是extension classloader，最后才是system classloader。大家会发现加载的Class越是重要的越在靠前面。这样做的原因是出于安全性的考虑，试想如果system classloader&#8220;亲自&#8221;加载了一个具有破坏性的&#8220;java.lang.System&#8221;类的后果吧。这种委托机制保证了用户即使具有一个这样的类，也把它加入到了类路径中，但是它永远不会被载入，因为这个类总是由bootstrap classloader来加载的。大家可以执行一下以下的代码：<br />
&nbsp; &nbsp;System.out.println(System.class.getClassLoader());<br />
将会看到结果是null，这就表明java.lang.System是由bootstrap classloader加载的，因为bootstrap classloader不是一个真正的ClassLoader实例，而是由JVM实现的，正如前面已经说过的。<br />
<br />
下面就让我们来看看JVM是如何来为我们来建立类加载器的结构的：<br />
sun.misc.Launcher，顾名思义，当你执行java命令的时候，JVM会先使用bootstrap classloader载入并初始化一个Launcher，执行下来代码：<br />
&nbsp;&nbsp;System.out.println("the Launcher's classloader is "+sun.misc.Launcher.getLauncher().getClass().getClassLoader());<br />
结果为：<br />
&nbsp;&nbsp;the Launcher's classloader is null (因为是用bootstrap classloader加载,所以class loader为null)<br />
Launcher 会根据系统和命令设定初始化好class loader结构，JVM就用它来获得extension classloader和system classloader,并载入所有的需要载入的Class，最后执行java命令指定的带有静态的main方法的Class。extension classloader实际上是sun.misc.Launcher$ExtClassLoader类的一个实例，system classloader实际上是sun.misc.Launcher$AppClassLoader类的一个实例。并且都是 java.net.URLClassLoader的子类。<br />
<br />
让我们来看看Launcher初试化的过程的部分代码。<br />
<br />
Launcher的部分代码：<br />
public class Launcher&nbsp;&nbsp;{<br />
&nbsp; &nbsp;public Launcher() {<br />
&nbsp; &nbsp;&nbsp; &nbsp; ExtClassLoader extclassloader;<br />
&nbsp; &nbsp;&nbsp; &nbsp; try {<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;//初始化extension classloader<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;extclassloader = ExtClassLoader.getExtClassLoader();<br />
&nbsp; &nbsp;&nbsp; &nbsp; } catch(IOException ioexception) {<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;throw new InternalError("Could not create extension class loader");<br />
&nbsp; &nbsp;&nbsp; &nbsp; }<br />
&nbsp; &nbsp;&nbsp; &nbsp; try {<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;//初始化system classloader，parent是extension classloader<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;loader = AppClassLoader.getAppClassLoader(extclassloader);<br />
&nbsp; &nbsp;&nbsp; &nbsp; } catch(IOException ioexception1) {<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;throw new InternalError("Could not create application class loader");<br />
&nbsp; &nbsp;&nbsp; &nbsp; }<br />
&nbsp; &nbsp;&nbsp; &nbsp; //将system classloader设置成当前线程的context classloader（将在后面加以介绍）<br />
&nbsp; &nbsp;&nbsp; &nbsp; Thread.currentThread().setContextClassLoader(loader);<br />
&nbsp; &nbsp;&nbsp; &nbsp; ......<br />
&nbsp; &nbsp;}<br />
&nbsp; &nbsp;public ClassLoader getClassLoader() {<br />
&nbsp; &nbsp;&nbsp; &nbsp; //返回system classloader<br />
&nbsp; &nbsp;&nbsp; &nbsp; return loader;<br />
&nbsp; &nbsp;}<br />
}<br />
<br />
extension classloader的部分代码：<br />
static class Launcher$ExtClassLoader extends URLClassLoader {<br />
<br />
&nbsp; &nbsp;public static Launcher$ExtClassLoader getExtClassLoader()<br />
&nbsp; &nbsp;&nbsp; &nbsp; throws IOException<br />
&nbsp; &nbsp;{<br />
&nbsp; &nbsp;&nbsp; &nbsp; File afile[] = getExtDirs();<br />
&nbsp; &nbsp;&nbsp; &nbsp; return (Launcher$ExtClassLoader)AccessController.doPrivileged(new Launcher$1(afile));<br />
&nbsp; &nbsp;}<br />
&nbsp;&nbsp;private static File[] getExtDirs() {<br />
&nbsp; &nbsp;&nbsp; &nbsp; //获得系统属性&#8220;java.ext.dirs&#8221;<br />
&nbsp; &nbsp;&nbsp; &nbsp; String s = System.getProperty("java.ext.dirs");<br />
&nbsp; &nbsp;&nbsp; &nbsp; File afile[];<br />
&nbsp; &nbsp;&nbsp; &nbsp; if(s != null) {<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;StringTokenizer stringtokenizer = new StringTokenizer(s, File.pathSeparator);<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;int i = stringtokenizer.countTokens();<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;afile = new File;<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;for(int j = 0; j &lt; i; j++)<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;afile[j] = new File(stringtokenizer.nextToken());<br />
<br />
&nbsp; &nbsp;&nbsp; &nbsp; } else {<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;afile = new File[0];<br />
&nbsp; &nbsp;&nbsp; &nbsp; }<br />
&nbsp; &nbsp;&nbsp; &nbsp; return afile;<br />
&nbsp; &nbsp;}<br />
}<br />
<br />
system classloader的部分代码：<br />
static class Launcher$AppClassLoader extends URLClassLoader<br />
{<br />
<br />
&nbsp; &nbsp;public static ClassLoader getAppClassLoader(ClassLoader classloader)<br />
&nbsp; &nbsp;&nbsp; &nbsp; throws IOException<br />
&nbsp; &nbsp;{<br />
&nbsp; &nbsp;&nbsp; &nbsp; //获得系统属性&#8220;java.class.path&#8221;<br />
&nbsp; &nbsp;&nbsp; &nbsp; String s = System.getProperty("java.class.path");<br />
&nbsp; &nbsp;&nbsp; &nbsp; File afile[] = s != null ? Launcher.access$200(s) : new File[0];<br />
&nbsp; &nbsp;&nbsp; &nbsp; return (Launcher$AppClassLoader)AccessController.doPrivileged(new Launcher$2(s, afile, classloader));<br />
&nbsp; &nbsp;}<br />
}<br />
<br />
看了源代码大家就清楚了吧，extension classloader是使用系统属性&#8220;java.ext.dirs&#8221;设置类搜索路径的，并且没有parent。system classloader是使用系统属性&#8220;java.class.path&#8221;设置类搜索路径的，并且有一个parent classloader。Launcher初始化extension classloader，system classloader，并将system classloader设置成为context classloader，但是仅仅返回system classloader给JVM。<br />
<br />
　　这里怎么又出来一个context classloader呢？它有什么用呢？我们在建立一个线程Thread的时候，可以为这个线程通过setContextClassLoader方法来指定一个合适的classloader作为这个线程的context classloader，当此线程运行的时候，我们可以通过getContextClassLoader方法来获得此context classloader，就可以用它来载入我们所需要的Class。默认的是system classloader。利用这个特性，我们可以&#8220;打破&#8221;classloader委托机制了，父classloader可以获得当前线程的context classloader，而这个context classloader可以是它的子classloader或者其他的classloader，那么父classloader就可以从其获得所需的 Class，这就打破了只能向父classloader请求的限制了。这个机制可以满足当我们的classpath是在运行时才确定,并由定制的 classloader加载的时候,由system classloader(即在jvm classpath中)加载的class可以通过context classloader获得定制的classloader并加载入特定的class(通常是抽象类和接口,定制的classloader中是其实现),例如web应用中的servlet就是用这种机制加载的.<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;好了，现在我们了解了classloader的结构和工作原理，那么我们如何实现在运行时的动态载入和更新呢？只要我们能够动态改变类搜索路径和清除 classloader的cache中已经载入的Class就行了，有两个方案，一是我们继承一个classloader，覆盖loadclass方法，动态的寻找Class文件并使用defineClass方法来；另一个则非常简单实用，只要重新使用一个新的类搜索路径来new一个 classloader就行了，这样即更新了类搜索路径以便来载入新的Class，也重新生成了一个空白的cache(当然,类搜索路径不一定必须更改)。噢，太好了，我们几乎不用做什么工作，java.netURLClassLoader正是一个符合我们要求的classloader！我们可以直接使用或者继承它就可以了！<br />
<br />
这是j2se1.4 API的doc中URLClassLoader的两个构造器的描述：<br />
URLClassLoader(URL[] urls)<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;Constructs a new URLClassLoader for the specified URLs using the default delegation parent ClassLoader.<br />
URLClassLoader(URL[] urls, ClassLoader parent)<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;Constructs a new URLClassLoader for the given URLs.<br />
其中URL[] urls就是我们要设置的类搜索路径，parent就是这个classloader的parent classloader，默认的是system classloader。<br />
<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;好，现在我们能够动态的载入Class了，这样我们就可以利用newInstance方法来获得一个Object。但我们如何将此Object造型呢？可以将此Object造型成它本身的Class吗？<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;首先让我们来分析一下java源文件的编译，运行吧！javac命令是调用&#8220;JAVA_HOME/lib/tools.jar&#8221;中的&#8220;com.sun.tools.javac.Main&#8221;的compile方法来编译：<br />
<br />
&nbsp; &nbsp;public static int compile(String as[]);<br />
<br />
&nbsp; &nbsp;public static int compile(String as[], PrintWriter printwriter);<br />
<br />
返回0表示编译成功，字符串数组as则是我们用javac命令编译时的参数，以空格划分。例如：<br />
javac -classpath c:\foo\bar.jar;. -d c:\ c:\Some.java<br />
则字符串数组as为{"-classpath","c:\\foo\\bar.jar;.","-d","c:\\","c:\Some.java"}，如果带有PrintWriter参数，则会把编译信息出到这个指定的printWriter中。默认的输出是 System.err。<br />
<br />
其中 Main是由JVM使用Launcher初始化的system classloader载入的，根据全盘负责原则，编译器在解析这个java源文件时所发现的它所依赖和引用的所有Class也将由system classloader载入，如果system classloader不能载入某个Class时，编译器将抛出一个&#8220;cannot resolve symbol&#8221;错误。<br />
<br />
所以首先编译就通不过，也就是编译器无法编译一个引用了不在CLASSPATH中的未知Class的java源文件，而由于拼写错误或者没有把所需类库放到CLASSPATH中，大家一定经常看到这个&#8220;cannot resolve symbol&#8221;这个编译错误吧！<br />
<br />
其次，就是我们把这个Class放到编译路径中，成功的进行了编译，然后在运行的时候不把它放入到CLASSPATH中而利用我们自己的 classloader来动态载入这个Class，这时候也会出现&#8220;java.lang.NoClassDefFoundError&#8221;的违例，为什么呢？<br />
<br />
我们再来分析一下，首先调用这个造型语句的可执行的Class一定是由JVM使用Launcher初始化的system classloader载入的，根据全盘负责原则，当我们进行造型的时候，JVM也会使用system classloader来尝试载入这个Class来对实例进行造型，自然在system classloader寻找不到这个Class时就会抛出&#8220;java.lang.NoClassDefFoundError&#8221;的违例。<br />
<br />
OK，现在让我们来总结一下，java文件的编译和Class的载入执行，都是使用Launcher初始化的system classloader作为类载入器的，我们无法动态的改变system classloader，更无法让JVM使用我们自己的classloader来替换system classloader，根据全盘负责原则，就限制了编译和运行时，我们无法直接显式的使用一个system classloader寻找不到的Class，即我们只能使用Java核心类库，扩展类库和CLASSPATH中的类库中的Class。<br />
<br />
还不死心！再尝试一下这种情况，我们把这个Class也放入到CLASSPATH中，让system classloader能够识别和载入。然后我们通过自己的classloader来从指定的class文件中载入这个Class（不能够委托 parent载入，因为这样会被system classloader从CLASSPATH中将其载入），然后实例化一个Object，并造型成这个Class，这样JVM也识别这个Class（因为 system classloader能够定位和载入这个Class从CLASSPATH中），载入的也不是CLASSPATH中的这个Class，而是从 CLASSPATH外动态载入的，这样总行了吧！十分不幸的是，这时会出现&#8220;java.lang.ClassCastException&#8221;违例。<br />
<br />
为什么呢？我们也来分析一下，不错，我们虽然从CLASSPATH外使用我们自己的classloader动态载入了这个Class，但将它的实例造型的时候是JVM会使用system classloader来再次载入这个Class，并尝试将使用我们的自己的classloader载入的Class的一个实例造型为system classloader载入的这个Class（另外的一个）。大家发现什么问题了吗？也就是我们尝试将从一个classloader载入的Class的一个实例造型为另外一个classloader载入的Class，虽然这两个Class的名字一样，甚至是从同一个class文件中载入。但不幸的是JVM 却认为这个两个Class是不同的，即JVM认为不同的classloader载入的相同的名字的Class（即使是从同一个class文件中载入的）是不同的！这样做的原因我想大概也是主要出于安全性考虑，这样就保证所有的核心Java类都是system classloader载入的，我们无法用自己的classloader载入的相同名字的Class的实例来替换它们的实例。<br />
<br />
看到这里，聪明的读者一定想到了该如何动态载入我们的Class，实例化，造型并调用了吧！<br />
<br />
那就是利用面向对象的基本特性之一的多形性。我们把我们动态载入的Class的实例造型成它的一个system classloader所能识别的父类就行了！这是为什么呢？我们还是要再来分析一次。当我们用我们自己的classloader来动态载入这我们只要把这个Class的时候，发现它有一个父类Class，在载入它之前JVM先会载入这个父类Class，这个父类Class是system classloader所能识别的，根据委托机制，它将由system classloader载入，然后我们的classloader再载入这个Class，创建一个实例，造型为这个父类Class，注意了，造型成这个父类 Class的时候（也就是上溯）是面向对象的java语言所允许的并且JVM也支持的，JVM就使用system classloader再次载入这个父类Class，然后将此实例造型为这个父类Class。大家可以从这个过程发现这个父类Class都是由 system classloader载入的，也就是同一个class loader载入的同一个Class，所以造型的时候不会出现任何异常。而根据多形性，调用这个父类的方法时，真正执行的是这个Class（非父类 Class）的覆盖了父类方法的方法。这些方法中也可以引用system classloader不能识别的Class，因为根据全盘负责原则，只要载入这个Class的classloader即我们自己定义的 classloader能够定位和载入这些Class就行了。<br />
<br />
这样我们就可以事先定义好一组接口或者基类并放入CLASSPATH中，然后在执行的时候动态的载入实现或者继承了这些接口或基类的子类。还不明白吗？让我们来想一想Servlet吧，web application server能够载入任何继承了Servlet的Class并正确的执行它们，不管它实际的Class是什么，就是都把它们实例化成为一个Servlet Class，然后执行Servlet的init，doPost，doGet和destroy等方法的,而不管这个Servlet是从web- inf/lib和web-inf/classes下由system classloader的子classloader(即定制的classloader)动态载入。说了这么多希望大家都明白了。在applet,ejb等容器中,都是采用了这种机制.<br />
<br />
对于以上各种情况，希望大家实际编写一些example来实验一下。<br />
<br />
最后我再说点别的， classloader虽然称为类加载器，但并不意味着只能用来加载Class，我们还可以利用它也获得图片，音频文件等资源的URL，当然，这些资源必须在CLASSPATH中的jar类库中或目录下。我们来看API的doc中关于ClassLoader的两个寻找资源和Class的方法描述吧：<br />
　　　　　　　　public URL getResource(String name)<br />
　　　　　　　　用指定的名字来查找资源，一个资源是一些能够被class代码访问的在某种程度上依赖于代码位置的数据（图片，音频，文本等等）。<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;一个资源的名字是以'/'号分隔确定资源的路径名的。<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;这个方法将先请求parent classloader搜索资源，如果没有parent，则会在内置在虚拟机中的classloader（即bootstrap classloader）的路径中搜索。如果失败，这个方法将调用findResource(String)来寻找资源。<br />
　　　　　　　　public static URL getSystemResource(String name)<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;从用来载入类的搜索路径中查找一个指定名字的资源。这个方法使用system class loader来定位资源。即相当于ClassLoader.getSystemClassLoader().getResource(name)。<br />
<br />
例如：<br />
&nbsp; &nbsp;System.out.println(ClassLoader.getSystemResource("java/lang/String.class"));<br />
的结果为：<br />
&nbsp; &nbsp;jar:文件:/C:/j2sdk1.4.1_01/jre/lib/rt.jar!/java/lang/String.class<br />
表明String.class文件在rt.jar的java/lang目录中。<br />
因此我们可以将图片等资源随同Class一同打包到jar类库中（当然，也可单独打包这些资源）并添加它们到class loader的搜索路径中，我们就可以无需关心这些资源的具体位置，让class loader来帮我们寻找了！ 
<img src ="http://www.blogjava.net/yjjlovewjf/aggbug/166418.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yjjlovewjf/" target="_blank">wǒ愛伱--咾婆 </a> 2007-12-09 11:32 <a href="http://www.blogjava.net/yjjlovewjf/archive/2007/12/09/166418.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java 中的堆和栈－－转</title><link>http://www.blogjava.net/yjjlovewjf/archive/2007/12/08/166336.html</link><dc:creator>wǒ愛伱--咾婆 </dc:creator><author>wǒ愛伱--咾婆 </author><pubDate>Sat, 08 Dec 2007 13:09:00 GMT</pubDate><guid>http://www.blogjava.net/yjjlovewjf/archive/2007/12/08/166336.html</guid><wfw:comment>http://www.blogjava.net/yjjlovewjf/comments/166336.html</wfw:comment><comments>http://www.blogjava.net/yjjlovewjf/archive/2007/12/08/166336.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/yjjlovewjf/comments/commentRss/166336.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yjjlovewjf/services/trackbacks/166336.html</trackback:ping><description><![CDATA[<strong><span style="font-size: 10pt"><strong>Java 中的堆和栈</strong><br />
<br />
简单的说：<br />
Java把内存划分成两种：一种是栈内存，一种是堆内存。&nbsp; &nbsp;<br />
&nbsp; &nbsp; <br />
&nbsp;&nbsp;在函数中定义的一些基本类型的变量和对象的引用变量都在函数的栈内存中分配。&nbsp; &nbsp;<br />
&nbsp; &nbsp; <br />
&nbsp;&nbsp;当在一段代码块定义一个变量时，Java就在栈中为这个变量分配内存空间，当超过变量的作用域后，Java会自动释放掉为该变量所分配的内存空间，该内存空间可以立即被另作他用。&nbsp; &nbsp;<br />
&nbsp; &nbsp; <br />
&nbsp;&nbsp;堆内存用来存放由new创建的对象和数组。&nbsp; &nbsp;<br />
&nbsp; &nbsp; <br />
&nbsp;&nbsp;在堆中分配的内存，由Java虚拟机的自动垃圾回收器来管理。&nbsp; &nbsp;<br />
&nbsp; &nbsp; <br />
&nbsp;&nbsp;在堆中产生了一个数组或对象后，还可以在栈中定义一个特殊的变量，让栈中这个变量的取值等于数组或对象在堆内存中的首地址，栈中的这个变量就成了数组或对象的引用变量。&nbsp; &nbsp;<br />
&nbsp; &nbsp; <br />
&nbsp;&nbsp;引用变量就相当于是为数组或对象起的一个名称，以后就可以在程序中使用栈中的引用变量来访问堆中的数组或对象。&nbsp; &nbsp;<br />
&nbsp; &nbsp; <br />
<br />
<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;<br />
<br />
具体的说：<br />
栈与堆都是Java用来在Ram中存放数据的地方。与C++不同，Java自动管理栈和堆，程序员不能直接地设置栈或堆。 <br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; Java的堆是一个运行时数据区,类的(对象从中分配空间。这些对象通过new、newarray、anewarray和multianewarray等指令建立，它们不需要程序代码来显式的释放。堆是由垃圾回收来负责的，堆的优势是可以动态地分配内存大小，生存期也不必事先告诉编译器，因为它是在运行时动态分配内存的，Java的垃圾收集器会自动收走这些不再使用的数据。但缺点是，由于要在运行时动态分配内存，存取速度较慢。 <br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;栈的优势是，存取速度比堆要快，仅次于寄存器，栈数据可以共享。但缺点是，存在栈中的数据大小与生存期必须是确定的，缺乏灵活性。栈中主要存放一些基本类型的变量（,int, short, long, byte, float, double, boolean, char）和对象句柄。 <br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;栈有一个很重要的特殊性，就是存在栈中的数据可以共享。假设我们同时定义： <br />
int a = 3; <br />
int b = 3； <br />
编译器先处理int a = 3；首先它会在栈中创建一个变量为a的引用，然后查找栈中是否有3这个值，如果没找到，就将3存放进来，然后将a指向3。接着处理int b = 3；在创建完b的引用变量后，因为在栈中已经有3这个值，便将b直接指向3。这样，就出现了a与b同时均指向3的情况。这时，如果再令a=4；那么编译器会重新搜索栈中是否有4值，如果没有，则将4存放进来，并令a指向4；如果已经有了，则直接将a指向这个地址。因此a值的改变不会影响到b的值。要注意这种数据的共享与两个对象的引用同时指向一个对象的这种共享是不同的，因为这种情况a的修改并不会影响到b, 它是由编译器完成的，它有利于节省空间。而一个对象引用变量修改了这个对象的内部状态，会影响到另一个对象引用变量。 <br />
<br />
String是一个特殊的包装类数据。可以用： <br />
String str = new String("abc"); <br />
String str = "abc"; <br />
两种的形式来创建，第一种是用new()来新建对象的，它会在存放于堆中。每调用一次就会创建一个新的对象。 <br />
而第二种是先在栈中创建一个对String类的对象引用变量str，然后查找栈中有没有存放"abc"，如果没有，则将"abc"存放进栈，并令str指向&#8221;abc&#8221;，如果已经有&#8221;abc&#8221; 则直接令str指向&#8220;abc&#8221;。 <br />
<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;比较类里面的数值是否相等时，用equals()方法；当测试两个包装类的引用是否指向同一个对象时，用==，下面用例子说明上面的理论。 <br />
String str1 = "abc"; <br />
String str2 = "abc"; <br />
System.out.println(str1==str2); //true <br />
可以看出str1和str2是指向同一个对象的。 <br />
<br />
String str1 =new String ("abc"); <br />
String str2 =new String ("abc"); <br />
System.out.println(str1==str2); // false <br />
用new的方式是生成不同的对象。每一次生成一个。 <br />
&nbsp; &nbsp;&nbsp; &nbsp; 因此用第一种方式创建多个&#8221;abc&#8221;字符串,在内存中其实只存在一个对象而已. 这种写法有利与节省内存空间. 同时它可以在一定程度上提高程序的运行速度，因为JVM会自动根据栈中数据的实际情况来决定是否有必要创建新对象。而对于String str = new String("abc")；的代码，则一概在堆中创建新对象，而不管其字符串值是否相等，是否有必要创建新对象，从而加重了程序的负担。 <br />
&nbsp; &nbsp;&nbsp; &nbsp; 另一方面, 要注意: 我们在使用诸如String str = "abc"；的格式定义类时，总是想当然地认为，创建了String类的对象str。担心陷阱！对象可能并没有被创建！而可能只是指向一个先前已经创建的对象。只有通过new()方法才能保证每次都创建一个新的对象。由于String类的immutable性质，当String变量需要经常变换其值时，应该考虑使用StringBuffer类，以提高程序效率。<br />
<br />
<br />
<br />
<br />
java中内存分配策略及堆和栈的比较 <br />
2.1 内存分配策略 <br />
按照编译原理的观点,程序运行时的内存分配有三种策略,分别是静态的,栈式的,和堆式的. <br />
静态存储分配是指在编译时就能确定每个数据目标在运行时刻的存储空间需求,因而在编译时就可以给他们分配固定的内存空间.这种分配策略要求程序代码中不允许有可变数据结构(比如可变数组)的存在,也不允许有嵌套或者递归的结构出现,因为它们都会导致编译程序无法计算准确的存储空间需求. <br />
栈式存储分配也可称为动态存储分配,是由一个类似于堆栈的运行栈来实现的.和静态存储分配相反,在栈式存储方案中,程序对数据区的需求在编译时是完全未知的,只有到运行的时候才能够知道,但是规定在运行中进入一个程序模块时,必须知道该程序模块所需的数据区大小才能够为其分配内存.和我们在数据结构所熟知的栈一样,栈式存储分配按照先进后出的原则进行分配。 <br />
静态存储分配要求在编译时能知道所有变量的存储要求,栈式存储分配要求在过程的入口处必须知道所有的存储要求,而堆式存储分配则专门负责在编译时或运行时模块入口处都无法确定存储要求的数据结构的内存分配,比如可变长度串和对象实例.堆由大片的可利用块或空闲块组成,堆中的内存可以按照任意顺序分配和释放. <br />
<br />
2.2 堆和栈的比较 <br />
上面的定义从编译原理的教材中总结而来,除静态存储分配之外,都显得很呆板和难以理解,下面撇开静态存储分配,集中比较堆和栈: <br />
从堆和栈的功能和作用来通俗的比较,堆主要用来存放对象的，栈主要是用来执行程序的.而这种不同又主要是由于堆和栈的特点决定的: <br />
在编程中，例如C/C++中，所有的方法调用都是通过栈来进行的,所有的局部变量,形式参数都是从栈中分配内存空间的。实际上也不是什么分配,只是从栈顶向上用就行,就好像工厂中的传送带(conveyor belt)一样,Stack Pointer会自动指引你到放东西的位置,你所要做的只是把东西放下来就行.退出函数的时候，修改栈指针就可以把栈中的内容销毁.这样的模式速度最快, 当然要用来运行程序了.需要注意的是,在分配的时候,比如为一个即将要调用的程序模块分配数据区时,应事先知道这个数据区的大小,也就说是虽然分配是在程序运行时进行的,但是分配的大小多少是确定的,不变的,而这个"大小多少"是在编译时确定的,不是在运行时. <br />
堆是应用程序在运行的时候请求操作系统分配给自己内存，由于从操作系统管理的内存分配,所以在分配和销毁时都要占用时间，因此用堆的效率非常低.但是堆的优点在于,编译器不必知道要从堆里分配多少存储空间，也不必知道存储的数据要在堆里停留多长的时间,因此,用堆保存数据时会得到更大的灵活性。事实上,面向对象的多态性,堆内存分配是必不可少的,因为多态变量所需的存储空间只有在运行时创建了对象之后才能确定.在C++中，要求创建一个对象时，只需用 new命令编制相关的代码即可。执行这些代码时，会在堆里自动进行数据的保存.当然，为达到这种灵活性，必然会付出一定的代价:在堆里分配存储空间时会花掉更长的时间！这也正是导致我们刚才所说的效率低的原因,看来列宁同志说的好,人的优点往往也是人的缺点,人的缺点往往也是人的优点(晕~). <br />
<br />
<br />
2.3 JVM中的堆和栈 <br />
JVM是基于堆栈的虚拟机.JVM为每个新创建的线程都分配一个堆栈.也就是说,对于一个Java程序来说，它的运行就是通过对堆栈的操作来完成的。堆栈以帧为单位保存线程的状态。JVM对堆栈只进行两种操作:以帧为单位的压栈和出栈操作。 <br />
我们知道,某个线程正在执行的方法称为此线程的当前方法.我们可能不知道,当前方法使用的帧称为当前帧。当线程激活一个Java方法,JVM就会在线程的 Java堆栈里新压入一个帧。这个帧自然成为了当前帧.在此方法执行期间,这个帧将用来保存参数,局部变量,中间计算过程和其他数据.这个帧在这里和编译原理中的活动纪录的概念是差不多的. <br />
从Java的这种分配机制来看,堆栈又可以这样理解:堆栈(Stack)是操作系统在建立某个进程时或者线程(在支持多线程的操作系统中是线程)为这个线程建立的存储区域，该区域具有先进后出的特性。 <br />
每一个Java应用都唯一对应一个JVM实例，每一个实例唯一对应一个堆。应用程序在运行中所创建的所有类实例或数组都放在这个堆中,并由应用所有的线程共享.跟C/C++不同，Java中分配堆内存是自动初始化的。Java中所有对象的存储空间都是在堆中分配的，但是这个对象的引用却是在堆栈中分配,也就是说在建立一个对象时从两个地方都分配内存，在堆中分配的内存实际建立这个对象，而在堆栈中分配的内存只是一个指向这个堆对象的指针(引用)而已。 </span></strong>
 <img src ="http://www.blogjava.net/yjjlovewjf/aggbug/166336.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yjjlovewjf/" target="_blank">wǒ愛伱--咾婆 </a> 2007-12-08 21:09 <a href="http://www.blogjava.net/yjjlovewjf/archive/2007/12/08/166336.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java虚拟机体系结构概述 （转）</title><link>http://www.blogjava.net/yjjlovewjf/archive/2007/12/08/166293.html</link><dc:creator>wǒ愛伱--咾婆 </dc:creator><author>wǒ愛伱--咾婆 </author><pubDate>Sat, 08 Dec 2007 07:53:00 GMT</pubDate><guid>http://www.blogjava.net/yjjlovewjf/archive/2007/12/08/166293.html</guid><wfw:comment>http://www.blogjava.net/yjjlovewjf/comments/166293.html</wfw:comment><comments>http://www.blogjava.net/yjjlovewjf/archive/2007/12/08/166293.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/yjjlovewjf/comments/commentRss/166293.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yjjlovewjf/services/trackbacks/166293.html</trackback:ping><description><![CDATA[Java虚拟机之所以称为&#8220;虚拟&#8221;，就是因为它仅仅是由一个规范来定义的抽象计算机。要运行某个Java程序，首先需要一个符合该规范的具体实现。下面主要讨论这个规范本身。
<p style="line-height: 150%"><font color="#0000ff"><strong>Java虚拟机是什么</strong></font> <br />
&nbsp;&nbsp;&nbsp;要理解Java虚拟机，你必须意识到，当你说&#8220;Java虚拟机&#8221;时，可能指的是如下三种不同的东西：</p>
<ul>
    <li>抽象规范&nbsp;
    <li>一个具体的实现&nbsp;
    <li>一个运行中的虚拟机实例 </li>
</ul>
<p style="line-height: 150%">Java虚拟机抽象规范仅仅是个概念。该规范的具体实现，可能来自多个提供商，并存在多个平台上。它或者完全用软件实现，或者以硬件和软件相结合的方式来实现。当运行一个Java程序的同时，也就在运行了一个Java虚拟机实例。</p>
<p style="line-height: 150%"><font color="#0000ff"><strong>Java虚拟机的生命周期</strong></font> <br />
&nbsp;&nbsp; 一个运行时的Java虚拟机实例的天职就是：负责运行一个Java程序。当启动一个Java程序时，一个虚拟机实例也就诞生了。当该程序关闭推出，这个虚拟机实例也就随之消亡。每个Java程序都运行在于自己的Java虚拟机实例中。Java虚拟机实例通过调用某个初始类的main()方法来运行一个Java程序。而这个main()方法必须是public,static,返回值为void。main()方法作为该程序初始线程的起点，任何其他的线程都是由这个初始线程启动的。 <br />
&nbsp;&nbsp; Java虚拟机内部有两种线程：守护线程和非守护线程。守护线程通常由虚拟机自己使用的，比如执行垃圾收集任务的线程。但是，Java程序也可以把它的创建的任何线程标记为守护线程。而Java程序中的初始线程，就是开始于main()的那个，是非守护线程。只要有非守护线程在运行，那么这个Java程序也在继续运行，只有该程序中所有的非守护线程都终止时，虚拟机实例将自动退出。 </p>
<p style="line-height: 150%"><strong><font color="#0000ff">Java虚拟机的体系结构</font></strong> <br />
&nbsp;&nbsp;Java虚拟机的结构分为：类装载子系统，运行时数据区，执行引擎，本地方法接口。其中运行时数据区又分为：方法区，堆，Java栈，PC寄存器，本地方法栈。 </p>
<p style="line-height: 150%"><strong><font color="#0000ff">类装载子系统</font></strong> <br />
&nbsp;&nbsp;Java虚拟机中，负责查找并装载类型的那部分称为类装载子系统。 <br />
&nbsp;&nbsp;Java虚拟机有两种类装载器：启动类装载器和用户自定义类装载器。启动类装载器是Java虚拟机实现的一部分。用户自定义类装载器是Java程序的一部分。 <br />
&nbsp;&nbsp;类装载器的动作： </p>
<ol>
    <li>装载---查找并装载类型的二进制数据
    <li>连接---执行验证，准备，以及解析（可选） <br />
    验证：确保被导入类型的正确性 <br />
    准备：为类变量分配内存，并将其初始化为默认值 <br />
    把类型中的符号引用换为直接引用
    <li>初始化---把类变量初始化为正确的初始值 </li>
</ol>
<p style="line-height: 150%"><font color="#0000ff"><strong>方法区</strong></font> <br />
&nbsp;&nbsp;在Java虚拟机中，被装载类型的信息存储在一个逻辑上被称为方法区的内存中。当虚拟机装载某个类型时，它使用类装载器定位相应的class文件，然后读入这个class文件，然后将它传输到虚拟机中，紧接着虚拟机提取其中的类型信息，并将这些信息存储到方法区。该类型中的类（静态）变量同样也是存储在方法区中。方法区的大小不必固定，可以根据需要动态调整。方法区也可以被垃圾收集，因为虚拟机允许通过用户定义的类装载器来动态扩展Java程序，因此，一些类也会成为&#8220;不再引用&#8221;的类。&nbsp; <br />
&nbsp;&nbsp;对于每个装载的类型，虚拟机都会在方法区中存储以下类型信息： </p>
<ul>
    <li>这个类型的全限定名。
    <li>这个类型的直接超类的全限定名（除非是java.lang.Object,无超类）
    <li>这个类型是类类型还是接口类型。
    <li>这个类型的访问修饰符（public,abstract ...)
    <li>任何直接超接口的全限定名的有序列表 </li>
</ul>
<p>除了上面列出的基本类型信息外，虚拟机还为每个被装载的类型存储以下信息 </p>
<ul>
    <li>该类型的常量池
    <li>字段信息
    <li>方法信息
    <li>除了常量以外所有类（静态）变量
    <li>一个到类ClassLoader的引用
    <li>一个到Class类的引用 </li>
</ul>
<p>http://blog.csdn.net/mimicimim/archive/2007/10/08/1815880.aspx</p>
 <img src ="http://www.blogjava.net/yjjlovewjf/aggbug/166293.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yjjlovewjf/" target="_blank">wǒ愛伱--咾婆 </a> 2007-12-08 15:53 <a href="http://www.blogjava.net/yjjlovewjf/archive/2007/12/08/166293.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>从Raylong - 睿狼的blog中收到的小知识..积累了</title><link>http://www.blogjava.net/yjjlovewjf/archive/2007/12/08/166291.html</link><dc:creator>wǒ愛伱--咾婆 </dc:creator><author>wǒ愛伱--咾婆 </author><pubDate>Sat, 08 Dec 2007 07:49:00 GMT</pubDate><guid>http://www.blogjava.net/yjjlovewjf/archive/2007/12/08/166291.html</guid><wfw:comment>http://www.blogjava.net/yjjlovewjf/comments/166291.html</wfw:comment><comments>http://www.blogjava.net/yjjlovewjf/archive/2007/12/08/166291.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/yjjlovewjf/comments/commentRss/166291.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yjjlovewjf/services/trackbacks/166291.html</trackback:ping><description><![CDATA[对象的存储：Java中所有对象的存储空间都是在堆中分配的，但是这个对象的引用却是在堆栈中分配,也就是说在建立一个对象时从两个地方都分配内存，在堆中分配的内存实际建立这个对象，而在堆栈中分配的内存只是一个指向这个堆对象的指针(引用)而已。堆的特点是灵活性，但为此牺牲了高效性，可以在运行时动态地分配存储；堆栈的特点是高效性，但缺乏灵活性，在编译时刻必须知道所要分配的空间大小。堆像个大馒头，可以根据你的食量随便吃，吃饱了算；堆栈像是吃大锅饭，每个人都是定食定量的，你必须告诉厨子你的饭量，厨子据此做饭，然后你们就排队打饭吧。它们没有孰优孰劣之分，各自不同特点有不同的应用。<br />
<br />
<br />
字符串的连接。<br />
int i=1,j=2,k=3;<br />
System.out.println(i+j+k);<br />
输出了6。<br />
int i=1,j=2,k=3;<br />
System.out.println(""+i+j+k);<br />
输出了123。有趣吧？这是因为从左到右的运算顺序。 <a class="weblogtitle" id="Header1_HeaderTitle" href="http://www.blogjava.net/raylong1982/">Raylong - 睿狼</a><br />
<br />
 <img src ="http://www.blogjava.net/yjjlovewjf/aggbug/166291.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yjjlovewjf/" target="_blank">wǒ愛伱--咾婆 </a> 2007-12-08 15:49 <a href="http://www.blogjava.net/yjjlovewjf/archive/2007/12/08/166291.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java语法总结 - 方法</title><link>http://www.blogjava.net/yjjlovewjf/archive/2007/12/08/166284.html</link><dc:creator>wǒ愛伱--咾婆 </dc:creator><author>wǒ愛伱--咾婆 </author><pubDate>Sat, 08 Dec 2007 07:05:00 GMT</pubDate><guid>http://www.blogjava.net/yjjlovewjf/archive/2007/12/08/166284.html</guid><wfw:comment>http://www.blogjava.net/yjjlovewjf/comments/166284.html</wfw:comment><comments>http://www.blogjava.net/yjjlovewjf/archive/2007/12/08/166284.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/yjjlovewjf/comments/commentRss/166284.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yjjlovewjf/services/trackbacks/166284.html</trackback:ping><description><![CDATA[Java语法总结 - 方法<br />
原文：<a href="http://www.blogjava.net/raylong1982/">http://www.blogjava.net/raylong1982/</a>以下几篇都是的....<br />
一、方法的重写。<br />
<br />
1、重写只能出现在继承关系之中。当一个类继承它的父类方法时，都有机会重写该父类的方法。一个特例是父类的方法被标识为final。重写的主要优点是能够定义某个子类型特有的行为。<br />
&nbsp;&nbsp; &nbsp;class Animal {<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;public void eat(){<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;System.out.println ("Animal is eating.");<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}<br />
&nbsp;&nbsp; &nbsp;}<br />
&nbsp;&nbsp; &nbsp;<br />
&nbsp;&nbsp; &nbsp;class Horse extends Animal{<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;public void eat(){<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;System.out.println ("Horse is eating.");<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}<br />
&nbsp;&nbsp; &nbsp;}<br />
<br />
2、对于从父类继承来的抽象方法，要么在子类用重写的方式设计该方法，要么把子类也标识为抽象的。所以抽象方法可以说是必须要被重写的方法。<br />
<br />
3、重写的意义。<br />
重写方法可以实现多态，用父类的引用来操纵子类对象，但是在实际运行中对象将运行其自己特有的方法。<br />
&nbsp;&nbsp; &nbsp;public class Test {<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;public static void main (String[] args) {<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;Animal h = new Horse();<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;h.eat();&nbsp;&nbsp; &nbsp;<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}<br />
&nbsp;&nbsp; &nbsp;}<br />
<br />
&nbsp;&nbsp; &nbsp;class Animal {<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;public void eat(){<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;System.out.println ("Animal is eating.");<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}<br />
&nbsp;&nbsp; &nbsp;}<br />
&nbsp;&nbsp; &nbsp;<br />
&nbsp;&nbsp; &nbsp;class Horse extends Animal{<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;public void eat(){<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;System.out.println ("Horse is eating.");<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;public void buck(){<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}<br />
&nbsp;&nbsp; &nbsp;}<br />
<br />
一个原则是：使用了什么引用，编译器就会只调用引用类所拥有的方法。如果调用子类特有的方法，如上例的h.buck(); 编译器会抱怨的。也就是说，编译器只看引用类型，而不是对象类型。<br />
<br />
4、重写方法的规则。<br />
若想实现一个合格重写方法，而不是重载，那么必须同时满足下面的要求！<br />
<br />
A、重写规则之一：重写方法不能比被重写方法限制有更严格的访问级别。<br />
（但是可以更广泛，比如父类方法是包访问权限，子类的重写方法是public访问权限。）<br />
比如：Object类有个toString()方法，开始重写这个方法的时候我们总容易忘记public修饰符，编译器当然不会放过任何教训我们的机会。出错的原因就是：没有加任何访问修饰符的方法具有包访问权限，包访问权限比public当然要严格了，所以编译器会报错的。<br />
<br />
B、重写规则之二：参数列表必须与被重写方法的相同。<br />
重写有个孪生的弟弟叫重载，也就是后面要出场的。如果子类方法的参数与父类对应的方法不同，那么就是你认错人了，那是重载，不是重写。<br />
<br />
C、重写规则之三：返回类型必须与被重写方法的返回类型相同。<br />
父类方法A：void eat(){}&nbsp; 子类方法B：int eat(){}&nbsp; 两者虽然参数相同，可是返回类型不同，所以不是重写。<br />
父类方法A：int eat(){}&nbsp;&nbsp; 子类方法B：long eat(){}&nbsp; 返回类型虽然兼容父类，但是不同就是不同，所以不是重写。<br />
<br />
D、重写规则之四：重写方法不能抛出新的异常或者比被重写方法声明的检查异常更广的检查异常。但是可以抛出更少，更有限或者不抛出异常。<br />
&nbsp;&nbsp; &nbsp;import java.io.*;<br />
&nbsp;&nbsp; &nbsp;public class Test {<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;public static void main (String[] args) {<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;Animal h = new Horse();<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;try {<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;h.eat();&nbsp;&nbsp; &nbsp;<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;catch (Exception e) {<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}<br />
&nbsp;&nbsp; &nbsp;}<br />
<br />
&nbsp;&nbsp; &nbsp;class Animal {<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;public void eat() throws Exception{<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;System.out.println ("Animal is eating.");<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;throw new Exception();<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}<br />
&nbsp;&nbsp; &nbsp;}<br />
&nbsp;&nbsp; &nbsp;<br />
&nbsp;&nbsp; &nbsp;class Horse extends Animal{<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;public void eat() throws IOException{<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;System.out.println ("Horse is eating.");<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;throw new IOException();<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}<br />
&nbsp;&nbsp; &nbsp;}<br />
这个例子中，父类抛出了检查异常Exception，子类抛出的IOException是Exception的子类，也即是比被重写的方法抛出了更有限的异常，这是可以的。如果反过来，父类抛出IOException，子类抛出更为宽泛的Exception，那么不会通过编译的。<br />
注意：这种限制只是针对检查异常，至于运行时异常RuntimeException及其子类不再这个限制之中。<br />
<br />
E、重写规则之五：不能重写被标识为final的方法。<br />
<br />
F、重写规则之六：如果一个方法不能被继承，则不能重写它。<br />
比较典型的就是父类的private方法。下例会产生一个有趣的现象。<br />
&nbsp;&nbsp; &nbsp;public class Test {<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;public static void main (String[] args) {<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;//Animal h = new Horse();<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;Horse h = new Horse();<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;h.eat();<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}<br />
&nbsp;&nbsp; &nbsp;}<br />
<br />
&nbsp;&nbsp; &nbsp;class Animal {<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;private void eat(){<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;System.out.println ("Animal is eating.");<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}<br />
&nbsp;&nbsp; &nbsp;}<br />
&nbsp;&nbsp; &nbsp;<br />
&nbsp;&nbsp; &nbsp;class Horse extends Animal{<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;public void eat(){<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;System.out.println ("Horse is eating.");<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}<br />
&nbsp;&nbsp; &nbsp;}<br />
这段代码是能通过编译的。表面上看来违反了第六条规则，但实际上那是一点巧合。Animal类的eat()方法不能被继承，因此Horse类中的eat()方法是一个全新的方法，不是重写也不是重载，只是一个只属于Horse类的全新的方法！这点让很多人迷惑了，但是也不是那么难以理解。<br />
main()方法如果是这样：<br />
&nbsp;&nbsp; &nbsp;Animal h = new Horse();<br />
&nbsp;&nbsp; &nbsp;//Horse h = new Horse();<br />
&nbsp;&nbsp; &nbsp;h.eat();<br />
编译器会报错，为什么呢？Horse类的eat()方法是public的啊！应该可以调用啊！请牢记，多态只看父类引用的方法，而不看子类对象的方法！<br />
<br />
<br />
二、方法的重载。<br />
重载是有好的，它不要求你在调用一个方法之前转换数据类型，它会自动地寻找匹配的方法。方法的重载是在编译时刻就决定调用哪个方法了，和重写不同。最最常用的地方就是构造器的重载。<br />
<br />
1、基本数据类型参数的重载。<br />
&nbsp;&nbsp; &nbsp;public class Test {<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;static void method(byte b){<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;System.out.println ("method:byte");<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;static void method(short s){<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;System.out.println ("method:short");<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;static void method(int i){<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;System.out.println ("method:int");<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;static void method(float f){<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;System.out.println ("method:float");<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;static void method(double d){<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;System.out.println ("method:double");<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;public static void main (String[] args) {<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;method((byte)1);<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;method('c');<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;method(1);<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;method(1L);<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;method(1.1);<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;method(1.1f);<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}<br />
&nbsp;&nbsp; &nbsp;}<br />
输出结果：<br />
method:byte<br />
method:int<br />
method:int<br />
method:float<br />
method:double<br />
method:float<br />
<br />
可以看出：首先要寻找的是数据类型正好匹配方法。如果找不到，那么就提升为表达能力更强的数据类型，如上例没有正好容纳long的整数类型，那么就转换为float类型的。如果通过提升也不能找到合适的兼容类型，那么编译器就会报错。反正是不会自动转换为较小的数据类型的，必须自己强制转换，自己来承担转变后果。<br />
<br />
char类型比较特殊，如果找不到正好匹配的类型，它会转化为int而不是short，虽然char是16位的。<br />
<br />
<br />
2、重载方法的规则。<br />
<br />
A、被重载的方法必须改变参数列表。<br />
参数必须不同，这是最重要的！不同有两个方面，参数的个数，参数的类型，参数的顺序。<br />
<br />
B、被重载的方法与返回类型无关。<br />
也就是说，不能通过返回类型来区分重载方法。<br />
<br />
C、被重载的方法可以改变访问修饰符。<br />
没有重写方法那样严格的限制。<br />
<br />
D、被重载的方法可以声明新的或者更广的检查异常。<br />
没有重写方法那样严格的限制。<br />
<br />
E、方法能够在一个类中或者在一个子类中被重载。<br />
<br />
<br />
3、带对象引用参数的方法重载。<br />
&nbsp;&nbsp; &nbsp;class Animal {}<br />
&nbsp;&nbsp; &nbsp;class Horse extends Animal{}<br />
&nbsp;&nbsp; &nbsp;<br />
&nbsp;&nbsp; &nbsp;public class Test {<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;static void method(Animal a){<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;System.out.println ("Animal is called.");<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;static void method(Horse h){<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;System.out.println ("Horse is called.");<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;public static void main (String[] args) {<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;Animal a = new Animal();<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;Horse h = new Horse();<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;Animal ah = new Horse();<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;method(a);<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;method(h);<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;method(ah);<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp; &nbsp;}<br />
输出结果是：<br />
Animal is called.<br />
Horse is called.<br />
Animal is called.<br />
前两个输出没有任何问题。第三个方法为什么不是输出&#8220;Horse is called.&#8221;呢？还是那句老话，要看引用类型而不是对象类型，方法重载是在编译时刻就决定的了，引用类型决定了调用哪个版本的重载方法。<br />
<br />
<br />
4、重载和重写方法区别的小结。<br />
如果能彻底弄明白下面的例子，说明你对重载和重写非常了解了，可以结束这节的复习了。<br />
&nbsp;&nbsp; &nbsp;class Animal {<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;public void eat(){<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;System.out.println ("Animal is eating.");&nbsp;&nbsp; &nbsp;<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}<br />
&nbsp;&nbsp; &nbsp;}<br />
&nbsp;&nbsp; &nbsp;class Horse extends Animal{<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;public void eat(){<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;System.out.println ("Horse is eating.");&nbsp;&nbsp; &nbsp;<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;public void eat(String food){<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;System.out.println ("Horse is eating " + food);<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}<br />
&nbsp;&nbsp; &nbsp;}<br />
&nbsp;&nbsp; &nbsp;<br />
&nbsp;&nbsp; &nbsp;public class Test {<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;public static void main (String[] args) {<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;Animal a = new Animal();<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;Horse h = new Horse();<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;Animal ah = new Horse();<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;a.eat();<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;h.eat();<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;h.eat("apple");<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;ah.eat();<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;//a.eat("apple");<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;//ah.eat("apple");<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp; &nbsp;}<br />
<br />
四个输出分别是什么？被注释的两条语句为什么不能通过编译？<br />
第一条：a.eat(); 普通的方法调用，没有多态，没什么技术含量。调用了Animal类的eat()方法，输出：Animal is eating.<br />
第二条：h.eat(); 普通的方法调用，也没什么技术含量。调用了Horse类的eat()方法，输出：Horse is eating.<br />
第三条：h.eat("apple"); 重载。Horse类的两个eat()方法重载。调用了Horse类的eat(String food)方法，输出：Horse is eating apple<br />
第四条：ah.eat(); 多态。前面有例子了，不难理解。输出：Horse is eating.<br />
第五条：a.eat("apple"); 低级的错误，Animal类中没有eat(String food)方法。因此不能通过编译。<br />
第六条：ah.eat("apple"); 关键点就在这里。解决的方法还是那句老话，不能看对象类型，要看引用类型。Animal类中没有eat(String food)方法。因此不能通过编译。<br />
<br />
小结一下：多态不决定调用哪个重载版本；多态只有在决定哪个重写版本时才起作用。<br />
重载对应编译时，重写对应运行时。够简洁的了吧！<br />
<br />
<br />
三、构造方法。<br />
构造方法是一种特殊的方法，没有构造方法就不能创建一个新对象。实际上，不仅要调用对象实际类型的构造方法，还要调用其父类的构造方法，向上追溯，直到Object类。构造方法不必显式地调用，当使用new关键字时，相应的构造方法会自动被调用。<br />
<br />
1、构造方法的规则。<br />
A、构造方法能使用任何访问修饰符。包括private，事实上java类库有很多都是这样的，设计者不希望使用者创建该类的对象。<br />
<br />
B、构造方法的名称必须与类名相同。这样使得构造方法与众不同，如果我们遵守sun的编码规范，似乎只有构造方法的首字母是大写的。<br />
<br />
C、构造方法不能有返回类型。<br />
反过来说，有返回类型的不是构造方法<br />
&nbsp;&nbsp; &nbsp;public class Test {<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;int Test(){<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;return 1;<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}<br />
&nbsp;&nbsp; &nbsp;}<br />
这个方法是什么东西？一个冒充李逵的李鬼而已，int Test()和其他任何普通方法没什么两样，就是普通的方法！只不过看起来很恶心，类似恶心的东西在考试卷子里比较多。<br />
<br />
D、如果不在类中创建自己的构造方法，编译器会自动生成默认的不带参数的构造函数。<br />
这点很容易验证！写一个这样简单的类，编译。<br />
class Test {<br />
}<br />
对生成的Test.class文件反编译：javap Test，可以看到：<br />
D:"JavaCode"bin&gt;javap Test<br />
Compiled from "Test.java"<br />
class Test extends java.lang.Object{<br />
&nbsp;&nbsp;&nbsp; Test();<br />
}<br />
看到编译器自动添加的默认构造函数了吧！<br />
<br />
E、如果只创建了带参数的构造方法，那么编译器不会自动添加无参的构造方法的！<br />
<br />
F、在每个构造方法中，如果使用了重载构造函数this()方法，或者父类的构造方法super()方法，那么this()方法或者super()方法必须放在第一行。而且这两个方法只能选择一个，因此它们之间没有顺序问题。<br />
<br />
G、除了编译器生成的构造方法，而且没有显式地调用super()方法，那么编译器会插入一个super()无参调用。<br />
<br />
H、抽象类有构造方法。<br />
<br />
<br />
四、静态方法的重载与重写（覆盖）。<br />
<br />
1、静态方法是不能被覆盖的。可以分两种情况讨论：<br />
<br />
A、子类的非静态方法&#8220;覆盖&#8221;父类的静态方法。<br />
这种情况下，是不能通过编译的。<br />
<br />
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #0000ff">class</span><span style="color: #000000">&nbsp;Father{<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">static</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">void</span><span style="color: #000000">&nbsp;print(){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println&nbsp;(</span><span style="color: #000000">"</span><span style="color: #000000">in&nbsp;father&nbsp;&nbsp;method</span><span style="color: #000000">"</span><span style="color: #000000">);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
}<br />
</span><span style="color: #0000ff">class</span><span style="color: #000000">&nbsp;Child&nbsp;</span><span style="color: #0000ff">extends</span><span style="color: #000000">&nbsp;Father{<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">void</span><span style="color: #000000">&nbsp;print(){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println&nbsp;(</span><span style="color: #000000">"</span><span style="color: #000000">in&nbsp;child&nbsp;method</span><span style="color: #000000">"</span><span style="color: #000000">);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
}</span></div>
<br />
static方法表示该方法不关联具体的类的对象，可以通过类名直接调用，也就是编译的前期就绑定了，不存在后期动态绑定，也就是不能实现多态。子类的非静态方法是与具体的对象绑定的，两者有着不同的含义。<br />
<br />
B、子类的静态方法&#8220;覆盖&#8221;父类静态方法。<br />
这个覆盖依然是带引号的。事实上把上面那个例子Child类的print方法前面加上static修饰符，确实能通过编译！但是不要以为这就是多态！多态的特点是动态绑定，看下面的例子：<br />
<br />
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #0000ff">class</span><span style="color: #000000">&nbsp;Father{<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">static</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">void</span><span style="color: #000000">&nbsp;print(){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println&nbsp;(</span><span style="color: #000000">"</span><span style="color: #000000">in&nbsp;father&nbsp;&nbsp;method</span><span style="color: #000000">"</span><span style="color: #000000">);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
}<br />
</span><span style="color: #0000ff">class</span><span style="color: #000000">&nbsp;Child&nbsp;</span><span style="color: #0000ff">extends</span><span style="color: #000000">&nbsp;Father{<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">static</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">void</span><span style="color: #000000">&nbsp;print(){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println&nbsp;(</span><span style="color: #000000">"</span><span style="color: #000000">in&nbsp;child&nbsp;method</span><span style="color: #000000">"</span><span style="color: #000000">);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
}<br />
<br />
</span><span style="color: #0000ff">class</span><span style="color: #000000">&nbsp;Test{<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">static</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">void</span><span style="color: #000000">&nbsp;main&nbsp;(String[]&nbsp;args)&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Father&nbsp;f&nbsp;</span><span style="color: #000000">=</span><span style="color: #0000ff">new</span><span style="color: #000000">&nbsp;Child();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;f.print();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
}</span></div>
<br />
输出结果是：in father&nbsp; method<br />
从这个结果可以看出，并没有实现多态。<br />
但是这种形式很迷惑人，貌似多态，实际编程中千万不要这样搞，会把大家搞懵的！<br />
它不符合覆盖表现出来的特性，不应该算是覆盖！<br />
总而言之，静态方法不能被覆盖。<br />
<br />
2、静态方法可以和非静态方法一样被重载。<br />
这样的例子太多了，我不想写例程了。看看java类库中很多这样的例子。<br />
如java.util.Arrays类的一堆重载的binarySearch方法。<br />
在这里提一下是因为查资料时看到这样的话&#8220;sun的SL275课