- 可以将构造器的访问权限设置为private。
- 在构造器中调用构造器只能调用一次,且只能放在调用的起始处。
- 初始化的顺序是先静态对象后非静态。
- static的含义:
- 表示该域或方法与任何包含该域或方法的任何对象没有关联。
- 作为方法,不能使用this(意味着不能调用非static方法)。
- 垃圾回收只与内存有关,并不等于析构(finalize()不同于析构函数)。
- Java中没有C/C++的条件编译语句,可以使用import导入不同的包来代替这个功能。
- 在同一个目录中且没有设定所属包的编译单元(文件)被看成属于这个包的“默认包”(Netbeans中叫做“缺省包”)。
- 所有的类都继承自Object这个原始类。
- 与this类似,我们可以使用super来表示一个类的基类,与this具有相同的使用方法。
- 不要滥用继承,组合和代理也是不错的选择,特别是在不需要向上转型时。
- 可以使用@Override注解来防止自己犯没有覆写的错误。
- 向上转型并没有改变一个类本身,比如Base b = new Derived(),b指向的仍然是一个Derived类。这是因为动态的类型本身仅仅由其存储空间决定,所以引用作为一个地址并不影响类型本身。
- 空白final变量必须要使用前被初始化。
- 使用final的原因:
- 锁定方法,防止被继承类修改。
- 写出可以在运行时被确定的代码,从而可以内嵌调用。
- 所有private方法都是隐式final的。
- final类不可以被继承。
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的使用差不多。
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)。
系统为WinXP SP3,使用jdk-6u18-windows-i586.exe安装。
在使用含有外部URL的jnlp 文件时,会产生如下的错误信息:
java.net.MalformedURLException: unknown protocol: socket
解决方案是在Java的控制面板中把代理的设置更改为“直接连接(Direct Connection)”。
C++果然是非常微妙的语言,%f和%lf对于printf()和scanf()的效果是不同的。
事实上,对于printf(),无论是%f还是%lf,效果都是一样的。因为,遇到float,printf()会将float类型自动提升到double,所以不会有什么问题。而且严格地讲,printf()并没有对于%lf的定义,虽然很多编译器会接受,所以最好使用%f。
而对于scanf(),由于接受的是指针,并没有类型提升的说法,所以对于double就应该用%lf,float就是%f。