哈哈,这么实现也是没办法的事。楼主可以想象,如果是你实现append方法,你会怎么做呢。append(null) 会将null做如何处理呢?
我想大多数人可能都会给出三种处理方案:
1. 直接返回null。一般来讲,append方法都是返回一个StringBuilder对象,所以返回null,有些不符合append的设计思想。
2. 什么都不做,返回原来的StringBuilder对象。这么做似乎合理,但是往StringBuilder里放null,总得和往里放空串有点区别吧。所谓人过留名,雁过留声。所以这种看似合理的方法却不太好。
3. 这种方案就是现在append方法的实现方案了,将null变成"null"。
因此,将null变成"null"是最佳的方案。
re: 关于蚂蚁问题(Ants) 银河使者 2008-05-10 14:14
楼主这个想法非常的好,打满分。
下面用数学归纳法证明一下这个算法。让我们先来看最简单的形式(m=1),有两只蚂蚁的情况,假设细木杆的长度为n,两只蚂蚁的位置分别为p1和p2。并且p2 > p1。其他的条件如原题。下面分别用p1和p2来代表两只蚂蚁。
对于两只蚂蚁,方向组合只有四种,分别如下:
1. p1、p2都向左 最长时间:time(p2)
2. p1、p2都向右 最长时间:time(p1)
3. p1向左、p2向右 最长时间:max(time(p1), time(n - p2))
4. p1向右、p2向左(这种情况会发生碰撞)
最长时间:max(time(n - p1), time(p2))
对于这种情况,实际上p2的时间为time(((p2 - p1) / 2 ) * 2 + n - p2 )= time(n - p1)
p1的时间为time(((p2 - p1) / 2 ) * 2 + p1) = time(p2),
从最终结果看,A- >, < -B 就相当于< -B , A - > 相当于A、B互相穿越而过,并且B只走到A最初的位置,而A也只走到B最初的位置。
从上面四种情况的最长时间可看出,正好将两种蚂蚁p1和p2可能存在的的四种可能:p1、p2、n - p1、n-p2 。我们要做的就是求这四个值的最大值,即max(time(p1)、time(p2)、time(n - p1)、time(n-p2))。 如果用文字来描述的话,就是任意一只蚂蚁到达两端的最长时间就是最终结果。
最简单的情况已经ok了,现在假设m只蚂蚁也成立,那么这m只蚂蚁也可以看成是一只蚂蚁,而m+1只蚂蚁当然就相当于两只蚂蚁了。所以
m = 1 成立
假设m成立
而证明了m+1也成立
所以“任意一只蚂蚁到达两端的最长时间就是最终结果”的结论成立
index保存了当前数字串的索引,index.indexOf(i + 48) < 0就是判断当前的数字的索引是否在index中(由于给定的数字串有重复的数字,因此,只能使用索引来判断了),如果不在,就会认为这个数字还没有加到index中,如果存在了,说明这个数已经在数字串中了。
注:i+48 ,当i=0时,正好是数字0的ASCII,以此类推
本文是Java 1.5 Tiger: A Developer's Notebook 的学习总结,没看过《精通Hibernate》,中文的?谁写的?如果有些雷同,估计这本英文书是最终的源头了。
注释就这点东西,谁讲都是这些内容。上述这本英文书应该是国外最早一批讲j2se5.0的书(可是2004年6出的啊),那时国内好象还没有这种书。
如果连接字符串不在循环中,当然不需要new StringBuilder了。我的意思是说尽量让jvm少建立StringBuilder对象。
本文只是个引子,虽然标签是toString方法,但我们可以引申到其他的任何方法。
变量和常量都是压栈,这在bytecode中没有区别,就象汇编语言,根本就没有变量和常量之分。
如下面的代码
String s = "dd";
String ss = "ok" + s + "xyz" + 5;
System.out.println(ss);
对应的bytecode是
String s = "dd";
// 0 0:ldc1 #32 <String "dd">
// 1 2:astore_1
String ss = (new StringBuilder("ok")).append(s).append("xyz").append(5).toString();
// 2 3:new #16 <Class StringBuilder>
// 3 6:dup
// 4 7:ldc1 #34 <String "ok">
// 5 9:invokespecial #20 <Method void StringBuilder(String)>
// 6 12:aload_1
// 7 13:invokevirtual #25 <Method StringBuilder StringBuilder.append(String)>
// 8 16:ldc1 #36 <String "xyz">
// 9 18:invokevirtual #25 <Method StringBuilder StringBuilder.append(String)>
// 10 21:iconst_5
// 11 22:invokevirtual #38 <Method StringBuilder StringBuilder.append(int)>
// 12 25:invokevirtual #29 <Method String StringBuilder.toString()>
// 13 28:astore_2
System.out.println(ss);
// 14 29:getstatic #41 <Field PrintStream System.out>
// 15 32:aload_2
// 16 33:invokevirtual #47 <Method void PrintStream.println(String)>
// 17 36:return
仍然使用了StringBuilder.append(s)
另外System.out.println(new InfiniteRecursion());和 System.out.println(new InfiniteRecursion().toString());是完全一样的,都会抛出java.lang.StackOverflowError异常
没错,是覆盖或重写(override),已经改过来了!
re: B/S,C/S架构混合使用 银河使者 2008-05-07 19:10
我以前做过一个项目,客户端就是用的delphi,服务端用的jsp+hibernate,效果很好。反正通讯用的都是tcp
re: B/S,C/S架构混合使用 银河使者 2008-05-07 19:09
做C/S的客户端不必非得用java吧,虽然Java是跨平台的,在国内客户端基本都是windows。个人认为客户端用delphi、c++ builder、vb,甚至C#比较好,可以用java做服务端。java的swing、awt或是SWT做GUI远不如delphi这些开发工具方便。如果非得要做的话,netbeans6.1提供的java gui比较好,layout也非常方便,大家可以试试。
re: B/S,C/S架构混合使用 银河使者 2008-05-07 14:27
是的,从技术上差不多。
re: B/S,C/S架构混合使用 银河使者 2008-05-07 09:12
实际上C/S和B/S从底层技术上没什么区别。C/S只是模拟浏览器来访问服务端资源,至于会话状态,可以读取http响应头的Session-cookie信息来处理,至于安全性,客户端可以使用https协议访问服务端,或是自已加密数据。
re: B/S,C/S架构混合使用 银河使者 2008-05-06 17:26
以前也做过很多这处C/S和B/S混合的项目。但有些客户端使用的不是java。当然,服务端也非得使用象EJB一样的重量级组件。如我做过的一个系统C/S部分的客户端使用的是delphi,而服务端只是普通的jsp/servlet程序,也未使用web service,而是通过servlet来为C/S部分的客户端(delphi客户端)返回数据(也包括一些加密数据),而客户端通过http协议访问servlet。当然,B/S部分的还是jsp。这样实现个人感觉比较简单。
现在最新版的NetBeans6.1对Java GUI支持的很好,大家可以去下载试试。非常不错。现在我感觉NetBeans在开发Java GUI、J2ME和ROR上是非常不错的。如果开发这三类程序,NetBeans是首选
to tanleyxu
从bytecode上看是String s = "abc" 不建立String对象。其实也没必要这么较真。至于jvm内部到底如何工作,只有看jvm的源代码了。jvm、MSIL这些东西对String对处理都不太一样,无法只从语意上分析。不知道tanleyxu最后这个评论:
String s1 = "Fred";
String s2 = "Fred";
// s1 == s2
String s1 = new String("Fred");
String s2 = "Fred";
// s1 != s2
String s1 = new String("Fred");
String s2 = new String("Fred");
// s1 != s2
是什么意思.如果String s = "Fred", s是压栈操作,用的是方法栈中的空间。new String(),用的是堆的空间,这没错。难道我最后补充的有问题。我可不这么认为。实际上String s = "aa"确实不创建新的String。反正在bytecode里没找到new。
下面是String s = new String("Fred")的bytecode,看看吧,只有一个new
public class Test
{
public Test()
{
// 0 0:aload_0
// 1 1:invokespecial #1 <Method void Object()>
// 2 4:return
}
public void main(String args[])
{
String s = new String("Fred");
// 0 0:new #2 <Class String>
// 1 3:dup
// 2 4:ldc1 #3 <String "Fred">
// 3 6:invokespecial #4 <Method void String(String)>
// 4 9:astore_2
// 5 10:return
}
}
还有就是在本文中我的分析有一点小毛病,就是String s = "Fred"的确在运行时不创建String对象,只是压栈操作,另外说String s = "Fred"相当于String s = new String("Fred")也不严谨。从底层上它们还是有区别的。但可以肯定的是String s = new String("Fred")在当前方法中肯定是建立一个String对象,而String s = "Fred"并不创建对象。而StringBuilder的toString创建了一个String对象。这从上面的bytecode就可以看出。
四楼的Matthew Chen说的没错。多谢提醒。
String s = new String("Fred")这句,new 肯定是创建了一个String对象。但是"Fred",我看了一下bytecode,好象是直接压栈了,并不创建String对象。
据说这是一道SCJP的考试题,哈哈,哪天再弄点SCJP的试题分析一下。再来几次头脑风暴!
activex、ole、ocx都是基于com技术的。这三种实际上都是com的具体表现。
至于dll,和其它四种没什么关系,虽然Activex、OLE、COM、OCX的扩展名也可以是dll,但也可以是exe,或是ocx/vbx等等。
dll的种类就很多了,com组件有很多是以dll形式提供的,当然,普通的api一般也是被封在dll中。 甚至还有.net程序。
实际上,微软在.net之前,只有两种基本的组件技术,一个是com(在com的基础上出现了很多其他的技术,如activex),另一个就是普通的api了,如windows kernel api。 不过有了.net ,尽尽量使用.net的技术。com注册太麻烦,弄不好就会掉进com hell里去了。
re: 接口、类、抽象类、对象的另类解释 银河使者 2008-04-27 15:34
to stanleyxu
你说接口破坏了oop的规则。在我看来,先不管接口是否打破了oop。单就oop本身来说,它的存在并不是让我们非得使用它,换句话说,我们不能为了使用oop而使用oop,就象有很多java framework,我们也不能为了使用它们而使用它们。
虽然oop从总休上说可以使大规模团队开发成为可能,但oop从某种程度上也确实增加了程序的复杂度,只是现在程序规模的增加程度远远超过了oop所给我们带来的复杂程度,因此,我们感觉oop给我们带来了方便。
但如果各位读过按着oop思想的编写的源代码。就会感觉到,读起来,要远比过程语言更难阅读。当然,我承认有更好的读oop源代码的方法,但oop也确实正在使这个世界变得更复杂。哈哈,这个世界本来就很复杂!!多留恋当初的汇编和C语言时代啊!没有这么多概念,一切都是tech-to-tech。不过社会在发展,当然,编程思想也得与时俱进。但愿将来出个比oop更好的编程方式或技术。最好由计算机自己去编程,那样程序员就可以一边喝咖啡,一边看着自己喜欢的video。尽情地享受生活。 是不是有些象科幻啊! 我就用火箭之父齐奥尔科夫斯基话过的一句话结尾吧:昨天的梦想就是今天的希望,更是明天的现实。 但愿每个人天天做好梦,而且梦想成真!
re: 接口、类、抽象类、对象的另类解释 银河使者 2008-04-27 15:12
哈哈,任何东西都有缺点,抽象类也类例外。不能多继承是目前大多数面象对象语言都存在的问题,有利必有弊。但总体上是平衡的。最好是根据具体的需要使用接口、抽象类或普通类,以及它们的任意组合。没有绝对的好坏之分。只要能满足要求,就是正确的选择。
本文的目的并不是深究这些东东哪个更好,哪个不好。只是在itpub上有人不太明白接口、类、抽象类之间的关系,这是我的一个回答,希望对初学者有一些帮助。至于如何应用它们才更好,并不是本文要讨论的范围。
不过我衷心希望各位高手可以将自己的设计思想和设计理念共享出来,以便和大家分享。谢谢!
re: 接口、类、抽象类、对象的另类解释 银河使者 2008-04-27 13:56
总之,先有的类,然后再有的接口,接口主要是为了制定规范而存在的。如在团队开发过程中,设计师可以会设计一系列的接口,然后所有的开发人员在开发component时,都会遵循这些接口。这样就可以尽量避免设计和实现冲突。
就象servlet、jsp、ejb的规范都是由接口(也有抽象类)组成的。
至于抽象类,我认为是sun的设计师看到接口和类都有缺点。接口虽然可以强迫类必须实现接口的方法,但是如果多个类同时实现一个接口,而这个接口中的一些方法在这些类中的实现是完全一样的。那么就会出现代码冗余(虽然可以使用组合的方式解决,但仍会出现一定的代码冗余)。因此,java就会为我们增加了抽象类,既可以强迫抽象类的子类实现某些方法,又可以达到代码重用。
因此,也可以这么说。所有的方法都是抽象方法的抽象类就是接口,所有的方法都是普通方法的抽象类就相当于普通类(虽然不能创建抽象类的实例)
就象一个划杆,左边代表抽象,右边代表具体。如果划到最左边,就是接口,划到最右边,就相当于普通类(除了不能创建实例,其他的和普通类完全一样)。
总之,有了抽象类,就可以同时拥有接口和普通类的优点,而屏蔽了接口和普通类的缺点。
注:接口的主要缺点是不能代码重用。
类的主要缺点是继承一个普通类后,在创建子类实例时,父类也会创建一个实例,也就是说更耗资源,同时,也不能强迫子类必须继承父类的某些方法。
to Matthew Chen
String s = "Fred"; 这句我查了一下bytecode,应该是一个压栈的操作。如果要是创建String对象,就是四个String对象了。
StringBuilder类的toString确实创建了一个String对象,下面是toString方法的代码。
public String toString() {
// Create a copy, don't share the array
return new String(value, 0, count);
}
re: 接口、类、抽象类、对象的另类解释 银河使者 2008-04-27 11:04
一个类当然可以有多个规格。就象一个模具,如五角星,当然可以有多个规格(如角度不同,五角星也有很多变了型的,哈哈),
接口:规格
类:模具
对象:用模具制作的产品
一个类(模具)可以实现多个接口(规格)。一个模具可以建立多个对象(产品)。
实际上,struts1或struts2的标签根本不用记,只要知道大概有什么样的标签就可以了,有很多IDE(如MyEclipse)都会将这些了标签自动列出来的,包括它们的属性。你要知道的就是这些属性和标签都起什么作用就可以了,至于它们的名子,基本上不用记,顶多知道前几个字母就可以了。
哈哈,我想没人用记事本来编写java程序吧(练习除外)。
那要看如何用了。一般情况下,在action类中不需要使用request和response。而只是做一跳转的动作。这样一来。就显得struts1.x的execute的四个参数有些多余。因为大多数时候用不着。
我的blog:
http://www.blogjava.net/nokiaguy为什么发的是随笔,但显示的是文章数?
还有那么访问总数如何出来?
忘回复