发布新日志

  • HEAD IN DESIGN PATTERNS第一章读书笔记

    2007-06-22 16:54:42

        学习了《深入浅出DESIGN PATTERNS》的第一章,关于设计模式方面暂时不表,感觉还没有完全参透,单表一表这章的例子程序。这篇笔记主要是针对C++和JAVA的编程比较的。

        JAVA和C++都学过,但是都是简单的学习,并且长时间没有接触了,很多概念都模糊了,并且两种语言很容易混淆。如果习惯了其中一种的语法,转到另一种时总有种似是而非的感觉。

        这章的例子程序是一个MiniDuckSimulator的程序,书中是用JAVA实现的(DESIGN PATTERN里面的原理似乎通常都是用JAVA,我的理解是因为和C++比较起来JAVA的面向对象更纯粹)。首先是一个absract class Duck,它包含一个抽象方法diaplay(),以及两个interface类型的成员变量flybehavīor和quackbehavīor,使用这两个interface的原因是:并不是所有的Duck都能fly或者quack,所以必须把这两种方法从Duck类中分离出来;但是由于JAVA不支持多重继承,因此这两个抽象行为就抽象成了两个interface,每一种具体的fly行为和quack行为都实现为一个具体的类,并且实现上述接口。具体的Duck如MallardDuck继承了Duck类,并且把flybehavīor和quackbehavīor这两个接口类变量具体化为Quack类和FlyWithWings类。这样Duck类通过performFly()方法和performQuack()方法把fly行为和quack行为delegate给了flybehavīor和quackbehavīor,最终由实际的Flybehavīor和Quackbehavīor类成员变量完成这两个方法。

        程序很简单,但是把它转化为C++时还是遇到了一些问题。

        首先是Duck类中的flybehavīor和quackbehavīor这两个成员变量,在JAVA中通过接口类执行fly()方法和quack()方法,都是运行时按照对象的实际类型执行对应的方法;而在C++中,只有通过基类指针或引用间接指向派生类子类型时,多态性才会发生作用。并且在C++中,构造函数返回的是一个指针,因此flybehavīor和quackbehavīor这两个成员变量应修改为指针类型的p_flybehavīor和p_quackbehavīor。

        其次是Flybehavīor类中的fly()方法和Quackbehavīor类中的quack()方法,在JAVA实现中它们是interface中的方法,默认为abstract的,要达到相同的语义,在C++中就要用纯虚函数来实现。这样Flybehavīor类和Quackbehavīor类也就成为抽象基类;另外在JAVA实现中,Duck类的diaplay()方法是一个抽象方法,在C++中用纯虚函数实现,因此Duck类也是一个抽象基类。(这样可以看到JAVA里的abstract class和interface在JAVA中的相同语义实现都是抽象基类)。

        此外,在JAVA类中没有显式声明访问控制符的成员变量默认是友元型的,即同一个包中的类和自身可以访问,如果子类不与该基类在同一个包内,则也不能访问这些成员变量。在这个例子中,因为Duck类和MallardDuck类在同一个包下,因此MallardDuck可以访问成员变量flybehavīor和quackbehavīor;而在C++中没有显式声明访问控制符的成员变量默认是private的,因此需要把p_flybehavīor和p_quackbehavīor显式的声明为protected。

        无论是JAVA的abstrace class中的abstract 方法还是C++抽象基类中的纯虚函数,在具体的子类(非抽象类)中都必须实现。此外还需要注意C++中为了避免重复包含,头文件中应使用宏定义等。

        限于本人水平,上面的内容还请指正。

     

  • [转]JAVA和C++区别

    2007-06-22 11:27:51

    1.指针

    JAVA语言让编程者无法找到指针来直接访问内存无指针,并且增添了自动的内存管理功能,从而有效地防止了c/c++语言中指针操作失误,如野指针所造成的系统崩溃。但也不是说JAVA没有指针,虚拟机内部还是使用了指针,只是外人不得使用而已。这有利于Java程序的安全。

    2.多重继承

    c++支持多重继承,这是c++的一个特征,它允许多父类派生一个类。尽管多重继承功能很强,但使用复杂,而且会引起许多麻烦,编译程序实现它也很不容易。Java不支持多重继承,但允许一个类继承多个接口(extends+implement),实现了c++多重继承的功能,又避免了c++中的多重继承实现方式带来的诸多不便。

    3.数据类型及类

    Java是完全面向对象的语言,所有函数和变量部必须是类的一部分。除了基本数据类型之外,其余的都作为类对象,包括数组。对象将数据和方法结合起来,把它们封装在类中,这样每个对象都可实现自己的特点和行为。而c++允许将函数和变量定义为全局的。此外,Java中取消了c/c++中的结构和联合,消除了不必要的麻烦。

    4.自动内存管理

    Java程序中所有的对象都是用new操作符建立在内存堆栈上,这个操作符类似于c++的new操作符。下面的语句由一个建立了一个类Read的对象,然后调用该对象的work方法:

    Readr=newRead();

    r.work();

    语句Readr=newRead();在堆栈结构上建立了一个Read的实例。Java自动进行无用内存回收操作,不需要程序员进行删除。而c十十中必须由程序贝释放内存资源,增加了程序设计者的负扔。Java中当一个对象不被再用到时,无用内存回收器将给它加上标签以示删除。JAVA里无用内存回收程序是以线程方式在后台运行的,利用空闲时间工作。

    5.操作符重载

    Java不支持操作符重载。操作符重载被认为是c十十的突出特征,在Java中虽然类大体上可以实现这样的功能,但操作符重载的方便性仍然丢失了不少。Java语言不支持操作符重载是为了保持Java语言尽可能简单。

    6.预处理功能

    Java不支持预处理功能。c/c十十在编译过程中都有一个预编泽阶段,即众所周知的预处理器。预处理器为开发人员提供了方便,但增加丁编译的复杂性。JAVA虚拟机没有预处理器,但它提供的引入语句(import)与c十十预处理器的功能类似。

    7.Java不支持缺省函数参数,而c十十支持

    在c中,代码组织在函数中,函数可以访问程序的全局变量。c十十增加了类,提供了类算法,该算法是与类相连的函数,c十十类方法与Java类方法十分相似,然而,由于c十十仍然支持c,所以不能阻止c十十开发人员使用函数,结果函数和方法混合使用使得程序比较混乱。

    Java没有函数,作为一个比c十十更纯的面向对象的语言,Java强迫开发人员把所有例行程序包括在类中,事实上,用方法实现例行程序可激励开发人员更好地组织编码。

    8字符串

    c和c十十不支持字符串变量,在c和c十十程序中使用Null终止符代表字符串的结束,在Java中字符串是用类对象(strinR和stringBuffer)来实现的,这些类对象是Java语言的核心,用类对象实现字符串有以下几个优点:

    (1)在整个系统中建立字符串和访问字符串元素的方法是一致的;

    (2)J3阳字符串类是作为Java语言的一部分定义的,而不是作为外加的延伸部分;

    (3)Java字符串执行运行时检空,可帮助排除一些运行时发生的错误;

    (4)可对字符串用“十”进行连接操作。

    9“goto语句

    “可怕”的goto语句是c和c++的“遗物”,它是该语言技术上的合法部分,引用goto语句引起了程序结构的混乱,不易理解,goto语句子要用于无条件转移子程序和多结构分支技术。鉴于以广理由,Java不提供goto语句,它虽然指定goto作为关键字,但不支持它的使用,使程序简洁易读。

    l0.类型转换

    在c和c十十中有时出现数据类型的隐含转换,这就涉及了自动强制类型转换问题。例如,在c十十中可将一浮点值赋予整型变量,并去掉其尾数。Java不支持c十十中的自动强制类型转换,如果需要,必须由程序显式进行强制类型转换。

    11.异常

    JAVA中的异常机制用于捕获例外事件,增强系统容错能力

    try{//可能产生例外的代码

    }catch(exceptionTypename){

    //处理

    }

  • [转]JAVA:深入理解abstract class和interface

    2007-06-22 11:06:08

    abstract class和interface是Java语言中对于抽象类定义进行支持的两种机制,正是由于这两种机制的存在,才赋予了Java强大的面向对象能力。abstract class和interface之间在对于抽象类定义的支持方面具有很大的相似性,甚至可以相互替换,因此很多开发者在进行抽象类定义时对于abstract class和interface的选择显得比较随意。其实,两者之间还是有很大的区别的,对于它们的选择甚至反映出对于问题领域本质的理解、对于设计意图的理解是否正确、合理。本文将对它们之间的区别进行一番剖析,试图给开发者提供一个在二者之间进行选择的依据。 

    理解抽象类 

    abstract class和interface在Java语言中都是用来进行抽象类(本文中的抽象类并非从abstract class翻译而来,它表示的是一个抽象体,而abstract class为Java语言中用于定义抽象类的一种方法,请读者注意区分)定义的,那么什么是抽象类,使用抽象类能为我们带来什么好处呢? 

    在面向对象的概念中,我们知道所有的对象都是通过类来描绘的,但是反过来却不是这样。并不是所有的类都是用来描绘对象的,如果一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类。抽象类往往用来表征我们在对问题领域进行分析、设计中得出的抽象概念,是对一系列看上去不同,但是本质上相同的具体概念的抽象。比如:如果我们进行一个图形编辑软件的开发,就会发现问题领域存在着圆、三角形这样一些具体概念,它们是不同的,但是它们又都属于形状这样一个概念,形状这个概念在问题领域是不存在的,它就是一个抽象概念。正是因为抽象的概念在问题领域没有对应的具体概念,所以用以表征抽象概念的抽象类是不能够实例化的。 

    在面向对象领域,抽象类主要用来进行类型隐藏。我们可以构造出一个固定的一组行为的抽象描述,但是这组行为却能够有任意个可能的具体实现方式。这个抽象描述就是抽象类,而这一组任意个可能的具体实现则表现为所有可能的派生类。模块可以操作一个抽象体。由于模块依赖于一个固定的抽象体,因此它可以是不允许修改的;同时,通过从这个抽象体派生,也可扩展此模块的行为功能。熟悉OCP的读者一定知道,为了能够实现面向对象设计的一个最核心的原则OCP(Open-Closed Principle),抽象类是其中的关键所在。 


    从语法定义层面看abstract class和interface 

    在语法层面,Java语言对于abstract class和interface给出了不同的定义方式,下面以定义一个名为Demo的抽象类为例来说明这种不同。 

    使用abstract class的方式定义Demo抽象类的方式如下: 

    abstract class Demo { 
     abstract void method1(); 
     abstract void method2(); 
     … 
    } 

    使用interface的方式定义Demo抽象类的方式如下: 

    interface Demo { 
     void method1(); 
     void method2(); 
     … 


    在abstract class方式中,Demo可以有自己的数据成员,也可以有非abstarct的成员方法,而在interface方式的实现中,Demo只能够有静态的不能被修改的数据成员(也就是必须是static final的,不过在interface中一般不定义数据成员),所有的成员方法都是abstract的。从某种意义上说,interface是一种特殊形式的abstract class。 

          从编程的角度来看,abstract class和interface都可以用来实现"design by contract"的思想。但是在具体的使用上面还是有一些区别的。 

    首先,abstract class在Java语言中表示的是一种继承关系,一个类只能使用一次继承关系。但是,一个类却可以实现多个interface。也许,这是Java语言的设计者在考虑Java对于多重继承的支持方面的一种折中考虑吧。 

    其次,在abstract class的定义中,我们可以赋予方法的默认行为。但是在interface的定义中,方法却不能拥有默认行为,为了绕过这个限制,必须使用委托,但是这会 增加一些复杂性,有时会造成很大的麻烦。 

    在抽象类中不能定义默认行为还存在另一个比较严重的问题,那就是可能会造成维护上的麻烦。因为如果后来想修改类的界面(一般通过abstract class或者interface来表示)以适应新的情况(比如,添加新的方法或者给已用的方法中添加新的参数)时,就会非常的麻烦,可能要花费很多的时间(对于派生类很多的情况,尤为如此)。但是如果界面是通过abstract class来实现的,那么可能就只需要修改定义在abstract class中的默认行为就可以了。 

    同样,如果不能在抽象类中定义默认行为,就会导致同样的方法实现出现在该抽象类的每一个派生类中,违反了"one rule,one place"原则,造成代码重复,同样不利于以后的维护。因此,在abstract class和interface间进行选择时要非常的小心。 


    从设计理念层面看abstract class和interface 

    上面主要从语法定义和编程的角度论述了abstract class和interface的区别,这些层面的区别是比较低层次的、非本质的。本小节将从另一个层面:abstract class和interface所反映出的设计理念,来分析一下二者的区别。作者认为,从这个层面进行分析才能理解二者概念的本质所在。 

    前面已经提到过,abstarct class在Java语言中体现了一种继承关系,要想使得继承关系合理,父类和派生类之间必须存在"is a"关系,即父类和派生类在概念本质上应该是相同的(参考文献〔3〕中有关于"is a"关系的大篇幅深入的论述,有兴趣的读者可以参考)。对于interface 来说则不然,并不要求interface的实现者和interface定义在概念本质上是一致的,仅仅是实现了interface定义的契约而已。为了使论述便于理解,下面将通过一个简单的实例进行说明。 

    考虑这样一个例子,假设在我们的问题领域中有一个关于Door的抽象概念,该Door具有执行两个动作open和close,此时我们可以通过abstract class或者interface来定义一个表示该抽象概念的类型,定义方式分别如下所示: 

    使用abstract class方式定义Door: 

    abstract class Door { 
     abstract void open(); 
     abstract void close(); 


      
    使用interface方式定义Door: 


    interface Door { 
     void open(); 
     void close(); 


      
    其他具体的Door类型可以extends使用abstract class方式定义的Door或者implements使用interface方式定义的Door。看起来好像使用abstract class和interface没有大的区别。 

    如果现在要求Door还要具有报警的功能。我们该如何设计针对该例子的类结构呢(在本例中,主要是为了展示abstract class和interface反映在设计理念上的区别,其他方面无关的问题都做了简化或者忽略)?下面将罗列出可能的解决方案,并从设计理念层面对这些不同的方案进行分析。 

    解决方案一: 

    简单的在Door的定义中增加一个alarm方法,如下: 

    abstract class Door { 
     abstract void open(); 
     abstract void close(); 
     abstract void alarm(); 


      
    或者 

    interface Door { 
     void open(); 
     void close(); 
     void alarm(); 


      
    那么具有报警功能的AlarmDoor的定义方式如下: 

    class AlarmDoor extends Door { 
     void open() { … } 
     void close() { … } 
     void alarm() { … } 


      
    或者 

    class AlarmDoor implements Door { 
     void open() { … } 
     void close() { … } 
     void alarm() { … } 
    } 

    这种方法违反了面向对象设计中的一个核心原则ISP(Interface Segregation Priciple),在Door的定义中把Door概念本身固有的行为方法和另外一个概念"报警器"的行为方法混在了一起。这样引起的一个问题是那些仅仅依赖于Door这个概念的模块会因为"报警器"这个概念的改变(比如:修改alarm方法的参数)而改变,反之依然。 

    解决方案二: 

    既然open、close和alarm属于两个不同的概念,根据ISP原则应该把它们分别定义在代表这两个概念的抽象类中。定义方式有:这两个概念都使用abstract class方式定义;两个概念都使用interface方式定义;一个概念使用abstract class方式定义,另一个概念使用interface方式定义。 

    显然,由于Java语言不支持多重继承,所以两个概念都使用abstract class方式定义是不可行的。后面两种方式都是可行的,但是对于它们的选择却反映出对于问题领域中的概念本质的理解、对于设计意图的反映是否正确、合理。我们一一来分析、说明。 

    如果两个概念都使用interface方式来定义,那么就反映出两个问题:1、我们可能没有理解清楚问题领域,AlarmDoor在概念本质上到底是Door还是报警器?2、如果我们对于问题领域的理解没有问题,比如:我们通过对于问题领域的分析发现AlarmDoor在概念本质上和Door是一致的,那么我们在实现时就没有能够正确的揭示我们的设计意图,因为在这两个概念的定义上(均使用interface方式定义)反映不出上述含义。 

    如果我们对于问题领域的理解是:AlarmDoor在概念本质上是Door,同时它有具有报警的功能。我们该如何来设计、实现来明确的反映出我们的意思呢?前面已经说过,abstract class在Java语言中表示一种继承关系,而继承关系在本质上是"is a"关系。所以对于Door这个概念,我们应该使用abstarct class方式来定义。另外,AlarmDoor又具有报警功能,说明它又能够完成报警概念中定义的行为,所以报警概念可以通过interface方式定义。如下所示: 

    abstract class Door { 
     abstract void open(); 
     abstract void close(); 

    interface Alarm { 
     void alarm(); 

    class AlarmDoor extends Door implements Alarm { 
     void open() { … } 
     void close() { … } 
        void alarm() { … } 


      
    这种实现方式基本上能够明确的反映出我们对于问题领域的理解,正确的揭示我们的设计意图。其实abstract class表示的是"is a"关系,interface表示的是"like a"关系,大家在选择时可以作为一个依据,当然这是建立在对问题领域的理解上的,比如:如果我们认为AlarmDoor在概念本质上是报警器,同时又具有Door的功能,那么上述的定义方式就要反过来了。 



    结论 

    abstract class和interface是Java语言中的两种定义抽象类的方式,它们之间有很大的相似性。但是对于它们的选择却又往往反映出对于问题领域中的概念本质的理解、对于设计意图的反映是否正确、合理,因为它们表现了概念间的不同的关系(虽然都能够实现需求的功能)。这其实也是语言的一种的惯用法,希望读者朋友能够细细体会。

    其他地方摘抄的:

    abstract class和interface有什么区别?
      声明方法的存在而不去实现它的类被叫做抽象类(abstract class),它用于要创建一个体现某些基本行为的类,并为该类声明方法,但不能在该类中实现该类的情况。不能创建abstract 类的实例。然而可以创建一个变量,其类型是一个抽象类,并让它指向具体子类的一个实例。不能有抽象构造函数或抽象静态方法。Abstract 类的子类为它们父类中的所有抽象方法提供实现,否则它们也是抽象类为。取而代之,在子类中实现该方法。知道其行为的其它类可以在类中实现这些方法。
      接口(interface)是抽象类的变体。在接口中,所有方法都是抽象的。多继承性可通过实现这样的接口而获得。接口中的所有方法都是抽象的,没有一个有程序体。接口只可以定义static final成员变量。接口的实现与子类相似,除了该实现类不能从接口定义中继承行为。当类实现特殊接口时,它定义(即将程序体给予)所有这种接口的方法。然后,它可以在实现了该接口的类的任何对象上调用接口的方法。由于有抽象类,它允许使用接口名作为引用变量的类型。通常的动态联编将生效。引用可以转换到接口类型或从接口类型转换,instanceof 运算符可以用来决定某对象的类是否实现了接口。

  • JAVA面试题

    2007-06-21 20:23:24

    1.抽象类与接口?
    答:抽象类与接口都用于抽象,但是抽象类(JAVA)可以有自己的部分实现,而接口则完全是一个标识(同时有多重继承的功能)

    2STRINGSTRINGBUFFER的区别。
    答:STRING的长度是不可变的,STRINGBUFFER的长度是可变的。如果你对字符串中的内容经常进行操作,特别是内容要修改时,那么使用StringBuffer,如果最后需要String,那么使用StringBuffertoString()方法

    3jsp有哪些内置对象?作用分别是什么?
    :JSP共有以下9种基本内置组件(可与ASP6种内部组件相对应):
     request 用户端请求,此请求会包含来自GET/POST请求的参数
    response
    网页传回用户端的回应
    pageContext
    网页的属性是在这里管理
    session
    与请求有关的会话期
    application servlet
    正在执行的内容
    out
    用来传送回应的输出
    config servlet
    的构架部件
    page JSP
    网页本身
    exception
    针对错误网页,未捕捉的例外

    4jsp有哪些动作?作用分别是什么?
    :JSP共有以下6种基本动作
    jsp:include
    :在页面被请求的时候引入一个文件。
    jsp:useBean
    :寻找或者实例化一个JavaBean
    jsp:setProperty
    :设置JavaBean的属性。
    jsp:getProperty
    :输出某个JavaBean的属性。
    jsp:forward
    :把请求转到一个新的页面。
    jsp:plugin
    :根据浏览器类型为Java插件生成OBJECTEMBED标记

    5、JSP中动态INCLUDE与静态INCLUDE的区别?
    答:动态INCLUDEjsp:include动作实现
    <jsp:include page="included.jsp" flush="true" />
    它总是会检查所含文件中的变化,适合用于包含动态页面,并且可以带参数
    静态INCLUDEinclude伪码实现,定不会检查所含文件的变化,适用于包含静态页面
    <%@ include file="included.htm" %>

    6
    、两种跳转方式分别是什么?有什么区别?
    答:有两种,分别为:
    <jsp:include page="included.jsp" flush="true">
    <jsp:forward page= "nextpage.jsp"/>
    前者页面不会转向include所指的页面,只是显示该页的结果,主页面还是原来的页面。执行完后还会回来,相当于函数调用。并且可以带参数.后者完全转向新页面,不会再回来。相当于go to 语句。

    7、说一说Servlet的生命周期?
    :servlet有良好的生存期的定义,包括加载和实例化、初始化、处理请求以及服务结束。这个生存期由javax.servlet.Servlet接口的init,servicedestroy方法表达。

    8JAVA SERVLET APIforward() redirect()的区别?
    :前者仅是容器中控制权的转向,在客户端浏览器地址栏中不会显示出转向后的地址;后者则是完全的跳转,浏览器将会得到跳转的地址,并重新发送请求链接。这样,从浏览器的地址栏中可以看到跳转后的链接地址。所以,前者更加高效,在前者可以满足需要时,尽量使用forward()方法,并且,这样也有助于隐藏实际的链接。在有些情况下,比如,需要跳转到一个其它服务器上的资源,则必须使用sendRedirect()方法。

    9
    Servlet的基本架构
    public class ServletName extends HttpServlet {
    public void doPost(HttpServletRequest request, HttpServletResponse response) throws
    ServletException, IOException {
    }
    public void doGet(HttpServletRequest request, HttpServletResponse response) throws
    ServletException, IOException {
    }
    }

    10EJBJAVA BEAN的区别?
    :Java Bean 是可复用的组件,对Java Bean并没有严格的规范,理论上讲,任何一个Java类都可以是一个Bean。但通常情况下,由于Java Bean是被容器所创建(如Tomcat)的,所以Java Bean应具有一个无参的构造器,另外,通常Java Bean还要实现Serializable接口用于实现Bean的持久性。Java Bean实际上相当于微软COM模型中的本地进程内COM组件,它是不能被跨进程访问的。Enterprise Java Bean 相当于DCOM,即分布式组件。它是基于Java的远程方法调用(RMI)技术的,所以EJB可以被远程访问(跨进程、跨计算机)。但EJB必须被布署在诸如WebspereWebLogic这样的容器中,EJB客户从不直接访问真正的EJB组件,而是通过其容器访问。EJB容器是EJB组件的代理,EJB组件由容器所创建和管理。客户通过容器来访问真正的EJB组件。

    11MVC的各个部分都有那些技术来实现?如何实现?
    :MVCModelViewController的简写。"Model" 代表的是应用的业务逻辑(通过JavaBeanEJB组件实现), "View" 是应用的表示面(由JSP页面产生),"Controller" 是提供应用的处理过程控制(一般是一个Servlet),通过这种设计模型把应用逻辑,处理过程和显示逻辑分成不同的组件实现。这些组件可以进行交互和重用。

    12J2EE是什么?
    :Je22Sun公司提出的多层(multi-diered),分布式(distributed),基于组件(component-base)的企业级应用模型(enterpriese application model).在这样的一个应用系统中,可按照功能划分为不同的组件,这些组件又可在不同计算机上,并且处于相应的层次(tier)中。所属层次包括客户层(clietn tier)组件,web层和组件,Business层和组件,企业信息系统(EIS)层。




  • [转]C++]static/全局变量、函数等

    2007-06-21 15:17:11

    http://blog.csdn.net/duckur/archive/2005/11/05/523545.aspx



    static Global variable: 文件作用域:只在声明的文件中有效,其他源文件中不可见;同时有了static的生命周期
    Global variable:文件作用域:可以加上extern 声明为外部变量,跨文件作用域

    static (Global) Function: 有文件作用域,只在本文件中使用
    Global Function:无文件作用域

    static Member (in Function) variable:函数调用完成后,变量保存状态,再次调用函数,不会重新分配空间
    Member(in Funcition) variable:函数内的生命周期

    static Member(in Class) variable: 属于类范围,
    Member(in Class) variable:属于类派生的特定对象,生命周期和对象一致

  • 一道简单的智力题

    2007-06-19 15:51:19

    一道据说是SAP的笔试题:

    2个人轮流拿10个硬币,每次只能拿1、2或者4个,拿到最后剩下的硬币者输。
    问:输赢能确定吗?

    关于这道题,可以通过简单的分析得出结论,假设先拿的为A,后拿的为B。

    假设A先拿1枚硬币,B此时可以拿2枚硬币来破局,(此后A若拿4枚,则B拿2枚;若A拿2枚,则B拿4枚;若A拿1枚,则B拿2枚),所以A必败

    假设A先拿2枚硬币,B此时可以拿1枚硬币来破局(此后的情况与上同)

    假设A先拿4枚硬币,B此时可以拿2枚硬币来破局(此后若A拿2枚,则B拿1枚;若A拿1枚,则B拿2枚,A拿4枚更没话说了)

    分析到此可以得出结论:先拿的必败(当然在后拿的知道分析的情况下)

    不知道除了上述这样分析,还有没有更好的解题思路,有兴趣的不妨贴上你们的解答

  • unix shell中(),[]和[[]]的区别

    2007-06-18 14:30:15

    1. 首先,尽管很相似,但是从概念上讲,二者是不同层次的东西。
    "[[",是关键字,许多shell(如ash bsh)并不支持这种方式。ksh, bash(据说从2.02起引入对[[的支持)等支持。
    "["是一条命令, 与test等价,大多数shell都支持。在现代的大多数sh实现中,"["与"test"是内部(builtin)命令,换句话说执行"test"/"["时不会调用/some/path/to/test这样的外部命令(如果有这样的命令的话)。


    2.[[]]结构比Bash版本的[]更通用。在[[和]]之间的所有的字符都不会被文件扩展或是标记分割,但是会有参数引用和命令替换。

    用[[ ... ]]测试结构比用[ ... ]更能防止脚本里的许多逻辑错误。比如说,&&,||,<和>操作符能在一个[[]]测试里通过,但在[]结构会发生错误。

    3.(( ))结构扩展并计算一个算术表达式的值。如果表达式值为0,会返回1或假作为退出状态码。一个非零值的表达式返回一个0或真作为退出状态码。这个结构和先前test命令及[]结构的讨论刚好相反。

    4.[ ... ]为shell命令,所以在其中的表达式应是它的命令行参数,所以串比较操作符">" 与"<"必须转义,否则就变成IO改向操作符了(请参看上面2中的例子)。在[[中"<"与">"不需转义;
    由于"[["是关键字,不会做命令行扩展,因而相对的语法就稍严格些。例如
    在[ ... ]中可以用引号括起操作符,因为在做命令行扩展时会去掉这些引号,而在[[ ... ]]则不允许这样做。

    5.[[ ... ]]进行算术扩展,而[ ... ]不做

    1)在ksh中的test
    数字的运算可使用let、(( )) ,其中运算时不需要变量$符号,运算符为 +、-、*、/、% ,不建议使用expr
    数字的比较使用 (( )) ,其运算符 >、>=、<、<=、==、!=
    可以使用算术扩展,如:(( 99+1 <= 101 ))
    字符表达式的比较使用 [[ ]] ,其运算符 =、!=、-n、-z
    文件表达式的测试使用 [[ ]] ,其运算符 -r、-l、-w、-x、-f、-d、-s、-nt、-ot
    逻辑表达式的测试使用 [[ ]] ,其运算符 !、&&、||
    数字比较、字符比较、逻辑测试可以组合,如$ [[ "a" != "b" && 4 -gt 3 ]]
    支持bash中的通配符扩展,如:[[ hest = h??t ]] 、[ hest = h*t ]]
    使用 (( )) 时,不需要空格分隔各值和运算符,使用 [[ ]] 时需要用空格分隔各值和运算符。

    2)bash与ksh中的 [[ ]] 不同
    在redhat9的bash中也可以使用 [[ ]] 符号。但是建议严格按照上面的原则使用。
    在bash中,数字的比较最好使用 (( )),虽说可以使用 [[ ]],但若在其内使用运算符 >、>=、<、<=、==、!= 时,其结果经常是错误的,不过若在 [[ ]] 中使用 [ ] 中的运算符“-eq、-ne、-le、-lt、-gt、-ge”等,还尚未发现有错。因此诸如$ [[ " a" != “b” && 4 > 3 ]] 这类组合(见上)也不可以在bash中使用,其出错率很高。
    例:[[ "a" != "b" && 10 > 2 ]] 判断结果就不正常。
    诸如 [ 2 \< 10 ]、[[ 2 < 10 ]] 都是不要使用。使用算术扩展最好用 (( 99+1 == 100 )) ,而不要使用[[ 99+1 -eq 100 ]] 。

     


     

     

  • [转]Linux VMWARE上网设置

    2007-06-17 10:02:17

    linux vmware上网设置

    第一种情况:
    主机使用PPPOE拨号上网

    方法一:NAT方式

    1、先关闭虚拟机中的操作系统,回到虚拟机主界面
    双击主界面右上方的的“Ethernet”,弹出“Network Adapter”对话框,选择“NAT”

    2、启动虚拟机操作系统,设置IP为动态获取,即通过DHCP获得。

    此时虚拟机中的操作系统用的是主机的IP,主机能够上网,那么虚拟机也能。

    方法二:Host-only方式

    1、先关闭虚拟机中的操作系统,回到虚拟机主界面
    双击主界面右上方的的“Ethernet”,弹出“Network Adapter”对话框,选择“Host-only”

    2、右击拨号上网的连接,打开PPPOE连接属性,选择“高级”,选择“允许其它网络用户通过此计算机的INTERNET连接来连接”
    在“家庭网络”下拉框中,选择“VMware Network Adapter VMnet1”
    VMware Network Adapter VMnet1虚拟网卡的IP会自动变为192.168.0.1
    此时ping 192.168.0.1 能通即可。

    3、进入vmware中,启动linux操作系统
    用netconfig命令
    将IP,设为192.168.0.2 (与虚拟网卡在同一网段)
    网关为192.168.0.1 即VMware Network Adapter VMnet1虚拟网卡的IP地址
    DNS设置为ISP的DNS,如61.147.37.1

    4、重启网络:
    #service network restart

    此时,只要主机拨号上网后,虚拟机的系统就可以上网,且不用再拨号

    方法三:Bridge方式

    这种方式,虚拟机最接近一台真实的机器

    1、先关闭虚拟机中的操作系统,回到虚拟机主界面
    双击主界面右上方的的“Ethernet”,弹出“Network Adapter”对话框,选择“Bridge”

    2、宿主机中安装sygate或wingate之类的代理服务器

    3、设置虚拟机的代理服务器为宿主机的IP即可

    第二种情况:
    在单位局域网内

    “Ethernet”要选择“Bridge”方式
    使用这种方式时,虚拟机跟一台真实的机器一样,此时IP设置为局域网中另一个可用IP即可
    网关:局域网网关服务器的地址(或路由器的地址)
    DNS:设置为ISP的DNS服务器地址
  • UML学习笔记(五)

    2007-06-15 18:27:18

    1. 聚集是强关联,它是整体与部分之间的关系。在UML中,聚集显示为连接两个类的直线,整体端画一个菱形。

    2. 和关联关系一样,聚集可以自反。类A的一个实例,由同为A的一个或几个其他实例构成。

    3. 对聚集关系生成代码时,ROSE生成支持聚集的属性。

    4. 泛化关系是两个类之间的继承关系。

    5. ROSE对关联和聚集关系产生属性。Static字段确定生成的属性是否静态的。如果将一个角色(Role)设置成静态的,则产生的关联属性为静态的。

    6. 链接元素(Link Element)也称为关联类,可以放置与关联相关的属性。例如两个类Student和Course,则Grade可作为关联类。

  • UML学习笔记(四)——依赖关系

    2007-06-15 16:23:27

    1. 对存在依赖关系的两个类生成代码时,并不对关系的类增加属性。但产生支持关系所需的特定语句。在C++中,生成代码中会包括必要的#include语句。

    例如类A依赖于类B,类A没有B属性,因此要用其他方法查找B。有三种方法:

    • 如果B是全局的,则类A知道它存在。
    • 如果B实例化为类A操作中的本地变量,则类A知道它存在。
    • 如果B作为参数传递到类A中,则类A知道它存在。

    在依赖关系中,必须采用这三种方法之一。

    关联于依赖的第二个差别在于方向,关联可以是双向的,而依赖只能是单向的。

    2. 包之间同样存在依赖性。例如包A依赖于包B。则不能直接在另一个应用程序中复用A包,而要同时复用B包。而B包更容易复用,因为它没有依赖于其他包。

    要确定包依赖性关系,就要检查Class框图中的关系。如果不同包中的类之间有关系,则包也有关系。

    生成包依赖关系时,要尽量避免循环依赖性。要避免循环依赖,可以把一个包一分为二。

  • UML学习笔记(三)——关联关系

    2007-06-15 16:11:31

    1. 类之间可以建立四种关系:关联、依赖、聚集(Aggregation)和泛化(Generalization)。

    2. 关联可以是双向的,也可以是单向的.

    3. 依赖总是单向的,显示一个类依赖于另一个类的定义。依赖用虚线箭头表示。

    4. 聚集是强关联。聚集关系是整体和个体间的关系。

    5. 泛化显示类之间的继承关系

    6. 通过Sequence或Collaboration框图可以确定关联方向。如果Interaction框图中总是类A向类B发消息,则是类A到类B的单向关系。如果又有类B到类A的消息,则需要双向关系。

    单向关系更容易建立和维护,有助于寻找可复用的类。如果类A和类B之间的关系是双向的,则每个类都需要知道对方,因此两者都不能复用。但假设是从类A到类B的单向关系,则类A需要知道类B,没有类B就无法复用,而类B不需要知道类A,因此类B是可以复用的。

    任何输出多个单向关系的类都很难复用,而只接收单向关系的类则很容易复用。

    7. 关联也可以自反。自反关联让类的一个实例同该类的其他实例相联系。

  • UML学习笔记(二)

    2007-06-15 16:10:36

    1. 边界类:边界类位于系统与外界的交界处,包括所有窗体、报表、与打印机和扫描仪等硬件的接口、以及与其他系统的接口。

    要寻找边界类,可以检查Use Case框图。每个角色/用例交互至少要有一个边界类。边界类使角色与系统交互。

    2. 实体类:实体类保存要放进持续存储体的信息。实体类通常在事件流和Interaction框图中,是对用户最有意义的类。实体类中的每一个字段都是数据库结构中的字段。

    3. 控制类:控制类负责协调其他类的工作。也称为管理者类。

  • UML学习笔记(一)

    2007-06-14 22:54:17

    1.不要在两个用例之间画箭头(除了使用与扩展关系)

    2. UML将使用关系显示为箭头和<<uses>>字样,被使用的用例为抽象用例。

    3. 扩展关系也是用箭头表示,注明<<extends>>字样,扩展的用例为抽象用例(比如ExpressWithdraw扩展了Withdraw,则ExpressWithdraw提供了扩展的功能,为抽象用例)

    具体用例和抽象用例之间存在一个区别。具体用例由主角来启动,并且构成一个完整的事件流。“完整”意味着该用例的一个实例执行由主角调用的全部操作。

          抽象用例本身从来不会被实例化。抽象用例包括在(请参阅指南:包含关系)其他用例中,扩展到(请参阅指南:扩展关系)或泛化关系(请参阅指南:用例泛化关系)其他用例。在启动一个具体用例时,也就创建了该用例的一个实例。这一实例还展示了由其关联关系的抽象用例指定的活动。因而,从抽象用例中无法创建单独的实例。

  • Everyday Scripting with Ruby学习笔记(一)

    2007-06-13 22:12:07

    1.When a name begins with a capital letter, you’re telling Ruby that you
    expect it always to refer to the same object. Ruby will complain if you
    try to use the same name for a different object:
    irb(main):007:0> MyShip = "a cutter"
    => "a cutter"
    irb(main):008:0> MyShip = "a bark"
    (irb):4: warning: already initialized constant MyShip
    => "a bark"
    (Ruby complains but still obeys.)

    2. Although puts is printing a string, it doesn’t put quotes around
    it like irb does. irb’s output is formatted for you, a scrīpter. puts
    formats its output for end-user consumption. If you want the irbstyle
    output, use the inspect message: inspect
    irb(main):010:0> puts "I'd like some quotes, please".inspect
    "I'd like some quotes, please"
    => nil

  • [转]突破XP Home版的限制安装IIS

    2007-06-13 11:50:54

    来源:Yesky 作者:刘晖 出处:巧巧读书

    常见的Windows XP有两个版本,Professional和Home版。这两个版本大体上是相同的,只是在细节方面,Professional版比Home版多了一些功能。例如Professional版的XP支持双CPU,多国 语言,加入域,EFS文件加密,以及IIS(Internet Information Services)。

     
    很多人在买电脑的时候了解的不够清楚,买了预装Home版XP的电脑,而需要用到或者想学习IIS的时候才发现,原来Home版根本不能安装IIS或者PWS。如果按照一般的方法,你只能升级到Windows XP Professional或者使用Windows 2000,不过仔细看看下文吧,你也可以在Windows XP Home上安装IIS了。

      首先需要说明一点,就是这种做法可能会有风险,因此在你实际操作之前,最好明确你的行为会带来什么后果。并且经过这样处理安装的IIS在运行上可能存在某种未知的缺陷。还有,同Professional版的XP一样,在Home版上运行的IIS也有10个并发连接的限制。在同一个时间内,最多只能有10个人使用你提供的IIS服务。如果你还想继续,那么就往下看吧。

      准备条件:一张Windows 2000 Professional的光盘(假设光驱是F盘)。

      首先在运行中输入"c:\windows\inf\sysoc.inf",系统会自动使用记事本打开sysoc.inf这个文件。在sysoc.inf中找到"[Components]"这一段,并继续找到类似"iis=iis.dll,OcEntry,iis.inf,hide,7"的一行字,把这一行替换为"iis=iis2.dll,OcEntry,iis2.inf,,7"。之后保存并关闭。

      把Windows 2000 Professional的光盘插入光驱,同时按下Shift键禁止光驱的自动运行。在运行中输入"CMD"然后回车,打开命令行模式,在命令行下输入下列的两条命令,在每一行命令结束后回车:

      Expand d:\i386\iis.dl_ c:\windows\system32\setup\iis2.dll
      Expand d:\i386\iis.in_ c:\windows\inf\iis2.inf

    这时,打开你的控制面板,并点击"添加删除程序"图标,之后点击"添加删除Windows组件",你应该可以看见图一的界面。请仔细看,在开始菜单中显示的操作系统Windows XP Home,但是经过修改,已经有了添加IIS的选项了。

    突破XP Home版的限制安装IIS(图一)

    图 一

      然后你可以按照在Windows XP Professional或者Windows 2000中的方法添加IIS,在本例中我们只安装了WWW服务。系统会开始复制文件,这需要一些时间。并且在这起见,请保持Windows 2000 Professional的光盘还在光驱中。

      在安装结束后,你可以打开控制面板-性能和选项-管理工具,"Internet信息服务管理"已经出现在那里(图二)。如果你想要验证IIS是否运行正常,而已打开IE,在地址栏中输入"http://localhost"然后回车,如果能看到图三的界面,那么你的IIS就全部正常运行了。

    突破XP Home版的限制安装IIS(图二)

    图 二

    突破XP Home版的限制安装IIS(图三)

    图 三

      最后还有一点注意的:

      如果你在安装过程中,系统需要你插入Window Whistler CD或者需要你提供exch_adsiisex.dll这个文件,那是因为你按照默认的选项安装了IIS。要解决这个问题,只要在安装IIS的时候先点击"详细信息",然后取消对SMTP的选择(即,不要安装SMTP服务器),那么复制文件的时候就不会需要那两个文件了。

      如果在你安装的到图一的位置后发现,已经显示了Internet信息服务(IIS)的安装项目,但是它们根本无法被选中,那很可能因为你使用的iis.dl_和iis.in_是从Windows XP Professional中取出的,只要换成Windows 2000 Professional中的就可以继续正常安装了。

      经过验证,WWW、FTP等几个服务经过这样的修改都可以在Windows XP Home上正常运行。

  • [转]什么情况下应建立索引

    2007-06-11 09:15:38

    什么情况下应该建立索引

    表的主关键字
    自动建立唯一索引
    如zl_yhjbqk(用户基本情况)中的hbs_bh(户标识编号)

    表的字段唯一约束
    ORACLE利用索引来保证数据的完整性
    如lc_hj(流程环节)中的lc_bh+hj_sx(流程编号+环节顺序)

    直接条件查询的字段
    在SQL中用于条件约束的字段
    如zl_yhjbqk(用户基本情况)中的qc_bh(区册编号)
    select * from zl_yhjbqk where qc_bh=’<????甼曀???>7001’

    查询中与其它表关联的字段
    字段常常建立了外键关系
    如zl_ydcf(用电成份)中的jldb_bh(计量点表编号)
    select * from zl_ydcf a,zl_yhdb b where a.jldb_bh=b.jldb_bh and b.jldb_bh=’540100214511’

    查询中排序的字段
    排序的字段如果通过索引去访问那将大大提高排序速度
    select * from zl_yhjbqk order by qc_bh(建立qc_bh索引)
    select * from zl_yhjbqk where qc_bh=’7001’ order by cb_sx(建立qc_bh+cb_sx索引,注:只是一个索引,其中包括qc_bh和cb_sx字段)

    查询中统计或分组统计的字段
    select max(hbs_bh) from zl_yhjbqk
    select qc_bh,count(*) from zl_yhjbqk group by qc_bh

    什么情况下应不建或少建索引

    表记录太少

    如果一个表只有5条记录,采用索引去访问记录的话,那首先需访问索引表,再通过索引表访问数据表,一般索引表与数据表不在同一个数据块,这种情况下ORACLE至少要往返读取数据块两次。而不用索引的情况下ORACLE会将所有的数据一次读出,处理速度显然会比用索引快。

    如表zl_sybm(使用部门)一般只有几条记录,除了主关键字外对任何一个字段建索引都不会产生性能优化,实际上如果对这个表进行了统计分析后ORACLE也不会用你建的索引,而是自动执行全表访问。如:

    select * from zl_sybm where sydw_bh=’5401’(对sydw_bh建立索引不会产生性能优化)

    经常插入、删除、修改的表
    对一些经常处理的业务表应在查询允许的情况下尽量减少索引,如zl_yhbm,gc_dfss,gc_dfys,gc_fpdy等业务表。

    数据重复且分布平均的表字段
    假如一个表有10万行记录,有一个字段A只有T和F两种值,且每个值的分布概率大约为50%,那么对这种表A字段建索引一般不会提高数据库的查询速度。

    经常和主字段一块查询但主字段索引值比较多的表字段

     如gc_dfss(电费实收)表经常按收费序号、户标识编号、抄表日期、电费发生年月、操作标志来具体查询某一笔收款的情况,如果将所有的字段都建在一个索引里那将会增加数据的修改、插入、删除时间,从实际上分析一笔收款如果按收费序号索引就已经将记录减少到只有几条,如果再按后面的几个字段索引查询将对性能不产生太大的影响。

  • [转]软件测试的衡量标准

    2007-06-08 08:31:58

    需求的覆盖 需求追溯表/需求矩阵

    缺陷数量 多、新

    缺陷重现率 BUG能按照一定的测试过程稳定重现

    效率 平均每人天发现的BUG数(5个/人天)

    成本 少。合理的测试人力和软、硬件资源安排

    重用价值 测试的数据或者样例可以重用

  • [转]子网掩码计算方法

    2007-06-07 21:16:43

    子网掩码是用来判断任意两台计算机的IP地址是否属于同一子网络的根据。

    最为简单的理解就是两台计算机各自的IP地址与子网掩码进行AND运算后,如果得出的结果是相同的,则说明这两台计算机是处于同一个子网络上的,可以进行直接的通讯。就这么简单。

    请看以下示例:

    运算演示之一:aa
    I P 地址  192.168.0.1
    子网掩码  255.255.255.0
    AND运算

    转化为二进制进行运算:
    I P 地址 11010000.10101000.00000000.00000001
    子网掩码 11111111.11111111.11111111.00000000
    AND运算

         11000000.10101000.00000000.00000000
    转化为十进制后为:

          192.168.0.0


    运算演示之二:
    I P 地址  192.168.0.254
    子网掩码  255.255.255.0
    AND运算

    转化为二进制进行运算:
    I P 地址 11010000.10101000.00000000.11111110
    子网掩码 11111111.11111111.11111111.00000000
    AND运算

         11000000.10101000.00000000.00000000
    转化为十进制后为:

          192.168.0.0


    运算演示之三:
    I P 地址  192.168.0.4
    子网掩码  255.255.255.0
    AND运算

    转化为二进制进行运算:
    I P 地址 11010000.10101000.00000000.00000100
    子网掩码 11111111.11111111.11111111.00000000
    AND运算

         11000000.10101000.00000000.00000000
    转化为十进制后为:

          192.168.0.0


      通过以上对三组计算机IP地址与子网掩码的AND运算后,我们可以看到它运算结果是一样的。均为192.168.0.0

      所以计算机就会把这三台计算机视为是同一子网络,然后进行通讯的。我现在单位使用的代理服务器,内部网络就是这样规划的。

    也许你又要问,这样的子网掩码究竟有多少了IP地址可以用呢?你可以这样算。
    根据上面我们可以看出,局域网内部的ip地址是我们自己规定的(当然和其他的ip地址是一样的),这个是由子网掩码决定的通过对255.255.255.0的分析。可得出:
      前三位IP码由分配下来的数字就只能固定为192.168.0  所以就只剩下了最后的一位了,那么显而易见了,ip地址只能有(2的8次方-1),即256-1=255一般末位为0或者是255的都有其特殊的作用。

    那么你可能要问了:如果我的子网掩码不是255.255.255.0呢?你也可以这样做啊假设你的子网掩码是255.255.128.0

    那么你的局域网内的ip地址的前两位肯定是固定的了(什么,为什么是固定的?你看上边不就明白了吗?·#¥)

    这样,你就可以按照下边的计算来看看同一个子网内到底能有多少台机器

    1、十进制128 = 二进制1000 0000

    2、IP码要和子网掩码进行AND运算

    3、
    I P 地址 00010000.01001001.1*******.********
    子网掩码 11111111.11111111.10000000.00000000
    AND运算

         00010000.01001001.10000000.00000000
    转化为十进制后为:

          16 . 73 . 128 . 0

    4、可知我们内部网可用的IP地址为:

    00010000.01001001.10000000.00000000
           到
    00010000.01001001.11111111.11111111

    5、转化为十进制:

    16.73.128.0 到 16.73.255.255

    6、0和255通常作为网络的内部特殊用途。通常不使用。

    7、于是最后的结果如下:我们单位所有可用的IP地址为:
    192.168.128.1-192.168.128.254
    192.168.129.1-192.168.129.254
    192.168.130.1-192.168.130.254
    192.168.131.1-192.168.131.254
    . . . . . . . . . . . . .
    192.168.139.1-192.168.139.254
    192.168.140.1-192.168.140.254
    192.168.141.1-192.168.141.254
    192.168.142.1-192.168.142.254
    192.168.143.1-192.168.143.254
    . . . . . . . . . . . . .
    192.168.254.1-192.168.254.254
    192.168.255.1-192.168.255.254

    8、总数为(255-128+1)*(254-1+1) =128 * 254 = 32512

    FAINT!!!!@#!@把我们公司都买了还买不了这么多的机器呢!·¥!·#

    9、看看的结果是否正确

      (1)、设定IP地址为192.168.128.1

        Ping 192.168.129.233通过测试

        访问http://192.168.129.233可以显示出主页

      (2)、设定IP地址为192.168.255.254

        Ping 192.168.129.233通过测试

        访问http://192.168.129.233可以显示出主页

    10、结论

      以上证明我们的结论是对的。


    现在你就可以看你的子网中能有多少台机器了

    255.255.255.128
    分解:
    11111111.11111111.11111111.1000000
    所以你的内部网络的ip地址只能是
    xxxxxxxx.xxxxxxxx.xxxxxxxx.0???????

    xxxxxxxx.xxxxxxxx.xxxxxxxx.01111111

  • PL/SQL学习笔记(八)

    2007-06-07 11:11:53

    1. PL/SQL支持三类集合:

    索引表;嵌套表;变长数组

    2. 索引表是一个由元素组成的表,它被保存在内存中,其中每一个元素用一个整数值做索引。索引表的功能与数组类似,但有两个主要的区别:

    • 索引表可以稀疏地填充;
    • 不给索引表设置最大长度。

    3. 通过声明一个类型,然后声明一个或多个这种类型的变量来声明索引表。声明类型时,指定了集合的数据类型,并指定了表索引的数据类型。集合的数据类型可以是标量类型(如NUMBER或VARCHAR2)或复合类型(如记录)。表索引的数据类型必须是BINARY_INTEGER.声明索引表类型的语法如下:

    TYPE type_name IS TABLE OF data_type [NOT NULL] INDEX BY BINARY_INTEGER;

    4. 可以用table_name.EXISTS(index_num)来判断某个索引值对应的条目是否存在。

    5. 删除索引表中的条目:

    table_name.DELETE[(first_entry[,last_entry])];

    6. 在数据库中,嵌套表是一个无序记录集合。声明嵌套表类型的语法:

    TYPE type_name IS TABLE OF data_type (NOT NULL);

    如果需要PL/SQL专用数据类型(如BOOLEAN/NATUAL或INTEGER)的数组,则只能选择索引表。

    7. 给嵌套表添加条目与给索引表添加条目有些不同。必须使用构造函数初始化嵌套表后,才能给它添加条目。初始化嵌套表后,如果要增加表的大小,需要调用extend方法。

    构造函数的名称与声明表时使用的类型名称相同,例如:

    depts := dept_table();

    也可以在调用构造函数时,给它传递一个或多个条目的值,如

    depts := dept_table(dept1,dept2);

    8. 对于嵌套表,使用delete()方法删除条目后,exists()方法并不知道删除了一些条目,所以删除条目后工作区必须至少执行一次count()方法

    9. 声明变长数组类型的语法如下:

    TYPE type_name IS (VARRAY|VARYING ARRAY) (size) OF entry_type [NOT NULL];

    10. 批绑定让您编写对集合中所有条目进行操作的SQL语句,而不必使用PL/SQL代码在集合中循环。从SQL(取回数据)到PL/SQL(将数据添加到数组中)的切换被称为关联转换(context switch),这增加了许多开销。可以使用批绑定避免大部分这种开销。

    两个新关键字支持绑定。BULK COLLECT用于SELECT语句中,将所有的数据放到一个集合中;FORALL用于INSERT/UPDATE/DELETE语句中,以便对集合中的每一个元素执行这些语句一次。

    11. 可以在SELECT INTO语句和FETCH 语句中使用BULK COLLECT。(但是BULK COLLECT不能使用记录表)

    12. 关键字FORALL允许您将一条数据操纵语言(DML)语句(即INSERT/UPDATE或DELETE)基于一个集合的内容,使用FORALL时,该语句对集合中的每个条目执行一次,但从PL/SQL到SQL的关联转换只有一次,这使得性能比在PL/SQL中使用循环快的多。

  • PL/SQL学习笔记(七)

    2007-06-06 21:02:59

     1. Oracle游标是一种用于轻松地处理多行数据的机制。游标的另一项功能是,它包含一个跟踪当前访问的记录的指针,这使您的程序能够一次处理多条记录。

    2. 将游标放在一个FOR循环中,这种FOR循环被称为游标FOR循环。它显式地完成下述工作:

    声明循环索引;

    打开游标;

    每次循环迭代都取回游标的下一条记录;

    处理完所有的记录或退出循环时关闭游标

    如:

    DECLARE
      CURSOR all_depts
       is
        SELECT dept_id,dept_name
        FROM department
        ORDER BY dept_name;
       
      dept all_depts%ROWTYPE;
    BEGIN                      --implicit cursor open
      FOR dept in all_depts LOOP     --implicit cursor fetch
       
        DBMS_OUTPUT.PUT_LINE(dept.dept_name);
        DBMS_OUTPUT.PUT_LINE(all_depts%rowcount);
       
     
      END LOOP;            --implicit cursor close
      COMMIT;

    END;

    3. Oracle允许删除或更新当前的记录。要删除或更新取回的记录,必须使用FOR UPDATE子句声明游标,并且必须打开了游标。

    4. 游标变量B被赋值为游标变量A,游标变量A被赋值为游标对象123,两个游标变量都在游标对象的作用域内,当游标变量A被删除后,游标变量B仍然可以访问游标对象123。

    5. 隐式游标可用sql对象访问游标属性,如sql%rowcount,sql%found,etc

692/4<1234>
Open Toolbar