深入了解static关键字的作用和应用--java面向对象学习

Static修饰成员变量

Static是什么

  • 叫静态,可以修饰成员变量,成员方法

成员变量按有无static修饰分俩种:

  • 类变量:有static修饰,属于类,在计算机里只有一份,会被类的全部对象共享
  • 实例变量(对象的变量):无static修饰,属于每个对象的

类变量为所有对象共享,类变量的生命周期同类一样,而每个对象都有独属于自己的示例变量,实例变量的生命周期同对应实例一样,公家的和自家的区别

访问类变量的方式:

  • 类名.类变量(推荐,高效,方便)

  • 对象.类变量(不推荐)

    ------通过类名访问相当于直接去方法区找到类和对应类方法,而通过对象访问是先找到对象再通过对象去找类,再找到对应类方法

代码演示:

  • 创建一个学生类:

    复制代码
    public class Student {
        static int grade;    //年级
        String name;    //姓名
    }
  • 创建俩个学生对象:

    复制代码
    public class StaticDemo1 {
        public static void main(String[] args) {
            Student s1 = new Student(); //定义学生对象1
            Student s2 = new Student(); //定义学生对象2
    
            Student.grade = 1;  //通过类名访问类变量,给类变量grade赋值
    //        s1.grade = 2; //也可以通过对象来访问类变量,不过不推荐这麽做
    
            s1.name = "小明"; //学生对象1实例变量赋值
            s2.name = "小红"; //学生对象2示例变量赋值
    
            System.out.println("我是" + Student.grade +"年级的" + s1.name);  //输出学生对象1和学生对象2的信息
            System.out.println("我是" + Student.grade +"年级的" + s2.name);
        }
    }

注:实例变量不能通过类名去访问

像这种访问方式是错误的,因为实例变量独属于每个对象,只通过类名怎么知道你是想访问哪个对象呢~

类变量的应用场景

  • 在开发中,如果某个数据只需要一份,且希望能够被共享(访问、修改),则该数据可以定义成类变量来记住

案例:

  • 有一个学生类,希望学生类可以自己记录已经创建过多少学生对象

    public class Student2 {
    public static int number; //记录已经创建多少个学生对象

    复制代码
      public Student2() {
          //在同一个类中,访问自己类的类变量可以不写类名,在别的类中需要写类名
          number++; //每次调用构造函数,都记录下来
      }

    }

    public class StaticDemo2 {
    public static void main(String[] args) {
    Student2 s1 = new Student2();
    Student2 s2 = new Student2();
    Student2 s3 = new Student2();

    复制代码
          System.out.println("我已经创建了" + Student2.number + "个学生对象啦");
      }

    }

运行结果:


Static修饰成员方法

成员方法按有无Static修饰分俩种

  • 类方法:有Static修饰的成员方法,属于类
  • 实例方法:无Static修饰的成员方法,属于对象

类方法不可以访问实例方法和实例变量,但是实例方法可以访问类方法和类变量

访问类方法的方式:

  • 类名.类方法(推荐,高效,方便)
  • 对象.类方法(不推荐)

代码演示:

  • 对象

    复制代码
    public class Student3 {
        double score;   //分数
    
        public static void HelloWorld(){    //Static修饰的成员方法------类方法
            System.out.println("HelloWorld!");
        }
    
        public void Pass(){     //没用Static修饰的成员方法------实例方法
            System.out.println(this.score >= 60? "及格" : "不及格");
        }
    }
  • 访问

    复制代码
    public class StaticDemo3 {
        public static void main(String[] args) {
    
            //通过类名访问实例方法,推荐
            Student3.HelloWorld();
    
            //通过对象访问实例方法.不推荐
            Student3 s = new Student3();
            s.HelloWorld();
    
            //通过类名访问实例方法,报错
    //        Student3.Pass();
        }
    }

    注:同实例对象一样实例方法也不能通过类名去访问

小知识:

其实main方法就是一个类方法,当我们用java命令执行程序的时候,虚拟机会用当前类直接.main()方法,也就是说 java test == test.main(), 那么main方法括号里的字符串数组是干什么的呢?:,这个数组实际上是用来接收数据的,并且我们也可以去使用这个数组里的数据(如果有的话),我们可以在控制台执行class文件的时候传入一些参数给main方法使用,比如现在有这麽一串代码:

复制代码
public class Test {
    public static void main(String[] args) {
        for (String arg : args) {
            System.out.println(arg);
        }
    }
}

在控制台编译执行并传入数据给它:

类方法的常见应用场景

  • 类方法最常见的应用场景是设计工具类

工具类是什么

  • 用来完成某一个功能的,用来给开发人员共同使用的类方法

使用类方法设计工具类有什么好处

  • 提高了代码复用,调用方便,提高了开发效率

**如果需要一个类只存一些需要重复使用的方法,那么就可以创造一个专门提供这些方法的工具类,在类里面创造需要的类方法,需要使用该方法的时候直接类名.类方法就可以很方便的使用了。**例如有多个类都需要创建指定位数验证码时,就可以 创建一个工具类专门存放生成随机验证码方法以供调用:

案例:

假设现在有一个方法1需要创建一个四位验证码,另一个方法2需要创建一个六位验证码,为了提高代码复用,减少重复代码,我们就可以专门为创建验证码这个方法设计一个方法类,放在工具类中以供调用:

方法1代码:

复制代码
public class Demo1 {
    //需要创建四位验证码
    public void CreateCode(){
        System.out.println(MyUtil.CreateCode(4));
    }
}

方法2代码:

复制代码
public class Demo2 {
    //需要创建六位验证码
    public void CreateCode(){
        System.out.println(MyUtil.CreateCode(6));
    }
}

工具类代码:

复制代码
import java.util.Random;

public class MyUtil {   //专门存放需要重复使用的方法的工具类
    public static String CreateCode(int digit) {   //验证码随机生成方法,作为类方法提高复用性
        Random r = new Random();
        String numbers = "1234567890abcdefghijklmnopqistuvwxyzABCDEFGHIJKLMNOPQISTUVWXYZ";  //字符池
        StringBuilder code = new StringBuilder();

        while(digit-- != 0){    //传入的形参控制位数
                code.append(numbers.charAt(r.nextInt(0, 63)));
        }

        return code.toString();
    }
}

测试:

复制代码
public class Test {
    public static void main(String[] args) {
        Demo1 d1 = new Demo1();
        Demo2 d2 = new Demo2();

        d1.CreateCode();
        d2.CreateCode();
    }
}

运行结果:

小知识:

  • 为什么工具类中的方法要用类方法不用实例方法?
  • 用实例方法当然也是可行的,但是作为实例方法必须使用对象调用,必须先创建类对象才能调用相关实例方法,而此时对象只是为了调用方法,浪费内存,不如直接使用类方法
  • 因为工具类只是为了提供类方法而存在,不需要创建对象,所以其实可以将工具类的构造方法私有:

使用类方法、实例方法时的几点注意事项

  • 类方法中可以直接访问类变量,不可以直接访问实例变量
  • 实例方法中既可以直接访问类成员,也可以直接访问实例成员
  • 实例方法中可以出现this关键字,类方法中不可以出现this关键字

Static修饰代码块

代码块是什么

  • 代码块是类的五大成分之一(成员变量、构造器、方法、代码块、内部类)

代码块按有无Static修饰分俩种:

  • 静态代码块
    -->格式:static{ ... }
    -->特点:类加载时自动执行,由于类只会加载一次,所以静态代码块也只会执行一次
    -->作用:完成类的初始化,例如:对类变量的初始化赋值
  • 实例代码块
    -->格式:{ ... }
    -->特点:每次创建对象时,执行实例代码块,并在构造器前执行
    -->作用:和构造器一样,都是用来完成对象的初始化,例如对示例变量进行初始化赋值

代码演示:

静态代码块:

复制代码
public class Block {
    static int age = 18;    //类变量

    static{ //静态代码块,只会在类加载时执行一次
        System.out.println("静态代码块被执行");
    }
}

测试:

复制代码
public class Test {
    public static void main(String[] args) {
        System.out.println(Block.age);  //访问Block类的类变量,会先加载Block类
        System.out.println(Block.age);  //访问三次
        System.out.println(Block.age);
    }
}

结果:

虽然访问了三次类变量,但是静态代码块只在第一次访问加载时执行了一次

实例代码块:

复制代码
public class Block {
    String name;    //实例变量

    { //实例代码块,每次创建对象在构造器前执行一次
        System.out.println("实例代码块执行");
    }

    public Block() {
        System.out.println("无参构造器执行");
    }

    public Block(String name) {
        System.out.println("有参构造器执行");
    }
}

测试:

复制代码
public class Test {
    public static void main(String[] args) {
       Block b1 = new Block();  //创建对象并调用无参构造器
       Block b2 = new Block("小明");  //创建对象并调用有参构造器
    }
}

结果:

每次创建对象时,都会在调用构造器之前执行一次实例代码块

虽然实例代码块可以给示例变量赋初值,但是意义不大,因为实例代码块不能传参,所有赋初值的实例变量都是一个值,所以一般不会去使用实例代码块给实例变量赋初值,但是可以用实例代码块记录日志之类的,比如每次有人创建对象,就可以在实例代码块记录一下


Static应用:单例设计模式

设计模式是什么

  • 一个问题通常有n种解法,其中肯定有一种解法时最优的,这个最优的解法就是设计模式
  • 设计模式总共有23种,对应各种软件开发种会遇到的问题

单例设计模式

  • 确保一个类只有一个对象
  • 把类的构造器私有
  • 定义一个类变量记住类的一个对象
  • 定义一个类方法返回对象

代码演示:

单例设计模式设计一个类:

复制代码
public class SingleCase {

    private static SingleCase s = new SingleCase(); //2、定义一个类变量记住一个类对象

    private SingleCase(){}  //1、私有类的构造器

    public static SingleCase getObject(){   //定义一个类方法返回类对象
        return s;
    }
}

测试:

复制代码
public class Test {
    public static void main(String[] args) {
//       SingleCase s = new SingleCase();   无法再通过原来的方法创建该类对象

        SingleCase s1 = SingleCase.getObject();  //但是可以通过类方法调用类变量返回一个对象
        SingleCase s2 = SingleCase.getObject();  //因为类变量只会在类加载的时候创建一次,所以通过这种方法创建的类对象都是同一个

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

运行结果:

俩个类对象的地址都是一样的,说明它们引用的是同一个对象

单例设计模式的应用

这是官方提供的Runtime类,可以看到它就是使用的单例设计模式来设计的

比如说我们常用到的任务管理器就是单例设计模式,不管启动多少次任务管理器,它都只会打开那一个任务管理器。在只需要一个对象即可解决问题时,就可以使用单例设计模式来设计,即可以避免内存浪费

小知识:

单例设计模式不止一种:

像刚才代码演示的单例设计模式只是其中一种,称为饿汉式单例设计模式,除此之外还有懒汉式单例模式、双检索等等.......

相关推荐
考虑考虑17 小时前
Jpa使用union all
java·spring boot·后端
用户37215742613517 小时前
Java 实现 Excel 与 TXT 文本高效互转
java
浮游本尊18 小时前
Java学习第22天 - 云原生与容器化
java
渣哥20 小时前
原来 Java 里线程安全集合有这么多种
java
间彧20 小时前
Spring Boot集成Spring Security完整指南
java
间彧20 小时前
Spring Secutiy基本原理及工作流程
java
Java水解21 小时前
JAVA经典面试题附答案(持续更新版)
java·后端·面试
洛小豆1 天前
在Java中,Integer.parseInt和Integer.valueOf有什么区别
java·后端·面试
前端小张同学1 天前
服务器上如何搭建jenkins 服务CI/CD😎😎
java·后端
ytadpole1 天前
Spring Cloud Gateway:一次不规范 URL 引发的路由转发404问题排查
java·后端