Mar 14
  1. 可以将构造器的访问权限设置为private。
  2. 在构造器中调用构造器只能调用一次,且只能放在调用的起始处。
  3. 初始化的顺序是先静态对象后非静态。
  4. static的含义:
    • 表示该域或方法与任何包含该域或方法的任何对象没有关联。
    • 作为方法,不能使用this(意味着不能调用非static方法)。
  5. 垃圾回收只与内存有关,并不等于析构(finalize()不同于析构函数)。
  6. Java中没有C/C++的条件编译语句,可以使用import导入不同的包来代替这个功能。
  7. 在同一个目录中且没有设定所属包的编译单元(文件)被看成属于这个包的“默认包”(Netbeans中叫做“缺省包”)。
  8. 所有的类都继承自Object这个原始类。
  9. 与this类似,我们可以使用super来表示一个类的基类,与this具有相同的使用方法。
  10. 不要滥用继承,组合和代理也是不错的选择,特别是在不需要向上转型时。
  11. 可以使用@Override注解来防止自己犯没有覆写的错误。
  12. 向上转型并没有改变一个类本身,比如Base b = new Derived(),b指向的仍然是一个Derived类。这是因为动态的类型本身仅仅由其存储空间决定,所以引用作为一个地址并不影响类型本身。
  13. 空白final变量必须要使用前被初始化。
  14. 使用final的原因:
    • 锁定方法,防止被继承类修改。
    • 写出可以在运行时被确定的代码,从而可以内嵌调用。
  15. 所有private方法都是隐式final的。
  16. final类不可以被继承。
Mar 11

Java的输入输出也是基于“流”的概念,和C++采用的概念很相似。流分为输入流(Input Stream)和输出流(Output Stream)两种。

java.io包为我们提供了多种数据流,大致分为字节流和字符流两种。它们的区别在于字节流是以8字节为单位处理文件,而字符流是以16字节为单位。这区别其实就是以byte为单位还是以Unicode码字符为单位,又由于Java本身更倾向于Unicode,所以字符流兼容性会好一点。

下文中的所有类、方法和接口都可以在java.sun.com上找到相关的文档。

字节流主要是从InputStream和OutputStream中派生出的,大致有:

  • FileInputStream、FileOutputStream
  • PipedInputStream、PipedOutputStream
  • ByteArrayInputStream、ByteArrayOutputStream
  • FilterInputStream、FilterOutputStream
  • DataInputStream、DataOutputStream
  • BufferedInputStream、BufferedOutputStream

字节流提供了DataInputStream和DataOutputStream作为数据流的类,可以较方便地读取数据。

而字符流是从Reader和Writer中派生出的,有:

  • InputStreamReader、OutputStreamWriter
  • FileReader、FileWriter
  • CharArrayReader、CharArrayWriter
  • PipedReader、PipedWriter
  • FilterReader、FilterWriter
  • BufferedReader、BufferedWriter
  • StringReader、StringWriter

字符流提供的接口和字节流类似,但是把其中的参数换成了字符或者字符数组。

我们可以使用上面的类来建立比较方便的输入输出过程,比如:

BufferedReader buffReader = new BufferedReader(new FileReader(“XXX.xxx”));
BufferedWriter buffWriter = new BufferedWriter(new FileWriter(“XXX.xxx”));

另外Java还提供了Scanner这个封装得很好的类进行读入。经过我的测试BufferedReader、BufferedWriter类的速度并不比C++的速度慢很多,而Scanner相对很慢,但是比较方便。另外,BufferedWriter还可以再放入PrintWriter中(这也是一个字符流的类,对应的字节流类是PrintStream):

PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter("XXX.xxx")));

而PrintWriter封装得也很好,和System.out的使用差不多。

Mar 9

Java是相当典型的OOP语言,其本身的实现方式就是抽象的类。相比于C所具有的过程性,Java在思考难度上要降低了不少。但是要实现一个好的Java代码还是很困难的。

Java中一切都是对象。除了一些特殊的基本类型,基本类型一共有boolean, char, byte, short, int, long, float, double, void几种。这些基本类型在操作上与一般的“类”有一些不同。这些基本类型在赋值的时候,执行的是内容的复制。虽然这些基本类型也有相应的包装器类型,但是基本类型的存在时必要的。基本类型和包装器类型之间可以相互直接转化。Java中还内置了BigInteger和BigDecimal类,这些都是很方便的高精度数字类。其中,BigInteger中的乘法采用了FFT乘法。

Java中有关于对象的变量我们都认为是“引用”。也就是说

String s = new String(“Hello World!”),t = new String(“Bad!”);

这里的s, t仅仅是一个引用,如果有

s = t;

那么仅仅是将s指向t。Java中的数组也是“引用”数组。要注意函数的参数传递中参数也是以引用的形式传递的。

Java的作用域和C/C++稍有不同,不允许以下的情况:

int x = 0;
for (int i = 0; i<n; i++) {
  int x = i;
}

也就是说,Java中不存在将变量作用域隐藏的做法,这里后一个x的定义是非法的。

Java会给基本类型赋初值,初值默认为0(这里是二进制意义上的0)。

Mar 1

系统为WinXP SP3,使用jdk-6u18-windows-i586.exe安装。

在使用含有外部URL的jnlp 文件时,会产生如下的错误信息:

java.net.MalformedURLException: unknown protocol: socket

解决方案是在Java的控制面板中把代理的设置更改为“直接连接(Direct Connection)”。

Jan 15

C++果然是非常微妙的语言,%f和%lf对于printf()和scanf()的效果是不同的。

事实上,对于printf(),无论是%f还是%lf,效果都是一样的。因为,遇到float,printf()会将float类型自动提升到double,所以不会有什么问题。而且严格地讲,printf()并没有对于%lf的定义,虽然很多编译器会接受,所以最好使用%f。

而对于scanf(),由于接受的是指针,并没有类型提升的说法,所以对于double就应该用%lf,float就是%f。