脱离 Rails 看 Ruby
来源:互联网 发布:淘宝一键上传权重 编辑:程序博客网 时间:2024/06/09 23:47
脱离 Rails 看 Ruby
在搭上 Rails 潮流之前了解 Ruby
文档选项将此页作为电子邮件发送
级别: 初级
Andrew Glover, CTO, Vanward Technologies
2006 年 1 月 09 日
Ruby on Rails 只是使 Ruby 非常强大的方面之一,就像 EJB 只是 Java™ 企业平台的一部分一样。Andrew Glover 揭示了 Java 开发人员可以使用 Ruby 做什么。
在开始这篇文章之前,我需要澄清一些事情。首先,这不是一篇关于 Ruby on Rails 的文章。如果您希望了解 Rails,每周(甚至每小时)都有相关的文章和 blog 出现,它们都对这个令人兴奋的框架的众多特性大加推崇;请参见 参考资料 中的列表。其次,本文并不是想预言,Java 面对像 Ruby on Rails 这样更好的 语言、工具和框架会衰败下去。所以本文并不涉及近来通常与 Ruby 最相关的主题。
别误会 —— 我认为 Rails 是令人难以置信的!它的功能极其强大,已经明显地改变了 Web 开发的面貌和步调。我只想指出一点:Ruby 要比 Rails 功能丰富,尤其是从 Java 开发人员的视角来看。
Rails 的专长是 Web 站点开发;但是,我自己没有构建过全新的 Web 站点。我所工作的大多数 Web 站点已经 使用 Struts、Tapestry 或其他技术构建起来了。在我利用 Ruby 时,基本上是将它作为一种与 Java 平台衔接的开发实践。所以在本文中,我将谈谈如果您主要是 Java 开发人员,那么应该如何利用 Ruby 进行开发。
掌握多种语言的好处如果您掌握了多种语言,在与多个国家的朋友一起旅行时能够帮助他们消除语言障碍,从而获得尊重,会外语也会提升您在本国语言环境中的地位。掌握多种编程语言 也有同样的好处。与只会一种语言的人相比,掌握多种编程语言的开发人员在 IT 世界中会更自由(他们能够将技能应用于任何环境),而且他们在自己的编程母语 领域中也会更受尊重,因为他们了解源自这种母语的其他东西。您不想掌握多种语言吗?
感觉是如此不同
Ruby 的语法与 Java 语言的语法不同。首先,Ruby 没有方括号或分号,而且它使类型成为完全可选的。有人可能会说 Ruby 的语法很简洁,这正是它的意图:这种语言使开发人员可以迅速编写简洁的代码。
如果用 Java 语言和 Ruby 分别定义同一个类,通过比较,就能够看到这种简洁性。我先给出用 Java 语言编写的两个类 —— Word
和 Definition
(就像是词典)。在图 1 所示的简单类图中,可以看出这两个类有几个关系(如果这种复杂性看起来不自然,请忍耐一下;这是有意义的!):
- 一个
Word
可以拥有一个同义词(Word
的实例)集合。 - 一个
Word
还拥有一个Definition
集合。 - 一个
Definition
拥有一个对Word
的聚合关联。
图 1. 具有单词和定义的简单词典
用 Java 语言编写的类定义
在清单 1 中,用 Java 语言定义了 Word
类。注意,必须对 Definition
和同义词集合进行关系检验。这是因为在这个例子中,最初创建 Definition
时可以不带 Word
关系,最初定义 Word
时也可以不带 Definition
。
清单 1. 用 Java 语言编写的 Word 类
package com.vanward.dictionary;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class Word {
private String spelling;
private String partOfSpeech;
private Collection definitions;
private Collection synonyms;
public Word(String spelling, String partOfSpeech) {
this.spelling = spelling;
this.partOfSpeech = partOfSpeech;
this.definitions = new ArrayList();
this.synonyms = new ArrayList();
}
public Word(String spelling, String partOfSpeech,
Collection definitions) {
this(spelling, partOfSpeech);
if(definitions != null){
for(Iterator iter = definitions.iterator(); iter.hasNext();){
this.validateRelationship((Definition)iter.next());
}
this.definitions = definitions;
}
}
public Word(String spelling, String partOfSpeech,
Collection definitions, Collection synonyms) {
this(spelling, partOfSpeech, definitions);
if(synonyms != null){
this.synonyms = synonyms;
}
}
private void validateRelationship(Definition def){
if(def.getWord() == null || def.getWord() != this){
def.setWord(this);
}
}
public Collection getDefinitions() {
return definitions;
}
public void addDefinition(Definition definition) {
this.validateRelationship(definition);
this.definitions.add(definition);
}
public String getPartOfSpeech() {
return partOfSpeech;
}
public void setPartOfSpeech(String partOfSpeech) {
this.partOfSpeech = partOfSpeech;
}
public String getSpelling() {
return spelling;
}
public void setSpelling(String spelling) {
this.spelling = spelling;
}
public Collection getSynonyms() {
return synonyms;
}
public void addSynonym(Word synonym) {
this.synonyms.add(synonym);
}
}
清单 1 中的 Word
类相当简单;它是一个 JavaBean,具有一个构造函数链,使用户能够用各种属性集创建 Word
。还要注意,它的 synonyms
和 definitions
属性是 只读的(即没有针对它们的设置方法)。只能添加 一个 Definition
实例,或者为一个同义词添加 另一个 Word
。
在清单 2 中是相关的 Definition
类,这个类与 Word
类的相似之处是,它的 exampleSentences
属性没有对应的 set()
方法:
清单 2. 用 Java 语言编写的 Definition 类
package com.vanward.dictionary;
import java.util.Collection;
public class Definition {
private Word word;
private String definition;
private Collection exampleSentences;
public Definition(String definition){
this.definition = definition;
this.exampleSentences = new ArrayList();
}
public Definition(String definition, Word word) {
this(definition);
this.word = word;
}
public Definition(String definition, Word word,
Collection exampleSentences) {
this(definition, word);
if(exampleSentences != null){
this.exampleSentences = exampleSentences;
}
}
public String getDefinition() {
return definition;
}
public void setDefinition(String definition) {
this.definition = definition;
}
public Collection getExampleSentences() {
return exampleSentences;
}
public void addExampleSentence(String exampleSentence) {
this.exampleSentences.add(exampleSentence);
}
public Word getWord() {
return word;
}
public void setWord(Word word) {
this.word = word;
}
}
用 Ruby 编写的类定义
在清单 3 中,可以看到用 Ruby 定义的这两个类。清单 3 确实 看起来很不一样,不是吗?
清单 3. 用 Ruby 编写的相同类
module Dictionary
class Word
attr_reader :spelling, :part_of_speech, :definitions, :synonyms
attr_writer :spelling, :part_of_speech
def initialize(spelling, part_of_speech, definitions = [], synonyms = [])
@spelling = spelling
@part_of_speech = part_of_speech
definitions.each{ |idef| idef.word = self}
@definitions = definitions
@synonyms = synonyms
end
def add_definition(definition)
definition.word = self if definition.word != self
@definitions << definition
end
def add_synonym(synonym)
@synonyms << synonym
end
end
class Definition
attr_reader :definition, :word, :example_sentences
attr_writer :definition, :word
def initialize(definition, word = nil, example_sentences = [])
@definition = definition
@word = word
@example_sentences = example_sentences
end
end
end
从清单 3 中可以看出,Ruby 的语法非常简洁。但是,不要让这种简洁性欺骗了您,这段代码中有许多内容!首先,在一个模块 中定义了两个类,模块本质上相当于 Java 语言中的 包
。另外,能够在一个文件中定义这些类,而 Java 语言要求用两个文件。您还会注意到,Ruby 的构造函数名为 initialize
,而 Java 语言中的构造函数使用类名进行命名。
回页首
创建对象实例
在 Ruby 中创建新的对象实例的方式是不一样的。Ruby 并不使用 Java 代码中的 new ObjectInstance()
语法,Ruby 实际上支持在对象上调用 new
方法,即在内部调用 initialize
方法。在清单 4 中,可以看到如何在 Ruby 中创建一个 Word
实例和一些对应的 Definition
:
清单 4. 在 Ruby 中创建新的对象实例
require "dictionary"
happy_wrd = Dictionary::Word.new("ebullient", "adjective")
defin_one = Dictionary::Definition.new("Overflowing with enthusiasm")
defin_two = Dictionary::Definition.new("Boiling up or over")
happy_wrd.add_definition(defin_one)
happy_wrd.add_definition(defin_two)
在清单 4 中,我用 Ruby 的 require
方法(这个方法可以在 Kernel
类中找到)“导入了” dictionary
模块。然后通过 Object.new
语法创建一个新的 Word
实例(ebullient)。尽管导入了 dictionary
模块,但是仍然需要对对象实例进行限定,因此采用 Dictionary::Word
。如果在 require
子句后面编写了 include Dictionary
,那么也可以去掉 Dictionary::
前缀。
默认参数值
您是否注意到了,在清单 4 中创建 happy_wrd
实例时没有 指定 Definition
或同义词集合。我只为 spelling
和 part_of_speech
传递了值。可以进行这样的省略是因为 Ruby 支持参数的默认值。在清单 3 定义的 Word
的 initialize
方法中,指定了 definitions = []
和 synonyms = []
作为参数,这基本上就是告诉 Ruby 如果调用者没有提供这些集合,就将它们默认设置为空集合。
还要注意,在 清单 3 中 Definition
的 initialize
方法如何通过将 example_sentences
设置为一个空集合,从而支持默认参数(word
的默认值 nil
是 Java 语言中 null
的 Ruby 版本)。回到 清单 1,在这里必须创建三个构造函数 才能获得 Java 语言提供的相同灵活性!
现在,我用灵活的 initialize()
方法创建另一个 Word
实例,见清单 5:
清单 5. 灵活性的表现!
require "dictionary"
defin = Dictionary::Definition.new("Skill in or performance of tricks")
defin_two = Dictionary::Definition.new("sleight of hand")
defs = [defin, defin_two]
tricky_wrd = Dictionary::Word.new("prestidigitation", "noun", defs)
在定义两个 Definition
之后,将它们添加进一个集合中(集合看起来就像 Java 语言中的数组)。然后将这个集合传递给 Word
的 initialize()
方法。
回页首
集合的处理
Ruby 的集合处理同样简单得令人吃惊;看看 Word
类中的 add_definition
和 add_synonym
方法就知道了。<<
语法被重载,表示 add
。如果再看看 清单 2 中的 Definition
类,就会发现 Java 语言中的对应代码复杂多了:this.exampleSentences.add(exampleSentence)
。
对于集合,您不认为 Ruby 的
[]
语法非常干净利落吗?如果您是 Groovy 用户,就应该很熟悉这种语法。 Ruby 的集合处理非常简洁。在清单 6 中,可以看到组合集合(使用 +
操作符)和访问成员(通过 [
position ]
)是多么容易,没有 什么值得操心的东西!
清单 6. 简练的集合
require "dictionary"
idef_1 = Dictionary::Definition.new("Sad and lonely because deserted")
idef_2 = Dictionary::Definition.new("Bereft; forsaken")
defs = [idef_1, idef_2]
idef_3 = Dictionary::Definition.new("Wretched in appearance or condition")
idef_4 = Dictionary::Definition.new("Almost hopeless; desperate")
defs_2 = [idef_3, idef_4]
n_def = defs + defs_2 #n_def is now [idef_1, idef_2, idef_3, idef_4]
n_def[1] # produces idef_2
n_def[9] # produces nil
n_def[1..2] # produces [idef_2, idef_3]
清单 6 中的代码只触及到了 Ruby 集合处理的皮毛!
回页首
RubyBean?
在 清单 3 中的两个类中您可能会注意到,Ruby 支持一种定义属性的简写方式:attr_reader
和 attr_writer
。因为使用了这种方式,所以可以在 Word
类中设置 和获取 对应的属性,如清单 7 所示:
清单 7. attr_reader 和 attr_writer 的作用
require "dictionary"
wrd = Dictionary::Word.new("turpitude", "Noun")
wrd.part_of_speech # "Noun"
wrd.spelling # "turpitude"
wrd.spelling = "bibulous"
wrd.spelling # "bibulous"
syns = [Dictionary::Word.new("absorptive", "Adjective"),
Dictionary::Word.new("imbibing", "Noun") ]
# Danger!
wrd.synonyms = syns = syns #Exception: undefined method `synonyms='...
attr_reader
和 attr_writer
都不是关键词,而是 Ruby 中的实际方法(在 Module
类中),它们以符号作为参数。符号 是前面有冒号(:
)的任何变量,更妙的是符号本身也是对象!
注意,因为在 清单 3 中使 synonyms
成为只读的,所以 Ruby 拒绝执行清单 7 中的最后一行代码。另外,还可以使用 attr_accessor
方法编写属性声明代码,指出属性是既可读又 可写的。
回页首
观察 Ruby 的迭代
灵活的迭代方式也是用 Ruby 编写代码时的乐趣之一。看一下清单 8,这里给出了 Word
的 initialize()
方法:
清单 8. 闭包是很方便的
def initialize(spelling, part_of_speech, definitions = [], synonyms = [])
@spelling = spelling
@part_of_speech = part_of_speech
definitions.each{ |idef| idef.word = self}
@definitions = definitions
@synonyms = synonyms
end
清单 8 的第四行有点儿与众不同。为了让初学者看明白,在 definitions
实例上调用 each
方法时使用了花括号。each
方法本质上就像 Java 语言中的 Iterator
,但是它更简洁。在清单 8 中,each
方法处理迭代的细节,使调用者能够将注意力集中在想要的效果上。在这个例子中,传递一个代码块来表示以下意思:对于集合中的每个值 —— 即 idef
(这是 Definition
的一个实例),将它的 word
属性设置为 self
(这相当于 Java 语言中的 this
)。
清单 9 给出 Java 语言中等效的代码行(取自 清单 1 中的 Word
构造函数):
清单 9. Ruby 的 each 方法就像 Java 的 Iterator
for(Iterator iter = definitions.iterator(); iter.hasNext();){
this.validateRelationship((Definition)iter.next());
}
是的,是的,是的...!
Java 5 的泛型和新的 for
循环语法比清单 9 中的代码好得多。Ruby 也 支持大家熟悉的 Java 循环结构,比如 for
和 while
;但是在实践中很少用到这些结构,因为 Ruby 中的几乎所有东西都支持迭代表示法。例如,在清单 10 中,可以看出迭代文件的内容是多么容易:
清单 10. 迭代非常简单
count = 0
File.open("./src/dictionary.rb").each { |loc| puts "#{count += 1}:" + loc }
Ruby 中支持 each
方法的任何类(比如 File
)都允许以这种方式进行迭代。顺便说一句,Ruby 的 puts
方法(见清单 10)相当于 Java 语言的 System.out.println
。
回页首
条件语法
讨论了循环之后,我们来看看 清单 3 的 Word
类中的条件语句。在清单 11 中,单独给出了 add_definition()
方法:
清单 11. 漂亮的条件语法
def add_definition(definition)
definition.word = self if definition.word != self
@definitions << definition
end
仔细看看第二行代码。看得出 if
语句的逻辑吗?可以 将它改写为清单 12 所示的一般形式,但是清单 11 不是更好吗?
清单 12. 表达条件有多种方式
def add_definition(definition)
if definition.word != self
definition.word = self
end
@definitions << definition
end
在 Java 语言中,如果条件结构的体只有一行,那么可以省略括号。在 Ruby 中,如果条件结构的体只有一行,那么可以编写 清单 11 中所示的表达式。还要注意,同样的条件还可以写成 definition.word = self unless definition.word == self
,这使用了 Ruby 的 unless
特性。这很棒,不是吗?
回页首
Ruby 中的多态性
因 为 Ruby 是动态类型语言,所以它不需要接口。但是要记住,接口的功能在 Ruby 中是存在的,只是以灵活得多的方式表现出来。Ruby 中的多态性被亲切地称为 “duck typing”(意思是,如果它走起路来像鸭子,叫起来也像鸭子,那么它一定是鸭子!),这种多态性只是对方法名进行匹配的问题。我们来比较一下 Ruby 和 Java 语言中的多态性。
Java 的多态性
在 Java 语言中利用多态性的方式之一是声明一个接口类型,并让其他类型实现这个接口。然后就可以按照接口类型引用实现此接口的对象,并调用这个接口中存在的任何方法。例如,在清单 13 中,定义了一个简单的接口 Filter
:
清单 13. 简单的 Java 接口
package com.vanward.filter;
public interface Filter {
boolean applyFilter(String value);
}
在清单 14 中,定义了一个名为 RegexPackageFilter
的实现类,它应用一个正则表达式来进行过滤:
清单 14. RegexPackageFilter 实现了 Filter
package com.vanward.filter.impl;
import org.apache.oro.text.regex.MalformedPatternException;
import org.apache.oro.text.regex.Pattern;
import org.apache.oro.text.regex.PatternCompiler;
import org.apache.oro.text.regex.PatternMatcher;
import org.apache.oro.text.regex.Perl5Compiler;
import org.apache.oro.text.regex.Perl5Matcher;
import com.vanward.filter.Filter;
public class RegexPackageFilter implements Filter {
private String filterExpression;
private PatternCompiler compiler;
private PatternMatcher matcher;
public RegexPackageFilter() {
this.compiler = new Perl5Compiler();
this.matcher = new Perl5Matcher();
}
public RegexPackageFilter(final String filterExpression){
this();
this.filterExpression = filterExpression;
}
public boolean applyFilter(final String value) {
try{
Pattern pattrn = this.getPattern();
return this.matcher.contains(value, pattrn);
}catch(MalformedPatternException e){
throw new RuntimeException("Regular Expression was uncompilable " +
e.getMessage());
}
}
private Pattern getPattern() throws MalformedPatternException{
return compiler.compile(this.filterExpression);
}
}
现在,假设有 Filter
接口的多个实现(比如 RegexPackageFilter
、ClassInclusionFilter
类型和 SimplePackageFilter
类型)。为了使应用程序的灵活性最大化,其他对象现在可以引用接口类型(Filter
),而不是实现者,如清单 15 所示:
清单 15. 多态性非常酷
private boolean applyFilters(final String value, final Filter[] filters){
boolean passed = false;
for(int x = 0; (x < filters.length && !passed); x++){
passed = filters[x].applyFilter(value);
}
return passed;
}
Ruby 多态性
在 Ruby 中没有接口!只要方法名匹配,就可以利用多态性。看看吧。
在清单 16 中,用 Ruby 重新创建了 Java Filter
类型。注意,每个类之间并没有关系(只不过它们都拥有同一个方法 apply_filter
)。是的,这两个类应该被重构以扩展 Filter
基类;但是,在这里我只是想展示在 Ruby 中如何利用多态性,而类并不共享相同的类型。
清单 16. 过滤我,Ruby!
class RegexFilter
attr_reader :fltr_exprs
def initialize(fltr_exprs)
@fltr_exprs = fltr_exprs
end
def apply_filter(value)
value =~ @fltr_exprs
end
end
class SimpleFilter
attr_reader :fltr_exprs
def initialize(fltr_exprs)
@fltr_exprs = fltr_exprs
end
def apply_filter(value)
value.include?(@fltr_exprs)
end
end
注意在清单 16 中,可以通过 =~
语法在 RegexFilter
的 apply_filter()
方法中创建一个正则表达式匹配器。(如果您是 Groovy 用户,就应该熟悉它;清单 16 说明 Groovy 受到了 Ruby 的强烈影响!)
duck typing 的表现
在清单 17 中,我使用 Ruby 的 Test::Unit
(这就像 Java 的 JUnit)来演示 duck typing。顺便说一句,在 Ruby 中建立自动测试只需扩展 Test::Unit
并添加以 test
开头的方法。这与 JUnit 很相似,对吗?
清单 17. 多态性过滤
require "test/unit"
require "filters"
class FiltersTest < Test::Unit::TestCase
def test_filters
fltrs = [SimpleFilter.new("oo"), RegexFilter.new(/Go+gle/)]
fltrs.each{ | fltr |
assert(fltr.apply_filter("I love to Goooogle"))
}
end
end
注意,在 test_filters()
方法中,创建了一个包含两个类 SimpleFilter
和 RegexFilter
的集合。这些类并不共享同一个基类,但是在对集合进行迭代时,仍然可以简单地调用 apply_filter()
方法。
还要注意 Ruby 多么轻松地支持正则表达式。要创建正则表达式,只需使用 /
regex /
语法。因此,清单 17 中 RegexFilter
的正则表达式是一个大写的 G,后面是一个或多个 o,最后是 gle。
回页首
mix-in
Ruby 没有接口,但是它有 mix-in。可以把 mix-in 看成多重继承,但是它没有 多重继承的麻烦。mix-ins 是模块(不能被实例化),其中包含类可以选择包含的方法。这些模块方法会变成包含它们的类的实例方法。
例如,在 JUnit 中,Assertion
类是一个具体的类,其中包含许多 static
断言方法,我们熟悉的 TestCase
类会扩展这些方法。因此,任何 TestCase
实现类都可以在它自己的已定义方法中引用断言方法。
Ruby 的单元测试框架有点儿不一样。它并未定义 Assertion
类,而是定义了一个 Assertions
模块。这个模块定义了许多断言方法,但是 Ruby 不对这个模块进行扩展,Ruby 的 TestCase
类以 mix-in 的形式包含 assertion
。因此,这些断言方法现在都是 TestCase
上的实例方法,如 清单 17 所示。
回页首
结束语
您已经看到,Ruby 的语法与 Java 语言很不一样,但是非常容易掌握。另外,某些事情用 Ruby 做起来比用 Java 语言容易得多。
学习多种自然语言的经验告诉我们,可以混合使用不同的编程语言是件好事儿。能够用多种语言进行编程,使您在面对各种编程任务时具有更大的灵活性。这还会提升您的编程母语的价值。
正如在本文开头所说的,我主要是 Java 开发人员,但是我发现有许多办法可以将 Ruby(和 Groovy、Jython 等等)用在工作中。而且这么做的时候不需要使用 Rails!如果您放弃了 Ruby on Rails,因为您实际上不需要 在短时间内构建购物车应用程序,那么好好了解一下 Ruby 本身吧。我认为您会喜欢自己看到的东西。
参考资料
学习- 您可以参阅本文在 developerWorks 全球站点上的 英文原文。
- “Programming in the Ruby language” (Joshua Drake,developerWorks,2001 年 7 月):分为四部分的 Ruby 编程简介。
- “Test-first Ruby programming” (Pat Eyler,developerWorks,2005 年 5 月):这个教程介绍用 Ruby 的 Test::Unit 库进行单元测试。
- “使用 Eclipse 插件 Ruby Development Tools” (Neal Ford,developerWorks,2005 年 10 月):一种在 Java 平台和 Ruby 之间进行衔接的方式。
- “使用 Ruby on Rails 快速开发 Web 应用程序” (David Mertz,developerWorks,2005 年 6 月):深入介绍这种小型平台。
- “alt.lang.jre: Take a shine to JRuby” (Michael Squillace 和 Barry Feigenbaum,developerWorks,2004 年 9 月):要同时获得 Smalltalk 的面向对象能力、Perl 的表达能力和 Java 类库的灵活性吗?那就试试 JRuby 吧!
- Programming Ruby: The Pragmatic Programmer's Guide (David Thomas 和 Andrew Hunt;Addison-Wesley,2001 年):这本著名书籍的在线版本。
- Ten things every Java programmer should know about Ruby (Jim Weirich,O'Reilly Open Source Convention,2005 年):从 Java 开发人员的视角了解 Ruby。
- 实战 Groovy系列 (Andrew Glover,developerWorks):学习 Groovy 的各个方面 —— 这是一种在 Ruby 的启发下为 Java 平台开发的语言。
- Java 技术专区:数百篇关于 Java 编程所有方面的文章。
获得产品和技术
- Ruby 主页:下载 Ruby。
讨论
- developerWorks blogs:加入 developerWorks 社区!
关于作者
Andrew Glover 是 Stelligent Incorporated 的 President,这是一家 JNetDirect 公司。Stelligent Incorporated 通过有效的开发人员测试策略和框架、软件测量分析和综合以及持续集成,帮助软件开发团队和管理者持续监视代码质量,从而帮助公司
- 脱离 Rails 看 Ruby
- 脱离 Rails 看 Ruby
- ruby05_脱离 Rails 看 Ruby
- 也看Ruby on Rails
- 也看Ruby on Rails
- 看了一下ruby on rails
- ruby/rails
- ruby & rails
- ruby/rails
- Ruby & Rails on Rails 進階書單
- ruby and ruby on rails
- Ruby/Rails书讯
- install Ruby on Rails
- Ruby on Rails 实践
- Ruby on Rails!
- Ruby on Rails
- Ruby and Rails 当时
- 关于Ruby on Rails
- Web应用体系结构
- JBuilder2006与JBoss4.2.2GA的几点使用心得
- 网络字节序和主机字节序
- EXPLAIN 语法(得到SELECT 的相关信息)
- Symbian开发笔记(二)
- 脱离 Rails 看 Ruby
- 发现一个jet2的bug
- Spring 框架简介
- 当 Hibernate 遇上 Spring
- 计算机病毒及其防范技术
- OpenCms安装常见问题及解决
- C# winform 调用系统时间窗体
- 完全PHP5之session篇
- EventHandler 委托