请教各位一个问题,
//这是一个得到当前目录下的所有文件的列表的方法
//其中fullPath是表示当前路径的变量
  public File[] listFiles() {
    File dir=new File(fullPath);
   String[] ss = dir.list();
   if (ss == null)
    return null;
    int n = ss.length;
   File[] fs = new File[n];
  for(int i = 0; i < n; i++) {
    fs[i] = new File(dir.getPath(), ss[i]);
   }
  return fs;
  }
关于这个方法,使用是完全正确的,但是我有点语法上的疑问。
在File[] fs = new File[n]一句中,应该生成了包含n个file实例的file数组fs,其生成时应该是调用了File的默认构造函数吧。
既然fs已经构造了n个File出来,为什么在fs[i] = new File(dir.getPath(), ss[i])中又调用构造函数重新构造一次,这样的语法正确吗?
不好意思,我初用java,很多思路还是用C++的来考虑,在C++中语法这样用是错误的。请大家帮我解释一下,谢谢。

解决方案 »

  1.   

    个人理解
    File[]   fs   =   new   File[n];  这时建立了一个file数组,里面每个元素为null
    fs[i]   =   new   File(dir.getPath(),   ss[i]);  为每个元素赋值 
      

  2.   

    楼上的为正解,
    如果没有fs[i]   =   new   File(dir.getPath(),   ss[i]); 
    而使用了fs[n]那麽应该是出现类似NullPointerException的异常
      

  3.   

    声明一个数组,并不表示声明了数组内所有的元素
    File[] fs = new File[] 
    只是声明了这个"数组",但是里面所有的元素都是空的
    fs[0] = null
    fs[1] = null
    fs[n] = null必须为每个元素声明实际类型
    for(int i = 0; i < n; i ++)
     fs[i] = new File();
      

  4.   

    “在File[]   fs   =   new   File[n]一句中,应该生成了包含n个file实例的file数组fs,其生成时应该是调用了File的默认构造函数吧。
    既然fs已经构造了n个File出来,为什么在fs[i]   =   new   File(dir.getPath(),   ss[i])中又调用构造函数重新构造一次,这样的语法正确吗? ”其实,这样做没有什么问题的,关键是你要理解赋值号的作用:在Java中,使用new+构造函数是创建了数组(本质上是一个对象)的实体,而赋值号左边的
    File[]   fs 是声名了一个数组的名字,或者说引用。赋值号的作用就是将该引用指向该实体。显然,你最初令一个引用指向一个实体,后来,你又转而让这个引用指向另一个实体(即第二个语句),这没有什么不可以的,完全是符合语法的。本质上恰如你下面的定义了一个对象,接着把另一个对象赋给它
    A a=new A();
    A b=new A();
    a=b;
      

  5.   

    以上各位的回答我都认为都有可能,但是希望java不是按照lixkyx兄弟所说的来处理,这样就有点浪费内存了。有没有更好的办法实现哪个方法呢? 
      

  6.   

    对象类型初始化的时候为null
    File[] fs=new File[n]的时候,n个File对象fs[0]~fs[n-1]都为null,没有调用File的构造方法
      

  7.   

    在File[]   fs   =   new   File[n]一句中,应该生成了包含n个file实例的file数组fs,其生成时应该是调用了File的默认构造函数吧只声明了一个数组,数组内不包含任何东西
      

  8.   

    “以上各位的回答我都认为都有可能,但是希望java不是按照lixkyx兄弟所说的来处理,这样就有点浪费内存了。有没有更好的办法实现哪个方法呢?  ”呵呵!那你就要失望了。你随便找一本讲Java虚拟机的教材看看就知道了,这就是的内存空间管理的模式。
    在JVM中,对象(包括数组)的引用空间和实体空间是分开的。前者实际上存储了实体空间的首地址(在JVM上,而非C++那样的物理内存中),后者是存储了对象各个成员变量的值。
    引用空间和实体空间的位置也不同的,前者在程序的栈区,而后者在程序的堆区。
      

  9.   

    实际上,这个做法并不是Java首创的,在C++中,严格地说也是这样的。C++的对象的实体空间是内存中的某一块,它存储了各个成员变量的值。而对象的名字是一个标识符,当程序编译的时候,编译器把它绑定在一个地址型数据上——即对象的实体空间在内存中的首地址,这个绑定工作完成之后,描述“标示符——首地址”的映射关系的代码存放在程序所占据的内存空间的代码区中。C++与Java的区别在于,C++中的对象的声明与对象的创建(分配实体空间)是联系在一起的,不能互相独立存在。当你声明了一个对象的时候,必须为它分配实体空间。即:
    在C++中:
    语句 A a1;意味着声明了一个标识符a1,同时调用了A的无参数构造函数创建了对象(即在内存中分配一个实体空间间),并且把标识符a1与实体空间的首地址关联起来。在Java中:
    语句 A a1;意味着你声明了一个标识符a1,它将要代表一个实体对象,但是,此时,还没有实体空间被分配给它,所以它只是一个“空对象”,或者说,只是一个名字而已,并没有真正创建对象。只有当你再使用new算法+构造方法时,才算是真正创建了这个个对象!
    a1=new A();
    在上式中,new A() 代表在内存中分配一块空间(或者说,创建了一个无名对象),然后,把它赋值a1,即把无名对象的首地址赋给a1。此时,a1这个标识符才与对象的实体空间联系起来。或者说,到了这一步,你才能够说:创建了一个名字叫做a1的对象。
      

  10.   

    看来我得静下心来仔细看看java的设计思想。谢谢各位,特别是lixkyx,我学到了不少知识。
      

  11.   

    另一方面,Java和C++还有一个明显不同的地方,就是同种类型的对象互相赋值的时候。C++:
    A a1,a2;  语句 a1=a2;
    上述语句实际上是拷贝构造函数的调用,即以a2为原本对象创建一个副本对象,然后赋给a1,实际上,a1这个标识符现在指向这个副本对象,也就是说,标识符a1与副本对象的内存首地址关联起来,所以,最终我们得到了两个对象,一个a1,一个a2,它们彼此互不相干,只是对应成员变量的值相等。至于,a1对象原来所占据的内存空间则失去了名字,变成一个无法访问的区域,但是它仍然存在。因此,这种做法会浪费内存的。Java:
    A a1=new A();A a2=new A();  语句 a1=a2;
    这里实际上是把a2的值(引用)复制到a1,对象的值就是它所指向的实体空间的首地址,所以,a1和a2变成了值相同的两个标识符,它们都指向同一个对象实体空间,即原来a2的实体空间,实际上,此时a1和a2实际上变成了同一个对象的两个别名,它们根本就是一回事!而a2对象原来指向的实体空间失去了名字,变成一个无法访问的区域,但是,Java的垃圾收集机制会定期工作,清除掉它。因此,上述做法在Java里面是常规的,没有任何问题。
      

  12.   

    纠正!“C++:
    A   a1,a2;     语句   a1=a2;
    上述语句实际上是拷贝构造函数的调用,即以a2为原本对象创建一个副本对象,然后赋给a1,实际上,a1这个标识符现在指向这个副本对象,也就是说,标识符a1与副本对象的内存首地址关联起来,所以,最终我们得到了两个对象,一个a1,一个a2,它们彼此互不相干,只是对应成员变量的值相等。至于,a1对象原来所占据的内存空间则失去了名字,变成一个无法访问的区域,但是它仍然存在。因此,这种做法会浪费内存的。”上述说法是错误的!拷贝构造函数只是将原本对象的成员变量值的复制到副本对象的对应成员变量,假如副本对象原来已经存在,则不会重新构造。
    A   a1,a2; a1=a2;
    在上述语句中,a2本来已经存在,则语句 a1=a2; 只是相当于调用拷贝构造函数,将a2的成员变量的值交给a1对应的成员变量,并没有重新创建一个对象。 
      

  13.   

    只有当副本对象原来还不存在的情况下,才会出现重新构造,例如A a1; A a2(a1);这里会首先创建一个新对象a2,然后把a1的成员变量的值赋给它对应的成员变量。