存亡安危网

18、Java的类变量、类方法;static 关键字;静态导入;初始化块;静态初始化块;单例模式

18、Java的类变量、类方法;static 关键字;静态导入;初始化块;静态初始化块;单例模式

文章目录

  • 一、类导入单例static
    • (1) static 修饰成员变量
    • (2) static 修饰成员方法
  • 二、变量静态导入
    • (1) 静态导入概念
    • (2) 静态导入使用场景
  • 三、类方如何给实例变量设置初始值
  • 四、键字静态静态如何给类变量设置初始值
  • 五、初始初始继承中出现(静态)初始化块 ☆
  • 六、化块化块单例模式

一、模式static

☘️ static可用来修饰类的类导入单例成员:成员变量、方法、变量嵌套类

public class Person {     /* static 可以修饰成员变量 */    private static int age;    /* static 可以修饰成员方法 */    public static void eat() {     }    /* static 可以修饰嵌套类 */    static class Head {     }}

(1) static 修饰成员变量

☘️ 被static修饰的类方成员变量可叫做:类变量、静态变量、键字静态静态静态字段
☘️ 类变量在程序运行过程中只占用一份固定的初始初始内存(存储在方法区
☘️ 可通过类名访问
☘️ 可通过引用变量名访问(不推荐)

类名或引用变量名访问静态变量:

public class VisitStaticField {     public static void main(String[] args) {         /* 通过类名访问静态变量 */        // Book.bookNum = 1        System.out.println("Book.bookNum = " + Book.bookNum);        Book.bookNum = 11;        /* 通过引用变量名访问静态变量 */        // book 是引用变量名        Book book = new Book();        // book.bookNum = 11        System.out.println("book.bookNum = " + book.bookNum);    }}class Book {     /* bookNum 是一个静态变量 (类变量) */    public static int bookNum = 1;}

统计 Person 对象的个数:

public class CountPersonObjectNum {     public static void main(String[] args) {         Person p = new Person();        Person pp = new Person();        Person ppp = new Person();        Person pppp = new Person();        Person ppppp = new Person();        Person pppppp = new Person();        Person ppppppp = new Person();                // 当前 Person 对象个数:7        System.out.println("当前 Person 对象个数:" + Person.personObjNum);    }}class Person {     /* personObjNum 记录 Person 对象的个数 */    public static int personObjNum = 0;    public Person() {         personObjNum++;    }}

☘️ 没有被static修饰的成员变量可叫做:实例变量
☘️ 实例变量在每个实例内部都有一份内存(存储在空间)
☘️ 只能通过引用变量名访问


(2) static 修饰成员方法

☘️ 被 static修饰的成员方法可叫做:类方法、静态方法
☘️ 类方法可通过类名调用
☘️ 类方法可通过引用变量名调用
通过类名或对象名调用类方法:

public class TestDemo {     public static void main(String[] args) {         /* 通过类名调用类方法 */        String randStr1 = GqUtil.obtainRandomStr();        /* 通过引用变量名(对象名)访问类方法(不推荐) */        GqUtil util = new GqUtil();        String randStr2 = util.obtainRandomStr();        // randStr1 = 2185dffafc244193a9c056db2cf7ba93        System.out.println("randStr1 = " + randStr1);        // randStr2 = 9beb2ecd2a4842f18692b33354508c16        System.out.println("randStr2 = " + randStr2);    }}class GqUtil {     /**     * 被 static 修饰的化块化块方法叫做类方法(或静态方法)     * 作用:返回随机字符串     */    public static String obtainRandomStr() {         return UUID.randomUUID().toString().replace("-", "");    }}

☘️ 类方法内部坚决不能使用this

✏️ this
① 与实例挂钩
② 是一个隐藏的、位置最靠前的模式方法参数
③ 是当前对象(实例)的引用
④ 类变量、类方法可通过类名访问或调用,类导入单例与实例没有瓜葛

☘️ 类方法中可直接访问类变量和调用其他类方法
☘️ 类方法中不可以直接访问实例变量,不可以直接调用实例方法

public class TestDemo {     public static void main(String[] args) {         /* 通过类名调用类方法 */        String randStr1 = GqUtil.getRandString();        /* 通过引用变量名(对象名)访问类方法(不推荐) */        GqUtil util = new GqUtil();        String randStr2 = util.getRandString();        System.out.println("randStr1 = " + randStr1);        System.out.println("randStr2 = " + randStr2);    }}class GqUtil {     /* 一个类变量 */    public static int count = 6;    public String name = "庆医";    /* 类方法 */    public static String getRandString() {         // 类方法中可直接访问类变量        System.out.println("count = " + count);        /*            类方法中不能直接访问实例变量 name,            需创建 GqUtil 的对象, 然后通过对象名访问 name            类方法中不能直接调用实例方法 test2            需创建 GqUtil 的对象, 然后通过对象名调用 test2         */        GqUtil util = new GqUtil();        System.out.println("name = " + util.name);        util.test2();        // 类方法中可调用其他类方法        test1();        return UUID.randomUUID().toString().replace("-", "");    }    /* 类方法 */    public static void test1() {         System.out.println("类方法 test1()");    }    /* 实例方法 */    public void test2() {         System.out.println("实例方法 test2()");    }}

☘️ 没有被static修饰的方法叫做实例方法(只能通过对象名去调用)
☘️ 只能通过对象名去调用
☘️ 内部可以使用this
☘️ 可直接访问实例变量、实例方法
☘️ 可直接访问或调用类变量、类方法(类变量、类方法可通过对象名进行访问或调用)

二、静态导入

(1) 静态导入概念

☘️ 使用了静态导入后,就可以省略类名访问静态成员(成员变量、方法、嵌套类)

public class TestClass {     public static int age = 1;    public static void show() {         System.out.println("age is " + age);    }    public static class Other {         public void other() {             System.out.println("Other_other()");        }    }}
public class TestDemo {     public static void main(String[] args) {         // 1        System.out.println(TestClass.age);        // age is 1        TestClass.show();        TestClass.Other other = new TestClass.Other();        // Other_other()        other.other();    }}

静态导入后访问静态成员:

import static com.gq.TestClass.*; // 静态导入public class TestDemo {     public static void main(String[] args) {         // 1        System.out.println(age);        // age is 1        show();        Other other = new Other();        // Other_other()        other.other();    }}

(2) 静态导入使用场景

import static java.lang.Math.PI;public class TestDemo {     public static void main(String[] args) {         // 62.83185307179586        System.out.println(2 * PI * 10);        // 125.66370614359172        System.out.println(2 * PI * 20);    }}

三、如何给实例变量设置初始值

☘️ 声明的时候就赋值
☘️ 构造方法的时候赋值
☘️ 在初始化代码块中赋值

✏️ 编译器会将初始化代码块中的代码复制到每个构造方法的头部(每创建一个对象就会执行一次初始化代码块中的代码)
✏️ 先执行初始化代码块中的代码,后执行构造方法中的代码

public class TestDemo {     public static void main(String[] args) {         Person person = new Person("庆医");        // age = 17        System.out.println("age = " + person.age);        // name = 庆医        System.out.println("name = " + person.name);        // money = 67899.99        System.out.println("money = " + person.money);        // address = 日本神奈川县川崎市        System.out.println("address = " + person.address);    }}class Person {     /* 声明 age 属性的时候就给 age 赋值 */    public int age = 17;    public String name;    public double money;    public String address;    public Person(String name) {         /* 在构造方法中给 name 属性赋值 */        this.name = name;    }    /* 在初始化代码块中给 money 和 address 属性赋值 */ {         money = 67899.99;        address = "日本神奈川县川崎市";    }}

先执行初始化代码块中的代码,后执行构造方法中的代码
看下面代码,思考打印结果是什么:

public class TestDemo {     public static void main(String[] args) {         Person p = new Person(11, "庆医", 10000);        System.out.println("age = " + p.age); // age = 12        System.out.println("name = " + p.name); // name = 庆医        System.out.println("money = " + p.money); // money = 15000.0    }}class Person {     public int age;    public String name;    public double money;    public Person(int age, String name, double money) {         this.name = name;        this.age = age + this.age;        this.money = money + this.money;    }    /* 每次创建 Person 对象都会调用初始化代码块的代码 */    {         name = "张浩男";        age = 1;        money = 5000;    }}

四、如何给类变量设置初始值

☘️ 声明的时候就赋值
☘️ 在静态初始化(代码)块

✏️ 当一个类被初始化的时候会执行静态初始化块中的代码
✏️ 当一个类第一次被主动使用的时候,JVM 会对类进行初始化(当一个类第一次被主动使用的时候会执行静态初始化块中的代码)
✏️ 静态初始化块中的代码只会被执行一次

public class TestDemo {     public static void main(String[] args) {         new Person();        new Person(12898);    }}class Person {     /* 静态初始化块(作用:为类变量赋初始值) */    static {         System.out.println("\n静态初始化块中的代码在类第一次被使用的时候会被执行一次(只执行一次)");    }    /* 初始化块(为实例变量赋初始值) */     {         System.out.println("初始化块中的代码会被复制到每个构造方法的头部, 每次创建对象都会执行一次初始化块中的代码");    }    public Person() {     }    public Person(int money) {     }}

在这里插入图片描述

☘️ 初始化块和静态初始化块都可以有多个(按照它们在源码中出现的顺序依次执行)

五、继承中出现(静态)初始化块 ☆

public class TestDemo {     public static void main(String[] args) {         new Student();        /*            Person_静态初始化块            Student_静态初始化块             Person_初始化块            Person_Person()            Student_初始化块            Student_Person()         */    }}class Person {     // 静态初始化块, 当类第一次被使用的时候会执行一次静态初始化块里面的代码    static {         System.out.println("Person_静态初始化块");    }    // 初始化块, 初始化块里面的代码会被拷贝到每个构造方法的头部    // 每次创建 Person 对象的时候都会执行一次初始化块里面的代码    {         System.out.println("Person_初始化块");    }    public Person() {         System.out.println("Person_Person()");    }}class Student extends Person {     // 静态初始化块, 当类第一次被使用的时候会执行一次静态初始化块里面的代码    static {         System.out.println("Student_静态初始化块");    }    // 初始化块, 初始化块里面的代码会被拷贝到每个构造方法的头部    // 每次创建 Student 对象的时候都会执行一次初始化块里面的代码    {         System.out.println("Student_初始化块");    }    public Student() {         System.out.println("Student_Person()");    }}

六、单例模式

☘️ Singleton Pattern:如果一个类被设计成单例设计模式,则在整个应用程序运行过程中,该类只能存在一个实例。
饿汉式:

class Rocket {  /* 饿汉式 */    private static Rocket instance = new Rocket();    // 构造方法私有化    private Rocket() {     }    /**     * 返回唯一的 Rocket 实例     */    public static Rocket getInstance() {         return instance;    }}

懒汉式:

class Rocket {  /* 懒汉式: 有线程安全问题 */    private static Rocket instance = null;    // 构造方法私有化    private Rocket() {     }    /**     * 返回唯一的 Rocket 实例     */    public static Rocket getInstance() {         if (instance == null)            instance = new Rocket();        return instance;    }}

再见!如有错误,请不吝赐教!

未经允许不得转载:存亡安危网 » 18、Java的类变量、类方法;static 关键字;静态导入;初始化块;静态初始化块;单例模式