[Java笔记7] 面向对象2(静态关键字static)

目录

static修饰成员变量

静态成员变量和实例成员变量

static修饰成员变量的内存原理

static修饰成员方法

静态成员方法和实例成员方法

static修饰成员方法的内存原理

工具类

代码块

代码块分类

静态代码块作用

单例设计模式

饿汉单例设计模式

懒汉单例设计模式

饿汉单例和懒汉单例比较


视频教程传送门 -> https://www.bilibili.com/video/BV1Cv411372m?p=97

static修饰成员变量

static修饰成员变量表示该成员变量只在内存中只存储一份,可以被共享访问、修改。

例如在线人数、观看人数这类变量适合定义为静态成员变量

静态成员变量和实例成员变量

成员变量类别 特点 访问方式 使用场景
静态成员变量 有static修饰,属于类、加载一次,可以被共享访问 类名.静态成员变量 (推荐)
对象.静态成员变量
表示在线人数等需要被共享的信息
实例成员变量 无static修饰,属于对象 对象.实例成员变量 属于每个对象,且每个对象信息不同时(name,age,…等)

static修饰成员变量的内存原理

static修饰成员方法

静态成员方法和实例成员方法

成员方法类别 特点 访问方式 使用场景
静态成员方法 有static修饰,属于类和对象共享 类名.静态成员方法(推荐)
对象.静态成员方法
以执行一个通用功能为目的,或者需要方便访问的方法
实例成员方法 无static修饰,属于对象 对象.实例成员方法 表示对象自己的行为,且方法中需要访问实例成员

static修饰成员方法的内存原理

注意:

静态方法只能访问静态的成员,不可以直接访问实例成员(间接访问-> 静态方法中创建对象)。
实例方法可以访问静态的成员,也可以访问实例成员。
静态方法中是不可以出现this关键字的。

工具类

内部是一些静态方法,每个方法完成一个功能
一次编写,处处可用,提高代码的重用性

建议工具类的构造器私有化处理 => 不让创建对象,节约内存

【例】验证码工具类,登录、注册等功能均可使用

定义一个工具类 VerifyTool,私有构造器,类中有一个静态方法 createCode

无需创建实例对象,通过类名引用静态方法创建验证码即可

package com.test.d3_static_test;

import java.util.Random;

public class VerifyTool {
    /**
       私有构造器
     */
    private VerifyTool(){
    }

    /**
      静态方法
     */
    public static String createCode(int n){
        // 1、使用String开发一个验证码
        String chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        // 2、定义一个变量用于存储n位随机的字符作为验证码
        String code = "";
        // 3、循环
        Random r = new Random();
        for (int i = 0; i < n; i++) {
            int index = r.nextInt(chars.length());
            // 4、对应索引提取字符
            code += chars.charAt(index);
        }
        return code;
    }
}

一个登录的测试类可以通过工具类类名调用验证码静态方法

package com.test.d3_static_test;

public class Login {
    public static void main(String[] args) {
        // 验证码:
        System.out.println("验证码:" + VerifyTool.createCode(10));
    }
}

代码块

代码块定义在类中方法外。
在Java类下,使用 { } 括起来的代码被称为代码块 。

代码块分类

静态代码块: 
格式:static{}
特点:需要通过static关键字修饰,随着类的加载而加载,并且自动触发、只执行一次
使用场景:在类加载的时候做一些静态数据初始化的操作,以便后续使用。

构造代码块(了解,用的少):
格式:{}
特点:每次创建对象,调用构造器执行时,都会执行该代码块中的代码,并且在构造器执行前执行
使用场景:初始化实例资源。

静态代码块作用

在启动系统时对数据进行初始化

单例设计模式

可以保证系统中,一个类永远只能创建一个对象。
例如任务管理器对象只需要一个就可以(重复点击也只有一个),这样可以节省内存空间。

饿汉单例设计模式

在用类获取对象的时候,对象已经提前为你创建好了。

设计步骤:
定义一个类,把构造器私有。
定义一个静态变量存储一个对象。

【例】SingleInstanceHungry.java内容如下(私有化构造器 + 公开的静态变量)

package com.test.d6_singleinstance;

/**
    饿汉单例模式
 */

/** 
    1、定义一个单例类 
*/
public class SingleInstanceHungry {
    /**
       3.定义一个静态变量存储一个对象,加载一次,只有一份
     */
    // public static int onLineNumber = 21; 类比:与这个静态变量赋值是一样的格式
    public static SingleInstanceHungry instance = new SingleInstanceHungry();

    /**
        2、必须私有构造器:私有构造器对外不能被访问。
     */
    private SingleInstanceHungry(){
    System.out.println("创建了一个饿汉对象");
    }
}

执行测试类 Test.java

package com.test.d6_singleinstance;

public class Test {
    public static void main(String[] args) {
//        SingleInstanceHungry s1 = new SingleInstanceHungry(); 执行会报错,因为构造器是private
        //使用类的静态成员变量instance,“创建3个”对象,看看其地址是否一样(1个对象)
        SingleInstanceHungry s1 = SingleInstanceHungry.instance;
        SingleInstanceHungry s2 = SingleInstanceHungry.instance;
        SingleInstanceHungry s3 = SingleInstanceHungry.instance;
        System.out.println(s1);
        System.out.println(s2);
        System.out.println(s3);
        System.out.println(s1 == s2);
    }
}

观察输出可以发现,无论引用几次静态变量,创建几次对象,地址都是同一个

懒汉单例设计模式

在真正需要该对象的时候,才去创建一个对象(延迟加载对象)。

设计步骤:
定义一个类,把构造器私有。
定义一个静态变量存储一个对象。
提供一个返回单例对象的方法。

【例】SingleInstanceLazy.java内容如下(私有化构造器 + 私有的静态变量 + 公开的静态方法)

package com.test.d6_singleinstance;

/**
    懒汉单例模式
 */
/** 
    1、定义一个单例类 
*/
public class SingleInstanceLazy {
    /**
       3、定义一个静态的成员变量存储一个对象,一开始不要初始化对象,因为人家是懒汉
     */
    private static SingleInstanceLazy instance;

    /**
       2、私有化构造器
     */
    private SingleInstanceLazy(){
    }

    /**
      4、提供一个方法暴露,真正调用这个方法的时候才创建一个单例对象
     */
    public static SingleInstanceLazy getInstance(){
        if(instance == null){
            // 第一次来拿对象,新建一个对象
            instance = new SingleInstanceLazy();
        }
        return instance;
    }
}

执行测试类 Test.java

package com.test.d6_singleinstance;

public class Test2 {
    public static void main(String[] args) {
        SingleInstanceLazy s1 = SingleInstanceLazy.getInstance();
        SingleInstanceLazy s2 = SingleInstanceLazy.getInstance();

        System.out.println(s1 == s2);
    }
}

输出为true,即地址是相同的

饿汉单例和懒汉单例比较

优缺点:饿汉单例取对象快,懒汉单例节约内存

共同点:都要把构造器私有 -> 不让外部创建对象(合理隐藏)

              都定义了一个单例类型的静态成员变量 -> 随着类只加载一次,保证最多一个实例对象

不同点:饿汉单例定义单例类型的静态变量时就初始化(外部需要访问,public),类一加载即创建对象; 懒汉单例定义单例类型的静态变量不初始化(外部无需访问,可私有化),后续通过公开的静态方法判断单例是否存在,首次访问则创建对象、否则返回静态变量指向的对象

猜你喜欢

转载自blog.csdn.net/wy_hhxx/article/details/121418963