免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1116 | 回复: 0
打印 上一主题 下一主题

JavaFAQ[zz] [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2005-09-08 17:23 |只看该作者 |倒序浏览
java编程中的一些常见错误,适合初学者!
一、准备篇
Q1.1 什么是Java、Java2、JDK?JDK后面的1.3、1.4版本号又是怎么回事?
答:Java是一种通用的,并发的,强类型的,面向对象的编程语言。
JDK是Sun公司分发的免费Java开发工具包,正式名称为J2SDK(Java2 Software Develop Kit)。包括基本的java工具包和标准类库。
到目前为止,Java有3个主要版本,即1.0,1.1,2.0;
JDK有1.0,1.1,1.2,1.3,1.4五个版本。
从JDK1.2起,Sun公司觉得Java改变足够大而将java语言版本号提升为2.0。
不同的JDK主要在于提供的类库不同。作为学习你可以下载最新的JDK1.4.2。
真正开发时则应考虑向前兼容,比如1.3。
Q1.2 什么是JRE/J2RE?
答:J2RE是Java2 Runtime Environment,即Java运行环境,有时简称JRE。
如果你只需要运行Java程序或Applet,下载并安装它即可。
如果你要自行开发Java软件,请下载JDK。在JDK中附带有JRE。
注意由于Microsoft对Java的支持不完全,请不要使用IE自带的虚拟机来运行Applet,务必安装一个JRE或JDK。
Q1.3 学习Java用什么工具比较好?
答:作者建议首先使用JDK+文本编辑器,这有助你理解下列几个基础概念:path,classpath,package 并熟悉基本命令:javac和java。并且下载和你的JDK版本一致的API帮助。如果你不确定类或函数的用法,请先查阅API而不是发贴求助。
当你熟悉Java之后,你可以考虑开始使用一个IDE。
eclispe的主要缺点是缺乏一个可视化的桌面程序开发工具,
幸运的是IBM在2003年11月已经将部分代码捐给eclipse组织,可以预计这个缺点很快就会得到弥补。
无论如何,请不要使用Microsoft的VJ++!众所周知Microsoft从来就没有认真支持过Java。
最后但并非最不重要,要有一本好的参考书,并且英文要过关。
Q1.4  学习Java有哪些好的参考书?
答:作者首先推荐Thinking in Java,中文名《Java编程思想》,有中文版。
目前的最新版本是第三版。
该书第一章介绍了很多面向对象的编程思想,作为新手应当认真阅读。除此以外,O'relly出版社和Wrox出版社的书也不错。作者本人不喜欢大陆作者的书。也许你觉得英文太难,但是网上大多数资料都是英文的。另外,你需要经常查阅API,而那也是英文的。
Q1.5  Java和C++哪个更好?
答:这个问题是一个很不恰当的问题。你应该问:Java和C++哪个更适用于我的项目?
Java的优点和缺点一样明显。
跨平台是Java的主要优点,但代价是运行速度的下降。
VC和Windows平台有良好的集成和足够快的速度,但是也只能局限在Windows平台上。
和C++相比,Java学起来更快,开发人员不会碰到很多容易出错的特性。
但是VB程序员甚至只需要拼装模块就可以了。
Q1.6  什么是J2SE/J2EE/J2ME?
答:J2SE就是一般的Java。
J2ME是针对嵌入式设备的,比如支持Java的手机,它有自己的JRE和SDK。
J2EE是一组用于企业级程序开发的规范和类库,它使用J2SE的JRE。
二、命令篇
Q2.1  我写了第一个Java程序,应该如何编译/运行?
答:首先请将程序保存为xxx.java文件,注意你可能需要修改文件后缀名。然后在dos窗口下使用javac xxx.java命令,你会发现该目录下多了一个xxx.class文件,再使用java xxx命令,你的java程序就开始运行了。
Q2.2  我照你说的做了,但是出现什么“'javac' 不是内部或外部命令,也不是可运行的程序或批处理文件。”。
答:你遇到了path问题。操作系统在一定的范围(path)内搜索javac.exe,但是没能找到。
请编辑你的操作系统环境变量,新增一个JAVA_HOME变量,设为你JDK的安装目录,再编辑Path变量,加上一项 %JAVA_HOME%in。然后保存并新开一个dos窗口,你就可以使用javac和java命令了。
Q2.3  环境变量怎么设置?
答:请向身边会设的人咨询。
Q2.4  我在javac xxx.java的时候显示什么“unreported exception java.io.IOException;”。
答:参见Q4.8以了解java中的异常机制。
Q2.5  javac xxx.java顺利通过了,但是java xxx的时候显示什么“NoClassDefFoundError”。
答:1. 你遇到了classpath问题。java命令在一定的范围(classpath)内搜索你直接或间接使用的class文件,但是未能找到。首先请确认你没有错敲成java xxx.class,其次,检查你的CLASSPATH环境变量,其实你并不需要设置该变量,但如果你设置了该变量又没有包含.(代表当前目录)的项,你就会遇到这个问题。请在你的CLASSPATH环境变量中加入一项. 或干脆删掉这个变量。
2. 如果你使用了并非JDK自带的标准包,比如javax.servlet.*包,也会遇到这个问题,请将相应的jar文件加入classpath。
3. 如果你在java源文件中定义了package,请参见Q2.11。
Q2.6  我在java xxx的时候显示“Exception in thread "main" java.lang.NoSuchMethodError: main”。
答:首先,在你的程序中每个java文件有且只能有一个public类,这个类的类名必须和文件名的大小写完全一样。其次,在你要运行的类中有且只能有一个public static void main(String[] args)方法,这个方法就是你的主程序。
Q2.7  在java xxx的时候显示“Exception in thread "main" java.lang.NullPointerException”。
答:在程序中你试图在值为null的对象变量上调用方法,请检查你的程序确保你的对象被恰当的初始化。
参见Q4.8以了解java中的异常机制。
Q2.8 package是什么意思?怎么用?
答:为了唯一标识每个类并分组,java使用了package的概念。每个类都有一个全名,例如String的全名是java.lang.String,其中java.lang是包名,String是短名。按照java命名惯例,包名是全部小写的,而类名的第一个字母是大写的。这样,如果你自行定义了同样名字的类String,你可以把它放在mypackage中,通过使用全名mypackage.String和java.lang.String来区分这两个类。同时,将逻辑上相关的类放在同一个包中,可以使程序结构更为清楚。为了定义包,你要做的就是在java文件开头加一行“package mypackage;”。注意包没有嵌套或包含关系,mypackage包和mypackage.mysubpackage包对JRE来说是并列的两个包(虽然开发者可能暗示包含关系)。
Q2.9 我没有声明任何package会怎么样?
答:你的类被认为放在默认包中。这时全名和短名是一致的。
Q2.10 在一个类中怎么使用其他类?
答:如果你使用java.lang包或者默认包中的类,不用做任何事。如果你的类位于mypackage包中,并且要调用同一包中的其他类,也不用做任何事。如果你使用其他包中的类,在package声明之后,类声明之前使用import otherpackage1.Class1; 或 import otherpackage2.*;  
这里.*表示引入这个包中的所有类。然后在程序中你可以使用其他类的短名。如果短名间有重名冲突,必须使用全名来区分。
注意在使用其他包中的类时,你只能使用public的类和接口,参见Q5.4。
Q2.11 我用了package的时候显示"NoClassDefFoundError",但是我把所有package去掉的时候能正常运行。
答:将你的java文件按包名组织存放。比如你的工作目录是/work,你的类是package1.Class1,那么将它存放为/work/package1
/Class1.java。如果没有声明包,那么直接放在/work下。在/work下执行javac package1/class1.java,再执行java package1.class1,你会发现
一切正常。另外,如果你的类的个数已经多到了你需要使用包来组织的话,你可以考虑开始使用IDE。
Q2.12 我想把java编译成exe文件,该怎么做?
答:JDK只能将java源文件编译为class文件。class文件是一种跨平台的字节码,必须依赖平台相关的JRE来运行。Java以此来实现跨
平台性。有些开发工具可以将java文件编译为exe文件。作者反对这种做法,因为这样就取消了跨平台性。
如果你确信你的软件只在Windows平台上运行,你可以考虑使用C++/C#来编程。
Q2.13 我在编译的时候遇到什么"deprecated API",是什么意思?
答:所谓deprecated是指已经过时,但是为了向前兼容起见仍然保留的方法。这些方法可能会在以后取消支持。你应当改用较新的方法。在API里面会说明你应当用什么方法来代替之。
Java FAQ (3) 文件与磁盘操作
四、 关键字篇
Q4.1  java里面怎么定义宏?
答:java不支持宏,因为宏代换不能保证类型安全。如果你需要定义常量,可以将它定义为某个类的static final成员。参见Q4.2和Q4.6。
Q4.2  java里面没法用const。
答:你可以用final关键字。例如 final int m = 9。被声明为final的变量不能被再次赋值。唯一的例外是所谓blank final,如下例所示:
public class MyClass1 {
  private final int a = 3;
    private final int b; // blank final
    public MyClass1() {
        a = 5; // 不合法,final变量不能被再次赋值。
        b = 4; // 合法,这是b第一次被赋值。
        b = 6; // 不合法,b不能被再次赋值。
    }
}
final也可以用于声明方法或类,被声明为final的方法或类不能被继承。
注意const是java的保留字以备扩充。
Q4.3  java里面也不能用goto。
答:甚至在面向过程的语言中你也可以完全不用goto。请检查你的程序流程是否合理。如果你需要从多层循环中迅速跳出,java增强了(和C++相比)break和continue的功能,支持label。
例如:
outer :
while( ... )
{
    inner :
    for( ... )
    {
           ...   break inner; ...
           ... continue outer; ...
    }
}
和const一样,goto也是java的保留字以备扩充。
Q4.4  java里面能不能重载操作符?
答:不能。String的+号是唯一一个内置的重载操作符。你可以通过定义接口和方法来实现类似功能。
Q4.5  我new了一个对象,但是没法delete掉它。
答:java有自动内存回收机制,即所谓Garbarge Collection。你不需要删除对象。你再也不用担心指针错误,内存溢出了。
Q4.6  我想知道为什么main方法必须被声明为public static?为什么在main方法中不能调用非static成员?
答:声明为public是为了这个方法可以被外部调用,详情见Q5.4。
static是为了将某个成员变量/方法关联到类(class)而非实例(instance)。你不需要创建一个对象就可以直接使用这个类的static成员,因而在static成员中不能调用非static成员,因为后者是关联到对象实例(instance)的。在A类中调用B类的static成员可以使用B.staticMember的写法。注意一个类的static成员变量是唯一的,被所有该类对象所共享的,在多线程程序设计
中尤其要谨慎小心。类的static成员是在类第一次被JRE装载的时候初始化的。你可以使用如下方法来使用非static成员:
public class A
{
    private void someMethod() //非static成员
    {}
    public static void main(String args)
    {
         A a = new A();  //创建一个对象实例
         a.someMethod();  //现在你可以使用非static方法了
    }
}
Q4.7  throw和throws有什么不同?
答:throws用于方法声明中,声明一个方法会抛出哪些异常。而throw是在方法体中实际执行抛出异常的动作。如果你在方法中throw一个异常,却没有在方法声明中声明之,编译器会报错。注意Error和RuntimeException的子类是例外,无需特别声明。
Q4.8  什么是异常?
答:异常最早在Ada语言中引入,用于在程序中动态处理错误并恢复。你可以在方法中拦截底层异常并处理之,也可以抛给更高层的模块去处理。你也可以抛出自己的异常指示发生了某些不正常情况。常见的拦截处理代码如下:
try
{
    ......//以下是可能发生异常的代码
        ...... //异常被你或低层API抛出,执行流程中断并转向拦截代码。
        ......
}
catch(Exception1 e) //如果Exception1是Exception2的子类并要做特别处理,应排在前面
{
  //发生Exception1时被该段拦截
}
catch(Exception2 e)
{
  //发生Exception2时被该段拦截
}
finally //这是可选的
{
   //无论异常是否发生,均执行此段代码
   //即使在catch段中又向外抛出了新的exception,finally段也会得到执行。
}
五、 面向对象篇
Q5.1  extends和implements有什么不同?
答:对于class而言,extends用于(单)继承一个类(class),而implements用于实现一个接口(interface)。interface的引入是为了部分地提供多继承的功能。在interface中只需声明方法头,而将方法体留给实现的class来做。这些实现的class的实例完全可以当作interface的实例来对待。在interface之间也可以声明为extends(多继承)的关系。注意一个interface可以extends多个其他interface。
Q5.2  java怎么实现多继承?
答:java不支持显式的多继承。因为在显式多继承的语言例如c++中,会出现子类被迫声明祖先虚基类构造函数的问题,而这是违反面向对象的封装性原则的。java提供了interface和implements关键字来部分地实现多继承。参见Q5.1。
Q5.3 abstract是什么?
答:被声明为abstract的方法无需给出方法体,留给子类来实现。而如果一个类中有abstract方法,那么这个类也必须声明为abstract。
被声明为abstract的类无法实例化,尽管它可以定义构造方法供子类使用。
Q5.4 public,protected,private有什么不同?
答:这些关键字用于声明类和成员的可见性。public成员可以被任何类访问,protected成员限于自己和子类访问,private成员限于自己访问。Java还提供了第四种的默认可见性,一般称为package private,当没有任何public,protected,private修饰符时,成员是同一包内可见。类可以用public或默认来修饰。
Q5.5 Override和Overload有什么不同?
答:Override是指父类和子类之间方法的继承关系,这些方法有着相同的名称和参数类型。Overload是指同一个类中不同方法(可以在子类也可以在父类中定义)间的关系,这些方法有着相同的名称和不同的参数类型。
Q5.6 我继承了一个方法,但现在我想调用在父类中定义的方法。
答:用super.xxx()可以在子类中调用父类方法。
Q5.7 我想在子类的构造方法中调用父类的构造方法,该怎么办?
答:在子类构造方法的第一行调用super(...)即可。
Q5.8 我在同一个类中定义了好几个构造方法并且想在一个构造方法中调用另一个。
答:在构造方法第一行调用this(...)。
Q5.9 我没有定义构造方法会怎么样?
答:自动获得一个无参数的构造方法。
Q5.10 我调用无参数的构造方法失败了。
答:如果你至少定义了一个构造方法,就不再有自动提供的无参数的构造方法了。你需要另外显式定义一个无参数的构造方法。另外一种可能是你的构造方法或者类不是public的,参见Q5.4了解java中的可见性。
Q5.11 我该怎么定义类似于C++中的析构方法(destructor)?
答:提供一个void finalize()方法。在Garbarge Collector回收该对象时会调用该方法。
注意实际上你很难判断一个对象会在什么时候被回收。作者从未感到需要用到该方法。
Q5.12 我想将一个父类对象转换成一个子类对象该怎么做?
答:强制类型转换。如
public void meth(A a)
{
    B b = (B)a;
}
如果a实际上并不是B的实例,会抛出ClassCastException。所以请确保a确实是B的实例。
Q5.13 其实我不确定a是不是B的实例,能不能分情况处理?
答:可以使用instanceof操作符。例如
if( a instanceof B )
{
    B b = (B)a;
}
else
{
    ...
}
Q5.14 我在方法里修改了一个对象的值,但是退出方法后我发现这个对象的值没变!
答:很可能你把传入参数重赋了一个新对象,例如下列代码就会造成这种错误:public void fun1(A a) //a是局部参数,指向了一个外在对象。
{
    a = new A(); //a指向了一个新对象,和外在对象脱钩了。如果你要让a作为
传出变量,
不要写这一句。
        a.setAttr(attr);//修改了新对象的值,外在对象没有被修改。
}
基本类型也会出现这种情况。例如:
public void fun2(int a)
{
    a = 10;//只作用于本方法,外面的变量不会变化。
}
1 如何获得某一个目录下的文件列表?
  File MyDir = new File("C:/Windows/.");
  String[] FileNames = MyDir.list();
2 如何实现一个打开文件或者是存储文件对话框?
  AWT:    FileDialog类 + FilenameFilter类
  Swing:  JFileChooser类 + FileFilter类
  其中,基于Swing的解决方案功能更加强大,界面也更加美观。
3 利用FileReader/FileOutputStream拷贝中文文件出错?
  利用如下代码片断拷贝中文文件不会出错:
  int c;
  while ((c = MyFileReader.read()) != -1)
      MyFileWriter.write(c);
  利用如下代码片断拷贝中文文件会导致文件内容错误:
  int c;
  while ((c = MyFileReader.read()) != -1)
    MyFileOutputStream.write(c);
  造成这个问题的原因是:FileReader.read()返回一个int,其取值范围是
  0 到65535,通常来说是两个字节的;FileWriter.write(int c)向文件写
  入一个int,通常来说也是两个字节的,如果某个字符的高位字节为空,那
  么其高位字节将被舍弃;FileOutputStream.write(int b)虽然接受一个
  int作为参数,实际上只向文件写入一个字节,如果传递过来的参数是一个
  双字节的汉字,其高位字节将被舍弃,造成文件内容错误。
  建议:永远只使用InputStream/OutputStream进行IO操作。
  利用如下代码片断拷贝中文文件不会出错:
  int c;
  while ((c = MyFileInputStream.read()) != -1)
      MyFileOutputStream.write(c);
4 如何显示和存储拉丁语言中的特殊字符
  使用统一码Unicode可以显示和存储拉丁语言中的特殊字符。具体应用范例
  如下:
  MyJTextArea.append("u00E1");
  MyJTextArea.append("u00E2");
  MyJTextArea.append("u00E3");
  MyJTextArea.append("u00E4");
  MyJTextArea.append("u00E5");
  MyFileOutputStream.write(MyJTextArea.getText().getBytes("UTF-8"));
  MyFileOutputStream.close();
  同样,在读取文件的时候也需要将读到的内容转换成统一码。
  byte[] b = new byte[MyFile.length()];
  FileInputStream in = new FileInputStream(MyFile);
  in.read(b);
  MyJTextArea.append(new String(b, "UTF-8"));
5 如何利用文件进行数据存取
  对于一般的科学计算应用程序,DataInputStream和DataOutputStream类通
  常是最好的选择。这两个类提供了存取各种数据的方法。下面的范例演示了
  构造DataInputStream和DataOutputStream的方法:
  MyDataInputStream  = new DataInputStream(new FileInputStream(MyInputFile));
  MyDataOutputStream = new DataOutputStream(new FileOutputStream(MyOutputFile));
  利用ObjectInputStream和ObjectOutputStream同样可以进行数据存取,需
  要注意的是这样做增加了硬盘的开销,因为进行对象序列化过程添加了一
  些额外的信息。在利用ObjectInputStream和ObjectOutputStream进行通讯
  的时候,虽然数据发收过程得到了大大简化,但是对带宽的要求也大大的
  提高了。
6 文件操作的基本原则是什么?
  a. 避免多次访问磁盘,例如一次读出n个字节就比每次读出1个字节的访问
     效率要高很多。
  b. 避免多次访问操作系统。
  c. 避免多次调用文件存取方法。
  d. 避免将字节和字符混淆处理,在Java语言中字节与字符的概念是不一样
     的,在涉及到双字节字符的问题上更是容易出错。
7 如何获得可用的硬盘空间?
  目前尚未发现有任何干净利落的纯Java方法能够解决这个问题。通常的解
  决方案是直接访问操作系统获得这些信息。有一个被称为JConfig的类库提
  供了一些方法可以获得磁盘和文件信息,但是可以肯定这个类库使用了JNI
  方法。
  下载地址:http://www.tolstoy.com/samizdat/jconfig.html
  如果你使用的是晕倒死系列操作系统,那么下面的方法也许能够获得正确
  的结果。我之所以说也许,是因为我在多个晕倒死平台上作过实际测试,
  在英文版的晕倒死上基本上都能够得到正确的结果,在中文版的晕倒死上
  基本上都不能够获得正确的结果。
  String osname = System.getProperty("os.name");
  String command = "";
  if (osname.indexOf("NT") > -1)
  command = "c:\winnt\System32\cmd.exe";
  else if (osname.indexOf("Windows") > -1)
  command = "c:\windows\command.com";
  Process p = Runtime.getRuntime().exec(command + " /c dir > c:\dir.txt");
  p.waitFor();
  然后你需要做的是对得到的dir.txt文件进行分析。
  如果你使用的是UNIX/Linux操作系统,你可以使用类似的方法来获得相关
  信息。建议使用的命令是df -k > dir.txt。
8 我能够用Java来格式化我的硬盘或者是软盘么?
  关于这个问题,想来在不久的将来仍然是不会有纯Java的解决方案了。如
  果你一定要在你的Java应用程序里面格式化你的C盘的话,下面的这个方法
  也许会有所帮助。当然,在你使用这个方法之前,请仔细备份好女朋友给你
  的情书或者是记下和下一个网友约会的日期。
  建立一个称为FormatDrive.bat的文件,该文件必须放在当前目录或者是系
  统路径下,文件的内容如下:
  rundll32.exe shell32.dll, SHFormatDrive
  格式化硬盘的方法可以这样写:
  public void FormatDrive()
  {
      try
      {
          Process p = Runtime.getRuntime().exec("FormatDrive.bat");
          p.waitfor();
      } catch (Exception e)
      {
          System.out.println(e);
      }
  }
9 怎么知道我究竟有几个可用的存储设备?
  在UNIX/Linux下你通常没有必要关心这个问题,只要记住那个斜杠就可以了。
  在晕倒死下硬盘可以有多个逻辑分区,可应用下面的方法找出来:
  public void ListDisks()
  {
      File[] roots = File.listRoots();
      for (int i=0; i
      {
            System.out.println(roots);
      }
  }


本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u/2016/showart_46719.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP