正文
匈牙利法用java代码 匈牙利算法结果唯一吗
小程序:扫一扫查出行
【扫一扫了解最新限行尾号】
复制小程序
【扫一扫了解最新限行尾号】
复制小程序
匈牙利算法 java
#includestdio.h
#includestring.h
bool g[201][201];
int n,m,ans;
bool b[201];
int link[201];
bool init()
{
int _x,_y;
memset(g,0,sizeof(g));
memset(link,0,sizeof(link));
ans=0;
if(scanf("%d%d",n,m)==EOF)return false;
for(int i=1;i=n;i++)
{
scanf("%d",_x);
for(int j=0;j_x;j++)
{
scanf("%d",_y);
g[ i ][_y]=true;
}
}
return true;
}
bool find(int a)
{
for(int i=1;i=m;i++)
{
if(g[a][ i ]==1!b[ i ])
{
b[ i ]=true;
if(link[ i ]==0||find(link[ i ]))
{
link[ i ]=a;
return true;
}
}
}
return false;
}
int main()
{
while(init())
{
for(int i=1;i=n;i++)
{
memset(b,0,sizeof(b));
if(find(i))ans++;
}
printf("%d\n",ans);
}
}
Pascal:
Program matching;
Const
max = 1000;
Var
map : array [1..max, 1..max] of boolean; {邻接矩阵}
match: array [1..max] of integer; {记录当前连接方式}
chk : array [1..max] of boolean; {记录是否遍历过匈牙利法用java代码,防止死循环}
m, n, i, t1, t2, ans,k: integer;
Function dfs(p: integer): boolean;
var
i, t: integer;
begin
for i:=1 to k do
if map[p, i] and not chk[ i ] then
begin
chk[ i ] := true;
if (match[ i ] = 0) or dfs(match[ i ]) then {没有被连过 或 寻找到增广路}
begin
match[ i ] := p;
exit(true);
end;{if}
end;{for}
exit(false);
end;{function}
begin{main}
readln(n, m); {N 为二分图左侧点数 M为可连接匈牙利法用java代码的边总数}
fillchar(map, sizeof(map), 0);
k:=0;
for i:=1 to m do{initalize}
begin
readln(t1, t2);
map[t1, t2] := true;
if kt2 then k:=t2;
end;{for}
fillchar(match, sizeof(match), 0);
ans := 0;
for i:=1 to n do
begin
fillchar(chk, sizeof(chk), 0);
if dfs(i) then inc(ans);
end;
writeln(ans);
for i:=1 to 1000 do
if match[ i ] 0 then
writeln(match[ i ], '--', i);
end.
编程5分钟,命名2小时!大神程序员都在用这套命名方法
在 软件中随处可见命名:要给变量、函数、参数、类和封包命名匈牙利法用java代码,还要给源代码及源代码所在目录命名匈牙利法用java代码,甚至还有jar文件、war文件和ear文件命名。
但是匈牙利法用java代码,看似简单的命名,也是让不少程序员头疼的问题。 有一些小伙伴,在进行变量命名的时候,对于自己熟悉的英文,可能还会用英文命名一下,如果需要命名的部分不会用英文表达,或许就直接用拼音了。
有的童鞋一下想不起来怎么命名,直接用拼音直接用aa,bb等这样没有任何代表意义的字母来命名,可读性非常差,可能自己今天写的,一个星期后回来再看,也忘记其具体代表的含义了。
因此,许多人在写代码之前,总会在想啊想啊,用什么命名法好呢?对于经常在C++、Java、Python等主流语言上切换的强迫症来说,换个语言换种命名风格简直不要太混乱。
既然有这么多命名要做,不妨做好它。本期内容中,异步君为大家带来了起个好名字应遵从的几条简单规则,一起来看看吧
— 01 —
名副其实
名副其实说起来简单。我们想要强调,这事很严肃。选个好名字要花时间,但省下来的时间比花掉的多。注意命名,而且一旦发现有更好的名称,就换掉旧的。这么做,读匈牙利法用java代码你代码的人(包括你自己)都会更开心。
变量、函数或类的名称应该已经答复了所有的大问题。它该告诉你,它为什么会存在,它做什么事,应该怎么用。如果名称需要注释来补充,那就不算是名副其实。
名称d什么也没说明。它没有引起读者对时间消逝的感觉,更别说以日计了。我们应该选择指明了计量对象和计量单位的名称:
选择体现本意的名称能让人更容易理解和修改代码。下列代码的目的何在?
为什么难以说明上述代码要做什么事?里面并没有复杂的表达式,空格和缩进中规中矩,只用到三个变量和两个常量,甚至没有涉及任何其他类或多态方法,只是(或者看起来是)一个数组的列表而已。
问题不在于代码的简洁度,而在于代码的模糊度:即上下文在代码中未被明确体现的程度。上述代码要求我们了解类似以下问题的答案:
(1)theList中是什么类型的东西?
(2)theList零下标条目的意义是什么?
(3)值4的意义是什么?
(4)我怎么使用返回的列表?
问题的答案没体现在代码段中,可代码段就是它们该在的地方。比方说,我们在开发一种扫雷 游戏 ,我们发现,盘面是名为theList的单元格列表,那就将其名称改为gameBoard。
盘面上每个单元格都用一个简单数组表示。我们还发现,零下标条目是一种状态值,而该种状态值为4表示“已标记”。只要改为有意义的名称,代码就会得到相当程度的改进:
注意,代码的简洁性并未被触及。运算符和常量的数量全然保持不变,嵌套数量也全然保持不变,但代码变得明确多了。
还可以更进一步,不用int数组表示单元格,而是另写一个类。该类包括一个名副其实的函数(称为isFlagged),从而掩盖住那个魔术数[1]。于是得到函数的新版本:
只要简单改一下名称,就能轻易知道发生了什么。这就是选用好名称的力量。
— 02 —
避免误导
程序员必须避免留下掩藏代码本意的错误线索。应当避免使用与本意相悖的词,例如,hp、aix和sco都不该用作变量名,因为它们都是Unix平台或类Unix平台的专有名称。即便你是在编写三角计算程序,hp看起来是一个不错的缩写[2],但那也可能会提供错误信息。
别用accountList来指称一组账号,除非它真的是List类型。List一词对程序员有特殊意义。如果包纳账号的容器并非真是一个List,就会引起错误的判断。
所以,用accountGroup或bunchOfAccounts,甚至直接用accounts都会好一些。
提防使用外形相似度较高的名称。例如,想区分模块中某处的XYZControllerFor-EfficientHandlingOfStrings和另一处的XYZControllerForEfficientStorage-OfStrings,会花多长时间呢?这两个词的外形实在太相似了。
以同样的方式拼写出同样的概念才是信息。拼写前后不一致就是误导。我们很享受现代Java编程环境的自动代码完成特性。键入某个名称的前几个字母,按一下某个热键组合(如果有的话),就能得到一列该名称的可能形式。
假如相似的名称依字母顺序放在一起,且差异很明显,那就会相当有助益,因为程序员多半会压根不看你的详细注释,甚至不看该类的方法列表就直接看名字挑一个对象。
误导性名称真正可怕的例子,是用小写字母l和大写字母O作为变量名,尤其是在组合使用的时候。当然,问题在于它们看起来完全像是常量“壹”和“零”。
读者可能会认为这纯属虚构,但我们确曾见过充斥这类名称的代码。有一次,代码作者建议用不同字体写变量名,好显得更清楚些,但前提是这种方案得要通过口头和书面传递给未来所有的开发者才行。后来,只是做了简单的重命名操作,就解决了问题,而且也没引起别的问题。
— 03 —
做有意义的区分
如果程序员只是为满足编译器或解释器的需要而写代码,就会制造麻烦。例如,因为同一作用范围内两样不同的东西不能重名,你可能会随手改掉其中一个的名称,有时干脆以错误的拼写充数,结果就会出现在更正拼写错误后导致编译器出错的情况。
光是添加数字系列或是废话远远不够,即便这足以让编译器满意。如果名称必须相异,那么其意思也应该不同才对。
以数字系列命名(a1、a2…aN)是依义命名的对立面。这样的名称纯属误导——完全没有提供正确信息,没有提供导向作者意图的线索。试看:
如果参数名改为source和destination,这个函数就会像样许多。
废话是另一种没意义的区分。假设你有一个Product类,如果还有一个名为ProductInfo或ProductData的类,那它们的名称虽然不同,意思却无区别。Info和Data就像a、an和the一样,是意义含混的废话。
注意,只要体现出有意义的区分,使用a和the这样的前缀就没错。例如,你可能把a用在域内变量,而把the用于函数参数[5]。但如果你已经有一个名为zork的变量,又想调用一个名为theZork的变量,麻烦就来了。
废话都是冗余。variable一词永远不应当出现在变量名中。table一词永远不应当出现在表名中。NameString会比Name好吗?难道Name会是一个浮点数?如果是这样,就违反了关于误导的规则。
设想有一个名为Customer的类,还有一个名为CustomerObject的类,它们的区别何在呢?哪一个是表示客户 历史 支付情况的最佳方式?
有一个应用反映了这种状况。为当事者讳,我们改了一下,不过犯错的代码的确就是这个样子:
程序员怎么知道该调用哪个函数呢?
如果缺少明确约定,那么变量moneyAmount与money就没区别,customerInfo与customer没区别,accountData与account没区别,theMessage也与message没区别。要区分名称,就要以读者能鉴别不同之处的方式来区分。
— 04 —
使用读得出来的名称
人类长于记忆和使用单词。大脑的相当一部分就是用来容纳和处理单词的。单词能读得出来。人类的大脑中有那么大的一块地方用来处理言语,若不善加利用,实在是种耻辱。
如果名称读不出来,讨论的时候就会像个傻鸟。“哎,这儿,鼻涕阿三喜摁踢(bee cee arr three cee enn tee)[6]上头,有个皮挨死极翘(pee ess zee kyew)[7]整数,看见没?”这不是小事,因为编程本就是一种 社会 活动。
有一家公司,程序里面写了一个genymdhms(生成日期,年、月、日、时、分、秒),他们一般读作“gen why emm dee aich emm ess”[8]。我有见字照拼读的恶习,于是开口就念“gen-yah-mudda-hims”。
后来好些设计师和分析师都有样学样,听起来傻乎乎的。我们知道典故,所以会觉得很 搞笑 。 搞笑 归 搞笑 ,实际是在强忍糟糕的命名。在给新开发者解释变量名的意义时,他们总是读出傻乎乎的自造词,而非恰当的英语词。比较
现在读起来就像人话了:“喂,Mikey,看看这条记录!生成时间戳(generation timestamp)[9]被设置为明天了!不能这样吧?”
— 05 —
使用可搜索的名称
对于单字母名称和数字常量,有一个问题,就是很难在一大篇文字中找出来。
找MAX_CLASSES_PER_STUDENT很容易,但想找数字7就麻烦了,它可能是某些文件名或其他常量定义的一部分,出现在因不同意图而采用的各种表达式中。如果该常量是个长数字,又被人错改过,就会逃过搜索,从而造成错误。
同样,e也不是一个便于搜索的好变量名,它是英文中最常用的字母,在每个程序、每段代码中都有可能出现。由此而见,长名称胜于短名称,搜得到的名称胜于用自造编码代写就的名称。
窃以为单字母名称仅用于短方法中的本地变量。名称长短应与其作用域大小相对应 [N5]。若变量或常量可能在代码中多处使用,则应赋予其便于搜索的名称。再比较:
注意,上面代码中的sum并非特别有用的名称,不过至少搜得到它。采用能表达意图的名称,貌似拉长了函数代码,但要想想看,WORK_DAYS_PER_WEEK比数字5好找得多,而列表中也只剩下了体现作者意图的名称。
— 06 —
避免使用编码
编码已经太多,无谓再自找麻烦。把类型或作用域编进名称里面,徒然增加了解码的负担。没理由要求每位新人都在弄清要应付的代码之外(那算是正常的),还要再搞懂另一种编码“语言”。这对解决问题而言,纯属多余的负担。带编码的名称通常也不便发音,容易打错。
匈牙利语标记法
在往昔名称长短很重要的时代,我们毫无必要地破坏了不编码的规矩,如今后悔不迭。Fortran语言要求首字母体现出类型,导致了编码的产生。BASIC语言的早期版本只允许使用一个字母再加上一位数字。匈牙利语标记法[10](Hungarian Notation,HN)将这种态势愈演愈烈。
在Windows的C语言API的时代,HN相当重要,那时所有名称要么是一个整数句柄,要么是一个长指针或者void指针,要不然就是string的几种实现(有不同的用途和属性)之一。那时候编译器并不做类型检查,程序员需要匈牙利语标记法来帮助自己记住类型。
现代编程语言具有更丰富的类型系统,编译器也记得并强制使用类型。而且,程序员趋向于使用更小的类、更短的方法,好让每个变量的定义都在视野范围之内。
Java程序员不需要类型编码,因为对象是强类型的,代码编辑环境已经先进到在编译开始前就能监测到类型错误的程度!所以,如今HN和其他的类型编码形式都纯属多余。它们增加了修改变量、函数或类的名称或类型的难度,它们增加了阅读代码的难度,它们制造了让编码系统误导读者的可能性。
成员前缀
也不必用m_前缀来标明成员变量。应当把类和函数做得足够小,以消除对成员前缀的需要。你应当使用某种可以高亮或用颜色标出成员的编辑环境。
此外,人们会很快学会无视前缀(或后缀),而只看到名称中有意义的部分。代码读得越多,眼中就越没有前缀。最终,前缀变作了不入法眼的废料,变作了旧代码的标志物。
接口和实现
有时也会出现采用编码的特殊情形。比如,你在做一个创建形状用的抽象工厂(Abstract Factory),该工厂是一个接口,要用具体类来实现。你怎么来命名工厂和具体类呢?IShapeFactory和ShapeFactory吗?我喜欢不加修饰的接口。前导字母I被滥用到了说好听点儿是干扰,说难听点儿根本就是废话的程度。
我不想让用户知道我给他们的是接口,而就想让他们知道那是一个ShapeFactory。如果在接口和实现中必须选其一来编码的话,我宁肯选择实现。ShapeFactoryImp,甚至是丑陋的CShapeFactory,都比对接口名称编码好。
-END-
代码整洁之道
作者: [美] 罗伯特·C. 马丁(Robert C. Martin)
译者: 韩磊
内容简介:
软件质量,不但依赖架构及项目管理,而且与代码质量紧密相关。这一点,无论是敏捷开发流派还是传统开发流派,都不得不承认。
本书提出一种观点:代码质量与其整洁度成正比。干净的代码,既在质量上较为可靠,也为后期维护、升级奠定了良好基础。作为编程领域的佼佼者,本书作者给出了一系列行之有效的整洁代码操作实践。这些实践在本书中体现为一条条规则(或称“启示”),并辅以来自实际项目的正、反两面的范例。只要遵循这些规则,就能编写出干净的代码,从而有效提升代码质量。
本书阅读对象为一切有志于改善代码质量的程序员及技术经理。书中介绍的规则均来自作者多年的实践经验,涵盖从命名到重构的多个编程方面,虽为一“家”之言,然诚有可资借鉴的价值。
如何写出好的Java代码
如何写出好的Java代码
1. 优雅需要付出代价。
从短期利益来看,对某个问题提出优雅的解决方法,似乎可能花你更多的时间。但当它终于能够正确执行并可轻易套用于新案例中,不需要花上数以时计,甚至以天计或以月计的辛苦代价时,你会看得到先前所花功夫的回报(即使没有人可以衡量这一点)。这不仅给你一个可更容易开发和调试的程序,也更易于理解和维护。这正是它在金钱上的价值所在。这一点有赖某种人生经验才能够了解,因为当你努力让某一段程序代码变得比较优雅时,你并不是处于一种具生产力的状态下。但是,请抗拒那些催促你赶工的人们,因为那么做只会减缓你的速度罢了。
2. 先求能动,再求快。
即使你已确定某段程序代码极为重要,而且是系统的重要瓶颈,这个准则依然成立。尽可能简化设计,让系统能够先正确动作。如果程序的执行不够快,再量测其效能。几乎你总是会发现,你所认为的”瓶颈”其实都不是问题所在。把你的时间花在刀口上吧。
3. 记住”各个击破”的原理。
如果你所探讨的问题过于混杂,试着想像该问题的基本动作会是什么,并假设这一小块东西能够神奇地处理掉最难的部分。这”一小块”东西其实就是对象–请撰写运用该对象的程序代码,然后检视对象,并将其中困难的部分再包装成其他对象,依此类推。
4. 区分class开发者和class使用者(使用端程序员)。
Class 使用者扮演着”客户”角色,不需要(也不知道)class的底层运作方式。Class开发者必须是class设计专家,并撰写class,使它能够尽可能被大多数新手程序员所用,而且在程序中能够稳当执行。一套程序库只有在具备通透性的情况下,使用起来才会容易。
5.当你撰写class时,试着给予明了易懂的名称,减少不必要的注解。
你给客户端程序员的接口,应该保持概念上的单纯性。不了这个目的,当函数的重载(overloading)适合制作出直觉、易用的接口时,请善加使用。
6. 也必你的分析和设计必须让系统中的classes保持最少,须让其Public interfaces保持最少,以及让这些classes和其他classes之间的关联性( 尤其是base classes)保持最少。
如果你的设计所得结果更甚于此,请问问自己,是否其中每一样东西在整个程序生命期中都饶富价值?如果并非如此,那么,维护它们会使你付出代价。开发团队的成员都有不维护”无益于生产力提升”的任何东西的倾向;这是许多设计方法无法解释的现象。
7. 让所有东西尽量自动化。先撰写测试用的程序代码(在你撰写class之前),并让它和class结合在一起。请使用makefile或类似工具,自动进行测试动作。
通过这种方式,只要执行测试程序,所有的程序变动就可以自动获得验证,而且可以立即发现错误。由于你知道的测试架构所具备的安全性,所以当你发现新的需求时,你会更勇于进行全面修改。请记住,程序语言最大的改进,是来自型别检查、异常处理等机制所赋予的内置测试动作。但这些功能只能协助你到达某种程度。开发一个稳固系统时,你得自己验证自己的classes或程序的性质。
8. 在你撰写class之前先写测试码,以便验证你的class 是否设计完备。如果你无法撰写测试码,你便无法知道你的class 的可能长相。撰写测试码通常能够显现出额外的特性(features)或限制 ( constraints)__它们并不一定总是能够在分析和设计过程中出现。测试码也可做为展示class 用法的示例程序。
9. 所有软件设计上的问题,都可以通过”引入额外的概念性间接层(conceptual indirection)”加以简化。这个软件工程上的基础法则是抽象化概念的根据,而抽象化概念正是面向对象程序设计的主要性质。
10. 间接层(indirection)应该要有意义(和准则-9致)。
这里所指的意义可以像”将共用程序代码置于惟一函数”这么简单。如果你加入的间接层(或抽象化、或封装等等)不具意义,它可能就和没有适当的间接层一样糟糕。
11. 让class尽可能微小而无法切割(atomic)。
赋予每个class单一而清楚的用途。如果你的classes或你的系统成长得过于复杂,请将复杂的classes切割成比较简单的几个classes。最明显的一个判断指针就是class的大小:如果它很大,那么它工作量过多的机会就可能很高,那就应该被切割。重新设计class的建议线索是:
1) 复杂的switch语句:请考虑运用多态(Polymorphism)。
2) 许多函数各自处理类型极为不同的动作:请考虑切割为多个不同的(classes)。
12. 小心冗长的引数列(argument lists)。
冗长的引数列会使函数的调用动作不易撰写、阅读、维护。你应该试着将函数搬移到更适当的class中,并尽量以对象为引数。
13. 不要一再重复。
如果某段程序代码不断出现于许多derived class函数中,请将该段程序代码置于某个base class 函数内,然后在derived class函数中调用。这么做不仅可以省下程序代码空间,也可以让修改该段程序代码动作更易于进行。有时候找出此种共通程序代码还可以为接口增加实用功能。
14. 小心switch语句或成串的if-else 子句。
通常这种情况代表所谓的”type-check coding”。也就是说究竟会执行哪一段程序代码,乃是依据某种型别信息来做抉择(最初,确切型别可能不十分明显)。你通常可以使用继承和多态来取代此类程序代码;Polymorphical method (多态函数)的调用会自动执行此类型别检验,并提供更可靠更容易的扩充性。
15. 从设计观点来看,请找出变动的事物,并使它和不变的事物分离。
也就是说,找出系统中可能被你改变的元素,将它们封装于classes中。你可以在《Thinking in Patterns with Java》(可免费下载于 www. BruceEckel. Com)大量学习到这种观念。
16. 不要利用subclassing来扩充基础功能。
如果某个接口元素对class而言极重要,它应该被放在base class 里头,而不是直到衍生(derivation)时才被加入。如果你在继承过程中加入了函数,或许你应该重新思考整个设计。
17. 少就是多。
从class 的最小接口开始妨展,尽可能在解决问题的前提下让它保持既小又单纯。不要预先考量你的class被使用的所有可能方式。一旦class被实际运用,你自然会知道你得如何扩充接口。不过,一旦class被使用后,你就无法在不影响客户程序代码的情况下缩减其接口。如果你要加入更多函数倒是没有问题–不会影响既有的客户程序代码,它们只需重新编译即可。但即使新函数取代了旧函数的功能,也请你保留既有接口。如果你得通过”加入更多引数”的方式来扩充既有函数的接口,请你以新引数写出一个重载化的函数;通过 这种方式就不会影响既有函数的任何客户了。
18. 大声念出你的classes,确认它们符合逻辑。
请base class和derived class 之间的关系是”is-a”(是一种),让class和成员对象之间的关系是”has-a”(有一个)。
19. 当你犹豫不决于继承(inheritance)或合成(组合,composition)时,请你问问自己,是否需要向上转型(upcast)为基础型别。
如果不需要,请优先选择合成(也就是是使用成员对象)。这种作法可以消除”过多基础型别”。如果你采用继承,使用者会认为他们应该可以向上转型。
20. 运用数据成员来表示数值的变化,运用经过覆写的函数(overrided method)来代表行为的变化 。
也就是说,如果你找到了某个 class, 带有一些状态变量,而其函数会依据这些变量值切换不同的行为,那么你或许就应该重新设计,在subclasses 和覆写后的函数(overrided methods)中展现行为止的差异。
21. 小心重载(overloading)。
函数不应该依据引数值条件式地选择执行某一段程序代码。这种情况下你应该撰写两个或更多个重载函数(overloaded methods)
22. 使用异常体系(exception hierarchies)
最好是从Java标准异常体系中衍生特定的classes, 那么,捕捉异常的人便可以捕捉特定异常,之后才捕捉基本异常。如果你加入新的衍生异常,原有的客户端程序仍能通过其基础型别来捕捉它。
23. 有时候简单的聚合(aggregation)就够了。
飞机上的”旅客舒适系统”包括数个分离的元素:座椅、空调、视讯设备等等,你会需要在飞机上产生许多这样的东西。你会将它们声明为Private成员并开发出一个全新的接口吗?不会的,在这个例子中,元素也是Public接口的一部分,所以仍然是安全的。当然啦,简单聚合并不是一个常被运用的解法,但有时候的确是。
24. 试着从客户程序员和程序维护的角度思考。
你的class应该设计得尽可能容易使用。你应该预先考量可能性有的变动,并针对这些 可能的变动进行设计,使这些变动日后可轻易完成。
25. 小心”巨大对象并发症”。
这往往是刚踏OOP领域的过程式(procedural)程序员的一个苦恼,因为他们往往最终还是写出一个过程式程序,并将它们摆放到一个或两个巨大对象中。注意,除了application framework (应用程序框架,译注:一种很特殊的、大型OO程序库,帮你架构程序本体)之外,对象代表的是程序中的观念,而不是程序本身。
26. 如果你得用某种丑陋的方式来达成某个动作,请将丑陋的部分局限在某个class里头。
27. 如果你得用某种不可移植方式来达成某个动作,请将它抽象化并局限于某个class里头。这样一个”额外间接层”能够防止不可移植的部分扩散到整个程序。这种作法的具体呈现便是Bridge设计模式(design pattern)。
28. 对象不应仅仅只用来持有数据。
对象也应该具有定义明确界限清楚的行为。有时候使用”数据对象”是适当的,但只有在通用形容器不适用时,才适合刻意以数据对象来包装、传输一群数据项。
29. 欲从既有的classes身上产生新的classes时,请以组合(composition)为优先考量。
你应该只在必要时才使用继承。如果在组合适用之处你却选择了继承,你的设计就渗杂了非必要的复杂性。
30. 运用继承和函数覆写机制来展现行为上的差异,运用fields(数据成员)来展现状态上的差异。
这句话的极端例子,就是继承出不同的classes表现各种不同的颜色,而不使用”color”field.
31. 当心变异性(variance)。
语意相异的两个对象拥有相同的动作(或说责任)是可能的。OO世界中存在着一种天生的引诱,让人想要从某个class继承出另一个subclass,为的是获得继承带来的福利。这便是所谓”变异性”。但是,没有任何正当理由足以让我们强迫制造出某个其实并不存在的superclass/subclass关系。比较好的解决方式是写出一个共用的base class,它为两个derived classes制作出共用接口–这种方式会耗用更多空间,但你可以如你所盼望地从继承机制获得好处,而且或许能够在设计上获得重大发现。
32. 注意继承上的限制。
最清晰易懂的设计是将功能加到继承得来的class里头;继承过程中拿掉旧功能(而非增加新功能)则是一种可疑的设计。不过,规则可以打破。如果你所处理的是旧有的class程序库,那么在某个class的subclass限制功能,可能会比重新制定整个结构(俾使新class得以良好地相称于旧 class)有效率得多。
33. 使用设计模式(design patterns)来减少”赤裸裸无加掩饰的机能(naked functionality)”。
举个例子,如果你的class只应该产出惟一一个对象,那么请不要以加思索毫无设计的手法来完成它,然后撰写”只该产生一份对象”这样的注解就拍拍屁股走人。请将它包装成singleton(译注:一个有名的设计模式,可译为”单件”)。如果主程序中有多而混乱的”用以产生对象”的程序代码,请找出类似 factory method这样的生成模式(creational patterns),使价钱可用以封装生成动作减少”赤裸裸无加掩饰的机能”(naked functionality)不仅可以让你的程序更易理解和维护,也可以阻止出于好意却带来意外的维护者。
34. 当心”因分析而导致的瘫痪(analysis paralysis)”。
请记住,你往往必须在获得所有信息之前让项目继续前进。而且理解未知部分的最好也最快的方式,通常就是实际前进一步而不只是纸上谈兵。除非找到解决办法,否则无法知道解决办法。Java拥有内置的防火墙,请让它们发挥作用。你在单一class或一组classes中所犯的错误,并不会伤害整个系统的完整性。
35. 当你认为你已经获得一份优秀的分析、设计或实现时,请试着加以演练。
将团队以外的某些人带进来-他不必非得是个顾问不可,他可以是公司其他团队的成员。请那个人以新鲜的姿态审视你们的成果,这样可以在尚可轻易修改的阶段找出问题,其收获会比因演练而付出的时间和金钱代价来得高。实现 (Implementation)
36. 一般来说,请遵守Sun的程序编写习惯。
价钱可以在以下网址找到相关文档:java.sun.com/docs/codeconv/idex.html。本书尽可能遵守这些习惯。众多Java程序员看到的程序代码,都有是由这些习惯构成的。如果你固执地停留在过去的编写风格中,你的(程序代码)读者会比较辛苦。不论你决定采用什么编写习惯,请在整个程序中保持一致。你可以在home.wtal.de/software-solutions/jindent上找到一个用来重排Java程序的免费工具。
37. 无论使用何种编写风格,如果你的团队(或整个公司,那就更好了)能够加以标准化,那么的确会带来显著效果。这代表每个人都可以在其他人不遵守编写风格修改其作品,这是个公平的游戏。标准化的价值在于,分析程序代码时所花的脑力较小,因而可以专心于程序代码的实质意义。
38. 遵守标准的大小写规范。
将 class名称的第一个字母应为大写。数据成员、函数、对象(references)的第一个字母应为小写。所有识别名称的每个字都应该连在一块儿,所有非首字的第一个字母都应该大写。例如: ThisIsAClassName thisIsAMethodOrFieldName 如果你在static final 基本型别的定义处指定了常量初始式(constant initializers),那么该识别名称应该全为大写,代表一个编译期常量。 Packages是个特例,其名称皆为小写,即使非首字的字母亦是如此。域名(org, net, edu 等等)皆应为小写。(这是Java 1.1迁移至Java 2时的一项改变) 。
39、不要自己发明”装饰用的”Private数据成员名称。
通常这种的形式是在最前端加上底线和其他字符,匈牙利命名法(Hungarian notation)是其中最差的示范。在这种命名法中,你得加入额外字符来表示数据的型别、用途、位置等等。仿佛你用的是汇编语言(assembly language)而编译器没有提供任何协肋似的。这样的命名方式容易让人混淆又难以阅读,也不易推行和维护。就让classes和packages来进行”名称上的范
围制定(name scoping)”吧。
40、当你拟定通用性的class时,请遵守正规形式(canonical form)。
包括equals( )、hashCode( )、clone( ) ( 实现出Cloneable),并实现出Comparable和Serialiable等等。
41、对于那些”取得或改变Private数据值”的函数,请使用Java Beans 的”get”、”set”、”is”等命名习惯,即使你当时不认为自己正在撰写Java Bean。这么做不仅可以轻易以Bean的运用方式来运用你的class,也是对此类函数的一种标准命名方式,使读者更易于理解。
42、对于你所拟定的每一个class,请考虑为它加入static public test( ),其中含有class功能测试码。
你不需要移除该测试就可将程序纳入项目。而且如果有所变动,你可以轻易重新执行测试。这段程序代码也可以做为class的使用示例。
43、有时候你需要通过继承,才得以访问base class的protected成员。
这可能会引发对多重基类(multiple base types)的认识需求。如果你不需要向上转型,你可以先衍生新的class发便执行protected访问动作,然后在”需要用到上述 protected成员”的所有classes中,将新class声明为成员对象,而非直接继承。
44、避免纯粹为了效率考量而使用final函数。
只有在程序能动但执行不够快时,而且效能量测工具(profiler)显示某个函数的调用动作成为瓶颈时,才使用final函数。
45、如果两个classes因某种功能性原因而产生了关联(例如容器containers和迭代器iterators),那么请试着让其中某个class成为另一个class 的内隐类(inner class)。
这不仅强调二者间的关联,也是通过”将class名称嵌套置于另一个class 内”而使同一个class 名称在单一Package中可被重复使用。Java 容器库在每个容器类中都定义了一个内隐的(inner)Iterator class,因而能够提供容器一份共通接口。运用内隐类的另一个原因是让它成为private实现物的一部分。在这里,内隐类会为信息隐藏带来好处,而不是对上述的class关联性提供肋益,也不是为了防止命名空间污染问题(namespace pollution)。
46、任何时候你都要注意那些高度耦合(coupling)的 classes.请考虑内隐类(inner classes)为程序拟定和维护带来的好处。内隐类的使用并不是要去除classes间的耦合,而是要让耦合关系更明显也更便利。
47、不要成为”过早最佳化”的牺牲品。
那会让人神经错乱。尤其在系统建构初期,先别烦恼究竟要不要撰写(或避免)原生函数(native methods)、要不要将某些数声明为final、要不要调校程序代码效率等等。你的主要问题应该是先证明设计的正确性,除非设计本身需要某种程度的效率。
48、让范围(作用域,scope)尽可能愈小愈好,这么一来对象的可视范围和寿命都将尽可能地小。
这种作法可降低”对象被用于错误场所,因而隐藏难以察觉的臭虫”的机会。假设你有个容器,以及一段走访该容器的程序片段。如果你复制该段程序代码,将它用于新的容器身上,你可能会不小心以旧容器的大小做为新容器的走访上限值。如果旧容器已不在访问范围内,那么编译期便可找出这样的错误。
49、使用Java 标准程序库提供的容器。
请熟悉他们的用法。你将因此大幅提升你的生产力。请优先选择ArrayList来处理序列(sequences),选择HashSet来处理集合(sets)、选择HashMap来处理关联式数组(associative arrays),选择Linkedlist (而不是Stack) 来处理 shacks和queues。
50、对一个强固的(robust)程序而言,每一个组成都必须强固。
请在你所撰写的每个class中运用Java 提供的所有强固提升工具:访问权限、异常、型别检验等等。通过这种方式,你可以在建构系统时安全地移往抽象化的下一个层次。
51、宁可在编译期发生错误,也不要在执行期发生错误。
试着在最靠近问题发生点的地方处理问题。请优先在”掷出异常之处”处理问题,并在拥有足够信息以处理异常的最接近处理函数(handler)中捕捉异常。请进行现阶段你能够对该异常所做的处理;如果你无法解决问题,应该再次掷出异常。
52、当心冗长的函数定义。
函数应该是一种简短的、”描述并实现class接口中某个可分离部分”的功能单元。过长且复杂的函数不仅难以维护,维护代价也高。或许它尝试做太多事情了。如果你发现这一类函数,代表它应该被切割成多相函数。这种函数也提醒你或许得撰写新的class。小型函数同样能够在你的class中被重复运用。(有时候函数必须很大才行,但它们应该只做一件事情。)
53、尽可能保持”Private”。
一旦你对外公开了程序库的概况(method、Class 或field)。你便再也无法移除它们。因为如果移除它们,便会破坏某个现有的程序代码,使得它们必须重新被编写或重新设计。如果你只公开必要部分,那么你便可以改变其他东西而不造成伤害。设计总是会演化,所以这是个十分重要的自由度。通过这种方式,实现码的更动对derived class 造成的冲击会降最低。在多线程环境下,私密性格外重要-只有private数据可受保护而不被un-synchronized(未受同步控制)的运用所破坏。
54、大量运用注解,并使用javadoc的”注解文档语法”来产生程序的说明文档。
不过注解应该赋予程序代码真正的意义;如果只是重申程序代码已经明确表示的内容,那是很烦人的。请注意,通常Java class和其函数的名称都很长,为的便是降低注解量。
55、避免使用”魔术数字”,也就是那种写死在程序代码里头的数字–如果你想改变它们,它们就会成为你的恶梦,因为你永远都没有办法知道”100″究竟代表” 数组大小”或其他东西。你应该产生具描述性的常量度名称,并在程序中使用该常量名称。这使程序更易于理解也更易于维护。
56、撰写构造函数时,请考虑异常状态。最好情境下,构造函数不执行任何会掷出异常的动作。
次佳情境下,class 只继承自(或合成自)强固的(robust)classes,所以如有任何异常被掷出,并不需要清理。其他情况下,你就得在finally子句清理合成后的classes。如果某个构造函数一定会失败,适当的动作就是掷出异常,使调用者不至于盲目认为对象已被正确产生而继续执行。
57、如果你的class需要在”客户程序员用完对象”后进行清理动作,请将清理动作,放到单一而定义明确的函数中。最好令其名称为cleanup() 以便能够将用途告诉他人。此外请将boolean旗标放到class中,用以代表对象是否已被清理,使finalize()得以检验其死亡条件(请参考第 4章)。
58、finalize() 只可用于对象死亡条件的检验(请参考4章),俾有益于调试。
特殊情况下可能需要释放一些不会被垃圾回收的内存。因为垃圾回收器可能不会被唤起处理你的对象,所以你无法使用finalize()执行必要的清理动作。基于这个原因,你得拟定自己的”清理用”函数。在class finalize()中,请检查确认对象的确已被清理,并在对象尚未被清理时,掷出衍生自Runtime Exception 的异常。使用这种架构前,请先确认finalize()在你的系统上可正常动作(这可能需要调用System.gc()来确认)。
59、如果某个对象在某个特定范围(scope)内必须被清理(cleaned up),而不是被垃圾回收机制收回,请使用以下方法;将对象初始化,成功后立刻进入拥有finally子句的一个try区段内。Finally子句会引发清理动作。
60、当你在继承过程中覆写了finalize(),请记得调用super. Finalize()。
但如果你的”直接上一层superclass”是Object,,就不需要这个动作。你应该让super.finalize() 成为被覆写(overridden)之finalize()的最后一个动作而不是第一个动作,用以确保base class的组件在你需要它们的时候仍然可用。
61、当你撰写固定大小的对象容器,请将它们转换为数组–尤其是从某个函数返回此一容器时。
通过这种方式,你可以获得数组的”编译期型别检验”的好处,而且数组接收者可能不需要”先将数组中的对象加以转型”便能加以使用。请注意,容器库的base class (Java. Util. Collection) 具有两个toArray(),能够达到这个目的。
62、在interface(接口)和abstract class(抽象类)之间,优先选择前者。
如果你知道某些东西即将被设计为一个base class,你的第一选择应该是让它成为interface;只有在一定得放进函数或数据成员时,才应该将它改为abstract class. Interface只和”客户端想进行什么动作”有关,class则比较把重心放在实现细节上。
63、在构造函数中只做惟一必要动作:将对象设定至适当状态。
避免调用其他函数(除了final函数),因为这些函数可能会被其他人覆写因而使你在建构过程中得不可预期的结果(请参考第7章以取得更详细的信息)。小型而简单的构造函数比较不可能掷出异常或引发问题。
64、为了避免一个十分令人泄气的经验,请确认你的classpath中的每个名称,都只有一个未被放到packages里头class。否则编译器会先找到另一个名称相同的class,并回报错误消息。如果你怀疑你的classpath出了问题,试着从classpath中的每个起点查找同名的.class文件。最好还是将所有classes都放到packages里头。
65、留意一不小心犯下的重载(overloading)错误。
如果你覆写base class 函数时没有正确拼写其名称,那么便会增加一个新的函数,而不是覆写原有的函数。但是情况完全合法,所以你不会从编译器或执行期系统得到任何错误消息–你的程序代码只是无法正确作用,如此而已。
66、当心过早最佳化。
先让程序动起来,再让它快–但只有在你必须(也就是说只有在程序被证明在某段程序代码上遭遇效能瓶颈)时才这么做。除非你已经使用效能量测工具(profiler)找出瓶颈所在,否则你可能性只是在浪费你的时间。效能调校的”隐藏成本”便是让你的程序代码变得更不可读、更难维持。
67、记住,程序代码被阅读的时间多于它被撰写的时间。
清晰的设计能够制作出去易懂的程序。注解、细节说明、示例都是无价的。这些东西能够帮助你和你的后继者。如果没有其他信息,那么Java 线上文档找出一些有用的信息时,你所遭遇的挫败应该足以让你相信这一点。
java中方法的命名问题 什么by with for 代表什么意思,比如getCardByNo 中的by
首先,程序开发中,变量、方法名应该尽可能的定义做到顾名思义,即让人看到你的名称就大概的知道其的含义了。
其次,by with for三个都是英语中的介词,他们在上面的定义中跟在英语的意思是一样的,即是"以...、用....、通过...."的意思,就比如你题目中方法,意思就是通过卡号获取卡片信息。
现在大体明白了吧。
有问题欢迎提问,满意请采纳!
使用Java作为程序语言时,好的命名规范有哪些
Package 匈牙利法用java代码的命名
Package 的名字应该都是由一个小写单词组成。
Class 的命名
Class 的名字必须由大写字母开头而其他字母都小写的单词组成
Class 变量的命名
变量的名字必须用一个小写字母开头。后面的单词用大写字母开头。
Static Final 变量的命名
Static Final 变量的名字应该都大写匈牙利法用java代码,并且指出完整含义。
参数的命名
参数的名字必须和变量的命名规范一致。
数组的命名
数组应该总是用下面的方式来命名:
byte[] buffer;
而不是:
byte buffer[];
方法的参数
使用有意义的参数命名匈牙利法用java代码,如果可能的话,使用和要赋值的字段一样的名字:
SetCounter(int size){
this.size = size;
}
变量名
普通变量命名应该采用首字母小写,其他字母首字母大写的方式。
final static变量的名字应该都大写,并且指出完整含义。如果一个常量名称由多个单词组成,则应该用下划线来分割这些单词如。
NUM_DAYS_IN_WEEK MAX_VALU
如果需要对变量名进行缩写时,一定要注意整个代码中缩写规则的一致性
context=ctx message=msg
通过在结尾处放置一个量词,就可创建更加统一的变量
First(一组变量中的第一个) Last(一组变量中的最后一个) Next(一组变量中的下一个变量) Prev(一组变量中的上一个) Cur(一组变量中的当前变量)
无论什么时候,均提倡应用常量取代数字、固定字符串。也就是说,程序中除0,1以外,尽量不应该出现其他数字。
索引变量匈牙利法用java代码:i、j、k等只作为小型循环的循环索引变量。
逻辑变量:避免用flag来命名状态变量,用is来命名逻辑变量。
if(isClosed){ dosomeworks; return; }
数组
总是使用以下方式定义数组:
int[] arr = new int[10];
禁止使用C语言的是形式:
禁止 int arr[] = new int[10];
集合
数组或者容器推荐命名方式为名词+s的方式,例如:
List persons = getPerson(); for(Person person : persons){ dosomeworks; }
泛型
应该尽量简明扼要(最好是一个字母),以利于与普通的class或interface区分
Container中的Element应该用E表示;Map里的key用K表示,value用V;Type用T表示;异常用X表示
如果需要接收多个Type类型的参数,应该用邻接T的大写字母——例如S——来依次表示,当然也可以用T1, T2这样的方式
public class HashSet extends AbstractSet {…} public class HashMapextends AbstractMap {…} public class ThreadLocal {…} public interface Functor { T val() throws X; }
推荐的命名
1.当要区别接口和实现类的时候,可以在类的后面加上“Impl”。
interface Container class ContainerImpl
2.Exception类最好能用“Exception”做为类命名的结尾
DataNotFoundException InvalidArgumentException
3.抽象类最好能用“Abstract”做为类命名的开头
AbstractBeanDefinition AbstractBeanFactory
4. Test类最好能用“Test”做为类命名的结尾
ContainerTest
5.简称与缩写(不推荐使用)
cp代表colorPoint buf代表buffer off代表offset len代表length
除非是在循环中,否则一般不推荐使用单个字母作为变量名,不过也有例外,即约定俗成的单个字母
b代表byte c代表char d代表double e代表Exception f代表float i, j, k代表整数 l代表long o代表Object s代表String v代表某些类型的特定值
代码风格
花括号
花括号统一采用以下格式:
if(bool experssion){ dosomework; }
除非花括号中为空,不然任何情况下不能省略花括号,并且花括号必须换行,例如:
if(i==0){ return; } while(true) {}
以下写法禁止出现:
禁止 if(i != 0) return; 禁止 if(i !=0) {return;}
括号
括号的前,后一个字符不需要空格,例如:
Person p = new Person(“Jack”, 17);
空格
逗号之后紧跟一个空格。
Person p = new Person(“Jack”, 16, “China”);
二元操作符前后跟空格。
int i = a + b – c * d;
3. 一元操作符不需要空格,for语句分号后有空格。
for(int i = 0; I 10; i++){ dosomework; }
4. 括号前后不需要空格
类
类的定义结构按照顺序为:
1) 常量
2) 成员变量
3) 构造函数
4) 成员函数
5) get和set方法
各个部分之间留出一个空行。
例如:
规范类模板:
class Person{ private final static int MAX_AGE = 100; private String firstname = “Jack”; public Person(){} public Person(String firstname){ this.firstname = firstname; } public void doExercise(){ dosomeworks; run(); } private void run(){ dosomeworks; } public getFirstname(){ return firstname; } public setFirstname(String firstname){ this.firstname = firstname; } }
2.构造函数
1) 参数为空的构造函数出现在最上方
2) 有调用关系的构造函数相邻
3) 参数尽量由少到多从上至下排序
3.使用成员变量
在类的方法内引用成员变量了命名冲突以外,不使用this。非特殊情况在类的方法内都不使用get和set方法存取成员变量。
4.方法
有调用关系的方法尽量放在相邻的位置,public和private方法可以交叉放置。
5.get和set方法,所有需要公开的成员变量都要符合良好的javabean规范,提供get和set方法,尽量使用IDE工具自动生成。
Javadoc注释
在每个程序的最开始部分,一般都用Javadoc注释对程序的总体描述以及版权信息,之后在主程序中可以为每个类、接口、方法、字段添加 Javadoc注释,每个注释的开头部分先用一句话概括该类、接口、方法、字段所完成的功能,这句话应单独占据一行以突出其概括作用,在这句话后面可以跟随更加详细的描述段落。在描述性段落之后还可以跟随一些以Javadoc注释标签开头的特殊段落,例如上面例子中的@auther和@version,这些段落将在生成文档中以特定方式显示
匈牙利法用java代码的介绍就聊到这里吧,感谢你花时间阅读本站内容,更多关于匈牙利算法结果唯一吗、匈牙利法用java代码的信息别忘了在本站进行查找喔。