Java关键字修饰变量、方法、做静态代码块、静态导包

 2024-01-07 02:04:38  阅读 0

首先介绍关键字修饰变量

关键字所代表的概念是全局的、静态的,用它修饰的变量称为静态变量。

public class TestStatic {
    
    static int i = 10; // 定义了一个静态变量 i 
}

静态变量也称为类变量。 静态变量属于此类。 这意味着什么? 这实际上意味着关键字只能定义在类的{}中,而不能定义在任何方法中。

static变量能赋值吗_变量static_变量前加static

即使去掉方法中的关键字,也是一样的。

static变量能赋值吗_变量static_变量前加static

属于类,修改后的变量直接被类调用。 它不需要手动实例化该类来调用它。

public class TestStatic {
    static int i = 10;
    public static void main(String[] args) {
        System.out.println(TestStatic.i);
    }
}

这里需要理解几个变量的概念

详情请参阅

修改方法

方法可以修改。 修改后的方法称为静态方法。 其实就是在方法定义中添加关键字来修改,比如下面

static void sayHello(){}

《Java编程思想》P86页有经典描述

方法就是没有这个的方法。 非静态方法不能在内部调用,但反之亦然。 您可以仅通过类本身调用方法,而无需创建任何对象。 这实际上是方法的主要目的。

很重要的一句话是,没有这个方法就是方法。 换句话说,您可以在不创建对象的情况下访问方法。 怎么做到这一点?看下面这段代码

变量static_变量前加static_static变量能赋值吗

在上面的例子中,由于它是一个静态方法,因此可以使用类名和变量名来调用它。

因此,如果想在不创建对象的情况下调用方法,可以将此方法设置为 。 我们最常看到的方法就是main方法。 至于为什么一定是main方法,现在应该清楚了。 因为程序在执行main方法时并没有创建任何对象,所以只能通过类名来访问。

修改方法时的注意事项

变量前加static_static变量能赋值吗_变量static

变量前加static_static变量能赋值吗_变量static

装饰代码块

关键字可用于修改代码块。 代码块分为两种,一种是使用{}代码块; 另一个是{}静态代码块。 修改后的代码块称为静态代码块。 静态代码块可以放置在类中的任何位置。 类中可以有多个块。 当类第一次加载时,会按照代码块的顺序执行。 每个修改的代码块只能执行一次。 我们见面的时候会讲一下代码块的加载顺序。下面是一个静态代码块的例子

变量前加static_变量static_static变量能赋值吗

代码块可以用来优化程序执行顺序,因为它们具有以下特点:它们只会在类加载时执行一次。

用作静态内部类

内部类的使用场景相对较少,但是内部类还是有一些有用的用途的。在了解静态内部类之前,我们先来看看内部类的分类

静态内部类是修改的内部类。 静态内部类可以包含静态成员或非静态成员,但不能在非静态内部类中声明静态成员。

静态内部类有很多功能。 由于非静态内部类实例的创建需要引用外部类对象,因此非静态内部类对象的创建必须依赖于外部类的实例; 而静态内部类实例的创建只需要依赖外部类对象。 种类;

并且由于非静态内部类对象持有外部类对象的引用,因此非静态内部类可以访问外部类的非静态成员; 而静态内部类只能访问外部类的静态成员;

public class ClassDemo {
  
    private int a = 10;
    private static int b = 20;
    static class StaticClass{
        public static int c = 30;
        public int d = 40;
      
        public static void print(){
            //下面代码会报错,静态内部类不能访问外部类实例成员
            //System.out.println(a);
     
            //静态内部类只可以访问外部类类成员
            System.out.println("b = "+b);
            
        }
      
        public void print01(){
            //静态内部内所处的类中的方法,调用静态内部类的实例方法,属于外部类中调用静态内部类的实例方法
            StaticClass sc = new StaticClass();
            sc.print();
        }   
    }
}

静态导包

不知道大家有没有注意到这个现象。 例如,使用java.util中的工具类时,需要导入java.util包才能使用其内部工具类,如下

变量static_变量前加static_static变量能赋值吗

但是还有另一种方法可以使用静态导入来导入包。 静态导入是使用静态方法或静态变量来导入某个类或包。

import static java.lang.Integer.*;
public class StaticTest {
    public static void main(String[] args) {
        System.out.println(MAX_VALUE);
        System.out.println(toHexString(111));
    }
}

先进知识

了解了关键词的用法后,我们来看看深入的用法,即由浅入深,慢慢来,前戏充足~

关于类别

修改的属性和方法属于类,不会属于任何对象; 它们通过类名、属性名/方法名来调用,实例变量和局部变量属于特定的对象实例。

修改变量的存储位置

首先,我们来了解一下JVM的不同存储区域。

static变量能赋值吗_变量前加static_变量static

可变的生命周期

变量的生命周期与类的生命周期相同。 它在类加载时创建,在类销毁时销毁。 普通成员变量与其所属的成员变量具有相同的生命周期。

序列化

我们知道,序列化的目的是将Java对象转换为字节序列。 该对象被转换为有序的字节流,以便可以通过网络传输或保存在本地文件中。

声明为 和 类型的变量无法序列化,因为修改后的变量存储在方法区中,只有堆内存会被序列化。 关键字的作用是防止对象被序列化。

类加载顺序

前面我们提到过类加载顺序的概念。 修改的变量和静态代码块在使用前已经初始化。 类的初始化顺序是

加载父类的静态字段 -> 父类的静态代码块 -> 子类的静态字段 -> 子类的静态代码块 -> 父类的成员变量(非静态字段)

-> 父类非静态代码块 -> 父类构造函数 -> 子类成员变量 -> 子类非静态代码块 -> 子类构造函数

常用于日志打印

在开发过程中,我们经常会使用关键字进行日志打印。 您应该经常看到以下代码行。

private static final Logger LOGGER = LogFactory.getLoggger(StaticTest.class);

但是,您可以通过删除和最终打印日志。

private final Logger LOGGER = LogFactory.getLoggger(StaticTest.class);
private Logger LOGGER = LogFactory.getLoggger(StaticTest.class);

但是这种打印日志的方式有一个问题

每个实例化对象都会有一个。 如果创建1000个对象,就会多出1000个对象,造成资源浪费。 因此,对象通常被声明为变量,这样可以减少内存资源的使用。 占据。

通常用作单例模式

由于单例模式意味着不同的类只有一份副本,因此它可以完全匹配单例模式。

下面是双重验证锁实现单例模式的经典场景。

public class Singleton {
  
    private static volatile Singleton singleton;
 
    private Singleton() {}
 
    public static Singleton getInstance() {
        if (singleton == null) {
            synchronized (Singleton.class) {
                if (singleton == null) {
                    singleton = new Singleton();
                }
            }
        }
        return singleton;
    }
}

我们对上面的代码进行简单的说明

使用保证变量是静态的,使用保证变量的可见性,使用私有构造函数保证不能被new实例化。

使用.()获取对象时,会先进行判断。 如果为空,则类对象将被锁定。 这里有的朋友可能不知道为什么需要两个判断。 这是一个解释。

如果线程t1执行到==null,则判定该对象为null。 此时,线程将执行权交给t2。 T2判断对象为null,锁定类对象,并进行如下判断和实例化过程。 如果不进行第二次判断,t1在第一次空判断后也会走一遍实例化过程,此时仍然会创建多个对象。

类的构造函数是否为

相信大多数朋友都没有考虑过这个问题。 在Java编程思想中,有一种说法,类的构造函数虽然没有被修饰,但实际上是一个方法,但是没有给出实际的解释,但是这个问题可以从以下几个方面来回答

public class StaticTest {
    public StaticTest(){}
    public static void test(){
    }
    public static void main(String[] args) {
        StaticTest.test();
        StaticTest staticTest = new StaticTest();
    }
}

我们看一下javap -c生成的字节码

public class test.StaticTest {
  public test.StaticTest();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."":()V
       4: return
  public static void test();
    Code:
       0: return
  public static void main(java.lang.String[]);
    Code:
       0: invokestatic  #2                  // Method test:()V
       3: new           #3                  // class test/StaticTest
       6: dup
       7: invokespecial #4                  // Method "":()V
      10: astore_1
      11: return
}

我们发现调用方法时使用该指令,new对象调用该指令,并且在JVM规范#jvms-6.5中。

变量前加static_static变量能赋值吗_变量static

static变量能赋值吗_变量static_变量前加static

从这个角度来看,指令是专门用来执行方法的指令; 指令专门用于执行实例方法; 从这个角度来看,构造函数不是静态的。

如本站内容信息有侵犯到您的权益请联系我们删除,谢谢!!


Copyright © 2020 All Rights Reserved 京ICP5741267-1号 统计代码