成员的初始化
对于局部变量来讲,java采用错误提示的方式来提示程序员没有对变量进行初始化
对于成员变量来说,java则采用了提供默认值的方式来对成员变量进行初始化
指定初始化
有几种方式可以用于对于成员变量进行赋值,比如在定义成员变量的时候对它进行赋值,使用函数来对它进行赋值,采用构造函数的方式来进行初始化
使用构造器来进行初始化
可以使用构造器来对成员进行初始化,但是需要注意,在你使用构造器之前,成员就已经被初始化成默认值了。
初始化顺序
在类的内部,变量定义的先后顺序决定了初始化的顺序,既便变量散落在方法定义之外也是一样的,在调用构造器之前,会优先对成员变量进行默认初始化
package charpter05;
class window{
window(int number){System.out.println("window("+number+")");}
}
class House{
window w1=new window(1);
House(){
System.out.println("House");
w3=new window(4);
}
window w2=new window(2);
window w3=new window(3);
}
public class test_5_7_1 {
public static void main(String[] args) {
new House();
}
}
//window(1)
//window(2)
//window(3)
//House
//window(4)
最终的运行效果与我们预期的一致,成员变量的初始化在构造函数调用之前
静态数据的初始化
初始化顺序是先静态对象,而后才是非静态对象,以下是对象的创建过程,假设有一个Dog的类
- 即是没有显示地使用static关键字,构造器实际上也是静态方法,因此,当首次创建类型为Dog的对象时,或者Dog类的静态方法/静态域首次被访问时,java解释器必须查找类路径,以定位到Dog.class文件
- 然后载入Dog.class,有关静态初始化的所有动作都会执行,静态初始化只在class对象首次加载的时候进行一次
- 当用new Dog()创建对象时,首先将在堆上为Dog对象分配足够的空间
- 存储空间被清零,然后将对象的基本类型数据进行初始化,而引用则设置成null
- 执行所有处于字段定义处的初始化动作
- 执行构造器
package charpter05;
class Bowl{
static Bowl b2=new Bowl(2);
Bowl(int number){
System.out.println("Bowl("+number+")");
}
}
class Table{
static Bowl b1=new Bowl(1);
Table(){
System.out.println("Table create");
}
}
public class test_5_7_2 {
public static void main(String[] args) {
// TODO Auto-generated method stub
new Table();
}
}
//Bowl(2)
//Bowl(1)
//Table create
显示的静态初始化
Java允许将多个静态初始化动作组织成一个特殊的“静态子句”(有时也叫做“静态块”),但它实际上只是一段跟在static关键字后面的代码,与其他静态初始化动作一样,这段代码只会执行一次
package charpter05;
class Cup {
Cup(){
System.out.println("Cup create");
}
static {
int i = 47;
}
}
public class test_5_7_3 {
public static void main(String[] args) {
// TODO Auto-generated method stub
new Cup();
}
}
//Cup create
非静态实例初始化
{
int i=45;
String j="hello";
}
以上的写法在java当中也是允许的,可以使用块的形式来对非静态实例进行初始化
数组的初始化
如果没有没有使用花括号对数组进行初始化,那你获得的只是一个数组的引用,因此不允许指定数组的大小,如果使用花括号对数组进行初始化,那么必须在创建数组的地方出现
那为什么还可以直接创建数组的引用呢?因为在Java当中可以将一个数组赋值给另一个数组
package charpter05;
public class test_5_8 {
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.print(a1[i]+" ");
}
}
}
//2 3 4 5 6
由这个例子可以看出,a2只是获得了对a1的引用,而不是复制这个数组
如果不确定数组里面到底有需要多少个元素,可以使用new关键字来创建固定大小的数组
package charpter05;
import java.util.Arrays;
public class test_5_8 {
public static void main(String[] args) {
int[] a1=new int[5];
System.out.println(Arrays.toString(a1));
}
}
//[0, 0, 0, 0, 0]
如果创建了一个非基本类型的数组,那就创建了一个引用数组,但它只是一个引用,通过创建新的对象,初始化进程才算结束,如果忘记创建对象,则会产生运行时异常,可以使用两种方式来进行初始化
package charpter05;
import java.util.Arrays;
public class test_5_8 {
public static void main(String[] args) {
//第一种方法,比较受限,只能在创建数组的地方使用
Integer[] a1={new Integer(1),new Integer(2),new Integer(3)};
Integer[] a2=new Integer[] {
new Integer(1),
new Integer(2),
new Integer(3)};
System.out.println(Arrays.toString(a1));
System.out.println(Arrays.toString(a2));
}
}
//[1, 2, 3]
//[1, 2, 3]
可变参数列表
由于所有的对象都直接或者间接的继承Object类,因此,我们可以以Object为数组为参数的方法使用
package charpter05;
import java.util.Arrays;
class A{}
public class test_5_8 {
public static void printString(Object[] args) {
for(Object obj:args) {
System.out.print(obj+" ");
}
System.out.println();
}
public static void main(String[] args) {
printString(new Integer[] {1,2,3});
printString(new String[] {"hello","world"});
printString(new A[3]);
}
}
//1 2 3
//hello world
//charpter05.A@15db9742 charpter05.A@6d06d69c charpter05.A@7852e922
由于这个A对象没有toString方法,因此默认打印类名@十六进制的方式。
除了以上的方式以外,还可以使用这样的方式来使用可变参数列表
package charpter05;
import java.util.Arrays;
class A{}
public class test_5_8 {
public static void printString(Object... args) {
for(Object obj:args) {
System.out.print(obj+" ");
}
System.out.println();
}
public static void main(String[] args) {
printString(new Integer[] {1,2,3});
printString(new String[] {"hello","world"});
printString(new A[3]);
printString(new A(),new A(),new A());
}
}
//1 2 3
//hello world
//null null null
//charpter05.A@15db9742 charpter05.A@6d06d69c charpter05.A@7852e922
不用显示的声明数组,但是传递的仍然是一个数组,如果传入的不是数组,编译器会自动将它转换成一个数组,并且也可以传递0个参数。
在具有尾随参数的时候,这样的方式更加完美
package charpter05;
import java.util.Arrays;
class A{}
public class test_5_8 {
public static void printString(int number,String... args) {
System.out.print(number+" ");
for(String string1:args) {
System.out.print(string1+" ");
}
System.out.println();
}
public static void main(String[] args) {
printString(1,"hello");
printString(2,"hello","world");
}
}
//1 hello
//2 hello world
除了使用对象数组作为可变参数之外,还可以使用基本数据类型作为可变参数进行传递。
package charpter05;
import java.util.Arrays;
class A{}
public class test_5_8 {
public static void printString(int... args) {
System.out.print(args.getClass()+" ");
for(int string1:args) {
System.out.print(string1+" ");
}
System.out.println();
}
public static void main(String[] args) {
printString(1,2,3,4,5);
printString(2,3,4,5,6);
}
}
//class [I 1 2 3 4 5
//class [I 2 3 4 5 6
在上面这个程序当中,使用了getClass()
方法,这个方法会打印出类名,[表示这个一个数组,I表示这是一个整数基本类型。
可变参数列表的使得重载更加复杂,看起来可能不会有问题,但是在使用过程当中会产生许多问题,因此,在重载方法上最好只使用一个可变参数列表,或者不使用可变参数列表。
枚举类型
可以使用enum
关键字来创建枚举类型,由于枚举类型是常量,因此经常以大写的方法表示。
为了使用枚举类型,需要创建一个该类型的引用,并将其赋值给某个实例
package charpter05;
enum SimplEnumUse{
NOT,NILD,MEDIUM,HOT,FLAMING
}
public class test5_9 {
public static void main(String[] args) {
// TODO Auto-generated method stub
SimplEnumUse e1=SimplEnumUse.FLAMING;
System.out.println(e1);
}
}
//FLAMING
在创建枚举类型时,编译器会自动添加一些有用的功能,比如toString()
方法,用于显示枚举实例的名字,使用ordenal()
方法,表示某个特定枚举常量的声明顺序,使用static values()
方法,用来按照枚举常量的声明顺序,产生由这些常量值构成的数组,并且枚举类型还可以直接使用switch语句。
package charpter05;
enum SimplEnumUse{
NOT,NILD,MEDIUM,HOT,FLAMING
}
public class test5_9 {
public static void main(String[] args) {
// TODO Auto-generated method stub
for(SimplEnumUse s:SimplEnumUse.values()) {
System.out.println(s+",ordinal:"+s.ordinal());
}
}
}
//NOT,ordinal:0
//NILD,ordinal:1
//MEDIUM,ordinal:2
//HOT,ordinal:3
//FLAMING,ordinal:4
暂无评论内容