这是一本称为“圣经”的书,入手初看了一下,称“圣经”确实勉强了。其中一些深入的问题作者根本没有理解。
当然首先肯定书不失为一本好书,但问题还是不少,现择录于此。希望再版时能有所修正。
我边读边往这里加。
-------------------------------------------------
如何看"圣经"?
人类历史上那些曾经在某一时期辉煌的经典如璀璨的明星指引着历史中的人们不断前进.但是任何经典都是历史的
产物,也归终于历史........
象thinking in java,或者如同本书,在新技术发展的最初阶段,大多数学习者没有渠道系统全面地了解某一知识体系
的时候,这样的书籍无疑是学习的圣经.就如78年左右"中国的改革开放政策",还被红色的余辉照耀下的人们,对于这
种能给他们的生活,他们的思想带来翻天覆地的变化的伟大思想,除了"圣经"这样的词不足以形容其伟大.但是放眼
今天,学过历史的初中生都已经非常深入地理解和明白"改革开放"的思想内涵和历史背景.在他们眼中,这个政策是
"本应如此"的,何以见其伟大?
反过来说,对于java技术在中国已经有十多年的深入推广,.NET技术在中国已经有五年以上成熟的应用.这些当初的
经典在现在已经显现不出其高深和神圣.说实话我当初对TKJ的崇拜并不比别人低,但现在回过头来看看不过如此.这
本书谈不上思想,最多可以说是比较全面的比较深入地JAVA技术大全.这是任何一个水平在不断发展的技术人员对待
一部经典的正常心理,我们不能否认它们在当初的神圣和辉煌以及它给我们的能力提高所起的巨大指导作用.但我们
也坚决不能把它奉为永恒的经典!回过头来批判地看待正是对它的尊重与怀念.
本着同样的心情,本书出致3.0版,已经称不上圣经.非常简单的一个道理,因为一本书的升级永远不会比你的技术水平
的提高快.就我下面的这些问题,如果在此书第一版面市的时候我就能认识这些问题,那我可能就是全球顶级大牛了.
但我不是,我连普通高手都不是,只是我的水平这本书本身提高得快而已.
-------------------------------------------------
第63页下面那个图说明
public const string BestNbaTeam = "timberwolves";是常量的例子的图中编译后成.field public static literal string BestNbaTeam = "timberwolves"根本说明不了它是常量,应该加上一句调用:
Console.WriteLine(BestNbaTeam);编译后是 ldstr "timberwolves"而不是ldsfld string className::BestNbaTeam这才能说明问题.
-------------------------------------------------
64/65页对readonly的描述不准确确,不是不能改变而是一经赋值就不能重新赋值,简单说变量只能永远指向
最初的那个对象.不能重新赋值,但对象本身可以改变.
static readonly StringBuilder sb = new StringBuilder("axman");
static void Main(string[] args)
{
Console.WriteLine(sb.ToString());
sb.Append(' is a great person!');
Console.WriteLine(sb.ToString());
Console.ReadLine();
}
你完全可以改变sb指向的对象的内容.但你不能再把它指向另一个对象.
static void Main(string[] args)
{
sb = new new StringBuilder("axman1");
Console.ReadLine();
}
其实这和java中final变量的意思是一样的.
-------------------------------------------------
92页的Equals实现还是存在重大设计性错误。作者对陷井并不了解。
按作者的想法实现下面的类,看看是什么结果?
a==b,但b!=a
class Person {
public string name;
public int age;
public Person(string name,int age) {
this.name = name;
this.age = age;
}
public override bool Equals(object obj)
{
if (obj != null && obj is Person) {
Person temp = (Person)obj;
if (temp.name == this.name && temp.age == this.age) return true;
}
return false;
}
public override int GetHashCode()
{
return base.GetHashCode();
}
}
class ChinaPerson : Person {
public string city;
public ChinaPerson(string name, int age,string city) : base(name,age)
{
this.city = city;
}
public override bool Equals(object obj)
{
if (obj != null && obj is ChinaPerson)
{
ChinaPerson temp = (ChinaPerson)obj;
if (temp.name == this.name && temp.age == this.age && temp.city == this.city) return true;
}
return false;
}
public override int GetHashCode()
{
return base.GetHashCode();
}
}
static class Program
{
static void Main(string[] args)
{
ChinaPerson cp = new ChinaPerson('axman', 100, 'bj');
Person p = new Person('axman',100);
Console.WriteLine(p.Equals(cp));
Console.WriteLine(cp.Equals(p));
Console.ReadLine();
}
}
-------------------------------------------------
142页对于引用类型转换,仍然采用了笨拙的方法,浪费性能。
if(e is Manager){
((Manager)e).XXX;
}
这样的调用首先e is Manager要做isinst操作来测试类型,然后再调用castclass来强行转换。
而Manager m = e as Manager只需做isinst,如果返回真就直接用stloc.x操作将e的地址赋给了m.
后面我们只需判断if(m == null)或m!=null来操作m就行了。稍有水平的 .NET程序员应该坚决避免先isinst再
cstaclass这种耗时的操作。
有人说"这里"只是为了说明问题举的简单的例子,没有必要"刻意"表现性能,那么看223页,作者在"刻意"下仍然不
知道直接用as 来简化操作.
-------------------------------------------------
第197/199的clone实现实在是搞笑/愚蠢/无效
首先,197中.
public object Clone(){return new Point(this.x,this.y);}
这种行为本身就是一种非常搞笑的,别说实现得好不好,有这种思维就是一个愚蠢的行为.
clone的目的是什么?就是要通过"复制"而不是new 的方式来生成一个和已有对象状态一致的对象.如果用new 来
实现clone,那么调用者自己不会new ?你new的动作比调用者萧洒?由你new出来的对象比调用者自己new出来的
对象更好控制?既然是new出来的那为什么没事找事加上一个clone?所以这种实现本身就违反clone的意义.且不说
实现得好不好了.
我们再看199页所谓的深复制,Point的成员变量PointDescription有一个成员变量petName,所以作者new 了一个
PointDescription又复制了petName.如果PointDescription的成员变量又包含成成员变量,这样多级的引用呢?按
作者实现思路如何递归并反射进行赋值?如果是私有成员变量你还能给它赋值?这样的代码能实现真正的深复制?
我就想不通一般普通程序员都知道的用序列化实现对象的深复制,到了大师手里就这么难呢?
public object Clone() {
BinaryFormatter bf = new BinaryFormatter();
MemoryStream ms = new MemoryStream();
bf.Serialize(ms, this);
ms = new MemoryStream(ms.ToArray());
return bf.Deserialize(ms);
}//不要做任何异常处理,这里如果发生异常不是程序员的责任.就象int Add(int x,int y){return x+y;}一样,如果发生错误不是你的错误
这样一段对所有要实现深复制的对象都适用的代码难道不比那种要手工不断递归赋值也不能完全深复制的代码强?
我们要做的仅仅是在类前面加一段 [Serializable]而已.(不要钻牛角尖说有些字段不可序列化,那样的情况先反序列化得到一个新对象后再手工生成不可序列化字段也比递归反射再一个一个赋值要高明且完全得多)
-------------------------------------------------
第213页最下面"奇怪的是,同步Invoke()不能直接在C#中调用",我奇怪的是我为什么有直接调用?RP问题?
delegate void Test();
class Program
{
static void t() {
Console.WriteLine("Axman!");
}
static void Main(string[] args)
{
Test t1 = new Test(t);
t1.Invoke();
Console.ReadLine();
}
}
-------------------------------------------------
第267页 使用泛型后加入值类型后,作者说从编译后的IL看到没有Boxing和Unboxing操作,虽然结果巧合是正确的,
但这个说明是完全错误的,假如泛型也是完全基于堆来实现,List<int>对象的Add方法完全可以接收一个值类型后
在方法类Boxing,获取方法完全可以在方法内UnBoxing后再返回值类型.仅从编译后那几行IL不可能说明泛型没有
执行Boxing和Unboing操作.真正说明问题的是显示List<int>对象的_items成员,这个成员是根据传入的类型生成
的该类型数组,List<int> 时就是int[ ] 数组来存放Add加入的数据,这才可以说明没有发生Boxing和Unboing.
-------------------------------------------------
第161页 对表示状态的关键全局变量的改变竟然没有同步,disposed = true;完全是一个初级程序员的思维,任何
两个线程同时运行都有可能使这个"正式的可处置模式"失败.
转自:http://dev2dev.bea.com.cn/blog/axman/200803/08_924.html