Static关键字详解(静态成员变量,静态方法,代码块,静态代码块,单例模式)

Static关键字详解(静态成员变量,静态方法,代码块,静态代码块,单例模式)

1.Static

解释什么是static关键字,并举例至少三种用法

  • 创建静态变量

        static int count;
    
  • 创建静态方法

        static void printMessage() {
            System.out.println("Hello, World!");
        }
    
  • 创建静态块

        static {
            System.out.println("静态块被执行,用于初始化静态成员");
            count = 10; // 初始化静态变量
        }
    
2.静态成员变量

思考静态成员变量和非静态成员变量的区别

  1. 存储位置:

    • 静态成员变量存储在方法区的静态存储区域。
    • 非静态成员变量存储在堆空间中,每个对象实例的副本都位于各自的内存空间。
  2. 生命周期:

    • 静态成员变量的生命周期从类加载开始,到类卸载结束。
    • 非静态成员变量的生命周期从对象创建开始,到对象垃圾回收结束。
  3. 出现顺序:

    • 静态成员变量在类加载时就已经分配内存和初始化。
    • 非静态成员变量在创建对象时分配内存和初始化。
  4. 调用方式:

    • 静态成员变量可以直接通过类名调用,不依赖于对象实例。
    • 非静态成员变量必须通过对象实例来调用。
  5. 初始化时机:

    • 静态成员变量在类加载时进行初始化,通常是在静态初始化块中或者声明时进行赋值。
    • 非静态成员变量在创建对象时进行初始化,通常是在构造方法中或者声明时进行赋值。
  6. 内存占用:

    • 静态成员变量因为是被所有对象共享的,所以只有一个副本,占用固定的内存空间。
    • 非静态成员变量每个对象都有自己的副本,因此创建的对象越多,占用的内存空间就越大。
  7. 共享:

    • 静态成员变量是所有对象实例共享的,无论创建多少个对象,都只有一个静态成员变量的副本。
    • 非静态成员变量每个对象实例都有自己的副本,各个对象之间的非静态成员变量互不影响。
3.静态方法

请简述static方法和非static方法有什么区别?什么情况下应该使用static方法

static方法和非static方法的主要区别如下:

  1. 所属对象:

    • static方法是属于类的,不依赖于任何实例对象,可以通过类名直接调用。
    • 非static方法是属于对象的,必须通过类的实例对象来调用。
  2. 调用方式:

    • static方法可以通过类名直接调用,例如 ClassName.methodName()
    • 非static方法必须通过类的实例对象调用,例如 objectName.methodName()
  3. 访问成员变量:

    • static方法只能直接访问static成员变量和static成员方法。
    • 非static方法可以访问static成员变量和成员变量,以及static成员方法和成员方法。
  4. 生命周期:

    • static方法在类加载时就存在,不依赖于对象的创建和销毁。
    • 非static方法的定义与对象的生命周期相关,随着对象的创建而存在,随着对象的销毁而消失。
  5. 创建对象:

    • 调用static方法不需要创建类的实例对象。
    • 调用非static方法通常需要先创建类的实例对象。

使用static方法的场景:

  • 工具类方法: 当你需要一个不需要访问任何实例成员的方法时,比如数学计算、日期处理等工具类方法,使用static方法很合适。
  • 静态工厂方法: 当你需要一个用于创建类实例的方法,而这个方法不需要访问任何特定的实例数据时,可以使用静态工厂方法。
  • 代码组织: 当你想要组织代码,使得它不依赖于任何实例状态时,可以将相关方法定义为static。
  • 性能考虑: 如果方法调用非常频繁,并且不依赖于对象状态,使用static方法可以避免创建不必要的对象实例,从而提高性能。
4.代码块
匿名代码块

匿名代码块是没有名字的代码块,通常出现在类体内部,不与任何方法或构造器关联。其作用如下:

  1. 初始化实例成员变量: 匿名代码块通常用于初始化类的实例成员变量,它会在每次创建类的实例对象时执行。

  2. 执行实例初始化逻辑: 如果有一些逻辑需要在创建类的实例时执行,而这些逻辑又不适合放在构造器中,可以使用匿名代码块来完成。

  3. 代码块内的变量作用域: 匿名代码块中定义的变量只在代码块内部有效,不会影响到类中的其他成员变量。

示例:

public class MyClass {
    // 匿名代码块
    {
        // 初始化代码
    }
}
静态代码块

静态代码块是使用static关键字修饰的代码块,其作用如下:

  1. 初始化静态成员变量: 静态代码块通常用于初始化类的静态成员变量,它会在类加载时执行,且只执行一次。

  2. 执行静态初始化逻辑: 如果有一些逻辑需要在类加载时执行,而不是在创建实例时执行,可以使用静态代码块。

  3. 初始化顺序: 静态代码块在类加载时执行,优先于任何实例的初始化。如果有多个静态代码块,它们将按照它们在类定义中的顺序执行。

示例:

public class MyClass {
    // 静态代码块
    static {
        // 静态初始化代码
    }
}
5.继承static

在Java中,子类确实能够继承父类的static成员变量和方法。静态成员(包括静态变量和方法)属于类级别的成员,它们不是任何对象的实例的一部分,而是与类本身相关联。因此,当子类继承父类时,它会继承父类的所有静态成员。

6.程序分析

请阅读并分析以下三个案例中,程序启动运行的结果。

  • 案例1
class Test {
    public Test() {
        System.out.println("构造器");
    }
    
    public void info() {
        System.out.println("info");
    }

    static {
        System.out.println("test static 1");
    }

    public static void main(String[] args) {
        new Test().info();
    }

    {
        System.out.println("代码块");
    }

    static {
        System.out.println("test static 2");
    }
}
//当Test类被加载时先执行静态初始化代码块,因此先按顺序输出test static 1、test static 2。然后执行main方法,这时执行实例初始化代码块,输出“代码块”,之后用构造器来完成对象的创建,输出“构造器”,在最后调用info方法输出“info”
  • 案例2
class Parent {
    static {
        System.out.println("静态代码块Parent");
    }

    {
        System.out.println("构造代码块Parent");
    }

    public Parent() {
        System.out.println("构造方法Parent");
    }
}

class Child extends Parent {
    static {
        System.out.println("静态代码块Child");
    }

    {
        System.out.println("构造代码块Child");
    }

    public Child() {
        System.out.println("构造方法Child");
    }
}
//Child类继承Parent类,JVM先加载Parent类,加载过程按顺序执行静态代码块,输出“静态代码块Parent”,接着加载Child类,先执行静态代码块,输出“静态代码块Child”,当new Child()被调用时,先调用父类Parent的构造器,先构造代码块,输出“构造代码块Parent”,后“构造方法Parent”,最后使用子类Child的构造器,构造代码块,输出“构造代码块Child”,后“构造方法Child”
  • 案例3
class B {
    public static B b = new B();
    public static B b2 = new B();

    {
        System.out.println("构造块");
    }

    static {
        System.out.println("静态块");
    }
}

public class Test08 {
    public static void main(String[] args) {
        B b = new B();
    }
}
//调用new B()时,先初始化B类的静态变量b,执行初始化静态变量,输出“构造块”,接着初始化静态变量b2,输出“构造块”,然后执行静态初始化代码块,输出“静态块”,最后因为在main方法中执行了B b = new B(),所以会执行实例初始化代码块和构造方法,输出“构造块”。
7.单例模式

单例模式是一种设计模式,它确保一个类只有一个实例,并提供一个全局访问点来获取这个实例。这种模式通常用于管理共享资源,如数据库连接或线程池,因为这些资源只需要一个实例来避免资源的重复创建和浪费。

public class Singleton {
    // 静态变量,用于保存类的唯一实例
    private static Singleton instance;

    // 私有构造方法,防止外部直接创建实例
    private Singleton() {
        // 可以在这里添加一些初始化代码
    }

    // 静态方法,用于获取类的唯一实例
    public static Singleton getInstance() {
        if (instance == null) {
            // 如果实例尚未创建,则创建一个新的实例
            instance = new Singleton();
        }
        return instance;
    }

    // 其他方法,用于执行单例类的业务逻辑
    public void doSomething() {
        System.out.println("Doing something in the singleton instance.");
    }
}
8.次数统计

编写一个Java类,实现如下功能:

  • 该类能够自动记录被实例化的次数(即创建过该类多少对象)

  • 能够随时通过调用某个方法,获取到这个数值

public class Counter {
    private static int count = 0;

    public Counter() {
    	//创建实例时数量+1
        count++;
    }

    public static int getCount() {
        return count;
    }

    public static void main(String[] args) {
        System.out.println("未创建实例时的实例数量: " + getCount()); // 输出:0

        Counter c1 = new Counter();
        Counter c2 = new Counter();
        Counter c3 = new Counter();

        System.out.println("三次创建实例后的实例数量: " + getCount()); // 输出:3
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值