苹果的成长日记

我还是个青苹果呀!

  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::
  57 随笔 :: 0 文章 :: 74 评论 :: 0 Trackbacks

我的评论

我这段时间也在跟老公办理随迁,也真是给气得不行。

前楼主是写得是很详细,但我想再问一下计划生育证明,去派出所交资料就说差计划生育证明,但我去深圳的我户口的街道办去办理,又要说要老公老家当地户口所在地的计划生育证明,深圳这边的才能开。还需要我户口本的首页。要不我这边的街道办不给开计划生育证明。

所以请各位知道的能尽快帮忙告诉。非常的感谢。
re: JXL操作Excel[未登录] 苹果 2008-05-29 11:49  
简练!精炼!易懂! 好东西,值得学习!
如何制作银行支出表
谢谢,已收到,希望相互多多交流
谢谢,也给我发一份吧!
steven.yj@163.com
每个包使用一个特性文件,按类名称来限定键。
re: 【转载】java collection framwork 苹果 2005-06-28 15:41  
Map:关心唯一标识符。把唯一键(ID)映射为具体值,当然,键和值二者都是对象。这里,位于Map中的键基于键的散列码,因此,hashCode()设计越有效,访问性能越好。
HashMap:未分类未排序
适合:需要Map,而不关心其顺序(当遍历它时),则HashMap是一种方法,其他映射增加更多的开销。HashMap允许在一个集合中有一个null键和在一个集合中有多个null值。
Hashtable:是HashMap的同步版本。
记住:不要同步类,所谓同步,是指同步该类的主要方法。HashMap允许有null值和一个null键,但是Hashtable不允许有任何内容为null。
LinkedHashMap:维护插入顺序(或者访问顺序)。添加和删除元素比HashMap慢,但是遍历得更快。
TreeMap:分类排序。
re: 【转载】java collection framwork 苹果 2005-06-28 15:24  
所谓的有序就是你能够按照某种特定的(而不是随机的)顺序遍历这个集合。所谓的分类是指按照自然顺序分类的集合。排序的集合如果使用自然顺序或者在分类集合的构造函数中定义排序规则,就认为是分类的。 Set:关心唯一性——它不允许重复。equals()方法确定两个对象是否完全相同。
HashSet: 未排序未分类,它使用被插入对象的散列码。因此,hashCode()设计越有效,访问性能越好。
适合:需要集合不具有任何重复值,并且遍历它不关心顺序时。
LinkedHashSet:LinkedHashSet是HashSet的排序版本。可以构造一个按元素的访问顺序排序而不是插入顺序排序的LinkedHashSet。
适合:当关心遍历顺序时。如果想建立最近最少使用缓存
TreeSet: 排序、分类。使用一种Red-Black树结构,并保证元素将按照元素的自然顺序(可以在构造函数里提供规则)进行升序排列。
re: 【转载】java collection framwork 苹果 2005-06-28 15:15  
List: List只关心索引。所有三种List设计都是按照索引位置排序
ArrayLsit:
可以看做一个可增长的数组,特点是快速遍历和快速随机访问。排序但没有分类。
适合场所:需要快速遍历但不可能做大量的插入和删除
Vector:
基本与ArrayList相同,但是,为了安全起见,Vector()方法被同步了。通常会使用ArrayList而不是Vector,以免不必要的性能损失。如果确实需要线程安全,在Collections类中有些实用方法能够解决。
LinkedList:按照索引位置排序,它象ArrayList一样,除了元素相互之间是双链接之外。这种链接为从头到尾添加和删除提供新的方法(除了List接口得到的之外),适合用于设计栈和队列。
LinkedList遍历可能比ArrayList慢,适合:需要快速插入和删除。
re: 【Java面试题集锦系列一】 苹果 2005-06-24 15:11  
垃圾收集器
java的垃圾收集器为内存管理提供了一种自动解决方案。在多数情况下,它把你从必须为应用程序添加所有内存管理中解脱出来。自动垃圾收集的缺点是不能完全控制它什么时候执行以及什么时候不执行。
堆是java对象所在的内存部分,它是垃圾收集处理所涉及的一块也是唯一的一块内存。所有的垃圾收集考虑的是要确保堆有尽可能多的自由空间。问题的核心就是要删除运行的java程序不能再到达的任何对象。当垃圾收集器运行时,其目的时查找和删除不能被访问的对象,如果把java程序看作是处于一个这样的固定循环中:创建它所需的对象(这要占用堆上的空间),之后当不再需要他们时废弃它们,创建新的对象,再废弃它们,如此循环,这个问题中缺少的一部分是垃圾收集器。当它运行时,它从内存中查找那些被废弃的对象,并删除它们,这样使使用内存和释放内存的循环能够继续。
1。垃圾收集器什么时候运行?
垃圾收集器受JVM控制,JVM决定什么时候运行垃圾收集器。从Java程序内可以请求JVM运行垃圾收集器,但是,在任何情况下都无法保障JVM会答应你的请求。JVM通常会在它感到内存减少时运行垃圾收集器。经验告诉我们:当java程序请求进行垃圾收集时,JVM通常会在短期内响应请求,但这没有任何保障。刚好在你认为可以依靠它时,JVM可能会忽略你的请求。
2.GC怎样工作?
什么时候对象变得符合垃圾收集条件?每个java程序有一个或多个线程,每个线程都有其自己的小执行栈。通常,在一个java程序中至少要运行一个线程,即栈底部main()方法的线程。出了有其自己的小执行栈外,每个线程都有其自己的生命周期。线程可以是死的或活的,当没有任何活线程能够访问一个对象时,该对象就符合垃圾收集条件。
根据这一定义,GC做一些不可思议的未知操作,当它发现一个对象不能被任何活线程访问时,它将认为该对象符合删除条件,它可能在某时删除它(它也可能不删除它)。所谓到达一个对象,实际上是有一个可到达的引用变量引用所讨论的对象。如果我们的java程序有一个引用变量引用一个对象,并且该引用变量可用于一个活线程,则该对象被认为是可到达的。
注意:一个java程序能够耗尽内存。垃圾收集系统尝试在对象不被使用时把它们从内存中删除。然而,如果保持太多活对象(被其他活对象引用的对象),系统则会耗尽内存。垃圾收集不能保证有足够的内存,它只能保证可以使用的内存将尽可能被有效地管理。
3.编写代码明确使对象符合搜集条件
怎样使对象符合垃圾收集条件,怎样在必要时强制执行垃圾收集,怎样执行额外地清理?
1)空引用 把引用该对象的引用变量设置为null,使没有对它的可到达引用
public class GarbageTruck {
public static void main(String[] args) {
StringBuffer sb = new StringBuffer("hello");
System.out.println(sb);
//The StringBuffer object is not eligible for collection
sb = null;
//Now the StringBuffer object is eligible for collection
}
}
2)重新为引用变量赋值
可以通过设置引用变量引用另一个对象来解除该引用变量与一个对象间的引用关系。
class GarbageTruck {
public static void main(String [] args) {
StringBuffer s1= new StringBuffer("hello");
StringBuffer s2= new StringBuffer(goodbye");
System.out.println(s1);
//At this point the StringBuffer "hello" is not eligible
s1=s2;//Redirects s1 to refer to the "goodbye" object
//Now the StringBuffer "hello" is eligible for collection
在方法内创建对象也要考虑一下。当调用方法时,所创建的任何局部变量只在该方法期间存在。一旦该方法返回,在这个方法那创建的对象就符合垃圾收集条件。然而,有一种明显的例外情况,如果一个对象从一个方法被返回,其引用可能在调用它的方法内被赋予一个引用变量,因此它不符合搜集条件。请看下面代码:
import java.util.Date;
public class GarbageFactory {
public static void main(String[] args) {
Date d = getDate();
doComplicatedStuff();
System.out.println("d = "+d);
}
public static getDate() {
Date d2 = new Date();
String now = d2.toString();
System.out.println(now);
return d2;
}
}
在方法getDate()中,创建了两个对象,一个Date对象和一个包含日期信息的String对象。因为该方法返回Date对象,所以它将不符合搜集条件,即使在该方法完成之后。然而String对象将符合条件,即使没有明确把now变量设置为null。
3.隔离引用
一般来说,我们把正在计算机中执行的程序叫做"进程"(Process) ,而不将其
称为程序(Program)。所谓"线程"(Thread),是"进程"中某个单一顺序的控制流。
新兴的操作系统,如Mac,Windows NT,Windows 95等,大多采用多线程的概念,把线
程视为基本执行单位。线程也是Java中的相当重要的组成部分之一。

  甚至最简单的Applet也是由多个线程来完成的。在Java中,任何一个Applet的
paint()和update()方法都是由AWT(Abstract Window Toolkit)绘图与事件处理线
程调用的,而Applet 主要的里程碑方法——init(),start(),stop()和destory()
——是由执行该Applet的应用调用的。

  单线程的概念没有什么新的地方,真正有趣的是在一个程序中同时使用多个线
程来完成不同的任务。某些地方用轻量进程(Lightweig ht Process)来代替线程
,线程与真正进程的相似性在于它们都是单一顺序控制流。然而线程被认为轻量是
由于它运行于整个程序的上下文内,能使用整个程序共有的资源和程序环境。

  作为单一顺序控制流,在运行的程序内线程必须拥有一些资源作为必要的开销
。例如,必须有执行堆栈和程序计数器。在线程内执行的代码只在它的上下文中起
作用,因此某些地方用"执行上下文"来代替"线程"。

  2.线程属性

  为了正确有效地使用线程,必须理解线程的各个方面并了解Java 实时系统。
必须知道如何提供线程体、线程的生命周期、实时系统如 何调度线程、线程组、
什么是幽灵线程(Demo nThread)。

  (1)线程体
  所有的操作都发生在线程体中,在Java中线程体是从Thread类继承的run()方
法,或实现Runnable接口的类中的run()方法。当线程产生并初始化后,实时系统调
用它的run()方法。run()方法内的代码实现所产生线程的行为,它是线程的主要部
分。

  (2)线程状态
  附图表示了线程在它的生命周期内的任何时刻所能处的状态以及引起状态改
变的方法。这图并不是完整的有限状态图,但基本概括了线程中比较感兴趣和普遍
的方面。以下讨论有关线程生命周期以此为据。


  ●新线程态(New Thread)
  产生一个Thread对象就生成一个新线程。当线程处于"新线程"状态时,仅仅是
一个空线程对象,它还没有分配到系统资源。因此只能启动或终止它。任何其他操
作都会引发异常。
  ●可运行态(Runnable)
  start()方法产生运行线程所必须的资源,调度线程执行,并且调用线程的run
()方法。在这时线程处于可运行态。该状态不称为运行态是因为这时的线程并不
总是一直占用处理机。特别是对于只有一个处理机的PC而言,任何时刻只能有一个
处于可运行态的线程占用处理 机。Java通过调度来实现多线程对处理机的共享。

  ●非运行态(Not Runnable)
  当以下事件发生时,线程进入非运行态。
  ①suspend()方法被调用;
  ②sleep()方法被调用;
  ③线程使用wait()来等待条件变量;
  ④线程处于I/O等待。
  ●死亡态(Dead)
  当run()方法返回,或别的线程调用stop()方法,线程进入死亡态 。通常Appl
et使用它的stop()方法来终止它产生的所有线程。

  (3)线程优先级
  虽然我们说线程是并发运行的。然而事实常常并非如此。正如前面谈到的,当
系统中只有一个CPU时,以某种顺序在单CPU情况下执行多线程被称为调度(schedu
ling)。Java采用的是一种简单、固定的调度法,即固定优先级调度。这种算法是
根据处于可运行态线程的相对优先级来实行调度。当线程产生时,它继承原线程的
优先级。在需要时可对优先级进行修改。在任何时刻,如果有多条线程等待运行,
系统选择优先级最高的可运行线程运行。只有当它停止、自动放弃、或由于某种
原因成为非运行态低优先级的线程才能运行。如果两个线程具有相同的优先级,它
们将被交替地运行。
  Java实时系统的线程调度算法还是强制性的,在任何时刻,如果一个比其他线
程优先级都高的线程的状态变为可运行态,实时系统将选择该线程来运行。

  (4)幽灵线程
  任何一个Java线程都能成为幽灵线程。它是作为运行于同一个进程内的对象
和线程的服务提供者。例如,HotJava浏览器有一个称为" 后台图片阅读器"的幽灵
线程,它为需要图片的对象和线程从文件系统或网络读入图片。
  幽灵线程是应用中典型的独立线程。它为同一应用中的其他对象和线程提供
服务。幽灵线程的run()方法一般都是无限循环,等待服务请求。

  (5)线程组
  每个Java线程都是某个线程组的成员。线程组提供一种机制,使得多个线程集
于一个对象内,能对它们实行整体操作。譬如,你能用一个方法调用来启动或挂起
组内的所有线程。Java线程组由ThreadGroup类实现。
  当线程产生时,可以指定线程组或由实时系统将其放入某个缺省的线程组内。
线程只能属于一个线程组,并且当线程产生后不能改变它所属的线程组。

  3.多线程程序

  对于多线程的好处这就不多说了。但是,它同样也带来了某些新的麻烦。只要
在设计程序时特别小心留意,克服这些麻烦并不算太困难。

  (1)同步线程
  许多线程在执行中必须考虑与其他线程之间共享数据或协调执行状态。这就
需要同步机制。在Java中每个对象都有一把锁与之对应。但Java不提供单独的lo
ck和unlock操作。它由高层的结构隐式实现, 来保证操作的对应。(然而,我们注
意到Java虚拟机提供单独的monito renter和monitorexit指令来实现lock和unlo
ck操作。)
  synchronized语句计算一个对象引用,试图对该对象完成锁操作, 并且在完成
锁操作前停止处理。当锁操作完成synchronized语句体得到执行。当语句体执行
完毕(无论正常或异常),解锁操作自动完成。作为面向对象的语言,synchronized
经常与方法连用。一种比较好的办法是,如果某个变量由一个线程赋值并由别的线
程引用或赋值,那么所有对该变量的访问都必须在某个synchromized语句或synch
ronized方法内。
  现在假设一种情况:线程1与线程2都要访问某个数据区,并且要求线程1的访
问先于线程2, 则这时仅用synchronized是不能解决问题的。这在Unix或Windows
NT中可用Simaphore来实现。而Java并不提供。在Java中提供的是wait()和noti
fy()机制。使用如下:
  synchronized method-1(…){ call by thread 1.
  ∥access data area;
  available=true;
  notify()
  }
  synchronized method-2(…){∥call by thread 2.
  while(!available)
  try{
  wait();∥wait for notify().
  }catch (Interrupted Exception e){
  }
  ∥access data area
  }
  其中available是类成员变量,置初值为false。
  如果在method-2中检查available为假,则调用wait()。wait()的作用是使线
程2进入非运行态,并且解锁。在这种情况下,method-1可以被线程1调用。当执行
notify()后。线程2由非运行态转变为可运行态。当method-1调用返回后。线程2
可重新对该对象加锁,加锁成功后执行wait()返回后的指令。这种机制也能适用于
其他更复杂的情况。

  (2)死锁
  如果程序中有几个竞争资源的并发线程,那么保证均衡是很重要的。系统均衡
是指每个线程在执行过程中都能充分访问有限的资源。系统中没有饿死和死锁的
线程。Java并不提供对死锁的检测机制。对大多数的Java程序员来说防止死锁是
一种较好的选择。最简单的防止死锁的方法是对竞争的资源引入序号,如果一个线
程需要几个资源,那么它必须先得到小序号的资源,再申请大序号的资源。

  4.小结

  线程是Java中的重要内容,多线程是Java的一个特点。虽然Java的同步互斥不
如某些系统那么丰富,但适当地使用它们也能收到满意的效果。
re: 【Java面试题集锦系列一】 苹果 2005-06-23 21:49  
Java线程及同步(synchronized)样例代码

--------------------------------------------------------------------------------

Java线程及同步(synchronized)样例代码


import java.io.*;
import java.util.*;
import java.text.SimpleDateFormat;

public class TestThread extends Thread
{
private static Integer threadCounterLock; //用于同步,防止数据被写乱
private static int threadCount; //本类的线程计数器

static
{
threadCount = 0;
threadCounterLock = new Integer(0);
}

public TestThread()
{
super();
}

public synchronized static void incThreadCount()
{
threadCount++;
System.out.println("thread count after enter: " + threadCount);
}

public synchronized static void decThreadCount()
{
threadCount--;
System.out.println("thread count after leave: " + threadCount);
}

public void run()
{
synchronized(threadCounterLock) //同步
{
threadCount++;
System.out.println("thread count after enter: " + threadCount);
}

//incThreadCount(); //和上面的语句块是等价的

final long nSleepMilliSecs = 1000; //循环中的休眠时间

long nCurrentTime = System.currentTimeMillis();
long nEndTime = nCurrentTime + 30000; //运行截止时间
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

try
{
while (nCurrentTime < nEndTime)
{
nCurrentTime = System.currentTimeMillis();
System.out.println("Thread " + this.hashCode() + ", current time: " + simpleDateFormat.format(new Date(nCurrentTime)));

try
{
sleep(nSleepMilliSecs);
}
catch(InterruptedException ex)
{
ex.printStackTrace();
}
}
}
finally
{
synchronized(threadCounterLock) //同步
{
threadCount--;
System.out.println("thread count after leave: " + threadCount);
}

//decThreadCount(); //和上面的语句块是等价的
}
}

public static void main(String[] args)
{
TestThread[] testThread = new TestThread[2];
for (int i=0; i {
testThread[i] = new TestThread();
testThread[i].start();
}
}
}

同步就是简单的说我用的时候你不能用,大家用的要是一样的就这样!
比如说有只苹果很好吃,我拉起来咬一口,放下,你再拉起咬一口,这就同步了,要是大家一起咬,呵呵,那就结婚吧,婚礼上常能看到这个,也不怕咬着嘴,嘻嘻嘻!

举个例子,现在有个类,类中有一个私有成员一个苹果,两个方法一个看,一个吃。
现在不同步,我一“看”,哈哈一个苹果,我“吃”四分之一了
你一“看”,哈哈一个苹果,也“吃”四分之一了。
可能的情况就是都是看到一个苹果但我的吃方法用在你的之前,所以可能你只能吃到3/4的1/4也就是3/16个而不是1/4个苹果了。
现在加入同步锁,我在吃的时候你看被锁,等吃完了,你再看,啊3/4个苹果,吃1/3好了了,就这样!
re: 【Java面试题集锦系列一】 苹果 2005-06-23 21:48  
内部类
内部类的主要优点之一是内部类实例与外部类实例共享一种“特殊关系”。这种特殊关系为内部类中的代码提供对封装(外部)类成员的访问,就好象内部类是外部类的一部分。不仅是“一部分”,而且是外部类一个羽翼丰满、带着卡片的成员。内部类实例可以访问外部类的所有成员,甚至哪些被标识为private的成员。
re: 【转载】java与C++的区别 苹果 2005-06-23 21:11  
Java群体每天都在扩大,它既包括一些世界最大的ISV,也包括公司CIO、信息技术人员、系统分析人员、C/S开发人员、编程人员、多媒体设计者、市场行销人员、教育工作者、经理、影视生产者甚至业余爱好者等广泛的用户。从传统上看,这样一些人在一起有效地工作是不多见的。当我们谈到开放系统时,我们往往是就已发表的API及规格,或者源码的可得性,或者硬件、联网及操作系统而言的,没有一个人是从人的开放意义上来谈的。Java完成了开放系统的闭合链。它开发了人力资源,而反过来又开辟了共同工作的道路。

一谈到Java,人们马上会想起一种类似于C++的、适用于分布环境的面向对象编程语言,想到这种语言的简单、稳定、安全、与体系结构无关、可移植、可解释、高性能、多线程和动态性等特征。这些都是Java作为一种程序设计语言的主要特征。

Java是由Sun公司的一个技术小组研制出来的。在实现Java语言的过程中,Sun小组的技术人员很快就意识到:C++无法成为一种完全面向对象的、网络化的开发语言。C++是通过给原先的C语言增加面向对象功能而开发出来的,因此,它存在着先天不足。这主要体现在C++种类繁多,功能大量冗余,同时又没有任何一种C++编译器能够支持它的全部功能。鉴于这种情况,Sun公司的技术人员决定不扩充C++,而开发一种全新的计算机语言(Java的前身Oak)。但是,C++已经成了大多数编程人员所熟练掌握的语言,Java的设计显然不能无视这个现实。如果Java和C++之间的差别过大,那么程序员们在学会这种语言的过程中无疑要花费大量的时间和精力。因此,Java保留了尽可能多的C++风格。

Java自诞生起,为网络用户创造了无数客户端的小应用程序,由于这类应用程序效果良好、数量巨大,以至于许多用户想到Java编程语言时,会在脑海中出现一个不完全正确的印象-Java是用来编写小的客户端程序的。其实,随着技术的进步,Java语言正在逐步改变自己执行效率较低、无法担任企业关键计算任务的形象,不断向计算技术的核心地带前进。今天的Java技术正沿着网络渗入各个应用领域。

企业计算:企业计算是Java最重要的技术主题。Sun公司已经公布了企业JavaBean(EJB,Enterprise JavaBean)的规格,随后众多公司开始开发企业应用领域的Java技术。IBM公司也已经为Windows NT开发了IBM HPCJ(High Performance Compiler for Java)12.0版,同时研制了IBM JDK(JavaDevelopment Kit)for Windows NT,Novell公司也在宣布了一个新的服务器端的企业Java平台,而Sun公司也在积极地升级自己的JDK系统,这个形势表明,Java正在稳步走向企业高端计算。对于Java来说,与其它编程语言争夺企业计算主力编程工具的优势在于:其一,Java在进行面向对象的编程工作时,比其它的编程语言如C++更加简单,因此保证了编程的高效率,减少了编程投入;其二,Java虚拟机技术所提供的"一次编程,到处使用"的跨平台能力非常适合网络环境,这给Java在网络服务器端的发展提供了便利条件;其三,Java拥有强大的提供商和支持者队伍,该队伍包括IBM、Oracle、Novell、Sybase和Netscape等公司。

提速运行:许多企业的应用开发人员非常喜爱Java的语言特性,但是在开发重要系统时,语言特性和执行效率之间的抉择往往令人伤透脑筋。在关键计算中,用户可能并不在乎数据如何压缩或者运行的延迟关系如何设置,但是对程序的运行速度却非常重视,这使厂商将Java的编译策略开发放在了首位。现在的Java语言,其执行方式已经不仅仅是解释执行方式了,即时编译器(JITC、just-in-time compiler)技术和原型编译技术已经被许多厂家采用,包括Sun、IBM、Oracle以及Netscape等公司在内的技术提供商正在利用这些技术逐步提高Java的执行速度,其中IBM公司早已将Java虚拟机(JVM,JavaVirtual Machine)、操作系统和硬件的特性有机的结合在一起,非常有效地提高了Java的执行效率。

嵌入计算:嵌入式Java是一个潜力巨大的应用技术,该技术充分发挥了Java小巧灵活的特点。以HP公司为例,该公司以自己的方式制造编译工具和Java虚拟机,其目的是将Java嵌入各种设备,如打印机、医学监视器和自动提款机等。嵌入设备依靠一个实时操作系统来处理某一个实时生效的事件,Java被嵌入这些设备后,通过实时扩展(real-time extension)开始发挥作用,使设备具备了一定的智能性,增强了嵌入设备的可管理性和可用性,大大提高了设备的工作效率。各厂商对这一潜力巨大的市场都非常重视,目前该市场缺乏的是一个标准,如果存在标准的话,相信很快就会有大量使用嵌入Java技术的设备上市。

微软刚刚发行的Windows XP放弃了对Java的支持,但Java能够独立运行于很多操作平台上,其中也包括Linux,并且在某些特性上要比在Windows上发挥得更好,我们完全有理由抛弃Windows而选择使用Linux来做Java开发。现在,你可以左手拿着Linux,右手拿着Java,然后对面带微笑手里拿着Windows XP的Bill Gates说:"让你的XP去见鬼吧!"

对于软件开发者来讲,任何一种编程语言都不可能是完美的。如果希望更好地理解Java语言,最好的方法是把这种语言与其同类型的语言相比较。既然Java类似于C++,把它同C++进行一番比较也是顺理成章的事情,哪一个好,哪一个不好,每个开发人员都有各自的看法。我个人认为Java开发要比C++好一些。当然每个人的看法和喜好是不同的。后面的文章将向大家介绍Java和C++的不同和对其的改进。孰强孰弱,大家自然就会明白了。

我们知道,Java一开始采用C++的语法格式,基本上是为了让程序设计者可以很快地熟悉 Java的语法格式,缩短学习Java的时间,毕竟C和C++仍旧是最多人会的一种程序语言。但是如果我们仔细检查Java程序语言的许多细节设计,我们可以发现Java去掉了不少C++的特点,并且加入一些新的特性。这些与C++的差异包括:

1.不再有#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的程序文件就够了。

2.不再有structure、union及typedef

事实上,早在C++中就可以去掉C语言中的structure和union等对复杂数据的自定结构类型,因为类(Class)的定义方式可以完全做到这项功能。而typedef也是不必要的,一切都用类就可以了。虽然C++这样的设计是为了和C语言兼容,但是使用多余的语言特点不但不必要,而且容易造成对程序认识的混淆。

3.不再有函数

在Java程序语言中,去掉了程序向导语言中最重要的单元--函数(Function)。如果我们以对象向导的观念来看待函数,就可以了解函数在对象向导的概念中,是不必要的。在对象向导的程序观念里,对象的数据才是真正的主体,而处理对象数据的方法则必须依附在对象内才有意义。因此,去掉函数并不表示不再有子程序等模组化程 序的概念,相反地,是利用对象中的方法来取代函数,再一次强化对向导的发展策略。

4.不再有多重继承(Multiplelnheritance)

在C++中,多重继承是一项很强的功能,但也是一般人难以掌控的部分。去掉多重继承虽然降低了Java语言的功能,但是也大幅简化撰写程序时的困难度。虽然移除了多重继承的功能,但是Java提供了interface的方式,可以达到部分多重继承的功用。所谓的interface基本上定义了一个类的对外沟通的方法原型,以及类内部的常 数,和多重继承不同之处在于interface并不会定义类方法的内容,以及类中的变量数据。

5.不再有Goto

在程序语言的发展史上,Goto一直是毁誉参半的一项功能。在很多时候使用Goto可以大幅减少不必要的程序代码,但是也由于Goto可以很自由地改变程序的流程,如果冒然地使用,更可能造成程序结构混乱的情况。一般来说,正确使用Goto的例子多出现在循环内部,想要提早结束某一层循环。在C语言中,我们可以使用break 或contine来改变某一层循环的流程, 但如果想要改变两层以上的环执行流程,不是使用Goto就是以多余的布尔(boolean)变量,配合上一串if-then-else的判断来达成。

Java一方面移除了Goto的功能, 而另一方面同时扩大了break和continue的功能,可以允许多层循环的break或continue。如此一来不但避免了滥用Goto的可能性,同时也保存下Goto的好处。

6.不再有OperatorOverloading

在C++中,Operator Overloading同样也是一项值得讨论的设计。几乎在所有C++的书中,都会引用一些例子,告诉你使用OperatorOverloading可以使你的程序看起来更为自然。如下面是一个程序设计师自定义的复数类:

//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的存在并不是必要的,我们一样可以定义类中的方法来达到同样的目的,至于Java去掉这项功能的利弊,恐怕就要读者自己去评断了。

7.取消自动类型转换

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;



8.不再有指针

取消指针(Pointer)这样数据类型,可能会让许多熟悉C++语言的程序设计师大吃一惊。在C++语言里,灵活地运用指针是许多程序设计师的得意之作,但是占整个除错时间最久的也是指针的问题。配合上C++对内存管理的态度,程序设计师必须要自己去追踪自己向系统要到的内存,最后确实地交还给系统,并且在使用指针时,要小心翼翼地注意不要跨过合法的记忆空间,造成Segmentation Fault或General Protection Fault之类的问题。

Java去掉了指针类型,并不表示程序设计师在开发高级数据结构,像堆栈(stack)、 队列(queue)、二元树(binarytree)时,都必须要像在传统Basic上,利用大范围的数组来自行模拟系统内存,自行建构类似指针的表示方式。

相反地,Java提供了和Lisp语言中相似的Reference类型,通过Reference去读取配置到的内存内容,可以确保不会去读取到不属于自己的内存空间,而另一方面,程序的执行系统也可以动态地去做内存垃圾回收的工作,将没有被reference参考到的内存空间回收给系统使用。

9.和C++连接

不管Java是多么强大,总是有人需要把它和C++连接起来。因为只要有一个新的程序语言或是软件开发工具一出现,大家就会问:"它是否具有和原有程序库连接的能力呢?"也因为C++语言在电脑界中占了很重要的地位。大家的问题其实就等于是直接问"它是否可以和C++连接?"。目前在Java中,的确提供了和C++语言连接的方法,它的做法基本上是先将C++语言所写的程序建构成动态链接函数库(DynamicLinking Library,DLL),再由Java程序去调用DLL里的函数。

这种连接的方式,使得DLL中的函数,从Java的眼光看就是一个"方法"。不过因为这种方法是直接由其他的程序语言所提供,而不是以Java语言所写的,所以它被称之为"原生方法"(NativeMethod)。

由于Java Applet一些安全上的限制,所以这种连接外部程序的方法只能用在Java Application内。

小结:

事实上,constant和typedef这两条语句包含了#define语句的作用。现在,结构和联合已经被Java的类所代替。删除这些特性的原因是:由于其希望维持与C语言的向后兼容性,C ++的语言规范包含了大量冗余。比如,类实际上就已经包括了结构和联合的作用,因此这两种数据结构完全可以取消。关于#define语句,Java语言规范的制订者认为:尽管该语句的出发点是为了增强程序的可读性,但实际效果却恰恰相反,它常常导致难读的代码,故应该予以取消。Java不再支持独立函数,因此任何函数都必须封装到某个类中。由于人们普遍认为, C++所用的超类是非常不稳定的,因此Java抛弃了C++中的多继承并代之以接口。Java的接口指的是,在别的类看来一个类所能实现的方法。它所显示的只是一个类的方法或常量和变量 ,而不是这个类的全部结构。

最后,Java还取消了C++中的GOTO语句、操作符重载、自动类型转换及指针数据类型。 GOTO语句引起的争议已经有很多年了,可一直阴魂不散,这跟某些程序员对该语句一直情有独钟有关。C++仍然支持数据类型的自动转换,但Java要求编程人员显式实现数据类型之间的转换。自动数据类型转换使得两个数据类型互不兼容的变量可以相互赋值,而不需要给出显式说明。这有时会导致一些问题,其中最常见的是精确度损失。比方说,如果把一个带符号的32位整数赋给一个无符号整数,则所有的结果均为正数。Java的设计者们认为这很容易引起程序错误,从而决定不支持这种转换方式。
Java Q&A

Vector or ArrayList -- which is better?
Find out the difference between Vector and ArrayList

By Tony Sintes

Printer-friendly version | Mail this to a friend


Vector or ArrayList -- which is better and why?

Sometimes Vector is better; sometimes ArrayList is better; sometimes you don't want to use either. I hope you weren't looking for an easy answer because the answer depends upon what you are doing. There are four factors to consider:


API
Synchronization
Data growth
Usage patterns
Let's explore each in turn.

API
In The Java Programming Language (Addison-Wesley, June 2000) Ken Arnold, James Gosling, and David Holmes describe the Vector as an analog to the ArrayList. So, from an API perspective, the two classes are very similar. However, there are still some major differences between the two classes.

Synchronization
Vectors are synchronized. Any method that touches the Vector's contents is thread safe. ArrayList, on the other hand, is unsynchronized, making them, therefore, not thread safe. With that difference in mind, using synchronization will incur a performance hit. So if you don't need a thread-safe collection, use the ArrayList. Why pay the price of synchronization unnecessarily?

Data growth
Internally, both the ArrayList and Vector hold onto their contents using an Array. You need to keep this fact in mind while using either in your programs. When you insert an element into an ArrayList or a Vector, the object will need to expand its internal array if it runs out of room. A Vector defaults to doubling the size of its array, while the ArrayList increases its array size by 50 percent. Depending on how you use these classes, you could end up taking a large performance hit while adding new elements. It's always best to set the object's initial capacity to the largest capacity that your program will need. By carefully setting the capacity, you can avoid paying the penalty needed to resize the internal array later. If you don't know how much data you'll have, but you do know the rate at which it grows, Vector does possess a slight advantage since you can set the increment value.

Usage patterns
Both the ArrayList and Vector are good for retrieving elements from a specific position in the container or for adding and removing elements from the end of the container. All of these operations can be performed in constant time -- O(1). However, adding and removing elements from any other position proves more expensive -- linear to be exact: O(n-i), where n is the number of elements and i is the index of the element added or removed. These operations are more expensive because you have to shift all elements at index i and higher over by one element. So what does this all mean?

It means that if you want to index elements or add and remove elements at the end of the array, use either a Vector or an ArrayList. If you want to do anything else to the contents, go find yourself another container class. For example, the LinkedList can add or remove an element at any position in constant time -- O(1). However, indexing an element is a bit slower -- O(i) where i is the index of the element. Traversing an ArrayList is also easier since you can simply use an index instead of having to create an iterator. The LinkedList also creates an internal object for each element inserted. So you have to be aware of the extra garbage being created.

Finally, in "PRAXIS 41" from Practical Java (Addison-Wesley, Feb. 2000) Peter Haggar suggests that you use a plain old array in place of either Vector or ArrayList -- especially for performance-critical code. By using an array you can avoid synchronization, extra method calls, and suboptimal resizing. You just pay the cost of extra development time.

re: 【Java面试题集锦系列一】 苹果 2005-06-23 20:52  
2.HashMap和Hashtable基本相同,只是HashMap是非同步的,并且允许空值。
ArrayList和Vector的区别也是ArrayList是非同步的(unsyncronized). Hashtable和HashMap的区别: 1.Hashtable是Dictionary的子类,HashMap是Map接口的一个实现类; 2.Hashtable中的方法是同步的,而HashMap中的方法在缺省情况下是非同步的。即是说,在多线程应用程序中,不用专门的操作就安全地可以使用Hashtable了;而对于HashMap,则需要额外的同步机制。但HashMap的同步问题可通过Collections的一个静态方法得到解决: Map Collections.synchronizedMap(Map m) 这个方法返回一个同步的Map,这个Map封装了底层的HashMap的所有方法,使得底层的HashMap即使是在多线程的环境中也是安全的。 3.在HashMap中,null可以作为键,这样的键只有一个;可以有一个或多个键所对应的值为null。当get()方法返回null值时,即可以表示HashMap中没有该键,也可以表示该键所对应的值为null。因此,在HashMap中不能由get()方法来判断HashMap中是否存在某个键,而应该用containsKey()方法来判断。 Hashtable和HashMap采用的hash/rehash算法都大概一样,所以性能不会有很大的差异。
re: 【Java面试题集锦系列一】 苹果 2005-06-16 13:34  
下面是我自己的一些注释:
1.private 只有本类内的方法才具有访问权。
protected 只有本类内的方法、子类以及同一包内的其他类才具有访问权。
public 公开访问
final 一个常量或者一个不能被重载的类或方法
finally 一个try块中总会被执行的部分
re: Jena推理功能的展示 苹果 2005-05-26 21:53  
yujian:
我按你上面说的运行了一遍,结果是
list properties of master:
hastuorof
没有错误,你可以再运行一遍试试,应该不会有错,如果还不行,我可以把程序发给你。
re: Jena推理功能的展示 苹果 2005-05-20 20:26  
这个推理程序我用的就是Jena doc中inference小节中的关于计算机的例子,你们没有吗?
我们小组的推理工作刚刚开始,所以自己的推理程序还没有完成。你们有什么问题,我们可以一起探讨一下。