Java笔记 —— 初始化

h2{
color: #4ABCDE;
}
a{
text-decoration: none !important;
}
a:hover{
color: red !important;
text-decoration: underline !important;
}
pre{
border: solid 1px #CCCCCC;
border-radius: 3px;
background-color: #F8F8F8;
margin: 15px;
overflow: auto;
white-space: pre;
font-size: 13px;
font-family: consolas, courier, monospace;
line-height: 20px;
padding: 6px 10px;
tab-size: 4;
}
p.textRight{
text-align: right;
}
p.header{
color: #787878;
font-size: 20px;
font-family: 楷体, "微软雅黑", arial;
font-weight: bold;
}
span.bold{
font-weight: bold;
}

一、属性初始化和构造器调用

1)编译器会为属性指定一个默认的初始值,例如:int i; 默认初始值为 0,  double d; 默认初始值为0.0

2)局部变量使用前必须由程序员指定初始值

3)在构造器被调用之前,属性就被初始化了

例1:


package com.example;

public class Values{
private boolean bt;
private char c;
private byte b;
private short s;
private int i;
private float f;
private double d;
private Values v; public void show(){
System.out.println("属性的默认初始化值:");
System.out.println("boolean: " + bt);
System.out.println("char: " + c);
System.out.println("byte: " + b);
System.out.println("short: " + s);
System.out.println("int: " + i);
System.out.println("float: " + f);
System.out.println("double: " + d);
System.out.println("Values: " + v);
}
}

package com.example;

public class Test{
public static void main(String[] args){
Values val = new Values();
val.show();
}
}

运行结果为:

属性的默认初始化值:
boolean: false
char:
byte: 0
short: 0
int: 0
float: 0.0
double: 0.0
Values: null
  • 编译器为所有的属性都指定了一个默认初始值
  • 编译器为对象的引用指定的默认初始值是 null,例如:例子中的 private Values v;
  • 编译器为 char 类型指定的初始值是0(ASCII 中的 NUL),是空字符,这里以空白表示

例2:


package com.example;

public class Man{
public void speak(){
int i;
System.out.println("i = " + i); // error,i 是局部变量,局部变量使用之前必须要初始化
}
}

例3:


package com.example;

public class Man{
public Man(int i){
System.out.println("Man" + "(" + i + ")");
}
}

package com.example;

public class Woman{
public Man m1 = new Man(1);
public Man m2 = new Man(2); public Woman(){
System.out.println("Woman()");
} public Man m3 = new Man(3);
}

package com.example;

public class Test{
public static void main(String[] args){
new Woman();
}
}

运行结果为:

Man(1)
Man(2)
Man(3)
Woman()
  • 这个例子不是使用系统的默认值对属性进行初始化,而是通过我指定的值对属性进行初始化
  • Woman 类中有三个属性 m1,m2,m3 和一个 构造器 Woman(),从运行结果可以看出:属性先被初始化,然后构造器才被调用
  • 属性先被初始化这一特性与属性的位置无关,例如:Woman 类中 m3 就位于构造器的后面,但 m3 也在构造器被调用之前就已经被初始化了

二、初始化的顺序

1)属性分为静态属性和非静态属性,且静态属性比非静态属性先初始化,即初始化顺序为:静态属性 -> 非静态属性 -> 构造器调用

2)静态属性只会在创建对象或者被直接调用的时候初始化(在主类中静态属性也会被初始化),非静态属性只会在创建对象的时候初始化

3)无论创建多少个对象,静态属性只占用一块存储空间,所以静态属性只会初始化一次,而非静态属性在每次创建对象时都会初始化

4)含有继承关系的初始化:当创建一个子类对象时,该对象会包含一个父类的对象,那么保证父类对象初始化的方法是:在子类构造器中调用父类构造器

例1:


package com.example;

public class Pear{
public Pear(int i){
System.out.println("Pear" + "(" + i + ")");
}
}

package com.example;

public class Apple{
public Pear p1 = new Pear(1);
public static Pear p2 = new Pear(2); public Apple(){
System.out.println("Apple()");
} public static Pear p3 = new Pear(3);
}

package com.example;

public class Test{
public static void main(String[] args){
new Apple();
}
}

运行结果:

Pear(2)
Pear(3)
Pear(1)
Apple()
  • 该例子中用 new 创建了 Apple 对象,所以 Apple 类中的静态属性和非静态属性都会初始化
  • 初始化顺序:静态属性 -> 非静态属性 -> 构造器调用,例如:例子中先输出 Pear(2) 和 Pear(3),然后输出 Pear(1),最后调用 Apple() 构造器,所以是先初始化静态属性 p2 和 p3,然后初始化非静态属性 p1,最后调用构造器 Apple()

例2:


package com.example;

public class Pear{
public Pear(int i){
System.out.println("Pear" + "(" + i + ")");
}
}

package com.example;

public class Apple{
public static String color = "red";
public static int number = 10;
public String size = "big";
}

package com.example;

public class Test{
public static void main(String[] args){
System.out.println("Hello World !");
System.out.println("color: " + Apple.color);
}
static Pear p1 = new Pear(1);
static Pear p2 = new Pear(2);
Pear p3 = new Pear(3);
}

运行结果:

Pear(1)
Pear(2)
Hello World !
color: red
  • Test 类是主类,所以静态属性 p1 和 p2 都会初始化。非静态属性 p3 不会初始化,是因为我们没有创建 Test 对象
  • Apple 类中有两个静态属性和一个非静态属性,该例子中调用了 Apple.color ,静态属性 color 在调用的时候会初始化为 red,而静态属性 number 和非静态属性 size 没有被调用,也没有创建对象,所以此时它们不会初始化

例3:


package com.example;

public class Cat{
public Cat(int i){
System.out.println("Cat" + "(" + i + ")");
}
}

package com.example;

public class Dog{
public Cat c1 = new Cat(1);
public static Cat c2 = new Cat(2); public Dog(){
System.out.println("Dog()");
} public static Cat c3 = new Cat(3);
}

package com.example;

public class Test{
public static void main(String[] args){
System.out.println("第一次创建对象");
Dog d1 = new Dog();
System.out.println("第二次创建对象");
Dog d2 = new Dog();
}
}

运行结果:

第一次创建对象
Cat(2)
Cat(3)
Cat(1)
Dog()
第二次创建对象
Cat(1)
Dog()
  • 第一次创建对象的时候,静态属性和非静态属性都初始化了,但是第二次创建对象的时候,只有非静态属性会再次初始化,静态属性只初始化一次

例4:

父类不含构造器


package com.example;

public class T{
public T(int i){
System.out.println("T" + "(" + i + ")");
}
}

package com.example;

public class Person{ // 父类
public static T t4 = new T(4);
public T t5 = new T(5);
public static T t6 = new T(6);
}

package com.example;

public class Man extends Person{ // 子类
public static T t1 = new T(1);
public T t2 = new T(2);
public static T t3 = new T(3); public Man(){
System.out.println("Man()");
}
}

package com.example;

public class Test{
public static void main(String[] args){
new Man();
}
}

运行结果:

T(4)
T(6)
T(1)
T(3)
T(5)
T(2)
Man()
  • 某个类不含构造器时,编译器会为这个类生成一个默认构造器,该生成的默认构造器是一个无参构造器。这些操作是在编译时完成的,所以我们看不见
  • 当父类含有默认构造器时,编译器会自动在子类的构造器中调用父类的构造器来对父类进行初始化。这个过程也是在编译时完成的,所以我们看不见
  • 初始化的顺序:父类静态属性 -> 子类静态属性 -> 父类非静态属性 -> 子类非静态属性 -> 调用子类构造器

父类含有无参构造器


package com.example;

public class T{
public T(int i){
System.out.println("T" + "(" + i + ")");
}
}

package com.example;

public class Person{ // 父类
public static T t4 = new T(4);
public T t5 = new T(5);
public static T t6 = new T(6); public Person(){ // 无参构造器
System.out.println("Person()");
}
}

package com.example;

public class Man extends Person{ // 子类
public static T t1 = new T(1);
public T t2 = new T(2);
public static T t3 = new T(3); public Man(){
System.out.println("Man()");
}
}

package com.example;

public class Test{
public static void main(String[] args){
new Man();
}
}

运行结果:

T(4)
T(6)
T(1)
T(3)
T(5)
Person()
T(2)
Man()
  • 父类含有无参构造器时和父类含有默认构造器时差不多,编译器会自动在子类的构造器中调用父类的构造器来对父类进行初始化
  • 不同的是,当我们创建了构造器之后,编译器就不会再为类创建一个默认构造器了
  • 初始化顺序:父类静态属性 -> 子类静态属性 -> 父类非静态属性 -> 父类构造器调用 -> 子类非静态属性 -> 子类构造器调用

父类只含有有参构造器


package com.example;

public class T{
public T(int i){
System.out.println("T" + "(" + i + ")");
}
}

package com.example;

public class Person{ // 父类
public static T t4 = new T(4);
public T t5 = new T(5);
public static T t6 = new T(6); public Person(int i){
System.out.println("Person" + "(" + i + ")"); // 有参构造器
}
}

package com.example;

public class Man extends Person{ // 子类
public static T t1 = new T(1);
public T t2 = new T(2);
public static T t3 = new T(3); public Man(){
super(1); // super 关键字表示调用父类构造器,且必须位于子类构造器的第一行,每个子类的构造器只能调用父类构造器一次
System.out.println("Man()");
}
}

package com.example;

public class Test{
public static void main(String[] args){
new Man();
}
}

运行结果:

T(4)
T(6)
T(1)
T(3)
T(5)
Person(1)
T(2)
Man()
  • 当父类只有有参构造器时,子类构造器中必须使用 super 关键字调用父类构造器,否则会报错。
  • 当子类有多个构造器时,子类中的每个构造器都必须要调用父类构造器(如果父类有多个构造器,那么子类构造器只需挑父类构造器的其中一个来调用即可,不过一定要保证子类的每个构造器都有调用父类构造器)

父类既含有无参构造器,也含有有参构造器


package com.example;

public class T{
public T(int i){
System.out.println("T" + "(" + i + ")");
}
}

package com.example;

public class Person{ // 父类
public static T t4 = new T(4);
public T t5 = new T(5);
public static T t6 = new T(6); public Person(){ // 无参构造器
System.out.println("Person()");
}
public Person(int i){
System.out.println("Person" + "(" + i + ")"); // 有参构造器
}
}

package com.example;

public class Man extends Person{ // 子类
public static T t1 = new T(1);
public T t2 = new T(2);
public static T t3 = new T(3); public Man(){ // 子类无参构造器
System.out.println("Man()");
}
public Man(int i){ // 子类有参构造器
System.out.println("Man" + "(" + i + ")");
}
}

package com.example;

public class Test{
public static void main(String[] args){
System.out.println("调用子类的无参构造器");
new Man();
System.out.println("调用子类的有参构造器");
new Man(1);
}
}

运行结果:

调用子类的无参构造器
T(4)
T(6)
T(1)
T(3)
T(5)
Person()
T(2)
Man()
调用子类的有参构造器
T(5)
Person()
T(2)
Man(1)
  • 当父类含有无参构造器时,即使子类有多个构造器,这些构造器也无需显式地通过 super 关键字调用父类构造器,因为编译器会自动为每个子类的构造器都调用父类的无参构造器,例如:例子中运行结果打印了两次 Person(),这是两次创建子类对象时,编译器自动调用父类中无参构造器的结果

总结:如果要建立继承关系时,最好给父类创建一个无参构造器或者不给父类创建任何构造器

三、静态块和非静态块

1)静态块会使所有静态属性都被初始化,即使静态属性不在静态块内

例如:


package com.example;

public class T{
public T(int i){
System.out.println("T" + "(" + i + ")");
}
}

package com.example;

public class S{
public static T t1;
public static T t2;
public static T t3;
public T t4;
public T t5;
public T t6;
public T t7 = new T(7); // t7 不在静态块内 static{ // 静态块
t1 = new T(1);
t2 = new T(2);
t3 = new T(3);
} { // 非静态块
t4 = new T(4);
t5 = new T(5);
t6 = new T(6);
}
}

package com.example;

public class Test{
public static void main(String[] args){
System.out.println(S.t1);
}
}

运行结果:

T(7)
T(1)
T(2)
T(3)
com.example.T@15db9742
  • 可以看到,该例子中只是调用了 S.t1 ,静态属性 t2, t3, t7 也跟着被初始化了

四、初始化的方式

1)在定义处初始化

2)在构造器内初始化

3)在静态块或非静态块内初始化

4)等到要用的时候再初始化

五、数组初始化

数组有三种初始化的方式

第一种初始化的方式


package com.example;
import java.util.Arrays; public class Test{
public static void main(String[] args){
int[] a = {1,2,3,4,5}; /* error, 只能写在同一行 int[] a;
a = {1,2,3,4,5} */ // System.out.println(a); 这种方式无法打印数组的值 System.out.println(Arrays.toString(a)); // 打印数组的值
}
}

运行结果:

[1, 2, 3, 4, 5]

第二种初始化的方式


package com.example;
import java.util.Arrays; public class Test{
public static void main(String[] args){
int[] a;
a = new int[5];
for(int i=0; i

运行结果:

[0, 1, 2, 3, 4]

第三种初始化的方式

例1:


package com.example;
import java.util.Arrays; public class Test{
public static void main(String[] args){
int[] a;
a = new int[]{1,2,3,4,5};
System.out.println(Arrays.toString(a));
}
}

运行结果:

[1, 2, 3, 4, 5]

例2(这种方式的用途):


package com.example;
import java.util.Arrays; public class T{
public void show(Integer[] i){ //必须为 Integer 类型,不能是 int 这些基本类型
System.out.println(Arrays.toString(i));
}
public void show(String[] str){
System.out.println(Arrays.toString(str));
}
}

package com.example;

public class Test{
public static void main(String[] args){
T t1 = new T();
t1.show(new Integer[]{5,4,3,2,1}); // 必须为 Integer 类型,不能是 int 这些基本类型
t1.show(new String[]{"张三", "李四", "王五"});
}
}

运行结果:

[5, 4, 3, 2, 1]
[张三, 李四, 王五]
  • 很明显这种方式的优点是无需额外定义一个数组变量 int[] a

参考资料:

《Java 编程思想》第4版


End~

Java笔记 —— 初始化的更多相关文章

  1. Java笔记: 初始化块

    Java语言提供了很多类初始化的方法,包括构造器.初始化器等.除了这两种方法之外,我们还可以用初始化块(initialization block)来实现初始化功能. 基本语法 初始化块是出现在类声明中 ...

  2. Effective Java笔记一 创建和销毁对象

    Effective Java笔记一 创建和销毁对象 第1条 考虑用静态工厂方法代替构造器 第2条 遇到多个构造器参数时要考虑用构建器 第3条 用私有构造器或者枚举类型强化Singleton属性 第4条 ...

  3. java笔记整理

    Java 笔记整理 包含内容     Unix Java 基础, 数据库(Oracle jdbc Hibernate pl/sql), web, JSP, Struts, Ajax Spring, E ...

  4. 转 Java笔记:Java内存模型

    Java笔记:Java内存模型 2014.04.09 | Comments 1. 基本概念 <深入理解Java内存模型>详细讲解了java的内存模型,这里对其中的一些基本概念做个简单的笔记 ...

  5. Java笔记 —— 继承

    Java笔记 -- 继承 h2{ color: #4ABCDE; } a{ text-decoration: none!important; } a:hover{ color: red !import ...

  6. Java笔记---枚举类和注解

    Java笔记---枚举类和注解 一.枚举类 自定义枚举类 方式一:JDK5.0之前自定义枚举类 class Seasons { //1. 声明Seasons对象的属性 private final St ...

  7. Java类初始化

    Java类初始化 成员变量的初始化和构造器 如果类的成员变量在定义时没有进行显示的初始化赋值,Java会给每个成员变量一个默认值 对于  char.short.byte.int.long.float. ...

  8. Java提高篇——静态代码块、构造代码块、构造函数以及Java类初始化顺序

    静态代码块:用staitc声明,jvm加载类时执行,仅执行一次构造代码块:类中直接用{}定义,每一次创建对象时执行.执行顺序优先级:静态块,main(),构造块,构造方法. 构造函数 public H ...

  9. java数组初始化

    java数组初始化 //静态初始化数组:方法一 String cats[] = new String[] { "Tom","Sam","Mimi&qu ...

随机推荐

  1. IDEA中jsp页面写out.println会报错?

    解决办法: (1)在WEB-INF目录下新建一个lib目录,并把Tomcat安装目录下的如下两个jar包复制过来. (2)选择jsp-api.jar,右键,Add as Library. (3)在Fi ...

  2. Gson的fromJson()方法

    Gson提供了fromJson()方法来实现从Json相关对象到Java实体的方法. 在日常应用中,我们一般都会碰到两种情况,转成单一实体对象和转换成对象列表或者其他结构. 先来看第一种: 比如jso ...

  3. JTAG与JLink说明

    JTAG接口解读 通常所说的JTAG大致分两类,一类用于测试芯片的电气特性,检测芯片是否有问题:一类用于Debug:一般支持JTAG的CPU内都包含了这两个模块. 一个含有JTAG Debug接口模块 ...

  4. P2896 [USACO08FEB]一起吃饭Eating Together

    传送门 可以考虑DP 设 f [ i ] [ 1/2/3 ] [ 0/1 ] 表示当前考虑到第 i 头牛,打算让当前位置的编号变成 1/2/3,并且打算让整段序列上升/下降 0/1 然后就对每种情况慢 ...

  5. Xsheel远程链接ECS,Xftp上传文件到ECS

    下载Xshell 工具:用来远程实现远程访问. 下载Xftp工具:方便用来上传文件. 下载方式直接百度搜索,如下如: 下载完成之后安装. 接下来就是链接云服务器了. 直接百度经验按照步骤来就OK了,如 ...

  6. c#操作windows本地账户

    using System;using System.Collections.Generic;using System.Text;using System.Runtime.InteropServices ...

  7. python3 杂记

    python3 杂记 test001 --test001.py       ( from test2.test002 import * def test1(): print('1') if __nam ...

  8. pl/sql declare loop if

    -- 1.判断表是否存在,如果存在则drop表 -- 2.创建表 -- 3.插入1W条数据 -- 4.每1K条commit一次 declare v_table ):='STUDENT'; --表名 v ...

  9. Sublime text中文乱码解决办法

    ConvertToUTF8 安装这个插件可以解决编码混乱问题 首先必须先配一下Sublime text ,安装 Package Control 1.  用Sublimt text 打开任意一个文件,C ...

  10. 在Mac上安装mysql

    进入这个网站: https://dev.mysql.com/downloads/mysql/ 然后点击安装就行了. 注意在这里启动mysql 然后mac上所有的mysql命令都得用绝对路径才能生效