??xml version="1.0" encoding="utf-8" standalone="yes"?>一本综合久久国产二区,久久人人爽人人爽人人AV,99久久99这里只有免费费精品http://www.shnenglu.com/chenglong7997/category/18971.htmlzh-cnThu, 12 Apr 2012 16:19:42 GMTThu, 12 Apr 2012 16:19:42 GMT60java 提高性能http://www.shnenglu.com/chenglong7997/articles/171006.htmlSnapeSnapeWed, 11 Apr 2012 20:31:00 GMThttp://www.shnenglu.com/chenglong7997/articles/171006.htmlhttp://www.shnenglu.com/chenglong7997/comments/171006.htmlhttp://www.shnenglu.com/chenglong7997/articles/171006.html#Feedback0http://www.shnenglu.com/chenglong7997/comments/commentRss/171006.htmlhttp://www.shnenglu.com/chenglong7997/services/trackbacks/171006.html最q的机器内存又爆满了Q除了新增机器内存外Q还应该好好review一下我们的代码Q有很多代码~写q于随意化,q些不好的习惯或对程序语a的不了解是应该好好打压打压了?/p>

 

下面是参考网l资源ȝ的一些在Java~程中尽可能要做到的一些地斏V?br />
1. 量在合适的场合使用单例
使用单例可以减轻加蝲的负担,~短加蝲的时_提高加蝲的效率,但ƈ不是所有地斚w适用于单例,单来_单例主要适用于以下三个方面:
W一Q控制资源的使用Q通过U程同步来控制资源的q发讉KQ?/div>
W二Q控制实例的产生Q以辑ֈ节约资源的目的;
W三Q控制数据共享,在不建立直接兌的条件下Q让多个不相关的q程或线E之间实现通信?br />
2. 量避免随意使用静态变?/strong>
要知道,当某个对象被定义为stataic变量所引用Q那么gc通常是不会回收这个对象所占有的内存,?/div>
Java代码 
  1. public class A{  
  2. static B b = new B();  
  3. }  
 
此时静态变量b的生命周期与Acd步,如果AcM会卸载,那么b对象会常d存,直到E序l止?br />
3. 量避免q多q常的创建Java对象
量避免在经常调用的ҎQ@环中new对象Q由于系l不仅要p旉来创建对象,而且q要花时间对q些对象q行垃圾回收和处理,在我们可以控制的范围内,最大限度的重用对象Q最好能用基本的数据cd或数l来替代对象?/div>
4. 量使用final修饰W?/strong>
带有final修饰W的cL不可z的。在Java核心API中,有许多应用final的例子,例如java.lang.String。ؓStringcL定final防止了用者覆盖length()Ҏ。另外,如果一个类是final的,则该cL有方法都是final的。Java~译器会LZ内联QinlineQ所有的finalҎQ这和具体的~译器实现有养I。此举能够性能q_提高50%?br />
5. 量使用局部变?/strong>
调用Ҏ时传递的参数以及在调用中创徏的时变量都保存在栈QStackQ中Q速度较快。其他变量,如静态变量、实例变量等Q都在堆QHeapQ中创徏Q速度较慢?br />
6. 量处理好包装类型和基本cd两者的使用场所
虽然包装cd和基本类型在使用q程中是可以怺转换Q但它们两者所产生的内存区域是完全不同的,基本cd数据产生和处理都在栈中处理,包装cd是对象,是在堆中产生实例?/div>
在集合类对象Q有对象斚w需要的处理适用包装cdQ其他的处理提倡用基本类型?br />
7. 慎用synchronizedQ尽量减synchronize的方?/strong>
都知道,实现同步是要很大的系l开销作ؓ代h的,甚至可能造成死锁Q所以尽量避免无谓的同步控制。synchronizeҎ被调用时Q直接会把当前对象锁 了,在方法执行完之前其他U程无法调用当前对象的其他方法。所以synchronize的方法尽量小Qƈ且应量使用Ҏ同步代替代码块同步?br />
8. 量使用StringBuilder和StringBufferq行字符串连?/strong>
q个׃多讲了?br />
9. 量不要使用finalizeҎ
实际上,资源清理放在finalizeҎ中完成是非常不好的选择Q由于GC的工作量很大Q尤其是回收Young代内存时Q大都会引v应用E序暂停Q所以再选择使用finalizeҎq行资源清理Q会DGC负担更大Q程序运行效率更差?br />
10. 量使用基本数据cd代替对象
String str = "hello";
上面q种方式会创Z?#8220;hello”字符Ԍ而且JVM的字W缓存池q会~存q个字符Ԍ
String str = new String("hello");
此时E序除创建字W串外,str所引用的String对象底层q包含一个char[]数组Q这个char[]数组依次存放了h,e,l,l,o
11. 单线E应量使用HashMap、ArrayList
HashTable、Vector{用了同步机制Q降低了性能?br />
12. 量合理的创建HashMap
当你要创Z个比较大的hashMapӞ充分利用另一个构造函?/div>
public HashMap(int initialCapacity, float loadFactor)
避免HashMap多次q行了hash重构,扩容是一件很耗费性能的事Q在默认中initialCapacity只有16Q而loadFactor?0.75Q需要多大的定wQ你最好能准确的估计你所需要的最佛_,同样的HashtableQVectors也是一L道理?br />
13. 量减少对变量的重复计算
?/div>
for(int i=0;i<list.size();i++)
应该改ؓ
for(int i=0,len=list.size();i<len;i++)
q且在@环中应该避免使用复杂的表辑ּQ在循环中,循环条g会被反复计算Q如果不使用复杂表达式,而循环条gg变的话,E序会q行的更快?nbsp;
14. 量避免不必要的创徏
?/div>
A a = new A();
if(i==1){list.add(a);}
应该改ؓ
if(i==1){
A a = new A();
list.add(a);}
15. 量在finally块中释放资源
E序中用到的资源应当被释放Q以避免资源泄漏。这最好在finally块中d。不程序执行的l果如何Qfinally块L会执行的Q以保资源的正关闭?nbsp;
16. 量使用UM来代?a/b'的操?/strong>
"/"是一个代价很高的操作Q用移位的操作会更快和更有效
?/div>
int num = a / 4;
int num = a / 8;
应该改ؓ
int num = a >> 2;
int num = a >> 3;
但注意的是用移位应d注释Q因为移位操作不直观Q比较难理解
17.量使用UM来代?a*b'的操?/strong>
同样的,对于'*'操作Q用移位的操作会更快和更有效
?/div>
int num = a * 4;
int num = a * 8;
应该改ؓ
int num = a << 2;
int num = a << 3;
18. 量定StringBuffer的容?/strong>
StringBuffer 的构造器会创Z个默认大(通常?6Q的字符数组。在使用中,如果出q个大小Q就会重新分配内存,创徏一个更大的数组Qƈ原先的数组复制q来Q再 丢弃旧的数组。在大多数情况下Q你可以在创?StringBuffer的时候指定大,q样避免了在容量不够的时候自动增长,以提高性能?nbsp;
如:StringBuffer buffer = new StringBuffer(1000);  
19. 量早释放无用对象的引用
大部分时Q方法局部引用变量所引用的对?会随着Ҏl束而变成垃圾,因此Q大部分时候程序无需局部,引用变量昑ּ设ؓnull?/div>
例如Q?/div>
Java代码 
  1. Public void test(){  
  2. Object obj = new Object();  
  3. ……  
  4. Obj=null;  
  5. }  
 
上面q个没必要了,随着Ҏtest()的执行完成,E序中obj引用变量的作用域q束了。但是如果是Ҏ下面Q?/div>
Java代码 
  1. Public void test(){  
  2. Object obj = new Object();  
  3. ……  
  4. Obj=null;  
  5. //执行耗时Q耗内存操作;或调用耗时Q耗内存的Ҏ  
  6. ……  
  7. }  
 
q时候就有必要将obj赋gؓnullQ可以尽早的释放对Object对象的引用?br />
20. 量避免使用二维数组
二维数据占用的内存空间比一l数l多得多Q大?0倍以上?br />
21. 量避免使用split
除非是必ȝQ否则应该避免用splitQsplit׃支持正则表达式,所以效率比较低Q如果是频繁的几十,几百万的调用会耗费大量资源Q如果确实需 要频J的调用splitQ可以考虑使用apache的StringUtils.split(string,char)Q频Jsplit的可以缓存结果?br />
22. ArrayList & LinkedList
一 个是U性表Q一个是链表Q一句话Q随机查询尽量用ArrayListQArrayList优于LinkedListQLinkedListq要Ud?针,d删除的操作LinkedList优于ArrayListQArrayListq要Ud数据Q不q这是理论性分析,事实未必如此Q重要的是理解好2 者得数据l构Q对症下药?br />
23. 量使用System.arraycopy ()代替通过来@环复制数l?/strong>
System.arraycopy() 要比通过循环来复制数l快的多 
24. 量~存l常使用的对?/strong>
可能将l常使用的对象进行缓存,可以使用数组Q或HashMap的容器来q行~存Q但q种方式可能Dpȝ占用q多的缓存,性能下降Q推荐可以用一些第三方的开源工P如EhCacheQOscacheq行~存Q他们基本都实现了FIFO/FLU{缓存算法?br />
25. 量避免非常大的内存分配
有时候问题不是由当时的堆状态造成的,而是因ؓ分配p|造成的。分配的内存块都必须是连l的Q而随着堆越来越满,扑ֈ较大的连l块来困难?br />
26. 慎用异常
当创Z个异常时Q需要收集一个栈跟踪(stack track)Q这个栈跟踪用于描述异常是在何处创徏的。构些栈跟踪旉要ؓq行时栈做一份快照,正是q一部分开销很大。当需要创Z?Exception ӞJVM 不得不说Q先别动Q我惛_您现在的样子存一份快照,所以暂时停止入栈和出栈操作。栈跟踪不只包含q行时栈中的一两个元素Q而是包含q个栈中的每一个元素?/div>
?果您创徏一?Exception Q就得付Z仗好在捕获异常开销不大Q因此可以?try-catch 核心内容包h。从技术上Ԍ您甚臛_以随意地抛出异常Q而不用花费很大的代h。招致性能损失的ƈ不是 throw 操作——管在没有预先创建异常的情况下就抛出异常是有点不d。真正要׃L是创建异常。幸q的是,好的~程习惯已教会我们,不应该不三七二十一?抛出异常。异常是为异常的情况而设计的Q用时也应该牢记这一原则?/div>

Snape 2012-04-12 04:31 发表评论
]]>java中cloneQ)http://www.shnenglu.com/chenglong7997/articles/170906.htmlSnapeSnapeWed, 11 Apr 2012 06:08:00 GMThttp://www.shnenglu.com/chenglong7997/articles/170906.htmlhttp://www.shnenglu.com/chenglong7997/comments/170906.htmlhttp://www.shnenglu.com/chenglong7997/articles/170906.html#Feedback0http://www.shnenglu.com/chenglong7997/comments/commentRss/170906.htmlhttp://www.shnenglu.com/chenglong7997/services/trackbacks/170906.html 目录 

预备知识 
Z么要clone 
Object的clone以及Z么如此实?nbsp;
如何clone 
对clone的态度 
其他的选择 
和Serializable的比?nbsp;
性能 

预备知识 

Z理解java的cloneQ有必要先温习以下的知识?nbsp;
java的类型,java的类型分Z大类Q一cMؓprimitiveQ如intQ另一cMؓ引用cd,如String,Object{等?nbsp;
java引用cd的存储,java的引用类型都是存储在堆上?/span>
public class B { int a; String b; public B(int a, String b) { super(); this.a = a; this.b = b; } }
对这样一个引用类型的实例Q我们可以推,在堆上它的内存存储Ş式(除去指向class的引用,锁的理{等内务事务所占内存)Q应该有一个intDCa,以及一个引用,该引用指向b在堆上的存储I间?nbsp;
 

Z么要clone 

恩,因ؓ需要。废话?nbsp;
有名的GoF设计模式里有一个模式ؓ原型模式Q用原型实例指定创徏对象的种c?q且通过拯q些原型创徏新的对象. 
单的说就是clone一个对象实例。得clone出来的copy和原有的对象一模一栗?nbsp;

插一个简单用clone的例子,如果一个对象内部有可变对象实例的话Qpublic API不应该直接返回该对象的引用,以防调用方的code改变该对象的内部状态。这个时候可以返回该对象的clone?nbsp;

问题来了Q什么叫一模一栗?nbsp;
一般来_?nbsp;
x.clone() != x 
x.clone().getClass() == x.getClass() 
x.clone().equals(x) 
但是q些都不是强制的?nbsp;
我们需要什么样的clone搞Z么样的clone好了?nbsp;
一般而言Q我们要的clone应该是这L。copy和原型的内容一P但是又是彼此隔离的。即在clone之后Q改变其中一个不影响另外一个?nbsp;


Object的clone以及Z么如此实?/strong> 

Object的clone的行为是最单的。以堆上的内存存储解释的话(不计内务内存Q,对一个对象a的clone是在堆上分配一个和a在堆上所占存储空间一样大的一块地方,然后把a的堆上内存的内容复制到这个新分配的内存空间上?nbsp;
看例子?nbsp;
class User { 	String name; 	int age; } class Account implements Cloneable { 	User user; 	long balance; 	@Override 	public Object clone() throws CloneNotSupportedException { 		return super.clone(); 	} }


		// user. 		User user = new User(); 		user.name = "user"; 		user.age = 20; 		// account. 		Account account = new Account(); 		account.user = user; 		account.balance = 10000; 		// copy. 		Account copy = (Account) account.clone(); 		// balance因ؓ是primitiveQ所以copy和原型是相等且独立的?		Assert.assertEquals(copy.balance, account.balance); 		copy.balance = 20000; 		// 改变copy不媄响原型?		Assert.assertTrue(copy.balance != account.balance); 		// user因ؓ是引用类型,所以copy和原型的引用是同一的?		Assert.assertTrue(copy.user == account.user); 		copy.user.name = "newName"; 		// 改变的是同一个东ѝ?		Assert.assertEquals("newName", account.user.name);

 

恩,默认实现是帮了我们一些忙Q但是不是全部?nbsp;
primitive的确做到了相{且隔离?nbsp;
引用cd仅仅是复制了一下引用,copy和原型引用的东西是一L?nbsp;
q个是所谓的copy了?nbsp;
要实现深copyQ即复制原型中对象的内存copyQ而不仅仅是一个引用。只有自己动手了?nbsp;
{等Q是不是所有的引用cd都需要深copy呢? 
不是Q?nbsp;
我们之所以要深copyQ是因ؓ默认的实现提供的copy不是隔离的,换言之,改变copy的东西,会媄响到原型的内部。比如例子中Q改变copy的user的nameQ媄响了原型?nbsp;
如果我们要copy的类是不可变的呢Q如StringQ没有方法可以改变它的内部状态呢?nbsp;
class User implements Cloneable { 	String name; 	int age; 	@Override 	public Object clone() throws CloneNotSupportedException { 		return super.clone(); 	} }

		// user. 		User user = new User(); 		user.name = "user"; 		user.age = 20; 		// copy 		User copy = (User) user.clone(); 		// age因ؓ是primitiveQ所以copy和原型是相等且独立的?		Assert.assertEquals(copy.age, user.age); 		copy.age = 30; 		// 改变copy不媄响原型?		Assert.assertTrue(copy.age != user.age); 		// name因ؓ是引用类型,所以copy和原型的引用是同一的?		Assert.assertTrue(copy.name == user.name); 		// StringZ可变cR没有办法可以通过对copy.name的字W串的操作改变这个字W串?		// 改变引用新的对象不会影响原型?		copy.name = "newname"; 		Assert.assertEquals("newname", copy.name); 		Assert.assertEquals("user", user.name);
可见Q?/span>在考虑cloneӞprimitive和不可变对象cd是可以同{对待的?nbsp;

javaZ么如此实现clone呢? 
也许有以下考虑?nbsp;
1 效率和简单性,单的copy一个对象在堆上的的内存比遍历一个对象网然后内存深copy明显效率高ƈ且简单?nbsp;
2 不给别的cd加意义。如果A实现了CloneableQ同时有一个引用指向BQ如果直接复制内存进行深copy的话Q意味着B在意义上也是支持Clone的,但是q个是在使用B的A中做的,B甚至都不知道。破坏了B原有的接口?nbsp;
3 有可能破坏语义。如果A实现了CloneableQ同时有一个引用指向BQ该B实现为单例模式,如果直接复制内存q行深copy的话Q破坏了B的单例模式?nbsp;
4 方便且更灉|Q如果A引用一个不可变对象Q则内存deep copy是一U浪贏VShadow copyl了E序员更好的灉|性?nbsp;

如何clone 
clone三部曌Ӏ?nbsp;
1 声明实现Cloneable接口?nbsp;
2 调用super.clone拿到一个对象,如果父类的clone实现没有问题的话Q在该对象的内存存储中,所有父cd义的field都已lclone好了Q该cM的primitive和不可变cd引用也克隆好了,可变cd引用都是copy?nbsp;
3 把浅copy的引用指向原型对象新的克隆体?nbsp;
l个例子?nbsp;
class User implements Cloneable { 	String name; 	int age; 	@Override 	public User clone() throws CloneNotSupportedException { 		return (User) super.clone(); 	} } class Account implements Cloneable { 	User user; 	long balance; 	@Override 	public Account clone() throws CloneNotSupportedException { 		Account account = null; 		account = (Account) super.clone(); 		if (user != null) { 			account.user = user.clone(); 		} 		return account; 	} }


 

对clone的态度 

clone嘛,我觉得是个好东西Q毕竟系l默认实现已l帮我们做了很多事情了?nbsp;
但是它也是有~点的?nbsp;
1 手工l护clone的调用链。这个问题不大,E序员有责Q做好?nbsp;
2 如果class的field是个final的可变类Q就不行了。三部曲的第三步没有办法做了?nbsp;

考虑一个类对clone的态度Q有如下几种?nbsp;
1 公开支持Q好吧,按照clone三部曲实现吧。前提是父类支持Q公开或者默默)?nbsp;
2 默默支持Q不实现Cloneable接口Q但是在c里面有正确的protected的clone实现Q这P该类不支持cloneQ但是它的子cd果想支持的话也不妨碍?nbsp;
3 不支持:好吧Qؓ了明该目的Q提供一个抛CloneNotSupportedException 异常的protected的clone实现?nbsp;
4 看情冉|持:该类内部可以保存其他cȝ实例Q如果其他类支持则该cL持,如果其他cM支持Q该cL有办法,只有不支持?nbsp;


其他的选择 

可以用原型构造函敎ͼ或者静态copyҎ来手工制作一个对象的copy?nbsp;
好处是即使class的field为finalQ也不会影响该方法的使用。不好的地方是所有的primitive赋值都得自q护?nbsp;


和Serializable的比?/strong> 

使用Serializable同样可以做到对象的clone。但是: 
Cloneable本n是为clone设计的,虽然有一些缺点,但是如果它可以clone的话无疑用它来做clone比较合适。如果不行的话用原型构造函敎ͼ或者静态copyҎ也可以?nbsp;

Serializable制作clone的话Q添加了太多其它的东西,增加了复杂性?nbsp;
1 所有的相关的类都得支持Serializable。这个相比支持Cloneable只会工作量更?nbsp;
2 Serializabled了更多的意义Q除了提供一个方法用Serializable制作CloneQ该cȝ于也d了其它的public APIQ如果一个类实现了SerializableQ等于它?q制形式已l是其API的一部分了,不便于该cM后内部的改动?nbsp;
3 当类用Serializable来实现cloneӞ用户如果保存了一个老版本的对象2q制Q该cdU,用户用新版本的类反系列化该对象,再调用该对象用Serializable实现的clone。这里ؓ了一个clone的方法又引入了类版本兼容性的问题。不划算?nbsp;


性能 

不可否认QJVM来快了?nbsp;
但是pȝ默认的native实现q是挺快的?nbsp;
clone一个有100个元素的int数组Q用pȝ默认的clone比静态copyҎ?倍左叟?/span> 

Snape 2012-04-11 14:08 发表评论
]]>
java instanceQ)http://www.shnenglu.com/chenglong7997/articles/170905.htmlSnapeSnapeWed, 11 Apr 2012 06:07:00 GMThttp://www.shnenglu.com/chenglong7997/articles/170905.htmlhttp://www.shnenglu.com/chenglong7997/comments/170905.htmlhttp://www.shnenglu.com/chenglong7997/articles/170905.html#Feedback0http://www.shnenglu.com/chenglong7997/comments/commentRss/170905.htmlhttp://www.shnenglu.com/chenglong7997/services/trackbacks/170905.html java 中的instanceof q算W是用来在运行时指出对象是否是特定类的一个实例。instanceof通过q回一个布值来指出Q这个对象是否是q个特定cL者是它的子类的一个实例?br /> 用法Q?br />result = object instanceof class
参数Q?br />ResultQ布类型?br />ObjectQ必选项。Q意对象表辑ּ?br />ClassQ必选项。Q意已定义的对象类?br />说明Q?br />如果 object ?class 的一个实例,?instanceof q算W返?true。如?object 不是指定cȝ一个实例,或?object ?nullQ则q回 false?/p>

例子如下Q?/p>


package com.instanceoftest;

 interface A{}
 class B implements A{
  
 }
 class C extends B {
  
 }
 
 class instanceoftest {
  public static void main(String[] args){
     A a=null;
     B b=null;
     boolean res; 
     
     System.out.println("instanceoftest test case 1: ------------------");
       res = a instanceof A; 
       System.out.println("a instanceof A: " + res);
       
       res = b instanceof B;
       System.out.println("b instanceof B: " + res);
       
     System.out.println("\ninstanceoftest test case 2: ------------------");   
     a=new B();
     b=new B();
     
     res = a instanceof A; 
     System.out.println("a instanceof A: " + res);
     
     res = a instanceof B;
     System.out.println("a instanceof B: " + res);

     res = b instanceof A;
     System.out.println("b instanceof A: " + res);
     
     res = b instanceof B;
     System.out.println("b instanceof B: " + res);
    
     System.out.println("\ninstanceoftest test case 3: ------------------");
     B b2=(C)new C();
     
     res = b2 instanceof A;
     System.out.println("b2 instanceof A: " + res);
     
     res = b2 instanceof B;
     System.out.println("b2 instanceof B: " + res);
     
     res = b2 instanceof C;
     System.out.println("b2 instanceof C: " + res);
  }
}


/*
result:


instanceoftest test case 1: ------------------
a instanceof A: false
b instanceof B: false

instanceoftest test case 2: ------------------
a instanceof A: true
a instanceof B: true
b instanceof A: true
b instanceof B: true

instanceoftest test case 3: ------------------
b2 instanceof A: true
b2 instanceof B: true
b2 instanceof C: true



Snape 2012-04-11 14:07 发表评论
]]>
析JAVA之垃圑֛收机?/title><link>http://www.shnenglu.com/chenglong7997/articles/170904.html</link><dc:creator>Snape</dc:creator><author>Snape</author><pubDate>Wed, 11 Apr 2012 06:06:00 GMT</pubDate><guid>http://www.shnenglu.com/chenglong7997/articles/170904.html</guid><wfw:comment>http://www.shnenglu.com/chenglong7997/comments/170904.html</wfw:comment><comments>http://www.shnenglu.com/chenglong7997/articles/170904.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/chenglong7997/comments/commentRss/170904.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/chenglong7997/services/trackbacks/170904.html</trackback:ping><description><![CDATA[     摘要:   对于JAVA~程和很多类似C、C++语言有一个巨大区别就是内存不需要自己去free或者deleteQ而是由JVM垃圾回收机制d成的。对于这个过E很多h一直比较茫然或者觉得很Q得在写程序的q程不太考虑它的感受Q其实知道一些内在的原理Q帮助我们编写更加优U的代码是非常有必要的。本文从以下几个斚wq行阐述Q?、finalize()Ҏ2、System.gc()Ҏ及一些实用方??..  <a href='http://www.shnenglu.com/chenglong7997/articles/170904.html'>阅读全文</a><img src ="http://www.shnenglu.com/chenglong7997/aggbug/170904.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/chenglong7997/" target="_blank">Snape</a> 2012-04-11 14:06 <a href="http://www.shnenglu.com/chenglong7997/articles/170904.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JavaE序最Ҏ犯的21U错?/title><link>http://www.shnenglu.com/chenglong7997/articles/170903.html</link><dc:creator>Snape</dc:creator><author>Snape</author><pubDate>Wed, 11 Apr 2012 06:05:00 GMT</pubDate><guid>http://www.shnenglu.com/chenglong7997/articles/170903.html</guid><wfw:comment>http://www.shnenglu.com/chenglong7997/comments/170903.html</wfw:comment><comments>http://www.shnenglu.com/chenglong7997/articles/170903.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/chenglong7997/comments/commentRss/170903.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/chenglong7997/services/trackbacks/170903.html</trackback:ping><description><![CDATA[<p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">   1.Duplicated <a title="Powered by Text-Enhance" id="_GPLITA_0" in_rurl="http://www.textsrv.com/click?v=VVM6MTc5MDM6MzM2OmNvZGU6MmNiNDRlYmZmYmExZTcxODk1YTkwYjYyZDY2ZmYyYjY6ei0xMDQ3LTE0MjEyOnd3dy5qYXZhM3ouY29t" style="color: #0066ff; ">Code</a></p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">  代码重复几乎是最常见的异味了。他也是Refactoring的主要目标之一。代码重复往往来自于copy-and-paste的编E风根{与他相对应OAOO是一个好pȝ的重要标志?/p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">  2.Long method</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">  它是传统l构化的“遗毒”。一个方法应当具有自我独立的意图Q不要把几个意图攑֜一赗?/p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">  3.Large Class</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">  大类是你把太多的责Ml了一个类。这里的规则是One Class One Responsibility.</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">  4.Divergent Change</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">  一个类里面的内容变化率不同。某些状态一个小时变一ơ,某些则几个月一q才变一ơ;某些状态因斚w的原因发生变化,而另一些则因ؓ其他斚w的原因变一ơ。面向对象的抽象是把相对不变的和相对变化相隔离。把问题变化的一斚w和另一斚w盔RR这使得q些相对不变的可以重用。问题变化的每个斚w都可以单独重用。这U相异变化的共存使得重用非常困难?/p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">  5.Shotgun Surgery</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">  q正好和上面相反。对pȝ一个地方的改变涉及到其他许多地方的相关改变。这些变化率和变化内容相似的状态和行ؓ通常应当攑֜同一个类中?/p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">  6.Feature Envy</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">  对象的目的就是封装状态以及与q些状态紧密相关的行ؓ。如果一个类的方法频J用get Ҏ存取其他cȝ状态进行计,那么你要考虑把行为移到涉及状态数目最多的那个cR?/p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">  7.Data Clumps</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">  某些数据通常像孩子一h玩耍:一起出现在很多cȝ成员变量中,一起出现在许多Ҏ的参CQ这些数据或许应该自q立Ş成对象?/p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">  8.Primitive Obsession</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">  面向对象的新手通常习惯使用几个原始cd的数据来表示一个概c譬如对于范_他们会用两个数字。对于MoneyQ他们会用一个QҎ来表C。因Z没有使用对象来表N题中存在的概念,q得代码变的难以理解,解决问题的难度大大增加。好的习惯是扩充语言所能提供原始类型,用小对象来表C围、金额、{化率、邮政编码等{?/p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">  9.Switch Statement</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">  Z帔R的开兌句是OO 的大敌,你应当把他变为子cRstate或strategy.</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">  10. Parallel Inheritance Hierarchies</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">  q行的承层ơ是shotgun surgery的特D情c因为当你改变一个层ơ中的某一个类Ӟ你必d时改变另外一个层ơ的q行子类?/p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; "> 11. Lazy Class</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">  一个干zM多的cR类的维护需要额外的开销Q如果一个类承担了太的责QQ应当消除它?/p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">  12. Speculative Generality</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">  一个类实现了从未用到的功能和通用性。通常q样的类或方法唯一的用htestcase.不要犹UQ删除它?/p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">  13. Temporary Field</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">  一个对象的属性可能只在某些情况下才有意义。这L代码难以理解。专门徏立一个对象来持有q样的孤儿属性,把只和他相关的行为移到该cR最常见的是一个特定的法需要某些只有该法才有用的变量?/p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">  14. Message Chain</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">  消息铑֏生于当一个客户向一个对象要求另一个对象,然后客户又向q另一对象要求另一个对象,再向q另一个对象要求另一个对象,如此如此。这Ӟ你需要隐藏分z?/p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">  15. Middle Man</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">  对象的基本特性之一是装Q而你l常会通过分派d现封装。但是这一步不能走得太q,如果你发C个类接口的一大半Ҏ都在做分z,你可能需要移去这个中间h?/p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">  16. Inappropriate Intimacy</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">  某些cȝ互之间太亲密Q它们花费了太多的时间去砖研别h的私有部分。对人类而言Q我们也怸应该太假正经Q但我们应当让自qcM格遵守禁Ʋ主义?/p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">  17. Alternative Classes with Different Interfaces</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">  做相同事情的Ҏ有不同的函数signatureQ一致把它们往cdơ上U,直至协议一致?/p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">  18. Incomplete Library Class</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">  要徏立一个好的类库非常困难。我们大量的E序工作都基于类库实现。然而,如此q泛而又相异的目标对库构提Z苛刻的要求。库构徏者也不是万能的。有时候我们会发现库类无法实现我们需要的功能。而直接对库类的修Ҏ非常困难。这时候就需要用各种手段q行Refactoring.</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">  19. Data Class</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">  对象包括状态和行ؓ。如果一个类只有状态没有行为,那么肯定有什么地方出问题了?/p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">  20. Refused Bequest</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">  类传下来很多行为和状态,而子cd是用了其中的很小一部分。这通常意味着你的cdơ有问题?/p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">  21. Comments</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">  l常觉得要写很多注释表示你的代码难以理解。如果这U感觉太多,表示你需要Refactoring.</p><img src ="http://www.shnenglu.com/chenglong7997/aggbug/170903.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/chenglong7997/" target="_blank">Snape</a> 2012-04-11 14:05 <a href="http://www.shnenglu.com/chenglong7997/articles/170903.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>java启动方式http://www.shnenglu.com/chenglong7997/articles/170902.htmlSnapeSnapeWed, 11 Apr 2012 06:01:00 GMThttp://www.shnenglu.com/chenglong7997/articles/170902.htmlhttp://www.shnenglu.com/chenglong7997/comments/170902.htmlhttp://www.shnenglu.com/chenglong7997/articles/170902.html#Feedback0http://www.shnenglu.com/chenglong7997/comments/commentRss/170902.htmlhttp://www.shnenglu.com/chenglong7997/services/trackbacks/170902.html
  • 使用 -classpath 选项:
    java -classpath C:\hello\build\classes test.HelloWorld
  • 使用 -cp 选项,  -classpath 的简?
    java -cp C:\hello\build\classes test.HelloWorld
  • 使用 -Djava.class.path 讄pȝ属?
    java -Djava.class.path=C:\hello\build\classes test.HelloWorld
  • 使用 CLASSPATH 讄环境变量:
    set CLASSPATH=C:\hello\build\classes;
    java test.HelloWorld
  • 使用当前目录为启动目?
    cd C:\hello\build\classes;
    java test.HelloWorld
  • 打包所有类q入一个jar包中Qƈ讄对应?code> META-INF/MANIFEST.MF 文g
    文g内容Q?span style="color: #ff0000; ">Main-Class: test.HelloWorld 
    java -jar hello-world.jar
    注意Q当使用-jar选项Ӟ-classpath -cpq两个选项被忽略Q?/li>
  • 写Bash文gq行加蝲
  • 如果你用的是JDK6Q加载类路径q支?通配W加载所有jar文gQjava -cp ./lib/* test.HelloWorld


  • Snape 2012-04-11 14:01 发表评论
    ]]>
    java启动方式http://www.shnenglu.com/chenglong7997/articles/170901.htmlSnapeSnapeWed, 11 Apr 2012 06:01:00 GMThttp://www.shnenglu.com/chenglong7997/articles/170901.htmlhttp://www.shnenglu.com/chenglong7997/comments/170901.htmlhttp://www.shnenglu.com/chenglong7997/articles/170901.html#Feedback0http://www.shnenglu.com/chenglong7997/comments/commentRss/170901.htmlhttp://www.shnenglu.com/chenglong7997/services/trackbacks/170901.html
  • 使用 -classpath 选项:
    java -classpath C:\hello\build\classes test.HelloWorld
  • 使用 -cp 选项,  -classpath 的简?
    java -cp C:\hello\build\classes test.HelloWorld
  • 使用 -Djava.class.path 讄pȝ属?
    java -Djava.class.path=C:\hello\build\classes test.HelloWorld
  • 使用 CLASSPATH 讄环境变量:
    set CLASSPATH=C:\hello\build\classes;
    java test.HelloWorld
  • 使用当前目录为启动目?
    cd C:\hello\build\classes;
    java test.HelloWorld
  • 打包所有类q入一个jar包中Qƈ讄对应?code> META-INF/MANIFEST.MF 文g
    文g内容Q?span style="color: #ff0000; ">Main-Class: test.HelloWorld 
    java -jar hello-world.jar
    注意Q当使用-jar选项Ӟ-classpath -cpq两个选项被忽略Q?/li>
  • 写Bash文gq行加蝲
  • 如果你用的是JDK6Q加载类路径q支?通配W加载所有jar文gQjava -cp ./lib/* test.HelloWorld


  • Snape 2012-04-11 14:01 发表评论
    ]]>
    java重蝲重写陷阱Q?Q?/title><link>http://www.shnenglu.com/chenglong7997/articles/170900.html</link><dc:creator>Snape</dc:creator><author>Snape</author><pubDate>Wed, 11 Apr 2012 06:00:00 GMT</pubDate><guid>http://www.shnenglu.com/chenglong7997/articles/170900.html</guid><wfw:comment>http://www.shnenglu.com/chenglong7997/comments/170900.html</wfw:comment><comments>http://www.shnenglu.com/chenglong7997/articles/170900.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/chenglong7997/comments/commentRss/170900.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/chenglong7997/services/trackbacks/170900.html</trackback:ping><description><![CDATA[<p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; "><strong>隐藏QhideQ:</strong>子类的某个字Dc静态方法、成员内部类与其父类的具有相同名字(对于静态方法还需要相同的参数列表Q,此时父类对应的字Dc静态方法、成员内部类p隐藏了?/p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">举个例子Q天鹅(SwanQ是会飞的,而丑鸭QUglyDuckQ小时候是不会飞的Q看看下面的代码Q看看能够打印出什么?/p><pre style="color: #666666; font-size: 12px; line-height: normal; background-color: #ffffff; "><ol><li>class Swan {  </li><li>    public static void fly() {  </li><li>        System.out.println("swan can fly ...");  </li><li>    }  </li><li>}  </li><li> </li><li>class UglyDuck extends Swan {     </li><li>    public static void <a title="Powered by Text-Enhance" id="_GPLITA_0" in_rurl="http://www.textsrv.com/click?v=VVM6MTg3NzM6MzM2OmZseTozMjE3Yzc1Mjc3MzgxY2IxMDRhYTkyZjZjMjNlNGQwZTp6LTEwNDctMTQyMTI6d3d3LmphdmEzei5jb20%3D" style="font-family: Tahoma; color: #0066ff; ">fly</a>() {  </li><li>        System.out.println("ugly duck can't fly ...");  </li><li>    }  </li><li>}  </li><li> </li><li>public class TestFly {    </li><li>    public static void main(String [] args) {  </li><li>        Swan swan = new Swan();  </li><li>        <span style="background-color: #ffff00; ">Swan </span>uglyDuck = new UglyDuck();  </li><li>        swan.fly();  </li><li>        uglyDuck.fly();  </li><li>    }  </li><li>} </li></ol> </pre><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">按道理的话,我们认ؓ应该是输Z句不同的l果Q因为我们可能认?UglyDuck l承?Swan q且“重写”?fly() ҎQ而且?main() Ҏ?Swan uglyDuck = <span style="color: #0000ff; ">new</span> UglyDuck();  也表明了 uglyduck 实际上是 UglyDuck cd的,因此构成了多态行为?/p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">其实Q运行结果是两句“swan can fly ...”Qؓ什么会q样子?原因有下Q?/p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">1、父c?Swan 中的 static 静态方?fly() 是不能被重写的,上一D|寚w写二字用了双引号Q?/p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">2、尽子c?UglyDuck 中的 fly() Ҏ与父cM的有一致的参数列表Q但是对?static Ҏ来说Q这叫隐藏(hideQ,而不是重写(overrideQ;</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">3、对?static ҎQ根本不存在像多态那L动态分z机ӞJVM 不会Ҏ对象引用的实际类型来调用对应的重写方法。这一点在个例子中是最重要的?/p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">对于 static ҎQ我们称之ؓ<strong>cL?/strong>Q不?strong>实例Ҏ</strong>Q对 static Ҏ的调用直接用所属类名加个点pQ如 UglyDuck.fly() 。而实例方法就不得不用对象引用来获得其可讉KҎ的调用权。在上面的例?main() 中的 uglyDuck.fly() 语句QJVM Ҏ据不会去判断 uglyDuck 引用的究竟是什么类型,既然调用的是 fly() ҎQ那?JVM 只会Ҏ uglyDuck 的声明类型(?Swan c)去获得该 static Ҏ的调用。根本就谈不上多?#8230;</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">q就说明Q?strong>最好避免用对象引用的方式来讉K一?static Ҏ</strong>。此外,<strong>别以为在l承关系上的父类、子cd要方法名、参数列表一致就是重写(overrideQ而构成多态,其实q得看看父类中的Ҏ有没有被什么修饰符声明</strong>Q在q个例子中是 static 修饰的)。再?final 修饰W的Ҏ则表明不可被子类重写Q即Ҏ名、参数列表不能和父类完全一致。在我看来,q一cM饰符p明了Ҏ、变量、字D늭Ҏ的性质Q或者是w䆾?/p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">对于隐藏QhideQ,实际上是Z使得父类中的该方法、字Dc内部类{不允许再被下一U承树的子子类所l承。说起隐藏,我想赗代码大?2》当中刚好看q的内容Q作者认为把握住信息隐藏的原则来思考Y件构优于面向对象原则。有Ҏ象难懂,书中q讲到封装、模块化和抽象等几个概念Q徏议看看,我也要回q头d啃啃q些抽象概念?/p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">要修改上面代码,只需要去掉两?static 则可Q那构成多态了。《Java 解惑》中其他谜题q讲到多U该注意的地方,可以看看?/p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; "><strong>结Q?/strong></p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">1、注意掌握重写(overrideQ与隐藏QhideQ的异同点:相同点就是两者都是相对于l承树中父类、子cL_而不同点是其目的以及所造成的效果。别把重写和隐藏h在一起了Q?/p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">2、对?static ҎQ要避免用具体的对象引用来调用,而应该简单的用其所属类名进行调用即可?/p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; "> <strong>遮蔽QshadowQ:</strong>其实是qx我们可能遇到的窄作用域的变量名、方法名、类名等其他相同名字的变量、方法、类屏蔽掉的现象?/p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">例如Q最常见的就是局部变量将cd例变量屏蔽了。其实,遮蔽q个词我之前好像也没什么印象,不过作用域屏蔽这U情冉|们大多应该会避免的了Q因堂上、教材上对于变量作用域的内容已经讲解q了Q尽没有这么一个术语。此时如果想要获得被遮蔽实体的引用、调用,则只能通过完整的限定名dC。不q有一些情况可能是Ҏ引用不到的Q被屏蔽得太严密了?/p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; "> <strong>遮掩QobscureQ:</strong>一个变量可以遮掩具有相同名字的一个类Q只要它们都在同一个范围内Q如果这个名字被用于变量与类型都被许可的范围Q那么它引用到变量上。相似地Q一个变量名或一个类名可以遮掩一个包。遮掩是唯一一U两个名字位于不同的名字I间的名字重用Ş式,q些名字I间包括Q变量、包、方法或cR如果一个类型或一个包被遮掩了Q那么你不能通过其简单名引用到它Q除非是在这样一个上下文环境中,卌法只允许在其名字I间中出CU名字。遵守命名习惯就可以极大地消除生遮掩的可能性?/p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">其实Q遮掩这个术语我更是完全没听q了Q上面这一D|从《Java 解惑》中引用q来的。我觉得Q如果代码是一个h所写,或者团队中大家都遵守了一定的命名规范Q而且也各自分配了一定职责,那么遮掩q种情况应该是可以避免的。同P需要用完全限定名来引用被遮掩掉的实体Q如下:</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">用前面例子的代码大概是q种情况Q?br /></p><pre style="color: #666666; font-size: 12px; line-height: normal; background-color: #ffffff; "><ol><li>public class TestFly {    </li><li>    // 如此变量? </li><li>    static String <span style="background-color: #ffff00; ">System </span>= "system";  </li><li>    public static void main(String [] args) {  </li><li> </li><li>//      String System = "hao";    </li><li>        // ~译不通过  </li><li>//      <span style="background-color: #ffff00; ">System.out.println("No"); </span> </li><li>        // ~译通过  </li><li>        java.lang.System.out.println("OK");  </li><li>    }  </li><li>}</li></ol></pre><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; "><strong>结Q?/strong></p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">1、我觉得Q在文章标题当中的五个名词当中,ؓ前面三个最为重要,陷阱炸弹也多多,而且文中所讲仅仅是那么一丁点儿相关的Q大量更l节的还得慢慢发玎ͼ</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">2、就后面两个名词,也就是这两种情况不常见,但了解一下记在脑里还是不错的Q毕竟ؓ自己增加了专业词汇量Q?/p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">3、最后,是各位也看看《Java 解惑》然后也告诉我一些炸弹型陷阱之类的,呵呵...学习快乐Q加油!</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">本文 “蚂蚁” 博客Q请务必保留此出处http://haolloyin.blog.51cto.com/1177454/372911</p><img src ="http://www.shnenglu.com/chenglong7997/aggbug/170900.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/chenglong7997/" target="_blank">Snape</a> 2012-04-11 14:00 <a href="http://www.shnenglu.com/chenglong7997/articles/170900.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>java重蝲重写陷阱http://www.shnenglu.com/chenglong7997/articles/170899.htmlSnapeSnapeWed, 11 Apr 2012 05:59:00 GMThttp://www.shnenglu.com/chenglong7997/articles/170899.htmlhttp://www.shnenglu.com/chenglong7997/comments/170899.htmlhttp://www.shnenglu.com/chenglong7997/articles/170899.html#Feedback0http://www.shnenglu.com/chenglong7997/comments/commentRss/170899.htmlhttp://www.shnenglu.com/chenglong7997/services/trackbacks/170899.html  看《重构(注释版)》中“装集合QEncapsulate CollectionQ?#8221;一节时Q由于该重构手法对于不同?Java 版本会有相对应不同的处理方式Q于是注释者在旁边l出提示QJava 2 中的?Collections API 主要是由《Java 解惑》、《Effective Java》这两本书的作者开发改q的。我惻Iq可真是一个大消息QJava cd的开发者所写的书一定得看,开发者肯定深入探寻过 Java 内部机制Q说不定能从书中获得未知的知识点呢?/p>

    好在我记得自q脑里下蝲q《Java 解惑Q中文版Q》的清晰电子版,于是改变路线Q看赯本书来了。真是不看不知道Q一看吓一跻I里面?95 ?Java 谜题Q一点点地看了之后,我是既惭愧又兴奋Q因为里面的题真的是“莫名其妙”Q直白点是Q十有八九是想都想不出来的,⊙H?#8857;b…惌真正掌握 Java Q我觉得《Java 解惑》是不得不看的。大多谜题可谓是前所未见的炸弹,一不小心就 over 了?/p>

    快点切入正题Q如文章标题所C,我从《Java 解惑》中g认识C几个名词Q之所以用g修饰Q因为重载、重写、隐藏这几个接触q了Q而遮蔽、遮掩或许是见过但也忘光了。就整理一下文中的一些与此相关的 Java 谜题用自q理解描述一下吧?/p>

    重蝲QoverloadQ:同一个类中名字相同但参数列表不同的多个方法之间的关系?/p>

    关于重蝲Q是我们比较熟悉的了Q最常见的就是运用在cȝ多个构造函CQ看一?Java 帮助文档Q就可以明白q一情况了。而在《Java 解惑》中Q作者给Z下面一个谜题:

    1. public class Confusing {   
    2.       
    3.     private Confusing(Object o) {   
    4.         System.out.println("Object");   
    5.     }   
    6.       
    7.     private Confusing(double[] dArray) {   
    8.         System.out.println("double array");   
    9.     }   
    10.       
    11.     public static void main(String[] args) {   
    12.         new Confusing(null);   
    13.     }   
    14. }  

    问此?main() 中将会输Z么?初初一看,q没有多分析p得应该是输出“Object”Q虽然Java中的数组实际上也是引用类型,但毕竟Object 是所有类的最l父c,而且目前 JDK p参数中的基本数据cd变量也可以被自动想上转型成包装类而成?Object 的子cR于是我保守一点地p为参?null 应该是匹配到 Object 那个重蝲ҎM?/p>

    可是q答案是错的QJVM 对于重蝲Ҏ的解析是q样的:先找出方法名匚w的所有可能的ҎQ然后根据传q来的Ş参再ơ筛选出可能的重载方法;最后才是在q些Ҏ中匹配到一?strong>最_的一个方法?/span>于是Q上面的那个谜题变成确定哪一个才是最_q一点子上了?/p>

    而关于如何判断最_Q有q样的机Ӟ如果某个重蝲Ҏ能够接收所有传递给另一个重载方法的实参cdQ那么对于参数列表来看,昄后者至是前者的子集Q当然也更_了?/span>

    回到谜题上来QConfusing(Object)可以接受M传递给 Confusing(double[ ])的参敎ͼM数组引用最l能够都?Object 对象Q,因此 main() 中的 null 应该是被 JVM 匚w?Confusing(double[ ]) 中,也就有了与我所认ؓ的结果相反的输出了?/p>

    结Q?/strong>q个谜题表明了我们在写重载方法时Q最好是明确地区分出各个Ҏ中的参数列表Q不要让彼此之间有互相包含、模p不清的关系。虽焉载是Z在相同名字的Ҏ中传入实参,?JVM 动态解析选择合适的ҎQ但有时也很Ҏ陷入q种方便背后所带来的地雷区当中。其中一U可行的办法是Q?span style="background-color: #ffff00; ">提供不同的方法名。但是构造函数的名字一定得相同的啊Q?/p>

    实际上,在《重构与模式》第六章中,作者用他自w的目l验?#8220;创徏”q一话题展开了讲解,q是构造函敎ͼ也有很好的重构手法将其清晰地区分开来,不用重载而是用不同名U的ҎQ将原本需要重载的构造函数委托给h最大完整参数列表的U有构造函C。又是一本经典,值得看哦…

     

    重写QoverrideQ:父类中的实例Ҏ被其子类重新实现。既然是实例ҎQ那是?static 修饰的了Q否则就?static 静态方法了Q那叫做cL?/strong>。在我看来,正是重写q一机制的存在,才ؓ多态机制提供了基础。或?implements Q实玎ͼ一?interface Q接口)中所声明的方法也能成为重写,因ؓ interface 的一部分存在原因也是Z多态?/p>

    对于重写Q在《Java 解惑》中有下面这个谜题让我明白:l对不能在构造函C调用可能会被子类重写的方法?/strong>

    1. class Point {  
    2.     protected final int x, y;  
    3.     private final String name;  
    4.       
    5.     Point(int x, int y) {  
    6.         this.x = x;  
    7.         this.y = y;  
    8.         name = makeName();  
    9.     }  
    10.  
    11.     protected String makeName() {  
    12.         return "[" + x + "," + y + "]";  
    13.     }  
    14.       
    15.     public final String toString() {  
    16.         return name;  
    17.     }  
    18. }  
    19.  
    20. public class ColorPoint extends Point {  
    21.     private final String color;  
    22.       
    23.     ColorPoint(int x, int y, String color) {  
    24.         super(x, y);  
    25.         this.color = color;  
    26.     }  
    27.       
    28.     protected String makeName() {  
    29.        return super.makeName() + ":" + color;  
    30.     }  
    31.       
    32.     public static void main(String[] args) {  
    33.         System.out.println(new ColorPoint(4, 2, "purple"));  
    34.     }  

    此时E序q行l果q不是我们所想的 [4,2]:purple Q而是 [4,2]:null 。ؓ什么会q样Q看看下面用程标号注释q的代码Q就能理解了?/p>

    1. class Point {  
    2.     protected final int x, y;  
    3.     private final String name;  
    4.  
    5.     Point(int x, int y) {  
    6.         this.x = x;  
    7.         this.y = y;  
    8.         name = makeName();// 3. ׃被子c重写过的makeName()  
    9.     }  
    10.  
    11.     protected String makeName() {  
    12.         return "[" + x + "," + y + "]";  
    13.     }  
    14.       
    15.     public final String toString() {  
    16.         return name;  
    17.     }  
    18. }  
    19.  
    20. public class ColorPoint extends Point {  
    21.     private final String color;  
    22.  
    23.     ColorPoint(int x, int y, String color) {  
    24.         super(x, y); // 2. 调用Point父类构造函? 
    25.         this.color = color; // 5. 初始?nbsp;color Q可是已l太晚了...  
    26.     }  
    27.  
    28.     protected String makeName() {  
    29.         // 4. 问题来了Q它在子cL造函C前调用了  
    30.         // 而此时的 color ?nbsp;null 的啊Q!Q? 
    31.         return super.makeName() + ":" + color;  
    32.     }  
    33.  
    34.     public static void main(String[] args) {  
    35.         // 1. 调用ColorPoint子类构造函? 
    36.         System.out.println(new ColorPoint(4, 2, "purple"));  
    37.     }  

    思\很清CQColorPoint 子类中的构造函C?this.color = color; q未被执行到将 null 作ؓ String color 的g。正是因U来来回回的调用使得E序变得不正怺Q在我看来,有那么一点类g“回调”的意思?/p>

    要去除这U代码结构的不合理,最好还是把 Point 父类构造函C调用 makeName() Ҏ一句去掉,然后?toString  中判断ƈ调用 makeName() 来ؓ name 初始化,如下Q?/p>

    结Q?/strong>重写对于多态固焉要,但是设计Z正确的代码结构的话,原本惌的多态就会被扭曲甚至造成反效果。于是,l对不要在构造函C调用可能会被子类重写的方法?/p>

     好像文字太多的文章看了容易人晕乎乎的,啰啰嗦嗦、模模糊p地才写了两个词儿,q是分开来写吧。其实,看了一部分《Java 解惑》才明白q有好多好多 Java 里面该注意的要点。要惛_适当的时候L清各U语法上、机制上的知识点Q难啊!

    记得高中语文课上读过一片抒情的散文Q标题ؓ“?#8212;—香雪Q?#8221;而我看了《Java 解惑》,惌“?#8212;—JavaQ?#8221;~~~~(&gt;_&lt;)~~~~

    ȝQ?/strong>

    1、在我们~程领域Q好书真的是一大把Q就看自己有没时间、有没策略地d收了Q?/p>

    2、有时候看好书时留意作者对其他书籍?#8220;友情链接”Q或者出版社推荐的相关书c,q样p够免去自己慢慢搜d书的q程了,O(∩_∩)O哈!

    本文 “蚂蚁” 博客Q请务必保留此出处http://haolloyin.blog.51cto.com/1177454/372691



    Snape 2012-04-11 13:59 发表评论
    ]]>java 静态数?/title><link>http://www.shnenglu.com/chenglong7997/articles/170898.html</link><dc:creator>Snape</dc:creator><author>Snape</author><pubDate>Wed, 11 Apr 2012 05:57:00 GMT</pubDate><guid>http://www.shnenglu.com/chenglong7997/articles/170898.html</guid><wfw:comment>http://www.shnenglu.com/chenglong7997/comments/170898.html</wfw:comment><comments>http://www.shnenglu.com/chenglong7997/articles/170898.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/chenglong7997/comments/commentRss/170898.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/chenglong7997/services/trackbacks/170898.html</trackback:ping><description><![CDATA[<span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; text-align: -webkit-left; background-color: #ffffff; ">  前面讨论的this关键字,典型地反映了随着对象引用的不同,其变量和操作亦不同,体现了面向对象编E的内涵。但是,有时在程序中的要求正好与此相?#8212;—需要代表整个类的数据。Java提供的静态数据(static dataQ就是专门用来实现这一要求的?/span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; text-align: -webkit-left; background-color: #ffffff; " /><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; text-align: -webkit-left; background-color: #ffffff; " /><span id="dybnpzn" class="STYLE1" style="color: #0000ff; font-family: Tahoma; font-size: 12px; line-height: normal; text-align: -webkit-left; background-color: #ffffff; ">二、类数据</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; text-align: -webkit-left; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; text-align: -webkit-left; background-color: #ffffff; ">   静态数据属于全体对象,是所有对象共享的数据Q或cL据。静态常量也UCؓcd量;静态变量也U类变量。在解决实际问题中经怼遇到cL据。例如,Math.PIQMath.EҎ有对象的术q算都是一LQ它们被定义为Mathcȝ静态常量?/span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; text-align: -webkit-left; background-color: #ffffff; " /><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; text-align: -webkit-left; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; text-align: -webkit-left; background-color: #ffffff; ">    再例如,E收比率在计税ƾ时Ҏ有定义的对象都适用Q也是静态数据的典型例子。有Ӟ我们需要统计创Z多少个对象,或者有多少个对象调用了某个ҎQ或者应用了某个操作{等Q这需要在E序中用静态数据来完成q些d。类数据可以是private或public?/span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; text-align: -webkit-left; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; text-align: -webkit-left; background-color: #ffffff; ">如下是定义静态数据的典型例子?/span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; text-align: -webkit-left; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; text-align: -webkit-left; background-color: #ffffff; ">?Q定义静态变量?/span> <br /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">private static double accountLimit; //定义一个双_ֺ静态变?nbsp;</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">private static int userCount = 0; //定义一个整数静态变量ƈ赋?/span> <br /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">public static String welcome = "Java is hot!"; //定义一个字W串静态变量ƈ赋?/span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">?Q定义静态常量?/span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">private static final float TAX_RATE = 0.0875f; //定义一个Q炚w态常?/span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">public static final double EARTH_MASS = 5.972e24; //定义一个双_ֺ静态常?/span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">public static final int MONTH_IN_YEAR = 12; //定义一个整数静态常?/span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">注意 静态常量必d定义时赋倹{否则ؓ非法?/span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">如下是用静态数据的典型例子Q?/span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">public FutureValue() { //构造器</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">  //对对象数据初始化的各语句</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">  ...</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">  userCount++Q?//每创Z个对象,都对原来l计用户数目的静态变量userCount?</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">}</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">public FutureValue(String name) {</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">  this.name = name;</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">  //对其他各变量初始化的语句</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">  ...</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">  userCount++; //同上</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">}</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">以上例子表示无论以哪个构造器创徏对象Q对静态变量userCount都执行加1Q达到统计对象的目的。如果执行下列输句:</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">System.out.println(myFutureValue.getUserCount()); //用对象调?/span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">其输出gQ?/span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">System.out.pritnln(FutureValue.getUserCount()); //用静态方法通过cȝ接调?/span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">完全一栗?/span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">静态数据通常由静态方法来调用?/span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #0000ff; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">三?属于所有对?/span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">   静态数据ؓ什么属于整个类Q或cM的所有对象呢Q这是因为它们被储存在特D指定的存储器中。进一步讲Q静态数据储存在c访问区的储存空间。这个储存空间是q个cM表的所有对象共享的Q它的访问生命期和这个类相同?/span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">    而实例数据分别储存在代表每个对象的一D存储区域中。假设我们创Z100个对象,那么有100个这L储存区域存在。即每个对象都有它自q立存储区域,用来存储它所h的所有实例数据。这个存储区域的讉K生命期和对象相同?/span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #0000ff; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">四、静态数据原?/span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">   静态数据是cȝl成部分Q确定静态数据首先从cȝ设计入手Q分析和定cȝ应用范畴Q它所执行的运和操作Q包括确定数学公式以及运逻辑{。由此来定静态数据和实例数据。静态数据与实例数据本质的不同在于:</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">Q?Q?实例数据是在q个cȝ应用中,每个对象Q或大多数对象都h的、但各自有不同值的数据。例如,在计投资回报的E序中,每个对象都有姓名QnameQ、月投资额(monthlyInvestQ,q投资回报率QyearlyRateQ,以及投资q_yearsQ,但这些数据的值对每个对象来说Q是完全由对象来定的,与整个类无关Q与具体对象的Ş态有兟?/span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">Q?Q?静态数据是所有对象共享的数据。在q个cȝ应用中,无论哪一个对象,如果应用q个数据的话Q都必须h相同的|或者这个数据对所有对象都有意义,或者这个数据代表了所有对象的形态表征,与整个类有关?/span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">Ҏ以上分析Q确定静态数据可Ҏ如下原则Q?/span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">1Q?对类中的对象q行l计的数据应该确定ؓ静态数据?/span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">2Q?对类中所有对象,讄上下限的数据Q应该确定ؓ静态常量数据?/span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">3Q?在执行运的公式和解决问题的逻辑中,某个帔R对类中所有的对象Q如果有相同应用Q这个常量应该确定ؓ静态常量数据?/span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">4Q?用来对类中所有对象进行提C、询问、问候以及其他与具体对象无关的信息或数据Q应该确定ؓ静态常量数据?/span> <img src ="http://www.shnenglu.com/chenglong7997/aggbug/170898.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/chenglong7997/" target="_blank">Snape</a> 2012-04-11 13:57 <a href="http://www.shnenglu.com/chenglong7997/articles/170898.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>java重写Ҏ的原?/title><link>http://www.shnenglu.com/chenglong7997/articles/170896.html</link><dc:creator>Snape</dc:creator><author>Snape</author><pubDate>Wed, 11 Apr 2012 05:55:00 GMT</pubDate><guid>http://www.shnenglu.com/chenglong7997/articles/170896.html</guid><wfw:comment>http://www.shnenglu.com/chenglong7997/comments/170896.html</wfw:comment><comments>http://www.shnenglu.com/chenglong7997/articles/170896.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/chenglong7997/comments/commentRss/170896.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/chenglong7997/services/trackbacks/170896.html</trackback:ping><description><![CDATA[<span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; text-align: -webkit-left; background-color: #ffffff; "> 若想实现一个合格重写方法,而不是重载,那么必须同时满下面的要求! </span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; text-align: -webkit-left; background-color: #ffffff; " /><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; text-align: -webkit-left; background-color: #ffffff; " /><span style="color: #0000ff; font-family: Tahoma; font-size: 12px; line-height: normal; text-align: -webkit-left; background-color: #ffffff; ">A、重写规则之一Q?/span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; text-align: -webkit-left; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; text-align: -webkit-left; background-color: #ffffff; ">    重写Ҏ不能比被重写Ҏ限制有更严格的访问别?nbsp;</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; text-align: -webkit-left; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; text-align: -webkit-left; background-color: #ffffff; ">Q但是可以更q泛Q比如父cL法是包访问权限,子类的重写方法是public讉K权限。) 比如QObjectcL个toString()ҎQ开始重写这个方法的时候我们d易忘记public修饰W,~译器当然不会放qQ何教训我?的机会。出错的原因是Q没有加M讉K修饰W的Ҏh包访问权限,包访问权限比public当然要严gQ所以编译器会报错的?nbsp;</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; text-align: -webkit-left; background-color: #ffffff; " /><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; text-align: -webkit-left; background-color: #ffffff; " /><span style="color: #0000ff; font-family: Tahoma; font-size: 12px; line-height: normal; text-align: -webkit-left; background-color: #ffffff; ">B、重写规则之?/span><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; text-align: -webkit-left; background-color: #ffffff; ">Q?/span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; text-align: -webkit-left; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; text-align: -webkit-left; background-color: #ffffff; ">   参数列表必须与被重写Ҏ的相同?nbsp;</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; text-align: -webkit-left; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; text-align: -webkit-left; background-color: #ffffff; ">重写有个孪生的弟弟叫重蝲Q也是后面要出场的。如果子cL法的参数与父cd应的Ҏ不同Q那么就是你认错ZQ那是重载,不是重写?/span> <br /><br /><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; "><span style="color: #0000ff; ">C、重写规则之三:</span><br />   q回cd必须与被重写Ҏ的返回类型相同?br />父类ҎAQvoid eat(){} 子类ҎBQint eat(){} 两者虽然参数相同,可是q回cd不同Q所以不是重写?br />父类ҎAQint eat(){} 子类ҎBQlong eat(){} q回cd虽然兼容父类Q但是不同就是不同,所以不是重写?/p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; "><span style="color: #0000ff; ">D、重写规则之四:</span><br />   重写Ҏ不能抛出新的异常或者比被重写方法声明的查异常更q的查异常。但是可以抛出更,更有限或者不抛出异常?br />import java.io.*;<br />public class Test {<br />  public static void main (String[] args) {<br />   Animal h = new Horse();<br />   try {<br />     h.eat(); <br />   }<br />   catch (Exception e) {<br />   }<br /> }<br />}</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">class Animal {<br />  public void eat() throws Exception{<br />   System.out.println ("Animal is eating.");<br />   throw new Exception();<br />  }<br />}</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">class Horse extends Animal{<br />   public void eat() throws IOException{<br />    System.out.println ("Horse is eating.");<br />    throw new IOException();<br />  }<br />}<br /><br />q个例子中,父类抛出了检查异常ExceptionQ子cL出的IOException是Exception的子c,也即是比被重写的Ҏ抛出了更有限的异常,q是可以的。如果反q来Q父cL出IOExceptionQ子cL出更为宽泛的ExceptionQ那么不会通过~译的?br />注意Q这U限制只是针Ҏ查异常,至于q行时异常RuntimeException及其子类不再q个限制之中?/p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; "><span style="color: #0000ff; ">E、重写规则之五:</span><br />   不能重写被标识ؓfinal的方法?/p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; "><span style="color: #0000ff; ">F、重写规则之六:</span><br />  如果一个方法不能被l承Q则不能重写它?br />比较典型的就是父cȝprivateҎ。下例会产生一个有的现象?br />public class Test {<br />  public static void main (String[] args) {<br />   //Animal h = new Horse();<br />   Horse h = new Horse();<br />    h.eat();<br />   }<br />}</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">class Animal {<br />   private void eat(){<br />    System.out.println ("Animal is eating.");<br />    }<br /> }</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">class Horse extends Animal{<br />   public void eat(){<br />     System.out.println ("Horse is eating.");<br />   }<br />}<br />q段代码是能通过~译的。表面上看来q反了第六条规则Q但实际上那是一点y合。Animalcȝeat()Ҏ不能被承,因此HorsecM?eat()Ҏ是一个全新的ҎQ不是重写也不是重蝲Q只是一个只属于Horsecȝ全新的方法!q点让很多hqh了,但是也不是那么难以理解?br />main()Ҏ如果是这P<br />Animal h = new Horse();<br />//Horse h = new Horse();<br />h.eat();<br />~译器会报错Qؓ什么呢QHorsecȝeat()Ҏ是public的啊Q应该可以调用啊Q请牢记Q多态只看父cd用的ҎQ而不看子cd象的ҎQ?/p><img src ="http://www.shnenglu.com/chenglong7997/aggbug/170896.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/chenglong7997/" target="_blank">Snape</a> 2012-04-11 13:55 <a href="http://www.shnenglu.com/chenglong7997/articles/170896.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>java的nullhttp://www.shnenglu.com/chenglong7997/articles/170895.htmlSnapeSnapeWed, 11 Apr 2012 05:51:00 GMThttp://www.shnenglu.com/chenglong7997/articles/170895.htmlhttp://www.shnenglu.com/chenglong7997/comments/170895.htmlhttp://www.shnenglu.com/chenglong7997/articles/170895.html#Feedback0http://www.shnenglu.com/chenglong7997/comments/commentRss/170895.htmlhttp://www.shnenglu.com/chenglong7997/services/trackbacks/170895.html一、null是代表不定的对?/span>
        Java中,null是一个关键字Q用来标识一个不定的对象。因此可以将null赋给引用cd变量Q但不可以将null赋给基本cd变量?/span>

    比如Qint a = null;是错误的。Ojbect o = null是正的?/span>

      Java中,变量都遵循一个原则,先定义,q且初始化后Q才可以使用。我们不能int a后,不给a指定|去打印a的倹{?/span>
    q条对对于引用类型变量也是适用的?/span>

       有时候,我们定义一个引用类型变量,在刚开始的时候,无法l出一个确定的|但是不指定|E序可能会在try语句块中初始化倹{?/span>
        我们下面使用变量的时候就会报错。这时候,可以先给变量指定一个null|问题p决了。例如: 
    Connection conn = null;
    try {
       conn = DriverManager.getConnection("url", "user", "password");
    } catch (SQLException e) {
       e.printStackTrace();
    }

    String catalog = conn.getCatalog();

    如果刚开始的时候不指定conn = nullQ则最后一句就会报错?br />
    二、null本n不是对象Q也不是Objcet的实?br />
      null本n虽然能代表一个不定的对象,但就null本n来说Q它不是对象Q也不知道什么类型,也不是java.lang.Object的实例?br />可以做一个简单的例子Q?br />
    //null是对象吗? 属于Objectcd?
    if (null instanceof java.lang.Object) {
      System.out.println("null属于java.lang.Objectcd");
    } else {
      System.out.println("null不属于java.lang.Objectcd");
    }

    l果会输出:null不属于java.lang.Objectcd

    三、Java默认l变量赋?br />
    在定义变量的时候,如果定义后没有给变量赋|则Java在运行时会自动给变量赋倹{?br />赋值原则是整数cdint、byte、short?long的自动赋gؓ0Q带数点的float、double自动赋gؓ0.0Q?br />boolean的自动赋gؓfalseQ其他各供引用类型变量自动赋gؓ null?br />q个具体可以通过调试来看?br />
    四、容器类型与null

    ListQ允讔R复元素,可以加入L多个null?br />SetQ不允许重复元素Q最多可以加入一个null?br />MapQMap的key最多可以加入一个nullQvalue字段没有限制?br />数组Q基本类型数l,定义后,如果不给定初始|则javaq行时会自动l定倹{?br />引用cd数组Q不l定初始|则所有的元素gؓnull?br />
    五、null的其他作?br />
    1、判断一个引用类型数据是否null??=来判断?br />2、释攑ֆ存,让一个非null的引用类型变量指向null。这栯个对象就不再被Q何对象应用了?br />{待JVM垃圾回收机制d收?br />
    以下是我的一些想法:
    package com.zac.expe1;

    public class NullInDepth {
       public static void helloThere(){
        System.out.println("Hello from null?!");
       }

       public static void main(String[] args) {
         //((NullInDepth)null).helloThere();
         NullInDepth nullIn = null;
         nullIn.helloThere();
         Object nullStr = null;
         NullInDepth nullOut = (NullInDepth) nullStr;
         System.out.println(nullIn);
       }

    }

    q里Hello from null?!会被打印出来Q而后边一句会打印出nullQ?br />我们知道println一般是调用对象的toString来进行打华ͼ但是null明显不是对象Q?br />作ؓ一个不定引用它只是把自己的literall打C出来Q因此我猜测null是预先存储在内存中的一个引用,
    它是有值的Q可能根据不同的jvm有不同的实现Q但是jvm中会一致地这个值打Cؓnull?/p>


    另外按照我的猜测Qnull应该是栈里边的一个引用,null type是可以{换ؓ所有其他type的引用,
    所以我也猜null type应该是所有其他引用类型的子类型?nbsp;
    静态方法(也许需要是public的)应该是由cd来调用,但是也可以?cd(null).静态方法名的方式调用?/p>

    Snape 2012-04-11 13:51 发表评论
    ]]>
    java?深复?/title><link>http://www.shnenglu.com/chenglong7997/articles/170893.html</link><dc:creator>Snape</dc:creator><author>Snape</author><pubDate>Wed, 11 Apr 2012 05:48:00 GMT</pubDate><guid>http://www.shnenglu.com/chenglong7997/articles/170893.html</guid><wfw:comment>http://www.shnenglu.com/chenglong7997/comments/170893.html</wfw:comment><comments>http://www.shnenglu.com/chenglong7997/articles/170893.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/chenglong7997/comments/commentRss/170893.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/chenglong7997/services/trackbacks/170893.html</trackback:ping><description><![CDATA[<p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; "><span style="color: #0000ff; ">⑴复?克?</span><br />    被复制对象的所有变量都含有与原来的对象相同的|而所有的对其他对象的引用仍然指向原来的对象。换a之,复制仅仅复制所考虑的对象,而不复制它所引用的对象?/p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; "><span style="color: #0000ff; ">⑵深复?深克?</span><br />   被复制对象的所有变量都含有与原来的对象相同的|除去那些引用其他对象的变量。那些引用其他对象的变量指向被复制q的新对象,而不再是原有的那些被引用的对象。换a之,深复制把要复制的对象所引用的对象都复制了一遍?/p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">Java的clone()Ҏ</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">⑴cloneҎ对象复制了一份ƈq回l调用者。一般而言Qclone()Ҏ满Q?/p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">①对Q何的对象xQ都有x.clone() !=x//克隆对象与原对象不是同一个对?/p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">②对Q何的对象xQ都有x.clone().getClass()= =x.getClass()//克隆对象与原对象的类型一?/p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">③如果对象x的equals()Ҏ定义恰当Q那么x.clone().equals(x)应该成立?/p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">⑵Java中对象的克隆</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">①Z获取对象的一份拷贝,我们可以利用Objectcȝclone()Ҏ?/p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">②在派生类中覆盖基cȝclone()ҎQƈ声明为public?/p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">③在派生类的clone()Ҏ中,调用super.clone()?/p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">④在派生类中实现Cloneable接口?/p><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">L如下代码Q?/span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><pre style="color: #666666; font-size: 12px; line-height: normal; background-color: #ffffff; "> class Student implements Cloneable { String name; int age; Student(String name,int age) { this.name=name; this.age=age; } public Object clone() { Object o=null; try { o=(Student)super.clone();//Object中的clone()识别Z要复制的是哪一 // 个对象? } catch(CloneNotSupportedException e) { System.out.println(e.toString()); } return o; } public static void main(String[] args) { Student s1=new Student("zhangsan",18); Student s2=(Student)s1.clone(); s2.name="lisi"; s2.age=20; System.out.println("name="+s1.name+","+"age="+s1.age);//修改学生2后,不媄响学?的倹{? } }<br />q行l果Q?br />C:\java>java Student<br />name=zhangsan,age=18<br /><br />说明Q?/pre><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">①Z么我们在zcM覆盖Object的clone()ҎӞ一定要调用super.clone()?在运行时刻,Object中的 clone()识别Z要复制的是哪一个对象,然后为此对象分配I间Qƈq行对象的复Ӟ原始对象的内容一一复制到新对象的存储空间中?/p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">②l承自java.lang.Objectcȝclone()Ҏ是浅复制。以下代码可以证明之?/p><pre style="color: #666666; font-size: 12px; line-height: normal; background-color: #ffffff; "> class Professor { String name; int age; Professor(String name,int age) { this.name=name; this.age=age; } } public class Student implements Cloneable { String name;//帔R对象? int age; Professor p;//学生1和学?的引用值都是一L? Student(String name,int age,Professor p) { this.name=name; this.age=age; this.p=p; } public Object clone() { Student o=null; try { o=(Student)super.clone(); } catch(CloneNotSupportedException e) { System.out.println(e.toString()); } return o; } public static void main(String[] args) { Professor p=new Professor("wangwu",50); Student s1=new Student("zhangsan",18,p); Student s2=(Student)s1.clone(); s2.p.name="lisi"; s2.p.age=30; System.out.println("name="+s1.p.name+","+"age="+s1.p.age);//学生1的教授成为lisi,age?0? } }</pre><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">q行l果Q?/span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">C:\java>java Student</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">name=lisi,age=30</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">那应该如何实现深层次的克隆,即修改s2的教授不会媄响s1的教授,代码改进如下?/p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">改进使学?的Professor不改?深层ơ的克隆)</p><pre style="color: #666666; font-size: 12px; line-height: normal; background-color: #ffffff; "> class Professor implements Cloneable { String name; int age; Professor(String name,int age) { this.name=name; this.age=age; } public Object clone() { Object o=null; try { o=super.clone(); } catch(CloneNotSupportedException e) { System.out.println(e.toString()); } return o; } } public class Student implements Cloneable { String name; int age; Professor p; Student(String name,int age,Professor p) { this.name=name; this.age=age; this.p=p; } public Object clone() { Student o=null; try { o=(Student)super.clone(); } catch(CloneNotSupportedException e) { System.out.println(e.toString()); } o.p=(Professor)p.clone(); return o; } public static void main(String[] args) { Professor p=new Professor("wangwu",50); Student s1=new Student("zhangsan",18,p); Student s2=(Student)s1.clone(); s2.p.name="lisi"; s2.p.age=30; System.out.println("name="+s1.p.name+","+"age="+s1.p.age);//学生1的教授不改变? } } </pre><p style="color: #0000ff; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">3.利用串行化来做深复制</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">  把对象写到流里的q程是串行化(Serilization)q程Q但是在JavaE序师圈子里又非常Ş象地UCؓ“冷冻”或?#8220;腌咸?(picking)”q程;而把对象从流中读出来的ƈ行化(Deserialization)q程则叫?#8220;解冻”或?#8220;回鲜(depicking)”q程。应当指出的是,写在里的是对象的一个拷贝,而原对象仍然存在于JVM里面Q因?#8220;腌成咸菜”的只是对象的一个拷贝,Java咸菜q可以回鲜?/p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">在Java语言里深复制一个对象,常常可以先对象实现Serializable接口Q然后把对象(实际上只是对象的一个拷?写到一个流?腌成咸菜)Q再从流里读出来(把咸菜回?Q便可以重徏对象?/p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">如下为深复制源代码?/p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">public Object deepClone() <br />{ <br />  //对象写到流?nbsp;<br />  ByteArrayOutputStream bo=new ByteArrayOutputStream(); <br />  ObjectOutputStream oo=new ObjectOutputStream(bo); <br />  oo.writeObject(this); <br /><br />  //从流里读出来 <br />  ByteArrayInputStream bi=new ByteArrayInputStream(bo.toByteArray()); <br />  ObjectInputStream oi=new ObjectInputStream(bi); <br />  return(oi.readObject()); <br />}</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">q样做的前提是对象以及对象内部所有引用到的对象都是可串行化的Q否则,需要仔l考察那些不可串行化的对象可否设成transientQ从而将之排除在复制q程之外。上例代码改q如下?br /></p><pre style="color: #666666; font-size: 12px; line-height: normal; background-color: #ffffff; ">import java.io.*; class Professor implements Serializable { String name; int age; Professor(String name,int age) { this.name=name; this.age=age; } } public class Student implements Serializable { String name;//帔R对象? int age; Professor p;//学生1和学?的引用值都是一L? Student(String name,int age,Professor p) { this.name=name; this.age=age; this.p=p; } public Object deepClone() throws IOException, OptionalDataException,ClassNotFoundException { //对象写到流? ByteArrayOutputStream bo=new ByteArrayOutputStream(); ObjectOutputStream oo=new ObjectOutputStream(bo); oo.writeObject(this); //从流里读出来 ByteArrayInputStream bi=new ByteArrayInputStream(bo.toByteArray()); ObjectInputStream oi=new ObjectInputStream(bi); return(oi.readObject()); } public static void main(String[] args) throws IOException,ClassNotFoundException { Professor p=new Professor("wangwu",50); Student s1=new Student("zhangsan",18,p); Student s2=(Student)s1.deepClone(); s2.p.name="lisi"; s2.p.age=30; System.out.println("name="+s1.p.name+","+"age="+s1.p.age); //学生1的教授不改变? } }</pre><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; "></p><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">q行l果Q?/span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">C:\java>java Student</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">name=wangwu,age=50</span> <img src ="http://www.shnenglu.com/chenglong7997/aggbug/170893.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/chenglong7997/" target="_blank">Snape</a> 2012-04-11 13:48 <a href="http://www.shnenglu.com/chenglong7997/articles/170893.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JavaE序易遭受逆向工程d的原?/title><link>http://www.shnenglu.com/chenglong7997/articles/170892.html</link><dc:creator>Snape</dc:creator><author>Snape</author><pubDate>Wed, 11 Apr 2012 05:43:00 GMT</pubDate><guid>http://www.shnenglu.com/chenglong7997/articles/170892.html</guid><wfw:comment>http://www.shnenglu.com/chenglong7997/comments/170892.html</wfw:comment><comments>http://www.shnenglu.com/chenglong7997/articles/170892.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/chenglong7997/comments/commentRss/170892.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/chenglong7997/services/trackbacks/170892.html</trackback:ping><description><![CDATA[<div> Java应用E序虽然能够“~写一ơ,随处q行”QWrite Once, Run AnywhereQ是一个巨大的优势Q但q种环境的架构方式其远比本机应用程序更Ҏ被黑客进行逆向工程。这意味着开发h员面临着失去知识产权的非常真实的危险。基于应用程序的虚拟机比本机应用E序更容易逆向工程的原因有很多Q?/div><div><span style="color: red; ">JVM是开源的</span><br />  Sun已经免费提供JVM的源代码。这使得黑客只需查看代码卛_弄清虚拟机的工作方式?/div><div>Java .class文g格式是可公开获取?br />如前所qͼJava源代码被~译成字节码Q而字节码存储在Java .class文g中。Java .class文g格式的规范是可公开获取的,因此有技术背景的M人都能容易地~写可以处理、修Ҏ转换.class文g的工兗?/div><div><span style="color: red; ">JVM是YӞ而不是硬?/span></div><div>   与需要理解特定处理器的专家用的标准~程语言不同QJVM是一个应用程序,它如同微处理器一栯作,q用操作系l和计算机硬件提供的内置功能。由于黑客不必深入到gU别Q因此更Ҏ取得对JVM的完全控制?/div><div>   因此Q例如在使用标准本机pȝ开发语aq行调试Ӟ暂停处理器极为困难,需要具备处理器、调试功能及可用环调试器的专家知识。但是,׃JVM q行环境的源代码是可公开获取的,因此开发h员可以轻村֜建立自己的虚拟机来完全控制虚拟处理器的各个方面。这样可以容易地分析q行环境中运行的每个应用E序?/div><div><span style="color: red; ">Java的指令比本机代码?/span></div><div>   然而,JVM代码易于q行反向工程的另一个原因是它具有比本地应用E序更少的指令。这是出于性能考虑。JVM的用在应用E序和本机处理器之间增加了一个Y件层Q这会对性能产生负面影响。虽然现代处理器不断提高的执行速度最l将~解q一问题Q但q一问题仍然很明显。虚拟机开发h员提高执行速度的一U方法是使用比本机处理器汇编E序更小的字节码指o集。本机应用程序可能包含多?00条指令,而Java应用E序通常使用不超q?00条的指o。更的指o意味着黑客可以更快地分析代码以q行逆向工程。这些特性得虚拟机q比其它cd的应用程序更Ҏ遭受逆向工程d?/div><div><span style="color: red; ">W三方反汇编E序增加了漏z?/span></div><div> 不仅是JVM本nҎ遭受逆向工程dQ商业和免费的Java字节码反汇编E序也越来越多,从而进一步简化了代码逆向工程的过E。IDA和Eclipse字节码插件是众多Java字节码反汇编E序中的两种。作为商业品,IDA是一U普遍的反汇~程序,可用于许多不同的处理器,包括80x86和MIPS。Eclipse字节码插件是免费软g。它能够反编译Java .class文g的字节码q以适当的顺序显C所有操作码指o?nbsp;管q些产品不大可能从字节码完美地恢复原始代码,但它们恢复的源代码将{同于原始代码,q且比字节码更具可读性。一旦恢复了源代码,d者可以容易地删除部分代码q将光法地用于竞争Ҏ的应用程序中Q或?class文g中定位打补丁?/div><div></div><div>?提供了黑客可能如何在.class文g中打补丁的一个示例。屏q的上半部分昄了一段Java源代码。屏q的下半部分昄了字节码反汇~的输出Q也是一个字节码指o列表。标CؓU色的区域是源代码中IFl构的对应指令。字节码指o“LCMP”的十六进制表CZؓ0x94。该工具q指Z操作码在.class文g中的位置。有了这些信息,黑客可以使用单的十六q制~辑器来改变该IF分支Q而这只需不到一分钟的时间。假设该IF条g用于许可证检查,黑客可倒置该条Ӟ指示即在许可证被验证ؓ无效Q如已过期)的情况下仍返?#8220;True”Q从而突破许可证查。在q种情况下,黑客使用一个字节的补丁卛_完成所有工作。虽然大多数应用E序都比q个CZ更加复杂Q但即在复杂的应用E序中,字节码也非常单ƈ且容易理解?/div><div></div><div> Java应用E序虽然能够“~写一ơ,随处q行”QWrite Once, Run AnywhereQ是一个巨大的优势Q但q种环境的架构方式其远比本机应用程序更Ҏ被黑客进行逆向工程。这意味着开发h员面临着失去知识产权的非常真实的危险。基于应用程序的虚拟机比本机应用E序更容易逆向工程的原因有很多Q?/div><div></div><div><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; "><img src="http://www.java3z.com/cwbwebhome/article/article8/img7/161822209.jpg" width="392" height="279" alt="" /></p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">? - 用于字节码反汇编的Eclipse字节码插?/p></div><div></div><div></div><img src ="http://www.shnenglu.com/chenglong7997/aggbug/170892.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/chenglong7997/" target="_blank">Snape</a> 2012-04-11 13:43 <a href="http://www.shnenglu.com/chenglong7997/articles/170892.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java基本功——Referencehttp://www.shnenglu.com/chenglong7997/articles/170891.htmlSnapeSnapeWed, 11 Apr 2012 05:30:00 GMThttp://www.shnenglu.com/chenglong7997/articles/170891.htmlhttp://www.shnenglu.com/chenglong7997/comments/170891.htmlhttp://www.shnenglu.com/chenglong7997/articles/170891.html#Feedback0http://www.shnenglu.com/chenglong7997/comments/commentRss/170891.htmlhttp://www.shnenglu.com/chenglong7997/services/trackbacks/170891.html q是一一q多之前便已写就的文章,那时Q因为很多JavaE序员只求追随新生的事物Q却q基本的概念都没有,很多讨论中,很明显是基本功不q硬Q于是萌生写一个系列文章,讨论Java的基本功Q下面便是在q个x下催生出的第一文章。可事实上,真正完成的也只有q一。因为未能及时发布,它就被我遗忘在硬盘的角落中。今天,JavaEye上关于Java传D是传引用的论战让我记起了自己曄写过的这文章,愿与大家׃n?/p>

    Java基本?#8212;—Reference

    有这样一U说法,如今争锋于IT战场的两大势力,MS一族偏重于底层实现QJava一族偏重于pȝ架构。说法根据无从考证Q但从两大势力各自的C֌力量和图书市场已有佳作不隄出,此说法不虚。于是,事情的另一面让人忽略了?br />偏yQ我是一个喜Ƣ探I底层实现的JavaE序员,虽然我的喜好qU正咖啡Q剑走偏锋却别是一番风呟?/p>

    Reference
    Java世界泰山北斗U大作《Thinking In Java》切入Java提?#8220;Everything is Object”。在Javaq个充满Object的世界中Qreference是一切谜题的ҎQ所有的故事都是从这里开始的?/p>

    Reference是什么?
    如果你和我一样在q入Java世界之前曄迹于C/C++世界Q就一定不会对指针陌生。谈到指针,往日种U不堪回首的l历一下子涌上心头Q这里不是抱怨的地方Q让我们暂时忘记指针的痛苦,回忆一下最初接触指针的甜蜜吧!q记得你看过的教U书中,如何讲解指针吗?留在我印象中的一U说法是Q指针就是地址Q如同门牌号码一P有了地址Q你可以轻而易举找C个hӞ而不必费心力的大v捞针?br />C++M历史舞台Qreference也随之而来Q容我问个小问题Q指针和reference区别何在Q我的答案来自于在C++世界享誉盛名的《More Effective C++》?/p>

    1. 没有null reference?/li>
    2. reference必须有初倹{?/li>
    3. 使用reference要比使用指针效率高。因为reference不需要测试其有效性?/li>
    4. 指针可以重新赋|而referenceL指向它最初获得的对象

    设计选择Q?/strong>
    当你指向你需要指向的某个东西Q而且l不会改指向其它东西Q或是当你实作一个运符而其语法需要无法有指针达成Q你应该选择reference。其它Q何时候,请采用指针?/p>

    q和Java有什么关p?
    初学JavaQ鉴于reference的名Uͼ我毫不犹豫的它和C++中的reference{同h。不q,我错了。在Java中,reference可以随心所Ʋ的赋值置I,Ҏ一下上面列出的差异Q就不难发现QJava的reference如果要与C/C++对应Q它不过是一个穿着reference外衣的指针而已?br />于是Q所有关于C中关于指针的理解方式Q可以照搬到Java中,而言之,reference是一个地址。我们可以把它想象成一个把手,抓住它,抓住了我们惌操纵的数据。如同掌握C的关键在于掌握指针,探烦Java的钥匙就是reference?/p>

    一D小E序
    我知道,太多的文字L令h犯困Q那来D代码吧Q?br />public class ReferenceTricks {
      public static void main(String[] args) {
        ReferenceTricks r = new ReferenceTricks();
        // reset integer
        r.i = 0;
        System.out.println("Before changeInteger:" + r.i);
        changeInteger(r);
        System.out.println("After changeInteger:" + r.i);

        // just for format
        System.out.println();
      
        // reset integer
        r.i = 0;
        System.out.println("Before changeReference:" + r.i);
        changeReference(r);
        System.out.println("After changeReference:" + r.i);
      }

      private static void changeReference(ReferenceTricks r) {
       r = new ReferenceTricks();
       r.i = 5;
       System.out.println("In changeReference: " + r.i);
      }

      private static void changeInteger(ReferenceTricks r) {
       r.i = 5;
       System.out.println("In changeInteger:" + r.i);
      }

      public int i;
    }

    对不P我知道,把一个字D设成public是一U不好的~码习惯Q这里只是ؓ了说明问题?br />如果你有兴趣自己q行一下这个程序,我等你!

    OKQ你已经q行q了吗?l果如何Q是否如你预期?下面是我在自q机器上运行的l果Q?br />Before changeInteger:0
    In changeInteger:5
    After changeInteger:5

    Before changeReference:0
    In changeReference: 5
    After changeReference:0
    q里Q我们关注的是两个change——changeReference和changeInteger。从输出的内容中Q我们可以看出,两个Ҏ在调用前和调用中完全一P差异出现在调用后的结果?/p>

    p涂的讲?br />先让我们来分析一下changeInteger的行为?br />前面说过了,Java中的reference是一个地址Q它指向了一个内存空_q个I间存放着一个对象的相关信息。这里我们暂时不d心这个内存具体如何排布,只要知道Q通过地址Q我们可以找到rq个对象的i字段Q然后我们给它赋?。既然这个字D늚内容得到了修改,从函Cq回之后Q它自然是改动后的l果了,所以调用之后,r对象的i字段依然?。下囑ֱCZchangeInteger调用前后内存变化?/p>

         Reference +--------+                Reference +--------+
        ---------->| i = 0  |               ---------->| i = 5  |
                   |--------|                          |--------|
                   | Memory |                          | Memory |
                   |        |                          |        | 
                   |        |                          |        |
                   +--------+                          +--------+

        调用changeInteger之前               调用changeInteger之后

    让我们把目光转向changeReference?br />从代码上Q我们可以看出,同changeInteger之间的差别仅仅在于多了这么一句?br />r = new ReferenceTricks();
    q条语句的作用是分配一块新的内存,然后r指向它?br />执行完这条语句,r׃再是原来的rQ但它依然是一个ReferenceTricks的对象,所以我们依然可以对q个r的i字段赋倹{到此ؓ止,一切都是那么自然?/p>

         Reference +--------+                          +--------+
        ---------->| i = 0  |                          | i = 0  |
                   |--------|                          |--------|
                   | Memory |                          | Memory |
                   |        |                Reference |--------| 
                   |        |               ---------->| i = 5  |
                   +--------+                          +--------+

        调用changeReference之前              调用changeReference之后

    着q个思\l箋下去的话Q执行完changeReferenceQ输出的r的i字段Q那么应该是应该是新内存中的iQ所以应该是5。至于那块被我们抛弃的内存,Java的GC功能自然会替我们善后的?br />事与愿违?br />实际的结果我们已l看CQ输出的??br />肯定哪个地方错了Q究竟是哪个地方呢?

    参数传递的U密
    知道Ҏ参数如何传递吗Q?br />记得刚开始学~程那会儿,老师教导Q所谓参敎ͼ有Ş式参数和实际参数之分Q参数列表中写的那些东西都叫形式参数Q在实际调用的时候,它们会被实际参数所替代?br />~译E序不可能知道每ơ调用的实际参数都是什么,于是写编译器的高手就Z办法Q让实际参数按照一定顺序放C个大安可以扑־到的地方Q以此作为方法调用的一U约定。所?#8220;没有规矩Q不成方?#8221;Q有了这个规矩,大家协作h容易多了。这个公共数据区Q现在编译器的选择通常?#8220;?#8221;Q而所谓的序是形式参数声明的顺序?br />昄Q程序运行的q程中,作ؓ实际参数的变量可能遍布于内存的各个位|,而ƈ不一定要老老实实的呆在栈里。ؓ了守“规矩”Q程序只好将变量复制一份到栈中Q也是通常所说的参数压入栈中?br />打v_Q谜底就要揭晓了?br />我刚才说什么来着Q将变量复制一份到栈中Q没错,“复制”Q?br />q就是所谓的g递?br />C语言的旷世经典《The C Programming Language》开的W一章中Q谈到实际参数时_“在C中,所有函数的实际参数都是?#8216;??#8221;?br />马上会有人站出来Q?#8220;错了Q还有传地址Q比如以指针传递就是传地址”?br />不错Q传指针是传地址。在把指针视为地址的时候,是否考虑q这样一个问题,它也是一个变量。前面的讨论中说q了Q参C递必要把参数压入栈中,作ؓ地址的指针也不例外。所以,必须把这个指针也复制一份。函C对于指针操作实际上是对于q个指针副本的操作?br />Java的reference{于C的指针。所以,在Java的方法调用中Qreference也要复制一份压入堆栈。在Ҏ中对reference的操作就是对q个reference副本的操作?br />谜底揭晓
    好,让我们回到最初的问题上?br />在changeReference中对于reference的赋值实际上是对q个reference的副本进行赋|而对于reference的本没有生丝毫的影响?br />回到调用点,本尊醒来Q它q不知道自己睡去的这D|间内发生q什么,所以只好当作什么都没发生过一般。就q样Q副本消׃Q在Ҏ中对它的修改也就烟消云散了?br /> 
    也许你会问出q样的问题,“听了你的解释Q我反而对changeInteger感到qh了,既然是对于副本的操作Qؓ什么changeInteger可以q作正常Q?#8221;
    呵呵Q很有趣的大脑短路现象?br />好,那我q前面的说法解释一下changeInteger的运作?br />所谓复Ӟ其结果必然是副本完全{同于本。reference复制的结果必然是两个reference指向同一块内存空间?br />虽然在方法中对于副本的操作ƈ不会影响到本,但对内存I间的修改确实实实在在的?br />回到调用点,虽然本尊依然不知道曾l发生过的一切,但它按照原来的方式访问内存的时候,取到的确是经q方法修改之后的内容?br />于是Ҏ可以把自q影响扩展到方法之外?br /> 
    多说几句
    q个问题h于我对C/C++中同样问题的思考。同C/C++相比Q在changeReference中对reference赋值可能ƈ不会造成什么很严重的后果,而在C/C++中,q么做却会造成臭名昭著?#8220;内存泄漏”Q根本的原因在于Java拥有了可qGC功能。即便这P我仍不推荐用这U的手法Q毕竟GC已经很忙了,我们怎么好意思再ȝ人家?br />在C/C++中,q个问题q可以l引生뀂既然在函数中对于指针直接赋D不通,那么如何在函C修改指针呢?{案很简单,指针的指针,也就是把原来的指针看作一个普通的数据Q把一个指向它的指针传到函C可以了?br />同样的问题到了Java中就没有那么妙的解x案了Q因为Java中可没有reference的referenceq样的语法。可能的变通就是将referenceq行装成类。至于g|公道自在人心?/p>

    Snape 2012-04-11 13:30 发表评论
    ]]>
    java中的多线E??http://www.shnenglu.com/chenglong7997/articles/169591.htmlSnapeSnapeFri, 30 Mar 2012 19:19:00 GMThttp://www.shnenglu.com/chenglong7997/articles/169591.htmlhttp://www.shnenglu.com/chenglong7997/comments/169591.htmlhttp://www.shnenglu.com/chenglong7997/articles/169591.html#Feedback0http://www.shnenglu.com/chenglong7997/comments/commentRss/169591.htmlhttp://www.shnenglu.com/chenglong7997/services/trackbacks/169591.html
    java中的多线E?/div>
    在java中要惛_现多U程Q有两种手段Q一U是l箋Threadc,另外一U是实现Runable接口?/div>
    对于直接l承Thread的类来说Q代码大致框架是Q?/div>
    class cd extends Thread{
    Ҏ1;
    Ҏ2Q?/div>
    public void run(){
    // other code…
    }
    属?Q?/div>
    属?Q?/div>
     
    }
    先看一个简单的例子Q?/div>
    /**
     * @author Rollen-Holt l承Threadc?直接调用runҎ
     * */
    class hello extends Thread {
     
        public hello() {
     
        }
     
        public hello(String name) {
            this.name = name;
        }
     
        public void run() {
            for (int i = 0; i < 5; i++) {
                System.out.println(name + "q行     " + i);
            }
        }
     
        public static void main(String[] args) {
            hello h1=new hello("A");
            hello h2=new hello("B");
            h1.run();
            h2.run();
        }
     
        private String name;
    }
    【运行结果】:
    Aq行     0
    Aq行     1
    Aq行     2
    Aq行     3
    Aq行     4
    Bq行     0
    Bq行     1
    Bq行     2
    Bq行     3
    Bq行     4
    我们会发现这些都是顺序执行的Q说明我们的调用Ҏ不对Q应该调用的是startQ)Ҏ?/div>
    当我们把上面的主函数修改为如下所C的时候:
    public static void main(String[] args) {
            hello h1=new hello("A");
            hello h2=new hello("B");
            h1.start();
            h2.start();
        }
    然后q行E序Q输出的可能的结果如下:
    Aq行     0
    Bq行     0
    Bq行     1
    Bq行     2
    Bq行     3
    Bq行     4
    Aq行     1
    Aq行     2
    Aq行     3
    Aq行     4
    因ؓ需要用到CPU的资源,所以每ơ的q行l果基本是都不一LQ呵c?/div>
    注意Q虽然我们在q里调用的是startQ)ҎQ但是实际上调用的还是runQ)Ҏ的主体?/div>
    那么Qؓ什么我们不能直接调用runQ)Ҏ呢?
    我的理解是:U程的运行需要本地操作系l的支持?/div>
    如果你查看start的源代码的时候,会发玎ͼ
    public synchronized void start() {
            /**
         * This method is not invoked for the main method thread or "system"
         * group threads created/set up by the VM. Any new functionality added 
         * to this method in the future may have to also be added to the VM.
         *
         * A zero status value corresponds to state "NEW".
             */
            if (threadStatus != 0 || this != me)
                throw new IllegalThreadStateException();
            group.add(this);
            start0();
            if (stopBeforeStart) {
            stop0(throwableFromStop);
        }
    }
    private native void start0();
    注意我用U色加粗的那一条语句,说明此处调用的是start0Q)。ƈ且这个这个方法用了native关键字,ơ关键字表示调用本地操作pȝ的函数。因为多U程的实现需要本地操作系l的支持?/div>
    但是startҎ重复调用的话Q会出现java.lang.IllegalThreadStateException异常?/div>
    通过实现Runnable接口Q?/div>
     
    大致框架是:
    class cd implements Runnable{
    Ҏ1;
    Ҏ2Q?/div>
    public void run(){
    // other code…
    }
    属?Q?/div>
    属?Q?/div>
     
    }
    来先看一个小例子吧:
    /**
     * @author Rollen-Holt 实现Runnable接口
     * */
    class hello implements Runnable {
     
        public hello() {
     
        }
     
        public hello(String name) {
            this.name = name;
        }
     
        public void run() {
            for (int i = 0; i < 5; i++) {
                System.out.println(name + "q行     " + i);
            }
        }
     
        public static void main(String[] args) {
            hello h1=new hello("U程A");
            Thread demo= new Thread(h1);
            hello h2=new hello("U程Q?);
            Thread demo1=new Thread(h2);
            demo.start();
            demo1.start();
        }
     
        private String name;
    }
    【可能的q行l果】:
    U程Aq行     0
    U程Q运?    0
    U程Q运?    1
    U程Q运?    2
    U程Q运?    3
    U程Q运?    4
    U程Aq行     1
    U程Aq行     2
    U程Aq行     3
    U程Aq行     4
     
    关于选择l承Threadq是实现Runnable接口Q?/div>
    其实Thread也是实现Runnable接口的:
    ?
    1
    2
    3
    4
    5
    6
    7
    8
    class Thread implements Runnable {
        //…
    public void run() {
            if (target != null) {
                 target.run();
            }
            }
    }
    其实Thread中的runҎ调用的是Runnable接口的runҎ。不知道大家发现没有QThread和Runnable都实CrunҎQ这U操作模式其实就是代理模式。关于代理模式,我曾l写q一个小例子呵呵Q大家有兴趣的话可以看一下:http://www.cnblogs.com/rollenholt/archive/2011/08/18/2144847.html
    Thread和Runnable的区别:
    如果一个类l承ThreadQ则不适合资源׃n。但是如果实CRunable接口的话Q则很容易的实现资源׃n?/div>
    /**
     * @author Rollen-Holt l承Threadc,不能资源׃n
     * */
    class hello extends Thread {
        public void run() {
            for (int i = 0; i < 7; i++) {
                if (count > 0) {
                    System.out.println("count= " + count--);
                }
            }
        }
     
        public static void main(String[] args) {
            hello h1 = new hello();
            hello h2 = new hello();
            hello h3 = new hello();
            h1.start();
            h2.start();
            h3.start();
        }
     
        private int count = 5;
    }
    【运行结果】:
    count= 5
    count= 4
    count= 3
    count= 2
    count= 1
    count= 5
    count= 4
    count= 3
    count= 2
    count= 1
    count= 5
    count= 4
    count= 3
    count= 2
    count= 1
    大家可以惌Q如果这个是一个买系l的话,如果count表示的是车票的数量的话,说明q没有实现资源的׃n?/div>
    我们换ؓRunnable接口Q?/div>
    /**
     * @author Rollen-Holt l承Threadc,不能资源׃n
     * */
    class hello implements Runnable {
        public void run() {
            for (int i = 0; i < 7; i++) {
                if (count > 0) {
                    System.out.println("count= " + count--);
                }
            }
        }
     
        public static void main(String[] args) {
            hello he=new hello();
            new Thread(he).start();
        }
     
        private int count = 5;
    }
    【运行结果】:
    count= 5
    count= 4
    count= 3
    count= 2
    count= 1
     
    ȝ一下吧Q?/div>
    实现Runnable接口比承ThreadcLh的优势:
    1Q:适合多个相同的程序代码的U程d理同一个资?/div>
    2Q:可以避免java中的单承的限制
    3Q:增加E序的健壮性,代码可以被多个线E共享,代码和数据独立?/div>
    所以,本h大家劲量实现接口?/div>
    /**
     * @author Rollen-Holt 
     * 取得U程的名U?/div>
     * */
    class hello implements Runnable {
        public void run() {
            for (int i = 0; i < 3; i++) {
                System.out.println(Thread.currentThread().getName());
            }
        }
     
        public static void main(String[] args) {
            hello he = new hello();
            new Thread(he,"A").start();
            new Thread(he,"B").start();
            new Thread(he).start();
        }
    }
    【运行结果】:
    A
    A
    A
    B
    B
    B
    Thread-0
    Thread-0
    Thread-0
    说明如果我们没有指定名字的话Q系l自动提供名字?/div>
    提醒一下大ӞmainҎ其实也是一个线E。在java中所以的U程都是同时启动的,至于什么时候,哪个先执行,完全看谁先得到CPU的资源?/div>
     
    在java中,每次E序q行臛_启动2个线E。一个是mainU程Q一个是垃圾攉U程。因为每当用java命o执行一个类的时候,实际上都会启动一个JQӞ݋Q每一个jQӞ݋实习在就是在操作pȝ中启动了一个进E?/div>
    判断U程是否启动
    /**
     * @author Rollen-Holt 判断U程是否启动
     * */
    class hello implements Runnable {
        public void run() {
            for (int i = 0; i < 3; i++) {
                System.out.println(Thread.currentThread().getName());
            }
        }
     
        public static void main(String[] args) {
            hello he = new hello();
            Thread demo = new Thread(he);
            System.out.println("U程启动之前---? + demo.isAlive());
            demo.start();
            System.out.println("U程启动之后---? + demo.isAlive());
        }
    }
    【运行结果?/div>
    U程启动之前---》false
    U程启动之后---》true
    Thread-0
    Thread-0
    Thread-0
    ȝE也有可能在子线E结束之前结束。ƈ且子U程不受影响Q不会因ZU程的结束而结束?/div>
     
    U程的强制执行:
    /**
         * @author Rollen-Holt U程的强制执?/div>
         * */
        class hello implements Runnable {
            public void run() {
                for (int i = 0; i < 3; i++) {
                    System.out.println(Thread.currentThread().getName());
                }
            }
         
            public static void main(String[] args) {
                hello he = new hello();
                Thread demo = new Thread(he,"U程");
                demo.start();
                for(int i=0;i<50;++i){
                    if(i>10){
                        try{
                            demo.join();  //强制执行demo
                        }catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                    System.out.println("main U程执行-->"+i);
                }
            }
        }
    【运行的l果】:
    main U程执行-->0
    main U程执行-->1
    main U程执行-->2
    main U程执行-->3
    main U程执行-->4
    main U程执行-->5
    main U程执行-->6
    main U程执行-->7
    main U程执行-->8
    main U程执行-->9
    main U程执行-->10
    U程
    U程
    U程
    main U程执行-->11
    main U程执行-->12
    main U程执行-->13
    Q.Q?/div>
     
    U程的休眠:
    /**
     * @author Rollen-Holt U程的休?/div>
     * */
    class hello implements Runnable {
        public void run() {
            for (int i = 0; i < 3; i++) {
                try {
                    Thread.sleep(2000);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + i);
            }
        }
     
        public static void main(String[] args) {
            hello he = new hello();
            Thread demo = new Thread(he, "U程");
            demo.start();
        }
    }
    【运行结果】:Q结果每?s输出一个)
    U程0
    U程1
    U程2
     
    U程的中断:
    /**
     * @author Rollen-Holt U程的中?/div>
     * */
    class hello implements Runnable {
        public void run() {
            System.out.println("执行runҎ");
            try {
                Thread.sleep(10000);
                System.out.println("U程完成休眠");
            } catch (Exception e) {
                System.out.println("休眠被打?);
                return;  //q回到程序的调用?/div>
            }
            System.out.println("U程正常l止");
        }
     
        public static void main(String[] args) {
            hello he = new hello();
            Thread demo = new Thread(he, "U程");
            demo.start();
            try{
                Thread.sleep(2000);
            }catch (Exception e) {
                e.printStackTrace();
            }
            demo.interrupt(); //2s后中断线E?/div>
        }
    }
    【运行结果】:
    执行runҎ
    休眠被打?/div>
     
    在javaE序中,只要前台有一个线E在q行Q整个javaE序q程不会时Q所以此时可以设|一个后台线E,q样即javaq程时了,此后台线E依然能够l运行?/div>
    /**
     * @author Rollen-Holt U程的优先
     * */
    class hello implements Runnable {
        public void run() {
            for(int i=0;i<5;++i){
                System.out.println(Thread.currentThread().getName()+"q行"+i);
            }
        }
     
        public static void main(String[] args) {
            Thread h1=new Thread(new hello(),"A");
            Thread h2=new Thread(new hello(),"B");
            Thread h3=new Thread(new hello(),"C");
            h1.setPriority(8);
            h2.setPriority(2);
            h3.setPriority(6);
            h1.start();
            h2.start();
            h3.start();
             
        }
    }
    【运行结果】:
    Aq行0
    Aq行1
    Aq行2
    Aq行3
    Aq行4
    Bq行0
    Cq行0
    Cq行1
    Cq行2
    Cq行3
    Cq行4
    Bq行1
    Bq行2
    Bq行3
    Bq行4
    。但是请读者不要误以ؓ优先U越高就先执行。谁先执行还是取决于谁先ȝCPU的资源?/div>
     
    另外Q主U程的优先?.
    U程的礼让?/div>
    在线E操作中Q也可以使用yieldQ)ҎQ将一个线E的操作暂时交给其他U程执行?/div>
    /**
     * @author Rollen-Holt U程的优先
     * */
    class hello implements Runnable {
        public void run() {
            for(int i=0;i<5;++i){
                System.out.println(Thread.currentThread().getName()+"q行"+i);
                if(i==3){
                    System.out.println("U程的礼?);
                    Thread.currentThread().yield();
                }
            }
        }
     
        public static void main(String[] args) {
            Thread h1=new Thread(new hello(),"A");
            Thread h2=new Thread(new hello(),"B");
            h1.start();
            h2.start();
             
        }
    }
    Aq行0
    Aq行1
    Aq行2
    Aq行3
    U程的礼?/div>
    Aq行4
    Bq行0
    Bq行1
    Bq行2
    Bq行3
    U程的礼?/div>
    Bq行4
     
     
    同步和死锁:
    【问题引出?比如说对于买系l,有下面的代码Q?/div>
    /**
     * @author Rollen-Holt 
     * */
    class hello implements Runnable {
        public void run() {
            for(int i=0;i<10;++i){
                if(count>0){
                    try{
                        Thread.sleep(1000);
                    }catch(InterruptedException e){
                        e.printStackTrace();
                    }
                    System.out.println(count--);
                }
            }
        }
     
        public static void main(String[] args) {
            hello he=new hello();
            Thread h1=new Thread(he);
            Thread h2=new Thread(he);
            Thread h3=new Thread(he);
            h1.start();
            h2.start();
            h3.start();
        }
        private int count=5;
    }
    【运行结果】:
    5
    4
    3
    2
    1
    0
    -1
    q里出现?1Q显然这个是错的。,应该数不能倹{?/div>
    如果惌册U问题,需要用同步。所谓同步就是在l一旉D中只有有一个线E运行,
    其他的线E必ȝ到这个线E结束之后才能l执行?/div>
    【用线E同步解决问题?/div>
    采用同步的话Q可以用同步代码块和同步方法两U来完成?/div>
     
    【同步代码块】:
    语法格式Q?/div>
    synchronizedQ同步对象){
     //需要同步的代码
    }
    但是一般都把当前对象this作ؓ同步对象?/div>
    比如对于上面的买的问题Q如下:
    /**
     * @author Rollen-Holt 
     * */
    class hello implements Runnable {
        public void run() {
            for(int i=0;i<10;++i){
                synchronized (this) {
                    if(count>0){
                        try{
                            Thread.sleep(1000);
                        }catch(InterruptedException e){
                            e.printStackTrace();
                        }
                        System.out.println(count--);
                    }
                }
            }
        }
     
        public static void main(String[] args) {
            hello he=new hello();
            Thread h1=new Thread(he);
            Thread h2=new Thread(he);
            Thread h3=new Thread(he);
            h1.start();
            h2.start();
            h3.start();
        }
        private int count=5;
    }
    【运行结果】:Q每一U输Z个结果)
    5
    4
    3
    2
    1
    【同步方法?/div>
    也可以采用同步方法?/div>
    语法格式为synchronized Ҏq回cd Ҏ名(参数列表Q{
        // 其他代码
    }
    现在Q我们采用同步方法解决上面的问题?/div>
    ?
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    /**
     * @author Rollen-Holt
     * */
    class hello implements Runnable {
        public void run() {
            for (int i = 0; i < 10; ++i) {
                sale();
            }
        }
     
        public synchronized void sale() {
            if (count > 0) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(count--);
            }
        }
     
        public static void main(String[] args) {
            hello he = new hello();
            Thread h1 = new Thread(he);
            Thread h2 = new Thread(he);
            Thread h3 = new Thread(he);
            h1.start();
            h2.start();
            h3.start();
        }
     
        private int count = 5;
    }
    【运行结果】(每秒输出一个)
    5
    4
    3
    2
    1
    提醒一下,当多个线E共享一个资源的时候需要进行同步,但是q多的同步可能导致死锁?/div>
    此处列Dl典的生产者和消费者问题?/div>
    【生产者和消费者问题?/div>
    先看一D|问题的代码?/div>
    class Info {
     
        public String getName() {
            return name;
        }
     
        public void setName(String name) {
            this.name = name;
        }
     
        public int getAge() {
            return age;
        }
     
        public void setAge(int age) {
            this.age = age;
        }
     
        private String name = "Rollen";
        private int age = 20;
    }
     
    /**
     * 生?/div>
     * */
    class Producer implements Runnable{
        private Info info=null;
        Producer(Info info){
            this.info=info;
        }
         
        public void run(){
            boolean flag=false;
            for(int i=0;i<25;++i){
                if(flag){
                    this.info.setName("Rollen");
                    try{
                        Thread.sleep(100);
                    }catch (Exception e) {
                        e.printStackTrace();
                    }
                    this.info.setAge(20);
                    flag=false;
                }else{
                    this.info.setName("chunGe");
                    try{
                        Thread.sleep(100);
                    }catch (Exception e) {
                        e.printStackTrace();
                    }
                    this.info.setAge(100);
                    flag=true;
                }
            }
        }
    }
    /**
     * 消费者类
     * */
    class Consumer implements Runnable{
        private Info info=null;
        public Consumer(Info info){
            this.info=info;
        }
         
        public void run(){
            for(int i=0;i<25;++i){
                try{
                    Thread.sleep(100);
                }catch (Exception e) {
                    e.printStackTrace();
                }
                System.out.println(this.info.getName()+"<---->"+this.info.getAge());
            }
        }
    }
     
    /**
     * 试c?/div>
     * */
    class hello{
        public static void main(String[] args) {
            Info info=new Info();
            Producer pro=new Producer(info);
            Consumer con=new Consumer(info);
            new Thread(pro).start();
            new Thread(con).start();
        }
    }
    【运行结果】:
    Rollen<---->100
    chunGe<---->20
    chunGe<---->100
    Rollen<---->100
    chunGe<---->20
    Rollen<---->100
    Rollen<---->100
    Rollen<---->100
    chunGe<---->20
    chunGe<---->20
    chunGe<---->20
    Rollen<---->100
    chunGe<---->20
    Rollen<---->100
    chunGe<---->20
    Rollen<---->100
    chunGe<---->20
    Rollen<---->100
    chunGe<---->20
    Rollen<---->100
    chunGe<---->20
    Rollen<---->100
    chunGe<---->20
    Rollen<---->100
    chunGe<---->20
    大家可以从结果中看到Q名字和q龄q没有对于?/div>
     
    那么如何解决呢?
    1Q?加入同步
    2Q?加入{待和唤?/div>
    先来看看加入同步会是如何?/div>
    class Info {
         
        public String getName() {
            return name;
        }
     
        public void setName(String name) {
            this.name = name;
        }
     
        public int getAge() {
            return age;
        }
     
        public void setAge(int age) {
            this.age = age;
        }
     
        public synchronized void set(String name, int age){
            this.name=name;
            try{
                Thread.sleep(100);
            }catch (Exception e) {
                e.printStackTrace();
            }
            this.age=age;
        }
         
        public synchronized void get(){
            try{
                Thread.sleep(100);
            }catch (Exception e) {
                e.printStackTrace();
            }
            System.out.println(this.getName()+"<===>"+this.getAge());
        }
        private String name = "Rollen";
        private int age = 20;
    }
     
    /**
     * 生?/div>
     * */
    class Producer implements Runnable {
        private Info info = null;
     
        Producer(Info info) {
            this.info = info;
        }
     
        public void run() {
            boolean flag = false;
            for (int i = 0; i < 25; ++i) {
                if (flag) {
                     
                    this.info.set("Rollen", 20);
                    flag = false;
                } else {
                    this.info.set("ChunGe", 100);
                    flag = true;
                }
            }
        }
    }
     
    /**
     * 消费者类
     * */
    class Consumer implements Runnable {
        private Info info = null;
     
        public Consumer(Info info) {
            this.info = info;
        }
     
        public void run() {
            for (int i = 0; i < 25; ++i) {
                try {
                    Thread.sleep(100);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                this.info.get();
            }
        }
    }
     
    /**
     * 试c?/div>
     * */
    class hello {
        public static void main(String[] args) {
            Info info = new Info();
            Producer pro = new Producer(info);
            Consumer con = new Consumer(info);
            new Thread(pro).start();
            new Thread(con).start();
        }
    }
    【运行结果】:
    Rollen<===>20
    ChunGe<===>100
    ChunGe<===>100
    ChunGe<===>100
    ChunGe<===>100
    ChunGe<===>100
    Rollen<===>20
    ChunGe<===>100
    ChunGe<===>100
    ChunGe<===>100
    ChunGe<===>100
    ChunGe<===>100
    ChunGe<===>100
    ChunGe<===>100
    ChunGe<===>100
    ChunGe<===>100
    ChunGe<===>100
    ChunGe<===>100
    ChunGe<===>100
    ChunGe<===>100
    ChunGe<===>100
    ChunGe<===>100
    ChunGe<===>100
    ChunGe<===>100
    ChunGe<===>100
    从运行结果来看,错ؕ的问题解决了Q现在是Rollen 对应20QChunGe对于100
    Q但是还是出C重复d的问题,也肯定有重复覆盖的问题。如果想解决q个问题Q就需要用Objectcd忙了?/div>
    Q我们可以用其中的{待和唤醒操作?/div>
    要完成上面的功能Q我们只需要修改Infoc饥_在其中加上标志位Qƈ且通过判断标志位完成等待和唤醒的操作,代码如下Q?/div>
    class Info {
         
        public String getName() {
            return name;
        }
     
        public void setName(String name) {
            this.name = name;
        }
     
        public int getAge() {
            return age;
        }
     
        public void setAge(int age) {
            this.age = age;
        }
     
        public synchronized void set(String name, int age){
            if(!flag){
                try{
                    super.wait();
                }catch (Exception e) {
                    e.printStackTrace();
                }
            }
            this.name=name;
            try{
                Thread.sleep(100);
            }catch (Exception e) {
                e.printStackTrace();
            }
            this.age=age;
            flag=false;
            super.notify();
        }
         
        public synchronized void get(){
            if(flag){
                try{
                    super.wait();
                }catch (Exception e) {
                    e.printStackTrace();
                }
            }
             
            try{
                Thread.sleep(100);
            }catch (Exception e) {
                e.printStackTrace();
            }
            System.out.println(this.getName()+"<===>"+this.getAge());
            flag=true;
            super.notify();
        }
        private String name = "Rollen";
        private int age = 20;
        private boolean flag=false;
    }
     
    /**
     * 生?/div>
     * */
    class Producer implements Runnable {
        private Info info = null;
     
        Producer(Info info) {
            this.info = info;
        }
     
        public void run() {
            boolean flag = false;
            for (int i = 0; i < 25; ++i) {
                if (flag) {
                     
                    this.info.set("Rollen", 20);
                    flag = false;
                } else {
                    this.info.set("ChunGe", 100);
                    flag = true;
                }
            }
        }
    }
     
    /**
     * 消费者类
     * */
    class Consumer implements Runnable {
        private Info info = null;
     
        public Consumer(Info info) {
            this.info = info;
        }
     
        public void run() {
            for (int i = 0; i < 25; ++i) {
                try {
                    Thread.sleep(100);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                this.info.get();
            }
        }
    }
     
    /**
     * 试c?/div>
     * */
    class hello {
        public static void main(String[] args) {
            Info info = new Info();
            Producer pro = new Producer(info);
            Consumer con = new Consumer(info);
            new Thread(pro).start();
            new Thread(con).start();
        }
    }
    【程序运行结果】:
    Rollen<===>20
    ChunGe<===>100
    Rollen<===>20
    ChunGe<===>100
    Rollen<===>20
    ChunGe<===>100
    Rollen<===>20
    ChunGe<===>100
    Rollen<===>20
    ChunGe<===>100
    Rollen<===>20
    ChunGe<===>100
    Rollen<===>20
    ChunGe<===>100
    Rollen<===>20
    ChunGe<===>100
    Rollen<===>20
    ChunGe<===>100
    Rollen<===>20
    ChunGe<===>100
    Rollen<===>20
    ChunGe<===>100
    Rollen<===>20
    ChunGe<===>100
    Rollen<===>20
    先在看结果就可以知道Q之前的问题完全解决?/div>


    Snape 2012-03-31 03:19 发表评论
    ]]> ҹþþþþþþõӰ| þþþƷ2019ѹۿ| ŷպþþƷ| 97þùۺϾƷŮ| þþþùƷŮӰԺ| ƷŮþþ| þþƷav鶹ѿ| Ʒþþ| ޾Ʒþþþþò| þ99ƷСѼ| þþþùպƷվ| ަvþþ| Ʒ99þò| ŷ޳ҹƷþ| ձƷþþĻ| ͵þþþƷר| þþþӰԺС | þۺ97ɫֱ| Ʒþþþþþþ| ɫۺϾþ88ɫۺ | þþùƷ| þĻƷһ| þþƷһ | ŷպ˾Ʒþþѿ| þ÷׾Ʒ| ˼˼þúúȾƷ| þþþþùƷ| Vþþ| Ʒݾþþþø| ˾þô߽AVһ| 99þùѸ| þþƷ99Ӱ| þóۺɫۺ| ҹƷþþþþëƬ| þĻ| 2021Ʒҹþ| Ʒݾþþþø| þ޾ƷVA| պƷרþþ| ĻþþƷ| þþƷĻһ |