1,软件测试,如何把这个测试做的更好。

 进到一个新项目,作为测试人员应该都是想把测试做好,项目在符合客户质量要求的情况下按时交付的吧。但往往都事与愿违,造成这个结果的原因有很多很多。通过这段时间做自动化测试,站在自动化测试的角度看手工测试,以及排除其他部门的问题,单说测试自身的问题来和大家分析讨论一下怎样我能做到更好。

  先说一下背景,我是中途进的项目,项目需要做自动化测试,依据是手工测试人员开发的用例。从测试用例和测试流程两方面来进行阐述吧。

  首先说说测试用例。当前大部分的项目一般都是任务重时间紧,往往为了能保证能把项目“做”完,挤压了测试开发、执行和需求分析的时间。测试用例设计开发作为测试团队主要的工作任务,其重要性仅次于需求分析。如果测试用例的质量出现问题会产生一连串的影响,比如不能让新进开发团队的人员了解系统、以手工用例为基础的自动化测试开发人员无从下手或繁重的修改工作、最重要的是增加了回归测试执行的时间及风险。

  在测试用例开发上,比较常见的问题就是用例有量无质。用例的数量上去了却无质量可言,大量重复的又缺乏测试必要的用例。做为测试团队重要的输出物之一,如果不能保证用例的质量那系统的质量又从何谈起呢?测试用例的质量我觉得体现在以下两个方面:

  1、测试用例不够详尽、缺乏目的性、重复性高

  测试用例的详细程度是一个相对的问题。太详尽了使操作步骤过于繁琐冗长,测试人员操作完之后无法对测试用例有一个整体认识;过于简约的用例同样无法让测试人员了解测试目的,应该如何操作。在我的想法中,一个具有一定质量的测试用例应该经过多方面配合的,比如用例描述信息、用例名称及操作步骤等等。描述信息中可以描述出测试用例是由谁、在和情况下、做了什么事及最后的结果;用例名称显示出是对哪个业务进行的正面/反面测试;如果说名称和描述为辅助的信息,那么测试步骤无疑是在一个相对比较重要的位置上了。测试步骤的来源是什么?是系统需求。那么系统需求的好坏就决定了测试步骤的好坏。如果需求详尽,简洁省时的方法当然可以用直接引用的方式,这样正确性有所保证也为开发其他用例节省了时间;相反的,需求不够详尽,是否应将测试步骤进行一定的扩展,避免操作步骤的混淆,让对系统不熟悉的人尽快了解系统功能。在测试开发的迭代周期中,最常见的问题就是需求的更改,这个是无法避免的。那么对于测试用例,我们如何应对这种变化呢?我想除了不要将用例中的期望结果过于详细外,应当勤于进行用例的开发迭代以符合系统需求,关于这一点,我们稍后再说。

  测试用例缺乏目的性、重复性高是造成用例数量直线上升,质量直线下降的一个重要因素。假设一个用户注册的场景,用户可通过不同的证件类型完成注册,如何设计这个用例呢?我的想法是,对于注册成功的预期结果,只安排一个用例,在用例的前提条件或描述信息中突出需通过不同证件类型参数进行测试。从开发人员的角度和2/8原则的角度讲,他们的主要精力会放在将正常的注册功能开发完成,即假定用户输入的值都是合法的。实际上,测试往往就是对那些无法顺利完成功能的场景,输入无效值或测试反面场景以覆盖完全的测试场景。在设计用例时,就应当将更多的精力放在这些场景的设计上。有些人可能会说,如果将手工用例参数化,在执行用例的时候,不同的测试人员往往不会按照用例的描述,分不同的数据要求去执行,这个无法保证。从我的角度来说,一方面需要测试领导的信任,一方面也许要对测试人员进行监督。对同事信任,相信他们会进行全面的测试。对按用例要求进行测试的人员给予奖励,对不能认真完成测试用例要求的测试人员实施惩罚,这样鼓励已经做好的人继续保持,还没做好的往好的目标前进。

  2、用例更新滞后

  在软件开发周期中会经过几次迭代过程,每一次迭代都会经历大小不同的需求变更、系统实现变化等等。在需求发生变化后,应及时更新测试用例,以保证测试用例适用于当前的系统实现,这样才能保证回归测试的执行是有效的,并节省下更多的人力物力到更容易发生错误的地方。除了新需求的增加、老需求的变更,实时的对测试用例进行重构也是必要的,如同对系统代码进行重构一样,这样才能让系统跑的更快更安全,以更少的测试用例覆盖更多的功能点和业务规则。最初开发测试用例,由于对系统需求缺乏深入理解或开发时间紧,不能覆盖全面的测试场景或者用例重复性较高,这都需要及时的通过测试用例的重构提高系统测试用例的有效性。我认为,应该尽量争取在下一个迭代周期结束前进行或完成之前一个迭代周期中测试用例的重构。积压的测试用例越多进行重构的难度越大,耗费的精力越多,风险也就越大。需求的遗忘、变更,需要修改的用例数量之大,加之有限的时间等等,都会给测试用例重构造成隐患,延误回归测试的进度。看着上千的测试用例,谁都会头疼吧。说起来我们有几千个用例测试系统可在真正执行时有多少是能发挥效果的呢?

  其次再说说测试流程。最早接触的是CMMI,现在慢慢的随着客户需求日新月异,加上新的流程概念的引入,越来越多的项目采用了敏捷开发的概念。就我对敏捷开发的认识,从形式上来说敏捷与CMMI的区别是,注重敏捷的沟通多于文档这些形式上的产物,当然敏捷开发不是简简单单注意沟通就可以的。对于刚刚引入敏捷概念的项目,团队之间的契合度不高,理解不深,加之大家还没有脱离CMMI的形式,导致项目流程既不敏捷,也不CMMI。说是CMMI可流程执行力度不够,说敏捷沟通又不够。我的理解,敏捷与CMMI在工作内容、职责上并无太大变化,不同的是需要加强团队之间的沟通,任何的变化都应该是连环动起来的,而不是变化传达到第一个人就结束了,就像军训时的向右看齐,只有每一个人都向右看,最后一个人才有可能和第一个人在一个水平线上。在我经历的几个项目中,沟通不够往往表现在几个方面,项目信息共享,包括技术的和业务的、需求变更、用例变更、开发进度等等。有多少会做到开发进度实时更新,更新了有多少人会去看,不如当面锣对面鼓的说清楚。在变化快的情况下,过于依赖文档反而会让大家对项目不甚了解或知之甚少。敏捷强调沟通也是为了避免在文档的更新上各个环节出现之后。再者文档对信息的传达力有多大也是个问题,举个例子,比如用例进行重构,测试人员通过映射表记录用例的变化情况,哪些是过期的,哪些是修改了步骤的,哪些是新增的等等。在设计这个映射表要提供哪些信息时一定要想谁会去看这些信息,所以哪些信息对他们是有用的,能让他们快速的找到他们想了解的东西,这些信息一定要记录。

  这里记录了一些在项目中遇到的问题,希望可以给自己更多的思考,在以后自己的工作中可以避免,也是把一些问题拿出来和大家讨论,希望集大家之广议共同提高,有些说的不清楚,更像是抱怨别人的问题,可能因为自己的认识还不够深刻吧,会在以后的时间中改进,多写一些改进措施。对于测试会有这样的现象出现也不是测试单方面的责任,很有可能是需求没有做好,或开发的问题。对于敏捷,我们应该想的更多做的更多,才能把项目做好

现在推广 敏捷 测试 ,发现很多人没有理解敏捷的实质。

从本质来说,敏捷是一种思想,不是一种软件工程模式。
从出发点来说,敏捷不是提高产品的质量,是如何能最大限度的快速获得用户的回馈并反应。
从流程来说,敏捷可以采用任何流程,瀑布也能敏捷起来。
从结果来说,敏捷是倒推,用户第一。
从执行过程来说,敏捷强调的是轻文档(不是不要,是轻量级和关键文档必须),重沟通(需求时刻变化,预设的文档需要不断的细化调整)
从角色来说,敏捷强调的是用户体验,也就是说所有角色要从用户体验出发。
从经验来说,敏捷不可复制,没有任何一个成功模板可套用,只能不断试错,然后选择适合自己的。
CMMI全称是Capability Maturity Model Integration,即软件能力成熟度模型集成(也有称为:软件能力成熟度集成模型)
<<CMMI包括:
1. 初始级(initial)

2. 可重复级(Repeatable)

3. 已定义级(Defined)

4. 已管理级(Managed)

5. 优化级(Optimizing)

<<各级含义:
CMMILevel 1,初始级。在完成级水平上,企业对项目的目标与要做的努力很清晰,项目的目标得以实现。但是由于任务的完成带有很大的偶然性,企业无法保证在实施同类项目的时候仍然能够完成任务。企业在一级上的项目实施对实施人员有很大的依赖性。
 
CMMILevel 2,可重复级。在管理级水平上,企业在项目实施上能够遵守既定的计划与流程,有资源准备,权责到人,对相关的项目实施人员有相应的培训,对整个流程有监测与控制,并与上级单位对项目与流程进行审查。企业在二级水平上体现了对项目的一系列的管理程序。这一系列的管理手段排除了企业在一级时完成任务的随机性,保证了企业的所有项目实施都会得到成功。
 
CMMILevel 3,定义级。在定义级水平上,企业不仅能够对项目的实施有一整套的管理措施,并保障项目的完成;而且,企业能够根据自身的特殊情况以及自己的标准流程,将这套管理体系与流程予以制度化这样,企业不仅能够在同类的项目上升到成功的实施,在不同类的项目上一样能够得到成功的实施。科学的管理成为企业的一种文化,企业的组织财富。
 
CMMILevel 4,管理级。在管理级水平上,企业的项目管理不仅形成了一种制度,而且要实现数字化的管理。对管理流程要做到量化与数字化。通过量化技术来实现流程的稳定性,实现管理的精度,降低项目实施在质量上的波动。
 
CMMILevel 5,优化级。在优化级水平上,企业的项目管理达到了最高的境界。企业不仅能够通过信息手段与数字化手段来实现对项目的管理,而且能够充分利用信息资料,对企业在项目实施的过程中可能出现的次品予以预防。能够主动地改善流程,运用新技术,实现流程的优化。 企业在实施CMMI的时候,路要一步一步地走。一般地讲,应该先从二级入手。在管理上下功夫。争取最终实现CMMI的第五级。
<<关于CSCMM:
我国的SE专家基于CMM 1.1,参照CMM2.0和有关资料,提出了符合我国国情的CSCMM。
CSCMM与CMM的主要区别:在等级1和等级2之间插入了一个“基本级”,使成熟度等级更加均匀。

意义:以免软件开发组织长时间达不到2级,会是之失去信心。

0. 初始级。没有定义软件过程。

1. 基本级。定义了软件过程但执行可能不一致。

2. 可重复级。定义了软件过程且执行基本一致。

3. 已定义级。工程过程/管理过程都明确/妥善定义,并且文档化/标准化,成为软件开发组织的 标准软件过程 。组织内所有软件开发项目均采用该 标准软件过程 的经批准的剪裁版本。

4. 定量管理级。在开发过程中,能详细采集软件过程/软件产品的度量数据,从而对成本/进度/质量 定量预测/定量控制。(可见,“定量管理级”这个名字比“已管理级”更传神。)

5. 优化级。能根据 实践总结/新的技术,对标准软件过程不断改进。

<<其实施方案:

1、在软件开发组织中,软件过程要规范化/具体化。

2、在软件开发组织中,要通过正式文档/文件和培训,将其软件过程准确无误地告知所有员工,新员工要进行特别培训。

3、CMM的组织结构:它推荐在最高领导之下设立SEPG(软工过程组)、SQA(质量保证组)、SEG(软工组)

2,java和C++ 的区别,

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方法: Read r=new Read(); r.work();语句Read r=new Read();在堆栈结构上建立了一个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(exceptionType name){ //处理 }其中exceptionType表示异常类型。而C++则没有如此方便的机制。
c++ 就是C语言加了一些东西。。就是所谓的++
java 说白了就是C++--加了一些东西减了一些东西。
java是在C++的基础上开发的。java是纯面向对象编程,C++不是,java没有指针,没有内存溢出,C++有。
都能够实现面向对象思想(封装,继乘,多态)。而由于c++为了照顾大量的C语言使用者,
而兼容了C,使得自身仅仅成为了带类的C语言,多多少少影响了其面向对象的彻底性!JAVA则是完全的面向对象语言,它句法更清楚,规模更小,更易学。它是在对多种程序设计语言进行了深入细致研究的基础上,据弃了其他语言的不足之处,从根本上解决了c++的固有缺陷。
Java和c++的相似之处多于不同之处,但两种语言问几处主要的不同使得Java更轻易学习,并且编程环境更为简朴。
我在这里不能完全列出不同之处,仅列出比较显著的区别:
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方法:
Read r=new Read();
r.work();
语句Read r=new Read();在堆栈结构上建立了一个Read的实例。Java自动进行无用内存回收操作,不需要程序员进行删除。而c十十中必须由程序贝释放内存资源,增加了程序设计者的负扔。Java中当一个对象不被再用到时,无用内存回收器将给它加上标签以示删除。JAVA里无用内存回收程序是以线程方式在后台运行的,利用空闲时间工作。
另外,站长团上有产品团购,便宜有保证
评论 | 4 0
举报| 2011-05-10 10:40wangkai_huli | 五级
Java程序中的每个变量要么是基本数据类型(boolean, char, byte, short, int, long, float, double),要么是对对象的引用 C++有许多种基本类型,额外还有struct, union, enum, 数组和指针,C++指针可以指向对象,也可以不指向对象 Java没有枚举、联合类型,因为Java认为没有必要。将可有可无的语言元素去掉是Java对C/C++做出的一大改变,因此,普遍认为Java较C++更轻便,更精简 Java采用Unicode字符集,C++通常用ASCII字符集。但ASCII是Unicode的子集,对于习惯于ASCII的程序员感觉不到区别 Java中的boolean类型不能转换成其他类型,反之亦然。C++最近引进了bool类型,代表布尔类型,整型也作为逻辑判断 模板是一种“泛型编程思想”,它有别于“面向对象编程思想”。C++在很大程度上已经支持了这种新型编程方法,特别是STL的出现
Java目前仍未支持泛型编程,不过据说Sun公司有在Java中引入模板的计划 C++支持“运算符的重载”,这是它的一个很重要的多态特征,是数据抽象和泛型编程的利器。它允许直接对对象进行四则运算,正像基本数据类型那样
Java不支持这种多态机制,也是为降低复杂性 两种语言都支持方法重载(overloading) 在C++中,为了允许运行时动态决定哪个函数被调用,一个函数必须用virtual修饰。virtual关键字被自动继承,用以支持多态 凡是没有用virtual修饰的成员函数(包括static)都是静态绑定的,即在编译时决定调用哪个版本 而在Java中,除了static、final、private是静态绑定以外,所有方法一律按动态绑定处理
C++中有“拷贝构造函数”的概念,在三种情况下,自动调用它
用一个对象初始化另一对象
对象作实参进行函数调用
对象作函数的返回值 通常,当一个对象需要做“深拷贝”(钱能:《C++程序设计教程》)时,我们需要为它事先定义“拷贝构造函数”、“赋值运算符的重载函数”和“析构函数”;否则编译器将以“按位copy”的形式自动生成相应的缺省函数。倘若类中含有指针成员或引用成员,那么这三个默认的函数就隐含了错误 Java则没有这种语法结构和语义逻辑
C++支持inline函数,可以避免函数的堆栈调用,提高运行效率 Java无这种语义 C++中,构造函数的初始化列表是这样使用的:首先按继承顺序调用基类的构造函数构造基类对象,然后按声明顺序调用成员对象的构造函数构造成员对象,最后对列表中出现的成员变量做初始化
Java不采用初始化列表这种构造机制
它们的构造顺序基本一致:
静态变量初始化
静态初始化块(Java)
调用基类的构造函数构造基类对象
实例变量的初始化
构造函数的其余部分
Java使用abstract关键字修饰抽象方法或抽象类 C++的对等语法是“纯虚函数”和“抽象类” 两者都使用抽象类作为继承层次中的基类,提供一般概念,由子类实现其抽象方法,且抽象类都不能被直接实例化为对象
Java中有final关键字,修饰类、方法或变量
final类不能被继承
final方法不能被子类覆盖
final变量就是常量 C++中没有这个关键字,常量可以使用const或#define定义
const还可以修饰成员函数,即“常成员函数”,当一个const成员函数修改成员数据,或调用非const成员函数时,编译器会报错
我们应将不修改成员数据的函数声明为const
Java和C++中的static关键字语法和语义基本相同 static成员变量又叫类变量,被类的所有对象共享
A::x (C++):必须在类体外初始化
A.x (Java):必须在类体内初始化
static成员方法又叫类方法,访问static变量
A::f( ) (C++)
A.f( ) (Java)
两者都有内部类和局部类的语法和语义 Java中没有友元函数和友元类的概念,严格支持封装,不允许外部方法访问类的私有成员
而C++支持friend关键字,允许外部方法访问类的私有成员,因此不是一种纯面向对象的编程语言
Java中类或interface可以用public修饰,也可以不修饰;而C++类不能修饰 三种访问权限的语义相同,语法略有差别 C++中还有继承权限修饰符,Java则没有
class A: protected B, public C (C++)
class A extends B (Java)
Java有super关键字,指代父类对象,通常被用于调用父类的构造方法或一般方法
C++则没有super关键字 两者都有this,指代当前对象 Java有package的概念,可以将类组织起来,便于打包和部署,也有利于类的安全。C++没有这个概念,一个类可以被任意类访问
Java applet可以被嵌入HTML文档中,然后由Web浏览器下载和执行
Java API有对网络通讯的特别支持 C++则无内置网络功能
C++程序员必须显式地实现动态内存管理,在析构函数中用delete运算符或free( )函数释放对象和其他动态分配的数据空间,否则会造成“内存泄露” 而在Java中,垃圾收集是自动的。当对象的最后一个引用变量被释放掉,这个对象就成为垃圾收集器的候选对象了
因此Java不支持析构函数
finalize( )方法主要被用来释放先前打开的非内存资源,如文件句柄
Java源代码被编译成字节码(.class文件),字节码是一种只有JVM才能识别的二进制低级代码,它与具体的处理器无关,要由安装在OS之上的JVM解释执行,转换成相应平台的机器码,因此Java是体系结构中立和跨平台的 而C++直接被编译成底层平台的二进制机器码,由CPU执行,是平台相关的 因此,当解释执行时,Java程序速度更慢
Java语言支持多线程,允许并发线程的同步与互斥操作
C++则没有这种内在机制

太多了,就说三个吧:
1,Java有接口(interface),C++没
2,Java不支持多重继承,C++可以
3,Java一般编译为.class的虚拟机代码, C++可以编译为本地平台的二进制代码
4,Java内置了垃圾收集器不用程序管理内存,C++一般需要自己维护内存
首先java和cC++都是经典的语言,但是二者却有着惊人的相似,对于面向对象的思想如出一辙!
但是C++却相对比java难点,一方面是因为指针和对象的建立与销毁,内存的分配C++要程序员自己处理,而且要编出高效的代码就需要一定的联系与经验的!
Java就不同,可以说是C++的精简版,对很多的处理都做了人性化的简化,更容易上手!C++对于底层通信,可以说了语言界的老大,而且API很全很丰富,大型的网游,游戏十之八九都是用它开发的。
而Java注重于web开发(后来发展出来的),因为其与平台的无关性,所以今年飞速发展-----可能是web时代的带动!你如果有C++基础,学java简直就是飞速,看下就明白了!但是学过java学C++,会比没有基础的人强,但是要费劲点。C++还是非常有市场潜力的!语言吗------任何一门语言,只要你精通,很容易找工组!精通最好,慢慢学习,都是种思想!
JAVA和c++的区别还是挺大的,显而易见的不同点。java比c++更为高级,在java当中多数是面向对象,而c++是主函数。但是就一般参加的竞赛来说,c++的执行效率要比java快很多,要是做软件的话,还是java比较人性化,编码易懂。这只是大方面的,在具体携带的时候不同点还是有很多的,如果想知道可以留言
都是面向对象的语言,但是用的地方不一样。
java 程序的总体布局是由很多类组成的,每个类都处于一个文件中。如果所有的类都位于同一个目录(文件夹)中,Java需要使用某个类(文件)的时候,就会自动 地找到它。通过使用import语句,也可以将不同目录中的类(文件)组合起来。Java和C++中的注释在本质上是完全一样的。Java中没有全局变量。Java中没有枚举类型。Java中没有typedef。Java中没有结构或联合。可以像在C++中那样,在Java中对方法(函数)名进行重载,但在Java中不能对运算符进行重载。Java中没有多重继承,但它确实通过接口恢复了多重继承的很多功能。Java中没有模板,但它确实通过泛型恢复了模板的很多功能。在Java中,类可以有一个与类具有相同类型参数的构造器,但这个构造器没什么特殊的地位,不同于C++中的副本构造函数。

Java与C/C++有什么区别

  1. Java中对内存的分配是动态的,它采用面向对象的机制,采用运算符new为每个对象分配内存空间,而且,实际内存还会随程序运行情况而改变.程序运行中,每个, Java系统自动对内存进行扫描,对长期不用的空间作为”垃圾”进行收集,使得系统资源得到更充分地利用.按照这种机制,程序员不必关注内存管理问题,这使Java程序的编写变得简单明了,并且避免了了由于内存管理方面的差错而导致系统出问题.而C语言通过malloc()和free()这两个库函数来分别实现分配内在和释放内存空间的,C++语言中则通过运算符new和delete来分配和释放内存.在C和C++这仲机制中,程序员必须非常仔细地处理内存的使用问题.一方面,如果对己释放的内存再作释放或者对未曾分配的内存作释放,都会造成死机;而另一方面,如果对长期不用的或不再使用的内存不释放,则会浪费系统资源,甚至因此造成资源枯竭.
  2. Java不在所有类之外定义全局变量,而是在某个类中定义一种公用静态的变量来完成全局变量的功能.
  3. Java不用goto语句,而是用try-catch-finally异常处理语句来代替goto语句处理出错的功能.
  4. Java不支持头文件,面C和C++语言中都用头文件来定义类的原型,全局变量,库函数等,这种采用头文件的结构使得系统的运行维护相当繁杂.
  5. Java不支持宏定义,而是使用关键字final来定义常量,在C++中则采用宏定义来实现常量定义,这不得于程序的可读性.
  6. Java对每种数据类型都分配固定长度.比如,在Java中,int类型总是32位的,而在C和C++中,对于不同的平台,同一个数据类型分配不同的字节数,同样是int类型,在PC机中为二字节即16位,而在VAX-11中,则为32位.这使得C语言造成不可移植性,而Java则具有跨平台性(平台无关性).
  7. 类型转换不同.在C和C++中,可通过指针进行任意的类型转换,常常带来不安全性,而在Java中,运行时系统对对象的处理要进行类型相容性检查,以防止不安全的转换.
  8. 结构和联合的处理.在C和C++中,结构和联合的所有成员均为公有,这就带来了安全性问题,而在Java中根本就不包含结构和联合,所有的内容都封装在类里面
  9. Java不再使用指针.指针是C和C++中最灵活,也最容易产生错误的数据类型.由指针所进行的内存地址操作常会造成不可预知的错误,同时通过指针对某个内存地址进行显式类型转换后,可以访问一个C++中的私有成员,从而破坏安全性.而Java对指针进行完全地控制,程序员不能直接进行任何指针操作.
C++和JAVA的区别JAVA和C++的区别介绍框架纲领如下:(一) 序言:(二) 我学习二者的个人感受:(三) 个人建议:(四) 用JAVA中继承的特性来描述C++和JAVA的关系图示:(五) JAVA和C++的区别(前言导读):(六) JAVA和C++的基本区别(开始华山论剑)1)JAVA摒弃的C++内容。2)JAVA的新特性。3)JAVA和C++都有却不同的特性.(七) JAVA和C++的区别详细介绍(对部分知识点的扩充):(八) C++与JAVA区别小总结:开始进行:(一)序言:本人整理的资料几乎涵盖了所有的方面,也可以说包含了用百度搜索能搜到的几乎所有的内容,并参考有关书籍资料,耗时将近12个小时。可以说它 是互联网上资料最全面、最具有代表性的二者的区别总汇,当然它没有一本专门介绍二者区别的书更具有权威性和全面性,但是我相信你通过这些内容足以解决你在 实际工作或学习中遇到的编程问题!其中所涉及到的内容不乏有拷贝的内容,但大部分是经过自己分析和思考而整理出来的,并对某些别人上传到互联网上的资料做了进一步的修改和说明。不是说我们从别人那里ctrl+c一下放到自己的家门儿就算是ok了,我们尽可能的要向资料的准确性和版权性付相应的责任。  这样一方面对自己有很大的提高,另一方面只有这样才能给广大同仁提供更准确和更丰富的信息内容,大家才能共同提高和进步.(二)我学习二者的个人感受:我最初学习的是Java,后来又学习C++,虽然二者都是面向对象的语言(C++是半面向对象语言),但是在C++的学习过程中,C++“几乎完全”没有规则性或者超灵活性的语法让一个之前学过JAVA语言的人感到很不爽!!!  Java确实是个很不错的东西,尤其是其背后有强大的类库做支撑,用起来感觉那是相当的爽,但速度也确实是个问题。幸好现在的Java语言,其执行方式已经不仅仅是解释执行方式了,即时编译器(JITC、just-in-time compiler)技术和原型编译技术的出现大大提高了JAVA的运行效率。  C++灵活无比,但纯属高级玩具或者高深的九阳神功,假如玩不好,就把自己绕进去,如练奇门遁甲一般走火入魔,如果玩好了,那可就是强大致极啊!  C++在设计时因为必须完全兼容C语言又必须提供所有的面向对象特性所以最终它的结构变得特别复杂,当引入泛型编程STL(标准模板库)之后显得更加复杂。  Java是在C++的基础上开发出来的,比C++简化很多,容易使用很多,但是在有些方面特别是泛型方面明显没有C++使用起来灵活。在某些功能上也稍逊于C++,例如对于图像的剪切等方面的技术。(三)个人建议:所以我认为如果先学习C++再来学习JAVA会容易很多。先学C++就好比一开始你是穿着裤子进行110米跨栏,再学习JAVA就好比你是穿着裤衩进行跨栏,没有那么多的乱七八糟的东西或者越弄越复杂的东西,显得干净利落,在增加了多个新特性后又不失功能的强大。要不有人曾经打比方说:Java就是C++这个超级重装骑兵脱下盔甲下了马换上短剑拿起轻盾再背一把可替换的AK47。  当然,如果有人想学习JAVA,也没有必要非得从C++开始学起,我说的是如果有人需要两种语言都学的话,这个流程还是可以考虑的!(四)下面我用一个JAVA中继承的特性来描述C++和JAVA的关系:class C++{   protected String attribute=”构造函数、new关键字等等”;   C++( ){System.out.println(“我C++是JAVA的爸爸!”);}   void C++的家产( ){   System.out.println(“我有家财万贯:结构体或联合体、枚举、指针、操作符重载、预处理、支持自动的类型转换、全局变量或全局函数、多 继承析构函数、支持typedef、可以声明无符号整数、goto语句、delete操作符、标准库函数、wchar_t型、支持异常处理等等”);}}class Java extends C++ {   //我完全继承了父亲的属性  Java( ){System.out.println(“我JAVA是C++的儿子!”);}   void C++的家产( )//儿子重写C++的家产( )这个方法{   System.out.println(“我有更值钱的东西:我用类来代替结构体、我有API来代替标准库函数、我有finalize( )函数来代替析构函数、我的char类型是16位的Unicode字符来代替wchar_t型、内置的字符串类型String来代替C++中的string类、我捕捉一个被引发的异常来代替C++的异常处理机制。”);}   void JAVA新属性( ) {System.out.println(“我不单单和父亲在相同的领域做的比他更好,我还涉及了他没有涉及到的领域:我拥有自己的包、多线程和接口、自动 内存管理机制、>>>操作完成无符号的右移、文档注释等等多元化的市场策略,涉及到了房地产、金融、健身美容、生物医药等领域,呵 呵!”); } }(五)JAVA和C++的区别(前言导读): JAVA和C++都是面向对象语言。也就是说,它们都能够实现面向对象思想(封装,继乘,多态)。而由于c++为了照顾大量的C语言使用者,从而兼容了C,使得自身仅仅成为了带类的C语言,多多少少影响了其面向对象的彻底性!JAVA则是完全的面向对象语言,它句法更清晰,规模更小,更易学。它是在对多种程序设计语言进行了深入细致研究的基础上,摒弃了其他语言的不足之处,从根本上解决了c++的固有缺陷。  用C++可以使用纯过程化的编程,也可以是基于对象的编程,还可以是面向对象的编程,当然大部分是混合编程,c++可以跨平台(我强调一下必须是用标准C++,就是调用标准库函数写的程序跨平台才能非常容易,不能跨平台的是VC++等IDE(也就是说你用VC++写出来的C++程序就不能跨平台,其实Linux下的G++编译器对标准C++支持得很好,注意:不要混淆C++和VC++的概念。)[/color]java是纯面向对象的语言,其最大的特色Write once ,Run anywhere!  作为一名C++程序员,我们早已掌握了面向对象程序设计的基本概念,而且Java的语法无疑是非常熟悉的。事实上,Java本来就是从C++衍生出来的, 而且Java语言的对象模型几乎就是C++对象模型的简化版。然而,C++和Java之间仍存在一些显著的差异。可以这样说,这些差异代表着技术的极大进 步。一旦我们弄清楚了这些差异,就会理解为什么说Java是一种优秀的程序设计语言。Java和c++的相似之处多于不同之处,但两种语言因为有几处主要的不同使得Java更容易学习,并且编程环境更为简单。(六)JAVA和C++的基本区别(开始华山论剑)先来探讨一下C++和JAVA的基本区别。  这些不同之处大致分为三类:  1)JAVA不支持的C++特性。  2)JAVA的独特之处。  3)C++和JAVA都有但是却不相同的特性。详细讨论这三类: 1)JAVA摒弃的C++内容.有些C++的内容特性JAVA并不再支持。在某些情况下,一个特殊的C++特性和JAVA的运行环境不相关。另一些情况下,JAVA的设计者舍弃了C++中某些重复的内容。还有一些情况是,出于对Internet applet的运行安全问题的考虑,JAVA不再支持某些C++的特点。  C++和JAVA之间的最大不同可能是JAVA不再支持指针。指针使C++语言成为功能最强大最重要的一种编程语言。但同时指针在使用不正确的情况下也是C++中最危险的部分。JAVA不支持指针的原因主要有两点:  (1)指针本身就非常不安全。例如,使用C++的状态指针,可以访问程序代码和数据段外的内存地址,一个恶意程序可以利用这个特点破坏系统,完成非法访问(如获取口令等),或者违反安全限制。  (2)即使指针可以被限制在JAVA的运行系统中(这在理论上是可行的,因为JAVA程序是解释执行的),JAVA的设计者相信它们仍然是麻烦所在。  注意:既然JAVA中不存在指针,那么也不存在->操作符。这里还有一些非常重要的”省略”:a)JAVA不再支持操作符重载。操作符重载在某些情况下造成类C++程序的含糊不清,JAVA的设计人员感觉它带来的麻烦要比它带来的好处多。b)JAVA不再包含结构或者联合。在可以完全包含它们的类出现后,这些结构成为冗余部分。c)JAVA不再包括预处理,也不再支持预处理指令。预处理在C++语言中已经不如C中那么重要,JAVA的设计者认为是彻底消除预处理的时候了。  d)JAVA不支持自动的类型转换,因为这种类型转换导致精度降低例如当从长整型转换为整型时,必须显示强制执行类型转换。  e)在JAVA中的代码必须封装在一个或者多个类中。因此JAVA中不再包含所谓的全局变量或者全局函数。  f)JAVA不再允许默认参数。在C++中,当过程调用时存在没有对应值的参数时可以使用一个预先指定的值。JAVA不再允许这样的操作。  g)JAVA不支持多继承,即不允许一个子类继承多个父类。h)虽然JAVA支持构造函数,但是不再支持析构函数[/b]。但是,JAVA增加了finalize( )函数。i)JAVA不再支持typedef.   j)在JAVA中不再可能声明无符号整数。  k)JAVA不再支持goto语句。  l)JAVA不再有delete操作符。  m)JAVA中的<>不再重载I/O操作。  n)JAVA中,对象只能由引用传递,C++中对象可由值或引用传递.2)、JAVA的新特性。 JAVA中的许多特性是C++中没有的。其中最重要的三个方面是多线程、包和接口,还有其他的许多独特之处都丰富了JAVA编程环境。  1)多线程允许两个或者多个相同的线程并发运行。而且,这是一种在语言级支持的并发机制。C++中没有类似的机制,或者说C++采用的是单线程的体系结构。如果需要并发执行一个C++程序,必须利用操作系统的功能手工启动。虽然这两种方法都可以同时执行两个或者多个线程,但是JAVA的方法清楚而且便于使用。 2)C++中没有可以与JAVA包对应的特性。[/b]最近似的是用一个公用头文件的一组库函数。然而,在C++中构建和使用库函数与在JAVA中构建包和使用包是完全不同的。  3)JAVA的接口与C++的抽象类相似(C++中的抽象类是包括至少一个纯虚函数的类)。[/b]例如,C++的抽象类和JAVA的接口都不能创建实例。两者都用于指定一个子类实现的一致接口。两者之间最大的不同之处在于接口更清晰的表明了这个概念。  4)JAVA提供一个流线型的内存分配机制。与C++类似,JAVA支持new这个关键字。但是,不支持delete关键字。当对象的最后一个引用撤销时,对象本身被自动地删除,并进行内存垃圾回收。  5)JAVA丢弃了C++的标准库,将它替换成自己的API类集合。[/b]它们功能上有相似之处,但是名字和参数有显著的不同。同时,因为所有的JAVA API库都是面向对象的,而C++库只有部分是,所以库例程调用的方式不同。  6)JAVA增强了break和continue语句以接收标记。 JAVA中的char类型是国际通用的16位Unicode字符集,所以能自动表达大多数国家的字符。这与C++中的wchar_t型相似。使用Unicode字符增强了代码的可移植性。  7)JAVA增加了>>>操作,完成无符号的右移。  8)除支持单行和多行的注释之外,JAVA增加了第三种注释方法:文档注释。文档注释以结尾。  9)JAVA包含一个内置的字符串类型叫做String。String在某种程度上和C++提供的标准string类很相似。当然C++中的string只有在程序中声明后方可使用,它并不是内置的类型3)、JAVA和C++的不同的特性。1)JAVA和C++都支持布尔类型的数据,但是JAVA实现true和false的方式和C++不同。在C++中,true是非零值,false是零。在JAVA中,true and false都是预先定义好的常量,并且是一个布尔表达式能得到的唯一的两个值。虽然C++也定义了true and false ,并指定为布尔变量,但是C++自动将非零值转换为true,零值转换为false。这种情况在JAVA中不会出现。  2)在创建C++类时,访问说明符应用到一组声明中。而JAVA中,访问说明符仅应用于其限定的声明中。  3)C++支持异常处理,这与JAVA类似,但是在C++中无需捕捉一个被引发的异常。(七)JAVA和C++的区别详细介绍(对部分知识点的扩充) (1) JAVA的运行速度(JAVA最大的障碍在于速度)解释过的Java要比C的执行速度慢上约20倍。无论什么都不能阻止Java语言进行编译。当时刚刚出现了一些准实时编译器,它们能显著加快速度。当然, 我们完全有理由认为会出现适用于更多流行平台的纯固有编译器,但假若没有那些编译器,由于速度的限制,必须有些问题是Java不能解决的。  许多企业的应用开发人员非常喜爱Java的语言特性,但是在开发重要系统时,语言特性和执行效率之间的抉择往往令人伤透脑筋。在关键计算中,用户可能并不 在乎数据如何压缩或者运行的延迟关系如何设置,但是对程序的运行速度却非常重视,这使厂商将Java的编译策略开发放在了首位。现在的Java语言,其执 行方式已经不仅仅是解释执行方式了,即时编译器(JITC、just-in-time compiler)技术和原型编译技术已经被许多厂家采用,包括Sun、IBM、Oracle以及Netscape等公司在内的技术提供商正在利用这些技 术逐步提高Java的执行速度,其中IBM公司早已将Java虚拟机(JVM,JavaVirtual Machine)、操作系统和硬件的特性有机的结合在一起,非常有效地提高了Java的执行效率。  (2)JAVA所有东西都必须置入一个类.Java是完全面向对象的语言,它不再支持C++程序时所使用的过程式的设计方法,所有函数和变量部必须是类的一部分。除了基本数据类型(例如整型、字符型、布尔型等)之外,其他的数据对Java来说都是对象,包括数组。  对象将数据和方法结合起来,把它们封装在类中,这样每个对象都可实现自己的特点和行为。JAVA不存在全局函数或者全局数据。如果想获得与全局函数等价的 功能,可考虑将static方法和static数据置入一个类里。而c++允许将函数和变量定义为全局的。此外,Java中取消了c/c++中的结构和联 合、枚举这一类的东西,一切只有“类”(Class),消除了不必要的麻烦。  JAVA的语法其实是参照c++的语法诞生的,但是她去除了c++中的多重继承,指针,delete等难于掌握的技术,为了便于移植和安全性,java采用了纯面向对象技术,即使是主函数public static void main(String[] args){}也要放在主类中,可以看出和C++的明显区别。  (3) 在Java中,类定义采取几乎和C++同样的形式。但没有标志结束的分号。没有类声明,只有类定义。 (4) Java中没有作用域范围运算符“::”.Java利用点号做所有的事情,但可以不用考虑它,因为只能在一个类里定义元素。即使那些方法定义,也必须在一个类的内部,所以根本没有必要指定作用域的范围。我们注意到的一项差异是对static方法的调用:使用ClassName.methodName()。  除此以外,package(包)的名字是用点号建立的,并能用import关键字实现C++的“#include”的一部分功能。  例如下面这个语句:import java.awt.*;   #include并不直接映射成import,但在使用时有类似的感觉。若想使用另一个库里的类,只需使用import命令,并指定库名即可。不存在类似于预处理机的宏。  c/c十十在编译过程中都有一个预编译阶段,即众所周知的预处理器。预处理器为开发人员提供了方便,但增加了编译的复杂性。JAVA虚拟机没有预处理器, 但它提供的引入语句(import)与c十十预处理器(#include)的功能类似。(注意:只是类似而已) (5)JAVA中没有预处理功能的详细介 绍不再有#define、#include等预处理程序(Preprocessor)的功能。C++语言很重要的一个特点就是它的预处理程序。有些其他程序 语言虽然也加入了#include的功能,但是还是欠缺处理宏(Macro)的能力。#define的功能在Java中我们可以用定义常数 (constant)的方式来取代,而#include在Java中是不需要的,因为在Java中程序在执行时,会把类型数据记录在对象实体之中,我们不 需要靠一些标头文件(header file)来知道我们使用的对象或数值是属于什么数据类型。  如果你使用C++语言时,只使用预处理程序的#include和#define功能的话,那么你大概不会觉得Java这样的设计对你产生什么样的困扰,但是如果你是使用C++语言预处理程序中宏功能的高手,你可能会觉得很不方便,进而怀疑Java如此设计的意义何在。  使用预处理程序虽然可以很方便地达到许多功能,但是站在软件工程的角度上看,对整个软件的维护其实是很不利的。由于C++语言中预处理程序的功能太过强 大,厉害的程序设计高手常会自行开发一套只有自己看的懂的宏语言,一旦整个软件要交给其他人去维护,后继者很难在短时间内了解前一个人所写下的宏功能,增 加软件开发时团队工作及日后维护的困难度。  另外一点则是C++语言的编译器所看到的程序代码,其实和程序设计者看到的程序代码是不同的。程序设计者看到的是尚未经过预处理程序处理过的程序代码,而 编译器看到的则是预处理程序处理过的程序代码,一旦交给预处理程序处理的宏内容有误,编译器产生的错误信息将不会是程序设计师所预料的。而这一点自然也增 加了程序在排错时的困难度。  预处理程序的存在也造成了阅读程序的不便。如果你想使用别人已经完成的C++语言程序,那么通常你不但要阅读他所写下的文件,还必须一并查阅上文件,才能了解其程序的全貌。如果换成是Java程序,只要查看java的程序文件就够了。  (6)与C++类似,Java含有一系列“主类型”(Primitive type),以实现更有效率的访问   在Java中,这些类型包括boolean,char,byte,short,int,long,float以及double.所有主类型的大小都是 固有的,且与具体的机器无关(考虑到移植的问题)。这肯定会对性能造成一定的影响,具体取决于不同的机器。对类型的检查和要求在Java里变得更苛刻。   例如:  条件表达式只能是boolean(布尔)类型,不可使用整数。  必须使用象X+Y这样的一个表达式的结果;不能仅仅用“X+Y”来实现“副作用”。  (7)Java静态引用的字串会自动转换成String对象。[/b][/color]   java和C及C++不同,没有独立的静态字符数组字串可供使用。  c和c十十不支持字符串变量,在c和c十十程序中使用Null终止符代表字符串的结束,在Java中字符串是用类对象(string和stringBuffer)来实现的,这些类对象是Java语言的核心,用类对象实现字符串有以下几个优点:  a)在整个系统中建立字符串和访问字符串元素的方法是一致的;  b)Java字符串类是作为Java语言的一部分定义的,而不是作为外加的延伸部分;  c)Java字符串执行运行时检查,可帮助排除一些运行时发生的错误;  d)可对字符串用“十”号进行连接操作。(8) Java增添了三个右移位运算符“>>>”,具有与“逻辑”右移位运算符类似的功用,可在最末尾插入零值。“>>”则会在移位的同时插入符号位(即“算术”移位)。(9) 尽管表面上类似,但与C++相比,Java数组采用的是一个颇为不同的结构,并具有独特的行为。就是说Java提供数据下标越界检查,而C++没有提供.有一个只读的length成员,通过它可知道数组有多大。而且一旦超过数组边界,运行期检查会自动丢弃一个异常。所有数组都是在内存“堆”里创建的,我们 可将一个数组分配给另一个(只是简单地复制数组句柄)。数组标识符属于第一级对象,它的所有方法通常都适用于其他所有对象。 (10) 对于所有不属于主类型的对象,都只能通过new命令创建 和C++不同,Java没有相应的命令可以“在堆栈上”创建不属于主类型的对象。所有主类型都只 能在堆栈上创建,同时不使用new命令。所有主要的类都有自己的“封装(器)”类,所以能够通过new创建等价的、以内存“堆”为基础的对象(主类型数组 是一个例外:它们可象C++那样通过集合初始化进行分配,或者使用new).(11) Java中不必进行提前声明方法。   若想在定义前使用一个类或方法,只需直接使用它即可——编译器会保证使用恰当的定义。所以和在C++中不同,我们不会碰到任何涉及提前引用的问题。  (12) Java用包代替了命名空间。   由于将所有东西都置入一个类,而且由于采用了一种名为 “封装”的机制,它能针对类名进行类似于命名空间分解的操作,所以命名的问题不再进入我们的考虑之列。数据包也会在单独一个库名下收集库的组件。我们只需简单地“import“(导入)一个包,剩下的工作会由编译器自动完成。  (13) 被定义成类成员的对象句柄会自动初始化成null。  对基本类数据成员的初始化在Java里得到了可靠的保障。若不明确地进行初始化,它们就会得到一个默认值(零或等价的值)可对它们进行明确的初始化(显式 初始化):要么在类内定义它们,要么在构建器中定义。采用的语法比C++的语法更容易理解,而且对于static和非static成员来说都是固定不变 的。我们不必从外部定义static成员的存储方式,这和C++是不同的。  (14) 在Java里,没有象C和C++那样的指针。   用new创建一个对象的时候,会获得一个引用(或者叫句柄)  例如: Strings = new String("helloworld");   然而,C++引用在创建时必须进行初始化,而且不可重定义到一个不同的位置。但Java引用并不一定局限于创建时的位置。它们可根据情况任意定义,这便消除了对指针的部分需求。  在C和C++里大量采用指针的另一个原因是为了能指向任意一个内存位置(这同时会使它们变得不安全,也是Java不提供这一支持的原因)。指针通常被看作 在基本变量数组中四处移动的一种有效手段。Java允许我们以更安全的形式达到相同的目标。解决指针问题的终极方法是“固有方法”。将指针传递给方法时, 通常不会带来太大的问题,因为此时没有全局函数,只有类。而且我们可传递对对象的引用。Java语言最开始声称自己“完全不采用指针!”但随着许多程序员 都质问没有指针如何工作?于是后来又声明“采用受到限制的指针”(有人管它叫隐藏了的指针)。大家可自行判断它是否“真”的是一个指针。但不管在何种情况 下,都不存在指针“算术”。  JAVA语言让编程者无法找到指针来直接访问内存无指针,并且增添了自动的内存管理功能,从而有效地防止了c/c++语言中指针操作失误,如野指针所造成 的系统崩溃。但也不是说JAVA没有指针,虚拟机内部还是使用了指针,只是外人不得使用而已。这有利于Java程序的安全。    其实,取消指针(Pointer)这样数据类型,可能会让许多熟悉C++语言的程序设计师大吃一惊。在C++语言里,灵活地运用指针是许多程序设计师的得 意之作,但是占整个除错时间最久的也是指针的问题。配合上C++对内存管理的态度,程序设计师必须要自己去追踪自己向系统要到的内存,最后确实地交还给系 统,并且在使用指针时,要小心翼翼地注意不要跨过合法的记忆空间,造成Segmentation Fault或General Protection Fault之类的问题。  Java去掉了指针类型,并不表示程序设计师在开发高级数据结构,像堆栈(stack)、队列(queue)、二元树(binarytree)时,都必须要像在传统Basic上,利用大范围的数组来自行模拟系统内存,自行建构类似指针的表示方式。  相反地,Java提供了和Lisp语言中相似的Reference类型,通过Reference去读取配置到的内存内容,可以确保不会去读取到不属于自己 的内存空间,而另一方面,程序的执行系统也可以动态地去做内存垃圾回收的工作,将没有被reference参考到的内存空间回收给系统使用。   ff(15) Java提供了与C++类似的“构建器”(Constructor)。    如果不自己定义一个,就会获得一个默认构建器。而如果定义了一个非默认的构建器,就不会为我们自动定义默认构建器。这和C++是一样的。注意没有复制构建器,因为所有自变量都是按引用传递的(注意:而C++中对象可由值或引用传递。)  (16) Java中没有“破坏器”(Destructor)。   变量不存在“作用域”的问题。一个对象的“存在时间”是由对象的存在时间决定的,并非由垃圾收集器决定。有个finalize()方法是每一个类的成员, 它在某种程度上类似于C++的“破坏器(就是析构函数的使用)”。但finalize()是由垃圾收集器调用的,而且只负责释放“资源”(如打开的文件、 套接字、端口、URL等等)。如需在一个特定的地点做某样事情,必须创建一个特殊的方法,并调用它,不能依赖finalize()。而在另一方面,C++ 中的所有对象都会(或者说“应该”)破坏,但并非Java中的所有对象都会被当作“垃圾”收集掉。由于Java不支持破坏器的概念,所以在必要的时候,必 须谨慎地创建一个清除方法。而且针对类内的基础类以及成员对象,需要明确调用所有清除方法。  (17) Java具有方法“重载”机制,它的工作原理与C++函数的重载载几乎是完全相同的。  (18) Java不支持默认自变量。   (19) Java中没有goto语句。Java一方面移除了Goto的功能,它采取的无条件跳转机制是“break 标签”或者“continue 标签” ,另一方面同时扩大了break和continue的功能,可以允许多层循环的break或continue。如此一来不但避免了滥用Goto的可能性,同时也保存下Goto的好处。  “可怕”的goto语句是c和c++的“遗物”,它是该语言技术上的合法部分,引用goto语句引起了程序结构的混乱,不易理解,goto语句主要用于无 条件转移子程序和多结构分支技术。鉴于以上理由,Java不提供goto语句,也不提供goto关键字和of、const关键字,使程序简洁易读。(注 意:有些书上会说java也提供goto关键字,但是不使用,我不知道以前的说法如何,你只要记住java里边没有goto这个东西就可以了。而且不能用 goto做为对象名字、引用或方法名、类名等。)  在程序语言的发展史上,Goto一直是毁誉参半的一项功能。在很多时候使用Goto可以大幅减少不必要的程序代码,但是也由于Goto可以很自由地改变程 序的流程,如果冒然地使用,更可能造成程序结构混乱的情况。一般来说,正确使用Goto的例子多出现在循环内部,想要提早结束某一层循环。在C语言中,我 们可以使用break 或contine来改变某一层循环的流程,但如果想要改变两层以上的环执行流程,不是使用Goto就是以多余的布尔(boolean)变量,配合上一串 if-then-else的判断来达成。  (20) Java采用了一种单根式的分级结构,因此所有对象都是从根类Object统一继承的。   而在C++中,我们可在任何地方启动一个新的继承树,所以最后往往看到包含了大量树的“一片森林”。在Java中,我们无论如何都只有一个分级结构。尽管 这表面上看似乎造成了限制,但由于我们知道每个对象肯定至少有一个Object接口,所以往往能获得更强大的能力。C++目前似乎是唯一没有强制单根结构 的唯一一种OO(面向对象)语言。  (21) Java没有模板或者参数化类型的其他形式。   它提供了一系列集合:Vector(向量),Stack(堆栈)以及Hashtable(散列表),用于容纳Object引用。利用这些集合,我们的一系列要求可得到满足。但这些集合并非是为实现象C++“标准模板库”(STL)那样的快速调用而设计的。Java 1.2中的新集合显得更加完整,但仍不具备正宗模板那样的高效率使用手段。  (22)“垃圾收集”意味着在Java中出现内存漏洞的情况会少得多,但也并非完全不可能。    若调用一个用于分配存储空间的固有方法,垃圾收集器就不能对其进行跟踪监视。  然而,内存漏洞和资源漏洞多是由于编写不当的finalize()造成的,或是由于在已分配的一个块尾释放一种资源造成的(“破坏器”在此时显得特别方 便)。垃圾收集器是在C++基础上的一种极大进步,使许多编程问题消弥于无形之中。但对少数几个垃圾收集器力有不逮的问题,它却是不大适合的。但垃圾收集 器的大量优点也使这一处缺点显得微不足道。  (23) Java内建了对多线程的支持。   利用一个特殊的Thread类,我们可通过继承创建一个新线程(放弃了run()方法)。若将synchronized(同步)关键字作为方法的一个类型 限制符使用,相互排斥现象会在对象这一级发生。在任何给定的时间,只有一个线程能使用一个对象的synchronized方法。在另一方面,一个 synchronized方法进入以后,它首先会“锁定”对象,防止其他任何synchronized方法再使用那个对象。只有退出了这个方法,才会将对 象“解锁”。在线程之间,我们仍然要负责实现更复杂的同步机制,方法是创建自己的“监视器”类。递归的synchronized方法可以正常运作。若线程 的优先等级相同,则时间的“分片”不能得到保证。  (24)我们不是象C++那样控制声明代码块,而是将访问限定符(public,private和 protected)置入每个类成员的定义里。    JAVA中若未规定一个“显式”(明确的)限定符,就会默认为“友好的”(friendly)。这意味着同一个包里的其他元素也可以访问它(相当于它们都成为 C++的“friends”——朋友),但不可由包外的任何元素访问。而在C++中如果未规定就会默认为私有的private。  类——以及类内的每个方法——都有一个访问限定符,决定它是否能在文件的外部“可见”private关键字通常很少在Java中使用,因为与排斥同一个包 内其他类的访问相比,“友好的”访问通常更加有用。  然而,在多线程的环境中,对private的恰当运用是非常重要的。Java的protected 关键字意味着“可由继承者访问,亦可由包内其他元素访问”。注意Java没有与C++的protected关键字等价的元素,后者意味着“只能由继承者访 问”(以前可用“private protected”实现这个目的,但这一对关键字的组合已被取消了)  (25) 嵌套的类。    在C++中,对类进行嵌套有助于隐藏名称,并便于代码的组织(但C++的“命名空间”已使名称的隐藏显得多余)。Java的“封装”或“打包”概念等价于 C++的命名空间,所以不再是一个问题。Java 1.1引入了“内部类”的概念,它秘密保持指向外部类的一个句柄——创建内部类对象的时候需要用到。这意味着内部类对象也许能访问外部类对象的成员,毋需 任何条件——就好象那些成员直接隶属于内部类对象一样。这样便为回调问题提供了一个更优秀的方案——C++是用指向成员的指针解决的。(由于存在前面介绍 的那种内部类,所以Java里没有指向成员的指针。 )   (26) Java不存在“嵌入”(inline)方法。   JAVA所有方法都是在类的主体定义的。所以用C++的眼光看,似乎所有函数都已嵌入,但实情并非如此。Java编译器也许会自行决定嵌入一个方法,但我 们对此没有更多的控制权力。在Java中,可为一个方法使用final关键字,从而“建议”进行嵌入操作。然而,嵌入函数对于C++的编译器来说也只是一 种建议。  (27) Java中的继承具有与C++相同的效果,但采用的语法不同。   Java用extends关键字标志从一个基础类的继承,并用super关键字指出准备在基础类中调用的方法,它与我们当前所在的方法具有相同的名字(然 而,Java中的super关键字只允许我们访问父类的方法——亦即分级结构的上一级)。通过在C++中设定基础类的作用域,我们可访问位于分级结构较深 处的方法。亦可用super关键字调用基础类构建器。正如早先指出的那样,所有类最终都会从Object里自动继承。和C++不同,不存在明确的构建器初 始化列表。但编译器会强迫我们在构建器主体的开头进行全部的基础类初始化,而且不允许我们在主体的后面部分进行这一工作。通过组合运用自动初始化以及来自 未初始化对象句柄的异常,成员的初始化可得到有效的保证。  b举例说明public class Foo extends Bar{   publicFoo(String msg) {      super(msg);  Calls base constructor }      public baz(int i)   {  Override         super.baz(i);        Calls base method    }  }   (28) Java中的继承不会改变基础类成员的保护级别。   我们不能在Java中指定public,priv ate或者protected继承,这一点与C++是相同的。此外,在衍生类中的优先方法不能减少对基础类方法的访问。例如,假设一个成员在基础类中属于public,而我们用另一个方法代替了它,那么用于替换的方法也必须属于public(编译器会自动检查)。  (29) Java提供了一个interface关键字,它的作用是创建抽象基础类的一个等价物。    在其中填充抽象方法,且没有数据成员。这样一来,对于仅仅设计成一个接口的东西,以及对于用extends关键字在现有功能基础上的扩展,两者之间便产生 了一个明显的差异。不值得用abstract关键字产生一种类似的效果,因为我们不能创建属于那个类的一个对象。一个abstract(抽象)类可包含抽 象方法(尽管并不要求在它里面包含什么东西),但它也能包含用于具体实现的代码。因此,它被限制成一个单一的继承。通过与接口联合使用,这一方案避免了对 类似于C++虚拟基础类那样的一些机制的需要。  为创建可进行“例示”(即创建一个实例)的一个interface(接口)的版本,需使用implements关键字。它的语法类似于继承的语法,如下所示:public interface Face{      public void smile();} public class Baz extends Bar implements Face{      public void smile( )  {     System.out.println("a warm smile");   }}   (30) Java中没有virtual关键字,因为所有非static方法都肯定会用到动态绑定。    在Java中,程序员不必自行决定是否使用动态绑定。C++之所以采用了virtual,是由于我们对性能进行调整的时候,可通过将其省略,从而获得执行 效率的少量提升(或者换句话说:“如果不用,就没必要为它付出代价”)。virtual经常会造成一定程度的混淆,而且获得令人不快的结果。final关 键字为性能的调整规定了一些范围——它向编译器指出这种方法不能被取代,所以它的范围可能被静态约束(而且成为嵌入状态,所以使用C++非virtual 调用的等价方式)。这些优化工作是由编译器完成的。  (31) Java不提供多重继承机制(MI),至少不象C++那样做。   与protected类似,MI表面上是一个很不错的主意,但只有真正面对一个特定的设计问题时,才知道自己需要它。由于Java使用的是“单根”分级结构,所以只有在极少的场合才需要用到MI。interface关键字会帮助我们自动完成多个接口的合并工作。  c++支持多重继承,这是c++的一个特征,它允许多父类派生一个类。尽管多重继承功能很强,但使用复杂,而且会引起许多麻烦,编译程序实现它也很不容 易。Java不支持多重继承,但允许一个类继承多个接口(extends+implement),实现了c++多重继承的功能,又避免了c++中的多重继 承实现方式带来的诸多不便。所谓的interface基本上定义了一个类的对外沟通的方法原型,以及类内部的常数,和多重继承不同之处在于interface并不会定义类方法的内容,以及类中的变量数据。  (32) 运行期的类型标识功能与C++极为相似。   例如,为获得与句柄X有关的信息,可使用下述代码:  X.getClass().getName();   为进行一个“类型安全”的紧缩造型,可使用:  derived d = (derived)base;   这与旧式风格的C造型是一样的。编译器会自动调用动态造型机制,不要求使用额外的语法。尽管它并不象C++的“new casts”那样具有易于定位造型的优点,但Java会检查使用情况,并丢弃那些“异常”,所以它不会象C++那样允许坏造型的存在。  (33) Java采取了不同的异常控制机制,因为此时已经不存在构建器。   可添加一个finally从句,强制执行特定的语句,以便进行必要的清除工作。Java中的所有异常都是从基础类Throwable里继承而来的,所以可确保我们得到的是一个通用接口。public void f(Obj b) throws IOException{      myresource mr = b.createResource();      try   {      mr.UseResource();      } catch(MyException e)   {  handle my exception   }        catch(Throwable e)    {         handle all other exceptions    }         finally{ mr.dispose();  special cleanup } }   (34) Java的异常规范比C++的出色得多。   JAVA中的异常机制用于捕获例外事件,增强系统容错能力  如代码所示:try{      可能产生例外的代码  } catch(exceptionType name)其中exceptionType表示异常类型。{ 处理 }   而C++则没有如此方便的机制。  java丢弃一个错误的异常后,不是象C++那样在运行期间调用一个函数,Java异常规范是在编译期间检查并执行的。除此以外,被取代的方法必须遵守那 一方法的基础类版本的异常规范:它们可丢弃指定的异常或者从那些异常衍生出来的其他异常。这样一来,我们最终得到的是更为“健壮”的异常控制代码。(35) Java具有方法重载的能力,但不允许运算符(操作符)重新载OperatorOverloading   String类不能用+和+=运算符连接不同的字串,而且String表达式使用自动的类型转换,但那是一种特殊的内建情况。(备注:在c++中的string是小写的)  Java不支持操作符重载。操作符重载被认为是c++的突出特征,在Java中虽然类大体上可以实现这样的功能,但操作符重载的方便性仍然丢失了不少。  Java语言不支持操作符重载是为了保持Java语言尽可能简单。 C++中使用操作符重载主要是可以使你的程序看起来更为自然。  如下面是一个程序自定义的复数类:  C++中自定义的复数类及0pemtor Overloading class Complex{   public:   Complex(double real,double image){     Real_number=real;   Image_number=image;} Complex operator+(Complex&rhs){   Return Complex(rhs.real_number+real_number,rhs.image_number+image_,nulnbef);}   private:   doublereal_number 实部  doublejmage_nunmber; 虚部 }   在这里,如果你使用+来作为复数的加法符号,大家都不会有疑义,但是如果你使用的是*或》这样的符号,那么别人看到你的程序之后,难保不会产生认识上的错误。这也是Operator Overloading一大问题,当大家都对运算符赋予自己的定义后,整个程序的可读性就会大受影响。Operator Overloading的存在并不是必要的,我们一样可以定义类中的方法来达到同样的目的.

(36) 通过事先的约定,C++中经常出现的const问题在Java里已得到了控制。    我们只能传递指向对象的句柄,本地副本永远不会为我们自动生成。若希望使用类似C++按值传递那样的技术,可调用clone(),生成自变量的一个本地副 本(尽管clone()的设计依然尚显粗糙)。根本不存在被自动调用的副本构建器。为创建一个编译期的常数值,可象下面这样编码:  static finalint  = 255   static finalint B = 8 *    (37) 由于安全方面的原因,“应用程序”的编程与“程序片”的编程之间存在着显著的差异。   一个最明显的问题是程序片不允许我们进行磁盘的写操作,因为这样做会造成从远程站点下载的、不明来历的程序可能胡乱改写我们的磁盘。随着Java 1.1对数字签名技术的引用,这一情况已有所改观。根据数字签名,我们可确切知道一个程序片的全部作者,并验证他们是否已获得授权。Java 1.2会进一步增强程序片的能力。  (38) 由于Java在某些场合可能显得限制太多,所以有时不愿用它执行象直接访问硬件这样的重要任务。   Java解决这个问题的方案是“固有方法”,允许我们调用由其他语言写成的函数(目前只支持C和C++)。这样一来,我们就肯定能够解决与平台有关的问题(采用一种不可移植的形式,但那些代码随后会被隔离起来)。程序片不能调用固有方法,只有应用程序才可以。  (39) Java提供对注释文档的内建支持,所以源码文件也可以包含它们自己的文档。   通过一个单独的程序,这些文档信息可以提取出来,并重新格式化成HTML。这无疑是文档管理及应用的极大进步。  (40) Java包含了一些标准库,用于完成特定的任务。   C++则依靠一些非标准的、由其他厂商提供的库。这些任务包括(或不久就要包括):  a)连网  b)数据库连接(通过JDBC)   c)多线程  d)分布式对象(通过RMI和CORBA)   e)压缩  f)商贸  由于这些库简单易用,而且非常标准,所以能极大加快应用程序的开发速度。  (41) Java 1.1包含了Java Beans标准,后者可创建在可视编程环境中使用的组件。    由于遵守同样的标准,所以可视组件能够在所有厂商的开发环境中使用。由于我们并不依赖一家厂商的方案进行可视组件的设计,所以组件的选择余地会加大,并可提高组件的效能。除此之外,Java Beans的设计非常简单,便于程序员理解;而那些由不同的厂商开发的专用组件框架则要求进行更深入的学习。  (42) 若访问Java句柄失败,就会丢弃一次异常。   这种丢弃测试并不一定要正好在使用一个句柄之前进行。根据Java的设计规范,只是说异常必须以某种形式丢弃。许多C++运行期系统也能丢弃那些由于指针错误造成的异常。  (43) Java通常显得更为健壮,为此采取的手段如下:    a)对象句柄初始化成null(一个关键字)  b)句柄肯定会得到检查,并在出错时丢弃异常  c)所有数组访问都会得到检查,及时发现边界违例情况  d)自动垃圾收集,防止出现内存漏洞  e)明确、“傻瓜式”的异常控制机制  f)为多线程提供了简单的语言支持  g)对网络程序片进行字节码校验  (44)自动内存管理机制   Java程序中所有的对象都是用new操作符建立在内存堆栈上,这个操作符类似于c++的new操作符。下面的语句由一个建立了一个类Read的对象,然后调用该对象的work方法:  Readr=new Read();  r.work();   语句Readr=new Read();在堆栈结构上建立了一个Read的实例。Java自动进行无用内存回收操作,不需要程序员进行删除。而c十十中必须由程序来释放内存资源 (就是通过new和delete运算符来分配和释放内存),增加了程序设计者的负担。Java中当一个对象不被再用到时,无用内存回收器将给它加上标签以 示删除。JAVA里无用内存回收程序是以线程方式在后台运行的,利用空闲时间工作。  C++有栈内存与堆内存两种分配方式,程序员可以根据自己的需要来选择使用哪种内存分配的方式,Java中对象只有堆分配。区别是C++中的堆分配必须程 序员手动释放,Java通过垃圾收集器自动释放。其实Java和C++的区别也主要在这里:对于一个问题,C++实现了几乎所有的解决方法,程序员可以根 据自己的需要来选择一种实现方法;而Java只提供一两种实现方法,但通常是他认为最容易用最灵活的方法。  (45)Java不支持缺省函数参数,而c十十支持    在c中,代码组织在函数中,函数可以访问程序的全局变量。c十十增加了类,提供了类算法,该算法是与类相连的函数,c十十类方法与Java类方法十分相 似,然而,由于c十十仍然支持c,所以不能阻止c十十开发人员使用函数,结果函数和方法混合使用使得程序比较混乱。(#ff0000也就是说C++里边既 有方法又有函数,我认为不能作为等同的概念来把二者混为一谈。)  Java不再有函数在Java程序语言中,去掉了程序向导语言中最重要的单元--函数(Function)。如果我们以对象向导的观念来看待函数,就可以 了解函数在对象向导的概念中,是不必要的。在对象向导的程序观念里,对象的数据才是真正的主体,而处理对象数据的方法则必须依附在对象内才有意义。因此, 去掉函数并不表示不再有子程序等模组化程序的概念,相反地,是利用对象中的方法来取代函数,再一次强化对向导的发展策略。  Java没有函数,作为一个比c十十更纯的面向对象的语言,Java强迫开发人员把所有例行程序包括在类中,事实上,用方法实现例行程序可激励开发人员更好地组织编码。  (46) 类型转换    在c和c十十中有时出现数据类型的隐含转换,这就涉及了自动强制类型转换问题。例如,在c十十中可将一浮点值赋予整型变量,并去掉其尾数。Java不支持c十十中的自动强制类型转换,如果需要,必须由程序显式进行强制类型转换。  Java是一个严格进行类型检查的程序语言,对于下面这样的程序,在C++的编译器上编译时最多只会出现警告的信息,但是在Java里则不予通过:  Int aInteger; Double aDouble=2.71828; AInteger = aDouble;  虽然这样的转型在C++里是合法的,但是也会造成数据精确度的损失。Java为了要确定写程序的人充分地了解这点,必须要程序设计强制转型(type casting),Java的编译器才会接受:   int aInteger;  doublea Double=2.71828;   aInteger=(int)aDouble;  (47)对C++而言,类库一旦升级,则必须对应用程序进行重新编译,否则就无法使用升级后类库的新增功能。而Java语言在其支持的类库升级后,只需要直接覆盖上已有的类库,不需要重新编译相应的应用程序。   (48)java不再有structure、union及typedef    事实上,早在C++中就可以去掉C语言中的structure和union等对复杂数据的自定结构类型,因为类(Class)的定义方式可以完全做到这项 功能。而typedef也是不必要的,一切都用类就可以了。虽然C++这样的设计是为了和C语言兼容,但是使用多余的语言特点不但不必要,而且容易造成对 程序认识的混淆。  (49)和C++连接    不管Java是多么强大,总是有人需要把它和C++连接起来。因为只要有一个新的程序语言或是软件开发工具一出现,大家就会问:"它是否具有和原有程序库 连接的能力呢?"也因为C++语言在电脑界中占了很重要的地位。大家的问题其实就等于是直接问"它是否可以和C++连接?"。目前在Java中,的确提供 了和C++语言连接的方法,它的做法基本上是先将C++语言所写的程序建构成动态链接函数库(DynamicLinking Library,DLL),再由Java程序去调用DLL里的函数。  这种连接的方式,使得DLL中的函数,从Java的眼光看就是一个"方法"。不过因为这种方法是直接由其他的程序语言所提供,而不是以Java语言所写的,所以它被称之为"原生方法"(NativeMethod)。由于Java Applet一些安全上的限制,所以这种连接外部程序的方法只能用在Java Application内50)C++的跨平台问题!   Java编译器所生成的代码可以不基于任何具体的硬件平台,而是基于一种抽象的机器---虚拟机。而c,c++的源程序要在不同平台上运行,必须重新编译。  不论是C还是C++都会有依赖平台与实现的不同比如int的大小。  由于C以及C++库功能基本都是最简化的。所以基本没法开发什么比较有用处的可移植代码.比如GUI的不同,socket实现的不同等等都制约了C++的可移植性  如果你要写一个完全可以跨平台编译的代码,只能依靠标准库来写,那样这个程序的功能就一定非常有限.当然也有一些跨平台的库可以使用.比如GUI方面的 wxWidgets等等  不过尽管如此.我们还是可以做一些工作来方便移植工作。不要假想平台的硬件环境,如果你要做一些对字节操作或者位操作的内容, 最好注意big endian以及small endian问题不同的平台实现不同.不要假想字节长度,int的大小是32,但是不同实现里面可能有不同的长度.这依赖实现,虽然大多数的实现都使用几 乎相同的标准。尽量不要操作底层的内容  基于上面两条,我们可以得出可移植性最高的代码,应该是那些不对位或者字节进行直接操作的.不对指针内容进行修 改的,大多调用标准库函数的.不使用高级模板功能的代码。  Linux下的G++编译器对标准C++支持得很好。如果做手机游戏,要用C++,nokia需要Symbian提供的C++开发环 境,smartphone则可以用vs.net提供的。这些环境开发出来的代码,都是与平台相关的。然而如果是游戏的话想跨平台就用J2ME吧!  纯c++代码的话,跨平台十分简单,重新编译就是了。但实际上哪有纯c++的软件?c++算是较底层的语言,所以用它写软件难免要出现平台相关的东西,这就是移植时要修改的重点。  总的来说,跨平台性还是不错的  C++的跨平台就只有两点。  1,遵循标准。特定的平台除外。  2,禁用reinterpret_cast和C风格的强制转换。   #ff0000当然上边说的两点只是针对与跨编译器。但是,如果说 OS 平台,那么基本所有功能都是与平台相关的,包括网络、文件系统等显而易见的功能,以及 IO、内存分配等那么不显而易见的。要让 C++ 代码跨平台,我们只能通过包装库来掩盖不同平台的区别,这样,基于这些包装库的 C++ 程序才能在【源码级别】实现“跨平台”。  跨平台当然要注意避免使用依赖系统的操作:  1. 基本类型的长度以及相对这些类型的操作,如wchar_t。  2. 字符操作,特别是汉字类的宽字符。  3. IO操作  另外不同编译器对C++的实现是不同的,这就要编译一下试验一下,不过这种问题都很容易修改的!  我感觉越涉及到底层的东西,越难实现跨平台。不同的硬件体系结构,不同的编译器和编译环境,都给跨平台带来了很多的困难。如果要写出跨平台的程序,尽量使用跨平台的函数库(STL+boost),尽量避免涉及到底层的编程。  c如果涉及到跨操作系统的东西,可以使用ace,这个东西是对系统的封装的程序包。还是不错的(备注:什么是ACE?ace的全名是adaptive communication environment(可适应的通信环境),它是一个通信中间件,具有良好的可移植性;winsock只是一个socket编程的api库,仅仅提供一组api给你调用,但是ace还提供了一个性能优异的框架,也就是说,ace已经把底层的socket api包装成一个具有逻辑性的框架,你只需要按照调用规范去使用就可以获得较好的性能)  在应用表示层上做到跨平台,低层实现上或多或少都是与平台相关的. (八)C++与JAVA区别小总结:   事实上,constant和typedef这两条语句包含了#define语句的作用。现在,结构和联合已经被Java的类所代替。删除这些特性的原因 是:由于其希望维持与C语言的向后兼容性,C ++的语言规范包含了大量冗余。比如,类实际上就已经包括了结构和联合的作用,因此这两种数据结构完全可以取消。关于#define语句,Java语言规 范的制订者认为:尽管该语句的出发点是为了增强程序的可读性,但实际效果却恰恰相反,它常常导致难读的代码,故应该予以取消。Java不再支持独立函数, 因此任何函数都必须封装到某个类中。由于人们普遍认为, C++所用的超类是非常不稳定的,因此Java抛弃了C++中的多继承并代之以接口。Java的接口指的是,在别的类看来一个类所能实现的方法。它所显示 的只是一个类的方法或常量和变量,而不是这个类的全部结构。  最后,Java还取消了C++中的GOTO语句、操作符重载、自动类型转换及指针数据类型。 GOTO语句引起的争议已经有很多年了,可一直阴魂不散,这跟某些程序员对该语句一直情有独钟有关。C++仍然支持数据类型的自动转换,但Java要求编 程人员显式实现数据类型之间的转换。自动数据类型转换使得两个数据类型互不兼容的变量可以相互赋值,而不需要给出显式说明。这有时会导致一些问题,其中最 常见的是精确度损失。比方说,如果把一个带符号的32位整数赋给一个无符号整数,则所有的结果均为正数。Java的设计者们认为这很容易引起程序错误,从 而决定不支持这种转换方式。 到此已经全部结束.全剧终3,java 的垃圾回收机制
Java的垃圾回收机制是Java虚拟机提供的能力,用于在空闲时间以不定时的方式动态回收无任何引用的对象占据的内存空间。
需要注意的是:垃圾回收回收的是无任何引用的对象占据的内存空间而不是对象本身,很多人来我公司面试时,我都会问这个问题的,70%以上的人回答的含义是回收对象,实际上这是不正确的。
System.gc()
Runtime.getRuntime().gc()
上面的方法调用时用于显式通知JVM可以进行一次垃圾回收,但真正垃圾回收机制具体在什么时间点开始发生动作这同样是不可预料的,这和抢占式的线程在发生作用时的原理一样。
一个跟踪过程,它传递性地跟踪指向当前使用的对象的所有指针,以便找到可以引用的所有对象,然后重新使用在此跟踪过程中未找到的任何堆内存。公共语言运行库垃圾回收器还压缩使用中的内存,以缩小堆所需要的工作空间。Java语言中一个显著的特点就是引入了垃圾回收机制,使c++程序员最头疼的内存管理的问题迎刃而解,它使得Java程序员在编写程序的时候不再需要考虑内存管理。由于有个垃圾回收机制,Java中的对象不再有“作用域”的概念,只有对象的引用才有“作用域”。垃圾回收可以有效的防止内存泄露,有效的使用可以使用的内存。垃圾回收器通常是作为一个单独的低级别的线程运行,不可预知的情况下对内存堆中已经死亡的或者长时间没有使用的对象进行清楚和回收,程序员不能实时的调用垃圾回收器对某个对象或所有对象进行垃圾回收。回收机制有分代复制垃圾回收和标记垃圾回收,增量垃圾回收。Java 程序员不用担心内存管理,因为垃圾收集器会自动进行管理。要请求垃圾收集,可以调用下面的方法之一:System.gc()Runtime.getRuntime().gc()
垃圾回收用于释放以后不再使用的对象所占的内存。而至于垃圾回收器什么时候回收是无法控制的,垃圾回收时间也是无法预料的。即使使用了System.gc()Runtime.getRuntime().gc()
也只是简单的申请垃圾回收,垃圾回收器并不一定在接到申请后就立刻回收。
这是Java的一大特色,至于SUN是如何实现这一功能的,因为其不开源,所以不得而知。
对于 GC 来说,当程序员创建对象时,GC 就开始监控这个对象的地址、大小以及使用情况。
通常,GC  采用有向图的方式记录和管理堆(heap) 中的所有对象。通过这种方式确定哪些对
象是"可达的",哪些对象是"不可达的"。当GC 确定一些对象为"不可达"时,GC 就有责任回
收这些内存空间。程序员可以手动执行 System.gc(),通知 GC 运行,但是 Java 语言
规范并不保证 GC 一定会执行。
回收机制就是 当一些资源被创建使用之后或不在调用的话 就会变成垃圾,垃圾的话会占用空间,这时候就需要释放空间给其他程序使用,所以JAVA拥有自动垃圾回收机制,会在适当的时候自动调用垃圾回收 释放资源,程序员也可以手动调用释放资源等等。
如:
public class A  {
String str;
public A(String str){this.str=str;
}public String toString(){return str;}@Overrideprotected void finalize() throws Throwable {System.out.println("我是"+str+".我被回收了..");}public static void main(String[] args) {A a=new A("李四");a=null;System.gc();   //运行结果 我是李四.我被回收了..}
}
对于 GC 来说,当程序员创建对象时,GC 就开始监控这个对象的地址、大小以及使用情况。
通常,GC  采用有向图的方式记录和管理堆(heap) 中的所有对象。通过这种方式确定哪些对
象是"可达的",哪些对象是"不可达的"。当GC 确定一些对象为"不可达"时,GC 就有责任回
收这些内存空间。程序员可以手动执行 System.gc(),通知 GC 运行,但是 Java 语言
规范并不保证 GC 一定会执行。
在你写的程序中 编好的代码全部运行在 JVM 即 java 虚拟机,这时你的代码就会占内存。而内存中运行着jvm , jvm 的 heap 和 stack  都是有限大的。你的程序代码 过多占用内存。导致硬件出问题  系统运行不流畅 慢 ,这时 就产生了GC  GC自动回收那些 已死的代码对象 或 已经无用的类    判断无用的类 标准   1.该类所有的实例都以回收。也就是Java堆中不存在该类的任何实例
2.  加载该类的classLoader已经被回收
3.该类对应的java.lang.class 对象没有在任何地方被引用, 无法在任何地方通过反射访问该类的方法无用的类 和对象就会自动被 GC垃圾回收机制回收。。。。
java中垃圾回收机制的原理
推荐一篇文章:对高性能JAVA代码之内存管理更甚者你写的代码,GC根本就回收不了,直接系统挂掉。GC是一段程序,不是智能,他只回收他认为的垃圾,而不是回收你认为的垃圾。GC垃圾回收:Grabage Collection相信学过JAVA的人都知道这个是什么意思。但是他是如何工作的呢?首先,JVM在管理内存的时候对于变量的管理总是分新对象和老对象。新对象也就是开发者new出来的对象,但是由于生命周期短,那么他占用的内存并不是马上释放,而是被标记为老对象,这个时候该对象还是要存在一段时间。然后由JVM决定他是否是垃圾对象,并进行回收。所以我们可以知道,垃圾内存并不是用完了马上就被释放,所以就会产生内存释放不及时的现象,从而降低了内存的使用。而当程序浩大的时候。这种现象更为明显,并且GC的工作也是需要消耗资源的。所以,也就会产生内存浪费。JVM中的对象生命周期里谈内存回收:对象的生命周期一般分为7个阶段:创建阶段,应用阶段,不可视阶段,不可到达阶段,可收集阶段,终结阶段,释放阶段。创建阶段:首先大家看一下,如下两段代码:test1:for( int i=0; i《10000; i++)Object obj=new Object();test2:Object obj=null;for( int i=0; i《10000; i++)obj=new Object();这两段代码都是相同的功能,但是显然test2的性能要比test1性能要好,内存使用率要高,这是为什么呢?原因很简单,test1每次执行for循环都要创建一个Object的临时对象,但是这些临时对象由于JVM的GC不能马上销毁,所以他们还要存在很长时间,而test2则只是在内存中保存一份对象的引用,而不必创建大量新临时变量,从而降低了内存的使用。另外不要对同一个对象初始化多次。例如:public class A{private Hashtable table = new Hashtable();public A(){ table = new Hashtable();// 这里应该去掉,因为table已经被初始化。}这样就new了两个Hashtable,但是却只使用了一个。另外一个则没有被引用。而被忽略掉。浪费了内存。并且由于进行了两次new操作。也影响了代码的执行速度。应用阶段:即该对象至少有一个引用在维护他。不可视阶段:即超出该变量的作用域。这里有一个很好的做法,因为JVM在GC的时候并不是马上进行回收,而是要判断对象是否被其他引用在维护。所以,这个时候如果我们在使用完一个对象以后对其obj=null或者obj.doSomething()操作,将其标记为空,可以帮助JVM及时发现这个垃圾对象。不可到达阶段:就是在JVM中找不到对该对象的直接或者间接的引用。可收集阶段,终结阶段,释放阶段:此为回收器发现该对象不可到达,finalize方法已经被执行,或者对象空间已被重用的时候。JAVA的析构方法:可能不会有人相信,JAVA有析构函数? 是的,有。因为JAVA所有类都继承至Object类,而finalize就是Object类的一个方法,这个方法在JAVA中就是类似于C++析构函数。一般来说可以通过重载finalize方法的形式才释放类中对象。如:public class A{public Object a;public A(){ a = new Object ;}protected void finalize() throws java.lang.Throwable{a = null; // 标记为空,释放对象super.finalize(); // 递归调用超类中的finalize方法。}}当然,什么时候该方法被调用是由JVM来决定的。..。..。..。..。..。..。..。.一般来说,我们需要创建一个destory的方法来显式的调用该方法。然后在finalize也对该方法进行调用,实现双保险的做法。由于对象的创建是递归式的,也就是先调用超级类的构造,然后依次向下递归调用构造函数,所以应该避免在类的构造函数中初始化变量,这样可以避免不必要的创建对象造成不必要的内存消耗。当然这里也就看出来接口的优势。数组的创建:由于数组需要给定一个长度,所以在不确定数据数量的时候经常会创建过大,或过小的数组的现象。造成不必要的内存浪费,所以可以通过软引用的方式来告诉JVM及时回收该内存。(软引用,具体查资料)。例如:Object obj = new char[10000000000000000];SoftReference ref = new SoftReference(obj);共享静态存储空间:我们都知道静态变量在程序运行期间其内存是共享的,因此有时候为了节约内存工件,将一些变量声明为静态变量确实可以起到节约内存空间的作用。但是由于静态变量生命周期很长,不易被系统回收,所以使用静态变量要合理,不能盲目的使用。以免适得其反。因此建议在下面情况下使用:1,变量所包含的对象体积较大,占用内存过多。2,变量所包含对象生命周期较长。3,变量所包含数据稳定。4,该类的对象实例有对该变量所包含的对象的共享需求。(也就是说是否需要作为全局变量)。对象重用与GC:有的时候,如数据库操作对象,一般情况下我们都需要在各个不同模块间使用,所以这样的对象需要进行重用以提高性能。也有效的避免了反复创建对象引起的性能下降。一般来说对象池是一个不错的注意。如下:public abstarct class ObjectPool{private Hashtable locked,unlocked;private long expirationTime;abstract Object create();abstract void expire( Object o);abstract void validate( Object o);synchronized Object getObject(){。..};synchronized void freeObject(Object o){。..};这样我们就完成了一个对象池,我们可以将通过对应的方法来存取删除所需对象。来维护这快内存提高内存重用。当然也可以通过调用System.gc()强制系统进行垃圾回收操作。当然这样的代价是需要消耗一些cpu资源。不要提前创建对象:尽量在需要的时候创建对象,重复的分配,构造对象可能会因为垃圾回收做额外的工作降低性能。JVM内存参数调优:强制内存回收对于系统自动的内存回收机制会产生负面影响,会加大系统自动回收的处理时间,所以应该尽量避免显式使用System.gc(),JVM的设置可以提高系统的性能。例如:java -XX:NewSize=128m -XX:MaxNewSize=128m -XX:SurvivorRatio=8 -Xms512m -Xmx512m具体可以查看java帮助文档。我们主要介绍程序设计方面的性能提高。JAVA程序设计中有关内存管理的其他经验:根据JVM内存管理的工作原理,可以通过一些技巧和方式让JVM做GC处理时更加有效。,从而提高内存使用和缩短GC的执行时间。1,尽早释放无用对象的引用。即在不使用对象的引用后设置为空,可以加速GC的工作。(当然如果是返回值。..。.)2,尽量少用finalize函数,此函数是JAVA给程序员提供的一个释放对象或资源的机会,但是却会加大GC工作量。3,如果需要使用到图片,可以使用soft应用类型,它可以尽可能将图片读入内存而不引起OutOfMemory.4,注意集合数据类型的数据结构,往往数据结构越复杂,GC工作量更大,处理更复杂。5,尽量避免在默认构造器(构造函数)中创建,初始化大量的对象。6,尽量避免强制系统做垃圾回收。会增加系统做垃圾回收的最终时间降低性能。7,尽量避免显式申请数组,如果不得不申请数组的话,要尽量准确估算数组大小。8,如果在做远程方法调用。要尽量减少传递的对象大小。或者使用瞬间值避免不必要数据的传递。9,尽量在合适的情况下使用对象池来提高系统性能减少内存开销,当然,对象池不能过于庞大,会适得其反.
我们可以让变量、常量、用完后指向null,这样就是一个null的垃圾,JVM执行的时候就会回收。也就是说我们可以利用指向null来通知JVM这个事没用的变量!
详细介绍Java垃圾回收机制

垃圾收集GC(Garbage Collection)是Java语言的核心技术之一,之前我们曾专门探讨过Java 7新增的垃圾回收器G1的新特性,但在JVM的内部运行机制上看,Java的垃圾回收原理与机制并未改变。垃圾收集的目的在于清除不再使用的对象。GC通过确定对象是否被活动对象引用来确定是否收集该对象。GC首先要判断该对象是否是时候可以收集。两种常用的方法是引用计数和对象引用遍历。

引用计数收集器

引用计数是垃圾收集器中的早期策略。在这种方法中,堆中每个对象(不是引用)都有一个引用计数。当一个对象被创建时,且将该对象分配给一个变量,该变量计数设置为1。当任何其它变量被赋值为这个对象的引用时,计数加1(a = b,则b引用的对象+1),但当一个对象的某个引用超过了生命周期或者被设置为一个新值时,对象的引用计数减1。任何引用计数为0的对象可以被当作垃圾收集。当一个对象被垃圾收集时,它引用的任何对象计数减1。

优点:引用计数收集器可以很快的执行,交织在程序运行中。对程序不被长时间打断的实时环境比较有利。

缺点: 无法检测出循环引用。如父对象有一个对子对象的引用,子对象反过来引用父对象。这样,他们的引用计数永远不可能为0.

跟踪收集器

早期的JVM使用引用计数,现在大多数JVM采用对象引用遍历。对象引用遍历从一组对象开始,沿着整个对象图上的每条链接,递归确定可到达(reachable)的对象。如果某对象不能从这些根对象的一个(至少一个)到达,则将它作为垃圾收集。在对象遍历阶段,GC必须记住哪些对象可以到达,以便删除不可到达的对象,这称为标记(marking)对象。

下一步,GC要删除不可到达的对象。删除时,有些GC只是简单的扫描堆栈,删除未标记的未标记的对象,并释放它们的内存以生成新的对象,这叫做清除(sweeping)。这种方法的问题在于内存会分成好多小段,而它们不足以用于新的对象,但是组合起来却很大。因此,许多GC可以重新组织内存中的对象,并进行压缩(compact),形成可利用的空间。

为此,GC需要停止其他的活动活动。这种方法意味着所有与应用程序相关的工作停止,只有GC运行。结果,在响应期间增减了许多混杂请求。另外,更复杂的 GC不断增加或同时运行以减少或者清除应用程序的中断。有的GC使用单线程完成这项工作,有的则采用多线程以增加效率。

一些常用的垃圾收集器

(1)标记-清除收集器

这种收集器首先遍历对象图并标记可到达的对象,然后扫描堆栈以寻找未标记对象并释放它们的内存。这种收集器一般使用单线程工作并停止其他操作。并且,由于它只是清除了那些未标记的对象,而并没有对标记对象进行压缩,导致会产生大量内存碎片,从而浪费内存。

(2)标记-压缩收集器

有时也叫标记-清除-压缩收集器,与标记-清除收集器有相同的标记阶段。在第二阶段,则把标记对象复制到堆栈的新域中以便压缩堆栈。这种收集器也停止其他操作。

(3)复制收集器

这种收集器将堆栈分为两个域,常称为半空间。每次仅使用一半的空间,JVM生成的新对象则放在另一半空间中。GC运行时,它把可到达对象复制到另一半空间,从而压缩了堆栈。这种方法适用于短生存期的对象,持续复制长生存期的对象则导致效率降低。并且对于指定大小堆来说,需要两倍大小的内存,因为任何时候都只使用其中的一半。

 (4) 增量收集器

增量收集器把堆栈分为多个域,每次仅从一个域收集垃圾,也可理解为把堆栈分成一小块一小块,每次仅对某一个块进行垃圾收集。这会造成较小的应用程序中断时间,使得用户一般不能觉察到垃圾收集器正在工作。

(5)分代收集器

复制收集器的缺点是:每次收集时,所有的标记对象都要被拷贝,从而导致一些生命周期很长的对象被来回拷贝多次,消耗大量的时间。而分代收集器则可解决这个问题,分代收集器把堆栈分为两个或多个域,用以存放不同寿命的对象。JVM生成的新对象一般放在其中的某个域中。过一段时间,继续存在的对象(非短命对象)将获得使用期并转入更长寿命的域中。分代收集器对不同的域使用不同的算法以优化性能。

并行收集器

并行收集器使用某种传统的算法并使用多线程并行的执行它们的工作。在多CPU机器上使用多线程技术可以显著的提高java应用程序的可扩展性。

最后,贴出一个非常简单的跟踪收集器的例图,以便大家加深对收集器的理解:

跟踪收集器图例

使用垃圾收集器要注意的地方

下面将提出一些有关垃圾收集器要注意的地方,垃圾收集器知识很多,下面只列出一部分必要的知识:

(1)每个对象只能调用finalize( )方法一次。如果在finalize( )方法执行时产生异常(exception),则该对象仍可以被垃圾收集器收集。

(2)垃圾收集器跟踪每一个对象,收集那些不可触及的对象(即该对象不再被程序引用 了),回收其占有的内存空间。但在进行垃圾收集的时候,垃圾收集器会调用该对象的finalize( )方法(如果有)。如果在finalize()方法中,又使得该对象被程序引用(俗称复活了),则该对象就变成了可触及的对象,暂时不会被垃圾收集了。但是由于每个对象只能调用一次finalize( )方法,所以每个对象也只可能 "复活 "一次。

(3)Java语言允许程序员为任何方法添加finalize( )方法,该方法会在垃圾收集器交换回收对象之前被调用。但不要过分依赖该方法对系统资源进行回收和再利用,因为该方法调用后的执行结果是不可预知的。

(4)垃圾收集器不可以被强制执行,但程序员可以通过调研System.gc方法来建议执行垃圾收集。记住,只是建议。一般不建议自己写System.gc,因为会加大垃圾收集工作量。

详解Java GC的工作原理

概要: JVM内存结构由堆、栈、本地方法栈、方法区等部分组成,另外JVM分别对新生代和旧生代采用不同的垃圾回收机制。

1. 首先来看一下JVM内存结构,它是由堆、栈、本地方法栈、方法区等部分组成,结构图如下所示。

1)堆

所有通过new创建的对象的内存都在堆中分配,其大小可以通过-Xmx和-Xms来控制。堆被划分为新生代和旧生代,新生代又被进一步划分为Eden和Survivor区,最后Survivor由FromSpace和ToSpace组成,结构图如下所示:

新生代。新建的对象都是用新生代分配内存,Eden空间不足的时候,会把存活的对象转移到Survivor中,新生代大小可以由-Xmn来控制,也可以用-XX:SurvivorRatio来控制Eden和Survivor的比例旧生代。用于存放新生代中经过多次垃圾回收仍然存活的对象

2)栈

每个线程执行每个方法的时候都会在栈中申请一个栈帧,每个栈帧包括局部变量区和操作数栈,用于存放此次方法调用过程中的临时变量、参数和中间结果

3)本地方法栈

用于支持native方法的执行,存储了每个native方法调用的状态

4)方法区

存放了要加载的类信息、静态变量、final类型的常量、属性和方法信息。JVM用持久代(PermanetGeneration)来存放方法区,可通过-XX:PermSize和-XX:MaxPermSize来指定最小值和最大值。介绍完了JVM内存组成结构,下面我们再来看一下JVM垃圾回收机制。

2. JVM垃圾回收机制

JVM分别对新生代和旧生代采用不同的垃圾回收机制

新生代的GC:

新生代通常存活时间较短,因此基于Copying算法来进行回收,所谓Copying算法就是扫描出存活的对象,并复制到一块新的完全未使用的空间中,对应于新生代,就是在Eden和FromSpace或ToSpace之间copy。新生代采用空闲指针的方式来控制GC触发,指针保持最后一个分配的对象在新生代区间的位置,当有新的对象要分配内存时,用于检查空间是否足够,不够就触发GC。当连续分配对象时,对象会逐渐从eden到survivor,最后到旧生代,

用javavisualVM来查看,能明显观察到新生代满了后,会把对象转移到旧生代,然后清空继续装载,当旧生代也满了后,就会报outofmemory的异常,如下图所示:

在执行机制上JVM提供了串行GC(SerialGC)、并行回收GC(ParallelScavenge)和并行GC(ParNew)

1)串行GC

在整个扫描和复制过程采用单线程的方式来进行,适用于单CPU、新生代空间较小及对暂停时间要求不是非常高的应用上,是client级别默认的GC方式,可以通过-XX:+UseSerialGC来强制指定

2)并行回收GC

在整个扫描和复制过程采用多线程的方式来进行,适用于多CPU、对暂停时间要求较短的应用上,是server级别默认采用的GC方式,可用-XX:+UseParallelGC来强制指定,用-XX:ParallelGCThreads=4来指定线程数

3)并行GC

与旧生代的并发GC配合使用

旧生代的GC:

旧生代与新生代不同,对象存活的时间比较长,比较稳定,因此采用标记(Mark)算法来进行回收,所谓标记就是扫描出存活的对象,然后再进行回收未被标记的对象,回收后对用空出的空间要么进行合并,要么标记出来便于下次进行分配,总之就是要减少内存碎片带来的效率损耗。在执行机制上JVM提供了串行GC(SerialMSC)、并行GC(parallelMSC)和并发GC(CMS),具体算法细节还有待进一步深入研究。

以上各种GC机制是需要组合使用的,指定方式由下表所示:

1. 垃圾回收的意义
  在C++中,对象所占的内存在程序结束运行之前一直被占用,在明确释放之前不能分配给其它对象;而在Java中,当没有对象引用指向原先分配给某个对象的内存时,该内存便成为垃圾。JVM的一个系统级线程会自动释放该内存块。垃圾回收意味着程序不再需要的对象是"无用信息",这些信息将被丢弃。当一个对象不再被引用的时候,内存回收它占领的空间,以便空间被后来的新对象使用。事实上,除了释放没用的对象,垃圾回收也可以清除内存记录碎片。由于创建对象和垃圾回收器释放丢弃对象所占的内存空间,内存会出现碎片。碎片是分配给对象的内存块之间的空闲内存洞。碎片整理将所占用的堆内存移到堆的一端,JVM将整理出的内存分配给新的对象。
  垃圾回收能自动释放内存空间,减轻编程的负担。这使Java 虚拟机具有一些优点。首先,它能使编程效率提高。在没有垃圾回收机制的时候,可能要花许多时间来解决一个难懂的存储器问题。在用Java语言编程的时候,靠垃圾回收机制可大大缩短时间。其次是它保护程序的完整性, 垃圾回收是Java语言安全性策略的一个重要部份。
  垃圾回收的一个潜在的缺点是它的开销影响程序性能。Java虚拟机必须追踪运行程序中有用的对象,而且最终释放没用的对象。这一个过程需要花费处理器的时间。其次垃圾回收算法的不完备性,早先采用的某些垃圾回收算法就不能保证100%收集到所有的废弃内存。当然随着垃圾回收算法的不断改进以及软硬件运行效率的不断提升,这些问题都可以迎刃而解。
2. 垃圾收集的算法分析
  Java语言规范没有明确地说明JVM使用哪种垃圾回收算法,但是任何一种垃圾回收算法一般要做2件基本的事情:(1)发现无用信息对象;(2)回收被无用对象占用的内存空间,使该空间可被程序再次使用。
  大多数垃圾回收算法使用了根集(root set)这个概念;所谓根集就是正在执行的Java程序可以访问的引用变量的集合(包括局部变量、参数、类变量),程序可以使用引用变量访问对象的属性和调用对象的方法。垃圾回收首先需要确定从根开始哪些是可达的和哪些是不可达的,从根集可达的对象都是活动对象,它们不能作为垃圾被回收,这也包括从根集间接可达的对象。而根集通过任意路径不可达的对象符合垃圾收集的条件,应该被回收。下面介绍几个常用的算法。
  2.1. 引用计数法(Reference Counting Collector)
  引用计数法是唯一没有使用根集的垃圾回收的法,该算法使用引用计数器来区分存活对象和不再使用的对象。一般来说,堆中的每个对象对应一个引用计数器。当每一次创建一个对象并赋给一个变量时,引用计数器置为1。当对象被赋给任意变量时,引用计数器每次加1当对象出了作用域后(该对象丢弃不再使用),引用计数器减1,一旦引用计数器为0,对象就满足了垃圾收集的条件。
  基于引用计数器的垃圾收集器运行较快,不会长时间中断程序执行,适宜地必须实时运行的程序。但引用计数器增加了程序执行的开销,因为每次对象赋给新的变量,计数器加1,而每次现有对象出了作用域生,计数器减1。
  2.2. tracing算法(Tracing Collector)
  tracing算法是为了解决引用计数法的问题而提出,它使用了根集的概念。基于tracing算法的垃圾收集器从根集开始扫描,识别出哪些对象可达,哪些对象不可达,并用某种方式标记可达对象,例如对每个可达对象设置一个或多个位。在扫描识别过程中,基于tracing算法的垃圾收集也称为标记和清除(mark-and-sweep)垃圾收集器.
  2.3. compacting算法(Compacting Collector)
  为了解决堆碎片问题,基于tracing的垃圾回收吸收了Compacting算法的思想,在清除的过程中,算法将所有的对象移到堆的一端,堆的另一端就变成了一个相邻的空闲内存区,收集器会对它移动的所有对象的所有引用进行更新,使得这些引用在新的位置能识别原来的对象。在基于Compacting算法的收集器的实现中,一般增加句柄和句柄表。
  2.4. copying算法(Coping Collector)
  该算法的提出是为了克服句柄的开销和解决堆碎片的垃圾回收。它开始时把堆分成一个对象区和多个空闲区,程序从对象区为对象分配空间,当对象满了,基于coping算法的垃圾回收就从根集中扫描活动对象,并将每个活动对象复制到空闲区(使得活动对象所占的内存之间没有空闲间隔),这样空闲区变成了对象区,原来的对象区变成了空闲区,程序会在新的对象区中分配内存。
  一种典型的基于coping算法的垃圾回收是stop-and-copy算法,它将堆分成对象区和空闲区域区,在对象区与空闲区域的切换过程中,程序暂停执行。
  2.5. generation算法(Generational Collector)
  stop-and-copy垃圾收集器的一个缺陷是收集器必须复制所有的活动对象,这增加了程序等待时间,这是coping算法低效的原因。在程序设计中有这样的规律:多数对象存在的时间比较短,少数的存在时间比较长。因此,generation算法将堆分成两个或多个,每个子堆作为对象的一代 (generation)。由于多数对象存在的时间比较短,随着程序丢弃不使用的对象,垃圾收集器将从最年轻的子堆中收集这些对象。在分代式的垃圾收集器运行后,上次运行存活下来的对象移到下一最高代的子堆中,由于老一代的子堆不会经常被回收,因而节省了时间。
  2.6. adaptive算法(Adaptive Collector)
  在特定的情况下,一些垃圾收集算法会优于其它算法。基于Adaptive算法的垃圾收集器就是监控当前堆的使用情况,并将选择适当算法的垃圾收集器。

3. System.gc()方法

命令行参数透视垃圾收集器的运行
  使用System.gc()可以不管JVM使用的是哪一种垃圾回收的算法,都可以请求Java的垃圾回收。在命令行中有一个参数-verbosegc可以查看Java使用的堆内存的情况,它的格式如下:
  java -verbosegc classfile
  可以看个例子:
  

[java] view plaincopy
  1. class TestGC
  2. {
  3. public static void main(String[] args)
  4. {
  5.       new TestGC();
  6.       System.gc();
  7.       System.runFinalization();
  8.    }
  9. }

  在这个例子中,一个新的对象被创建,由于它没有使用,所以该对象迅速地变为不可达,程序编译后,执行命令: java -verbosegc TestGC 后结果为:
  [Full GC 168K->97K(1984K), 0.0253873 secs]
  机器的环境为,Windows 2000 + JDK1.3.1,箭头前后的数据168K和97K分别表示垃圾收集GC前后所有存活对象使用的内存容量,说明有168K-97K=71K的对象容量被回收,括号内的数据1984K为堆内存的总容量,收集所需要的时间是0.0253873秒(这个时间在每次执行的时候会有所不同)。

需要注意的是,调用System.gc()也仅仅是一个请求(建议)。JVM接受这个消息后,并不是立即做垃圾回收,而只是对几个垃圾回收算法做了加权,使垃圾回收操作容易发生,或提早发生,或回收较多而已。

4. finalize()方法

在JVM垃圾回收器收集一个对象之前,一般要求程序调用适当的方法释放资源,但在没有明确释放资源的情况下,Java提供了缺省机制来终止该对象心释放资源,这个方法就是finalize()。它的原型为:
  protected void finalize() throws Throwable
  在finalize()方法返回之后,对象消失,垃圾收集开始执行。原型中的throws Throwable表示它可以抛出任何类型的异常。
  之所以要使用finalize(),是存在着垃圾回收器不能处理的特殊情况。假定你的对象(并非使用new方法)获得了一块“特殊”的内存区域,由于垃圾回收器只知道那些显示地经由new分配的内存空间,所以它不知道该如何释放这块“特殊”的内存区域,那么这个时候java允许在类中定义一个由finalize()方法。

特殊的区域例如:1)由于在分配内存的时候可能采用了类似 C语言的做法,而非JAVA的通常new做法。这种情况主要发生在native method中,比如native method调用了C/C++方法malloc()函数系列来分配存储空间,但是除非调用free()函数,否则这些内存空间将不会得到释放,那么这个时候就可能造成内存泄漏。但是由于free()方法是在C/C++中的函数,所以finalize()中可以用本地方法来调用它。以释放这些“特殊”的内存空间。2)又或者打开的文件资源,这些资源不属于垃圾回收器的回收范围。
      换言之,finalize()的主要用途是释放一些其他做法开辟的内存空间,以及做一些清理工作。因为在JAVA中并没有提够像“析构”函数或者类似概念的函数,要做一些类似清理工作的时候,必须自己动手创建一个执行清理工作的普通方法,也就是override Object这个类中的finalize()方法。例如,假设某一个对象在创建过程中会将自己绘制到屏幕上,如果不是明确地从屏幕上将其擦出,它可能永远都不会被清理。如果在finalize()加入某一种擦除功能,当GC工作时,finalize()得到了调用,图像就会被擦除。要是GC没有发生,那么这个图像就会

被一直保存下来。

一旦垃圾回收器准备好释放对象占用的存储空间,首先会去调用finalize()方法进行一些必要的清理工作。只有到下一次再进行垃圾回收动作的时候,才会真正释放这个对象所占用的内存空间。
  在普通的清除工作中,为清除一个对象,那个对象的用户必须在希望进行清除的地点调用一个清除方法。这与C++"析构函数"的概念稍有抵触。在C++中,所有对象都会破坏(清除)。或者换句话说,所有对象都"应该"破坏。若将C++对象创建成一个本地对象,比如在堆栈中创建(在Java中是不可能的,Java都在堆中),那么清除或破坏工作就会在"结束花括号"所代表的、创建这个对象的作用域的末尾进行。若对象是用new创建的(类似于Java),那么当程序员调用C++的 delete命令时(Java没有这个命令),就会调用相应的析构函数。若程序员忘记了,那么永远不会调用析构函数,我们最终得到的将是一个内存"漏洞",另外还包括对象的其他部分永远不会得到清除。
  相反,Java不允许我们创建本地(局部)对象--无论如何都要使用new。但在Java中,没有"delete"命令来释放对象,因为垃圾回收器会帮助我们自动释放存储空间。所以如果站在比较简化的立场,我们可以说正是由于存在垃圾回收机制,所以Java没有析构函数。然而,随着以后学习的深入,就会知道垃圾收集器的存在并不能完全消除对析构函数的需要,或者说不能消除对析构函数代表的那种机制的需要(原因见下一段。另外finalize()函数是在垃圾回收器准备释放对象占用的存储空间的时候被调用的,绝对不能直接调用finalize(),所以应尽量避免用它)。若希望执行除释放存储空间之外的其他某种形式的清除工作,仍然必须调用Java中的一个方法。它等价于C++的析构函数,只是没后者方便。
      在C++中所有的对象运用delete()一定会被销毁,而JAVA里的对象并非总会被垃圾回收器回收。In another word, 1 对象可能不被垃圾回收,2 垃圾回收并不等于“析构”,3 垃圾回收只与内存有关。也就是说,并不是如果一个对象不再被使用,是不是要在finalize()中释放这个对象中含有的其它对象呢?不是的。因为无论对象是如何创建的,垃圾回收器都会负责释放那些对象占有的内存。

5. 触发主GC(Garbage Collector)的条件

  JVM进行次GC的频率很高,但因为这种GC占用时间极短,所以对系统产生的影响不大。更值得关注的是主GC的触发条件,因为它对系统影响很明显。总的来说,有两个条件会触发主GC:

  1)当应用程序空闲时,即没有应用线程在运行时,GC会被调用。因为GC在优先级最低的线程中进行,所以当应用忙时,GC线程就不会被调用,但以下条件除外。

  2)Java堆内存不足时,GC会被调用。当应用线程在运行,并在运行过程中创建新对象,若这时内存空间不足,JVM就会强制地调用GC线程,以便回收内存用于新的分配。若GC一次之后仍不能满足内存分配的要求,JVM会再进行两次GC作进一步的尝试,若仍无法满足要求,则 JVM将报“out of memory”的错误,Java应用将停止。

  由于是否进行主GC由JVM根据系统环境决定,而系统环境在不断的变化当中,所以主GC的运行具有不确定性,无法预计它何时必然出现,但可以确定的是对一个长期运行的应用来说,其主GC是反复进行的。

6. 减少GC开销的措施

  根据上述GC的机制,程序的运行会直接影响系统环境的变化,从而影响GC的触发。若不针对GC的特点进行设计和编码,就会出现内存驻留等一系列负面影响。为了避免这些影响,基本的原则就是尽可能地减少垃圾和减少GC过程中的开销。具体措施包括以下几个方面:

  (1)不要显式调用System.gc()

  此函数建议JVM进行主GC,虽然只是建议而非一定,但很多情况下它会触发主GC,从而增加主GC的频率,也即增加了间歇性停顿的次数。

  (2)尽量减少临时对象的使用

  临时对象在跳出函数调用后,会成为垃圾,少用临时变量就相当于减少了垃圾的产生,从而延长了出现上述第二个触发条件出现的时间,减少了主GC的机会。

  (3)对象不用时最好显式置为Null

  一般而言,为Null的对象都会被作为垃圾处理,所以将不用的对象显式地设为Null,有利于GC收集器判定垃圾,从而提高了GC的效率。

  (4)尽量使用StringBuffer,而不用String来累加字符串

  由于String是固定长的字符串对象,累加String对象时,并非在一个String对象中扩增,而是重新创建新的String对象,如Str5=Str1+Str2+Str3+Str4,这条语句执行过程中会产生多个垃圾对象,因为对次作“+”操作时都必须创建新的String对象,但这些过渡对象对系统来说是没有实际意义的,只会增加更多的垃圾。避免这种情况可以改用StringBuffer来累加字符串,因StringBuffer是可变长的,它在原有基础上进行扩增,不会产生中间对象。

  (5)能用基本类型如Int,Long,就不用Integer,Long对象

  基本类型变量占用的内存资源比相应对象占用的少得多,如果没有必要,最好使用基本变量。

  (6)尽量少用静态对象变量

  静态变量属于全局变量,不会被GC回收,它们会一直占用内存。

  (7)分散对象创建或删除的时间

  集中在短时间内大量创建新对象,特别是大对象,会导致突然需要大量内存,JVM在面临这种情况时,只能进行主GC,以回收内存或整合内存碎片,从而增加主GC的频率。集中删除对象,道理也是一样的。它使得突然出现了大量的垃圾对象,空闲空间必然减少,从而大大增加了下一次创建新对象时强制主GC的机会。

下面这个例子向大家展示了垃圾收集所经历的过程,并对前面的陈述进行了总结。

[java] view plaincopy
  1. class Chair {
  2.   static boolean gcrun = false;
  3.   static boolean f = false;
  4.   static int created = 0;
  5.   static int finalized = 0;
  6.   int i;
  7.   Chair() {
  8.       i = ++created;
  9.       if(created == 47)
  10.          System.out.println("Created 47");
  11.   }
  12.   protected void finalize() {
  13.       if(!gcrun) {
  14.          gcrun = true;
  15.          System.out.println("Beginning to finalize after " + created + " Chairs have been created");
  16.       }
  17.       if(i == 47) {
  18.          System.out.println("Finalizing Chair #47, " +"Setting flag to stop Chair creation");
  19.          f = true;
  20.       }
  21.       finalized++;
  22.       if(finalized >= created)
  23.          System.out.println("All " + finalized + " finalized");
  24.   }
  25. }
  26. public class Garbage {
  27.   public static void main(String[] args) {
  28.   if(args.length == 0) {
  29.      System.err.println("Usage: /n" + "java Garbage before/n or:/n" + "java Garbage after");
  30.      return;
  31.   }
  32.   while(!Chair.f) {
  33.      new Chair();
  34.      new String("To take up space");
  35.   }
  36.   System.out.println("After all Chairs have been created:/n" + "total created = " + Chair.created +
  37.   ", total finalized = " + Chair.finalized);
  38.   if(args[0].equals("before")) {
  39.     System.out.println("gc():");
  40.     System.gc();
  41.     System.out.println("runFinalization():");
  42.     System.runFinalization();
  43.   }
  44.   System.out.println("bye!");
  45.   if(args[0].equals("after"))
  46.      System.runFinalizersOnExit(true);
  47.   }
  48. }

上面这个程序创建了许多Chair对象,而且在垃圾收集器开始运行后的某些时候,程序会停止创建Chair。由于垃圾收集器可能在任何时间运行,所以我们不能准确知道它在何时启动。因此,程序用一个名为gcrun的标记来指出垃圾收集器是否已经开始运行。利用第二个标记f,Chair可告诉main()它应停止对象的生成。这两个标记都是在finalize()内部设置的,它调用于垃圾收集期间。另两个static变量--created以及 finalized--分别用于跟踪已创建的对象数量以及垃圾收集器已进行完收尾工作的对象数量。最后,每个Chair都有它自己的(非 static)int i,所以能跟踪了解它具体的编号是多少。编号为47的Chair进行完收尾工作后,标记会设为true,最终结束Chair对象的创建过程。

7. 关于垃圾回收的几点补充
  经过上述的说明,可以发现垃圾回收有以下的几个特点:
  (1)垃圾收集发生的不可预知性:由于实现了不同的垃圾回收算法和采用了不同的收集机制,所以它有可能是定时发生,有可能是当出现系统空闲CPU资源时发生,也有可能是和原始的垃圾收集一样,等到内存消耗出现极限时发生,这与垃圾收集器的选择和具体的设置都有关系。
  (2)垃圾收集的精确性:主要包括2 个方面:(a)垃圾收集器能够精确标记活着的对象;(b)垃圾收集器能够精确地定位对象之间的引用关系。前者是完全地回收所有废弃对象的前提,否则就可能造成内存泄漏。而后者则是实现归并和复制等算法的必要条件。所有不可达对象都能够可靠地得到回收,所有对象都能够重新分配,允许对象的复制和对象内存的缩并,这样就有效地防止内存的支离破碎。
  (3)现在有许多种不同的垃圾收集器,每种有其算法且其表现各异,既有当垃圾收集开始时就停止应用程序的运行,又有当垃圾收集开始时也允许应用程序的线程运行,还有在同一时间垃圾收集多线程运行。
  (4)垃圾收集的实现和具体的JVM 以及JVM的内存模型有非常紧密的关系。不同的JVM 可能采用不同的垃圾收集,而JVM 的内存模型决定着该JVM可以采用哪些类型垃圾收集。现在,HotSpot 系列JVM中的内存系统都采用先进的面向对象的框架设计,这使得该系列JVM都可以采用最先进的垃圾收集。
  (5)随着技术的发展,现代垃圾收集技术提供许多可选的垃圾收集器,而且在配置每种收集器的时候又可以设置不同的参数,这就使得根据不同的应用环境获得最优的应用性能成为可能。
  针对以上特点,我们在使用的时候要注意:
  (1)不要试图去假定垃圾收集发生的时间,这一切都是未知的。比如,方法中的一个临时对象在方法调用完毕后就变成了无用对象,这个时候它的内存就可以被释放。
  (2)Java中提供了一些和垃圾收集打交道的类,而且提供了一种强行执行垃圾收集的方法--调用System.gc(),但这同样是个不确定的方法。Java 中并不保证每次调用该方法就一定能够启动垃圾收集,它只不过会向JVM发出这样一个申请,到底是否真正执行垃圾收集,一切都是个未知数。
  (3)挑选适合自己的垃圾收集器。一般来说,如果系统没有特殊和苛刻的性能要求,可以采用JVM的缺省选项。否则可以考虑使用有针对性的垃圾收集器,比如增量收集器就比较适合实时性要求较高的系统之中。系统具有较高的配置,有比较多的闲置资源,可以考虑使用并行标记/清除收集器。
  (4)关键的也是难把握的问题是内存泄漏。良好的编程习惯和严谨的编程态度永远是最重要的,不要让自己的一个小错误导致内存出现大漏洞。
  (5)尽早释放无用对象的引用。大多数程序员在使用临时变量的时候,都是让引用变量在退出活动域(scope)后,自动设置为null,暗示垃圾收集器来收集该对象,还必须注意该引用的对象是否被监听,如果有,则要去掉监听器,然后再赋空值。

一、谁在做Garbage collection 
          垃圾回收机制是放在JVM中,由JVM来负责回收垃圾,我们只需要创建对象来分配空间,当对象无用时则不用担心空间回收的问题。  二、对象什么时候被回收 
          对象的生命周期与作用域无关,与引用有关。当一个对象被多个引用所指向,当该对象不再有任何引用指向它时,这个对象就被抛弃了,就可以被垃圾回收机制回收。比如当某个对象不存在任何引用时,引用告诉jvm你可以回收这个对象了,它对于我来说没有用了。         当jvm的垃圾回收机制对堆空间做检测时,发现某个对象的引用数为0时,就会把这个对象列入待回收列表中,并不是马上就销毁。 
         当一个对象被认为没有必要存在了,则会释放它占用的内存,被释放的内存可以再分配。但是并不是立刻就被回收的,jvm进程做空间回收有较大的系统开销,如果一个对象被丢弃就立刻回收它,会使整个应用的运转效率非常低下,jvm的垃圾回收机制有很多算法,除了引用计数法用来判断对象是否被抛弃外,其他算法是用来确定何时与如何做回收。为了提高效率,垃圾回收器通常在满足两个条件才运行:有对象要被回收,系统需要回收。因此运行时系统只在需要的时候才使用它,所以你不知道垃圾回收发生的准确时间。  三、没有引用指向的对象有用么? 
          没有引用指向的对象是要被回收的,是堆空间里的一个垃圾。但是有个例外,对于一次性使用的对象(临时对象)。可以不用引用变量指向它。例如:System.out.print("I like Java");就是创建了一个字符串对象后,无引用指向,直接传递给println()方法。  四、应用能干预垃圾回收吗? 
          这是不能的,对于垃圾回收机制来说,应用只有两个途径发消息给JVM,第一个就是指向某对象的引用全部移除了,这个对象不要了;第二个就是调用方法System.gc()。          对于system.gc()来说这也仅仅是个请求,JVM接受这个消息后并不是立即做垃圾回收,而只是对几个垃圾回收算法做了加权,使垃圾回收操作容易发生,或提早发生,或回收较多而已。 
         Java的垃圾回收机制是为所有java应用进程服务的,而不是为个特定的进程服务的,所以任何进程都不能命令垃圾回收机制做什么、怎么做或做多少。

什么事情java能做,但是C++不能做;

网络和夸平台

Ping 命令是什么协议

使用的是ICMP协议,是“Internet Control Message Protocol”(Internet控制消息协议)的缩写,是TCP/IP协议族的一个子协议,用于在IP主机、路由器之间传递控制消息。
不是IGMP协议,而是ICMP协议.ping命令的作用是通过发送"国际消息控制协议(ICMP)"回响请求消息来验证与另一台TCP/IP计算机的IP级连接状态,回响应答消息的接收情况将和往返过程的次数一起显示出来.ping命令是用于检测网络连接性 可到达性和名称解析的疑难问题的主要TCP/IP命令.

TCP/IP了解多少

1. TCP/IP参考模型有哪几层?
答:应用层、传输层、互联网层、网络接口层。
 
2. TCP和UDP有什么区别。
TCP和UDP都是传输层的协议。TCP是面向连接的,提供可靠服务的协议。UDP是面向无连接的,提供不可靠服务的协议。
TCP是传输控制协议,提供的是面向连接、可靠的字节流服务。通信双方彼此交换数据前,必须先通过三次握手协议建立连接,之后才能传输数据。TCP提供超时重传,丢弃重复数据,检验数据,流量控制等功能,保证数据能从一端传到另一端。
UDP是用户数据报协议,是一个简单的面向无连接的协议。UDP不提供可靠的服务。在数据数据前不用建立连接,故而传输速度很快。UPD主要用户流媒体传输,IP电话等对数据可靠性要求不是很高的场合。
 
3. 交换机与路由器有什么区别?
答:①工作所处的OSI层次不一样,交换机工作在OSI第二层数据链路层,路由器工作在OSI第三层网络层
②寻址方式不同:交换机根据MAC地址寻址,路由器根据IP地址寻址
③转发速不同:交换机的转发速度快,路由器转发速度相对较慢。
 
4. 说说静态路由和动态路由有什么区别。
答:静态路由是由管理员手工配置的,适合比较简单的网络或需要做路由特殊控制。而动态路由则是由动态路由协议自动维护的,不需人工干预,适合比较复杂大型的网络。
 
5. ARP的作用?
答:ARP的作用是把连在同一个网上计算机的IP地址转换为该机的物理地址
 
6. PING用的什么协议?
答:ICMP(网际控制消息协议)
 
7. 常用协议的端口号
21/tcp     FTP 文件传输协议
22/tcp     SSH 安全登录、文件传送(SCP)和端口重定向
23/tcp     Telnet 不安全的文本传送
25/tcp     SMTP Simple Mail Transfer Protocol (E-mail)
53/udp     DNS 域名解析
69/udp     TFTP Trivial File Transfer Protocol(微型文件传输协议)
80/tcp     HTTP 超文本传送协议 (WWW)
110/tcp    POP3 Post Office Protocol (E-mail)
443/tcp    HTTPS used for securely transferring web pages

1. TCP的三次握手最主要是防止已过期的连接再次传到被连接的主机。(废弃连接问题)
    如果采用两次的话,会出现下面这种情况。
比如是A机要连到B机,结果发送的连接信息由于某种原因没有到达B机;
于是,A机又发了一次,结果这次B收到了,于是就发信息回来,两机就连接。
传完东西后,断开。
    结果这时候,原先没有到达的连接信息突然又传到了B机,于是B机发信息给A,然后B机就以为和A连上了,这个时候B机就在等待A传东西过去。

2. 三次握手改成仅需要两次握手,死锁是可能发生
考虑计算机A和B之间的通信,假定B给A发送一个连接请求分组,A收到了这个分组,
并发送了确认应答分组。按照两次握手的协定,A认为连接已经成功地建立了,可以开始发送数据分组。可是,B在A的应答分组在传输中被丢失的情况下,将不知道A是否已准备好,不知道A建议什么样的序列号,B甚至怀疑A是否收到自己的连接请求分组。在这种情况下,B认为连接还未建立成功,将忽略A发来的任何数据分组,只等待连接确认应答分组。而A在发出的分组超时后,重复发送同样的分组。这样就形成了死锁

3. TCP通讯中,select到读事件,但是读到的数据量是0,为什么,如何解决????
select 返回0代表超时。select出错返回-1。
select到读事件,但是读到的数据量为0,说明对方已经关闭了socket的读端。本端关闭读即可。
当select出错时,会将接口置为可读又可写。这时就要通过判断select的返回值为-1来区分。

4. 2MSL(maximum segment lifetime) 
(1).等待一段时间,防止最后的FIN的ACK包丢失,对方未收到ACK会重发FIN
(2).TCP连接在2MSL时间内 ip,port不能重新被bind

5.复位报文(RST)
(1).接收到不存在端口的连接请求,回复RST包(但是udp是响应ICMP端口不可达的error)
(2).异常终止一个连接,发送RST包,收到RST的一方终止该连接。
(3).收到一个半开连接的数据包后,回复RST,收到RST的一方终止该连接。

6.几种情况
(1).服务器未开启服务,回复RST
(2).服务器连接正常关闭,回复FIN
(3).服务器进程异常终止,回复RST。
(4).服务器直接掉电,如果客户端没有"发送数据"或者"设置keepalive选项",客户端将一直保持此半开连接。
    如果客户端重新连接,将新建立一个连接。
(5).服务器重启时,如果收到一个半开连接的数据包,回复RST.

TCP/IP协议的工作流程如下:
●在源主机上,应用层将一串应用数据流传送给传输层。
●传输层将应用层的数据流截成分组,并加上TCP报头形成TCP段,送交网络层。
●在网络层给TCP段加上包括源、目的主机IP地址的IP报头,生成一个IP数据包,并将IP数据包送交链路层。
●链路层在其MAC帧的数据部分装上IP数据包,再加上源、目的主机的MAC地址和帧头,并根据其目的MAC地址,将MAC帧发往目的主机或IP路由器。
●在目的主机,链路层将MAC帧的帧头去掉,并将IP数据包送交网络层。
●网络层检查IP报头,如果报头中校验和与计算结果不一致,则丢弃该IP数据包;若校验和与计算结果一致,则去掉IP报头,将TCP段送交传输层。
●传输层检查顺序号,判断是否是正确的TCP分组,然后检查TCP报头数据。若正确,则向源主机发确认信息;若不正确或丢包,则向源主机要求重发信息。
●在目的主机,传输层去掉TCP报头,将排好顺序的分组组成应用数据流送给应用程序。这样目的主机接收到的来自源主机的字节流,就像是直接接收来自源主机的字节流一样。
TCP/IP协议的工作流程如下:
●在源主机上,应用层将一串应用数据流传送给传输层。
●传输层将应用层的数据流截成分组,并加上TCP报头形成TCP段,送交网络层。
●在网络层给TCP段加上包括源、目的主机IP地址的IP报头,生成一个IP数据包,并将IP数据包送交链路层。
●链路层在其MAC帧的数据部分装上IP数据包,再加上源、目的主机的MAC地址和帧头,并根据其目的MAC地址,将MAC帧发往目的主机或IP路由器。
●在目的主机,链路层将MAC帧的帧头去掉,并将IP数据包送交网络层。
●网络层检查IP报头,如果报头中校验和与计算结果不一致,则丢弃该IP数据包;若校验和与计算结果一致,则去掉IP报头,将TCP段送交传输层。
●传输层检查顺序号,判断是否是正确的TCP分组,然后检查TCP报头数据。若正确,则向源主机发确认信息;若不正确或丢包,则向源主机要求重发信息。
●在目的主机,传输层去掉TCP报头,将排好顺序的分组组成应用数据流送给应用程序。这样目的主机接收到的来自源主机的字节流,就像是直接接收来自源主机的字节流一样。
TCP/IP协议的工作流程如下:
●在源主机上,应用层将一串应用数据流传送给传输层。
●传输层将应用层的数据流截成分组,并加上TCP报头形成TCP段,送交网络层。
●在网络层给TCP段加上包括源、目的主机IP地址的IP报头,生成一个IP数据包,并将IP数据包送交链路层。
●链路层在其MAC帧的数据部分装上IP数据包,再加上源、目的主机的MAC地址和帧头,并根据其目的MAC地址,将MAC帧发往目的主机或IP路由器。
●在目的主机,链路层将MAC帧的帧头去掉,并将IP数据包送交网络层。
●网络层检查IP报头,如果报头中校验和与计算结果不一致,则丢弃该IP数据包;若校验和与计算结果一致,则去掉IP报头,将TCP段送交传输层。
●传输层检查顺序号,判断是否是正确的TCP分组,然后检查TCP报头数据。若正确,则向源主机发确认信息;若不正确或丢包,则向源主机要求重发信息。
●在目的主机,传输层去掉TCP报头,将排好顺序的分组组成应用数据流送给应用程序。这样目的主机接收到的来自源主机的字节流,就像是直接接收来自源主机的字节流一样。

第一套:

网络基础知识考查

日期:2008/3/3

姓名:Amxking

一,基础部份

1、OSI的中文全称是( 国际标准化组织),
它们分别是( 应用层(Application layer) 表示层(Presentation layer) 会话层(Session layer) 传输层(Transport layer)
网络层(Network layer) 数据链路层(Data link layer) 物理层(Physical layer) )。

2、集线器hub工作在OSI参考模型的(物理)层;网卡工作在OSI参考模型的(物理)层;
路由器router工作在OSI参考模型的(网络)层;交换机Switch工作在OSI参考模型的(数据链路)层。

3、机器A的IP地址为202.96.128.130,子网掩码为255.255.255.128,则该IP地址的网络号是(202.96.128),
主机号是(130 )。

4、ARP的中文意思是(地址解析协议),请用简单语言说明其的工作原理。

  1. 首先,每台主机都会在自己的ARP缓冲区 (ARP Cache)中建立一个 ARP列表,以表示IP地址和MAC地址的对应关系。

  2. 当源主机需要将一个数据包要发送到目的主机时,会首先检查自己 ARP列表中是否存在该 IP地址对应的MAC地址,
       如果有﹐就直接将数据包发送到这个MAC地址;如果没有,就向本地网段发起一个ARP请求的广播包,查询此目的
       主机对应的MAC地址。此ARP请求数据包里包括源主机的IP地址、硬件地址、以及目的主机的IP地址。

  3. 网络中所有的主机收到这个ARP请求后,会检查数据包中的目的IP是否和自己的IP地址一致。如果不相同就忽略此
       数据包;如果相同,该主机首先将发送端的MAC地址和IP地址添加到自己的ARP列表中,如果ARP表中已经存在该IP
       的信息,则将其覆盖,然后给源主机发送一个 ARP响应数据包,告诉对方自己是它需要查找的MAC地址;

  4. 源主机收到这个ARP响应数据包后,将得到的目的主机的IP地址和MAC地址添加到自己的ARP列表中,并利用此信息
       开始数据的传输。如果源主机一直没有收到ARP响应数据包,表示ARP查询失败。

5、DNS是指(  域名系统Domain Name System)。请用简单语言描述其工作原理。

当 DNS 客户机需要查询程序中使用的名称时,它会查询 DNS 服务器来解析该名称。
    客户机发送的每条查询消息都包括3条信息,以指定服务器应回答的问题。

  1 指定的 DNS 域名,表示为完全合格的域名 (FQDN) 。

  2 指定的查询类型,它可根据类型指定资源记录,或作为查询操作的专门类型。

  3 DNS域名的指定类别。

6、TCP和UDP的区别

TCP提供的是面向连接的、可靠的数据流传输,而UDP提供的是非面向连接的、不可靠的数据流传输。
   简单的说,TCP注重数据安全,而UDP数据传输快点,但安全性一般

7、网关的作用。
通过它可以访问外网

二,网络命令

1、ipconfig的作用是什么?

显示当前的TCP/IP配置的设置值

2、运行net share 返回的结果是什么?

列出共享资源相关信息 如 IPC$

3、net use 和net user分别是指什么?

net user 用于用户管理,添加,删除网络使用用户。
net use 用于网络设备管理,例如添加磁盘

4、如何在命令行下面查看当前系统开放的服务?

在命令行下执行net services 命令

5、除以上命令,还有哪些,请写出你知道的命令。

taskill
   taslist
   net view显示计算机列表
   netstat
   ftp
   telnet
  
三,系统端口及服务

 1、关掉以下服务,会出现什么样的情况,并请说明你的看法。

Automatic Updates 

不能自动更新

Plug and Play

禁用会导致USB不能使用.

Remote Registry Service

防范通过浏览网页来修改你的注册表

Computer Browser

无法通过该服务维护网络上计算机的最新列表以及提供这个列表给请求的程序。

2.端口及相对的服务

FTP(21 文件传输FTP服务   )

Terminal Services 的端口是( 3389   )

23端口是(TELNET)开放的默认端口

25端口是(E-mail SMTP)开放

109端口是(  POP2 )开放

1433端口是(  SQL Server   )开放

四,网络协议

ICMP:
是Internet Control Message Protocol(Internet控制消息协议)的缩写。
它是TCP/IP协议族的一个子协议,用于在IP主机、路由器之间传递控制消息。
控制消息是指网络通不通、主机是否可达、路由是否可用等网络本身的消息。
这些控制消息虽然并不传输用户数据,但是对于用户数据的传递起着重要的作用。

TFTP:
Trivial File Transfer Protocol,是TCP/IP协议族中的一个用来在客户机与服务器之间进行简单文件传输的协议
提供不复杂、开销不大的文件传输服务。  

HTTP:
HTTP超文本传输协议,是一个属于应用层的面向对象的协议,由于其简捷、快速的方式,适用于分布式超媒体信息系统,
它于1990年提出,经过几年的使用与发展,得到不断地完善和扩展。
   
DHCP:动态主机配置协议, 是一种让系统得以连接到网络上,并获取所需要的配置参数手段

  第二套:

网络知识考查

日期:2008/3/3

姓名:Amxking

一,填空题。

1,浏览器与WWW服务器之间传输信息时使用的协议是(http       )。

2,在星型局域网结构中,连接文件服务器与工作站的设备是(交换机   )。

3,在安装完成Linux系统后,系统自动创建的管理员帐号是( root )。

4,单位分得合法IP地址202.112.68.40 掩码为255.255.255.248,其中,路由器的外口和ISP之间占据了2个,
若使用202.112.68.41和202.112.68.42,掩码为255.255.255.252

问:1,则可供使用的合法IP还有多少哪些?

还可用的有 202.112.68.44/29, 202.112.68.45/29 ,202.112.68.46/29

问:2,使用内部IP进行地址转换,若用一台主机连接内外两个网络,请说出2中不同的网络接法;并进行比较?

1)主机接一块网卡绑定两个不同子网的地址,运行代理软件,内部网络将网关设置指向该主机。
2)主机插2块网卡,分别连接内外网,主机起到网关和地址转换作用。

1)中方案若内网盗用主机合法IP可以绕过主机
2)不能绕过主机。

问:3,Internet上保留了哪些内部IP有可以供使用?

 可以使用10.0.0.0 或 172.16直172.31 或192.168.0 直192.168.255

5,如何规划防火墙,将内部业务服务器和部分PC机与Internet隔离?

可以构建一个非军事区,将内部业务服务器通过内网路由器对内提供服务。
部分PC通过外网路由连接INTERNET,Internet上限制内部的部分pc机访问Internet。
在非军事区和内网之间设置路由器或代理服务器作为防火墙,限制外部的访问。

6,在我国,目前可供选择大的用户选择的接入方式有哪些,各自的接入速率为多少?

DDN 最高2M

ISDN 64K*2 (2B+D)

帧中继 最高2M

X.25 64K

[[[DDH  ( 最高2M  )

ADSL  ( 非对称数字用户线,下行速率从512Kbit/s到8Mbit/s,而上行速率则从64Kbit/s到640Kbit/s   ) 

ISDN   (综合业务数字网最高速度可达到64Kbps或128Kbps  )]]]

7,被路由器隔离的2个子网能否公用一台DHCP服务器?( 不能  )

8,用户通过什么命令可以看到自己申请到的本机IP地址?用何命令可以重新向DHCP服务器申请IP?用何命令可以释放IP?

ipconfig /all          
ipconfig /release释放ip
ipconfig /renew 获取新ip

8,ADSL使用的多路复用技术是(a )

A.频分多路复用 B.时分多路复用
C.码分多址 D.空分多址  

二,问答题。

1,写出下面网络命令的作用。

Netstat –p   (只打印给出名字的协议的统计数字和协议控制块信息         )

Net   view      (显示当前域或网络上的计算机上的列表)

如何在命令行下显示windows的服务 (   net services        )

2, 网桥的作用。

是一个局域网与另一个局域网之间建立连接的桥梁

3,用一条命令实现:将远程主机C盘映射为自己的F盘

 net use f: \\远程主机IP\c$ "密码" /user:"用户名"

5,防火墙的端口防护是指?

指通过对防火墙的端口开关的设置,关闭一些非必需端口,达到一定安全防护目的的行为。

1、建立连接协议(三次握手)
(1)客户端发送一个带SYN标志的TCP报文到服务器。这是三次握手过程中的报文1。
(2) 服务器端回应客户端的,这是三次握手中的第2个报文,这个报文同时带ACK标志和SYN标志。因此它表示对刚才客户端SYN报文的回应;同时又标志SYN给客户端,询问客户端是否准备好进行数据通讯。
(3) 客户必须再次回应服务段一个ACK报文,这是报文段3。
2、连接终止协议(四次挥手)
   由于TCP连接是全双工的,因此每个方向都必须单独进行关闭。这原则是当一方完成它的数据发送任务后就能发送一个FIN来终止这个方向的连接。收到一个 FIN只意味着这一方向上没有数据流动,一个TCP连接在收到一个FIN后仍能发送数据。首先进行关闭的一方将执行主动关闭,而另一方执行被动关闭。
 (1) TCP客户端发送一个FIN,用来关闭客户到服务器的数据传送(报文段4)。
 (2) 服务器收到这个FIN,它发回一个ACK,确认序号为收到的序号加1(报文段5)。和SYN一样,一个FIN将占用一个序号。
 (3) 服务器关闭客户端的连接,发送一个FIN给客户端(报文段6)。
 (4) 客户段发回ACK报文确认,并将确认序号设置为收到序号加1(报文段7)。
CLOSED: 这个没什么好说的了,表示初始状态。
LISTEN: 这个也是非常容易理解的一个状态,表示服务器端的某个SOCKET处于监听状态,可以接受连接了。
SYN_RCVD: 这个状态表示接受到了SYN报文,在正常情况下,这个状态是服务器端的SOCKET在建立TCP连接时的三次握手会话过程中的一个中间状态,很短暂,基本上用netstat你是很难看到这种状态的,除非你特意写了一个客户端测试程序,故意将三次TCP握手过程中最后一个ACK报文不予发送。因此这种状态时,当收到客户端的ACK报文后,它会进入到ESTABLISHED状态。
SYN_SENT: 这个状态与SYN_RCVD遥想呼应,当客户端SOCKET执行CONNECT连接时,它首先发送SYN报文,因此也随即它会进入到了SYN_SENT状态,并等待服务端的发送三次握手中的第2个报文。SYN_SENT状态表示客户端已发送SYN报文。
ESTABLISHED:这个容易理解了,表示连接已经建立了。
FIN_WAIT_1: 这个状态要好好解释一下,其实FIN_WAIT_1和FIN_WAIT_2状态的真正含义都是表示等待对方的FIN报文。而这两种状态的区别是:FIN_WAIT_1状态实际上是当SOCKET在ESTABLISHED状态时,它想主动关闭连接,向对方发送了FIN报文,此时该SOCKET即进入到FIN_WAIT_1状态。而当对方回应ACK报文后,则进入到FIN_WAIT_2状态,当然在实际的正常情况下,无论对方何种情况下,都应该马上回应ACK报文,所以FIN_WAIT_1状态一般是比较难见到的,而FIN_WAIT_2状态还有时常常可以用netstat看到。
FIN_WAIT_2:上面已经详细解释了这种状态,实际上FIN_WAIT_2状态下的SOCKET,表示半连接,也即有一方要求close连接,但另外还告诉对方,我暂时还有点数据需要传送给你,稍后再关闭连接。
TIME_WAIT: 表示收到了对方的FIN报文,并发送出了ACK报文,就等2MSL后即可回到CLOSED可用状态了。如果FIN_WAIT_1状态下,收到了对方同时带FIN标志和ACK标志的报文时,可以直接进入到TIME_WAIT状态,而无须经过FIN_WAIT_2状态。
CLOSING: 这种状态比较特殊,实际情况中应该是很少见,属于一种比较罕见的例外状态。正常情况下,当你发送FIN报文后,按理来说是应该先收到(或同时收到)对方的ACK报文,再收到对方的FIN报文。但是CLOSING状态表示你发送FIN报文后,并没有收到对方的ACK报文,反而却也收到了对方的FIN报文。什么情况下会出现此种情况呢?其实细想一下,也不难得出结论:那就是如果双方几乎在同时close一个SOCKET的话,那么就出现了双方同时发送FIN报文的情况,也即会出现CLOSING状态,表示双方都正在关闭SOCKET连接。
CLOSE_WAIT: 这种状态的含义其实是表示在等待关闭。怎么理解呢?当对方close一个SOCKET后发送FIN报文给自己,你系统毫无疑问地会回应一个ACK报文给对方,此时则进入到CLOSE_WAIT状态。接下来呢,实际上你真正需要考虑的事情是察看你是否还有数据发送给对方,如果没有的话,那么你也就可以close这个SOCKET,发送FIN报文给对方,也即关闭连接。所以你在CLOSE_WAIT状态下,需要完成的事情是等待你去关闭连接。
LAST_ACK: 这个状态还是比较容易好理解的,它是被动关闭一方在发送FIN报文后,最后等待对方的ACK报文。当收到ACK报文后,也即可以进入到CLOSED可用状态了。
最后有2个问题的回答,我自己分析后的结论(不一定保证100%正确)
1、 为什么建立连接协议是三次握手,而关闭连接却是四次握手呢?
这是因为服务端的LISTEN状态下的SOCKET当收到SYN报文的建连请求后,它可以把ACK和SYN(ACK起应答作用,而SYN起同步作用)放在一个报文里来发送。但关闭连接时,当收到对方的FIN报文通知时,它仅仅表示对方没有数据发送给你了;但未必你所有的数据都全部发送给对方了,所以你可以未必会马上会关闭SOCKET,也即你可能还需要发送一些数据给对方之后,再发送FIN报文给对方来表示你同意现在可以关闭连接了,所以它这里的ACK报文和FIN报文多数情况下都是分开发送的。
2、 为什么TIME_WAIT状态还需要等2MSL后才能返回到CLOSED状态?
这是因为:虽然双方都同意关闭连接了,而且握手的4个报文也都协调和发送完毕,按理可以直接回到CLOSED状态(就好比从SYN_SEND状态到ESTABLISH状态那样);但是因为我们必须要假想网络是不可靠的,你无法保证你最后发送的ACK报文会一定被对方收到,因此对方处于LAST_ACK状态下的SOCKET可能会因为超时未收到ACK报文,而重发FIN报文,所以这个TIME_WAIT状态的作用就是用来重发可能丢失的ACK报文。

TCP/IP 面试题整理

TCP/IP协议的工作流程如下:
●在源主机上,应用层将一串应用数据流传送给传输层。
●传输层将应用层的数据流截成分组,并加上TCP报头形成TCP段,送交网络层。
●在网络层给TCP段加上包括源、目的主机IP地址的IP报头,生成一个IP数据包,并将IP数据包送交链路层。
●链路层在其MAC帧的数据部分装上IP数据包,再加上源、目的主机的MAC地址和帧头,并根据其目的MAC地址,将MAC帧发往目的主机或IP路由器。
●在目的主机,链路层将MAC帧的帧头去掉,并将IP数据包送交网络层。
●网络层检查IP报头,如果报头中校验和与计算结果不一致,则丢弃该IP数据包;若校验和与计算结果一致,则去掉IP报头,将TCP段送交传输层。
●传输层检查顺序号,判断是否是正确的TCP分组,然后检查TCP报头数据。若正确,则向源主机发确认信息;若不正确或丢包,则向源主机要求重发信息。
●在目的主机,传输层去掉TCP报头,将排好顺序的分组组成应用数据流送给应用程序。这样目的主机接收到的来自源主机的字节流,就像是直接接收来自源主机的字节流一样。
TCP/IP协议的工作流程如下:
●在源主机上,应用层将一串应用数据流传送给传输层。
●传输层将应用层的数据流截成分组,并加上TCP报头形成TCP段,送交网络层。
●在网络层给TCP段加上包括源、目的主机IP地址的IP报头,生成一个IP数据包,并将IP数据包送交链路层。
●链路层在其MAC帧的数据部分装上IP数据包,再加上源、目的主机的MAC地址和帧头,并根据其目的MAC地址,将MAC帧发往目的主机或IP路由器。
●在目的主机,链路层将MAC帧的帧头去掉,并将IP数据包送交网络层。
●网络层检查IP报头,如果报头中校验和与计算结果不一致,则丢弃该IP数据包;若校验和与计算结果一致,则去掉IP报头,将TCP段送交传输层。
●传输层检查顺序号,判断是否是正确的TCP分组,然后检查TCP报头数据。若正确,则向源主机发确认信息;若不正确或丢包,则向源主机要求重发信息。
●在目的主机,传输层去掉TCP报头,将排好顺序的分组组成应用数据流送给应用程序。这样目的主机接收到的来自源主机的字节流,就像是直接接收来自源主机的字节流一样。

第一套:

网络基础知识考查

日期:2008/3/3

姓名:Amxking

一,基础部份

1、OSI的中文全称是( 国际标准化组织),
它们分别是( 应用层(Application layer) 表示层(Presentation layer) 会话层(Session layer) 传输层(Transport layer)
网络层(Network layer) 数据链路层(Data link layer) 物理层(Physical layer) )。

2、集线器hub工作在OSI参考模型的(物理)层;网卡工作在OSI参考模型的(物理)层;
路由器router工作在OSI参考模型的(网络)层;交换机Switch工作在OSI参考模型的(数据链路)层。

3、机器A的IP地址为202.96.128.130,子网掩码为255.255.255.128,则该IP地址的网络号是(202.96.128),
主机号是(130 )。

4、ARP的中文意思是(地址解析协议),请用简单语言说明其的工作原理。

  1. 首先,每台主机都会在自己的ARP缓冲区 (ARP Cache)中建立一个 ARP列表,以表示IP地址和MAC地址的对应关系。

  2. 当源主机需要将一个数据包要发送到目的主机时,会首先检查自己 ARP列表中是否存在该 IP地址对应的MAC地址,
       如果有﹐就直接将数据包发送到这个MAC地址;如果没有,就向本地网段发起一个ARP请求的广播包,查询此目的
       主机对应的MAC地址。此ARP请求数据包里包括源主机的IP地址、硬件地址、以及目的主机的IP地址。

  3. 网络中所有的主机收到这个ARP请求后,会检查数据包中的目的IP是否和自己的IP地址一致。如果不相同就忽略此
       数据包;如果相同,该主机首先将发送端的MAC地址和IP地址添加到自己的ARP列表中,如果ARP表中已经存在该IP
       的信息,则将其覆盖,然后给源主机发送一个 ARP响应数据包,告诉对方自己是它需要查找的MAC地址;

  4. 源主机收到这个ARP响应数据包后,将得到的目的主机的IP地址和MAC地址添加到自己的ARP列表中,并利用此信息
       开始数据的传输。如果源主机一直没有收到ARP响应数据包,表示ARP查询失败。

5、DNS是指(  域名系统Domain Name System)。请用简单语言描述其工作原理。

当 DNS 客户机需要查询程序中使用的名称时,它会查询 DNS 服务器来解析该名称。
    客户机发送的每条查询消息都包括3条信息,以指定服务器应回答的问题。

  1 指定的 DNS 域名,表示为完全合格的域名 (FQDN) 。

  2 指定的查询类型,它可根据类型指定资源记录,或作为查询操作的专门类型。

  3 DNS域名的指定类别。

6、TCP和UDP的区别

TCP提供的是面向连接的、可靠的数据流传输,而UDP提供的是非面向连接的、不可靠的数据流传输。
   简单的说,TCP注重数据安全,而UDP数据传输快点,但安全性一般

7、网关的作用。
通过它可以访问外网

二,网络命令

1、ipconfig的作用是什么?

显示当前的TCP/IP配置的设置值

2、运行net share 返回的结果是什么?

列出共享资源相关信息 如 IPC$

3、net use 和net user分别是指什么?

net user 用于用户管理,添加,删除网络使用用户。
net use 用于网络设备管理,例如添加磁盘

4、如何在命令行下面查看当前系统开放的服务?

在命令行下执行net services 命令

5、除以上命令,还有哪些,请写出你知道的命令。

taskill
   taslist
   net view显示计算机列表
   netstat
   ftp
   telnet
  
三,系统端口及服务

 1、关掉以下服务,会出现什么样的情况,并请说明你的看法。

Automatic Updates 

不能自动更新

Plug and Play

禁用会导致USB不能使用.

Remote Registry Service

防范通过浏览网页来修改你的注册表

Computer Browser

无法通过该服务维护网络上计算机的最新列表以及提供这个列表给请求的程序。

2.端口及相对的服务

FTP(21 文件传输FTP服务   )

Terminal Services 的端口是( 3389   )

23端口是(TELNET)开放的默认端口

25端口是(E-mail SMTP)开放

109端口是(  POP2 )开放

1433端口是(  SQL Server   )开放

四,网络协议

ICMP:
是Internet Control Message Protocol(Internet控制消息协议)的缩写。
它是TCP/IP协议族的一个子协议,用于在IP主机、路由器之间传递控制消息。
控制消息是指网络通不通、主机是否可达、路由是否可用等网络本身的消息。
这些控制消息虽然并不传输用户数据,但是对于用户数据的传递起着重要的作用。

TFTP:
Trivial File Transfer Protocol,是TCP/IP协议族中的一个用来在客户机与服务器之间进行简单文件传输的协议
提供不复杂、开销不大的文件传输服务。  

HTTP:
HTTP超文本传输协议,是一个属于应用层的面向对象的协议,由于其简捷、快速的方式,适用于分布式超媒体信息系统,
它于1990年提出,经过几年的使用与发展,得到不断地完善和扩展。
   
DHCP:动态主机配置协议, 是一种让系统得以连接到网络上,并获取所需要的配置参数手段

  第二套:

网络知识考查

日期:2008/3/3

姓名:Amxking

一,填空题。

1,浏览器与WWW服务器之间传输信息时使用的协议是(http       )。

2,在星型局域网结构中,连接文件服务器与工作站的设备是(交换机   )。

3,在安装完成Linux系统后,系统自动创建的管理员帐号是( root )。

4,单位分得合法IP地址202.112.68.40 掩码为255.255.255.248,其中,路由器的外口和ISP之间占据了2个,
若使用202.112.68.41和202.112.68.42,掩码为255.255.255.252

问:1,则可供使用的合法IP还有多少哪些?

还可用的有 202.112.68.44/29, 202.112.68.45/29 ,202.112.68.46/29

问:2,使用内部IP进行地址转换,若用一台主机连接内外两个网络,请说出2中不同的网络接法;并进行比较?

1)主机接一块网卡绑定两个不同子网的地址,运行代理软件,内部网络将网关设置指向该主机。
2)主机插2块网卡,分别连接内外网,主机起到网关和地址转换作用。

1)中方案若内网盗用主机合法IP可以绕过主机
2)不能绕过主机。

问:3,Internet上保留了哪些内部IP有可以供使用?

 可以使用10.0.0.0 或 172.16直172.31 或192.168.0 直192.168.255

5,如何规划防火墙,将内部业务服务器和部分PC机与Internet隔离?

可以构建一个非军事区,将内部业务服务器通过内网路由器对内提供服务。
部分PC通过外网路由连接INTERNET,Internet上限制内部的部分pc机访问Internet。
在非军事区和内网之间设置路由器或代理服务器作为防火墙,限制外部的访问。

6,在我国,目前可供选择大的用户选择的接入方式有哪些,各自的接入速率为多少?

DDN 最高2M

ISDN 64K*2 (2B+D)

帧中继 最高2M

X.25 64K

[[[DDH  ( 最高2M  )

ADSL  ( 非对称数字用户线,下行速率从512Kbit/s到8Mbit/s,而上行速率则从64Kbit/s到640Kbit/s   ) 

ISDN   (综合业务数字网最高速度可达到64Kbps或128Kbps  )]]]

7,被路由器隔离的2个子网能否公用一台DHCP服务器?( 不能  )

8,用户通过什么命令可以看到自己申请到的本机IP地址?用何命令可以重新向DHCP服务器申请IP?用何命令可以释放IP?

ipconfig /all          
ipconfig /release释放ip
ipconfig /renew 获取新ip

8,ADSL使用的多路复用技术是(a )

A.频分多路复用 B.时分多路复用
C.码分多址 D.空分多址  

二,问答题。

1,写出下面网络命令的作用。

Netstat –p   (只打印给出名字的协议的统计数字和协议控制块信息         )

Net   view      (显示当前域或网络上的计算机上的列表)

如何在命令行下显示windows的服务 (   net services        )

2, 网桥的作用。

是一个局域网与另一个局域网之间建立连接的桥梁

3,用一条命令实现:将远程主机C盘映射为自己的F盘

 net use f: \\远程主机IP\c$ "密码" /user:"用户名"

5,防火墙的端口防护是指?

指通过对防火墙的端口开关的设置,关闭一些非必需端口,达到一定安全防护目的的行为。

1、建立连接协议(三次握手)
(1)客户端发送一个带SYN标志的TCP报文到服务器。这是三次握手过程中的报文1。
(2) 服务器端回应客户端的,这是三次握手中的第2个报文,这个报文同时带ACK标志和SYN标志。因此它表示对刚才客户端SYN报文的回应;同时又标志SYN给客户端,询问客户端是否准备好进行数据通讯。
(3) 客户必须再次回应服务段一个ACK报文,这是报文段3。
2、连接终止协议(四次挥手)
   由于TCP连接是全双工的,因此每个方向都必须单独进行关闭。这原则是当一方完成它的数据发送任务后就能发送一个FIN来终止这个方向的连接。收到一个 FIN只意味着这一方向上没有数据流动,一个TCP连接在收到一个FIN后仍能发送数据。首先进行关闭的一方将执行主动关闭,而另一方执行被动关闭。
 (1) TCP客户端发送一个FIN,用来关闭客户到服务器的数据传送(报文段4)。
 (2) 服务器收到这个FIN,它发回一个ACK,确认序号为收到的序号加1(报文段5)。和SYN一样,一个FIN将占用一个序号。
 (3) 服务器关闭客户端的连接,发送一个FIN给客户端(报文段6)。
 (4) 客户段发回ACK报文确认,并将确认序号设置为收到序号加1(报文段7)。
CLOSED: 这个没什么好说的了,表示初始状态。
LISTEN: 这个也是非常容易理解的一个状态,表示服务器端的某个SOCKET处于监听状态,可以接受连接了。
SYN_RCVD: 这个状态表示接受到了SYN报文,在正常情况下,这个状态是服务器端的SOCKET在建立TCP连接时的三次握手会话过程中的一个中间状态,很短暂,基本上用netstat你是很难看到这种状态的,除非你特意写了一个客户端测试程序,故意将三次TCP握手过程中最后一个ACK报文不予发送。因此这种状态时,当收到客户端的ACK报文后,它会进入到ESTABLISHED状态。
SYN_SENT: 这个状态与SYN_RCVD遥想呼应,当客户端SOCKET执行CONNECT连接时,它首先发送SYN报文,因此也随即它会进入到了SYN_SENT状态,并等待服务端的发送三次握手中的第2个报文。SYN_SENT状态表示客户端已发送SYN报文。
ESTABLISHED:这个容易理解了,表示连接已经建立了。
FIN_WAIT_1: 这个状态要好好解释一下,其实FIN_WAIT_1和FIN_WAIT_2状态的真正含义都是表示等待对方的FIN报文。而这两种状态的区别是:FIN_WAIT_1状态实际上是当SOCKET在ESTABLISHED状态时,它想主动关闭连接,向对方发送了FIN报文,此时该SOCKET即进入到FIN_WAIT_1状态。而当对方回应ACK报文后,则进入到FIN_WAIT_2状态,当然在实际的正常情况下,无论对方何种情况下,都应该马上回应ACK报文,所以FIN_WAIT_1状态一般是比较难见到的,而FIN_WAIT_2状态还有时常常可以用netstat看到。
FIN_WAIT_2:上面已经详细解释了这种状态,实际上FIN_WAIT_2状态下的SOCKET,表示半连接,也即有一方要求close连接,但另外还告诉对方,我暂时还有点数据需要传送给你,稍后再关闭连接。
TIME_WAIT: 表示收到了对方的FIN报文,并发送出了ACK报文,就等2MSL后即可回到CLOSED可用状态了。如果FIN_WAIT_1状态下,收到了对方同时带FIN标志和ACK标志的报文时,可以直接进入到TIME_WAIT状态,而无须经过FIN_WAIT_2状态。
CLOSING: 这种状态比较特殊,实际情况中应该是很少见,属于一种比较罕见的例外状态。正常情况下,当你发送FIN报文后,按理来说是应该先收到(或同时收到)对方的ACK报文,再收到对方的FIN报文。但是CLOSING状态表示你发送FIN报文后,并没有收到对方的ACK报文,反而却也收到了对方的FIN报文。什么情况下会出现此种情况呢?其实细想一下,也不难得出结论:那就是如果双方几乎在同时close一个SOCKET的话,那么就出现了双方同时发送FIN报文的情况,也即会出现CLOSING状态,表示双方都正在关闭SOCKET连接。
CLOSE_WAIT: 这种状态的含义其实是表示在等待关闭。怎么理解呢?当对方close一个SOCKET后发送FIN报文给自己,你系统毫无疑问地会回应一个ACK报文给对方,此时则进入到CLOSE_WAIT状态。接下来呢,实际上你真正需要考虑的事情是察看你是否还有数据发送给对方,如果没有的话,那么你也就可以close这个SOCKET,发送FIN报文给对方,也即关闭连接。所以你在CLOSE_WAIT状态下,需要完成的事情是等待你去关闭连接。
LAST_ACK: 这个状态还是比较容易好理解的,它是被动关闭一方在发送FIN报文后,最后等待对方的ACK报文。当收到ACK报文后,也即可以进入到CLOSED可用状态了。
最后有2个问题的回答,我自己分析后的结论(不一定保证100%正确)
1、 为什么建立连接协议是三次握手,而关闭连接却是四次握手呢?
这是因为服务端的LISTEN状态下的SOCKET当收到SYN报文的建连请求后,它可以把ACK和SYN(ACK起应答作用,而SYN起同步作用)放在一个报文里来发送。但关闭连接时,当收到对方的FIN报文通知时,它仅仅表示对方没有数据发送给你了;但未必你所有的数据都全部发送给对方了,所以你可以未必会马上会关闭SOCKET,也即你可能还需要发送一些数据给对方之后,再发送FIN报文给对方来表示你同意现在可以关闭连接了,所以它这里的ACK报文和FIN报文多数情况下都是分开发送的。
2、 为什么TIME_WAIT状态还需要等2MSL后才能返回到CLOSED状态?
这是因为:虽然双方都同意关闭连接了,而且握手的4个报文也都协调和发送完毕,按理可以直接回到CLOSED状态(就好比从SYN_SEND状态到ESTABLISH状态那样);但是因为我们必须要假想网络是不可靠的,你无法保证你最后发送的ACK报文会一定被对方收到,因此对方处于LAST_ACK状态下的SOCKET可能会因为超时未收到ACK报文,而重发FIN报文,所以这个TIME_WAIT状态的作用就是用来重发可能丢失的ACK报文。

简述TCP协议在数据传输过程中收发双方是如何保证数据包的可靠性的
答:
(1)为了保证数据包的可靠传递,发送方必须把已发送的数据包保留在缓冲区;
(2)并为每个已发送的数据包启动一个超时定时器;
(3)如在定时器超时之前收到了对方发来的应答信息(可能是对本包的应答,也可以是对本包后续包的应答),则释放该数据包占用的缓冲区;
(4)否则,重传该数据包,直到收到应答或重传次数超过规定的最大次数为止。
(5)接收方收到数据包后,先进行CRC校验,如果正确则把数据交给上层协议,然后给发送方发送一个累计应答包,表明该数据已收到,如果接收方正好也有数据要发给发送方,应答包也可方在数据包中捎带过去。

TCP和UDP的区别
        TCP(Transmission Control Protocol,传输控制协议)是基于连接的协议,也就是说,在正式收发数据前,必须和对方建立可靠的连接。一个TCP连接必须要经过三次“对话”才能建立起来,其中的过程非常复杂,我们这里只做简单、形象的介绍,你只要做到能够理解这个过程即可。我们来看看这三次对话的简单过程:主机A向主机B发出连接请求数据包:“我想给你发数据,可以吗?”,这是第一次对话;主机B向主机A发送同意连接和要求同步(同步就是两台主机一个在发送,一个在接收,协调工作)的数据包:“可以,你什么时候发?”,这是第二次对话;主机A再发出一个数据包确认主机B的要求同步:“我现在就发,你接着吧!”,这是第三次对话。三次“对话”的目的是使数据包的发送和接收同步,经过三次“对话”之后,主机A才向主机B正式发送数据。 TCP协议能为应用程序提供可靠的通信连接,使一台计算机发出的字节流无差错地发往网络上的其他计算机,对可靠性要求高的数据通信系统往往使用TCP协议传输数据。 “面向非连接”就是在正式通信前不必与对方先建立连接,不管对方状态就直接发送。这与现在风行的手机短信非常相似:你在发短信的时候,只需要输入对方手机号就OK了。 
        UDP(User Data Protocol,用户数据报协议)是与TCP相对应的协议。它是面向非连接的协议,它不与对方建立连接,而是直接就把数据包发送过去! UDP适用于一次只传送少量数据、对可靠性要求不高的应用环境。比如,我们经常使用“ping”命令来测试两台主机之间TCP/IP通信是否正常,其实 “ping”命令的原理就是向对方主机发送UDP数据包,然后对方主机确认收到数据包,如果数据包是否到达的消息及时反馈回来,那么网络就是通的。例如,在默认状态下,一次“ping”操作发送4个数据包(如图2所示)。大家可以看到,发送的数据包数量是4包,收到的也是4包(因为对方主机收到后会发回一个确认收到的数据包)。这充分说明了UDP协议是面向非连接的协议,没有建立连接的过程。正因为UDP协议没有连接的过程,所以它的通信效果高;但也正因为如此,它的可靠性不如TCP协议高。QQ就使用UDP发消息,因此有时会出现收不到消息的情况。

TCP---传输控制协议,提供的是面向连接、可靠的字节流服务。当客户和服务器彼此交换数据前,必须先在双方之间建立一个TCP连接,之后才能传输数据。TCP提供超时重发,丢弃重复数据,检验数据,流量控制等功能,保证数据能顺序地从一端传到另一端。
        UDP---用户数据报协议,是一个简单的面向数据报的运输层协议。UDP不提供可靠性,它只是把应用程序传给IP层的数据报发送出去,但是并不能保证它们能到达目的地。由于UDP在传输数据报前不用在客户和服务器之间建立一个连接,且没有超时重发等机制,不保证数据按顺序传递,故而传输速度很快。

TCP与UDP的区别
    1. 基于连接与无连接
    2. 对系统资源的要求(TCP较多,UDP少)
    3. UDP程序结构较简单
    4. 流模式与数据报模式
            TCP保证数据正确性,UDP可能丢包
            TCP保证数据顺序,UDP不保证
    具体编程时的区别
    1. socket()的参数不同
    2. UDP Server不需要调用listen和accept
    3. UDP收发数据用sendto/recvfrom函数
    4. TCP:地址信息在connect/accept时确定
         UDP:在sendto/recvfrom函数中每次均 需指定地址信息
    5. UDP:shutdown函数无效

进程和线程的区别
1、进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位. 
线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源. 
一个线程可以创建和撤销另一个线程;同一个进程中的多个线程之间可以并发执行 
2、进程和线程的区别在于: 
简而言之,一个程序至少有一个进程,一个进程至少有一个线程. 
线程的划分尺度小于进程,使得多线程程序的并发性高。 
另外,进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率。 
线程在执行过程中与进程还是有区别的。每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口。但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。 
从逻辑角度来看,多线程的意义在于一个应用程序中,有多个执行部分可以同时执行。但操作系统并没有将多个线程看做多个独立的应用,来实现进程的调度和管理以及资源分配。这就是进程和线程的重要区别。
参考资料:http://blog.csdn.net/danforn/archive/2008/05/21/2464755.aspx

三次握手
  在TCP/IP协议中,TCP协议提供可靠的连接服务,采用三次握手建立一个连接。  
第一次握手:建立连接时,客户端发送syn包(syn=j)到服务器,并进入SYN_SEND状态,等待服务器确认;SYN:同步序列编号(Synchronize Sequence Numbers)。
第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态;
第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手。
完成三次握手,客户端与服务器开始传送数据,在上述过程中,还有一些重要的概念:

滑动窗口协议

工作原理:
  TCP协议在工作时,如果发送端的TCP协议软件每传输一个数据分组后,必须等待接收端的确认才能够发送下一个分组,由于网络传输的时延,将有大量时间被用于等待确认,导致传输效率低下。为此TCP在进行数据传输时使用了滑动窗口机制。
  TCP滑动窗口用来暂存两台计算机间要传送的数据分组。每台运行TCP协议的计算机有两个滑动窗口:一个用于数据发送,另一个用于数据接收。发送端待发数据分组在缓冲区排队等待送出。被滑动窗口框入的分组,是可以在未收到接收确认的情况下最多送出的部分。滑动窗口左端标志X的分组,是已经被接收端确认收到的分组。随着新的确认到来,窗口不断向右滑动。
  TCP协议软件依靠滑动窗口机制解决传输效率和流量控制问题。它可以在收到确认信息之前发送多个数据分组。这种机制使得网络通信处于忙碌状态,提高了整个网络的吞吐率,它还解决了端到端的通信流量控制问题,允许接收端在拥有容纳足够数据的缓冲之前对传输进行限制。在实际运行中,TCP滑动窗口的大小是可以随时调整的。收发端TCP协议软件在进行分组确认通信时,还交换滑动窗口控制信息,使得双方滑动窗口大小可以根据需要动态变化,达到在提高数据传输效率的同时,防止拥塞的发生。 称窗口左边沿向右边沿靠近为窗口合拢,这种现象发生在数据被发送和确认时。
  当窗口右边沿向左移动时将允许发送更多的数据,称之为窗口张开。这种现象发生在另一端的接收进程读取已经确认的数据并释放了TCP的接收缓存时。
  当左边沿向右移动时,称为窗口收缩。Host Requirements RFC强烈建议不要使用这种方式。但TCP必须能够在某一端产生这种情况时进行处理。

  如果左边沿到达右边沿,则称其为一个零窗口。

IP地址分类

A类保留给政府机构,B类分配给中等规模的公司,C类分配给任何需要的人,D类用于组播,E类用于实验,各类可容纳的地址数目不同。
A类地址
  (1)A类地址第1字节为网络地址,其它3个字节为主机地址。它的第1个字节的第一位固定为0.
  (2)A类地址范围:1.0.0.1---126.255.255.254
  (3)A类地址中的私有地址和保留地址:
  ① 10.X.X.X是私有地址(所谓的私有地址就是在互联网上不使用,而被用在局域网络中的地址)。
  范围(10.0.0.0---10.255.255.255)
② 127.X.X.X是保留地址,用做循环测试用的。
B类地址
  (1) B类地址第1字节和第2字节为网络地址,其它2个字节为主机地址。它的第1个字节的前两位固定为10.
  (2) B类地址范围:128.0.0.1---191.255.255.254。
  (3) B类地址的私有地址和保留地址
  ① 172.16.0.0---172.31.255.255是私有地址
  ② 169.254.X.X是保留地址。如果你的IP地址是自动获取IP地址,而你在网络上又没有找到可用的DHCP服务器。就会得到其中一个IP。
  191.255.255.255是广播地址,不能分配。
D类地址
  (1) D类地址不分网络地址和主机地址,它的第1个字节的前四位固定为1110。
  (2) D类地址范围:224.0.0.1---239.255.255.254
E类地址
  (1) E类地址不分网络地址和主机地址,它的第1个字节的前五位固定为11110。
  (2) E类地址范围:240.0.0.1---255.255.255.254
  IP地址如果只使用ABCDE类来划分,会造成大量的浪费:一个有500台主机的网络,无法使用C类地址。但如果使用一个B类地址,6万多个主机地址只有500个被使用,造成IP地址的大量浪费。因此,IP地址还支持VLSM技术,可以在ABC类网络的基础上,进一步划分子网。
  无类地址
  除ABCDE以外的IP地址段划分方式,如:192.168.1.0 255.255.255.252等分成C段划分的地址
虚拟IP
  不过,众所皆知的,IP 位址仅为 xxx.xxx.xxx.xxx 的资料型态,其中, xxx 为 1-255 间的整数,由于近来计算机的成长速度太快,实体的 IP 已经有点不足了,好在早在规划 IP 时就已经预留了三个网段的 IP 做为内部网域的虚拟 IP 之用。这三个预留的 IP 分别为:
  A级:10.0.0.0 - 10.255.255.255
  B级:172.16.0.0 - 172.31.255.255
  C级:192.168.0.0 - 192.168.255.255
  上述中最常用的是192.168.0.0这一组。不过,由于是虚拟 IP ,所以当您使用这些地址的时候﹐当然是有所限制的,限制如下:
  私有位址的路由信息不能对外散播
  使用私有位址作为来源或目的地址的封包﹐不能透过Internet来转送
  关于私有位址的参考纪录(如DNS)﹐只能限于内部网络使用
  由于虚拟 IP 的计算机并不能直接连上 Internet ,因此需要特别的功能才能上网。不过,这给我们架设IP网络提供了很大的方便﹐比如﹕目前您的公司还没有连上Internet﹐但这不保证将来不会。使用公共IP的话﹐如果没经过注册﹐在以后真正连上网络的时候﹐就很可能和别人冲突了。也正如前面所分析的﹐到时候再重新规划IP的话﹐将是件非常头痛的问题。这时候﹐我们可以先利用私有位址来架设网络﹐等到真要连上internet的时候﹐我们可以使用IP转换协定﹐如 NAT (Network Addresss Translation)等技术﹐配合新注册的IP就可以了。

虚函数
定义
  定义:在某基类中声明为 virtual 并在一个或多个派生类中被重新定 义的成员函数 [1]
  语法:virtual 函数返回类型 函数名(参数表) { 函数体 }
  用途:实现多态性,通过指向派生类的基类指针,访问派生类中同名覆盖成员函数
  虚函数必须是基类的非静态成员函数,其访问权限可以是protected或public,在基类的类定义中定义虚函数的一般形式:
作用
  虚函数的作用是实现动态联编,也就是在程序的运行阶段动态地选择合适的成员函数,在定义了虚函数后,可以在基类的派生类中对虚函数重新定义,在派生类中重新定义的函数应与虚函数具有相同的形参个数和形参类型。以实现统一的接口,不同定义过程。如果在派生类中没有对虚函数重新定义,则它继承其基类的虚函数。
  当程序发现虚函数名前的关键字virtual后,会自动将其作为动态联编处理,即在程序运行时动态地选择合适的成员函数。虚函数是C++多态的一种表现。
  例如:子类继承了父类的一个函数(方法),而我们把父类的指针指向子类,则必须把父类的该函数(方法)设为virtual(虚函数)。
  ([2010.10.28] 注:下行语义容易使人产生理解上的偏差,实际效果应为:
  如存在:Base -> Derive1 -> Derive2 及它们所拥有的虚函数func()
  则在访问派生类Derive1的实例时,使用其基类Base及本身类型Derive1,或被静态转换的后续派生类Derive2的指针或引用,均可访问到Derive1所实现的func()。)
  动态联编规定,只能通过指向基类的指针或基类对象的引用来调用虚函数,其格式:
  1、指向基类的指针变量名->虚函数名(实参表)
  2、基类对象的引用名. 虚函数名(实参表)
  使用虚函数,我们可以灵活的进行动态绑定,当然是以一定的开销为代价。如果父类的函数(方法)根本没有必要或者无法实现,完全要依赖子类去实现的话,可以把此函数(方法)设为virtual 函数名=0 我们把这样的函数(方法)称为纯虚函数。
如果一个类包含了纯虚函数,称此类为抽象类。
条件
  所以,从以上程序分析,实现动态联编需要三个条件:
  1、 必须把动态联编的行为定义为类的虚函数。
  2、 类之间存在子类型关系,一般表现为一个类从另一个类公有派生而来。
  3、 必须先使用基类指针指向子类型的对象,然后直接或者间接使用基类指针调用虚函数。
其他信息
  定义虚函数的限制:(1)非类的成员函数不能定义为虚函数,类的成员函数中静态成员函数和构造函数也不能定义为虚函数,但可以将析构函数定义为虚函数。实际上,优秀的程序员常常把基类的析构函数定义为虚函数。因为,将基类的析构函数定义为虚函数后,当利用delete删除一个指向派生类定义的对象指针时,系统会调用相应的类的析构函数。而不将析构函数定义为虚函数时,只调用基类的析构函数。
  (2)只需要在声明函数的类体中使用关键字“virtual”将函数声明为虚函数,而定义函数时不需要使用关键字“virtual”。
  (3)当将基类中的某一成员函数声明为虚函数后,派生类中的同名函数自动成为虚函数。
  (4)如果声明了某个成员函数为虚函数,则在该类中不能出现和这个成员函数同名并且返回值、参数个数、类型都相同的非虚函数。在以该类为基类的派生类中,也不能出现这种同名函数。
虚函数联系到多态,多态联系到继承。所以本文中都是在继承层次上做文章。没了继承,什么都没得谈。

虚基类
简介
  用 abstract 修饰的类是抽象类。
  在C++中,含有纯虚拟函数的类称为抽象类,它不能生成对象。
  凡是包含纯虚函数的类都是抽象类。
  抽象类是不完整的,并且它只能用作基类。它与非抽象类的不同:
  1、抽象类不能直接实例化,并且对抽象类使用 new 运算符是编译时错误。虽然一些变量和值在编译时的类型可以是抽象的,但是这样的变量和值必须或者为 null,或者含有对非抽象类的实例的引用(此非抽象类是从抽象类派生的)。
  2、允许(但不要求)抽象类包含抽象成员。
  3、抽象类不能被密封。
  当从抽象类派生非抽象类时,这些非抽象类必须具体实现所继承的所有抽象成员,从而重写那些抽象成员。在下边的示例中:
  abstract class A{ public abstract void F();}
  abstract class B: A{ public void G() {}}
  class C: B{ public override void F() { // actual implementation of F }}
   抽象类 A 引入抽象方法 F。类 B 引入另一个方法 G,但由于它不提供 F 的实现,B 也必须声明为抽象类。类 C 重写 F,并提供一个具体实现。由于 C 中没有了抽象成员,因此可以(但并非必须)将 C 声明为非抽象类。
  抽象类与接口紧密相关。然接口又比抽象类更抽象,这主要体现在它们的差别上:1)类可以实现无限个接口,但仅能从一个抽象(或任何其他类型)类继承,从抽象类派生的类仍可实现接口,从而得出接口是用来解决多重继承问题的。2)抽象类当中可以存在非抽象的方法,可接口不能且它里面的方法只是一个声明必须用public来修饰没有具体实现的方法。3)抽象类中的成员变量可以被不同的修饰符来修饰,可接口中的成员变量默认的都是静态常量(static final)。4)这一点也是最重要的一点本质的一点"抽象类是对象的抽象,然而接口是一种行为规范"。
定义
  抽象类表示该类中可能已经有一些方法的具体定义,但是接口就仅仅只能定义各个方法的界面(方法名,参数列表,返回类型),并不关心具体细节。
用法
  1)在继承抽象类时,必须覆盖该类中的每一个抽象方法,而每个已实现的方法必须和抽象类中指定的方法一样,接收相同数目和类型的参数,具有同样的返回值,这一点与接口相同。
  2)当父类已有实际功能的方法时,该方法在子类中可以不必实现,直接引用的方法,子类也可以重写该父类的方法(继承的概念)。
  3)而实现 (implement)一个接口(interface)的时候,是一定要实现接口中所定义的所有方法,而不可遗漏任何一个。
  4)另外,抽象类是不能产生对象的,但可以由它的实现类来声明对象。
  有鉴于此,在实现接口时,我们也常写一个抽象类,来实现接口中的某些子类所需的通用方法,接着在编写各个子类时,即可继承该抽象类来使用,省去在每个都要实现通用的方法的困扰。

多态性
  指相同对象收到不同消息或不同对象收到相同消息时产生不同的实现动作。C++支持两种多态性:编译时多态性,运行时多态性。
  a 编译时多态性:通过重载函数实现
  b 运行时多态性:通过虚函数实现。

浅谈数据库中的触发器

触发器

  其是一种特殊的存储过程。一般的存储过程是通过存储过程名直接调用,而触发器主要是

  通过事件(增、删、改)进行触发而被执行的。其在表中数据发生变化时自动强制执行。

  常见的触发器有两种:after(for)、instead of,用于insert、update、delete事件。

  after(for)        表示执行代码后,执行触发器

  instead of        表示执行代码前,用已经写好的触发器代替你的操作

触发器语法:

  create trigger 触发器的名字   on 操作表

  for|after         instead of

  update|insert|delete

  as

  SQL语句

触发器实现原理图

触发器示例

Example1

--禁止用户插入数据(实际上是先插入,然后立刻将其删除!)

  create trigger tr_insert on bank

  for          --for表示执行之后的操作

  insert       --即先执行了插入操作,同时在临时表中保存了插入记录

  as

  --执行完插入之后,在新生成的表中将刚刚插入的那条记录删除,

   --而此时得到的刚刚插入的记录的id是通过临时表 inserted得到的

  delete * from bank where cid=(select cid from inserted)

  生成上面的触发器后,当用户再输入insert语句后就见不到效果了!

  如:insert into bank values('0004',10000),是插入不进数据库的。

Example2

--删除谁就让谁的账户加上10元

  create trigger tr_dalete on bank

  instead of

  delete

  as

  update bank balance=balance+10 where cid=(select cid from deleted)

  生成这个触发器之后,当用户输入delete语句后,对应的那个id不但没有被删除掉,而且他的账户增加了10元

  如:delete from bank where cid='0002',执行完这句话后,编号为0002的账户会增加10元

数据库 触发器小结

触发器的概念、分类与作用
触发器是一种特殊类型的存储过程。
触发器主要是通过事件进行触发而被执行的,而存储过程可以通过存储过程名字而被直接调用。
触发器有4个要素:
Ø  名称:触发器有一个符合标志符命名规则的名称。
Ø  定义的目标:触发器必须定义在表或者视图上。
Ø  触发条件:是UPDATE、INSERT还是DELETE语句。
Ø  触发逻辑:触发之后如何处理。
 
触发器的种类
Ø  AFTER触发器
AFTER触发器是告诉SQL语句执行了INSERT、UPDATE或者DELETE操作后干什么。 
Ø  INSTEAD OF触发器
告诉当要执行INSERT、UPDATE或DELETE操作时用什么别的操作来代替。
触发器的作用
Ø  强化约束:触发器能够实现比CHECK约束更为复杂的约束
Ø  跟踪变化:触发器可以侦测数据库内的操作,从而不允许数据库中未经许可的变化。
Ø  级联运行
Ø  存储过程的调用
触发器的工作原理
 
SQL Server在工作时为每个触发器在服务器的内存上建立两个特殊的表:插入表和删除表。
Ø  (1) 插入表的功能
一旦对该表执行了插入(INSERT)操作,那么对该表插入的所有行来说,都有一个相应的副本存放到Inserted表中,即Inserted表用来存储原表插入的内容。
Ø  (2)删除表的功能
一旦对该表执行了删除(DELETE)操作,则将所有的删除行存放至Deleted表中。这样做的目的是,一旦触发器遇到了强迫它中止的语句被执行时,删除的那些行可以从Deleted表中得以还原。
创建触发器
在创建触发器以前必须考虑到以下几个方面:
Ø  CREATE TRIGGER语句必须是批处理的第一个语句。
Ø  表的所有者具有创建触发器的缺省权限,表的所有者不能把该权限传给其他用户。
Ø  触发器是数据库对象,所以其命名必须符合命名规则。
Ø  尽管在触发器的SQL语句中可以参照其他数据库中的对象,但是触发器只能创建在当前数据库中。
Ø  虽然触发器可以参照视图或临时表,但不能在视图或临时表上创建触发器,只能在基表或在创建视图的表上创建触发器。
Ø  一个触发器只能对应一个表,这是由触发器的机制决定的。
 
[例] 创建一个触发器,当向S表中插入一条记录时,自动显示S表中的记录。
 
CREATE TRIGGER ChangeDisplay
ON S
FOR INSERT
AS
SELECT * FROM S
查看触发器
使用 系统 存储过程查看触发器
Ø  EXEC sp_help '触发器名'
了解触发器的一般信息,如触发器的名字、属性、类型、创建时间

Ø  EXEC sp_helptext '触发器名'
查看触发器的正文信息

Ø  EXEC sp_depends '触发器名'
Ø  EXEC sp_depends '表名  '
查看指定触发器所引用的表或指定的表所涉及到的所有触发器
Ø  修改触发器
使用sp_rename修改触发器的名字
sp_rename oldname,newname
 
Ø  删除触发器
用系统命令DROP TRIGGER删除指定的触发器
DROP TRIGGER 触发器名
注:删除触发器所在的表时,SQL Server将自动删除与该表相关的触发器。

数据库常见的面试题

在整理准备数据库面试的过程中,先是在网上一顿海搜,找到历史面试题,然后一个骨头一个骨头的啃完,现在基本上这些问题(或者说叫做实践)都没有问题了。遇到的困难是:PL/SQL居多,T-SQL太少,所以需要筛选,修改答案,甚至有一些在T-SQL里面还没有支持。

下一步再把数据库T-SQL经典教程在翻看一遍,基本上对数据库就算告一段落了,前前后后共整整1个多月的时间(去年10.1是二周,下载是三周),学习的还行吧。

下面的就是全部内容,大段摘录的,或者是抄的,我都写了出处;有一些实在忘记了,请见谅:向大家共享知识,想必也是作者的本愿吧。

1.     三个范式

即: 属性唯一,   记录唯一,   表唯一

第一范式(1NF):数据库表中的字段都是单一属性的,不可再分。这个单一属性由基本类型构成,包括整型、实数、字符型、逻辑型、日期型等。

第二范式(2NF):数据库表中不存在非关键字段对任一候选关键字段的部分函数依赖(部分函数依赖指的是存在组合关键字中的某些字段决定非关键字段的情况),也即所有非关键字段都完全依赖于任意一组候选关键字。    
 第三范式(3NF):在第二范式的基础上,数据表中如果不存在非关键字段对任一候选关键字段的传递函数依赖则符合第三范式。所谓传递函数依赖,指的是如果存在"A → B → C"的决定关系,则C传递函数依赖于A。因此,满足第三范式的数据库表应该不存在如下依赖关系: 关键字段 → 非关键字段x → 非关键字段y

2.     一些常识:http://www.enet.com.cn/article/2007/0802/

A20070802755140.shtml

² 简要叙述一下SQL Server 2000中使用的一些数据库对象

表格、视图、用户定义的函数,存储过程,触发器等。

² NULL是什么意思

NULL这个值表示UNKNOWN(未知):它不表示“”(空字符串)。假设您的SQL Server数据库里有ANSI_NULLS,当然在默认情况下会有,对NULL这个值的任何比较都会生产一个NULL值。您不能把任何值与一个 UNKNOWN值进行比较,并在逻辑上希望获得一个答案。您必须使用IS NULL操作符

使用ISNULL(var,value)来进行NULL判断:当var为NULL的时候,var = value,并且返回value

² 什么是索引?SQL Server 2000里有什么类型的索引?

索引是一个数据结构,用来快速访问数据库表格或者视图里的数据。在SQL Server里,它们有两种形式:聚集索引非聚集索引。聚集索引在索引的叶级保存数据。这意味着不论聚集索引里有表格的哪个(或哪些)字段,这些字段都会按顺序被保存在表格,物理顺序和逻辑顺序一致。由于存在这种排序,所以每个表格只会有一个聚集索引。非聚集索引在索引的叶级有一个行标识符。它允许每个表格有多个非聚集索引。

² 什么是主键?什么是外键?

主键是表格里的(一个或多个)字段,只用来定义表格里的行;主键里的值总是唯一的。外键是一个用来建立两个表格之间关系的约束。这种关系一般都涉及一个表格里的主键字段与另外一个表(可能是同一表)里的字段。那么这些相连的字段就是外键。

² 什么是触发器?SQL Server 2000有什么不同类型的触发器?

INSTEAD-OF和AFTER两种触发器。触发器是一种专用类型的存储过程,它被捆绑到表格或者视图上。INSTEAD-OF触发器是替代数据操控语言(DML)语句对表格执行语句的存储过程。例如,如果我有一个用于TableA的INSTEAD-OF-UPDATE触发器,同时对这个表格执行一个更新语句,那么INSTEAD-OF-UPDATE触发器里的代码会执行,而不是我执行的更新语句则不会执行操作。

AFTER触发器要在DML语句在数据库里使用之后才执行。这些类型的触发器对于监视发生在数据库表格里的数据变化十分好用。

² 您如何确一个带有名为Fld1字段的TableB表格里只具有Fld1字段里的那些值,而这些值同时在名为TableA的表格的Fld1字段里?

第一个答案(而且是您希望听到的答案)是使用外键限制。外键限制用来维护引用的完整性integrity。它被用来确保表格里的字段只保存有已经在不同的(或者相同的)表格里的另一个字段里定义了的值。这个字段就是候选键(通常是另外一个表格的主键)。 
另外一种答案是触发器。触发器可以被用来保证以另外一种方式实现与限制相同的作用,但是它非常难设置与维护,而且性能一般都很糟糕。由于这个原因,微软建议开发人员使用外键限制而不是触发器来维护引用的完整性。

² 对一个投入使用的在线事务处理表格(OLTP)有过多索引需要有什么样的性能考虑?

对一个表格的索引越多,数据库引擎用来更新、插入或者删除数据所需要的时间就越多,因为在数据操控发生的时候索引也必须要维护。

² 你可以用什么来确保表格里的字段只接受特定范围里的值?

Check限制,它在数据库表格里被定义,用来限制输入该列的值。 
触发器也可以被用来限制数据库表格里的字段能够接受的值,但是这种办法要求触发器在表格里被定义,这可能会在某些情况下影响到性能。

² 返回参数总是由存储过程返回,它用来表示存储过程是成功还是失败。返回参数总是INT数据类型。

OUTPUT参数明确要求由开发人员来指定,它可以返回其他类型的数据,例如字符型和数值型的值。(可以用作输出参数的数据类型是有一些限制的。)您可以在一个存储过程里使用多个OUTPUT参数,而您只能够使用一个返回参数。

² 什么是相关子查询?如何使用这些查询?

相关子查询是一种包含子查询的特殊类型的查询。查询里包含的子查询会真正请求外部查询的值,从而形成一个类似于循环的状况。

11. 某一列允许NULL值,但希望确保所有的非空(Non-NULL)值都是唯一的 
SQL Server没有实现非NULL值唯一性的内建机制,因此需要通过自定义的trigger:

Create trigger mytrigger on t1 for insert, update as

BEGIN

IF (select max(cnt) from (select count(i.c1)as cnt

from t1, inserted i where t1.c1=i.c1 group by i.c1) x) > 1

ROLLBACK TRAN

END

3.     某列里最大或最小的前几个,或是大于或小于某一个值(最大值或平均值)的数据

http://www.blogjava.net/looline/archive/2006/12/08/86367.html

** HAVING子句对GROUP BY子句设置条件的方式与WHERE子句和SELECT语句交互的方式类似。WHERE子句搜索条件在进行分组操作之前应用;而HAVING搜索条件在进行分组操作之后应用。HAVING语法与WHERE语法类似,但HAVING可以包含聚合函数。HAVING子句可以引用选择列表中出现的任意项。

² 显示数据库中的最后一条记录的所有字段(ID是自增的)

SELECT top 1 * FROM Table_Name ORDER BY ID DESC -- 或者

SELECT * FROM Table_Name WHERE ID=(SELECT MAX (ID) FROM Table_Name)

² 显示数据库中的最后十条记录的所有字段(ID 是自增的  DESC 做降序 ASC 做升序)

SELECT top 10 * FROM Table_Name ORDER BY ID DESC

² 对来自表 authors 的前十个作者的 state 列进行更新

UPDATE s SET s.saleprice = s.saleprice+2

FROM (SELECT TOP 10 * FROM sales ORDER BY saleid) AS t1, sales s

WHERE s.saleid=t1.saleid

-- 或者

UPDATE s SET s.saleprice = s.saleprice+2 FROM sales s

WHERE s.saleid in (SELECT TOP 10 saleid FROM sales ORDER BY saleid)

² 找出公司里收入最高的前三名员工

select top 3 * from t1  order by a desc --或者

Select top 3 *, ROW_NUMBER() OVER(order by a DESC) as No from  t1

(根据分析,执行计划中的顺序:sort (order by )+ top 3, 然后是where等条件)

² 找出公司里收入最高(低)的三->五名员工

select top 3 a from t1 where  a in ( select top 5 a from t1  order by a asc) order by a desc

--弊端:参与排序的一定要是index,或者unique,且选出来的只能是单一的一个列

-- 所以用下面的方法

SELECT top (10-3+1) * FROM (SELECT TOP 10 * FROM customers Order by zip asc)t order by zip desc

² 取出表A中第31条到第40条记录(SQLServer,以自动增长的ID为主键,注意:ID可能不是连续的。)

-- top 10 可以省略

SELECT top 10 * FROM A WHERE ID not in (SELECT top 30 id FROM A)

² 显示出员工的平均工资大于3000元的部门名称(用SQL语句)

注意Full outer join,left join, right join,inner join区别和联系

SELECT Dept_Name

FROM t_Dept

WHERE ID in (SELECT Dept_IDFROM t_Salary

GROUP BY Dept_ID             --对部门分组(即:相同部门的,进行同一操作)

Having avg(Salary)>3000)

² 找出那些工资高于他们所在部门的平均工资的员工

select last_name, dept_id, salary from s_emp a
 where salary>(select avg(salary) from s_emp where dept_id=a.dept_id)

² 找出那些工资高于他们所在部门的 manager 的工资的员工。

select id, last_name, salary, manager_id   from s_emp a
  where salary>(select salary  from s_emp where id=a.manager_id)

²  有两个表分别如下: 
表A(varchar(32) NAME,int GRADE)

数据:ZHANGSHAN 80, LISI 60, WANGWU 84
表B(varchar(32) NAME,int AGE)
数据:ZHANGSHAN 26, LISI 24, WANGWU 26, WUTIAN 26
1)写SQL语句得到如下查询结果: 
NAME      GRADE   AGE  
ZHANGSHAN    80      26
LISI      60      24
WANGWU     84      26
WUTIAN      NULL    26

答:select * from A right join B on A.NAME = B.NAME
2)写SQl语句根据名字(NAME)相同按年龄(AGE)分组得到不同年龄的人的平均成绩,并写出结果。

答:avg(grade) group by name, age

4.     横表竖起来
请写出 SQl 语句实现题目要求的结果:写一个 SQL完成左边的表变成右边的表。

表的结构

要求结果

ProductID  SALE_YEAR   SALES

001          2001             10

002          2001            15

003          2002             12

003          2003             10

productID   2001  2002     2003

001        10 
    002        15 
    003               12       10

² 交叉表的列数是确定的 

select name,

sum(case subject when '数学' then source else 0 end) as '数学',

sum(case subject when '英语' then source else 0 end) as '英语',

sum(case subject when '语文' then source else 0 end) as '语文'

from   test   group   by   name

 

² 交叉表的列数是不确定的 

declare @sql varchar(8000)

set @sql = 'select name,'

select @sql = @sql + 'sum(case subject when '''+subject+'''

then source else 0 end) as '''+subject+''','

from (select distinct subject from test) as a

select @sql = left(@sql,len(@sql)-1) + ' from test group by name'

exec(@sql)

5.     SQLServer删除重复数据记录

http://www.cnblogs.com/luohoufu/archive/2008/06/05/1214286.html

有两个意义上的重复记录,一是完全重复的记录,也即所有字段均重复的记录,二是部分关键字段重复的记录,比如Name字段重复,而其他字段不一定重复。

² 写出 SQl 语句(或 SQL 语句组),查询所有 id_no 重复的记录。

select  dept_ID from salary

group by dept_ID having count(dept_ID) > 1

² 对于第一种重复,比较容易解决,使用

select distinct * from tableName
就可以得到无重复记录的结果集。
如果该表需要删除重复的记录(重复记录保留1条),可以按以下方法删除
select distinct * into #Tmp from tableName
truncate table tableName
select * into tableName from #Tmp
drop table #Tmp
发生这种重复的原因是表设计不周产生的,增加唯一索引列即可解决

² 这类重复问题通常要求保留重复记录中的第一条记录,操作方法如下:

假设有重复的字段为Name,Address,要求得到这两个字段唯一的结果集
select identity(int,1,1) as autoID, * into #Tmp from tableName
select min(autoID) as autoID into #Tmp2 from #Tmp group by Name,autoID
select * from #Tmp where autoID in(select autoID from #tmp2)
最后一个select即得到了Name,Address不重复的结果集(但多了一个autoID字段,实际写时可以写在select子句中省去此列)

² 部分关键字段重复,且记录中有ID. (***这个比较实用***)

第一种方法可一次删除所有重复的..(只保留重复中ID最小的记录)。
delete from table where id not in ( select min(id) from table group by name)第二种方法每次只删除重复中ID最大的一条记录。

delete from table where id in ( select max(id) from table group by name having count(*)>1)

² 使用SQL程序删除

declare @max integer,@id integer
declare cur_rows cursor local for select 主字段,count(*) from 表名 group by 主字段 having count(*) > 1
open cur_rows
fetch cur_rows into @id,@max
while @@fetch_status=0
begin
select @max = @max -1
set rowcount @max
delete from 表名 where 主字段 = @id
fetch cur_rows into @id,@max
end
close cur_rows
set rowcount 0

² 自己还得出的办法:

select * from user1 where id not in (select top 1 id from user1 where name = user1.name) -- 两个name相等比较重要,否则就不对了。但是group by更加好一些

删就这样写

delete from user1 where id not in (select top 1 id from user1 where name=user1.name)

delete from user where id not in ( select max(id) from user where name=user.name)

delete from user where id not in (select max(id) from user group by name having count(*) > 1)

其他方法

A:保留id最大(或者最小)的行,删除其它行

--方法1

delete [user] from [user] t

inner join(select name,max(id) as id from [user] group by name) a

on t.name = a.name and t.id <> a.id

--方法2

delete [user] from [user] t

where exists(select * from [user] where name = t.name and id > t.id)

B:删除所有重复的name行,一行也不留

delete [user] from [user] t

inner join

(select id from [user] a where exists(select * from [user] where name = a.name group by name having count(*) > 1)) as b

on t.id = b.id

6.     一些高难度的SQL

http://www.teecool.com/post/2007072807.html

² 如果表的结构和数据

表1:usertable
USERID USERNAME 
1 user1 
2 null 
3 user3 
4 null 
5 user5 
6 user6

表2: usergrade; 
USERID USERNAME GRADE 
1 user1 90 
2 null 80 
7 user7 80 
8 user8 90

那么,执行语句 select count(*) from usergrade where username not in (select username from usertable);

select count(*) from usergrade g where not exists (select null from usertable t where t.userid=g.userid and t.username=g.username);

结果为:语句1( 0 ) 语句2 ( 3 ) A: 0 B:1 C:2 D:3 E:NULL  --- 不懂

第一个结果为什么是零?因为:括号里面得到了usertable的所有的名字,其中有两个是NULL, in这个关键字的含义是or

类比,所以通过上面的例子我们知道,其实not in 产生了不确定的结果,因此返回给我们的是没有任何结果。

我自己做实验也尝试了这个问题把表中的2,4去掉就会得到的是2

<code><span class="pln">A</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">select</span><span class="pln"> </span><span class="str">'true'</span><span class="pln"> </span><span class="kwd">where</span><span class="pln"> </span><span class="lit">3</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> </span><span class="pun">(</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">3</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">null</span><span class="pun">)</span><span class="pln">
B</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">select</span><span class="pln"> </span><span class="str">'true'</span><span class="pln"> </span><span class="kwd">where</span><span class="pln"> </span><span class="lit">3</span><span class="pln"> </span><span class="kwd">not</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> </span><span class="pun">(</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">null</span><span class="pun">)</span></code>
<code><span class="kwd">select</span><span class="pln"> </span><span class="str">'true'</span><span class="pln"> </span><span class="kwd">where</span><span class="pln"> </span><span class="lit">3</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="kwd">or</span><span class="pln"> </span><span class="lit">3</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> </span><span class="kwd">or</span><span class="pln"> </span><span class="lit">3</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">3</span><span class="pln"> </span><span class="kwd">or</span><span class="pln"> </span><span class="lit">3</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">null</span></code>

加上一个not之后 变成and

<code><span class="kwd">select</span><span class="pln"> </span><span class="str">'true'</span><span class="pln"> </span><span class="kwd">where</span><span class="pln"> </span><span class="lit">3</span><span class="pln"> </span><span class="pun"><></span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="kwd">and</span><span class="pln"> </span><span class="lit">3</span><span class="pln"> </span><span class="pun"><></span><span class="pln"> </span><span class="lit">2</span><span class="pln"> </span><span class="kwd">and</span><span class="pln"> </span><span class="lit">3</span><span class="pln"> </span><span class="pun"><></span><span class="pln"> </span><span class="kwd">null</span></code>
<code><span class="lit">3</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="kwd">or</span><span class="pln"> </span><span class="lit">3</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> </span><span class="kwd">or</span><span class="pln"> </span><span class="lit">3</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">3</span><span class="pln"> </span><span class="kwd">or</span><span class="pln"> </span><span class="lit">3</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">null</span><span class="pln">
which </span><span class="kwd">is</span><span class="pun">:</span><span class="pln">FALSE </span><span class="kwd">or</span><span class="pln"> FALSE </span><span class="kwd">or</span><span class="pln"> TRUE </span><span class="kwd">or</span><span class="pln"> UNKNOWN
which evaluates </span><span class="kwd">to</span><span class="pln"> TRUE</span></code>
<code><span class="pln">    </span><span class="lit">3</span><span class="pln"> </span><span class="pun"><></span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="kwd">and</span><span class="pln"> </span><span class="lit">3</span><span class="pln"> </span><span class="pun"><></span><span class="pln"> </span><span class="lit">2</span><span class="pln"> </span><span class="kwd">and</span><span class="pln"> </span><span class="lit">3</span><span class="pln"> </span><span class="pun"><></span><span class="pln"> </span><span class="kwd">null</span><span class="pln">
which evaluates </span><span class="kwd">to</span><span class="pun">:</span><span class="pln">TRUE </span><span class="kwd">and</span><span class="pln"> TRUE </span><span class="kwd">and</span><span class="pln"> UNKNOWN
which evaluates </span><span class="kwd">to</span><span class="pun">:</span><span class="pln">UNKNOWN</span></code>

The UNKNOWN is not the same as FALSE you can easily test it by calling:

<code><span class="kwd">select</span><span class="pln"> </span><span class="str">'true'</span><span class="pln"> </span><span class="kwd">where</span><span class="pln"> </span><span class="lit">3</span><span class="pln"> </span><span class="pun"><></span><span class="pln"> </span><span class="kwd">null</span><span class="pln">
</span><span class="kwd">select</span><span class="pln"> </span><span class="str">'true'</span><span class="pln"> </span><span class="kwd">where</span><span class="pln"> </span><span class="kwd">not</span><span class="pln"> </span><span class="pun">(</span><span class="lit">3</span><span class="pln"> </span><span class="pun"><></span><span class="pln"> </span><span class="kwd">null</span><span class="pun">)</span></code>

² 在以下的表的显示结果中,以下语句的执行结果是(知识点:in/exists+rownum)

SQL> select * from usertable; 
USERID USERNAME 
1 user1 
2 user2 
3 user3 
4 user4 
5 user5

SQL> select * from usergrade; 
USERNAME GRADE 
user9 90 
user8 80 
user7 80 
user2 90 
user1 100 
user1 80

那么,执行语句Select count(*) from usertable t1 where username in 
(select username from usergrade t2);

Select count(*) from usertable t1 where exists 
(select 'x' from usergrade t2 where t1.username=t2.username );

以上语句的执行结果是:( c) (c )  A: 0 B: 1 C: 2 D: 3

count(*)和count(GRADE)有区别:前者统计NULL行;后者忽略NULL行

² 关联更新

有表一的查询结果如下,该表为学生成绩表select id,grade from student_grade 
ID GRADE   
1 50 
2 40 
3 70 
4 80 
5 30 
6 90

表二为补考成绩表 select id,grade from student_makeup 
ID GRADE 
1 60 
2 80 
5 60

执行语句: 
update student_grade s set s.grade = 
(select t.grade from student_makeup t where s.id=t.id);

-- 这里,把1、2、5更新为对应的结果,但是3、4、6也会被更新,但是由于没有对应的值,所以都被更新为了NULL

请问之后查询: select GRADE from student_grade where id = 3;结果为: (c)

A: 0 B: 70 C: null D: 以上都不对

7.     英文

http://www.teecool.com/post/2007072808.html

² Question 1: calculating the Number of Days in a Month

declare @now datetime

--select @now = getdate()

select @now = '20090211'

-- 方法是:下月日-本月日的日期差。所以先构造本月日,在构造下月日,减

select datediff(dd, dateadd(dd, -1* datepart(dd, @now) + 1, @now),

dateadd(MM, 1, dateadd(dd, -1* datepart(dd, @now) + 1, @now)) )

-- 方法:下月日的前一天就是本月的月末,这一天的‘dd’就是本月天数。

select datepart(dd,

dateadd(dd,-1,dateadd(mm,1,cast(cast(year(getdate()) as varchar)

+'-'+cast(month(getdate()) as varchar)+'-01' as datetime))));

² Question2:How can I print "10 to 20" for books that sell for between $10 and $20,"unknown" for books whose price is null, and "other" for all other prices?

select bookid,bookname,

price=case when price is null then   'unknown'

when  price between 10 and 20 then '10 to 20' else price end

from books

Question3:to find duplicate values! Find authors with the same last name?
You can use the table authors in datatabase pubs. I want to get the result:
au_lname   number_dups 
Ringer        2
Answer 3
select au_lname,number_dups=count(1) from authors group by au_lname

--count(1)和count(*)结果一样,都是根据au_lname分组进行的组内全部统计

²  Question4:Can you create a cross-tab report in my SQL Server!
How can I get the report about sale quality for each store and each quarter and the total sale quality for each quarter at year 1993?

  You can use the table sales and stores in datatabase pubs
Table Sales record all sale detail item for each store. Column store_id is the id of each store, ord_date is the order date of each sale item, and column qty is the sale quality. Table stores record all store information.
I want to get the result look like as below:
Output:

stor_name  Total Qtr1  Qtr2  Qtr3  Qtr4  
Barnum's   50 0  50 0  0
Bookbeat   55 25  30 0  0
Doc-U-Mat:   85 0  85 0  0
Fricative    60 35  0 0   25
Total     250 60 165 0  25

Answer 4:用动态SQL实现,前面有。不过看起来很复杂

use pubs

declare @s varchar(8000)

set @s='select isnull(stores.stor_name,''Total'') '

select @s=@s + ',[Qtr' + cast(datepart(q,ord_date) as char(1))

+ ']=sum(case when datepart(q,ord_date)='''

+ cast(datepart(q,ord_date) as char(1)) + ''' then qty else 0 end)'

from Sales

group by datepart(q,ord_date)

set @s=@s + ' ,sum(qty) "Total" from Sales inner join stores on Sales.stor_id = stores.stor_id '

set @s=@s + ' where datepart(yyyy,ord_date) = ''1993'' '

set @s=@s + ' group by stores.stor_name WITH ROLLUP '

set @s=@s + ' order by stores.stor_name '

print @s

exec(@s)

-- print @s的结果是这样的:

select isnull(stores.stor_name,'Total') , -- isnull把rollup造成的NULL值改成了Total,技巧

[Qtr1]=sum(case when datepart(q,ord_date)='1' then qty else 0 end),

[Qtr2]=sum(case when datepart(q,ord_date)='2' then qty else 0 end),

[Qtr3]=sum(case when datepart(q,ord_date)='3' then qty else 0 end),

[Qtr4]=sum(case when datepart(q,ord_date)='4' then qty else 0 end),

sum(qty) "Total"

from Sales inner join stores on Sales.stor_id = stores.stor_id

where datepart(yyyy,ord_date) = '1993'

group by stores.stor_name WITH ROLLUP  -- rollup是一个很重要的东西

order by stores.stor_name   -- order by,貌似不需要,或者用desc更好

²  Question5: The Fastest Way to Recompile All Stored Procedures
I have a problem with a database running in SQL Server 6.5 (Service Pack 4). We moved the database (object transfer) from one machine to another last night, and an error (specific to a stored procedure) is cropping up. However, I can't tell which procedure is causing it. Permissions are granted in all of our stored procedures; is there a way from the isql utility to force all stored procedures to recompile?

Tips: sp_recompile can recomplie a store procedure each time

Answer 5:在执行存储过程时,使用 with recompile 选项强制编译新的计划;使用sp_recompile系统存储过程强制在下次运行时进行重新编译

Question6: How can I add row numbers to my result set?
In database pubs, have a table titles , now I want the result shown as below,each row have a row number, how can you do that?
line-no  title_id 
1          BU1032
2          BU1111
3          BU2075
4          BU7832
5          MC2222
6          MC3021
7          MC3026
Answer 6:
-- row_number()的这种用法据我了解不行,他必须和over连用

select row_number() over(order by title_id) as line_no ,title_id from titles

²  Question 7: the difference of two SQL statements at performance of execution?
Statement 1:
if NOT EXISTS ( select * from publishers where state = ‘NY’) 
  SELECT ‘Sales force needs to penetrate New York market’
else
  SELECT ‘We have publishers in New York’
Statement 2:
if EXISTS ( select * from publishers where state = ‘NY’) 
  SELECT ‘We have publishers in New York’
else
  SELECT ‘Sales force needs to penetrate New York market’
Answer 7:
不同点:初步感觉应该是第二个性能比较好,因为不需要遍历整个数据表,只要有一个存在的就可以结束。但是从执行计划的时间和IO看,结果是一样的。

²  Question9: How can I get a list of the stores that have bought both ‘bussiness’ and ‘mod_cook’ type books?
In database pubs, use three table stores,sales and titles to implement this requestment. Now I want to get the result as below:
stor_id stor_name

...
7896 Fricative Bookshop
...
...
...
Answer 9:
use pubs

select distinct a.stor_id, a.stor_name from stores a,sales b,titles c

where a.stor_id=b.stor_id and b.title_id=c.title_id and c.type='business' and

exists(select 1 from sales k,titles g where stor_id=b.stor_id

and k.title_id=g.title_id and g.type='mod_cook');

-- 或者使用个连续的join也可以

select distinct a.stor_id, a.stor_name from stores a

join sales b on a.stor_id=b.stor_id

join titles c on b.title_id=c.title_id and c.type='business'

and exists (select * from  sales k,titles g where stor_id=b.stor_id

and k.title_id=g.title_id and g.type='mod_cook')

Question11: How can I list all book with prices greather than the average price of books of the same type?
In database pubs, have a table named titles , its column named price mean the price of the book, and another named type mean the type of books.
Now I want to get the result as below:
type           title                                                   price 
business     The Busy Executive’s Database Guide            19.9900
...
...
Answer 11:
select distinct t1.price, t1.type from titles t1, titles t2

where t1.price <

( select avg(price) from titles t2 where t1.type = t2.type group by type )

-- 或者

select distinct t1.price, t1.type from titles t1

join titles

on t1.price <

( select avg(price) from titles t2 where t1.type = t2.type group by type )

8.     其他

http://www.teecool.com/post/2007071809.html

²  有订单表SO_Table,单号字段RefNo VARCHAR(10),需要实现自动编号,格式为YYYYMMXXXX,其中XXXX为序号,如:2004050001,2004050002……2004059999等,采用Transact-SQL实现新订单编号的思路。

思路:

1,IDENTITY(smallint, 100, 1)只有在select…into这样的数据插入里面可用;

2,6位长度的年月可以用:convert(char(6), getdate(), 112);

或者cast(datepart(YY, @date) as varchar(4)) +

right(cast(datepart(MM, @date)+100 as varchar(3)), 2)

3, 如果必须在SP里面工作的话,可以获得上次的最大序号,加1

²  有表T1,T2,现有一事务,在向表T1添加数据时,同时也必须向T2也添加数据,如何确何数据的完整性。

使用trigger可以做到;另外,添加过程要在一个transaction中进行;

²  如何求表中相邻(按聚集索引相邻)的两条记录的某字段的值之差

select s2.saleid, p=(s1.saleprice-s2.saleprice)

from

(select *, id=row_number() over(order by saleid) from sales)  s1,

(select *, id=row_number() over(order by saleid) from sales) s2

where s2.id-s1.id=1

-- 下面的办法不行,因为如果相邻的ID不是连续的就不行了。另外,可以使用cursor

select a.source - b.source from test a, test b

where (a.id - b.id) = 1

order by a.id

²  如何删除表中的重复数据。上面有答案。

²  人员情况表(employee)中字段包括,员工号(ID),姓名(name),年龄(age),文化程度(wh):包括四种情况(本科以上,大专,高中,初中以下),现在我要根据年龄字段查询统计出:表中文化程度为本科以上,大专,高中,初中以下,各有多少人,占总人数多少。结果如下:
学历       年龄      人数        百分比
本科以上   20        34           14
大专       20        33           13
高中       20        33           13
初中以下   20        100          40
本科以上   21        50           20
。。。。。。

Transact-SQL查询语句如何写?

-- Count(*) * 100 由group by限定;SELECT Count(*) FROM是总数。

SELECT wh AS 学历,age as 年龄, Count(*) AS 人数,

Count(*) * 100 /(SELECT Count(*) FROM employee) AS 百分比

FROM employee GROUP BY wh,age

²  表一(AAA)
商品名称a   商品总量b
   A          100
   B          120
表二(BBB)
商品名称a   出库数量b
    A          10
    A          20
    B          10
    B          20
    B          30

用一条Transact-SQL语句算出商品A,B目前还剩多少?

select sum(b)

from (select * from a

union all select a, b*(-1) from b) x

group by a

²  找到连续编号中断的那一个的最小值

select   min(t.id) as id   from   (select   id=id+1   from   tt) t   
    where   id   not   in   (select   id   from   tt)

9.     实际应用

A) 为管理岗位业务培训信息,建立3个表:
S (S#,SN,SD,SA) S#,SN,SD,SA 分别代表学号、学员姓名、所属单位、学员年龄
C (C#,CN ) C#,CN 分别代表课程编号、课程名称
SC ( S#,C#,G ) S#,C#,G 分别代表学号、所选修的课程编号、学习成绩

²  查询选修课程名称为’税收基础’的学员学号和姓名

Select SN,SD FROM S  -- 实际上,使用3个join才是合理的

Where [S#] IN(

Select [S#] FROM C,SC

Where C.[C#]=SC.[C#]

AND CN=N'税收基础')

²  查询选修课程编号为’C2’的学员姓名和所属单位

Select S.SN,S.SD FROM S,SC

Where S.[S#]=SC.[S#]

AND SC.[C#]='C2'

²  查询不选修课程编号为’C5’的学员姓名和所属单位

Select SN,SD FROM S

Where [S#] NOT IN(      -- not in是正确的。不能使用=,会遗漏

Select [S#] FROM SC

Where [C#]='C5')

²  4. 查询选修全部课程的学员姓名和所属单位
-- 1)RIGHT JOIN可产生NULL行;2)COUNT(*),COUNT(S#)的结果不同

-- 解释:如果COUNT(*)<>COUNT(S#),

-- 说明C中有某个C#没有在sc中出现,也就是说:这门课程没有被S#同学选中。

Select SN,SD FROM S

Where [S#] IN(

Select [S#] FROM SC

RIGHT JOIN

C ON SC.[C#]=C.[C#] GROUP BY [S#]

HAVING COUNT(*)=COUNT([S#]))

²  5. 查询选修了课程的学员人数

Select 学员人数=COUNT(DISTINCT [S#]) FROM SC

²  6. 查询选修课程超过5门的学员学号和所属单位

-- 关注having子句中的count()等聚合函数的使用

Select SN,SD FROM S

Where [S#] IN(

Select [S#] FROM SC

GROUP BY [S#]

HAVING COUNT(DISTINCT [C#])>5)

B)该题目中,很多都有歧义,所以只要掌握的基本的方法,不需要深究细节。

/*

S (SNO,SNAME) 学生关系。SNO 为学号,SNAME 为姓名

C (CNO,CNAME,CTEACHER) 课程关系。CNO 为课程号,CNAME 为课程名,CTEACHER 为任课教师

SC(SNO,CNO,SCGRADE) 选课关系。SCGRADE 为成绩

*/

²  找出没有选修过“李”老师讲授课程的所有学生姓名

select distinct sname from s

where s.sno not in --因为有这种情况:S.SNO不在SC中存在。

(select sno from sc,c where sc.CNO=c.cno and cteacher = '李')

²  列出有二门以上(含两门)不及格课程的学生姓名及其平均成绩

Select S.SNO,S.SNAME,AVG_SCGRADE=AVG(SC.SCGRADE)

FROM S,SC,(

Select SNO FROM SC Where SCGRADE<60

GROUP BY SNO HAVING COUNT(DISTINCT CNO)>=2

)A  -- 实际上,使用 IN 进行条件连接也行

-- where控制条件,having控制分组条件并聚合

Where S.SNO=A.SNO AND SC.SNO=A.SNO

GROUP BY S.SNO,S.SNAME

--下面是错误结果:它只是把没有及格的科目进行了avg,并不是所有的科目的avg

select avg(sc.scgrade), s.sname

from s

join sc on sc.sno = s.sno and sc.scgrade < 60

group by s.sname having count(sc.scgrade)>=2

²  列出既学过“c1”号课程,又学过“c2”号课程的所有学生姓名

select s.sname

from s, (select * from sc

where sc.sno in (select sc.sno from sc where sc.cno = 'c1')

and sc.cno = 'c2') SS -- 把sc.sno in换为exists也可以。两种方案

where s.sno = ss.sno

²  列出“c1”号课成绩比“s2”号同学该门课成绩高的所有学生的学号

select sc.sno, sc.scgrade from sc

where sc.cno='c1' and

sc.scgrade>(select sc.scgrade from sc where sc.cno='c1' and sc.sno='s2')

²  列出“c1”号课成绩比“c2”号课成绩高的所有学生的学号及其“c1”号课和“c2”号课的成绩

select sc1.sno, sc1.cno, sc1.scgrade

from sc sc1,

(select sc1.sno, sc1.cno, sc1.scgrade

from sc sc1, sc sc2

where sc1.cno='c1' and sc2.cno='c2' and sc1.scgrade>sc2.scgrade

and sc1.sno=sc2.sno) sc2

where sc2.sno=sc1.sno and (sc1.cno='c1' or sc1.cno='c2')

1.简述进程调度的两种方式?

高级调度:又称作业调度。其主要功能是根据一定的算法,从输人的一批作业中选出若干个作业,分配必要的资源,如内存、外设等,为它建立相应的用户作业进程和为其服务的系统进程(如输人、输出进程),最后把它们的程序和数据调人内存,等待进程调度程序对其执行调度,并在作业完成后作善后处理工作。
低级调度:又称进程调度。其主要功能是根据一定的算法将CPU分派给就绪队列中的一个进程。执行低级调度功能的程序称做进程调度程序,由它实现 CPU在进程间的切换。进程调度的运行频率很高,在分时系统中往往几十毫秒就要运行一次。进程调度是操作系统中最基本的一种调度。在一般类型的操作系统中都必须有进程调度,而且它的策略的优劣直接影响整个系统的计能。
中级调度:又称交换调度。为了使内存中同时存放的进程数目不至于太多,有时就需要把某些进程从内存中移到外存上,以减少多道程序的数目,为此设立了中级调度。特别在采用虚拟存储技术的系统或分时系统中,往往增加中级调度这一级。所以中级调度的功能是在内存使用情况紧张时,将一些暂时不能运行的讲程从内存对换到外存上等待。当以后内存有足够的空闲空间时,再将合适的进程重新换人内存,等待进程调度。引人中级调度的主要目的是为了提高内存的利用率和系统吞吐量。它实际上就是存储器管理中的对换功能

进程的调度方式  
<1>进程的调度方式包括非剥夺方式和剥夺方式。 
非剥夺方式:  分派程序一旦把处理机分配给某进程后便让它一直运行下去,直到进程完成或发生某事件而阻塞时,才把处理机分配给另一个进程。 
剥夺方式:  当一个进程正在运行时,系统可以基于某种原则,剥夺已分配给它的处理机,将之分配给其它进程。剥夺原则有:优先权原则、短进程优先原则、时间片原则。 
<2>进程调度算法 
一、先来先服务和短作业(进程)优先调度算法 
   1. 先来先服务调度算法。 先来先服务(FCFS)调度算法是一种最简单的调度算法,该算法既可用于作业调度, 也可用于进程调度。FCFS算法比较有利于长作业(进程),而不利于短作业(进程)。由此可知,本算法适合于CPU繁忙型作业, 而不利于I/O繁忙型的作业(进程)。 
2. 短作业(进程)优先调度算法。 短作业(进程)优先调度算法(SJ/PF)是指对短作业或短进程优先调度的算法,该算法既可用于作业调度, 也可用于进程调度。但其对长作业不利;不能保证紧迫性作业(进程)被及时处理;作业的长短只是被估算出来的。 
二、高优先权优先调度算法 
1. 优先权调度算法的类型。 为了照顾紧迫性作业,使之进入系统后便获得优先处理,引入了最高优先权优先(FPF)调度算法。 此算法常被用在批处理系统中,作为作业调度算法,也作为多种操作系统中的进程调度,还可以用于实时系统中。当其用于作业调度, 将后备队列中若干个优先权最高的作业装入内存。当其用于进程调度时,把处理机分配给就绪队列中优先权最高的进程,此时, 又可以进一步把该算法分成以下两种: 
    1)非抢占式优先权算法 
    2)抢占式优先权调度算法(高性能计算机操作系统) 
   2. 优先权类型 。 对于最高优先权优先调度算法,其核心在于:它是使用静态优先权还是动态优先权, 以及如何确定进程的优先权。 
   3. 高响应比优先调度算法  
    为了弥补短作业优先算法的不足,我们引入动态优先权,使作业的优先等级随着等待时间的增加而以速率a提高。 该优先权变化规律可描述为:优先权=(等待时间+要求服务时间)/要求服务时间;即 =(响应时间)/要求服务时间。 
三、基于时间片的轮转调度算法 
1. 时间片轮转法。 时间片轮转法一般用于进程调度,每次调度,把CPU分配队首进程,并令其执行一个时间片。 当执行的时间片用完时,由一个记时器发出一个时钟中断请求,该进程被停止,并被送往就绪队列末尾;依次循环。   2. 多级反馈队列调度算法 多级反馈队列调度算法多级反馈队列调度算法,不必事先知道各种进程所需要执行的时间,它是目前被公认的一种较好的进程调度算法。 其实施过程如下: 
    1) 设置多个就绪队列,并为各个队列赋予不同的优先级。在优先权越高的队列中, 为每个进程所规定的执行时间片就越小。 
    2) 当一个新进程进入内存后,首先放入第一队列的末尾,按FCFS原则排队等候调度。 如果他能在一个时间片中完成,便可撤离;如果未完成,就转入第二队列的末尾,在同样等待调度…… 如此下去,当一个长作业(进程)从第一队列依次将到第n队列(最后队列)后,便按第n队列时间片轮转运行。 
    3) 仅当第一队列空闲时,调度程序才调度第二队列中的进程运行;仅当第1到第(i-1)队列空时, 才会调度第i队列中的进程运行,并执行相应的时间片轮转。 
    4) 如果处理机正在处理第i队列中某进程,又有新进程进入优先权较高的队列, 则此新队列抢占正在运行的处理机,并把正在运行的进程放在第i队列的队尾。 
进程间通信方式  
一,文件映射: 文件映射(Memory-Mapped Files)能使进程把文件内容当作进程地址区间一块内存那样来对待。因此,进程不必使用文件I/O操作,只需简单的指针操作就可读取和修改文件的内容。  
二,共享内存: Win32 API中共享内存(Shared Memory)实际就是文件映射的一种特殊情况。进程在创建文件映射对象时用0xFFFFFFFF来代替 文件句柄(HANDLE),就表示了对应的文件映射对象是从操作系统页面文件访问内存,其它进程打开该文件映射对象就可以访问该内存块。 
三,匿名管道: 匿名管道(Anonymous Pipe)是 在父进程和子进程之间,或同一父进程的两个子进程之间传输数据的无名字的单向管道。通常由父进程创建管 道,然后由要通信的子进程继承通道的读端点句柄或写 端点句柄,然后实现通信。 
四,命名管道: 命名管道(Named Pipe)是服务器进程和一个或多个客户进程之间通信的单向或双向管道。 
五,邮件槽: 邮件槽(Mailslots)提 供进程间单向通信能力,任何进程都能建立邮件槽成为邮件槽服务器。 
六,剪贴板: 剪贴板(Clipped Board)实质是Win32 API中一组用来传输数据的函数和消息,为Windows应用程序之间进行数据共享提供了一个 中介,  Windows已建立的剪切(复制)-粘贴的机制为不同应用程序之间共享不同格式数据提供了一条捷径。

有关数据库的一些面试题

1、在一个查询中,使用哪个关键字能够去重复值?
   使用distinct关键字
2、解释存储过程和触发器?
   存储过程:是一个已编译的SQL语句,不必重新编译,可以重复执行,提高了代码的重用性和数据库的性能;
   触发器:是一种特殊的存储过程,不由用户直接调用,创建触发器时会对其进行定义,以便在对特定的表或列做特定的操作时执行。
*3、SQL Server中的锁机制有哪些,有什么好处?
   有行级锁、表级锁
   优化数据的并行访问。
4、数据库日志是干什么用的?
   数据库日志用以记录所有事务和每个事务对数据库所做的操作。
5、存在过程和函数的区别?
   存储过程是用户定义的一系列的SQL语句的集合,涉及特定表或其它对象的任务,用户可以调用存储过程;
   函数通常是数据库已定义的方法,它接收参数并返回某程类型号的值并且不涉及特定用户表。
6、事务是什么,有哪些特性?
   事务是作为一个逻辑单元执行的一系列操作。
   事务的特性是:原子性、一致性、隔离性、持久性。
7、提高数据库运行效率的办法有哪些?
   (1)在数据库物理设计时,降低范式,增加冗余,少用触发器,多用存储过程;
   (2)复杂的计算先在数据库外进行,最后才入库追加到表中;
   (3)如果表的记录太多,可以使用水平分割法将表进行分割;如果表中字段太多可以使用垂直分割法把表进行分割;
   (4)优化各种系统参,如缓冲区个数。
    总之,要提高数据库的运行效率,必须从数据库系统级优化、数据库设计级优化、程序实现级优化,这三个层次进行考虑。
8、主键和唯一索引有什么区别?
   相同点:它们都属于实体完整性约束;
   不同点:i、唯一性约束所在的列允许为空值,但是主键不允许为空;
           ii、可以把唯一性约束放在一个或多个列上,但在一个表中只可以有一个主键;
           iii、唯一性约束强制在指定的列上创建一个唯一性索引;而建立主键的目的是为了让外建           来引用。
9、数据库的六大约束都是什么?
   (1)主键约束:primary key;
   (2)外键约束:foreign key;
   (3)非空约束:not null;
   (4)唯一约束:unique;
   (5)检查约束:check;
   (6)默认约束:default;
10、数据库设计的五个阶段?
   (1)需求分析:主要是准确收集用户信息需求和处理需求,并对其进行整理分析;
   (2)概念结构设计:对用户的需求进行综合、归纳、抽象,形成一个具体的DBMS概念模式;
   (3)逻辑结构设计:将概念模式转化为某个特定的DBMS所支持的数据模型,并对其进行优化;
   (4)物理结构设计:为设计好的逻辑模型选择物理结构,包括存储结构和存取方法;
   (5)实施和维护:使用DLL语言建立数据库模式,将实际数据载入数据库,并对运行中的数据库进行        调整和修改。
11、建立索引的作用和原则?
   作用:加快查询数据的速度;
   原则:如果某属性或属性组经常出现在查询的条件中,考虑为该属性建立索引;
         如果某属性常作为最大值和最小值等聚集函数的参数,考虑为该属性建立索引;
         如果某属性经常出现在连接操作的连接条件中,考虑为该属性建立索引。
12、什么上基本表?什么是视图?
   基本表是本身独立存在的表,在SQL中一个关系就对应一个表;
   视图是从一个或几个基本表导出的表,视图本身不独立存储在数据库中,是一个虚表。
13、视图的优点?
   (1)视图能够简化用户的操作;
   (2)视图使用户能以多种角度看待同一数据;
   (3)视图为数据库提供了一定程度的逻辑独立性;
   (4)视图能够对机密数据提供安全保护。
14、数据库的整体结构可分为?
   网状、层次型、关系型三种。
15、关系数据库有几种实体之间的关系?
   三种,一对一、一对多、多对多关系。
16、关系型数据库中,对数据库最简单的描述是什么?
   数据库是结构化的数据集合。
17、数据库语言分为哪几种?
   DDL:数据定义语句,用于定义数据的结构;(create , drop , alert)
   DML:数据操作语言,用于检索或者修改数据;(select , insert , update , delete )
   DCL:数据控制语言,用于定义数据库用户的权限;(alert , grant , revoke)
   TCL:事务控制语言,用于管理事务;(savepoint , rollback , commit)
18、死锁的产生及处理方法?
   事务循环等待数据锁,则会死锁;
   处理方法:i、SQL Server自动检测和消除死锁;
             ii、设置死锁的优先级;
             iii、使用更新锁避免死锁;
             iiii、设置锁定超时。
19、简述一下简单视图与复杂视图的区别?
   简单视图:简单视图是对单表的创建视图操作,可以对视图进行更新、插入、删除等操作;
   复杂视图:复杂视图是多表之间的创建视图操作,可以使用聚合函数,不可以对视图进行更新、插入、删除等操作。
20、索引主要分为哪几种?
   B树索引:是一种最常用和系统默认的索引类型;
   位图索引:适用于那些基数比较小的字段;
   唯一索引:保证索引列中的唯一性能。

各数据库建表示例:
Oracle数据库:
create table table_name
(
 id int primary key, --Oracle数据库中无字段自增,只能通过序列创建,或创建触发器来实现。
 name varchar2(20) not null,
 birthday date,
 sex char(2) check(sex='男'or sex='女') default('男'),
 tel varchar2(12) unique,
 salary number(8,2)
)
create table table_name_1
(
 f_id int primary key,
 f_name varchar2(20) not null,
 p_id int,
 foreign key(p_id) references table_name
)

SQL Server数据库:
create table table_test
(
 p_id int primary key identity(1,1),
 p_name varchar(20) not null,
 birthday smalldatetime,
 sex char(2) check(sex='男'or sex='女') default('男'),
 tel varchar(12) unique
 salary money,
)
create table table_test1
(
 f_id int primary key,
 f_name varchar(20) not null,
 p_id int,
 foreign key(p_id) references table_test
)

MySql数据库:
create table table_name
(
 id int auto_increment primary key,
 name varchar(20) not null,
 tel varchar(10) unique,
 salary decimal(8,2),
 sex char(2) check(sex='男' or sex='女') default('男'),
 birthday date
)
create table table_name1
(
 id int primary key,
 name varchar(20) not null,
 f_id int,
 foreign key(f_id) references table_name(p_id)
)

Orical数据库的存储过程:
create [or replace] procedure p_name
(
  p_name p_type
)
as 
begin
PL/SQL语句;
end;

示例:输入empno,输出工种job,实发工资(sal+comm)?
create or replace procedure p1
(
p_empno in emp.empno%type,
p_job out emp.job%type,
p_salcomm out number
)
as
begin
select job,sal+nvl(comm,0)into p_job,p_salcomm from emp where empno=p_empno;
end;
调用存储过程的方法:
declare p_job varchar2(20);p_salcomm number(9,2);
begin
p1(123,p_job,p_salcomm);
end;

SQL Server数据库存储过程:
create procedure p_name
@param_name data_type,
@param_name2 data_type output
as
select @p2=column_name from table_name where column_name=@p1
示例:输入业务员编号,姓名,显示性别,电话?
create procedure p1
@p_ywid int,
@p_name varchar(8)
as
select sex,tel from shop_yw where ywid=@ywid and name=@p_name;
execute p1 1,'李小明';

Oracle数据库触发器:
create [or replace] trigger trigger_name [before/after] insert/update/delete on table_name
for each row
[when(condition)]
[declare]
begin
PL/SQL
end;
示例:当向销售表中添加一条记录后,触发实现基本表库存量做相应减少?
create or replace trigger t1
after insert
on show_xs
for each row
begin
update shop_jb set stock=stock-:new.quantity where id=:new.id;
end;

SQL Server数据库触发器:
create trigger trigger_name
on table_name
after/instead of    insert/delete/update
as
PL/SQL
示例:向销售表中添加一条记录,触发器基本表中库存量做相应的减少?
create trigger t1
on shop_xs
after insert
as
update shop_jb set stock=stock-(select quantity from inserted) where id=(select id from inserted);

1. 异常是如何产生的? 
答:java程序把运行中的各种可能出现的错误都看作异常 
异常是在程序运行过程中,由于不可避免的原因产生的错误例如除数为零,文件找不到无法读写.网点连接不上等 
2. 异常有哪些种类,他们的特点是什么? 
答:异常可分为:java.lang.Exception、java.lang.Error两大类. Error:由java虚拟机生成并抛出,java程序不做处理. 
Exception(程序可不做处理,可预知的):java编译器要求java程序必须捕捉或声明所有的非运行时异常. 
3. finally的作用是什么? 
答:Finally语句是为异常处理事件提供的一个清理机制,一般是用来关闭文件或释放其他
系统资源。作为try-catch-finally结构的一部分,可以没有Finally语句,如果存在Finally语句,不论try块中是否发生异常,是否执行过catch语句,都执行finally语句。 
4. java访问权限有哪些,他们的作用是什么? 
答:java中有四种访问控制权限,分别为:private, default, protected, public. 
1.private访问 
如果一个成员方法或成员变量名前使用了private访问控制符,那么这个成员只能在这个类的内部使用。 2.默认访问(default) 
默认访问控制成员可以被这个包的其它类的访问,如果一个子类与其父类位于不同的包中,子类也不能访问父类中是默认访问控制成员。 
3.protected访问 
如果一个成员方法或成员变量名前使用了protected访问控制符,那么这个成员即可以被同一个包中是其它类访问,也可以被不同包中的子类访问。 4.public访问 
如果一个成员方法或成员变量名前使用了public访问控制符,那么这个成员可以被所有的类访问,不管访问类与被访问类是否在同一个包中 
5. 请你谈谈对向上转型和向下转型的理解。 
答:向上转型是指子类中的对象转为父类的对象,java会自动完成。 
而向下转型是指把父类中的对象转为子类的对象,要想完成向下转型,要先进行向上转型,再向上转型,才能保证转型成功。

可以这么理解
try块中的内容是在无异常发生时执行到结束
catch块中的内容,是在try块中内容发生catch所声明的异常时,跳转到catch块执行
finally块则是无论是否发生异常,都会执行finally块的内容
所以,代码逻辑中有需要无论发生什么都必须执行的代码,则可以放在finally块中
例如:最常见的就是把关闭connection、释放资源等的代码放在finally块中
题目: final, finally, finalize的区别。答案:final修饰符(关键字),如果一个类被声明为final,意味着它不能再派生出新的子类,不能作为父类被继承。因此一个类不能既被声明为abstract的,又被声明为final的。将变量或方法声明为final,可以保证它们在使用中不被改变。被声明为final的变量必须在声明时给定初值,而在以后的引用中只能读取,不可修改。被声明为final的方法也同样只能使用,不能重载。方法的参数被final修饰表示在方法体内,该参数的值不可以被修改。 private final String ss = "ss";public final void m(){}public String m2(final String param){}finally在异常处理时提供finally块来执行任何清除操作。无论有没有异常被抛出、捕捉,finally块都会被执行。 finalize是方法名。Java技术允许使用finalize()方法在垃圾收集器将对象从内存中清除出去之前做必要的清理工作。这个方法是由垃圾收集器在确定这个对象没有被引用时对这个对象调用的。它是在Object类中定义的,因此所有的类都继承了它。子类覆盖finalize()方法以整理系统资源或者执行其他清理工作。finalize()方法是在垃圾收集器删除对象之前对这个对象调用的。
无异常执行 try
有异常执行catch
不管有无异常都要执行 finally
finally的作用用来关闭流、关闭连接、释放或销毁资源。

中兴面试总结,华为。技术,市场相关推荐

  1. 华为技术面试编码题_最佳技术编码面试准备书

    华为技术面试编码题 Technical coding interviews are notoriously difficult - almost borderline quiz-like for th ...

  2. 华为技术服务工程师实习生面试(已拿到offer)

    华为作为世界500强企业,让非常多的应届生想进去,而且,华为给应届生开的工资比很多公司高(应届生能上万...).今年华为是第一次公开招聘实习生,让我们学校的很多人跃跃欲试.华为的非技术岗的实习生招聘流 ...

  3. 华为笔记本软件商店_华为应用市场电脑版

          华为应用市场电脑版是一款手机自带的应用商店下载中心,华为应用市场电脑版能够为用户提供新鲜.好玩的Android应用,华为应用市场电脑版能完美运行的应用和游戏,软件拥有独家"一键安 ...

  4. nb-iot 华为云_海曼NB-IoT智慧消防解决方案通过华为云资格审核,正式入驻华为云市场...

    近日,海曼科技旗下NB-IoT智慧消防解决方案(含NB-IoT智能烟感.气感)通过华为云的重重资格审核,正式入驻华为云市场,推动消防产业智能升级,助力智慧城市发展! 严选商城 华为云严选商城,是华为的 ...

  5. Android版本9华为,华为应用市场旧版本下载-华为应用市场老版v9.0.0.303 安卓版 - 极光下载站...

    华为应用市场老版简介: 华为应用市场是华为手机官方应用下载平台,也是华为用户首选应用市场,是基于android系统的免费资源共享平台,依托华为全球化技术服务平台和实力雄厚的开发者群体,用户可以在应用市 ...

  6. 华为小程序怎么弄出来_华为应用市场也支持“小程序”了,你get了吗?

    微信小程序的出现,给用户和手机商家都带来了变化,不仅支付宝也推出小程序,谷歌谷歌也在推广一种全新的"实时软件"(Instant Apps)技术,让手机软件无需下载安装就能快速启动. ...

  7. 集成机器学习服务上架华为应用市场指南

    华为机器学习服务是什么 华为机器学习服务(ML Kit) 提供机器学习套件,为开发者应用机器学习能力开发各类应用提供优质体验.得益于华为长期技术积累,ML Kit为开发者提供简单易用.服务多样.技术领 ...

  8. DeepFM:深度学习算法助力华为应用市场APP推荐

    今年8月下旬,在澳大利亚墨尔本召开的IJCAI2017会议上,来自华为伏羲推荐团队的专家发表了他们在深度学习推荐算法方面的最新成果.伏羲推荐引擎是华为应用市场联合华为诺亚方舟实验室开发的一款推荐系统. ...

  9. 刷脸时代来临,深度解析人脸识别技术市场

    刷脸时代来临,深度解析人脸识别技术市场 编者按:iPhone X带动更多智能手机集成3D人脸识别,公共场所日益增长的监控需求.刷脸时代来临,人脸识别技术巨大的市场需求与广阔的应用前景,盈利模式多变,消 ...

  10. 唯众IT教学云平台获华为技术认证,入驻华为云严选商城

    2021年11月29日,唯众IT教学云平台获华为技术认证,入驻华为云严选商城! 唯众IT教学云平台华为技术认证 唯众IT教学云平台华为技术认证 华为云市场严选商城"使命" 对客户: ...

最新文章

  1. 盘点2019年336起机器人及相关领域投融资事件!注重细分领域深耕行业复苏趋势显现...
  2. GetResponse() 基础连接已经关闭:服务器关闭了本应保持活动状态的连接
  3. spring cloud config将配置存储在数据库中 1
  4. GitHub 发布了一款重量级产品,可直接运行代码!
  5. 关于ORACLE 10g中“ORA-12541:TNS:no listener”的问题解决方案
  6. 计算机dns的工作原理,DNS的工作原理图解说明
  7. 数据分析学习笔记——数据可视化
  8. NodeJS-queryString
  9. 作者:王志强(1975-),男,中国标准化研究院高新技术与信息标准化研究所副研究员、副所长。...
  10. CoreAnimation编程指南(简介)转自:http://www.dreamingwish.com/
  11. 好程序员web前端分享常见html5语义化标签
  12. [最小割] Luogu P4662 黑手党
  13. Android Problem- android.content.res.Resources$NotFoundException: String resource ID #0xa
  14. 走近汇编理解与内核编程
  15. python基本数据类型——整型,浮点型,复数,字符串
  16. DOS命令:diskpart
  17. 安卓系统PK浏览器:物联网开发,哪个才是最佳之选?
  18. collapsible data-collapsed Jquery-mobile动态设置
  19. 黑科技丨电脑必备的chrome插件(一)
  20. Spring Boot 解决同名类导致的bean名冲突bean name conflicts

热门文章

  1. 买菜app开发的基本功能
  2. Excel 函数教程之VLOOKUP实用教程与10个适用于初学者和高级用户的VLOOKUP案例(教程含数据excel)
  3. word文档docx密码忘了怎么办,word文档docx权限限制怎么办?
  4. Visual Basic编程的七个优良习惯
  5. canvas的fillText参数解释
  6. kotlin实现坦克大战
  7. SYD8821 WDT模块使用说明【WDT中断的使用】【WDT复位类型】
  8. IPC\DVS\DVR\NVR|XVR
  9. 旅行社管理系统 java_旅行社管理系统纯Java
  10. 回字有四种写法,阶乘verilog实现有几种方法?