- 浏览: 48329 次
- 性别:
- 来自: 长沙
使用原汁原味的 Java 语言
原文地址:http://www.ibm.com/developerworks/cn/java/j-noaccent.html
使用原汁原味的 Java 语言
非 Java 原生程序员的语言流畅性
简介: Elliotte Rusty Harold 探索了 Java™ 语言社区的各种原生习语、方言和口音。按照这篇文章的指导,C/C++ 和其他非 Java 原生语言的程序员可顺利融入到原生 Java 语言用户群体当中。
<!-- <p class="ibm-no-print"> <div id="dw-tag-this" class="ibm-no-print"></div> <div id="interestShow" class="ibm-no-print"></div> </p> -->发布日期: 2010 年 2 月 08 日
级别: 初级
其他语言版本: 英文 <!-- <br /><b>建议:</b> <span id="nCmts"><img alt="" src="//www.ibm.com/developerworks/i/circle-preloader.gif" height="12" width="50" /><img alt="" src="//www.ibm.com/i/gif" height="14" width="1" /></span> --><!-- Rating_Area_Begin --><!-- Ensure that div id is based on input id and ends with -widget -->
<!-- dW_Summary_Area_END --><!-- CONTENT_BODY -->
学习一种新的编程语言比学习新的口头语言要容易得多。然而,在这两种学习过程中,都要付出额外的努力去学习不带口音地说新语言。如果您熟悉 C 或 C++,那么学习 Java 语言并不困难,这就像是会说瑞典语的人去学丹麦语一样。语言虽有不同,但又彼此互通。但若不够谨慎,您的口音每次都会暴露出您并非原生语言使用者这个秘密。
C++ 程序员往往会对 Java 代码做出一些变形,而这样的举动将他们与原生 Java 语言用户清晰地区分开来。他们的代码可以无错运行,但对于原生语言用户来说,就是有一些地方不对劲。因而原生语言用户可能会轻视非原生用户。从 C 或 C++(或者 Basic、Fortran、Scheme 等)转到 Java 语言时,您需要根除一些习惯用语,并纠正某些发音,以便流畅地使用新语言。
在本文中,我探讨了一些往往被忽视的 Java 编程细节,因为从语义上来说,它们并不重要,甚至是无关紧要的。它们纯粹是风格和惯例问题。其中有些细节有着似是而非的理由,其他一些甚至连似是而非的理由也没有。但所有这些细节都是当今编写的 Java 代码中真实存在的现象。
让我们首先来看一段代码,其作用是将华氏温度转换为摄氏度,如清单 1 所示:
清单 1. 一段 C 代码?
float F, C; float min_tmp, max_tmp, x; min_tmp = 0; max_tmp = 300; x = 20; F = min_tmp; while (F <= max_tmp) { C = 5 * (F-32) / 9; printf("%f\t%f\n", F, C); F = F + x; } |
清单 1 中使用的是什么语言?很显然是 C 语言 —请等一下,让我们来看看完整的程序,如清单 2 所示:
清单 2. Java 程序
class Test { public static void main(String argv[]) { float F, C; float min_tmp, max_tmp, x; min_tmp = 0; max_tmp = 300; x = 20; F = min_tmp; while (F <= max_tmp) { C = 5 * (F-32) / 9; printf("%f\t%f\n", F, C); F = F + x; } } private static void printf(String format, Object... args) { System.out.printf(format, args); } } |
无论您是否相信,清单 1 和清单 2 都是使用 Java 语言编写的。它们只是以 C 语言方言(老实说,清单 1 也确实可以是 C 代码)编写的 Java 代码。这里的几个习语标志着:编写这段代码的人是以 C 语言思考的,只是单纯地将其翻译为 Java 语言:
- 变量是
float
而非double
。 - 所有变量都是在方法上方声明的。
- 初始化紧接声明之后。
- 使用了
while
循环而非for
循环。 - 使用了
printf
而非println
。 -
main()
方法的参数名为argv
。 - 数组括号紧接参数名之后,而非类型之后。
如果仅仅考虑所编写的这些代码是否能够编译或者是否会得到正确的结果,那么这些方言都不是错误的。如果分开来看,这几点都并不明显。但将它们结合在一起,就构成了一段非常古怪的代码,Java 程序员难以读懂,就像美国人难以听懂北英格兰人的方言一样。您使用的此类 C 语言方言越少,您的代码就会越清晰。请牢记这一点,下面我们将继续分析 C 语言程序员暴露自己身份的一些常见方式,并说明如何才能使他们的代码更符合 Java 程序员的眼光。
根据您原本使用的是 C、C++ 还是 C#,您可能有一些较为主观的类命名规范。举例来说,在 C# 中,类名都是以小写字母开头的,方法名和字段名以大写字母开头。Java 风格则恰好相反。我没有任何合理的原因能评判一种规范是否比另一种更好,但我了解,混用命名规范会使代码看起来存在严重错误。这种做法也会导致 bug。如果您知道,每一个全部由大写字母组成的名称都是常量,则会以不同的方式进行处理。在寻找命名规范与声明类型不匹配之处时,我发现了程序中的许多 bug。
args而非 argv
这一点是最微不足道的,但也正是这场风格之争所关注的细节。在 Java 的惯例中 main()
方法的参数名为 args
,而不是 argv
:
public static void main(String[] args) |
这至多只是对 argv
这个名称进行了一点细微的改进。作为参数的缩写,它或多或少地比 argv 更易懂一些。 当然,在合乎惯例的 Java 代码中,通常是禁止使用缩写的(参见 请勿缩写)。我们使用 args
作为 main()
方法的参数名的惟一原因与 C 程序员使用 argv
的原因是相同的 — 第一本关于 C 语言的图书的作者 Kernighan 和 Ritchie 使用了这个名称。而 Gosling 和 Arnold 使用了 args
。除此之外,再无其他原因。同样,所有原生 Java 程序员都倾向于使用 args
,如果您希望保持原汁原味,那么也应该这样做。
Java 编程中的基本命名规则非常简单,也值得牢记:
- 类和接口名以大写字母开头,如
Frame
。 - 方法、字段和本地变量名以小写字母开头,如
read()
。 - 类、方法和字段名均使用驼峰式大小写风格,如
InputStream
和readFully()
。 - 常量 — 终态静态字段和临时终态本地变量 — 全部适用大写字母,并以下划线分隔各词,如
MAX_CONNECTIONS
。
像 sprintf
和 nmtkns
这样的名称是超级计算机只有 32 KB 内存时代的遗物。编译器将标识符限制为 8 个字符或更少,以此来节约内存。近 30 年来,这已经不再是需要担心的问题。如今,再没有任何理由不使用完整拼写的变量和方法名称。难以解读、无元音字母的变量名清楚地表明这个程序出自一名皈依 Java 的 C 程序员之手,请参见清单 3:
清单 3. Abbrvtd nms r hrd 2 rd
for (int i = 0; i < nr; i++) { for (int j = 0; j < nc; j++) { t[i][j] = s[i][j]; } } |
不缩写、采用驼峰式大小写风格的名称更易读易懂,如清单 4 所示:
清单 4. 未缩写的名称更易读
for (int row = 0; i < numRows; row++) { for (int column = 0; column < numColumns; column++) { target[row][column] = source[row][column]; } } |
一段代码被阅读的次数要远远超过编写的次数,Java 语言为易读性而进行了优化。C 程序员近乎沉迷于难解的代码,而 Java 程序员则不然。Java 语言将易读性置于简洁性之前。
有一些极为常用的缩写形式,您仍然可以放心使用:
-
max
表示最大(maximum) -
min
表示最小(minimum) -
in
表示InputStream
-
out
表示OutputStream
-
e
或ex
表示catch
子句中的异常(不用于其他位置) -
num
表示数字(number),仅用作前缀,如numTokens
或numHits
-
tmp
表示主要在本地使用的临时变量 — 针对实例,在交换两个值的时候
除此之外(或许还有少数一些例外),您应完整拼写出名称中使用的所有词。
早期版本的 C 需要在方法开始处声明所有变量。这样是为了在编译器中实现一定的优化,允许它在 RAM 极为有限的环境中运行。因而,C 语言中的方法大多以几行变量声明开头:
int i, j, k; double x, y, z; float cf[], gh[], jk[]; |
然而,这种风格也有一些缺陷。它将变量的声明与其使用分离开来,使代码的易读性降低。此外,它会为多种不同的用途重用一个本地变量,有可能并非刻意而为。但若变量持有代码的某个片段无法接受的残值,这可能会带来无法预料的 bug。这一点与 C 语言中简短而难解的变量名结合在一起,将会后患无穷。
在 Java 语言(和较新版本的 C 语言)中,变量可在初次使用或接近初次使用时声明。在编写 Java 代码时,请采取这种做法。这将使您的代码更加安全、更不易出现 bug,也更易于阅读。
此外,Java 代码通常在声明变量时初始化各变量,而 C 程序员有时会写出下面这样的代码:
int i; i = 7; |
尽管这在语法上是正确的,但 Java 程序员永远不会写出这样的代码。他们会这样写这段代码:
int i = 7; |
这有助于避免因意外使用了未经初始化的变量而导致的 bug。惟一的常见例外是一个变量的作用域需要同时包含 try
块和 catch
或 finally
块。这往往是由于代码涉及需要在 finally
块中关闭的输入流和输出流而导致的,如清单 5 所示:
清单 5. 异常处理可能会使变量的作用域难以合理设定
InputStream in; try { in = new FileInputStream("data.txt"); // read from InputStream } finally { if (in != null) { in.close(); } } |
但这几乎是惟一的异常。
这种风格的最后一种连锁反应就是 Java 程序员通常每行仅声明一个变量。例如,他们初始化变量的方法如下:
int i = 3; int j = 8; int k = 9; |
通常不会写出下面这样的代码:
int i=3, j=8, k=9; |
这条语句在语法上是正确的,但除非在一种特殊的例外情况下,专业 Java 程序员是不会这样做的,后文将介绍这种特殊情况。
老式的 C 程序员甚至可能编写一个四行的代码:
int i, j, k; i = 3; j = 8; k = 9; |
Java 风格将声明与初始化结合在一起,因而实际上要更简练一些,只需要三行代码。
常见的一种特殊情况就是在循环外部声明变量。例如,考虑清单 6 中简单的 for
循环,其作用是计算斐波那契数列的前 20 项:
清单 6. C 程序员喜欢在循环外部声明变量
int high = 1; int low = 1; int tmp; int i; for (i = 1; i < 20; i++) { System.out.println(high); tmp = high; high = high+ low; low = tmp; } |
所有这四个变量都是在循环外声明的,尽管它们仅在循环内部使用,但作用域不止于此。这容易导致 bug,变量可能会在其目标作用域之外被重用。对于使用常用名的变量来说更是这样,例如 i
和 tmp
。某次使用的值可能会残留下来,并以无法预计的方式干扰后续的代码。
第一项改进(C 语言的现代版本也支持这项改进)是将 i
循环变量的声明移到循环之内,如清单 7 所示:
清单 7. 将循环变量移入循环
int high = 1; int low = 1; int tmp; for (int i = 1; i < 20; i++) { System.out.println(high); tmp = high; high = high+ low; low = tmp; } |
到这里还没有结束,经验丰富的 Java 程序员还会将 tmp
变量移入循环,如清单 8 所示:
清单 8. 在循环内声明临时变量
int high = 1; int low = 1; for (int i = 1; i < 20; i++) { System.out.println(high); int tmp = high; high = high+ low; low = tmp; } |
某些极度追求速度而又不够老练的开发人员有时会提出反对意见,认为这种做法导致循环内执行过多操作,而不只是必要的操作,从而降低代码运行速度。实际上,在运行时,声明根本不会执行。将声明移动到循环内绝不会给 Java 平台造成负面的性能影响。
许多程序员,包括许多经验丰富的 Java 程序员都可能在这里止步。然而,还有一种不太常见的技巧,将所有变量都移入循环。您可以在 for
循环的初始化阶段声明多个变量,只需使用逗号分隔即可,如清单 9 所示:
清单 9. 在循环内声明所有变量
for (int i = 1, high = 1, low = 1; i < 20; i++) { System.out.println(high); int tmp = high; high = high + low; low = tmp; } |
这已经不仅仅是惯用的流畅代码,而是真正的专业代码。与 C 代码相比,Java 代码中的 for
循环更多、while
循环更少,原因就在于这种严格限制本地变量作用域的能力。
上述讨论得出这样一个结论,Java 程序员几乎不会为不同的值和对象重用本地变量。例如,清单 10 建立了一些按钮及其关联的动作侦听器:
清单 10. 回收本地变量
Button b = new Button("Play"); b.addActionListener(new PlayAction()); b = new Button("Pause"); b.addActionListener(new PauseAction()); b = new Button("Rewind"); b.addActionListener(new RewindAction()); b = new Button("FastForward"); b.addActionListener(new FastForwardAction()); b = new Button("Stop"); b.addActionListener(new StopAction()); |
经验丰富的 Java 程序员会用 5 个不同的本地变量重写这段代码,如清单 11 所示:
清单 11. 未回收的变量
Button play = new Button("Play"); play.addActionListener(new PlayAction()); Button pause = new Button("Pause"); pause.addActionListener(new PauseAction()); Button rewind = new Button("Rewind"); rewind.addActionListener(new RewindAction()); Button fastForward = new Button("FastForward"); fastForward.addActionListener(new FastForwardAction()); Button stop = new Button("Stop"); stop.addActionListener(new StopAction()); |
为多个逻辑上不同的值或对象重用一个本地变量容易导致 bug。实际上,本地变量(并非始终是它们指向的对象)并不影响内存和时间问题。所以不必为此担忧,可以根据您的需要使用多个不同的本地变量。
信任垃圾收集器的内存管理能力
出身 C++ 世界的程序员往往过度担心内存消耗和内存泄漏问题。此类程序员有两种表现。一种是在使用过变量后将变量设置为 null。另一种是调用 finalize()
或将其用作一种伪析构函数。这是完全没有必要的。尽管有些时候确实需要在 Java 代码中手动释放内存,但这种情况十分罕见。大多数时候,只需依靠垃圾收集器即可合理快速地完成内存管理。与大多数优化一样,最佳实践准则就是:除非能够证明是有必要的,否则不要去干涉。
Java 语言有八种原语数据类型,但仅使用了其中的六种。在 Java 代码中,float
比 C 代码中少得多。float
变量或文字在 Java 代码中极为罕见,更常用的是 double
。使用 float
的惟一时机就是操纵精度有限的大型多维浮点数字数组,此时存储空间较为重要。否则使用 double
即可。
比 float
更不常见的是 short
。我在 Java 代码中几乎没有见过 short
变量。只有惟一的一次(我要警告您,这是极其罕见的情况),读入的外部定义数据格式碰巧包含 16 位有符号整型类型。在这种情况下,大多数程序员都会将其作为 int
读入。
您是否见过清单 22 中这种 equals()
方法?
清单 12. C++ 程序员编写的
equals()
方法
public class Foo { private double x; public double getX() { return this.x; } public boolean equals(Object o) { if (o instanceof Foo) { Foo f = (Foo) o; return this.x == f.getX(); } return false; } } |
这个方法在技术上是正确的,但我确信,这个类是由一名保守的 C++ 程序员编写的。他在一个方法中使用了私有字段 x
和公共 getter 方法 getX()
,实际上是在一行代码之中,这泄漏了他的身份。在 C++ 中,这种做法是必要的,因为私有属性的范围是对象而不是类。也就是说,在 C++ 中,同一个类的对象无法看到彼此的私有成员变量。他们必须使用 accessor 方法。在 Java 语言中,私有属性的范围是类而非对象。类型同为 Foo
的两个对象可直接访问对方的私有字段。
某些微妙 — 往往又不相关 — 的考虑思路认为,您应该在 Java 代码中首选直接字段访问而非 getter 访问,或者反之。字段访问相对速度较快,但在少数时候,getter 访问可能会提供与直接字段访问略有不同的值,特别是在涉及子类的时候。在 Java 语言中,没有任何理由在同一行代码中为同一个类的同一个字段同时使用直接字段访问和 getter 访问。
下面是一些与 C 语言对应部分不同的 Java 方言,在某些情况下,这样的差异是为了利用某些 Java 语言特性。
Java 语言声明数组的方式与 C 语言中大致相同:
int k[]; double temperature[]; String names[]; |
但 Java 语言也提供了一种替代性的语法,将数组复括号紧接于类型之后,而不是变量名之后:
int[] k; double[] temperatures; String[] names; |
大多数 Java 程序员都采用了第二种风格。上面的代码表示 k
的类型是 int
数组,temperatures
的类型是 double
数组,names
的类型是 String
数组。
同样,与其他本地变量一样,Java 程序员习惯在声明时初始化这些变量:
int[] k = new int[10]; double[] temperatures = new double[75]; String[] names = new String[32];
谨慎的 C 程序员已经学会了将文字置于比较运算符的左侧。例如:
if (7 == x) doSomething(); |
目标在于避免意外地使用单等号赋值运算符而非双等号比较运算符:
if (7 = x) doSomething(); |
若将文字置于左侧,这样的错误就会成为编译时错误。这项技巧是 C 语言中一项著名的编程实践。它能帮助避免出现真正的 bug,因为若将文字置于右端,将始终返回 true
。
然而,不同于 C 语言,Java 语言具有独立的 int
和 boolean
类型,赋值运算符返回 int
,而比较运算符返回 boolean
。因而,if (x = 7)
已经成为编译时错误,就没有必要为比较语句使用不自然的形式 if (7 == x)
,流畅的 Java 程序员不会这样做。
多年以来,Java 语言一直没有 printf()
函数。最终,Java 5 中增加了这个函数,有些时候能够发挥作用。具体来说,在您希望将数字格式化为特定宽度或小数点后带有特定位数的形式时,在这种不常见的情况下,格式字符串是一种便捷的字段特定语言。而 C 程序员往往在 Java 代码中过多地使用 printf()
。不应使用它取代简单的字符串连接。例如:
System.out.println("There were " + numErrors + " errors reported."); |
优于:
System.out.printf("There were %d errors reported.\n", numErrors); |
变体使用了字符串连接,更易于阅读,在简单的情况下更是如此,此外,由于不存在格式字符串中的占位符和数字或变量参数的类型匹配不当的情况,出现 bug 的机会也更少。
在某些位置,i++
和 ++i
之间的差别十分显著。Java 程序员为这些位置定义了一个具体的名称,那就是“bug”。
不应该编写依赖于前增量和后增量之间差异的代码(对于 C 语言来说也是如此)。原因在于难以理解、易于出错。如果您发现,在您编写的代码中两者的差别有重大影响,那么就应该重新将代码组织为独立的语句,使之不再能够影响大局。
如果前增量和后增量之间的差别不显著 — 例如,for
循环的增量步数 — 80% 的 Java 程序员更倾向于使用后增量,只有 20% 的 Java 程序员会选择前增量。i++
比 ++i
更为常用。我无法评判孰是孰非,但事实就是这样。如果您编写的代码中包含 ++i
,那么任何阅读您的代码的人都要浪费时间去思考您为什么要这样写。因而,除非有特殊的原因必须使用前增量(应该不存在必须使用前增量的情况),否则请使用后增量。
错误处理是 Java 编程中最令人困惑的问题之一,也是真正地将语言风格大师与平凡开发者区分开来的一道门槛。实际上,仅仅错误处理就可以自成一篇文章。简而言之,合理使用异常,切勿返回错误代码。
非原生语言使用者的第一类错误是返回一个表示错误的值,而不是抛出异常。如果回溯到 Java 1.0 的年代,在 Sun 的所有程序员都充分理解了这种新语言之前,在某些 Java 语言自己的 API 中也会看到这样的情况。例如,考虑 java.io.File
中的 delete()
方法:
public boolean delete() |
若文件或目录被成功删除,此方法将返回 true
,否则返回 false
。但最合理的做法 应该是,在成功完成时不返回任何内容,若存在出于某些原因未能删除的文件,则抛出异常:
public void delete() throws IOException |
在方法返回错误值时,每一个方法调用都要包含错误处理代码。在大多数正常情况下,这使得跟踪和理解方法的正常执行流变得困难。同时,如果由异常指出错误条件,错误处理即可单独作为文件末尾处的一个代码块。如果存在更适合处理问题的位置,甚至可将其移动到其他方法和其他类中。
这就带来了错误处理中的第二种反模式。具有 C++ 背景的程序员有时会竭力在异常抛出后尽快处理异常。如果达到极限,可能会得到如清单 13 所示的代码:
清单 13. 过早的异常处理
public void readNumberFromFile(String name) { FileInputStream in; try { in = new FileInputStream(name); } catch (FileNotFoundException e) { System.err.println(e.getMessage()); return; } InputStreamReader reader; try { reader = new InputStreamReader(in, "UTF-8"); } catch (UnsupportedEncodingException e) { System.err.println("This can't happen!"); return; } BufferedReader buffer = new BufferedReader(reader); String line; try { line = buffer.readLine(); } catch (IOException e) { System.err.println(e.getMessage()); return; } double x; try { x = Double.parseDouble(line); } catch (NumberFormatException e) { System.err.println(e.getMessage()); return; } System.out.println("Read: " + x); } |
这段代码非常难以阅读,甚至比异常处理取代的 if (errorCondition)
测试更为难解。流畅的 Java 代码将错误处理与故障点分离开来,不会将错误处理代码与正常执行流混合在一起。清单 14 中的版本更易于阅读和理解:
清单 14. 保持代码的主执行路线完好
public void readNumberFromFile(String name) { try { FileInputStream in = new FileInputStream(name); InputStreamReader reader = new InputStreamReader(in, "UTF-8"); BufferedReader buffer = new BufferedReader(reader); String line = buffer.readLine(); double x = Double.parseDouble(line); System.out.println("Read: " + x); } catch (NumberFormatException e) { System.err.println("Data format error"); } catch (IOException e) { System.err.println("Error reading from file: " + name); } } |
某些时候,您可能需要使用嵌套的 try
-catch
块来分离造成相同异常的不同故障模式,但这种情况并不常见。主要的实践经验是:如果一个方法中存在多个 try
块,那么就表明方法过于庞大,应拆分为多个较小的方法。
最后,具有各种语言背景、刚刚接触 Java 编程的程序员往往会错误地假设他们必须在抛出检查异常(checked exception)的方法中捕捉到这些异常。而抛出异常的方法通常并不是应该负责捕捉异常的方法。例如,考虑如清单 15 所示的方法:
清单 15. 过早的异常处理
public static void copy(InputStream in, OutputStream out) { try { while (true) { int datum = in.read(); if (datum == -1) break; out.write(datum); } out.flush(); } catch (IOException ex) { System.err.println(ex.getMessage()); } } |
此方法没有足够的信息来处理很有可能发生的 IOException
。它并不了解谁调用了它,也不了解故障的后果。对于此方法来说,惟一合理的举措就是允许 IOException
上行至调用方。编写此方法的正确方式如清单 16 所示:
清单 16. 并非所有异常都需要在第一时间捕捉
public static void copy(InputStream in, OutputStream out) throws IOException { while (true) { int datum = in.read(); if (datum == -1) break; out.write(datum); } out.flush(); } |
简而言之,这更为简单、更容易理解,将错误信息传递给代码中最适合处理这些信息的部分。
这些问题都不是关键问题。某些是惯例:在初次使用时声明;在不知道如何处理错误时抛出异常。其他则是纯粹的风格惯例(args
而非 argv
;i++
而非 ++i
)。我并不认为这些规则能使您的代码运行速度更快,但其中一些确实能帮助您避免 bug。如果您要成为一名流畅的 Java 语言使用者,所有这些规则都是重要的。
无论如何,以纯正的口音讲话(或编写代码)都能使其他人更加尊重您、更加关注您所表达的内容,甚至会为您表达的内容付给您更多的钱。此外,以纯正的口音使用 Java 语言要比说无口音的法语、汉语或英语要简单得多。一旦您学会了一门语言,就值得付出努力来使您的表达变得更加原汁原味。
<!-- CMA ID: 466853 --><!-- Site ID: 10 --><!-- XSLT stylesheet used to transform this file: dw-article-6.0-beta.xsl -->学习
-
Code Conventions for the Java Programming Language:尽管有些过时,但这份参考资料仍然是现代 Java 风格的基础。
-
The Java Language Specification (James Gosling et al.,Addison Wesley,2005 年):现已发行第三版,这或许是第一份认为除了语法和语义之外还有必要讨论风格的语言规范。其主要原因是与过去的 C++ 和 Basic 等语言相比,Java 语言在各个组织和项目中有着更加标准的风格。
-
Effective Java 第二版(Joshua Bloch,Prentice Hall,2008 年):Bloch 撰写的这本书籍涵盖了 Java 风格的偏向语义的方面。
- “Java programming for C/C++ developers”(James Stricker,developerWorks,2002 年 5 月):这份教程面向希望学习如何使用 Java 语言编程的 C 或 C++ 程序员。
-
Java 编程新手入门:阅读这份 Java 技术基础概述,了解技术如何适应现代软件开发环境。
- 浏览 技术书店,查看关于上述和其他技术主题的图书。
-
developerWorks Java 技术专区:查看数百篇关于 Java 编程方方面面的文章。
讨论
相关推荐
《转帖经典---JAVA设计模式》这本书或资料可能涵盖了这些模式的详细解释、示例代码以及如何在实际项目中应用这些模式。通过学习和理解这些设计模式,开发者能够更好地设计和重构软件,提升代码质量。
标题中的“论坛转帖工具.rar”表明这是一个用于在论坛之间转移帖子的软件工具,通常用于帮助用户方便地将一个论坛的帖子内容复制到另一个论坛,可能是为了分享信息、讨论或保存重要的帖子。这类工具可能包括自动抓取...
【贴吧转帖工具】是一种专为百度贴吧用户设计的便捷工具,主要用于提高用户...总的来说,【贴吧转帖工具】通过自动化操作,为百度贴吧用户提供了高效、便捷的互动方式,但用户在使用时也要注意风险防范和遵守社区规则。
UBB论坛转帖圣手.exeUBB论坛转帖圣手.exe
本篇文章将详细探讨“编辑人员转帖去水印工具”,并介绍如何使用名为Teorex Inpaint的1.0.0.2版本的软件来实现这一目标。 首先,我们要理解什么是水印。水印通常是指在图像或视频中添加的半透明标记,它可以是文字...
### 使用 JProfiler 监控 JBoss 运行情况 #### JProfiler简介与功能 JProfiler是一款功能强大的Java性能分析工具,它可以对Java应用程序、Applets、Java Web Start应用以及应用服务器进行性能监控与分析。通过深入...
- **Html2UBB**:这可能是实际的软件执行文件或库文件,用户需要运行或解压后才能使用转帖工具。 5. **使用步骤**: - 首先,阅读Readme.txt和站内插件安装方法,了解软件的使用条件和步骤。 - 如果需要,按照...
3. 原创保护:在转帖时,可以进行必要的处理,如添加引用、链接原文,尊重原作者,避免侵犯版权。 三、使用注意事项 1. 法律合规:使用这类工具时,必须确保所发布的帖子内容合法,不侵犯他人权益,遵循网络道德...
4. **编程语言的选择**:虽然大多数编程竞赛允许使用多种语言,但每种语言都有其特点和适用场景。例如,C++因其执行速度快而广受青睐;Python则以其简洁的语法和丰富的库支持,在数据处理和算法原型设计方面表现出色...
《HttpClient 4.0 使用详解:访问开心网组件实例》 HttpClient 是 Apache 开源基金会提供的一个 HTTP 客户端库,被广泛应用于 Java 开发中,用于执行 HTTP 请求。HttpClient 4.0 版本引入了许多改进和新特性,使得...
7. **Flex 和 BlazeDS**: BlazeDS是Adobe提供的一个服务器端技术,用于在Flex客户端和Java后端之间进行数据通信。它支持AMF(Action Message Format)协议,提供低延迟、高性能的数据交换。 8. **移动开发**: Flex ...
J2ME全方位开发讲解基础汇总[转帖] 一、J2ME中需要的Java基础知识 现在有大部分人,都是从零开始学J2ME的,学习J2ME的时候,总是从Java基础开始学习,而且现在讲Java基础的书籍中都是以J2SE来讲基础,这就给学习造成...
【标题】"zj.rar" 是一个以"Java_"为后缀名的压缩文件,很可能包含与Java编程语言相关的技术资料或个人经验分享。在IT领域,Java是一种广泛应用的、面向对象的编程语言,尤其在企业级应用开发、服务器端编程、移动...
"转帖工具插件 for PHPwind 7.5 正式版" 是专门为 PHPwind 7.5 版本设计的一个功能插件,旨在提供便捷的帖子转移功能,帮助管理员或者用户将内容从一个地方轻松移动到另一个地方,而无需直接编辑论坛的原始文件。...
这通常是在文章内容下方或者侧边栏等显眼位置,以方便用户快速找到并使用转帖功能。 3. **重新生成页面**:完成上述步骤后,为了确保新添加的功能生效,需要对内容页进行重新生成。这样,新插入的转帖按钮将出现在...
转帖图片提取工具可以对论坛...转帖图片提取工具使用方法: 将IP138上处理过的东西复制到上方的编辑框内,点击只要图片,下面的编辑框就出现结果,点击 复制结果 就可以把内容复制到剪切板中 转帖图片提取工具截图
1.修改自Convert X转帖工具 2.新增批量替换关键词(原来是单个词语替换,可以利用这个功能删除一些网站的防转帖代码) 3.批量随机新增文字(新增内容可自定义,从而实现伪原创) 4.cookie记录替换和新增关键词(避免每次...
"一键转帖功能插件 for 帝国CMS v1.0.rar" 是一个专为帝国CMS设计的扩展工具,其主要目标是简化用户在网站上分享内容的过程,提高用户体验。这个插件允许用户轻松地将网站上的文章或信息复制并转发到其他平台,如...