java 学习笔记《1》
2011-04-04 23:28 Rollen Holt 阅读(505) 评论(0) 编辑 收藏 举报1.除了标准输出串流out之外,Java程式在执行之后,还会开启标准输入串流in与标准错误输出串流err。对于in来说,它对应至键盘或其它的输入来源,准备接受使用者或其它来源的输入。而对于err,它会将指定的字串输出至显示装置或其它指定的装置,与标准输出串流out不同的是,它会立即显示指定的(错误)讯息给使用者知道,例如即使您指定程式将结果重新导向至档案,err输出串流的讯息并不会被重新导向,而仍会显示在指定的显示装置上,下面这个例子给您一个简单的测试方式: HelloWorld.java文件
1: public class HelloWorld {
2: public static void main(String[] args) {
3: System.out.println("Hello! World!");
4: System.err.println("Error Message Test");
5: }
6: }
但是在编译执行程序之后你会发现输出结果如下:
1: java HelloWorld >> output.txt
2: Error Message Test
当我们开启output.txt之后,您会发现当中只有"Hello! World!"讯息,而Error Message Test讯息并没有被导向至档案中,而是直接显示在Console(或终端机)中。
要重新导向标准输出是用 '>' ,标准输入则是 '<' ,而'>>'除了重导标准输出之外,还有附加的功能,也就是会把输出附加到被导向的目标档案后头,如果目标档案本来不存在,那么效果就和'>'一样。
2.关于自动装箱和自动拆箱的一点问题。
自动装箱与拆箱是编译器在编译时期为您作好一切的事情,是 编译蜜糖(Compiler sugar) ,这很方便,但在运行阶段您还是了解Java的语义,例如下面的程式是可以通过编译的:
1: Integer i = null;
2: int j = i;
通过测试我们可以知道,这段代码在编译期间完全是可以通过的。但是在运行时期会有错误,因为null表示i 没有参考至任何的物件实体,它可以合法的指定给物件参考名称,但null值对于基本型态j 的指定是不合法的,上面的写法在运行时会出现NullPointerException的错误。再来看一个,先看看程式,您以为结果是如何?
1: Integer i1 = 100;
2: Integer i2 = 100;
3: if (i1 == i2)
4: System.out.println("i1 == i2");
5: else
6: System.out.println("i1 != i2");
先不说结果,我们在看看下面的这段代码:
1: Integer i1 = 200;
2: Integer i2 = 200;
3: if (i1 == i2)
4: System.out.println("i1 == i2");
5: else
6: System.out.println("i1 != i2");
你认为这个结果是什么呢?也许第一个正如你所猜想的。结果是i1==i2,但是我想第二个应该是出乎你的意料吧。因为这两段代码区别仅仅在于我改变了一个数值。经过运行我们可以知道,第二断代码的结果是:“i1!=i2”。为什么呢?
其实这与 '=='运算子 的比较有关,'=='可用来比较两个基本型态的变数值是否相等,事实上'=='也用于判断两个物件变数名称是否参考至同一个物件。
所以'=='可以比较两个基本型态的变数值是否相等,也可以判断两个物件变数的参考物件是否相同。 预设对于值从 -128到127 之间的值,它们被装箱为Integer物件后,会存在记忆体之中被重用,所以当值在100,使用'=='进行比较时,i1与i2实际上参考至同一个物件。预设 如果超过了从-128到127之间的值,被装箱后的Integer物件并不会被重用,即相当于每次都新建一个Integer物件,所以当值在200,使用'=='进行比较时,i1与i2参考的是不同的物件。
所以不要过份依赖自动装箱与拆箱,您还是必须知道基本型态与物件的差异,上面的程式最好还是依正规的方式来写,而不是依赖编译蜜糖(Compiler sugar),例如当值为200时,必须改写为以下才是正确的。
1: Integer i1 = 200;
2: Integer i2 = 200;
3: if (i1.equals(i2))
4: System.out.println("i1 == i2");
5: else
6: System.out.println("i1 != i2");
事实上在我们编写Integer i=100;的时候,编译器其实将我们的代码转化为 Integer i = Integer.valueOf(100); valueOf()方法会将-128到127的值放到快取之中,以重复使用,这可以查看Integer.java的原始码得知,如果是JDK5:
1: public static Integer valueOf(int i) {
2: final int offset = 128;
3: if (i >= -128 && i <= 127) { // must cache
4: return IntegerCache.cache[i + offset];
5: }
6: return new Integer(i);
7: }
也就是在-128到127之间所产生的包裹物件,将会放到快取中重复使用 ,而在JDK6之后,则是这么写的:
1: public static Integer valueOf(int i) {
2: if(i >= -128 && i <= IntegerCache.high)
3: return IntegerCache.cache[i + 128];
4: else
5: return new Integer(i);
6: }
7:
IntegerCache.high预设是127,所以预设是 在-128到127之间所产生的包裹物件,将会放到快取中重复使用(可以透过设置属性
java.lang.Integer.IntegerCache.high来设定IntegerCache.high的值) 。
3.对于数组。和C/C++一样,java中不存在多维数组,只有一维数组,而我们平时所说的“多维数组”其实就是数组的数组。在java里面,我们可以有如下的代码:
1: import java.util.Scanner;
2:
3: public class CustomArrayLength {
4: public static void main(String[] args) {
5: Scanner scanner = new Scanner(System.in);
6:
7: System.out.print("请输入Array大小: ");
8:
9: int length = scanner.nextInt();
10: int[] arr = new int[length]; // 动态配置长度
11:
12: System.out.println("Array长度: " + arr.length);
13: System.out.print("内容: ");
14: for(int i = 0; i < arr.length; i++)
15: System.out.print(arr[i] + "");
16: System.out.println();
17: }
18: }
请注意第9和第10行。在C++中我们不能写如下的代码片段:
1: #include<iostream>
2: using namespace std;
3: int main(){
4: int i;
5: cin>>i;
6: int a[]=new int[i];
7: return 0;
8: }
然而我们在java中确实可以的.这一点希望对于C++程序员有一点点提醒.
另外提醒一下,在java中,数组是一个对象。当我们使用"="将对象指定给数组名的时候,并不是对于数组进行复制,而是将对象名指定给数组名进行引用。
对于对维数组我们在输出的时候可以采用加强的for 循环:
1: int [][] arr={ {1,2,3},
2: {1,2,3},
3: {1,2,3}
4:
5: };
6: for(int [] elment1 : arr)
7: for(int elment2 : elment1 )
8: System.out.println(elment2);
其次我们来谈谈对象数组吧.先来看下面的代码:
1: int[] arr=new int[3];
你认为它产生了几个对象呢?答案是一个一维数组对象.
下面的呢?
1: int[][]arr=new int [2][3];
产生了几个对象呢? 答案是3个对象.在进一步的说,
1: Integer[] arr= new Integer[3];
产生了几个对象呢?答案还是一个对象数组.同理.对于 Integer[][] arr =new Integer[2][3];也是产生3个对象。
4.对于String.
一个字串物件一旦被配置,它的内容就是固定 不可变的(immutable) ,例如下面这个宣告:
String str = "caterpillar";
这个宣告会配置一个长度为11的字串物件,您无法改变它的内容;别以为下面这个宣告就是改变一个字串物件的内容:
String str = "just";
str = "justin";
串物件,您无法改变它的内容;别以为下面这个宣告就是改变一个字串物件的内容:
String str = "just";
str = "justin";
事实上在这个程序片段中,会有两个字串物件,一个是"just",长度为4,一个是"justin",长度为6,它们两个是不同的字串物件,您并不是
在"just"字串后加上"in"字串,而是让str名称参考至新的字串物件。
在Java中,使用=将一个字串物件指定给一个名称,其意义为改变名称的参考物件,原来的字串物件若没有其它名称来参考它,就会在适当的时机
被Java的 「垃圾回收」(Garbage collection) 机制回收,在Java中,程式设计人员通常不用关心无用物件的资源释放问题,Java会检查物件
是否不再被参考,如果没有任何名称参考的物件将会被回收。
所以如果您在程式中使用下面的方式来宣告,则实际上是指向同一个字串物件:
1: String str1 = "flyweight"; 2: String str2 = "flyweight";
3: System.out.println(str1 == str2);
程式的执行结果会显示true,在Java中,会维护一个 String Pool ,对于一些可以共享的字串物件,会先在String Pool中查找是否存在相同的String
内容(字元相同),如果有就直接传回,而不是直接创造一个新的String物件,以减少记忆体的耗用。
谈到String pool,那就不能不提String的 intern() 方法,来看看它的API说明的节录:
Returns a canonical representation for the string object.
A pool of strings, initially empty, is maintained privately by the class String.
When the intern method is invoked, if the pool already contains a string equal to this String object as determined by the
equals(Object) method, then the string from the pool is returned. Otherwise, this String object is added to the pool and a
reference to this String object is returned.
如果大家看过《设计模式》的话,应该可以想起Flyweight模式。看个例子再说吧:
1: public class StringIntern { 2: public static void main(String[] args) { 3: String str1 = "fly"; 4: String str2 = "weight"; 5: String str3 = "flyweight"; 6: String str4; 7: 8: str4 = str1 + str2; 9: System.out.println(str3 == str4); 10: 11: str4 = (str1 + str2).intern(); 12: System.out.println(str3 == str4); 13: } 14: } 在
在程式中第一次比较str3与str4物件是否为同一物件时,您知道结果会是false,而intern()方法会先检查String Pool中是否存在字元部份相同的字串
物件,如果有的话就传回,由于程式中之前已经有"flyweight"字串物件,intern()在String Pool中发现了它,所以直接传回,这时再进行比较,str3
与str4所指向的其实是同一物件,所以结果会是true。
注意到了吗? ==运算在Java中被用来比较两个名称是否参考至同一物件,所以 不可以用==来比较两个字串的内容是否相同 ,例如:
1: String str1 = new String("caterpillar"); 2: String str2 = new String("caterpillar"); 3: System.out.println(str1 == str2); 4: System.out.println(str1.equals(str2));
或许结果在你的意料之中。前者为false,后者为true、所以我们不能用“==”来比较两个字符串是否相等。另外说一句闲话,上面代码段的前3行产生了几个String的对象呢?很多人也许会认为是2个吧,我之前也是这样,但是答案却是3个,别忘记“caterpillar”就是一个。它存在于String Pool里面(⊙o⊙)哦,小盆友。
==============================================================================
本博客已经废弃,不在维护。新博客地址:http://wenchao.ren
我喜欢程序员,他们单纯、固执、容易体会到成就感;面对压力,能够挑灯夜战不眠不休;面对困难,能够迎难而上挑战自我。他
们也会感到困惑与傍徨,但每个程序员的心中都有一个比尔盖茨或是乔布斯的梦想“用智慧开创属于自己的事业”。我想说的是,其
实我是一个程序员
==============================================================================