Heim > Java > JavaErste Schritte > Tiefes Verständnis des statischen Schlüsselworts

Tiefes Verständnis des statischen Schlüsselworts

青灯夜游
Freigeben: 2019-11-27 16:15:29
Original
3264 Leute haben es durchsucht

Tiefes Verständnis des statischen Schlüsselworts

Bevor ich anfange, über Statik zu sprechen, möchte ich Ihnen einen interessanten Code zeigen:

public class Test {
     
    static{
        System.out.println("test static 1");
    }
  
    static{
        System.out.println("test static 2");
    }
    
    public static void main(String[] args) {
         
    }
}
Nach dem Login kopieren

Nachdem er das Programm gelesen hatte, sagte Xiaobai Tongxiao: Was ist das? Die Hauptmethode enthält nichts. Was kann sie also ausführen? Blogger, du bist ein Star...

运行结果:
test static 1
test static 2
Nach dem Login kopieren

Little White Children's Shoes: Was dann... Was dann... Blogger, was habe ich gesagt, ich habe nichts gesagt...

Tatsächlich werden diejenigen, die den obigen Code verstehen, ihn natürlich verstehen, und diejenigen, die ihn nicht verstehen, werden ihn natürlich nicht verstehen, da der obige Code das Laden von JVM-Klassen beinhaltet! Dies liegt natürlich nicht im Rahmen dieses Blog-Artikels. Wenn Sie daran interessiert sind, das obige Programm zu verstehen, kann dieser Artikel für Sie hilfreich sein

Die Hauptbedeutung der statischen Existenz

Die Hauptbedeutung von static besteht darin, Domänenvariablen oder Methoden zu erstellen, die von bestimmten Objekten unabhängig sind. Damit Sie Eigenschaften verwenden und Methoden aufrufen können auch ohne ein Objekt zu erstellen!

Das Schlüsselwort static spielt auch eine Schlüsselrolle bei der Bildung statischer Codeblöcke zur Optimierung der Programmleistung . Ein statischer Block kann an einer beliebigen Stelle in einer Klasse platziert werden, und eine Klasse kann mehrere statische Blöcke enthalten. Wenn eine Klasse zum ersten Mal geladen wird, wird jeder statische Block in der Reihenfolge der statischen Blöcke und nur einmal ausgeführt.

Warum der statische Block zur Optimierung der Programmleistung verwendet werden kann, liegt an seinen Eigenschaften: Er wird nur einmal ausgeführt, wenn die Klasse geladen wird. Daher werden viele Initialisierungsvorgänge, die nur einmal ausgeführt werden müssen, in statischen Codeblöcken ausgeführt.

[Empfohlenes Lernen: Java-Video-Tutorial]

2. Die Einzigartigkeit von Statik

1. Durch Static geänderte Variablen oder Methoden sind unabhängig von Objekten der Klasse gehören zu keinem Instanzobjekt, sondern werden von Instanzobjekten der Klasse gemeinsam genutzt 🎜>.

Wie verstehen Sie den Satz „von Instanzobjekten einer Klasse gemeinsam genutzt“? Das heißt, ein statisches Mitglied einer Klasse gehört jedem [Jeder bezieht sich auf mehrere Objektinstanzen dieser Klasse. Wir alle wissen, dass eine Klasse mehrere Instanzen erstellen kann! ], von allen Klassenobjekten gemeinsam genutzt, im Gegensatz zu Mitgliedsvariablen, die persönlich sind [self bezieht sich auf ein einzelnes Instanzobjekt dieser Klasse] ... Ich denke, ich habe es sehr einfach gemacht, verstehen Sie?

2. Wenn die Klasse zum ersten Mal geladen wird, wird der durch Statik geänderte Teil geladen und erst dann geladen und initialisiert, wenn die Klasse zum ersten Mal verwendet wird Dies ist das erste Mal, dass die Klasse geladen wird. Sie muss nach der Verwendung initialisiert werden und kann später bei Bedarf erneut zugewiesen werden.

3. Dem statischen Variablenwert wird beim Laden der Klasse Speicherplatz zugewiesen und beim späteren Erstellen des Klassenobjekts wird dieser nicht erneut zugewiesen. Wenn Sie einen Wert zuweisen, können Sie ihn beliebig zuweisen!

4. Durch Static geänderte Variablen oder Methoden haben Vorrang vor Objekten, was bedeutet, dass nach dem Laden einer Klasse auf sie zugegriffen werden kann, auch wenn kein Objekt erstellt wird.

3. Statische Anwendungsszenarien

Da Statik von Instanzobjekten einer Klasse gemeinsam genutzt wird, wenn

eine Mitgliedsvariable ist werden von allen Objekten gemeinsam genutzt, daher sollte diese Mitgliedsvariable als statische Variable definiert werden.

Die häufigsten statischen Anwendungsszenarien sind:

1. Ändern von Mitgliedsvariablen

3. Geänderte Klassen [können nur interne Klassen ändern, d. h. statische interne Klassen]
5. Statisches Importpaket


Die oben genannten Anwendungsszenarien werden im Folgenden nacheinander besprochen...

4. Die Konzepte von statischen Variablen und Instanzvariablen

Statische Variablen: Die durch statische Variablen geänderten Mitgliedsvariablen werden als statische Variablen bezeichnet [auch genannt Klassenvariablen], statische Variablen gehören zu dieser Klasse, nicht zu Objekten.

Instanzvariablen:
Mitgliedsvariablen, die nicht durch Statik geändert werden, werden Instanzvariablen genannt und sind Instanzobjekte, die zu dieser Klasse gehören.

Eine weitere zu beachtende Sache ist:

statisch darf keine lokalen Variablen ändern

, fragen Sie mich nicht, was ich frage, denn es ist von Java vorgeschrieben!

5. Der Unterschied zwischen statischen Variablen und Instanzvariablen [Wichtige Punkte]

Statische Variablen:

Statisch Variablen gehören nicht zu Jedes Instanzobjekt gehört zu einer Klasse, daher gibt es nur eine Kopie im Speicher. Während des Ladevorgangs der Klasse weist die JVM statischen Variablen nur einmal Speicherplatz zu.

Instanzvariablen:

Jedes Mal, wenn ein Objekt erstellt wird, wird jedem Objekt Speicherplatz für Mitgliedsvariablen zugewiesen. Im Speicher wird das Objekt mehrmals erstellt . Mehrere Mitgliedsvariablen.

Ich glaube, dass Sie alle einen höheren IQ haben als Yichun, und Sie sollten alle das oben Gesagte verstehen. Die folgenden Beispiele dienen lediglich der Unterhaltung. Sie müssen sie nicht lesen, wenn Sie sie verstehen. Die folgenden Beispiele dienen nur der Unterhaltung und der Atmosphäre.

怎么理解呢?打个比喻吧...就比方说程序员小王是一个比较温柔阳光的男孩子,这1024的这一天,老板闲的没事,非要拉着程序员小王来玩耍,怎么个玩法呢?老板和小王一人拿着一把菜刀,规则很简单,互相伤害,一人一刀,你一刀,我一刀....游戏一开始,老板二话不说,跳起来就是一刀,程序员小王二话也没说反手就是一菜刀回去,这个时候老板发飙了,双眼瞪得忒大,跳起来又是一刀,这个时候程序员小王不敢还手了,就没动手。没想到老板越来越生猛,左一刀右一刀全程下来差不多砍个半个时....程序员小王一直没有还过手,因为小王知道他是老板...

这个程序员小王只会在老板第一次挥刀的时候,回老板一刀,之后就不还手了,这个时候我们把程序员小王看做是静态变量,把老板第一次向小王挥刀看做是类加载,把小王回老板一刀看出是分配内存空间,而一人一刀这个回合过程看成是类加载的过程,之后老板的每一刀都看成是创建一次对象。

连贯起来就是static变量值在类第一次加载的时候分配空间,以后创建类对象的时候不会重新分配

之后这个老板挨了一刀之后躺医院了一年,一出院回到公司第一件事就是拉程序员宜春出来玩耍,老板殊不知其然,这个博主程序员宜春性格异常暴躁,老板递给程序员宜春一把菜刀,博主宜春一接过菜刀,猝不及防的被老板跳起来就是一刀,程序员宜春痛的嗷了一声,暴躁的程序员宜春还没嗷完,在嗷的同时跳起来就是给老板一刀,接着老板跳起来又是一刀,程序员宜春嗷的一声又是回一刀,老板跳起来又一刀,程序员宜春嗷的一声又是回一刀,只要老板没停程序员宜春就没停,因为程序员宜春知道,就自己这曝脾气,暴躁起来si都敢摸,肯定有几个老铁知道....

程序员宜春就类似实例变量,每次创建对象,都会为每个对象分配成员变量内存空间,就像老板来一刀,程序员宜春都会回一刀这样子的...

6、访问静态变量和实例变量的两种方式

我们都知道静态变量是属于这个类,而不是属于是对象,static独立于对象。

但是各位有木有想过:静态成员变量虽然独立于对象,但是不代表不可以通过对象去访问,所有的静态方法和静态变量都可以通过对象访问【只要访问权限足够允许就行】,不理解没关系,来个代码就理解了

public class StaticDemo {

        static int value = 666;

        public static void main(String[] args) throws Exception{
            new StaticDemo().method();
        }

        private void method(){
            int value = 123;
            System.out.println(this.value);
        }

}
Nach dem Login kopieren

猜想一下结果,我猜你的结果是123,哈哈是咩?其实

运行结果: 666
Nach dem Login kopieren

回过头再去品味一下上面的那段话,你就能非常客观明了了,这个思想概念要有只是这种用法不推荐!

因此小结一下访问静态变量和实例变量的两种方法:

静态变量:

类名.静态变量

对象.静态变量(不推荐)

静态方法:

类名.静态方法

对象.静态方法(不推荐)

7、static静态方法

static修饰的方法也叫做静态方法,不知道各位发现咩有,其实我们最熟悉的static静态方法就是main方法了~小白童鞋:喔好像真的是哦~。由于对于静态方法来说是不属于任何实例对象的,this指的是当前对象,因为static静态方法不属于任何对象,所以就谈不上this了。

还有一点就是:构造方法不是静态方法

8、static静态代码块

先看个程序吧,看看自个是否掌握了static代码块,下面程序代码继承关系为 BaseThree——> BaseTwo——> BaseOne

BaseOne类

package com.gx.initializationblock;

public class BaseOne {

    public BaseOne() {
        System.out.println("BaseOne构造器");
    }

    {
        System.out.println("BaseOne初始化块");
        System.out.println();
    }

    static {
        System.out.println("BaseOne静态初始化块");

    }

}
Nach dem Login kopieren

BaseTwo类

package com.gx.initializationblock;

public class BaseTwo extends BaseOne {
    public BaseTwo() {
        System.out.println("BaseTwo构造器");
    }

    {
        System.out.println("BaseTwo初始化块");
    }

    static {
        System.out.println("BaseTwo静态初始化块");
    }
}
Nach dem Login kopieren

BaseThree 类

package com.gx.initializationblock;

public class BaseThree extends BaseTwo {
    public BaseThree() {
        System.out.println("BaseThree构造器");
    }

    {
        System.out.println("BaseThree初始化块");
    }

    static {
        System.out.println("BaseThree静态初始化块");
    }
}
Nach dem Login kopieren

测试demo2类

package com.gx.initializationblock;

/*
     注:这里的ABC对应BaseOne、BaseTwo、BaseThree 
 * 多个类的继承中初始化块、静态初始化块、构造器的执行顺序
     在继承中,先后执行父类A的静态块,父类B的静态块,最后子类的静态块,
     然后再执行父类A的非静态块和构造器,然后是B类的非静态块和构造器,最后执行子类的非静态块和构造器
 */
public class Demo2 {
    public static void main(String[] args) {
        BaseThree baseThree = new BaseThree();
        System.out.println("-----");
        BaseThree baseThree2 = new BaseThree();

    }
}
Nach dem Login kopieren

运行结果

BaseOne静态初始化块
BaseTwo静态初始化块
BaseThree静态初始化块
BaseOne初始化块

BaseOne构造器
BaseTwo初始化块
BaseTwo构造器
BaseThree初始化块
BaseThree构造器
-----
BaseOne初始化块

BaseOne构造器
BaseTwo初始化块
BaseTwo构造器
BaseThree初始化块
BaseThree构造器
Nach dem Login kopieren

至于static代码块运行结果不是很清晰的童鞋,详细讲解请看这篇Static静态代码块以及各代码块之间的执行顺序

以上仅仅是让各位明确代码块之间的运行顺序,显然还是不够的,静态代码块通常用来对静态变量进行一些初始化操作,比如定义枚举类,代码如下:

public enum WeekDayEnum {
    MONDAY(1,"周一"),
    TUESDAY(2, "周二"),
    WEDNESDAY(3, "周三"),
    THURSDAY(4, "周四"),
    FRIDAY(5, "周五"),
    SATURDAY(6, "周六"),
    SUNDAY(7, "周日");
 
    private int code;
    private String desc;
 
    WeekDayEnum(int code, String desc) {
        this.code = code;
        this.desc = desc;
    }
 
    private static final Map<Integer, WeekDayEnum> WEEK_ENUM_MAP = new HashMap<Integer, WeekDayEnum>();
 
    // 对map进行初始化
    static {
        for (WeekDayEnum weekDay : WeekDayEnum.values()) {
            WEEK_ENUM_MAP.put(weekDay.getCode(), weekDay);
        }
    }
 
    public static WeekDayEnum findByCode(int code) {
        return WEEK_ENUM_MAP.get(code);
    }
 
    public int getCode() {
        return code;
    }
 
    public void setCode(int code) {
        this.code = code;
    }
 
    public String getDesc() {
        return desc;
    }
 
    public void setDesc(String desc) {
        this.desc = desc;
    }
} 
Nach dem Login kopieren

当然不仅仅是枚举这一方面,还有我们熟悉的单例模式同样也用到了静态代码块,如下:

public class Singleton {
    private static Singleton instance;
 
    static {
        instance = new Singleton();
    }
 
    private Singleton() {}
 
    public static Singleton getInstance() {
        return instance;
    }
}
Nach dem Login kopieren

9、static变量与普通变量区别

static变量也称作静态变量,静态变量和非静态变量的区别是:静态变量被所有的对象所共享,在内存中只有一个副本,它当且仅当在类初次加载时会被初始化。而非静态变量是对象所拥有的,在创建对象的时候被初始化,存在多个副本,各个对象拥有的副本互不影响。

还有一点就是static成员变量的初始化顺序按照定义的顺序进行初始化。

10、静态内部类

静态内部类与非静态内部类之间存在一个最大的区别,我们知道非静态内部类在编译完成之后会隐含地保存着一个引用,该引用是指向创建它的外围内,但是静态内部类却没有。没有这个引用就意味着:

1、它的创建是不需要依赖外围类的创建。
2、它不能使用任何外围类的非static成员变量和方法。

代码举例(静态内部类实现单例模式)

public class Singleton {
    
   // 声明为 private 避免调用默认构造方法创建对象
    private Singleton() {
    }
    
   // 声明为 private 表明静态内部该类只能在该 Singleton 类中被访问
    private static class SingletonHolder {
        private static final Singleton INSTANCE = new Singleton();
    }

    public static Singleton getUniqueInstance() {
        return SingletonHolder.INSTANCE;
    }
}
Nach dem Login kopieren

Singleton 类加载时,静态内部类 SingletonHolder 没有被加载进内存。只有当调用 getUniqueInstance()方法从而触发 SingletonHolder.INSTANCESingletonHolder 才会被加载,此时初始化 INSTANCE 实例,并且 JVM 能确保 INSTANCE 只被实例化一次。

这种方式不仅具有延迟初始化的好处,而且由 JVM 提供了对线程安全的支持。

11、静态导包

静态导包格式:import static

这两个关键字连用可以指定导入某个类中的指定静态资源,并且不需要使用类名调用类中静态成员,可以直接使用类中静态成员变量和成员方法

//  Math. --- 将Math中的所有静态资源导入,这时候可以直接使用里面的静态方法,而不用通过类名进行调用
//  如果只想导入单一某个静态方法,只需要将换成对应的方法名即可
 
import static java.lang.Math.;
//  换成import static java.lang.Math.max;具有一样的效果
 
public class Demo {
    public static void main(String[] args) {
 
        int max = max(1,2);
        System.out.println(max);
    }
}
Nach dem Login kopieren

静态导包在书写代码的时候确实能省一点代码,可以直接调用里面的静态成员,但是会影响代码可读性,所以开发中一般情况下不建议这么使用。

12、static注意事项

1、静态只能访问静态。
2、非静态既可以访问非静态的,也可以访问静态的。

13、final与static的藕断丝连

到这里文章本该结束了的,但是static的使用始终离不开final字眼,二者可谓藕断丝连,常常繁见,我觉得还是很有必要讲讲,那么一起来看看下面这个程序吧。

package Demo;

class FinalDemo {
    public final double i = Math.random();
    public static double t = Math.random();
}

public class DemoDemo {
    public static void main(String[] args) {

        FinalDemo demo1 = new FinalDemo();
        FinalDemo demo2 = new FinalDemo();
        System.out.println("final修饰的  i=" + demo1.i);
        System.out.println("static修饰的 t=" + demo1.t);
        System.out.println("final修饰的  i=" + demo2.i);
        System.out.println("static修饰的 t=" + demo2.t);

        System.out.println("t+1= "+ ++demo2.t );
//      System.out.println( ++demo2.i );//编译失败
      }
}
运行结果:
    final修饰的  i=0.7282093281367935
    static修饰的 t=0.30720545678577604
    final修饰的  i=0.8106990945706758
    static修饰的 t=0.30720545678577604
    t+1= 1.307205456785776
Nach dem Login kopieren

static修饰的变量没有发生变化是因为static作用于成员变量只是用来表示保存一份副本,其不会发生变化。怎么理解这个副本呢?其实static修饰的在类加载的时候就加载完成了(初始化),而且只会加载一次也就是说初始化一次,所以不会发生变化!

至于final修饰的反而发生变化了?是不是巅覆你对final的看法?关于final详细讲解博主也准备好了一篇文章程序员你真的理解final关键字吗?

ok,文章就先到这里了,希望这篇文章能够帮助到你对static的认识,若有不足或者不正之处,希望谅解并欢迎批评指正!

本文来自 java入门 栏目,欢迎学习!

Das obige ist der detaillierte Inhalt vonTiefes Verständnis des statischen Schlüsselworts. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Verwandte Etiketten:
Quelle:php.cn
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage