Java中的static、代码块、final

一、static

1.1案例引入

如果说我们想要知道一个类创建了多少个实例对象,那我们就定义一个count 的变量,每当创建实例对象时,count++。

public class Test01 {
    public static void main(String[] args) {
        int count = 0;
        A a1 = new A();
        count++;

        A a2 = new A();
        count++;

        System.out.println("有" + count + "个A对象");
    }
}

class A{

}

这样写的话非常不安全,也体现不了封装,很low。

这时候不禁就会思考是否java中存在某个方式,能解决这个问题捏。

那就是static关键字!

我们现在可以这样写:

public class Test01 {
    public static void main(String[] args) {
        //int count = 0;
        A a1 = new A();
        //count++;

        A a2 = new A();
        //count++;

        System.out.println("有" + a1.count + "个A对象");//输出2
    }
}

class A{
    public static int count = 0;

    public A() {
        count++;
    }
}

在这里我们定义了一个变量count,是一个类变量(静态变量)

该变量的特点就是会被A类的所有对象实例共享

即:a1.count 和 a2.count都为2

因为也叫类变量,所以也可以这样调用A.count

1.2类变量(静态变量)

要点:1)static变量是同一个类所有对象共享

2)static变量,在类加载的时候就生成了(在代码块时会具体叙述)

1.3类方法(静态方法)

静态方法的调用与静态变量一样,并且与所有对象共享

注意事项:1)static方法中无this参数,即不能使用this

2)static方法中不能使用super

3)static方法中只能访问静态变量或静态方法

二、代码块

2.1案例引入

我们现在想要对一个类,在每次创建对象时候输出一个“hello,world‘’,那就在每个构造器中写一个输出语句。

class A{


    private int n1;

    public A() {
        System.out.println("hello,world");
    }

    public A(int n1) {
        System.out.println("hello,world");
        this.n1 = n1;
    }
}

此时我们发现,代码冗余,每个构造器都要写,很low,此时我们可以用代码块来解决。

public class Test01 {
    public static void main(String[] args) {
        A a1 = new A();
        A a2 = new A(1);
    }
}

class A{
    {
        System.out.println("hello,world");
    }

    private int n1;

    public A() {

    }

    public A(int n1) {
        this.n1 = n1;
    }
}

输出如下:

2.2基本介绍

1)如果多个构造器中都有 重复的语句,可以抽取到初始化块中,提高代码的重用性

2)代码块又称初始化块,属于类成员,类似于方法。

3)代码块没有方法名、返回值、参数,只有方法体

4)代码块不能通过显示调用(因为名字都没,咋调用),而是类加载时或创建对象时隐式调用。

5)代码块的调用顺序优先于构造器

2.3static代码块

static代码块也叫静态代码块,随着类的加载而执行,只会执行一次普通代码块每创建一个对象就执行。

注意:只执行一次是说当你使用过这个类以后,再使用的话也不会执行

只会输出一个hello,world

2.4类加载

那么类啥时候加载呢?

  1. 创建对象时,即new一个对象

  1. 创建子类对象实例,父类也会被加载

  1. 使用类的静态成员是,即使用里面静态方法、静态属性

总得来说就是一旦跟这个类有关时就会加载!

2.5创建一个对象

创将一个对象时在一个类中的调用顺序:

第一步:调用静态代码块和静态属性初始化,这两个人调用优先级一样,调用顺序根据定义顺序执行。

第二步:调用普通代码块和普通属性初始化,这两个人调用优先级一样,调用顺序根据定义顺序执行。

第三步:调用构造方法。

2.6烦人对象创建

当加上继承关系的时候,要遵守继承的调用原则。

public class test {
    public static void main(String[] args) {
        new BBB();
        //1.进行类的加载调用静态成员
        //由于继承关系,先加载父类在加载子类
        //2.创建对象
        //先进行成员属性的默认初始化
        //再进行成员属性的显示初始化和普通代码块初始化(调用顺序由定义顺序决定)
        //最后进行构造器中剩余内容初始化
        //!!遵守继承初始化调用原则
    }
}

class AAA {
    private int n = fun1();
    private static int sn = fun2();
    static {System.out.println("AAA的静态代码块的调用~");};
    {System.out.println("AAA的普通代码块的调用~");};
    //隐藏了
    //super()
    //普通代码块调用
    public AAA() {System.out.println("AAA 构造器调用");}
    public int fun1(){System.out.println("父类普通成员属性显示初始化"); return 1;}
    public static int fun2(){System.out.println("父类静态成员属性显示初始化"); return 1;}
}

class BBB extends AAA{
    private int n = fun1();
    private static int sn = fun2();
    static {System.out.println("BBB的静态代码块的调用~");};
    {System.out.println("BBB的普通代码块的调用~");};
    //隐藏了
    //super()
    //普通代码块调用
    public BBB() {System.out.println("BBB 构造器调用");}
    public int fun1(){System.out.println("子类普通成员属性显示初始化"); return 1;}
    public static int fun2(){System.out.println("子类静态成员属性显示初始化"); return 1;}
}

输出如下:

分析:

第一句:首先创建B类对象,由于继承会先加载父类,所以调用父类的静态成员,根据定义顺序,调用fun2().

注意:子类重写了父类的fun2(),但是子类的方法没有加载,所以调用的还是父类的fun2()

第二句:调用父类中的静态代码块

第三句:根据定义顺序,先调用子类静态属性的初始化

第四句:调用子类中的静态代码块

第五句:其实子类中的构造器前隐藏了两条语句:super() 和 自己普通代码块的调用。所以先执行了super()。父类的构造器同理也隐藏了。由于父类属性在普通代码块前,所以先调用父类属性的初始化,但是因为父类子类都已经加载完毕,此时发生运行类型是B类,所以执行子类中的重写方法

第六句:执行父类普通代码块

第七句:输出父类构造器本生的语句,至此父类结束

第八、九、十句同理。

总结:调用顺序

  1. 父类静态代码块和静态属性

  1. 子类静态代码块和静态属性

  1. 父类普通代码块和普通属性

  1. 父类构造器

  1. 子类普通代码块和普通属性

  1. 子类构造器

三、final

3.1基本介绍

final可以修饰类、属性。方法

  1. final修饰类,此类不能被继承

  1. final修饰父类中方法,此方法不能被子类重写

  1. final修饰变量,此时就变为了常量,不能被修改了

3.2注意事项

final修饰的属性得初始化赋值,以后不能修改(变常量了)

1)赋值位置:

对于非静态属性:1. 定义时

2.代码块

3.构造器

对于静态属性:1定义时

2.静态代码块

说明:因为静态属性在类加载时就会初始化,且只执行一次,如果在构造器中赋值,就会存在创建对象时就赋值,所以不能再构造器中。

2)fianl不能修饰构造器

3)fianl和static搭配,效率会更高,不会导致类加载,编译器做了优化处理

public class Test01 {
    public static void main(String[] args) {
        System.out.println(A.n1);
    }
}

class A{

//    public final static int n1 = set();
    public final static int n1 = 100;
    static {
        System.out.println("hello");
    }

    public static int set(){
        System.out.println("111");
        return 10;
    }
}

只会输出n1的值

四、最后

本人是java小白,如有问题,欢迎指出。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值