非静态代码块和实例初始化方法
类的成员: (1)属性 (2)方法 (3) 构造器
类的第四成员:代码块
作用:为属性初始化
一、非静态代码块
1、语法格式:
【修饰符】 class 类名 【extends 父类】{
{
非静态的代码块
}
}
2、执行特点
(1)在创建对象的时候自动执行,每创建一个对象就执行一次
如果有多个非静态的代码块,按照顺序执行
(2)先与构造器执行的
(3)非静态代码块与属性的显示赋值他两谁在上面谁先执行
(4)如果创建了子类的对象,会先执行父类的非静态代码块、父类的属性的显试赋值、父类的构造器
3、实例初始化(…)
(1) .java代码编译为 .class时,会把diamante重新组装,如果类中有n个构造器,就会重新组装为n个实例化初始方法。
无参构造 -> ()
有参构造 -> (形参列表)
(2)实例初始化方法由三个部分组成
(A)属性的显式赋值语句
(B)非静态代码块语句
(C)构造器语句
其中(A)(B)是按照顺序组装的,但是(C)无论放在那里,都在最后
(3)创建子类对象的时候会先调用父类的实例化方法
public class TestNonStaticBlock {
public static void main(String[] args) {
Son s1 = new Son();
//构造器是最后执行的所以num的值是3
System.out.println(s1.getNum());//3
}
}
class Father{
Father(){
System.out.println("父类的无参构造");
}
{
System.out.println("父类的非静态的代码块1");
}
{
System.out.println("父类的非静态的代码块2");
}
private int i= getNumberI();//为i属性赋值的
public int getNumberI() {
System.out.println("getNumberI()");
return 1;
}
public int getI() {
return i;
}
}
class Son extends Father{
Son(){
System.out.println("无参构造");
num = 3;
}
{
System.out.println("非静态的代码块1");
num = 2;
}
{
System.out.println("非静态的代码块2");
}
private int num= getNumber();//为num属性赋值的
public int getNumber() {
System.out.println("getNum()");
return 1;
}
public int getNum() {
return num;
}
}
下面程序运行时的内存顺序
非静态代码块和构造器和显式赋值之间的执行顺序(题目很重要,有时间得看一下)
练习一
public class TestInit1 {
public static void main(String[] args) {
A obj = new A(20);
}
}
class A{
private int a = getInt();
{
a++;
System.out.println("(1)A非静态代码块");
System.out.println("(1)a = " + a);
}
A(int num){
a = num;
System.out.println("(2)A有参构造");
System.out.println("(2)a = " + a);
}
private int getInt(){
System.out.println("(3)A->getInt");
System.out.println("(3)a = " + a);
return 1;
}
}
/*
(3)A->getInt
(3)a = 0
(1)A非静态代码块
(1)a = 2
(2)A有参构造
(2)a = 20
*/
练习二
/*
实例初始化的过程:
(1)实例初始化:调用/执行 实例初始化的方法<init>(...)
(2)实例初始化方法的方法体由三个部分组成
第一 属性显示赋值
第二 非静态代码块
第三 构造器
(3)创建子类对象的时候会先执行父类的实例初始化方法
*/
public class TestInit2 {
public static void main(String[] args) {
A obj = new B(20);
}
}
class A{
private int a = getInt();
{
a++;
System.out.println("(1)非静态代码块");
System.out.println("(1)a = " + a);
}
A(int num){
a = num;
System.out.println("(2)A:有参构造");
System.out.println("(2)a = " + a);
}
public int getInt(){
System.out.println("(3)A->getInt");
System.out.println("(3)a = " + a);
return 1;
}
}
class B extends A{
private int b = getIntValue();
{
b++;
System.out.println("(1)B:非静态代码块");
System.out.println("(1)b = " + b);
}
B(int num){
super(num);
b = num;
System.out.println("(2)B:有参构造");
System.out.println("(2)b = " + b);
}
public int getIntValue(){
System.out.println("(3)B->getIntValue");
System.out.println("(3)b = " + b);
return 1;
}
}
/*
(3)A->getInt
(3)a = 0
(1)非静态代码块
(1)a = 2
(2)A:有参构造
(2)a = 20
(3)B->getIntValue
(3)b = 0
(1)B:非静态代码块
(1)b = 2
(2)B:有参构造
(2)b = 20
*/
练习三
(里面有关于多态重写的问题,比较复杂好好看看)
如果看了不是很懂的话再去看看练习四的注释
/*
实例初始化的过程:
(1)实例初始化:调用/执行 实例初始化的方法<init>(...)
(2)实例初始化方法的方法体由三个部分组成
第一 属性显示赋值
第二 非静态代码块
第三 构造器
(3)创建子类对象的时候会先执行父类的实例初始化方法
(4) 注意:通常面试题当中注意方法重写的问题
父类A的实例初始化的方法<init>(...)
❤❤(1)a = getInt(); --> 等价于a = this.getInt() 这个this表示当前的对象,表示正在创建的对象,现在正在创建的是子类的对象,那么通过子类的对象调用getInt()是执行子类的重写的getInt()
(2){
a++;
System.out.println("(1)非静态代码块");
System.out.println("(1)a = " + a);
}
(3)构造器
a = num;
System.out.println("(2)A:有参构造");
System.out.println("(2)a = " + a);
子类B的实例初始化的方法<init>(...)
(1)b = getInt();
(2){
b++;
System.out.println("(1)B:非静态代码块");
System.out.println("(1)b = " + b);
}
(3)构造器
super(num);
b = num;
System.out.println("(2)B:有参构造");
System.out.println("(2)b = " + b);
*/
public class TestInit3 {
public static void main(String[] args) {
A obj = new B(20);
}
}
class A{
private int a = getInt();//这个地方有一个陷阱,注意是重写
{
a++;
System.out.println("(1)非静态代码块");
System.out.println("(1)a = " + a);
}
A(int num){
a = num;
System.out.println("(2)A:有参构造");
System.out.println("(2)a = " + a);
}
public int getInt(){
System.out.println("(3)A->getInt");
System.out.println("(3)a = " + a);
return 1;
}
}
class B extends A{
private int b = getInt();
{
b++;
System.out.println("(1)B:非静态代码块");
System.out.println("(1)b = " + b);
}
B(int num){
super(num);
b = num;
System.out.println("(2)B:有参构造");
System.out.println("(2)b = " + b);
}
public int getInt(){
System.out.println("(3)B->getInt");
System.out.println("(3)b = " + b);
return 1;
}
}
/*
(3)A->getInt
(3)a = 0
(1)非静态代码块
(1)a = 2
(2)A:有参构造
(2)a = 20
*/
练习四
/*
*Override或者Overwrite 重写 覆盖
*this在类中,就看的是A类中的getInt(),就近原则,因为这个getInt没有被覆盖掉
*如果getInt()被重写,被覆盖,即使在A类中,通过子类的对象this,看到的只有子类重写后的getInt()方法
*
*/
public class TestInit4 {
public static void main(String[] args) {
A obj = new B(20);
}
}
class A{
private int a = getInt();//因为getInt() 方法是private,在子类中不可见不会被重写
//虽然这个地方也是this.getInt(),但是子类中是私有的,所以根据就近原则调用的父类的getInt()
{
a++;
System.out.println("(1)非静态代码块");
System.out.println("(1)a = " + a);
}
A(int num){
a = num;
System.out.println("(2)A:有参构造");
System.out.println("(2)a = " + a);
}
private int getInt(){
System.out.println("(3)A->getInt");
System.out.println("(3)a = " + a);
return 1;
}
}
class B extends A{
private int b = getInt();
{
b++;
System.out.println("(1)B:非静态代码块");
System.out.println("(1)b = " + b);
}
B(int num){
super(num);
b = num;
System.out.println("(2)B:有参构造");
System.out.println("(2)b = " + b);
}
private int getInt(){
System.out.println("(3)B->getInt");
System.out.println("(3)b = " + b);
return 1;
}
}