Java拾贝第五天——静态和代码块

发布时间 2023-10-18 17:49:57作者: ocraft

Java拾贝不建议作为0基础学习,都是本人想到什么写什么

在Java中主要存在4块内存区域。
栈内存空间:保存所有变量(更准确的说是保存了指向堆内存空间的地址)
堆内存空间:保存每个对象的具体属性内容
全局数据区:保存static类型的属性
全局代码区:保存所有方法定义

static关键字

一个类实例化时会开辟栈内存、堆内存。

栈内存中存放其变量,堆内存中存放对象的属性。每个对象都有自己的属性。

静态属性

如果现在有某属性希望被所有对象共享,那么可以称其为静态(static)属性。也叫全局属性

为举栗子不封装。

public class test5 {
    public static void main(String args[]) {
        Work work1 = new Work("A",22,"SY");
        Work work2 = new Work("B",26,"SY");
        work1.Info();
        work2.Info();
    }
}

class Work {
    String name;
    int age;
    String cityName;

    public Work(String name, int age, String cityName) {
        this.name = name;
        this.age = age;
        this.cityName = cityName;
    }
    public void Info(){
        System.out.println(this.name+this.age+this.cityName);
    }
}

现有两名SY城的工作者想一起跳槽去TT城,该如何执行代码

    public static void main(String args[]) {
        Work work1 = new Work("A",22,"SY");
        Work work2 = new Work("B",26,"SY");
        work1.Info();
        work2.Info();
        work1.setCityName("TT");
        work2.setCityName("TT");
        System.out.println("跳槽后");
        work1.Info();
        work2.Info();
    }
/*
A22SY
B26SY
跳槽后
A22TT
B26TT
*/

可以看到确实成功抵达TT城,但如果不止AB两个实例呢?

这时可以使用static,使其被所有对象共享,达成一改全改。

public class test5 {
    public static void main(String args[]) {
        Work work1 = new Work("A", 22);
        Work work2 = new Work("B", 26);
        work1.Info();
        work2.Info();
        Work.cityName="TT";
        System.out.println("跳槽后");
        work1.Info();
        work2.Info();
    }
}

class Work {
    String name;
    int age;
    static String cityName="SY";

    public Work(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public void Info() {
        System.out.println(this.name + this.age + this.cityName);
    }
}
/*
A22SY
B26SY
跳槽后
A22TT
B26TT
*/

因为cityName被static修饰后被所拥有,不再局限于某个实例。

可以由类直接调用

//类名.静态属性
Work.cityName="TT";

静态方法

相应的,有静态属性就有静态方法。也叫类方法

静态方法和静态属性相同可以由类直接调用。

类名.方法();

继续使用上述的栗子,但把属性进行封装。

public class test5 {
    public static void main(String args[]) {
        Work work1 = new Work("A", 22);
        Work work2 = new Work("B", 26);
        Work.cityName = "TT";//报错,封装后不能直接访问属性
        System.out.println("跳槽后");
        work1.Info();
        work2.Info();
    }
}

class Work {
    private String name;
    private int age;
    private static String cityName="SY";

    public Work(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public void Info() {
        System.out.println(this.name + this.age + this.cityName);
    }


    public static String getCityName() {
        return cityName;
    }

    public static void setCityName(String cityName) {
        Work.cityName = cityName;
    }
	//其他getter和setter
}

修改代码:

Work.cityName = "TT";
?
Work.setCityName("TT");
    public static void main(String args[]) {
        Work work1 = new Work("A", 22);
        Work work2 = new Work("B", 26);
        Work.cityName = "TT";//报错,封装后不能直接访问属性
        System.out.println("跳槽后");
        work1.Info();
        work2.Info();
    }
/*
跳槽后
A22TT
B26TT
*/

但getter和setter方法为什么也要用static修饰呢?

至此提出静态方法遵循的规则:

  • 非static方法可以去调用static属性或方法
  • static方法不能调用非static属性或方法

非static方法可以去调用static属性或方法

public class test5 {
    public static void main(String args[]) {
        Work w = new Work();
        w.say();
    }
}

class Work {
    private String name;
    private static String cityName = "SY";

    public Work() {
    }

    public Work(String name) {
        this.name = name;
    }

    public void say() {
        tell();
        cityName="TT";
        System.out.println(Work.cityName);
        System.out.println("这是普通方法say");
    }

    public static void tell() {
        System.out.println("这是静态方法tell");
    }
/*
这是静态方法tell
TT
这是普通方法say
*/

static方法不能调用非static属性或方法

还是上述的栗子,修改一下tell方法

class Work {
    private String name;
    private static String cityName = "SY";

    public Work() {
    }

    public Work(String name) {
        this.name = name;
    }

    public void say() {
        System.out.println("这是普通方法say");
    }

    public static void tell() {
        System.out.println("这是静态方法tell");
        this.say();
        this.name="TT";
    }
}
//直接编译错误了,连运行都不能运行

其实也不难理解:

因为普通的属性和方法需要对象开辟堆内存空间之后才可以使用。

而static类型的方法不存放于堆内存中,它在内存中有独立的空间。

假设堆内存都还没有开辟完,静态方法怎么找到这个方法去调用呢?

通过实例也可也访问静态方法或静态变量,但编译器会运行过程中自动修改为类名。

接口的静态属性

在接口提到过,接口是不允许存在属性的。

但可以存在静态属性,并且静态属性必须为final。

interface Sex{
    public static final int Men=1;
    public static final int WoMen=2;
}

就像方法一样,接口中的方法默认为public abstract。

属性默认为public static final。

至此:

interface Sex{
     int Men=1;
     int WoMen=2;
}

代码块

所谓代码块指的是{}包括的内容,根据位置及关键字不同可以分为

  1. 普通代码块
  2. 构造代码块
  3. 静态代码块
  4. 同步代码块

普通代码块

普通代码块就是直接在方法中或语句中定义的代码块。

public class test5 {
    public static void main(String args[]) {
        {//直接定义在方法中的代码块,main方法当然也是方法
            int i = 1;//局部变量
            System.out.println("普通代码块:"+i);
        }
        int i = 2;
        System.out.println("代码块之外:"+i);
    }
}
/*
普通代码块:1
代码块之外:2
*/

构造代码块

构造代码块就是直接写在类中的代码块。

public class test5 {

    public static void main(String args[]) {
        new T5();
        new T5();
        new T5();
    }
}
class T5 {
    {
        //初始化本类时会调用构造代码块
        System.out.println("构造代码块被调用");
    }
    public T5() {
        System.out.println("构造方法被调用");
    }
}
/*
构造代码块被调用
构造方法被调用
构造代码块被调用
构造方法被调用
构造代码块被调用
构造方法被调用
*/

构造代码块优先于构造方法,并且每次实例化对象都会执行构造代码块,会执行多次。

静态代码块

静态代码块就是使用static修饰的代码块

public class test5 {

    public static void main(String args[]) {
        new T5();
        new T5();
        new T5();
    }

}

class T5 {
    static {//静态代码块
        System.out.println("静态代码块被调用");
    }

    {//构造代码块

        System.out.println("构造代码块被调用");
    }

    public T5() {
        System.out.println("构造方法被调用");
    }
}
/*
静态代码块被调用
构造代码块被调用
构造方法被调用
构造代码块被调用
构造方法被调用
构造代码块被调用
构造方法被调用
*/

静态代码块优先与构造代码块,并且会执行一次。

同步代码块

多线程内容。

代码块执行顺序

同步代码块不在内

public class test5 {

    public static void main(String args[]) {
        new T5();
    }

}

class T5 {
    static {//静态代码块
        System.out.println("静态代码块被调用");
    }

    {//构造代码块

        System.out.println("构造代码块被调用");
    }

    public T5() {
        {//普通代码块
            System.out.println("普通代码块被调用");
        }
        System.out.println("构造方法被调用");
    }
}
/*
静态代码块被调用
构造代码块被调用
普通代码块被调用
构造方法被调用
*/

至此,代码块优先级如下:

  1. 静态代码块
  2. 构造代码块
  3. 普通代码块