2010年11月24日星期三

认识Java - 篇一

A
先暂且只涉及Java语言本身,来列举一下参考资料:
The Java Programming Language, Fourth Edition
The Java Language Specification, Third Edition
The Java Tutorial, Fourth Edition
Java SE 6 API Javadocs
其中后三者有在线版本可以获得
http://java.sun.com/docs/books/jls/index.html
http://download.oracle.com/javase/tutorial/
http://download.oracle.com/javase/6/docs/api/
不过下面的内容仅是以这里的第一本书为基础来写一些想法。
希望可以留下若干片段来从Java中品尝出一些有趣的东西。

B
Java是一种编程语言,同时也是一个平台。最初由Sun Microsystems的James Gosling开发的,于1995年发布第一个版本。整体看起来有点像C++和SmallTalk结合的感觉,是一种运行在虚拟机JVM上的静态类型语言。开发通过JDK,将源代码编译为平台无关的字节码。Java当初针对嵌入式而产生,重视移植性和安全性,目前是服务端应用开发最为广泛使用的平台。
保持着向后兼容性,Java现在的稳定是Java6,且已得到普遍的部署。从发展历史上说1.1/1.2/1.5是较重要的几个版本,由于其中新特性的引入使得代码的编写产生了新的习惯。本文将依照Java5的规范来说明,对旧的代码将不再提倡,具体细节会在下文中有所提及。

C
凭着自己之前对C++的感受,编译时间实在很痛苦。而在Eclipse的增量编译中,构建会随着代码的修改而自动完成。使得源代码保存之后,便可以立即直接执行。
关于编辑器,之前用到了Geany这个很平凡而使用的文本编辑器。话说初学应该拿语法高亮都没有的记事本的,可以减少干扰和依赖。然后用了Sun的NetBeans,其优点是开箱即用。通过它的GUI可以调用若干Java工具,同时补全的存在缓和了对类库的恐惧。目前还是转到了喜欢的Eclipse上来了,一个顺手的环境可以使代码的编写更为轻快。
Eclipse支持Emacs风格的按键,可以安装更多插件,并且有很好用的代码导航和重构功能。之前对C++和Python自己也把它视为终极IDE的,除非目标很小让它庞大的身躯的启动得累赘。对我这种菜水平,它似乎介意我:)。

D
从C++到Java,个人起初的动力仅是想多个额外的工具写算法方便一些,此外Java的庞大的社区也是一个吸引人的要素。这样的对语言平台的扩展还是一个很平滑的过程,从可预见的收益来说,虽然是盲目乐观了一些,但也可以说是差不多是值得的。
在TJPL一书中,除去开篇那段和TC++PL一样是K&R风格的概括性教程,内容是从OO开始的。先介绍了对象的使用和类的扩展,然后才转向表达式和控制流程。这和TC++PL正好顺序相反,C++是扮演着一个OO的推动者的角色,而在Java中已经把OO视为了理所当然的,或者说是本能的事情了。类库方面两者都是作为垫后内容来说。
虽然Java都C++都可以通过各自的标准库来做到很多的事情,不过Java的库要丰富得多。而像线程这一特性在Java中是直接从语言的层面考虑,融入了程序的执行流程之中。这使得在对Java的接触中看到一些对浅薄的C++知识来说很是新鲜的东西。
不过,C++的库也有很鲜明的特征,特别是在Boost中使用库的层面来扩充语法。它让代码显示出了魔幻的一面,使得多种范式的程序风格都可以在同一种语言中得到实现。自己接触了比较熟悉的库是Qt,它是一个GUI库,不过它也提供了语言层面的限定与扩展。其实Qt和Java有着相当大的共同点,自己一直是把Qt当作Java风格的C++来看待的。比如双方都是自Object而下的单继承结构,都有固定的getter/setter写法。由于Java的风格对其他现代语言有着无法回避的影响,这样来在接触Java的时候反而有种亲切之感。

E
本文的分节没有很明了的原则,完全是想到哪里写到哪里。觉得差不多是一个内容了,或者篇幅差不多了,就单独作为一个段落。
记得Java的书上说过要忘记C++,因为两者之间的差别会花费不必要的经历,而且还容易带来混淆。我对这句话是很认可,两者毕竟是类似却又不同的语言,在同一个时候只会凭借一种语言的角度在思考。不过有一个差别还是要提一下,那就是指针。C语言用户有嵌套指针的习惯,并且有时以此为乐。不过这种风格在结构良好的C++程序中并不常见,阅读起来便较为清晰。恩,这样来看Java也是属于代码较容易阅读的类型。
下面说一下学习和使用间的关系,像Java这样的带着庞大的库的语言说什么完完全全掌握是一件不现实的事情。对于熟悉一种工具而言,就涉及了成本和收益之间的关系。先再把C++提上舞台,它基于了C并把OO提到语言层面来。OO是一种思想,它有它组织程序的益处,在C中并不是不可以使用。但是对C的使用者而言,即使知道OO但不熟悉OO的话,它很可能不会去OO。而在C++中OO成为了语言的一部分,并有了一致的实现方式。这使得C++的使用者对OO有所学习,并在实际的项目中运用OO的益处。就像现在ROR让Web应用的MVC普及一样,因为它提供了易于接受的方式,并且让其他平台上也转入对同样模式的使用。
这里想说的是,学习是有目的,但也是有偏泛的。在现实生活中不是一种保守型的一对一关系,作为一个工具来说人们是使用他熟悉的东西来解决不熟悉的问题。本文虽然很散乱,但还是参照了很系统的书目来写的。依照着Java的风格使用他,而不仅仅是抽取着语言的部分。不会去像从C++中抽取了已知的C部分,然后便以此为全部地使用C++。也不会因为看到了其中新鲜的东西,而去忽略语言它自身成为的一个整体。这样,虽然说这里还只是在从语言层面上谈,一个从实际运用角度说还有欠缺的层面。不过毕竟,话题总得有的浅薄的开端吧。

F
先来说Stream,按字面意思就是流。单说这个字看起来有所费解,还是觉得英文单词的表意比单独的中文字要清晰一些。Stream是一个很形象的单词,它是对I/O的一种抽象方式。该项机制源自Unix系统,为输入输出、文件操作、用户交互、进程协作、网络通讯提供一致的界面。Java和C++一样,都试图在IO方面提供较C更多的抽象概念和工具,以方便统一地解决在流的使用中常见的问题。
Java中的流,按方向区分有输入流和输出流两种,按数据划分有字节流和字符流两种。其中以字节流为基础,提供了InputStream和OutputStream这两个界面。在使用Stream时我们通常关注的是界面能怎么用,而将具体类的实现方式隐藏在界面之下。这里说界面其实是不恰当的,虽然在使用时可以这样理解。因为InputStream和OutputStream实际上是抽象类,有两组对应的抽象方法叫read和write。这样做的获得的好处是,在实现自己的Stream类时只提供read(int)和write(int),而其他方法可以使用依赖于它们的默认实现。Stream类的其他方法暂不说明,其中有个要注意的是它的方法有阻塞与否的区别,这对使用流的方法的返回值有着不可忽略的影响。和字符相关的IO流是实现了Reader和Writer这两个抽象类,从抽象层次上说它们和Stream的两个抽象类是平行的。它们提供的方法在名称上相对应,并同样有着各自的不同用途的实现。其间的差异是,字符流在字符编码上是保持着统一的,这样便实现了与实际使用编码的无关性,而字符流是直接地反映了数据自身的。在字节流和字符流之间,是可以通过InputStreamReader和OutputStreamWriter来转化的。
这是因为Java中的流实现是可以通过序列的方式来使用的,以其他的流作为当前流的输入或者输出,以达到在使用某个具体的Stream时可以实现功能上的扩充。例如在输出时通过OutputStreamWriter使用OutputStream时,将对输出的字符进行编码,编码方式可以用字符串指定或者由系统默认。调用某一个流的flush或者close方法都会使得它说使用的流也被调用同样的方法,不然的话它所使用的流的read和write方法一般将只会在该流认为需要的时候被执行。在Java中还提供有Filter、Buffered、Piped、Print、LineNumber、SequenceInput、Pushback、Tokenizer,Data可作为中间流使用,他们可以最终使用ByteArray、CharArray、String、File或者其他Stream的实现作为实际IO的对象。这些中间流除了可以用来提供过滤功能外,也可提供比Stream抽象类更多的可调用方法,或者用来实现将Stream转化为不同的接口供不同的目的使用。例如对象持久化就是通过流来实现了对象的保存和传递机制。
顺便说一下,负责字符编码的包是java.nio.charset,通常是用在与外界的IO操作中。Java的char类型会一致地使用UTF-16编码,这样就在程序的内部逻辑上尽量避免编码问题了。

G
下面开始内容简略一些,既然本文的本来目的是一片流水帐,就让它更像流水帐一些吧。想到关于Java语言本身有趣的或者说是值得关注的东西记录下来一些,想来随着这段时间的记忆过去也可以发掘其中遗留下的些许价值吧。
Java是直接提供对线程的支持的,一个线程即一个Thread对象。我们的方法main是被默认创建的一个线程,它可以调用其他Thread对象的start方法,让线程对象的run方法可以和自己同时执行。也就是说他们中的任何一个方法陷入阻塞或者死循环,其他执行着的方法依然可以不受影响的运行。自己的run方法可以通过派生Thread类实现,或者在单继承的限制中去派生Runnable后用来构造Thread对象。
当同时运行的线程要使用同一个数据时,如果该项操作不是原子的,那么可能会造成互相依赖的一组操作之间混入其他进程的数据。这就需要在数据操作前对所操作的对象加锁,然后在操作完成之后释放。进程在操作加锁的数据时会产生阻塞,直到其他进程完成任务后,再继续执行自身的代码。
使用java.util.concurrent包里的对象来实现同步任务是可以的,不过较常用的是使用synchronized关键词。它可以作为关键词来修饰方法,那么对象方法会以对象自身作为锁,类方法会以它所在的类作为锁。当某锁因为因为某个进程的使用处于locked状态时,其他进程调用要求同样的锁的方法时就会发生阻塞,直到先前的方法调用完成。通常在Java的类中数据成员是私有的,然后通过公开的方法来使用数据。如果一个方法是非同步的,那么它运行的前后它说使用的数据将可能被同时执行的另一个自己或者同类的方法所修改,在一些场合这种不一致是会造成功能上的错误的。有时会需要获得一个成员的最新状态,则需要使用volatile修饰符。
除了用来修饰方法,synchronized也可以作为语句使用仅用来保护需要保护的代码。在一段同步的代码中,它可能因为某些条件不满足希望暂停执行。它可以释放锁让其他和它同步的方法可以被调用,并在适当的时候通知它可以尝试继续执行。为实现这样的模型,Java的在Object对象上为我们定义了wait和notifyAll方法。当一个线程在调用某方法遇到wait时,它会阻塞并释放锁,直到有其他进程调用了包含notifyAll的方法时再重新争取锁并执行。这样便实现了多线程调用同步方法当中,实现阻塞与否的移交以达成协作的目的。这也有些像把有待执行的代码放到一个方法列队中供其他方法调用,不过这里使用的锁的机制是让有待执行的方法阻塞,而其他的方法的任务仅仅是相当于通知阻塞的进程而不是这个列队中的方法的执行者。

H
为了编写数据结构的重用,Java提供了Collection框架。它和C++中的STL一样,定义了容器和迭代的概念。这样使得算法和结构之间建立了接口上的抽象,让同样的操作能够以同样的界面去用使用到它满足它应用的数据结构上。既可以直接使用Java提供的相关的实现,也为用户的扩充带来了方便。用户可以直接使用Collection实现自己的算法,也可以编写Collection类来执行已有的算法,或者以此为基础增加双方面的扩充。
在Java中对Collection的使用是从接口和实现两方面考虑,接口提供了容器的用法,而实现则提供了可实际工作的对象。和C++中运用泛型和模板来实现容器与迭代的不同,Java不是通过静态多态让某个因为提供了某些方法而能做怎样的使用那样的“窄”界面,而是从Collection这个能提供Iterator对象(通过iterator方法)的“肥”界面进行实现,并让不能实现的方法抛出UnsupportedOperationException异常。此外,出于对用途的限制并提供能多的方法,从Collection派生出的界面有Set(SortedSet)、Queue、List,以及方法名相同但无法直接派生的Map(SortedMap)。
对于容器的使用通常是通过容器的迭代器来使用的,它提供方法hasNext和next以遍历数据,还有一个可选实现的remove方法产生对容器的修改。其子界面ListIterator还提供了可选实现的set与add方法,以及Collection界面自身的add和remove(包括提供其他的冗余的函数)都可以用产生副作用。不过在一个迭代器使用容器的时候,该容器被其他的其他的方法修改会造成功能上的错误,Java有时会通过抛出异常来实现自我保护。由于容器实际上是储存了对象的引用,修改容器的成员和对某个成员的修改是不同的概念,有时为当前要操作的容器建立共有界面的副本也是种可行的做法。此外,有些容器需要对它所含的元素排序,它会要求其所含对象实现Comparable的compareTo方法,或者提供有compare方法的Comparator。String类出于不同的排序要求,对两种方式都有提供。
再具体一些来列举,界面Collection还提供有方法size、isEmpty、contains、toArray、~All,并确保可以迭代。子界面Set限定元素唯一(!equal),List增加的方法get、set、indexOf,Queue增加了增加peek、poll、offer了,Sorted的类型增加了first、last、subSet并限定了排序。对于容器的选择,需要从用途和实现两个方面考虑以获取更好的性能。Java中提供有实现HashSet、LinkedHashSet、treeSet、ArrayList、LinkedList、PriorityQueue、HashMap、LinkedHashMap、IdentityHashMap、WeakHashMap、treeMap。这些默认实现的名称已经表明的它们的工作方式了,如Linked使得修改变慢而遍历变快,没有多少选择的余地。不过在使用的时候,也就是为实现创建实例之后,依然是通过接口所提供的方法来进行操作。此外,和STL名称相同的若干类依然存在,它们是现有的Collection框架之前的实现,针对enum类型还有一组专门的容器。
对Collection创建副本,虽然它们有共有的元素,但已经是不同的容器对象了。而上面提及的subSet一类对Sorted方法皆适用的方法,而是为原容器创建一个视图,视图与容器之间会保持着同步的关系。Wrapper是另一种创建视图的方式,如Java提供有Unmodifiable和Checked。可能这些View在使用时并不常用,但确实是一种implement和extend之外定义类的使用的常用模式。

I
继续关于Collection框架。默认实现的算法在Collections和Arrays下面,如sort和binarySearch,以及其他一些如fill、copy、shuffle、reverseOrder、frequency等等有用的工具,外加提供一些特殊的如singleton、empty的容器对象。使用同步操作的话,可以使用SynchronizedWrapper,或者用java.util.concurrent里允许阻塞的特殊的列队实现。在实现自己的容器时通常从Abstract类派生而不是去直接实现接口,例如至少有size和iterator方法,一些方法会提供默认实现或抛出异常。
说到容器,就要来说一下泛型。C++的STL正如其名,正是在模板机制提供之后才被实现的。不过Java中情况特殊的是Collection是Java1.2的特性,而Generic是Java5中添加的内容。虽然现在通常容器和泛型总是同时使用的,但他们运行时是以不同的方式存在的。Java为了达到向后兼容的目的,对泛型采用了擦除机制。这也就是说在编译的时候,Java会为变量选择一个较抽象的类型,而在使用到具体的类型时插入Cast运算。例如对于没有指定类型参数的Collection容器,便是默认以Object类型为方法的参数。
Java有着比C++更为严格的类型机制,在使用着以类为可见性的同时,要求子类可以充当父类进行使用。这也就是说继承与实现不仅仅是一种机制上的,也是一种概念上的。它限定了子类若干行为,如不能缩小方法可见性,不能扩大抛出的异常,以使得这种严格的“is a”关系确保实现。旧Java中的Stack is a Vector便被认为是一个此方面的过失。
在泛型中,Java也同样维持着类的关系的存在。对于泛型类或泛型方法,从无类型参数的raw type,到提供了?、extends、super作为参数的类,到提供了具体的类提供的类,它们在概念上趋于严格。如果代码编译时存在对要求类型的范围有更严格的限定时,编译器会更具不同情况拒绝编译或者提示unchecked。我们称变量的类型是静态类型而对象的实际类型是动态类型,Java中的泛型就是一种在静态类型之中实现的机制,像“new List<String>[1]”这样直接依赖类型参数的语句由于擦除机制是不可行的。从使用上说,目前泛型是作为一种编译时的类型检查来看待的,仅仅主要运用在容器框架当中。

J
再顺便说一下Exception,也就是Java中的异常机制。在C++中异常是以一种对错误处理的抽象机制被添加到语言中的,它分离异常的产生者和异常的处理者使得代码更关注于自身的事情,也避免了返回值方式或全局变量方式易产生的疏忽。不过由于异常机制实现方式的差异,throw和try通常只在一个模块内部进行,也就是说在类库提交给外界的接口上异常是很难见到的。而在Java中,异常成为了程序逻辑的一个一个部分,和语言自身有着更加紧密的联系。
这里仅仅谈Exception,尽管他不是唯一Throwable的东西,它允许通过字符串的message来构造或者用initCause构造异常链。这里的重点是,Exception可以划分为RuntimeException和其他Exception两种,前者是unchecked的,不加捕获的Exception将会造成程序的终止。而后者,也就是checked的异常,是要求它所在的方法是写明throws它或者它的父类的,而调用的这样的方法也明确要求语句放在try块中不然不予编译。
在这里checked异常是作为程序的控制流程的一部分来看待的,也就是说一个函数的调用结果有两种。一种是正常结束返回它写明了所返回的类型,另一种结果则是抛出它写明的可能抛出的异常,它们都是方法运行允许的方式。
异常可以通过它所包含的信息来区分,也可以使用不同异常或建立异常间的继承关系。后者使得使得通过catch语句对不同的异常和某个异常的范围的判别变得简单而清晰。而finally语句中的代码会确保执行,即使有break和return也一样,常会和try前的某条语句配对使用,例如某个文件指针不为null便调用close方法。不过虽然异常也是一种程序的逻辑,但是在应该使用条件语句的时候,还是不要滥用异常。还有一个方便调试的assert语句,它不影响程序逻辑,默认未开启。

K
反射机制通过java.lang.reflect包使用,它为程序添加了在运行时使用类型信息的能力,例如实现一个简单的类型浏览器。不过反射作为一种机制提供,它只是被认为是可以用来做什么,除了权限外没有对它的行为有所限定。除非有明确目的,应该使用编译时代码中的Token来使用对象,而不是运行时的字符串来使用。
这里可以想到的两个反射的用法是动态载入和解析DSL,因为动态语言较依赖运行时,它们之间会见到一些相似的地方。
Java中为反射提供的类型有Class、Annotation、Modifier、Member(包括Field、Constructor、Method)、Arrays、Package,它们与语言中的类型直接对应,并提供了访问、修改和使用它们的方法,将一些语言层面的功能以方法调用的方式来实现。Class还有一个父类叫Type,它随着Java5泛型的添加包含了运行参数的信息。不过我们使用依然是以Class为基础开始的。我们可以使用对象的getClass方法、使用.class语法、通过Class.forName或者其他返回Class对象的操作来获得对象。
动态载入的目的是在编译时我们不能确定某个类时候存在,例如调用某个数据库后端。我们就需要使用类的名称作为字符串调用forName方法,它可能返回我们所需要的类也可能抛出ClassNotFoundException。通过获取类的Constructor对象,便能通过其newInstance方法来创建我们所需要的实例。如果连调用的方法也需要运行时确定时,可以通过字符串获得Method对象后调用其的invoke(this)方法。获得Annotation实例,或者根据名称找到可修改的方法也是可以的。关于Class的类型转换,有asSubclass和cast,可能会抛出ClassCastException。例如有语句“Class cls = Class.forName("java.lang.String").asSubclass(String.class);”,并有一个叫getName的方法与之对应。
其他方面的,Java持久化里用反射来调用私有方法,还有InvocationHandler和ClassLoader两个在特定场合很有应用价值的类。不过日常里和反射机制本身一样都不算常见,自己不大熟悉。再由于相关文档都有很详尽的说明,这里就暂且略过。

L
Java在内存管理上使用了垃圾收集机制,在JVM认为有必要的时候,它会自动执行System.gc()清理不再使用的对象。对象可以定义它的finalize方法供gc时执行,不过如果在程序退出前没有gc的话,这段代码也不会被运行到。这里使用这个概念会对Reference对象有特别的差异,如用于缓存或内存原因的动态加载。
对于单线程程序,main方法结束,整个程序也就结束了,并返回状态0。对于多线程程序,可以向其他线程发送interrupt消息,使得那个线程可以通过interrupted方法以及InterruptedException来接受到这个消息,来自行退出。不然Java会一直运行直到所有的用户进程运行完毕,除非某些进程setDaemon(true)或者System.exit被调用。其中后者也是Java中用来返回状态码的方式,而不同于C中int(main)。TimerTask都属于守护进程。在程序因为自身或外界的因素被要求退出时,有短暂的时间可以执行ShutdownHooks。还有另一种意外地使程序运行时退出的是运行时异常,由main或者run抛出而不会被try语句保护,此时可以为线程提供UncaughtExceptionHandler对象。出于调试目的,常使用异常的printStackTrace方法。

M
Java中的原始类型有boolean、char、byte、short、int、long、float、double,并将它们包装为Boolean、Character、Number(Byte、Short、Integer、Long、Double)、Void,并可以在使用时自动于两者之间转化。这些包装后的方法除了继承自Object的toString用于类型转化equals用于比较,还提供有果然类型相关的静态方法如valueOf用于构建parseType解析(两者是对应的)字符串,以及对象方法compareTo用于比较typeValue转回原生类型。一些基本的类型相关的方法,也由Number或Character类的静态方法提供。数学函数则由java.math,也包括高精足算法,浮点晕眩有实现无关的Strict模式。随机数用Math.random。时间相关的除了System.currentTimeMillis返回long,其他属于Date和Calendar对象,非原生类型。还有一个BitSet比位移操作使用起来直观一些。
Java字符串用String类,表示一个不可修改的字符序列。它提供的方法有charAt、length、subSequence、indexOf、startsWith、intern、replace、trim、toLowerCase、getBytes(这个涉及编码转换)。此外还有replaceFirst、split为使用正则表达式的提供了简便的方法。正则表达式由包java.util.regex提供,是一个风格类似于perl5的实现。其中包含Pattern和Pattern两个概念,前者用来compile表达式并对CharSequence使用split或matcher,后者提供matches、lookingAt、find并使用自身保存匹配的状态,其状态通过返回值以及start、end、group获得。正则表达式比写一串字符串相关算法要显得简单而清晰。
结合IO很实用的类有Formatter和Scanner,前者用来格式化输出,在printf中会自动调用,后者的功能正好相对应,通过迭代器风格的接口使用。自己合成字符串的话建议用StringBuilder,原先还有一个线程安全的StringBuffer。不同编码会统一以UTF-16的codePoint来实现,它是一个用于char的int类型值,也用于字符流。

N
javadoc是Java中用来从源码生成的文档的工具,清晰的文档可以便于理解代码的结构,也使得代码的复用的接口有了清晰的说明。
文档注释通过/** doc comment */插在所要标注的元素之前,每行以*开始,使用HTML语法。注释其中的第一段用于表示总述,后跟多个空格表示风格。多余空缺的注释,会默认按照一定的规则继承其父类的描述。还可以使用的元素有:@see、{@link}、{@linkPlain}、@param p、@return、@throws E、@exception E、@deprecated、@author、@version、@since、{@literal text}、{@code text}、{@value field}、@serial、@serialField、@serialData、{@inheritDoc}、{@docRoot}。方法名和类名之间用#分割。包的翁、当写在package-info.java中。
Annotation虽然也是多代码元素的一种描述,但常用的有CLASS和RUNTIME的区分。后者在运行时可以通过反射获得,获得一个@interface的实例。系统还提供了@Target、@Retention、@Deprecated、@Documented、@Inherited、@Override、@SuppressWarnings。例如使用@Override修饰的方法会在编译是检查没有应为参数的错误而对父类方法进行了overload。对Package也同样适用。

O
最后来罗列一些零散的内容,不是说它们不重要或没有值得说的东西,只是在这里不做展开了。
java.util中有Observer/Observable类型用于实现观察者模式。这是设计模式中常见的一种,通过维护一个关联对象的列表,用于对象间的协作。所以用派生是一种让双反接口相协调的办法。当然,模式只是一种类之间的结构方式,它在实现方式上并不唯一。
系统变量的获得可以使用例如System.getProperty("user.home");之类的语句。通过调用Runtime.exec可以获得一个Processes对象,然后以流的方式可以进行通讯。如果是使用Java类的话,可以通过java.security限定权限以保障安全。
使用ResourceBundle.getBundle可以载入ListResourceBundle对象或者.properties文件里描述的资源,不同语言的版本可以实现派生关系对通用版本进行修改。不同的语言版本会自动根据环境进行选择,这是Java中程序实现i18n的方式。
JavaBeans是Java中的一个复用组件,可实现BeanInfo或用反射生成。通过get和set使用一个serializable的有默认构造器的类。
嵌套类从Java1.1开始运行,不过编译器会用$分割符把它抹平。静态的嵌套类问题不大,仅相当于有了一个命名空间,以及一些访问权限上的规则。不然的话这个类存在于与外部类中或者存在于方法中或者是一个匿名类的话,它的实例需要保持一个对外部类示例的引用。这会用到如this.new这样不常见的语法,内部实例可以访问它外部示例的成员。
枚举Enum也是Java5新增的,它源自C语言。原本在Java是通过final static来实现枚举作用的,现在有了语法糖衣之后依然是这样实现的。和C一样用枚举表示数字当然可以,不过原本Java中还有一个用法习惯是枚举的成员是不同的对象,每个枚举元素可以有它的属性和方法。所以现在Enum也是作为一个抽象类使用,枚举元素可以利用方便的语言构造或者派生。
Java6里增加的特性让我印象深刻的是自带了JavaScript的支持,它可以和Java代码之间互相使用。JS作为一门标准化后的语言,这里用的是Mozilla的实现。动态语言的好处是类型属于值而变量不需要类型,类的接口是出于概念上约定而不必复杂的层次关系。
文件操作除了File***Stream,还有File类和RandomAccessFile类,用途和接口上更加传统一些。

P
内容还有一些其他可以说的,例如上面有没提到或者未提详细的地方,不过从品尝的想法和时间的允许的角度说,也只能挑选着内容来说了。下面这本书的目录会是一个更详细的提示列表,是关于Java的各种特性方面的:http://www.amazon.com/Java-TM-Programming-Language-4th/dp/0321349806 。
以后会后篇二,不过话题会有所不同,将谈到Java语言自身之外的更多的东西。那啥啥啥的,这篇的文字呢也就一个通常长度,当废话看,当游泳池看什么的都是可以的。
真的就到这行结束了,本文的下一行就真的什么都没有了,至少传说中的最后一行就是这一行了。
晚安!

关于Django和OrgMode的杂乱物

警告:此文是个坑!
* 前言
之前有帖子把Emacs和Python一起写,这次也把可以涉及到的一些内容写在一起了。
仅仅是写在一起而已,它们的内容在下面还是将区分开来放在不同的章节里的
* Django
** 什么是Django
已经很长时间没碰Django了,以下的内容算是回顾一下之前接触到的一些状况,仅是回顾而已不再深入。
** Apache上Django
这一段说的是Apache的共享主机上一个可行配置方案,是目前比较常见的部署环境了。
用VPS的话,在更大的权限下会有更好的方案,还是看Django文档吧,这里暂不做更多尝试。
个人参照了helionet.org上方案,并做了尝试。可以用fcgi或者mod_wsgi的方式。
Django文档中在howtodeployment一节里面有同样原理的说明。
** rewrite
在用户访问的路径下建立".htaccess"文件,权限为644。
这里要做的事情有两件,让静态文件文件可以直接被返回,让对Django页面的请求能够转发到我们编写的项目上。
#+BEGIN_EXAMPLE
RewriteEngine On
RewriteBase /
RewriteRule ^(media/.*)$ - [L]
RewriteRule ^(admin_media/.*)$ - [L]
RewriteRule ^(dispatch\.wsgi/.*)$ - [L]
RewriteRule ^(.*)$ project_subdirectory/dispatch.wsgi/$1 [QSA,PT,L]
#+END_EXAMPLE
这个文件根据自身的需要来写,以上仅仅是一个示例。
** wsgi
紧接上一段,建立文件dispatch.wsgi,并设置权限为755。
#+BEGIN_EXAMPLE
import os, sys
sys.path.insert(0,"/home/zsyweb/public_html/python-site/");
os.environ['DJANGO_SETTINGS_MODULE'] = 'project.settings'
os.environ['PYTHON_EGG_CACHE'] = '/home/your_cpanel_username/.python_egg_cache'
import django.core.handlers.wsgi
application = django.core.handlers.wsgi.WSGIHandler()
#+END_EXAMPLE
django模块和我们的站点都是作为一个模块被import,随意要添加到"sys.path"中。
然后会有一个"environ['PATH_INFO']"字符串,它就是交给我们的urls.py匹配的部分。
该文件会被作为一个进程执行,并在被更新时自动重启。
** ……
在自己的home路径下建立目录".python_egg_cache",并设置权限为777。
上传Django模块,以及自己的项目,是它们都成为一个单独的目录,并保证父目录已添加到"sys.path"中。
在服务器上设置好数据库,然后执行"manage.py syncdb",即使无法使用shell也可以通过上传cgi脚本或执行call_command函数来解决。
如果使用Sqlite的话,要让它所在的目录具有可读写的权限,不然肯定有500错误。
** GAE上Django
目前Django程序是不能直接在GAE上执行,主要是由于ORM模块不能使用,导致依赖Model的部分需要以GAE提供的界面的来编写。
不过就目前而言,Django-nonrel是个很不错的解决办法,它为Django的ORM提供了NoSQL数据库的后端,其中就包括GAE。
目前觉得GAE还是不错的,注册时只需要用手机收取一下注册码,然后就可以免费建立若干应用了。
** GAE
需要安装Python2.5和GAE SDK1.3.5,我那时候故意选择这个版本的,因为they work。
不知到好来的GAE又更新了什么,当时安装了新版本却反而不能正常工作。
之前用Google的CLI工具也出现过最新版不如之前某些版本稳定的状况。
** Django-nonrel
*** 获取
去它的网站下载若干压缩包回来,它们就是下面烹饪过程中的食材。
其中的django-testapp解出来就是我们的项目目录,可以看到我们熟悉的manage.py文件在里面。
其他的文件是我们的项目import入我们项目的模块。根据Python的规则,一个模块就是一个有__init__.py的目录,目录名作为模块名使用。
就目前DN提供的模块而言,我们解开它们应该得到的是:
- <project>/django
- <project>/djangotoolbox
- <project>/dbindexer
- <project>/djangoappengine
不过因为GAE对文件数有限制,以上文件肯定是已经超过了。所以接下来的可算步骤成立必须要做的事情:
- 把django模块(就上上面列出的那个目录)打包为django.zip,放到名为"zip-packages"的目录下。
这个目录已经添加到"sys.path"中了,我们的Django App或者其他模块也可以以同样的方式处理。
不过DN的其他几个模块就不要动了,它们和我们项目结合较紧,会在较早的时候被import到。
*** 使用
**** ORM
DN最大的作用,同时也是比较通常Django应用最需要的注意的地方即是它的ORM。在NoSQL数据库上,数据是也对象的形式保存的,对象可以包含可若干属性,对象的属性可以不存在,也可以建立索引。但是在关系型数据上的JOIN查询却是不提供的,同时在数据库事务中如何保持数据的一致性上也有些许区别。
那么也就是说包含JOIN的查询,aggregates,select_reated目前都是不可以使用的。此外many-to-many和transactions也不能使用。
当然不能使用并不是说我们在用到这些特性的时候就达到不了我们需要的结果,而只是实现方式上不那么直接。一是需要自己再多去实现一些代码,一是会有性能上的损失。
例如对于join查询,可以增加查询的次数,将一些判断从SQL中移到Python中来。值得注意的是在迭代中使用查询是一件很恐怖的性能损耗,即使必须用到这样的方法来实现某写功能,一定要设置好缓存,并额外设置计划任务对缓存进行更新。
对于M2M关系,也需要手工建立"through"用到表,也就是有两个ForeignKey指向要建立关联的两个对象。
然后通过重写save以及相关的方法或者建立signal来确保这个表示Reletionship的表中记录能够在正确的时候被创建和删除。
事务方面,GAE提供了额外的支持,暂时和Django的事物模块没有关系,相关的内容在GAE的文档中。
**** Mangae
使用的格式是"manage.py <command>",命令shell、createsuperuser、syncdb都可以使用。
需要注意的是这些命令是对本地GAE数据库操作的,在NoSQL中虽然表依旧存在,但是字段是属于数据而不是表的,在对表的字段作出修改的时候,原有的数据项依然存在数据库中。
GAE的开发环境是把数据库以文件的形式存在本地硬盘上的,可以手工删除这个database文件。
此外"manage.py deploy"会上传整个项目,命令中加了"romote"如"manage.py remote createsuperuser"那么它所操作的数据库就是服务器上的数据了,它和本地的开发环境是想独立的。
静态文静也是同样的上传,然后需要在GAE的文件app.yaml中做关于路径定向的设置。
最然直接访问Django的Admin页面,但是在表和superuser建立之后,就可以正常工作了,所以不小心看到了500的错误的时候,不要慌乱了手脚哦。
**** GAE的限制
坑,涉及数据查询和运行时间
** Django的Style
*** 倾向
之前社团里说来建议一个站点,于是我就拿Django来写了写,不过最后还是中断了。
因为觉得使用现成的Php应用可以减少维护成本,其次也没有人去推动这个社团站点的设想。
再者当代码越来越多的使用,如何去掌控这个规模也是自己的短处,频繁的重构只使得结构变得脆弱,而新代码使得代码越来越难以修改。
所以,这里有必要重新回顾一些最Django的方式:
Django的出现是英国一个新闻站点的需要,它们需要以一个快速固定的方式,为新闻事件建立站点。
在这一个过程中,需要尽可能的实现功能的重用,此外还有整个开发流程的重用。
在Django中Model和URL是站点构建的一个出发点,Model部分将决定我们我们做要呈现的数据是什么,而URL部分是站点提供给用户的一个接口。
然后,另两个需要同时考虑到的重要要素是View和Template,View表明了站点呈现到用户面前的是什么,而Template将表示这种呈现将是以何种的效果。
可以以Restful的URL通过Generic views实现对Model的操作,也可以让Model和URl配合让Generic views能够正确的展现出来。
*** 避免
话说自己之前对Model过于重视了,觉得数据是站点的全部内容,其他的部分之不过是对数据的表达。
直到看了未来的Django1.3中View是可以mixin了,才发觉原先想法中的不足。
有时一个站点的构建也可以是从View开始的,人们是先意识到一个站点是要呈现什么,然后再去实现构建它的数据模型的。
当然,我只是说Django的使用去保持一种量产的态度,而不要太过调整它的结构(仅是说使用,Django的开发不在此限制之内)。
例如自己的一个不够如意的尝试就是利用ContentType机制,也就是相当如Java中反射加Python中的鸭子类型的一类东西那种不会用的时候很容易滥用的东西。
让整个站点的代码通过派生共用抽象模型,全部变成模型的一部分。
再加上metaclass等动态机制,让model提供一堆protected virtual的东西,而把CURD的View以及Form等东西全部抽象掉。
虽然这种修改我原以为会让之后代码修改变得简单,不过之际中,严格依照Django提供的结构把一个Model和它涉及到的View啦Form啦什么的都分开来写一遍。
这里仅仅是分开来写一遍而已,Django已经是提供的声明式的语法而且还有一段时间的向后兼容时间。
保持代码的基础以一个简洁稳定的方式,对于之后代码量大后的维护,才是可行的方式。
特别是通过建立自己的template tags,使得每个view只需要负责他所负责的数据,或许即使是像国内站点首页那样的庞然大物,也可以参照类似的方式来增加代码的灵活性。

** 回顾
居然这段打算说的被前面说掉了,大意就是这段时间没写Django代码过了。也没为自己写个博客程序,应为觉得还是blogspot省心。而且就搭建开发环境上来说还是php省心,最简单的情况是存一个php文件就能运行。想随手一个Django应用的话,则一下子就要面对许多需要涉及和不需要涉及的事情,MVC啦ORM啦如何去部署啦都是一下子都会考虑到的问题。当这种复杂性不是瞬间需要的时候,反而是对随手写几行代码这种行为的一种困扰。
不过,相比于Php门槛低应用多的优势,使用Django还是有他可以胜任的场合的。例如Django所要求的结构可以降低自行编写的站点的复杂度,有一个直接完整的学习过程,而且拿Python写算法的话也要相比而言等方便一些。
学习成本和使用成本,如果绘制成为曲线的话,它们陡缓的场合是不同的。
** 代码片段
这里内容并没有什么特定的内容,仅作为一个堆放而已。
#+BEGIN_SRC python
- url: /static
static_dir: static

from django.contrib.auth.models import User
user = User.objects.create_user('root', 'email', 'pass')
user.is_staff = True
user.save()

User.objects.create_superuser('root', 'e@mail.com', 'pass')

def profile_create(**kwargs):
if kwargs['created']:
profile = UserProfile.get_or_create(user=kwargs['instance'])
profile.save();
post_save.connect(profile_create, sender=User)

class Membership(models.Model):
person = models.ForeignKey(Person)
group = models.ForeignKey(Group)

#+END_SRC
user singal
django-registration
Nonrel-search
各种各样的缓存,只能指定的方式使用乖哦能
#+BEGIN_SRC emacs-lisp
点对点
#+END_SRC
#+BEGIN_EXAMPLE
点对点
#+END_EXAMPLE
abspath(
* org-mode
** 什么是org-mode
在emacs中,Org-Mode已经是自带的了,它已经是我开Emacs的主要用途了。
输入"M-x org-mode <RET>"就可以进入,用info可以查看它们的使用说明,文件名后缀.org。
自己主要拿它来写文档用,比如说这篇就是在org-mode里面写的,之前有一篇小说也是。
包括上文提到的那个站点项目,也是用org-mode来描述想法和记录进程的。
首先呢,建议阅读[[http://orgmode.org/orgguide.pdf][OrgGuide]]这份文档,它是对info手册的摘要,对系统地去了解一下org-mode还是很有帮助的。其中对org-mode的定义是:
: Org is a mode for keeping notes, maintaining TODO lists, and doing project planning with a fast and effective plain-text system. It is also an authoring and publishing system.
这段话概括了Org-Mode的功能,不过再接下来的文字里所要关注的,不是去列举org-mode的功能或者单纯的学习操作,而去寻找若干实际的应用场合,来看看Org-Mode是如何帮助我们完成特定的任务的。
享受Org-mode带来的文本显示与展示效果,使用它提供的种种功能,以及简化输入用的快捷键。
关于它所拥有的各种,本文无意去全部涉及或概括。至于使用上的创意则完全是看各自发挥了。
通过org-mode提供的格式,让其中文本语义在编辑中展现出来。
出于习惯,为节约编写时间,除非有特别的要专门要求,以下内容将从略,所以会以意义不甚明了的状况。
** Emacs的使用
仅当热身用,仅涉及光标移动什么的,对键盘的亲切感是下文展开的基础,因为org-mode的使用就是就是和文本大交道的。
那么,来尝试一个最基础的小问题吧:
1) 创建文件demo.txt
2) 输入"I don't like Emacs."
3) 保存一下
4) 把文本中的"don't"去掉
注意,这时候的光标在行末,编辑后也要把光标移到行末哦。
那么,我们可以有多上中手段来达成这个需且呢:
+ 用<Left>键向左移动光标
+ 用C-b来向左移动光标
+ 先用M-b移动到句首光标
+ 先用C-a来移动到行首
+ 用C-s来根据字符定位光标
+ 用鼠标来移动点击要移动的地方
+ 用bs建向左删除字符
+ 用delete向右删除字符
+ 用C-d向右删除字符
+ 用M-d向右删除单词
+ 用M-%把单词替换为空白
+ 用鼠标拖选单词后删除
+ 在单词一端M-@标记,在另一端C-w剪切
+ 在行首C-k删除行后重输
+ 最后C-移到行末
+ 或者M->移到文末
当然这里这样列举纯粹为了娱乐,况且这些确实是最基本的一些操作。
而且都是很有规律的按键,想必各位都已经对此出于机械反应了吧。
M-空格也很有用
** Outline
这个记号"*"星号,就是用来建立文本层次的,顶格写,后更一个空格。"*"连写则表示是一个子层次。
在层次下面还可以补充的使用"-"、"+"、"*"、"1."、"1)"建立列表,有前后空格,用缩进表示子层次,可"::"后跟描述。
注意要避免发生和前一种方式的混淆,前者是用来组织文档结构的方式。
然后来看一组快捷键:
#+BEGIN_EXAMPLE
折叠显示
TAB Subtree cycling,
S-TAB and C-u TAB Global cycling,
C-u C-u C-u TAB Show all, including drawers.
C-c C-x b 在新缓冲区内显示树
光标的移动
C-c C-n Next heading,
C-c C-p Previous heading,
C-c C-f Next heading same level,
C-c C-b Previous heading same level,
C-c C-u Backward to higher level heading.
编辑
M-RET 创建同层次同类型新项目
M-S-RET 见下文TodoList部分
M-LEFT/RIGHT 改变当前项目的层次
M-S-LEFT/RIGHT 改变项目层次,包括子项目
M-LEFT/M-RIGHT 移动当前项目位置
M-S-UP/DOWN 自动项目位置,包括子项目
C-c C-w 移动项目往某个位置
C-x n s/w 显示当前全部/项目
C-c - 或 S-方向键 改变项目状态
S-<Tab> 改变项目层次
C-c ^ 排序项目列表
C-c * list和tree之间转换
匹配
C-c / sparse tree
#+END_EXAMPLE
在Emacs中Outline也可以做单独的主模式或副模式使用。
有时后为了美观,会使用org-indent-mode。手工调用或#+STARTUP: indent都可以。
此外C-c C-c是个很有常用的按键,其功嫩根据场合,且没有破坏作用。
M-<TAB> 是多种场合下用来补全的快捷键。
这里sparse tree只是+-|&的条件查询
** Rich Text
*** Footnotes
个人比较喜欢的方式是用来做生成文档是用的页脚注释
: [fn:: This is the inline definition of this footnote]
不过一般还是在文本中"C-c C-x f"分开写,然后用利用OM的自动的链接功能,如
: [1] [fn:name]
*** Hyperlinks
用来实现HTML中的超级链接的功能
[[link][description]]
: [[link][description]]
其中[description]可以省略
可用的快捷键有:
: C-c C-l 创建/编辑链接
: C-c C-o 打开链接
: C-c & 返回跳转之前的位置
此外关于link的格式
#+BEGIN_EXAMPLE
[[My Target]] 或自动寻找文档内文本的位置
# <<My Target>> 用注释添加目标
[[*My Targets]] 仅查找项目
<<<My Target>>> 会自动创建指向它的链接
文档内章节引用的指向文字,也通过这样的机制来实现。
也可跨文件查找
[[file:~/code/main.c::255]]
[[file:~/xx.org::My Target]]
[[file:~/xx.org::*My Target]]
[[file:~/xx.org::/regexp/]]
使用URL
file: mailto: 或 http:// 来用不同协议指向本地或远程地址
可用此在插入图像
对于同类链接,可以用#+LINK简写
#+END_EXAMPLE
链接可以直接在Org-Mode中使用,或者在到处为其他格式时有特别的效果。
*** Markup
这一节说说富文本的标记
#+BEGIN_EXAMPLE
默认只用"\\"才表示换行,
不过这个可以该设定为"\n",也就是按实际文本的换行来。

有若干按格式引用文本的话,有方法
用 #+BEGIN_*** 和 #+END_*** 的形式可以
VERSE、QUOTE、CENTER

文字样式
*bold* 粗体
/italic/ 斜体
_underlined_ 下划线
`=code=' 代码
`~verbatim~' 字面的
`+strike-through+' 删除线

水平线用单独一行至少5个"-----"

可以在文本中添加注释
顶格写# 不顶格写#+
用COMMENT开始文本树的标题
结合BEGIN块使用,可以用M-<Tab>方便输入
快捷键 C-c ; 也是照常工作

在文本中插入示例使用
名为EXAMPLE的BEGIN块,或者": "(冒号+空格)开头
插入源代码用SRC块,之后跟参数如"#+BEGIN_SRC emacs-lisp"
编辑源码的快捷键有 C-c ' 和 C-c l
代码块提供参数支持格式或文本内引用的功能
使用参数-t则在HTML中以TextArea来显示

可以插入其他文件中的文本
如 #+INCLUDE: "~/.emacs" src emacs-lisp
这里的第二个参数是块名SRC,按键"C-c '"依然可用
可选参数 “:prefix1 " + " :prefix " " ”为引入内容添加前缀

可以在文本中使用宏
定义: #+MACRO: name replacement text $1, $2 are arguments
插入: {{{name(arg1,arg2)}}}
#+END_EXAMPLE
这段用来一个EXAMPLE块来展示,不过依然建议只在需要的时候再使用,以是文档结构清晰。
*** Tex & LaTex
此项功能用来在文本中插入特殊符号和数学公式,也或者为导出PDF格式做特别的标记。

特殊符号以"\"开始,可以使用补全,如
: \alpha \beta \gamma
将得到 \alpha \beta \gamma
它在HTML和LaTex输出中都可以使用,将分别得到
: &alpha; $\alpha$
{}符号依照Tex做结尾可选的间隔符用

上下标使用类似Tex的语法
: x^{2} a_{1} 10^30
得到 x^{2} a_{1} 10^30

对于特殊输入,都可以用\符号来转回原意

数学公式可以用dvipng程序转为图片,例如供HTML使用
LaTex片段使用\begin或直接插入公式片段
#+BEGIN_EXAMPLE
\begin{equation} % arbitrary environments,
x=\sqrt{b} % even tables, figures
\end{equation} % etc

If $a^2=b$ and \( b=2 \), then the solution must be
either $$ a=+\sqrt{2} $$ or \[ a=-\sqrt{2} \].
(setq org-export-with-LaTeX-fragments t)
#+END_EXAMPLE
可以在编辑模式中`C-c C-x C-l'插入预览效果,`C-c C-c'恢复文本显示
注意$里面不可以有多余的空格,不然直接作为文本识别了。

使用CDLaTeX minor mode可以得到类似AUCTeX的编辑便捷
*** Include
使用 #+INCLUDE: "file.org" 可以引入另一个文本的内容
也可以以块的形式引入,或者 “:prefix " "”为每行添加前缀
: #+INCLUDE: "~/.emacs" src emacs-lisp
也有宏替换的功能
: #+MACRO: name replacement text $1, $2 are arguments
在文本中可以使用】
: {{{name(arg1,arg2)}}}
: {{{title}}}
这里的title是由 #+TITLE: 指定的
*** Image
插入图像的功能,通常用在到处为其他格式时嵌入显示。
关于如何将org文件导出为其他格式的文本,将在下一节里说明。
#+BEGIN_EXAMPLE
插入表格
#+CAPTION: This is the caption for the next table (or link)
#+LABEL: tbl:basic-data
| ... | ...|
|-----|----|

#+CAPTION: This is the caption for the next figure link (or table)
#+LABEL: fig:SED-HR4049
[[./img/a.jpg]]
#+END_EXAMPLE
这里的CAPTION是插入内容的说明文字,而LABEL则是用于文本中的引用。
*** Source Code
导出或执行代码。
** Export & Publish
*** Org2____
功能集中在 "C-c C-e"按键下面,如果此时按键停留一段时间,屏幕上会给出进一步按键的提示。
输入`C-c C-e t'将给当前的文本插入一段输出选项的模板,对此模板的修改是接下来将org文件转换为其他格式的基础,因为很难保证默认的转换规则对当前文本适用。
至于为什么要org-mode的文件转换为其他格式,这个问题是...
如果一点这样的需要也没有的话,那么以下的内容就是在废话了,所以就暂且默认一下吧。
1. org-mode方便文本的编写与管理
2. 有时我们需要在不同场合使用不同分发格式
3. org-mode格式并不适合发布
不过,编写与发布其实是一个连贯的过程,org-mode的使用是一个流程中的一部分。
而不是像这里分出123在列举某一方面的优势和不足的。
*** Option
关于选项模板中的的 #OPTIONS选项,因为不像其他选项那样可以按照名称辨别,所以这里转一下说明:
#BEGIN_EXAMPLE
H: set the number of headline levels for export
num: turn on/off section-numbers
toc: turn on/off table of contents, or set level limit (integer)
\n: turn on/off line-break-preservation
@: turn on/off quoted HTML tags
:: turn on/off fixed-width sections
|: turn on/off tables
^: turn on/off TeX-like syntax for sub- and superscripts. If
you write "^:{}", `a_{b}' will be interpreted, but
the simple `a_b' will be left as it is.
-: turn on/off conversion of special strings.
f: turn on/off footnotes like this[1].
todo: turn on/off inclusion of TODO keywords into exported text
pri: turn on/off priority cookies
tags: turn on/off inclusion of tags, may also be `not-in-toc'
<: turn on/off inclusion of any time/date stamps like DEADLINES
*: turn on/off emphasized text (bold, italic, underlined)
TeX: turn on/off simple TeX macros in plain text
LaTeX: turn on/off LaTeX fragments
skip: turn on/off skipping the text before the first heading
author: turn on/off inclusion of author name/email into exported file
creator: turn on/off inclusion of creator info into exported file
timestamp: turn on/off inclusion creation time into exported file
d: turn on/off inclusion of drawers
#+END_EXAMPLE
关于LaTeX的数学公式的导出方式,在HTML文件中还有更具体的选项,需要参考具体的org-mode版本。
*** ___2what
个人是转为HTML较常用些,转为Text或者LaTeX也是可以的,org-mode还支持其他一些格式。
针对要转为的格式,可以添加一些直接的额外的标记。它们通用的形式如下:
#BEGIN_EXAMPLE
插入单行 #+DOCBOOK:
插入块 #+BEGIN_DOCBOOK
对标记插入 #+ATTR_DOCBOOK
#+END_EXAMPLE
具体一些什么的,之后再来根据遇到的一些实际的情况来补充,所以暂且略过。
*** HTML
1. CSS样式调整
2. JS交互界面
参见http://orgmode.org/Changes.html
*** Latex
1. 配合XeLaTeX使用
2. 关于中文的设置
*** Org
关于直接发布org-mode格式的一些说明
*** Project
到处项目的作用是将一组org文件转换为一个HTML站点
命令依然是以"C-c C-e"开始,不过还是需要提前来做一些配置。
** TodoList
*** GTD
前面貌似说到过,本文的目的并不是关于org怎么用,或者或来说明org-mode有哪些功能。
本文的目的是,如何用org-mode来达成我们需要的一些任务,也就是说想写成CookBook一样的东西。
当然,这只是对文本进行考虑的一个出发点,至于做到没做到就有时另一回事情了。
而且出于自私的想法,写着写着来跑题聊一些轻松的话题也是很有趣的事情。
甚至有时为了写着轻松,留了很多类似“请自行参考文档”一类的话,而让文本的内容常常莫名其妙。
然后,我还会有一个借口,叫什么“本文的目的是导读,而不是作为参考重点用的笔记。”
其实吧,本文也确实不是笔记。笔记什么的是学习时候的记录,用来之后做参考的。
而本文呢,出发点是对自己的使用感受做一下总结,看看对目前自己比较实用的有哪些用法。
好了,org-mode的那么多功能自己也还不都能用好,说成总结是有点牵强了,因为自己对om的使用也毕竟只算个开始。
不过话说会这里的关注点,本文只是恰巧是用om写关于om的话题,更多的机会还是用om写和om无关的东西。
只是om有功能可以让自己的事情完成的更方便一些,对om使用的增加只是会是om的存在感变得降低。
这样来说的话,对org-mode的使用就根本不是在一个学习om的过程之中了。
对于一个工具的使用,会存在两个方面的因素,一是自己能做什么,一是工具能做什么。
虽然这两者必须依赖于自己用工具做了什么,才能够显示出双方的意义,而且双方并不都是永恒不变的东西。
课本上面那种“普遍真理”一类的话,这里不想拿出来说了,因为它总是想用我遇到的例子来说明它的正确性,而不是关注到自己面前所处理的问题上。

这节是叫GTD来着,看来我跑题了。其实这也是一个自私的想法,因为对于一篇没人看的文字,我只好以满足自己的YY来作为优先原则。
话说什么叫GTD呢,它是一种时间管理的方法,很多PIM软件如果知道GTD方面的理论的话,会用起来顺手一些。
自己用的熟悉而是也是唯一的一款PIM软件是MS的OutLook,这是因为我手机上自带的关系。
虽然在新闻讨论中它并不常见,但是它确实功能成熟,而且确实很好用。
它包括了若干组件,比如邮件,日历,任务,便签,联系人,还有其他什么我不清楚的东西。
话说据说其实org-mode还有点像OneNote来着,因为都可以用于记笔记,手机上ON是还可以手写和录音。

不过自己用Org-Mode的话,还是以它的笔记功能为主,对日程方面的很多功能还不熟悉,而且暂时也觉得没有去熟悉它们的必要和动力。
所以这节换题虽然是如何以orgmode去实现任务列表功能,不过还是将继续上面几节的话题的方向。
*** TodoItem & CheckBox
按键 M-S-RET 用来将下方插入,headline对应todo headline,list对应checkbox。
headline可以通过"C-c C-t"或者"S-RIGHT/LEFT"在unmarked和TODO以及DONE状态之间转换,用来标记代办事项。
用"C-c /"来sparse tree时可以显示依照TODO状态来显示部分条目,树状条目的状态存在依赖关系,即子项目的状态是父项目的一部分。
有#+TODO:用于对状态的设定,S-UP/DOWN可以用来改变条目优先级状态。
CheckBox是list前包含[ ]或[x],父条目后包含[%][/]来统计状态。
其中后者对headline也适用,其状态会根据子条目的TODO状态自动改变。
用C-c C-c来改变其选中状态。关于细节在M-S-RET之后就会很明了的。
*** Tags
用:tag:标在headline后面,以方面整理,或添加属性。
相关的按键是"C-c C-c",可以":key1:key2:"使用多个tags。
Properties以k-v的形式实现类似的功能。
*** Dates & Times
"C-c ./!"插入,用S-LEFT/RIGHT/UP/DOWN改变光标位置的状态。
也支持时间范围(A--B)和离散的时间点(如每个...),可插入在headline后与om的其他机制配合。
*** Dict
在org-mode中使用字典,虽然这不是OM自己的功能,不过有实用价值。
** Calendar
出来MS的OutLook,Xfce的Orage也是自己很喜欢的日程类软件,OM的Mobile暂时无条件享用。
不过就目前的自己而言更多还是依赖纸和笔的传统方式,对GTD软件的使用还不大,以下部分从略。
*** Deadlines and scheduling
C-c C-d Insert ‘DEADLINE’
C-c C-s Insert ‘SCHEDULED’
配合TODO有Progress Logging
*** Capture - Refile - Archive
若干特定显示模式,或者项目的管理
其中C-c C-w Refile在文件内移动条目位置还是很有用的功能。
*** Agenda Views
建立文件列表来进行日程管理,以及相应的界面。
可以结合着使用全局的TODO列表。
用"C-c ["加入当前文件
*** Attachment
C-c C-a
** Spreadsheet
在org-mode可以插入表格,或者充当电子表格使用
*** Tbl
在菜单中有Tbl,其中列举了会用到的功能。如果菜单让你费解的话,请看下面的文字。虽然在接下来的使用中没有用到菜单,不过它们涉及的内容是一致的。
*** Tables
| ID | Key | Value |
|----+-------+--------|
| 1 | apple | Red |
| 2 | pear | Yellow |
| 3 | | |
#+TBLFM: $1=0
表格以|开始行或者|-做分割,之后TAB或RET键就可以被识别,C-c-c表示刷新。
表格的行宽会被自动根据内容的长度被调整。
#BEGIN_EXAMPLE
`C-c |' 创建或转化为表格
`M-<left>/<right>' 移动栏
`M-S-<left>' 删除当前栏
`M-S-<right>' 在左边插入栏
`M-<up>/<down>' 移动列
`M-S-<up>' 删除当前列
`M-S-<down>' 在上方插入列
`C-c -/<RET>' 在下方插入水平线
`C-c ^' 排序区域
`C-c C-x M-w' 区域复制
`C-c +' 获得栏的和
`S-<RET>' 自动插入栏
#+END_EXAMPLE
标题<N>指定显示宽度,用`C-c `'编辑。
列有水平线,栏则通过
#BEGIN_EXAMPLE
| / | <> | < | | > | < | > |
| / | < | | | < | |

#+END_EXAMPLE
有minor mode叫orgtbl-mode在其他mode中使用。
还可以结合gnuplot-mode使用。
*** Excel
这里是说那om充当Excel的部分功能,虽然统计分析什么的om并不可用。
引用单元格使用@ROW$COLUMN以及$2..$7,可以绝对数值或+-的相对数值。
然后可结合Calc或Lisp的表达式使用。
:=对当前单元格输入表达式,=为栏输入。
`C-u C-c C-c' `C-u C-u C-c C-c' 执行计算更新
** End
说明一下,虽然本文有好多处是说什么待写啦暂略啦,不过如果有补充的话会另开文的,所以对上面含糊的内容就不必要有期待了。
额,发现一文,比我写得好:
http://linuxtoy.org/archives/emacs-org-mode.html。

* 文本信息 :noexport:
** 笔记
todolist 思维导航 GTD 笔记 发布 日历 xiangmu xelatex
#+TITLE: Django和Org-Mode的若干
#+AUTHOR: ee.zsy
#+EMAIL: ee.zsy@163.com
#+DATE: 2010-11-10 星期三
#+DESCRIPTION:
#+KEYWORDS: django org-mode emacs python
#+LANGUAGE: zh_CN
#+OPTIONS: H:3 num:t toc:t \n:t @:t ::t |:t ^:t -:t f:t *:t <:t
#+OPTIONS: TeX:t LaTeX:nil skip:nil d:nil todo:t pri:nil tags:not-in-toc
#+INFOJS_OPT: view:nil toc:nil ltoc:t mouse:underline buttons:0 path:http://orgmode.org/org-info.js
#+EXPORT_SELECT_TAGS: export
#+EXPORT_EXCLUDE_TAGS: noexport
#+LINK_UP:
#+LINK_HOME: