您的位置:首页 > 编程语言 > Java开发

java 学习笔记《1》

2011-04-04 23:30 267 查看
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 len??gth = 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⊙)哦,小盆友。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: