1.下面这段代码的输出结果是什么?
public class HelloB extends HelloA {
public HelloB() {
System.out.println("HelloB");
}
{
System.out.println("I’m B class");
}
static {
System.out.println("static B");
}
public static void main(String[] args) {
new HelloB();
}
}
class HelloA {
public HelloA() {
System.out.println("HelloA");
}
{
System.out.println("I’m A class");
}
static {
System.out.println("static A");
}
}
static A
static B
I’m A class
HelloA
I’m B class
HelloB()
解析:
- 存在父子关系,又有静态代码块,先执行父类静态代码块,再执行子类静态代码块,故打印static A static B
- 存在父子关系,又有非静态代码块,先执行父类非静态代码块,父类构造器,再执行子类非静态代码块,子类构造器故打印I’m A class HelloA I’m B class HelloB
静态代码块=>非静态代码块=>构造方法
父子关系:父类静态代码块=>子类静态代码块=>父类非静态代码块=>父类构造函数=>子类非静态代码块=>子类构造函数
非静态代码块
{
System.out.println("I'm B class");
}
这个是非静态代码块,也叫普通代码块,在每个类创建前(构造函数之前)调用 ,不创建对象的时候,不被调用,代码块中定义的变量都是局部变量,如果有父子关系的话,先执行父类的,再执行子类的。非静态代码块属于对象,静态代码块属于类。
- 例1:
package com.mousycoder.staticTest;
public class Child extends Father{
static {
System.out.println("child-->static");
}
private int n = 20;
{
System.out.println("Child Non-Static");
n = 30;
}
public int x = 200;
public Child() {
this("The other constructor");
System.out.println("child constructor body: " + n);
}
public Child(String s) {
System.out.println(s);
}
public void age() {
System.out.println("age=" + n);
}
public void printX() {
System.out.println("x=" + x);
}
public static void main(String[] args) {
new Child().printX();
}
}
class Father {
static {
//System.out.println("n+"+n);
//当n定义在下面时,会提示Cannot reference a field before it is defined,
//所以必须把n定义移到上面才可以输出
System.out.println("super-->static");
}
public static int n = 10;
public int x = 100;
public Father() {
System.out.println("super's x=" + x);
age();
}
{
System.out.println("Father Non-Static");
}
public void age(){
System.out.println("nothing");
}
}
结果:
super-->static
child-->static
Father Non-Static
super's x=100
age=0
Child Non-Static
The other constructor
child constructor body: 30
x=200
解析:
- 先执行静态代码块,有父子关系,先执行父类静态代码块,打印super–>static
- 执行子类静态代码块,打印child–>static
- 实例化子类的时候,先实例化父类,在调用父类构造方法之前,先调用父类非静态代码块,打印Father Non-Static
- 实例化父类,调用父类构造方法,执行第一句 System.out.println(“super’s x=” + x); 在调用构造方法之前,成员变量x 已经被赋值为100,打印super’s x=100
- 执行age()方法,因为main方法中真正实例化的是子类,子类又重写了父类的age方法,所以执行子类的age方法,此时子类还没初始化,默认n=0 ,打印age=0
- 实例化子类,调用子类构方法之前,调用子类非静态代码块,打印Child Non-Static
- 调用子类构造方法,执行this(“The other constructor”),调用子类的Child(String s),打印The other constructor
- 执行System.out.println("child constructor body: " + n); 初始化之前 成员变量初始值为20,执行完非静态代码块后 n被修改成30 ,所以这里n =30 打印child constructor body: 30
- 执行printX()方法,打印x = 200
注意点:
子类重写父类的方法
虽然非静态代码块里是局部变量,但是可以改变类的成员变量的值
- 例2
public class Father {
{
System.out.println("Father___非静态代码块");
}
public Father() {
System.out.println("Father___构造方法");
}
}
class Son extends Father {
{
System.out.println("Son___非静态代码块");
}
public Son() {
System.out.println("Son___构造方法");
}
}
class Test {
public static void main(String [] args){
Father son=new Son();
son=new Son();
}
}
输出结果:
Father___非静态代码块
Father___构造方法
Son___非静态代码块
Son___构造方法
- 加载顺序
非静态代码块 > 构造方法 - 原因
因为是继承关系,所以首先会加载Father的非静态代码块,然后加载Son的非静态代码块,之后在加载Father的构造方法,然后在加载Son的构造方法,且非静态代码块每实例化一次就会执行一次。
静态代码块
static {
System.out.println("static B");
}
属于静态代码块,使用场景:
1.想用一个存储区域来保存一个特定的数据,不想创建对象
2.创建一个特殊的方法,与这个类的对象没有关联,即使没创建对象,也可以调用
- 例1:
public class Father {
static{
System.out.println("Father___静态代码块");
}
public Father() {
System.out.println("Father___构造方法");
}
}
class Son extends Father {
static{
System.out.println("Son___静态代码块");
}
public Son() {
System.out.println("Son___构造方法");
}
}
class Test {
public static void main(String [] args){
Father son=new Son();
son=new Son();
}
}
运行结果:
Father___静态代码块
Son___静态代码块
Father___构造方法
Son___构造方法
-
加载顺序:
静态代码块 > 构造器。
-
原因:
因为是继承关系,所以首先会加载Father的静态代码块,然后加载Son的静态代码块,之后在加载Father的构造方法,然后在加载Son的构造方法,且静态代码块在这个类被调用时只执行一次。