当前位置: 首页 > 工具软件 > statichtml > 使用案例 >

java中的static属性详细介绍

杨利
2023-12-01


本来仅仅百度查一下静态代码块,众说纷纭,结果一发不可收拾,不知道的东西太多了,把这块内容汇总整理如下,共勉学习。

java中static属性详细介绍

类的生命周期

我们知道类的生命周期为装载、连接、初始化、使用和卸载,
而静态代码块,构造代码块,普通代码块,静态变量等,
在不同的阶段被创建静态的代码块、方法、变量可以说就是类的一部分,在类加载时就已经加载(不一定执行)

代码块

1.普通代码块: 就是类中方法的方法体
public void xxx(){
//code
}
2.构造块: 用{}裹起来的代码片段,构造块在创建对象时会被调用,每次创建对象时都会被调用,并且优先于类构造函数执行。 构造块中定义的变量是局部变量。
{
//code
}
3.静态块: 用static{}裹起来的代码片段,只会被执行一次(第一次加载此类时执行,比如说用Class.forName("")加载类时就会执行static block),静态块优先于构造块执行。
static{
//code
}
4.同步代码块: 使用synchronized(obj){}裹起来的代码块,在多线程环境下,对共享数据进行读写操作是需要互斥进行的,否则会导致数据的不一致性。常见的是synchronized用来修饰方法,其语义是任何线程进入synchronized需要先取得对象锁如果被占用了,则阻塞,实现了互斥访问共享资源。而synchronized也是有代价的。一个常见的场景是,一个冗长的方法中,其实只有一小段代码需要访问共享资源,这时使用同步块,就只将这小段代码裹在synchronized block,既能够实现同步访问,也能够减少同步引入的开销。 同步代码块须写在方法中。
synchronized(obj){
//code
}

用static修饰符修饰的属性和方法叫作静态属性和静态方法 --用于给类初始化是全局变量和全局方法。

声明为static关键词修饰的变量叫做静态成员变量,也叫作全局变量。被static修饰的成员变量和成员方法独立于该类的任何对象。也就是说,它不依赖类特定的实例,被类的所有实例共享。只要这个类被加载,Java虚拟机就能根据类名在运行时数据区的方法区内找到他们。因此,static对象可以在它的任何对象创建之前访问,无需引用任何对象。

静态代码块的特点: 随着类的加载而执行,而且只执行一次

(静态代码块,静态变量)>>(非静态代码块,非静态变量)>>构造方法

静态代码块的执行顺序: 静态代码块----->非静态代码块-------->构造函数(注意main方法一定是在非静态代码块的前面 ,继承时在父类静态代码块后面,子类静态代码块前面)
执行顺序是先执行父类的静态代码块,然后执行子类的静态代码块;然后执行父类的非静态代码块,再执行父类的构造方法;之后再执行子类的非静态代码块,再执行子类的构造方法。即:静态代码块》非静态代码块》构造方法。

静态代码块、静态方法 两者的区别就是:静态代码块是自动执行的; 静态方法是被调用的时候才执行的.

静态代码块:

静态代码块不能存在于任何方法体中
执行优先级高于非静态的初始化块,它会在类初始化的时候执行一次,执行完成便销毁,它仅能初始化类变量,即static修饰的数据成员。
静态代码块只能写在类中方法外,不能写在方法中,它会随着类的加载而优先于各种代码块和构造方法的加载,并且只会加载一次,如果出现多个静态代码块,会按照书写顺序加载。
static 代码块也叫静态代码块,是在类中独立于类成员的static语句块,可以有多个,位置可以随便放,它不在任何的方法体内,JVM加载类时会执行这些静态的代码块,如果static代码块有多个,JVM将按照它们在类中出现的先后顺序依次执行它们,每个代码块只会被执行一次。在静态方法里面只能直接调用同类中其他的静态成员(包括变量和方法),而不能直接访问类中的非静态成员。因为对于非静态的方法和变量,需要先创建类的实例对象后方可使用,而静态方法在使用前不用创建任何对象。

静态代码块的作用:
一般情况下,有些代码需要在项目启动的时候就执行,这时候就需要静态代码块,比如一个项目启动需要加载配置文件,或初始化内容等。

对于普通方法: 普通方法是需要加载类new出一个实例化对象,通过运行这个对象才能运行代码块,而静态方法随着类加载就运行了。
对于静态方法: 在类加载时静态方法也加载了,但是必须需要类名或者对象名才可以访问,相比于静态代码块,静态方法是被动运行,而静态代码块是主动运行。

非静态代码块:
执行的时候如果有静态初始化块,先执行静态初始化块再执行非静态初始化块,在每个对象生成时都会被执行一次,它可以初始化类的实例变量。非静态初始化块会在构造函数执行时,在构造函数主体代码执行之前被运行。
非静态代码块的执行顺序在构造方法执行之前,类每new一次都会执行。

但是面试中,面试官可能会连着其他知识点一起问,比如说继承,这边我就写个小列子,

注:只有new对象的时候 才会执行该对象的构造方法,非静态代码块

public class StaticTestFathers {
    static {
        System.out.println("父类中的静态代码块");
    }

    StaticTestFathers() {
        System.out.println("父类中的无参构造");
    }

    {
        System.out.println("父类中的非静态方法");
    }

    public static void main(String[] args) {
        System.out.println("父类中的main方法");
        new StaticTestSon();
        //父类中的静态代码块
        //父类中的main方法
        //子类中的静态代码块
        //父类中的非静态方法
        //父类中的无参构造
        //子类中的非静态方法
        //子类中的无参构造
    }
}

public class StaticTestSon extends StaticTestFathers {
    static {
        System.out.println("子类中的静态代码块");
    }

    StaticTestSon() {
        System.out.println("子类中的无参构造");
    }

    {
        System.out.println("子类中的非静态方法");
    }

    public static void main(String[] args) {
        System.out.println("子类中的main方法");
        new StaticTestSon();
        //父类中的静态代码块
        //子类中的静态代码块
        //子类中的main方法
        //父类中的非静态方法
        //父类中的无参构造
        //子类中的非静态方法
        //子类中的无参构造
    }
}

静态方法

静态方法可以直接通过类名调用,任何的实例也都可以调用,因此静态方法中不能用this和super关键字,不能直接访问所属类的实例变量和实例方法 (就是不带static的成员变量和成员成员方法),只能访问所属类的静态成员变量和成员方法。因为类所属的实例变量和实例方法需要对象创建之后才会存在。
静态方法不能以任何方式引用this和super关键字,因为静态方法在使用前不用创建任何实例对象,当静态方法调用时,this所引用的对象根本没有产生。

静态属性和非静态属性的区别:

  1. 在内存中存放的位置不同:所有static修饰的属性和方法都存放在内存的方法区里,而非静态的都存在堆内存中。
  2. 出现的时机不同:静态属性和方法在没创建对象之前就存在,而非静态的需要在创建对象才存在。
  3. 静态属性是整个类都公用的。
  4. 生命周期不一样,静态在类消失后被销毁,非静态在对象销毁后销毁。
  5. 用法:静态的可以直接通过类名访问,非静态只能通过对象进行访问。

方法区:主要是存储类信息,常量池(static 常量和 static 变量),编译后的代码(字 节码)等数据。

使用static的注意事项

  1. 带静态修饰符的方法只能访问静态属性。
  2. 非静态方法既能访问静态属性也能访问非静态属性。
  3. 非静态方法不能定义静态变量。
  4. 静态方法不能使用this、super关键字。
  5. 静态方法不能调用非静态方法,反之可以。
    普通变量只能通过对象调用的,所以普通变量不能放在静态代码块中。

继承关系中静态和非静态的关系

  1. 对于非静态属性,子类可以继承父类非静态属性,但是当父子类出现相同的非静态属性时,不会发生子类的重写并覆盖父类的非静态属性,而是隐藏父类的非静态属性。
  2. 对于非静态方法,子类可以继承并重写父类的非静态方法。
  3. 对于静态属性,子类可以继承父类的静态属性,但是如果和非静态属性一样时,会被隐藏。
  4. 对于静态方法,子类可以继承父类的静态方法,但是不能重写静态方法,同名时会隐藏父类的。
    注:静态属性、静态方法、非静态属性都可以被继承和隐藏,但是不可以被重写, 非静态方法可以被重写和继承

普通代码块和构造代码块区别

  1. 静态代码块和构造代码块在声明上少一个static关键字。
    执行时机:
  2. 构造代码块在创建对象时被调用,每次创建对象都会调用一次,且优先于构造函数执行。

注:不是优先于构造函数执行,而是依托于构造函数,如果不创建对象就不会执行构造代码块。
普通代码块和构造代码块的区别在于,构造代码块是在类中定于的,而普通代码块是在方法体中定义的,执行顺序和书写顺序一致。

static的共性:

①凡是static的都跟对象有关,都类级别的。

②凡是static的在加载期会有特殊处理。

③构造方法不能使用static。

④static修饰的在加载时产生在数据段的静态区内。

static加上访问修饰符-------private

private static修饰成员变量,private 限制了它的访问范围,只能在本类中被访问,static 只是控制了它不需要实例化就可以访问,是一个私有的共享的数据。
private static 修饰成员方法也是一个意思,本类中可用的私有的属于类的静态方法。
注意!!!不要搞混 访问控制 和 static 的概念
default\ protected\ public\ private 限制的是访问范围。
static 修饰的变量或者方法,不需要实例化,在类加载时就已经存在了,是属于类的。

private static 是私有的,不能在外部访问,只能通过静态方法调用,这样可以防止对变量的修改
public static 是公开的,在外部就可以访问,且可以对该值修改,
在编程中,如果不希望静态变量随意修改,就应该声明private(私有)的,这样外部不能随意修改,此时在把构造函数私有,这样这个变量就没有办法使用一般方法修改了,
如果使用公开的,则可以在任意地方对其进行修改。

static与多态之间的联系

static是针对面向对象中的“多态”而提出来的,static修饰的静态成员不存在多态性。
static方法不能被覆盖,因为方法覆盖是基于运行时动态绑定的,而static方法是编译时静态绑定的。static方法跟类的任何实例都不相关,所以概念上不适用。
java中也不可以覆盖private的方法,因为private修饰的变量和方法只能在当前类中使用,如果是其他的类继承当前类是不能访问到private变量或方法的,当然也不能覆盖。
方法重载:在同一个类中,方法相同,方法的参数个数或者参数类型不同,为了实现方法的多态性。
方法重写(覆盖):重写或覆盖是发生在子类和父类之间,而且是基于动态绑定的,但static修饰的是静态绑定编译的。
覆盖是发生在子类和父类之间,所以private修饰的变量或方法是无法被子类访问的,无法继承,所以更没办法覆盖。

static和finall区别及一块用表示什么

static和final的意义是不同的,
static修饰的时候代表对象是静态的,而final修饰的时候代表对象只能赋值一次,
他们连用的时候是因为定义的那个对象既要它是静态的,也要求它的值不能再被修改。
 
static final用来修饰成员变量和成员方法,可简单理解为“全局常量”!
对于变量,表示一旦给值就不可修改,并且通过类名可以访问。
对于方法,表示不可覆盖,并且可以通过类名直接访问。

举例说明:
static int a=1;
static final b=1;
这里a和b的区别在于,a在程序里可以被重新赋值为2或3或等等的整数,而b在程序里不能被重新赋值,b永远都为1,也就是说b是一个常量。
final int c=1;
static final b=1;
这里c和b的区别在于,b存放在静态空间,不会在程序运行时被释放,它永远占着内存直到程序终止,而c在程序用完它而不会再用到它的时候就会被自动释放,不再占用内存。

当一个常数或字符串我们需要在程序里反复反复使用的时候,我们就可以把它定义为static final,这样内存就不用重复的申请和释放空间。

有时你希望定义一个类成员,使它的使用完全独立于该类的任何对象。通常情况下,类成员必须通过它的类的对象访问,但是可以创建这样一个成员,它能够被它自己使用,而不必引用特定的实例。在成员的声明前面加上关键字static(静态的)就能创建这样的成员。如果一个成员被声明为static,它就能够在它的类的任何对象创建之前被访问,而不必引用任何对象。你可以将方法和变量都声明为static。static 成员的最常见的例子是main( ) 。因为在程序开始执行时必须调用main() ,所以它被声明为static。

声明为static的变量实质上就是全局变量。当声明一个对象时,并不产生static变量的拷贝,而是该类所有的实例变量共用同一个static变量。声明为static的方法有以下几条限制:
  •它们仅能调用其他的static 方法。
  •它们只能访问static数据。
  •它们不能以任何方式引用this 或super(关键字super 与继承有关,在下一章中描述)。
  如果你需要通过计算来初始化你的static变量,你可以声明一个static块,Static 块仅在该类被加载时执行一次。下面的例子显示的类有一个static方法,一些static变量,以及一个static 初始化块:

final

它可以修饰非抽象类、非抽象类成员方法和变量。你可能出于两种理解而需要阻止改变:设计或效率。

    final类不能被继承,没有子类,final类中的方法默认是final的。

    final方法不能被子类的方法覆盖,但可以被继承。

    final成员变量表示常量,只能被赋值一次,赋值后值不再改变。

    final不能用于修饰构造方法。
    
    final可以修饰变量、方法及类,当你定义一个final变量时,jvm会将其分配到常量池中,程序不可改变其值; 
    当你定义一个方法时,改方法在子类中将不能被重写;
    当你修饰一个类时,该类不能被继承。

    注意:父类的private成员方法是不能被子类方法覆盖的,因此private类型的方法默认是final类型的。
     final类不能被继承,因此final类的成员方法没有机会被覆盖 ,
     默认都是final的。在设计类时候,如果这个类不需要有子类,类的实现细节不允许改变,
     并且确信这个类不会载被扩展,那么就设计为final类。

final方法

   如果一个类不允许其子类覆盖某个方法,则可以把这个方法声明为final方法。

    使用final方法的原因有二:

    第一、把方法锁定,防止任何继承类修改它的意义和实现。

    第二、高效。编译器在遇到调用final方法时候会转入内嵌机制,大大提高执行效率。

final变量(常量)

用final修饰的成员变量表示常量,值一旦给定就无法改变!

    final修饰的变量有三种:静态变量、实例变量和局部变量,分别表示三种类型的常量。

    从下面的例子中可以看出,一旦给final变量初值后,值就不能再改变了。

    另外,final变量定义的时候,可以先声明,而不给初值,这中变量也称为final空白,
    无论什么情况,编译器都确保空白final在使用之前必须被初始化。
    但是,final空白在final关键字final的使用上提供了更大的灵活性,
    为此,一个类中的final数据成员就可以实现依对象而有所不同,却有保持其恒定不变的特征。

static

static表示“全局”或者“静态”的意思,用来修饰成员变量和成员方法,也可以形成静态static代码块,但是Java语言中没有全局变量的概念。

被static修饰的成员变量和成员方法独立于该类的任何对象。也就是说,它不依赖类特定的实例,被类的所有实例共享。只要这个类被加载,Java虚拟机就能根据类名在运行时数据区的方法区内定找到他们。因此,static对象可以在它的任何对象创建之前访问,无需引用任何对象。

用public修饰的static成员变量和成员方法本质是全局变量和全局方法,当声明它类的对象市,不生成static变量的副本,而是类的所有实例共享同一个static变量。

static变量前可以有private修饰,表示这个变量可以在类的静态代码块中,或者类的其他静态成员方法中使用(当然也可以在非静态成员方法中使用–废话),但是不能在其他类中通过类名来直接引用,这一点很重要。实际上你需要搞明白,private是访问权限限定,static表示不要实例化就可以使用,这样就容易理解多了。static前面加上其它访问权限关键字的效果也以此类推。

static修饰的成员变量和成员方法习惯上称为静态变量和静态方法,可以直接通过类名来访问,访问语法为:

类名.静态方法名(参数列表…)

类名.静态变量名

用static修饰的代码块表示静态代码块,当Java虚拟机(JVM)加载类时,就会执行该代码块(用处非常大)。

static变量

按照是否静态的对类成员变量进行分类可分两种:一种是被static修饰的变量,叫静态变量或类变量;另一种是没有被static修饰的变量,叫实例变量。两者的区别是:
对于静态变量在内存中只有一个拷贝(节省内存),JVM只为静态分配一次内存,在加载类的过程中完成静态变量的内存分配,可用类名直接访问(方便),当然也可以通过对象来访问(但是这是不推荐的)。
对于实例变量,没创建一个实例,就会为实例变量分配一次内存,实例变量可以在内存中有多个拷贝,互不影响(灵活)。

静态方法

静态方法可以直接通过类名调用,任何的实例也都可以调用,因此静态方法中不能用this和super关键字,不能直接访问所属类的实例变量和实例方法(就是不带static的成员变量和成员成员方法),只能访问所属类的静态成员变量和成员方法。因为实例成员与特定的对象关联!这个需要去理解,想明白其中的道理,不是记忆!!!
因为static方法独立于任何实例,因此static方法必须被实现,而不能是抽象的abstract。

static代码块

static代码块也叫静态代码块,是在类中独立于类成员的static语句块,可以有多个,位置可以随便放,它不在任何的方法体内,JVM加载类时会执行这些静态的代码块,如果static代码块有多个,JVM将按照它们在类中出现的先后顺序依次执行它们,每个代码块只会被执行一次

构造代码块

格式:java类中使用{}声明的代码块(和静态代码块的区别是少了static关键字)
执行时机: 构造代码块在创建对象的时候被调用,每创建一次对象都会调用一次,但是优先于构造函数执行,需要注意的是,听名字我们就知道,构造代码块不是优先于构造函数执行的,而是依托于构造函数,也就是说,如果你不实例化对象,构造代码块是不会执行的。怎么理解呢?先看看下面的代码段:

public class Test1 {
    {
        System.out.println("构造代码块");
    }
    public Test1(){
        System.out.println("无参构造函数");
    }
    public Test1(String str){
        System.out.println("有参构造函数");
    }
        public void sayHello(){
        System.out.println("普通代码块");
    }
    public static void main(String[] args) {
        Test1 test1 = new Test1();
        //构造代码块
        //无参构造函数
    }
}

构造代码块的作用:

(1)和构造函数的作用类似,都能够对象记性初始化,并且只要创建一个对象,构造代码块都会执行一次。但是反过来,构造函数则不会再每个对象创建的时候都执行(多个构造函数的情况下,建立对象时传入的参数不同则初始化使用对应的构造函数)
(2)利用每次创建对象的时候都会提前调用一次构造代码块特性,我们做诸如统计创建对象的次数等功能。

构造函数

1.构造函数必须和类名完全相同。在java中,普通函数可以和构造函数同名,但是必须带有返回值。

2.构造函数的功能主要用于在类创建时定义初始化的状态。没有返回值,也不能用void来进行修饰。这就保证额它不仅什么也不用自动返回,而且根本不能有任何选择,而其他方法都有返回值,尽管方法体本身不会自动返回什么,但是仍然可以返回一些东西,而这些东西可能是不安全的;

3.构造函数不能被直接调用,必须通过New运算符在创建对象的时才会自动调用;而一般的方法是在程序执行到它的时候被调用的

4.当定义一个类的时候,通常情况下都会现实该类的构造函数,并在函数中指定初始化的工作也可省略,不过Java编译期会提供一个默认的构造函数,此默认的构造函数是不带参数的,即空参构造。而一般的方法不存在这一特点。

普通代码块和构造代码块的区别是,构造代码块是在类中定义的,而普通代码块是在方法体重定义的。并且普通代码块的执行顺序和书写顺序是一致的

执行顺序:1.静态代码块>构造代码块>构造函数>普通代码块


public class CodeBlock {
    static {
        System.out.println("静态代码块");
    }

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

    public CodeBlock() {
        System.out.println("无参构造函数");
    }

    public CodeBlock(String str) {
        System.out.println("有参构造函数");
    }

    public void sayHello() {
        System.out.println("普通代码块");
    }

    public static void main(String[] args) {
        System.out.println("执行了main方法");
        new CodeBlock().sayHello();
        System.out.println("---------------------------");
        new CodeBlock().sayHello();
        //静态代码块
        //执行了main方法
        //构造代码块
        //无参构造函数
        //普通代码块
        //---------------------------
        //构造代码块
        //无参构造函数
        //普通代码块
    }
}
public class Test1 {
    static{
      int   x = 5 ;//由于是局部变量,所以x= 5 不影响后面的值  去掉int变全局
    }
    static int x ,y;//这个时候会将x和y进行初始化,得到x=0;y=0
    public static void main(String args[]){
        x--;//-1
        myMethod();//运行myMethod方法,x之前是-1,开始调用myMethod()函数
        System.out.println(x+y++ +x);//最终的运行结果为2   1+0+1=2
    }
    public static void myMethod(){
        y=x++ + ++x;//-1+1=0  步骤2:这个地方的调用要注意:x++ + ++x 是将-1先自加然后加1,得到y=0  
    }
}

java 中静态代码和非静态代码块的区别!

相同点:都是在JVM加载类时且在构造方法执行之前执行,在类中都可以定义多个,
    一般在代码块中对一些static变量进行赋值。
    
不同点:静态代码块在非静态代码块之前执行(静态代码块—>非静态代码块—>构造方法)。
    静态代码块只在第一次new执行一次,之后不再执行,而非静态代码块在每new
    一次就执行一次。非静态代码块可在普通方法中定义(不过作用不大);而静态代码块不行。

https://blog.csdn.net/qq_43060759/article/details/83244041

https://blog.csdn.net/caoxiaohong1005/article/details/73719279

https://www.cnblogs.com/dyh-air/articles/7788854.html

https://www.cnblogs.com/luoyanli/archive/2012/12/04/2800758.html

https://blog.csdn.net/qq_31635851/article/details/108726756

https://www.cnblogs.com/protected/p/6419217.html

Java方法区和堆分别储存什么

 类似资料: