Archive for 01月, 2008
« Previous Entries放假了,笔记暂缓
星期三, 01月 23rd, 2008放假了,好好过年!笔记就暂缓了!
thinking in java 第六、七章
星期一, 01月 21st, 2008 1.类再生
Java引人注目的一项特性是代码的重复使用或者再生。但最具革命意义的是,除代码的复制和修改以外,我们还能做多得多的其他事情。”
在象C那样的程序化语言里,代码的重复使用早已可行,但效果不是特别显著。与Java的其他地方一样,这个方案解决的也是与类有关的问题。我们通过创建新类来重复使用代码,但却用不着重新创建,可以直接使用别人已建好并调试好的现成类。但这样做必须保证不会干扰原有的代码。
有两个达到这一目标的方法:
(1)在新类里简单地创建原有类的对象。我们把这种方法叫作“合成”,因为新类由现有类的对象合并而成。我们只是简单地重复利用代码的功能,而不是采用它的形式。
(2)创建一个新类,将其作为现有类的一个“类型”。我们可以原样采取现有类的形式,并在其中加入新代码,同时不会对现有的类产生影响。这种魔术般的行为叫作“继承”(Inheritance),涉及的大多数工作都是由编译器完成的
每种非基本类型的对象都有一个toString()方法。若编译器本来希望一个String,但却获得某个这样的对象,就会调用这个方法。所以在下面这个表达式中:
System.out.println(”source = ” + source) ;
编译器会发现我们试图向一个WaterSource添加一个String对象(”source =”)。这对它来说是不可接受的,因为我们只能将一个字串“添加”到另一个字串,所以它会说:“我要调用toString(),把source转换成字串!”经这样处理后,它就能编译两个字串,并将结果字串传递给一个System.out.println()。每次随同自己创建的一个类允许这种行为的时候,都只需要写一个toString()方法。
2.初始化的顺序
我个人的理解是,如果有派生的关系,先从根类开始初始化(其它类都由它派生出来),如果各个类中有static成员,那最初初始化的是static,再从根类开始初始化。而根类的初始化顺序应为先初始化成员,再调用构造函数进行初始化,其派生类也依从这样的顺序。而如果的确要实行清除操作,则先清除最底层的派生类,与初始化顺序刚好相反,这样做的理由时,再清除过程中派生类可能还用到基类的方法。
3.关于多态性
典型的例子如下:
public class PrivateOverride {
//private static Test monitor = new Test();
private void f(String s) {
System.out.println(”private f()”+s);
}
public static void main(String[] args) {
PrivateOverride po = new Derived();
po.f(”哈哈”);
/*monitor.expect(new String[] {
“private f()”
});*/
}
}
class Derived extends PrivateOverride {
private void f(String s) {
System.out.println(”public f()”+s);
[...]
深入浅出MFC-MFC六大关键技术笔记
星期日, 01月 20th, 2008上图为MFC各主要类的关系图
1.RTTI(执行时期类型识别)
以shape 为例,希望达到的技术效果如下,再程序执行期间可以识别对象的类型:
CSquare* pSquare = new CSquare;
cout << pSquare->IsKindOf(CSquare); // 应该获得1(TRUE)
cout << pSquare->IsKindOf(CRect); // 应该获得1(TRUE)
cout << pSquare->IsKindOf(CShape); // 应该获得1(TRUE)
以MFC 的类别阶层来说,希望:
CMyDoc* pMyDoc = new CMyDoc;
cout << pMyDoc->IsKindOf(CMyDoc); // 应该获得1(TRUE)
cout << pMyDoc->IsKindOf(CDocument); // 应该获得1(TRUE)
cout << pMyDoc->IsKindOf(CCmdTarget); // 应该获得1(TRUE)
cout << pMyDoc->IsKindOf(CWnd); // 应该获得0(FALSE)
要达到RTTI 的能力,我们(类别库的设计者)一定要在类别构造起来的时候,记录必要的信息,以建立型录。型录中的类别信息,最好以串行(linked list)方式串接起来,将来方便一一比对。我们这份「类别型录」的串行元素将以CRuntimeClass 描述之,那是一个结构。结构如下:
struct CRuntimeClass
{
// Attributes
LPCSTR m_lpszClassName;
int m_nObjectSize;
UINT m_wSchema; // schema number of the loaded class
CObject* (PASCAL* [...]
看完了深入浅出C++第三章(MFC六大关键技术之模拟),thinking in java第六章的3/4!
星期六, 01月 19th, 2008最近比较累,也晚了,要写的也比较多,就改天补上吧!
thinking in java 第五章 隐藏具体实现
星期五, 01月 18th, 2008进行面向对象的设计时,一项基本的考虑是:如何将发生变化的东西与保持不变的东西分隔开
为解决这个问题,Java推出了“访问指示符”的概念,允许库创建者声明哪些东西是客户程序员可以使用的,哪些是不可使用的。这种访问控制的级别在“最大访问”和“最小访问”的范围之间,分别包括:public,protected,包访问权限(没有关键词),private。
1.库单元
我们用import关键字导入一个完整的库时,就会获得“包”(Package)。例如:
import java.util.*;
之所以要进行这样的导入,是为了提供一种特殊的机制,以便管理“命名空间”(Name Space)。我们所有类成员的名字相互间都会隔离起来。位于类A内的一个方法f()不会与位于类B内的、拥有相同“签名”(自变量列表)的f()发生冲突
若在一个文件的开头使用下述代码:
package mypackage;
那么package语句必须作为文件的第一个非注释语句出现。该语句的作用是指出这个编译单元属于名为mypackage的一个库的一部分。或者换句话说,它表明这个编译单元内的public类名位于mypackage这个名字的下面。如果其他人想使用这个名字,要么指出完整的名字,要么与mypackage联合使用import关键字(使用前面给出的选项)。注意根据Java包(封装)的约定,名字内的所有字母都应小写,甚至那些中间单词亦要如此。
2.创建独一无二的域名
由于一个包永远不会真的“封装”到单独一个文件里面,它可由多个.class文件构成,所以局面可能稍微有些混乱。为避免这个问题,最合理的一种做法就是将某个特定包使用的所有.class文件都置入单个目录里。也就是说,我们要利用操作系统的分级文件结构避免出现混乱局面。这正是Java所采取的方法。
它同时也解决了另两个问题:创建独一无二的包名以及找出那些可能深藏于目录结构某处的类。正如我们在第2章讲述的那样,为达到这个目的,需要将.class文件的位置路径编码到package的名字里。但根据约定,编译器强迫package名的第一部分是类创建者的因特网域名。由于因特网域名肯定是独一无二的(由InterNIC保证——注释②,它控制着域名的分配),所以假如按这一约定行事,package的名称就肯定不会重复,所以永远不会遇到名称冲突的问题。换句话说,除非将自己的域名转让给其他人,而且对方也按照相同的路径名编写Java代码,否则名字的冲突是永远不会出现的。
这个技巧的另一部分是将package名解析成自己机器上的一个目录。这样一来,Java程序运行并需要装载.class文件的时候(这是动态进行的,在程序需要创建属于那个类的一个对象,或者首次访问那个类的一个static成员时),它就可以找到.class文件驻留的那个目录。
Java解释器的工作程序如下:首先,它找到环境变量CLASSPATH(将Java或者具有Java解释能力的工具——如浏览器——安装到机器中时,通过操作系统进行设定)。CLASSPATH包含了一个或多个目录,它们作为一种特殊的“根”使用,从这里展开对.class文件的搜索。从那个根开始,解释器会寻找包名,并将每个点号(句点)替换成一个斜杠,从而生成从CLASSPATH根开始的一个路径名(所以package foo.bar.baz会变成foo\bar\baz或者foo/bar/baz;具体是正斜杠还是反斜杠由操作系统决定)。随后将它们连接到一起,成为CLASSPATH内的各个条目(入口)。以后搜索.class文件时,就可从这些地方开始查找与准备创建的类名对应的名字。此外,它也会搜索一些标准目录——这些目录与Java解释器驻留的地方有关。
对于如下的包名,编译器是这样做的:
package com.bruceeckel.util;
这两个文件都置于我自己系统的一个子目录中:
C:\DOC\JavaT\com\bruceeckel\util
若通过它往回走,就会发现包名com.bruceeckel.util,但路径的第一部分又是什么呢?这是由CLASSPATH环境变量决定的。在我的机器上,它是:
CLASSPATH=.;D:\JAVA\LIB;C:\DOC\JavaT
可以看出,CLASSPATH里能包含大量备用的搜索路径。然而,使用JAR文件时要注意一个问题:必须将JAR文件的名字置于类路径里,而不仅仅是它所在的路径。所以对一个名为grape.jar的JAR文件来说,我们的类路径需要包括:
CLASSPATH=.;D:\JAVA\LIB;C:\flavors\grape.jar
3.包访问权限
如果根本不指定访问指示符,这意味着当前包内的其他所有类都能访问成员,但对包外的所有类来说,这些成员却是“私有”(Private)的,外界不得访问。
为获得对一个访问权限,唯一的方法就是:
(1) 使成员成为“public”(公共的)。这样所有人从任何地方都可以访问它。
(2) 变成一个“友好”成员,方法是舍弃所有访问指示符,并将其类置于相同的包内。这样一来,其他类就可以访问成员。
(3) 正如以后引入“继承”概念后大家会知道的那样,一个继承的类既可以访问一个protected成员,也可以访问一个public成员(但不可访问private成员)。只有在两个类位于相同的包内时,它才可以访问友好成员。但现在不必关心这方面的问题。
(4) 提供“访问器/变化器”方法(亦称为“获取/设置”方法),以便读取和修改值。这是OOP环境中最正规的一种方法,也是Java Beans的基础——具体情况会在第13章介绍。
下面举书上的两段程序加深对包访问权限的理解:
//: Cookie.java
// Creates a library
package c05.dessert;
public class Cookie {
public Cookie() {
System.out.println(”Cookie constructor”);
}
void foo() { System.out.println(”foo”); }
} ///:~
//: Dinner.java
// Uses the library
import c05.dessert.*;
public class Dinner {
public [...]
Linux主要文件学习笔记1
星期三, 01月 16th, 2008字符设备和块设备文件。
字符设备是指设备发送和接收数据以字符的形式进行,没有缓冲;而块设备则以整个数据缓冲区的形式进行。字符设备的驱动相对比较简单。用ls -l 查文件,根据开头的字母可以来判断,以b开头的说明是块设备(如硬盘),以c开头的为字符设备文件(如打印机,终端,/dev/null)
管道设备文件
从字面上理解,管道设备文件就是FIF0文件(先进先出)。管道设备文件从一头流进,从另一头流出。可以用管道文件实现分区的镜像 。用ls -l 命令查,以p开头的就是管道文件。mknod命令可用来建立字符,块,管道设备文件。如
mknod 管道文件名 p
链接文件
linux存在软链接和硬链接
软链接又叫作符号链接,这个文件包含了被链接文件的路径名,可以是任意文件和目录, 可以链接不同文件系统的文件,类似于WINDOWS中的快捷方式,但由不是。链接文件还可以链接不存在的文件,这就产生一个断链的问题。链接文件还可以
链接自己,这就产生了个循环链接的问题,应尽量避免。删除链接文件时,只删除链接文件本身,而不删除文件。可用以下命令创建符号链接:
ln -s 源文件 链接文件
硬链接相当于给已经存在的 文件的别名。硬链接的命令是:
ln -d exsiting file new file
硬链接有两个限制
1.不能给目录文件创建硬链接
2.不能在不同系统文间间创建硬链接
删除硬链接文件的源文件时,只删除文件本身,而不删除硬链接文件,而且还保留了原来的内容。这时系统就忘了它是一个硬链接文件,而把它看成普通文件看待。
thinking in java 第四章 初始化与删除续
星期三, 01月 16th, 20085.非静态实例的初始化
针对每个对象的非静态变量的初始化,它看起来与静态初始化从句极其相似,只是static关键字从里面消失了。为支持对“匿名内部类”的初始化,必须采用这一语法格式。
6.数组初始化
在C中初始化数组极易出错,而且相当麻烦。C++通过“集合初始化”使其更安全。Java则没有象C++那样的“集合”概念,因为Java中的所有东西都是对象。但它确实有自己的数组,通过数组初始化来提供支持。
数组代表一系列对象或者基本数据类型,所有相同的类型都封装到一起——采用一个统一的标识符名称。数组的定义和使用是通过方括号索引运算符进行的([])。为定义一个数组,只需在类型名后简单地跟随一对空方括号即可:
int[] al;
也可以将方括号置于标识符后面,获得完全一致的结果:
int al[];
基本数据类型的数组元素会自动初始化成“空”值(对于数值,空值就是零;对于char,它是null;而对于boolean,它却是false)。若操作的是一个非基本类型对象的数组,那么无论如何都要使用new,而且应该如下样式赋值,
Integer[] a = new Integer[pRand(20)];
prt(”length of a = ” + a.length);
for(int i = 0; i < a.length; i++) {
a[i] = new Integer(pRand(500));
prt(”a[" + i + "] = ” + a[i]);
}
7.多维数组的赋值
int[][][] a3 = new int[pRand(7)][][];
for(int i = 0; i < a3.length; i++) {
a3[i] = new int[pRand(5)][];
for(int j = 0; j < a3[i].length; j++)
a3[i][j] = [...]
thinking in java 第四章 初始化与删除
星期三, 01月 16th, 20081.以构造器(constructor)确保初始化
2.方法重载(method overloading)
每个重载的方法都有一个独一无二的参数列表。重载的方法就靠不同的参数列表来区分。以返回值是不能区分重载的方法的,以参数的顺序来区分不同的重载方法也是不可取的,容易导致代码混乱,不可维护。
3.缺省构造器(无参构造器)
如果没有写构造器,编译器会自动为程序生成一个构造器。如果你写了构造器,编译器 将不在为程序自动生成一个编译器。构造器里调用构造器,可以通过this实现。但在构造器里只能调用一次构造器,且只能放在最前处。ge collection
4.清除(clean up),终结(finalization),垃圾回收(garbage collection)
有时可能发现一个对象的存储空间永远都不会释放,因为自己的程序永远都接近于用光空间的临界点。若程序执行结束,而且垃圾收集器一直都没有释放我们创建的任何对象的存储空间,则随着程序的退出,那些资源会返回给操作系统。这是一件好事情,因为垃圾收集本身也要消耗一些开销。如永远都不用它,那么永远也不用支出这部分开销。
垃圾收集并不等于“破坏”!
若能时刻牢记这一点,踩到陷阱的可能性就会大大减少。它意味着在我们不再需要一个对象之前,有些行动是必须采取的,而且必须由自己来采取这些行动。Java并未提供“破坏器”或者类似的概念,所以必须创建一个原始的方法,用它来进行这种清除。例如,假设在对象创建过程中,它会将自己描绘到屏幕上。如果不从屏幕明确删除它的图像,那么它可能永远都不会被清除。若在finalize()里置入某种删除机制,那么假设对象被当作垃圾收掉了,图像首先会将自身从屏幕上移去。但若未被收掉,图像就会保留下来。所以要记住的第二个重点是:
我们的对象可能不会当作垃圾被收掉!
垃圾收集只跟内存有关!
垃圾收集器存在的唯一原因是为了回收程序不再使用的内存。所以对于与垃圾收集有关的任何活动来说,其中最值得注意的是finalize()方法,它们也必须同内存以及它的回收有关。
但这是否意味着假如对象包含了其他对象,finalize()就应该明确释放那些对象呢?答案是否定的——垃圾收集器会负责释放所有对象占据的内存,无论这些对象是如何创建的。它将对finalize()的需求限制到特殊的情况。在这种情况下,我们的对象可采用与创建对象时不同的方法分配一些存储空间。但大家或许会注意到,Java中的所有东西都是对象,所以这到底是怎么一回事呢?
之所以要使用finalize(),看起来似乎是由于有时需要采取与Java的普通方法不同的一种方法,通过分配内存来做一些具有C风格的事情。这主要可以通过“固有方法”来进行,它是从Java里调用非Java方法的一种方式(固有方法的问题在附录A讨论)。C和C++是目前唯一获得固有方法支持的语言。但由于它们能调用通过其他语言编写的子程序,所以能够有效地调用任何东西。在非Java代码内部,也许能调用C的malloc()系列函数,用它分配存储空间。而且除非调用了free(),否则存储空间不会得到释放,从而造成内存“漏洞”的出现。当然,free()是一个C和C++函数,所以我们需要在finalize()内部的一个固有方法中调用它。
5.成员初始化
一个类的所有基本类型数据成员都会保证获得一个初始值。
在一个类的内部定义一个对象句柄时,如果不将其初始化成新对象,那个句柄就会获得一个空值。
6.构造器初始化
可以在运行期调用方法和采取行动,从而“现场”决定初始化值。但要注意这样一件事情:不可妨碍自动初始化的进行。
对于所有基本类型以及对象句柄,这种情况都是成立的。
7.初始化顺序
在一个类里,初始化的顺序是由变量在类内的定义顺序决定的。即使变量定义大量遍布于方法定义的中间,那些变量仍会在调用任何方法之前得到初始化——甚至在构造器调用之前。
8.静态数据的初始化
若数据是静态的(static),那么同样的事情就会发生;如果它属于一个基本类型(主类型),而且未对其初始化,就会自动获得自己的标准基本类型初始值;如果它是指向一个对象的句柄,那么除非新建一个对象,并将句柄同它连接起来,否则就会得到一个空值(NULL)。
9.初始化顺序的总结
初始化的顺序是首先static(如果它们尚未由前一次对象创建过程初始化),接着是非static对象。大家可从输出结果中找到相应的证据。
在这里有必要总结一下对象的创建过程。请考虑一个名为Dog的类:
(1) 类型为Dog的一个对象首次创建时,或者Dog类的static方法/static字段首次访问时,Java解释器必须找到Dog.class(在事先设好的类路径里搜索)。
(2) 找到Dog.class后(它会创建一个Class对象,这将在后面学到),它的所有static初始化模块都会运行。因此,static初始化仅发生一次——在Class对象首次载入的时候。
(3) 创建一个new Dog()时,Dog对象的构建进程首先会在内存堆(Heap)里为一个Dog对象分配足够多的存储空间。
(4) 这种存储空间会清为零,将Dog中的所有基本类型设为它们的默认值(零用于数字,以及boolean和char的等价设定)。
(5) 进行字段定义时发生的所有初始化都会执行。
(6) 执行构建器。
10.非静态实例初始化
还没有看,明天总结。
linux实用培训教程笔记1(by 红联)
星期一, 01月 14th, 20081.linux的7个运行级别
LINUX系统中,共有7个运行级别,含义如下:
0 停机。不要把系统的默认级别设置为0,否则系统不能正常启动。
1 但用户模式。用于root用户对系统进行维护,不允许其他用户使用主机。
2 多用户模式。在该模式下不能使用NFS。
3 完全多用户模式。主机作为服务器时通常在该模式下。
4 未分配使用。
5 图形登陆的多用户模式。用户在该模式下可以进行图形界面的登陆。
6 重新启动。不要把系统的默认级别设置为6,否则不能正常启动。
2.Linux的命令组成
Linux命令组成:shell内部命令+shell外部命令
shell内部命令:最简单最常用的命令,在shell启动时进入内存
shell外部命令:独立的可执行程序。是一些使用工具程序
3.Shell命令基本规则
Shell命令的一般格式如下:命令名【选项】【参数1】【参数2】…【选项】是对命令的特别定义,以减
号(-)开始,多个选项可以用一个减号(-)连起来,如ls -l -a 与ls -la 相同。【参数】提供命令运行的信息,或者是
命令执行过程中所使用的文件名。
使用分号(;)可以将两个命令隔开,这样可以实现一行中输入多个命令。命令的执行顺序和输入的顺序相同
。
4. 常用的Shell命令-目录和文件操作
重命名文件
mv [源文件名] [目标文件名]
例:mv /etc/rc.d/rc3.d/K50xinetd /etc/rc.d/rc3.d/S50xinetd
删除文件
rm [文件名]
不需确认地删除多个文件
rm -f [带通配符的文件名]
硬链接文件。不能对目录文件做硬链接,不能在不同的文件系统之间做硬链接。
ln [源文件名] [目标文件名]
例:mv /etc/rc.d/rc3.d/K50xinetd /etc/rc.d/rc3.d/S50xinetd
软链接文件。也就是符号链接。可用此法创建文件的快捷方式。
ln -s [源文件或文件夹名] [目标名]
按文件名查找文件。
find / -name nametofind -print
改变文件所有者。
例:chown workman:workgroup 文件名
改变文件访问权限
例:chmod -R 755 /usr/local/LumaQQ
查看一个文件有多少行
wc -l usr.bin
查看一个文件有多少字节
wc -c usr.bin
查看文本文件的内容
cat usr.bin
空
5 .管道
将一个程序的标准输出写道一个文件中去,再将这个文件的内容作为另一个命令的标准输入,等效于通过
临时文件将两个命令结合起来。这种情况很普遍,需要Linux系统提供一种功能:它不需要或不必使用临时文件
,就能将两条命令结合在一起。这种功能就是管道。管道的操作符是一个竖杠“|”。管道是可以嵌套使用的,
因此可以把多个命令结合在一起。接上例,如果执行下面的命令将直接返回/usr/bin 中的文件列表的行数,而不
是列表的内容。
ls /usr/bin | wc -l
6.命令补全
在送入命令的任何时刻,可以按<Tab>键,当这样做时,系统将试图补全此时已输入的命令。如果已经输
入的字符串不足以唯一地确定它应该使用的命令,系统将发出警告声。再次按<Tab>键,系统则会给出可用来
用来补全的字符串清单。使用命令补全功能,可以提高使用长命令或操作较长名字的文件或文件夹的都是非常
有意义的。
7.启动与关闭shell(现在终于知道怎么回到图形界面了!)
在启动Linux桌面系统后,Shell已经在后台运行起来了,但并没有显示出来。如果想让它显示出来,按如下
的组合键就可以:<Ctrl> + <Alt> + <F2>组合键中的F2可以替换为F3、F4、F5、F6。如果要回到图形界面,则按
如下组合键:<Ctrl> + <Alt> + [...]
thinking in java 第三章-程序控制流
星期日, 01月 13th, 2008今天终于顺利的完成了thinking in java第三章,看了位操作符,移位操作符,三元操作符,逗号操作符,字符操作符,此外讨论了使用操作符时程序员易犯的错误,对于while等控制语句,由于在java里只能用boolean来比较,而不像C或C++那样可以拿数值量来当boolean,这样有效的避免了类似while(x=y),while(x|y)等错误的发生。在java中c++中sizeof,因为sizeof是考虑c的移植问题而产生的,不同的机子数据类型的存储位数可能不一样,但java没有这个问题,也就不需要了。另外一个比较有意思的地方是,java使用了标签,类似于goto语句,但java中的标签主要用来跳出多重循环,有严格的限制。此外文章里总结了操作符的使用,给出了个很好的总结各种基本数据类型使用的程序。提到了优先级。总体今天比较轻松。
« Previous Entries