详解java中的static关键字

 更新时间:2020年06月19日 10:13:42   作者:杨冠标  
这篇文章主要介绍了java中的static关键字的的相关资料,文中讲解非常细致,代码帮助大家更好的理解和学习,感兴趣的朋友可以了解下

Java中的static关键字可以用于修饰变量、方法、代码块和类,还可以与import关键字联合使用,使用的方式不同赋予了static关键字不同的作用,且在开发中使用广泛,这里做一下深入了解。

静态资源(静态变量与静态方法)

被static关键字修饰的变量和方法统一属于类的静态资源,是类实例之间共享的。被static关键字修饰的变量、方法属于类变量、类方法,可以通过【类名.变量名】、【类名.方法名】直接引用,而不需要派生一个类实例出来。

静态资源分类存放的好处

JDK把不同的静态资源放在了不同的类中而不是把所有的静态资源放在一个类里面,这样做主要有3点好处:

1.不同的类有自己的静态资源,就可以实现静态资源分类。比如,和数学相关的静态资源就放在了java.lang.Math中,和日历相关的静态资源就放在java.util.Calendar中,将组织形式固定为【类>静态资源】,使得代码的逻辑结构变得清晰。

2.因为静态资源的组织形式固定为了【类>静态资源】的形式,也就有效避免的静态资源在全局重名的问题。比如在A类中有一个name属性,B类中也有一个name属性,如果放在一起会重复,但是分类放开则不会重复了,因为实际上这两个属性的全名是A.name和B.name。

3.分类有助于避免因为静态资源都放在一个类中导致该类体积过大的问题,方便了管理与协同维护。

静态资源容易混淆的三个点

静态资源的知识点比较简单,但是还是有三点比较容易混淆:静态方法能不能引用非静态资源?静态方法能不能引用静态资源?非静态方法能不能引用静态资源?要弄明白这三个问题,就要先了解静态资源在JVM中的加载机制。

实际上,虽然说静态资源是属于类的,但在JVM中却是独立于类的存在。因为从JVM类加载机制的角度来讲,静态资源是类初始化的时候加载的,而非静态资源则是派生类的时候才加载的。类的初始化早于类的派生(new)。比如,在Class.forName("xxx")方法中,就是初始化了一个类,但是并不是派生出一个实例,而只是加载了这个类中的静态资源。因此对于一个静态资源来说,它是不可能知道一个类中有哪些非静态资源的。但是对于非静态资源来说就不一样了,由于它是派生实例之后才产生的,因此属于类的这些东西它都能识别得到。至此,上面三个问题的答案已经呼之欲出了:

1.静态方法能不能引用非静态资源?答案是不能,非静态资源是派生实例之后才产生的,对于在初始化阶段就存在的静态资源来说,根本识别不到。

2.静态方法能不能引用静态资源?答案是可以,因为静态资源都是在类初始化的时候一同加载的,自然都能互相识别得到。

3.非静态方法能不能引用静态资源?答案是可以,因为非静态方法就是实例方法,在派生类实例之后产生,而静态资源已经在类初始化的时候已经存在了,自然能在引用静态资源的时候成功识别。

静态块

静态块也是static关键字的重要应用之一,作用是初始化一个类的时候做特定的操作。和静态变量、静态方法同样,静态块里面的代码只会执行一次,且只在初始化类的时候执行。静态块同样很简单,只有三个小细节要特别提及:

静态资源的加载顺序是严格按照静态资源的定义顺序来加载的。

public class A
{
  private static int a = B();
   
  static
  {
    System.out.println("进入A类的静态块");
  }
   
  public static void main(String[] args)
  {
    new A();
  }
   
  public static int B()
  {
    System.out.println("进入A类静态变量a.B()静态方法中");
    return 1;
  }
}

在这里,因为静态变量a的定义顺序在静态块之前,因此在a先被初始化的时候静态方法B先于静态块被调用执行,打印的结果是:

进入A类静态变量a.B()静态方法中
进入A类的静态块

静态代码块对于定义在它之后的静态变量,可以赋值,但是不能访问。

public class A
{
  static
  {
    c = 3;
    System.out.println(c);
  }
  
  private static int c;
}

上面这段代码会在第6行报错:Cannot reference a field before it is defined。这个特性理解起来可能比较奇怪,个人的理解是给静态方法赋值并不是实时的,Java遇到赋值语句的时候会先将这些个赋值语句缓存起来,等所有静态资源都识别完成之后再统一进行赋值。

静态代码块是严格按照父类静态代码块->子类静态代码块的顺序加载的,且只加载一次。

public class A
{
  static
  {
    System.out.println("A类的静态代码块");
  }
  
  public A()
  {
    System.out.println("A类的构造器");
  }
}
public class B extends A
{
  static 
  {
    System.out.println("B类的静态代码块");
  }
  
  public B()
  {
    System.out.println("B类的构造器");
  }
  
  public static void main(String[] args)
  {
    new B();
    new B();
  }
}

上面代码的结果是:

A类的静态代码块
B类的静态代码块
A类的构造器
B类的构造器
A类的构造器
B类的构造器

静态内部类

一般情况下,static是关键字是不能用于修饰类的,只有在该类是内部类的情况下才能使用static修饰,且只能修饰一个,这样的内部类被称为静态内部类(匿名内部类)。静态内部类只有在一些特殊的场景中才能用得上,比如像线程池ThreadPoolExecutor中的四种拒绝机制CallerRunsPolicy、AbortPolicy、DiscardPolicy、DiscardOldestPolicy就是静态内部类。

与import关键字联合使用

import static是JDK1.5之后的新特性,这两个关键字联合使用可以指定导入某个类中的指定静态资源,并且不需要使用类名.资源名,可以直接使用资源名。

import static java.lang.Math.*;

public class A
{
  public static void main(String[] args)
  {
    System.out.println(sin(2.2));
  }
}

这么写意味着导入了java.lang.Math包下的所有静态资源,因此在main函数里就可以直接使用sin(2,2)而不需要使用Math.sin(2,2)了。另外使用这种语法要特别注意的是,这里要写import static java.lang.Math.*,最后的【.*】不可少,有了这两个字符才意味着导入的是Math下的所有静态资源,写成import static java.lang.Math是有问题的。当然,我们也可以指定只导入某个静态资源,比如只导入Math下sin这个方法而不导入Math下的所有静态资源。

import static java.lang.Math.sin;

public class A
{
  public static void main(String[] args)
  {
    System.out.println(sin(2.2));
  }
}

使用import static这样的语法可以有效简化一些操作,比如在频繁使用Math类下静态资源的地方可以少写很多【Math.】,但是这样却降低了代码的可读性,因为这样就模糊了该静态资源的来源,弱化了分类的概念。

以上就是详解java中的static关键字的详细内容,更多关于java static关键字的资料请关注脚本之家其它相关文章!

相关文章

  • SpringBoot使用WebSocket实现前后端交互的操作方法

    SpringBoot使用WebSocket实现前后端交互的操作方法

    springboot使用websocket有两种方式,一种是实现简单的websocket,另外一种是实现STOMP协议,本篇讲述如何使用springboot实现简单的websocket,需要的朋友可以参考下
    2022-04-04
  • Java StringBuffer与StringBuilder有什么区别

    Java StringBuffer与StringBuilder有什么区别

    当对字符串进行修改的时候,需要使用 StringBuffer 和 StringBuilder类,和String类不同的是,StringBuffer和 StringBuilder类的对象能够被多次的修改,并且不产生新的未使用对象,本篇我们来分析分析它们的区别
    2023-01-01
  • 详解Java修饰符

    详解Java修饰符

    Java语言提供了很多修饰符,主要分为以下两类:访问修饰符;非访问修饰符。修饰符用来定义类、方法或者变量,通常放在语句的最前端。我们通过下面的例子来说明,下面就跟小编一起来看下吧
    2016-12-12
  • java实现Redisson看门狗机制

    java实现Redisson看门狗机制

    redission看门狗机制是解决分布式锁的续约问题,本文就来详细的介绍一下java实现Redisson看门狗机制,具有一定的参考价值,感兴趣的可以了解一下
    2024-09-09
  • Quarkus改造Pmml模型项目异常记录及解决处理

    Quarkus改造Pmml模型项目异常记录及解决处理

    这篇文章主要为大家介绍了Quarkus改造Pmml模型项目是遇到的异常记录以及解决方法,有需要的同学可以借鉴参考下,希望能够有所帮助,祝大家多多进步
    2022-02-02
  • Spring Boot 整合RocketMq实现消息过滤功能

    Spring Boot 整合RocketMq实现消息过滤功能

    这篇文章主要介绍了Spring Boot 整合RocketMq实现消息过滤,本文讲解了RocketMQ实现消息过滤,针对不同的业务场景选择合适的方案即可,需要的朋友可以参考下
    2022-06-06
  • Java举例讲解分治算法思想

    Java举例讲解分治算法思想

    分治算法的基本思想是将一个规模为N的问题分解为K个规模较小的子问题,这些子问题相互独立且与原问题性质相同。求出子问题的解,就可得到原问题的解,本篇文章我们就用分治算法来实现归并排序快速排序以及二分搜索算法
    2022-04-04
  • SSH框架网上商城项目第22战之银行图标以及支付页面显示

    SSH框架网上商城项目第22战之银行图标以及支付页面显示

    这篇文章主要为大家详细介绍了SSH框架网上商城项目第22战之银行图标以及支付页面显示,感兴趣的小伙伴们可以参考一下
    2016-06-06
  • Java异常学习之自定义异常详解

    Java异常学习之自定义异常详解

    你的程序总有一天会崩溃掉,在崩溃掉的时候我们要知道它在哪,为了什么而崩溃掉,数据的保存或者丢失情况如何等问题。下面这篇文章主要给大家介绍了关于Java异常学习之自定义异常的相关资料,需要的朋友可以参考借鉴,下面来一起看看吧。
    2017-06-06
  • idea鼠标控制放大缩小的操作

    idea鼠标控制放大缩小的操作

    这篇文章主要介绍了idea鼠标控制放大缩小的操作教程,具有很好的参考价值,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-02-02

最新评论