一周过去了,又有些收获。

1.基本类型打包器的一点内幕

编译程序会以下代码

1
Integer number = 100;

转换为

1
Integer localInteger = Integer.valueOf(100);

查看src.zip文件夹中的java/lang中的Integer.java,有关valueOf()的操作内容如下:

1
2
3
4
5
public static Integer valueOf(int i){
if(i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}

IntegerCache.lowIntegerCache.high的默认值是-128和127.当i的值在这中间时就会检查前面是否有相同的值,如果有就直接返回这个实例。所以

1
2
3
Integer i1=100;
Integer i2=100;
System.out.println(i1==i2);

结果是true,但是换成200就是false。


2.数组

首先,数组是对象。

1
int[] scores = new int[2];

可以将int[]看作类名,这个类是由JVM动态产生的,而scores则是参考名称。

1
int[][] scores = new int[2][2];

应该理解为一个int[]的一维数组。如图

示意图

我的理解是:

  1. 有一个参考,是int[][]类型的,名字是scores,
  2. scores指向一个数组,数组长度为二,分别装了一个int[]类型的参考,
  3. 这两个参考有指向了两个连续的内存空间,分别里面是0,因为数组默认值是0。

默认值的情况:

数据类型 初始值
byte 0
short 0
int 0
long 0L
float 0.0F
double 0.0D
char \u0000
boolean false
null

看的出来,第一层的数组不影响第二层的,所以:

1
2
3
4
5
6
7
8
int[][] arr = new int[2][];
arr[0] = new int[]{1,2,3,4,5};
arr[1] = new int[]{1,2,3};
//------------------------------------
int[][] arr1 = {
{1,2,3,4,5},
(1,2,3)
}

注意:

1
Integer[] scores = new Integer;

这段代码建立了0个Integer数组,因为类的默认值是null。


3.数组复制

1
2
3
4
5
int[] scores1 = {1,2,3,4};
int[] scores2 =new int[scores1.lenght];
for(int i=0;i<scores1.length;++i){
scores2[i] = scores1[i];
}

这种复制要先创建一个新数组,再将值一个个填进去。

也有简单方法:

1
2
3
int[] scores1 = {1,2,3,4};
int[] scores2 =new int[scores1.lenght];
System.arraycopy(scores1,0,scores2,0,scores1.length);

五个参数是:来源数组,来源起始索引,目的数组,目的起始索引,复制长度。

在JDK6以上,有Arrays.copyOf()方法。不需要手动建立新数组。

1
2
int[] scores1 = {1,2,3,4};
int[] scores2 = Arrays.copyOf(scores1,scores1.length);

以上都是基本数据类型的复制,遇到对象时会不一样。

首先建立类:

1
2
3
4
5
6
7
8
class Clothes{
String color;
char size;
Clothes(String color,char size){
this.color = color;
this.size = size;
}
}
1
2
3
4
5
6
7
8
9
public class ShallowCopy{
public void static mian(String[] args){
Clothes[] Carray1 = {new Clothes("red",'L'),new Clothes("blue",'M')};
Clothes[] Carray2 = new Clothes[Carray1.length];
for(int i=0;i<Carray1.length;++i){
Carray2[i]=Carry1[i];
}
}
}

问题就出在这句Carray2[i]=Carry1[i]。对于基本数据类型,假设a=3,a=b,则b=3。但是对于对象来说,=代表了参考的相同,比如有个数组对象,参考名称是array1,如果,array2=array1,意思是这两个参考指向了同一个对象。从始至终,这里只会有一个对象,而我复制数组,显然是要两个对象(尽管他们一模一样)。

这种不成功的复制叫浅层复制,如图:

示意图

1
2
3
4
5
6
7
8
9
10
public class DeepCopy{
public void static mian(String[] args){
Clothes[] Carray1 = {new Clothes("red",'L'),new Clothes("blue",'M')};
Clothes[] Carray2 = new Clothes[Carray1.length];
for(int i=0;i<Carray1.length;++i){
Clothes c = new Clotnes(Carray1[i].color,Carray1[i].size);
Carray2[i] = c;
}
}
}

每次都新建一个对象,从Carray1那把相应的属性赋给它,再将这个对象的参考放入数组。

4.字符串

(1)将字符串转换为数字

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import java.util.Scanner;

public class Sum{
public static void main(Stirng[] args){
Scanner scanner = new Scanner(System.in);
long sum = 0;
long number = 0;
do{
System.out.print("输入数字:");
number = Long.parseLong(scanner.nextLine());
sum += number;
}while(number != 0);
System.out.println("总和:"+sum);
}
}

number = Long.parseLong(scanner.nextLine());可以将传入的字符串转化为long类型。其他转换方式与此类似:Byte.parseByte(number)

(2)字符串常量与字符串池

1
2
3
4
char name = {'k','a','t','e'};
String name1 = new String(name);
String name2 = new String(name);
System.out.println(name1==name2);

显然是false,因为new了两个对象,他们的内容是一样的,但是斌不是同一个对象。

1
2
3
String name1 = "kate";
String name2 = "kate";
System.out.println(name1==name2);

是什么呢?是true。

为了效率考虑,以””包含的字符串,只要内容相同,无论在程序中出现了多少次,JVM都只会建立一个String实例。

注意:**new一定是建立了新对象。**

(3)不可变动字符串

在Java中,字符串对象一旦建立,就无法再次更改,对象中没有任何方法可以更改。

1
2
3
String name1 = "Java";
String name2 = name1 + "world";
System.out.println(name2);

会显示Javaworld,显然并不是更改了name1的内容。

1
2
String s = "Java";
String s1 = (new StringBuilder()).append(s).append("world").toString();

大意是会变成建立java.lang.StringBuilder对象,使用其append()方法把s和”world”拼接,转换为toString()返回。

简单说,用+拼接会产生新的String实例。