1、静态初始化只有在必要的时刻才会进行。
静态初始化比如:static的变量成员,或者是一段跟在static关键字后面的代码。
public class Spoon{
static int i;
static{
i = 47;
}
}
这两种情况仅仅执行一次:当首次生成这个类的一个对象时,或者首次访问属于那个类的静态数据成员时(即使从未生成过那个类的对象)。
2、数组初始化
定义一个数组有两种写法:int [] a1 或者是 int a1[]
《Java编程思想》里面说到“编译器不允许指定数组的大小”,我认为这里是翻译错误了:Java的内存分配原则是先在堆栈建立一个变量的引用(可以理解为指针),也就是说无论我们用int[] a1还是int a1[],我们拥有的都只是对数组的引用,而数组真正的数组对象是在堆上面的对象。所以给数组以相应的存储空间,就必须写初始化表达式,初始化表达式应该是对数组对象进行操作而不是对引用进行操作。这与C++有很大的不同。
对于数组,初始化动作可以出现在代码的任何地方。但是也可以使用一种特殊的初始化表达式。类似:
int[] a1 = {1,2,3,4,5};
这种情况下存储空间的分配(等价于使用new关键字)将由编译器负责。
===========番外============
public class ArraysOfPrimitives{
public static void main(String[] args){
int[] a1 = {1,2,3,4,5};
int[] a2 ;
a2 = a1;
for(int i = 0; i < a2.length;i++)
a2[i] = a2[i] + 1;
for(int i = 0; i < a1.length; i++)
System.out.println(a[i]);
}
}
这里面a2是新建的一个句柄。并没有为a2分配一个新的对象而只是将a2指向了a1已经指向的数组对象。所以运行结果为2 3 4 5 6
==========================
此外数组的另一种初始化方式是使用new关键字。这适用于我们并不知道具体会有多少个元素以及各个元素是什么,但是我们可以知道一个元素数量的上标。比如:
import java.util.*;
public class ArrayNew{
public static void main(String[] args){
int[] a;
a = new int[100];//尽量int[] a = new int[100];
System.out.println(a.length);
System.out.println(Arrays.toString(a));
}
}
通过这个小例子我们可以发现,使用new关键字为数组进行初始化是可行的。此外:Arrays.toString()方法属于java.util标准类库,它将产生一维数组的可打印版本。
紧接着我们来比较一下原始类型和封装类型在数组初始化的时候会有什么不同。定义代码如下:
import java.util.*;
public class ArrayNew{
public static void main(String[] args){
int[] a = new int[10];
System.out.println(a[3]);
//System.out.println(a.length);
//System.out.println(Arrays.toString(a));
}
}
输出当然为0.
把上面的int改为Integer则输出为null.
3、可变参数列表
课本上给出的一个例子,其实我觉得是多态领域的例子。这里也做做笔记好了。
class A{}
public class VarArgs {
static void printArray(Object[] args){
for(Object obj : args)
System.out.print(obj + " ");
System.out.println();
}
public static void main(String[] args){
printArray(new Object[]{
new Integer(47),new Float(3.14),new Double(11.11)
});
printArray(new Object[]{
"one","two","three"
});
printArray(new Object[]{
new A(),new A(),new A()
});
}
}
47 3.14 11.11
one two three
A@f39b3a A@1542a75 A@af993e 默认行为下,如果没有定义toString()方法,则是打印类的名字和对象的地址。
printArray(new Object[]{
34,new Float(3.14),new Double(11.11)
});
也能正确编译运行。
在Java SE5新引入的可变参数的特性。我们可以实现下面的代码:
class A{}
public class VarArgs{
static void printArray(Object ... args){
for(Object obj : args)
System.out.print(obj + " ");
System.out.println();
}
public static void main(String[] args){
printArray(new Integer(47),new Float(3.14),new Double(11.11));
printArray(47,3.14F,11.11D);
printArray(new A(),new A(),new A());
printArray((Object[])new Integer[]{1,2,3,4});
printArray();
}
}
47 3.14 11.11
47 3.14 11.11
A@160a26f A@1484a05 A@f39b3a
1 2 3 4
有了可变参数,就再也不用显式地编写数组语法了,当你指定参数时,编译器实际上会为你去填充数组。你获取的仍旧是一个数组,这就是为什么print()可以使用foreach来迭代该数组的原因。但是,这不仅仅只是从元素列表到数组的自动转换,就像Integer数组被转型为一个Object数组并传递给了printArray方法,很明显,编译器会发现它已经是一个数组了,所以不会在其上执行任何转换。因此,如果你有一组事物,可以把它们当做列表传递,而如果你已经有了一个数组,该方法可以把它们当做可变参数列表来接受。
真的是可变的噢:
class A{}
public class VarArgs{
static void printArray(Object ... args){
System.out.println(args.length);
for(Object obj : args)
System.out.print(obj + " ");
System.out.println();
}
public static void main(String[] args){
printArray(new Integer(47),new Float(3.14),new Double(11.11));
printArray(47,3.14F,11.11D);
printArray(new A(),new A(),new A());
printArray((Object[])new Integer[]{1,2,3,4});
printArray();
}
}
3
47 3.14 11.11
3
47 3.14 11.11
3
A@160a26f A@1484a05 A@f39b3a
4
1 2 3 4
0