ホームページ > 記事 > ウェブフロントエンド > java_javascript スキルで学習する必要がある静的キーワード
1. 静的キーワード
クラス内のメンバー変数の場合、これらのメンバー変数は静的メンバー変数ではないため、すべての新しいオブジェクトが独自のメンバー変数を持つことがわかります。静的メンバー変数の場合、このメンバー変数のコピーは 1 つだけあり、このコピーはこのクラスのすべてのオブジェクトで共有されます。
1.1. 静的メンバー変数と非静的メンバー変数の違い
以下の例を例として挙げます
package cn.galc.test; public class Cat { /** * 静态成员变量 */ private static int sid = 0; private String name; int id; Cat(String name) { this.name = name; id = sid++; } public void info() { System.out.println("My Name is " + name + ",NO." + id); } public static void main(String[] args) { Cat.sid = 100; Cat mimi = new Cat("mimi"); Cat pipi = new Cat("pipi"); mimi.info(); pipi.info(); } }
メモリ解析図を描くことでプログラム全体の実行過程を理解する
プログラムの最初の文 Cat.sid = 100; を実行する場合、ここでの sid は静的メンバー変数です。静的変数はデータ領域 (データ セグメント) に格納されるため、最初に小さな領域を確保します。データ領域。最初の文が実行された後、sid の値は 100 になります。
この時のメモリレイアウト図は以下の通り
次のステップでは、プログラムを実行して次のことを行います:
猫 mimi = new Cat(“mimi”);
ここでは、Cat クラスのコンストラクター Cat(String name) が呼び出されます。コンストラクター メソッドは次のように定義されています。
Cat (文字列名){
this.name = name;
id=sid ;
}
呼び出し時には、まずスタック メモリに小さなメモリ mm を割り当てます。これには、ヒープ メモリ内の Cat クラスのインスタンス オブジェクトのアドレスが含まれます。 mm は、ヒープ メモリ内の Cat クラス オブジェクトの参照オブジェクトです。 。このコンストラクタは文字列型の仮引数変数を宣言しているため、実引数として「mimi」がコンストラクタに渡されます。文字列定数はデータ領域に確保されて格納されるため、データ領域のメモリ量は少なくなります。文字列「mimi」を格納するために使用されます。この時のメモリ配分は以下の通りです。
コンストラクターが呼び出されるとき、最初にスタック メモリに仮パラメータ名として小さな領域が割り当てられ、その後、文字列 "mimi" が実際のパラメータとして渡されます。 . Type は、4 つと 8 つの基本データ型を除き、その他はすべて参照型であるため、文字列もオブジェクトであると考えることができます。したがって、これは「mimi」オブジェクトの参照を name に渡すことと同じなので、name は「mimi」を指すようになります。したがって、この時点のメモリレイアウトは次のようになります。
次に、コンストラクター本体のコードを実行します。
this.name=name;
これは、ここでは現在のオブジェクトを指し、ヒープ メモリ内の cat を指します。ここで、スタック内のnameに含まれる値はヒープメモリ上のcatオブジェクトのname属性に渡されるため、nameに含まれる値はデータ領域にある文字列オブジェクト「mimi」からも確認できます。このとき、この名前は文字列オブジェクト「mimi」の参照オブジェクトでもあり、その属性値によりデータ領域にある文字列オブジェクト「mimi」を見つけることができる。この時のメモリ配分は以下の通りです:
次に、メソッド本体の別のコード行を実行します。
id=sid;
ここではidにsidの値を渡しているのでidの値は100となっています。sidを渡したら自分で1を足すとsidは101になります。この時のメモリ配置を下図に示します。
この時点でコンストラクタメソッドが呼び出され、このコンストラクタメソッドに割り当てられたローカル変数が占有していたメモリ空間がすべて消滅するため、スタック空間にあった名前メモリも消滅します。このとき、スタックメモリ上のデータ領域の文字列オブジェクト「mimi」への参照も消滅し、ヒープメモリ上の文字列オブジェクト「mimi」への参照のみが残る。この時のメモリ配置は以下の通りです。
次の実行:
Cat pipi = new Cat(“pipi”);
これは、コンストラクター メソッド Cat() の 2 回目の呼び出しです。呼び出しが完了した後の全体の呼び出しプロセスは、次のようになります。
最后两句代码是调用info()方法打印出来,打印结果如下:
通过这个程序,看出来了这个静态成员变量sid的作用,它可以计数。每当有一只猫new出来的时候,就给它记一个数。让它自己往上加1。
程序执行完后,内存中的整个布局就如上图所示了。一直持续到main方法调用完成的前一刻。
这里调用构造方法Cat(String name) 创建出两只猫,首先在栈内存里面分配两小块空间mimi和pipi,里面分别装着可以找到这两只猫的地址,mimi和pipi对应着堆内存里面的两只猫的引用。这里的构造方法声明有字符串类型的变量,字符串常量是分配在数据区里面的,所以这里会把传过来的字符串mimi和pipi都存储到数据区里面。所以数据区里面分配有存储字符串mimi和pipi的两小块内存,里面装着字符串“mimi”和“pipi”,字符串也是引用类型,除了那四类8种的基础数据类型之外,其他所有的数据类型都是引用类型。所以可以认为字符串也是一个对象。
这里是new了两只猫出来,这两只猫都有自己的id和name属性,所以这里的id和name都是非静态成员变量,即没有static修饰。所以每new出一只新猫,这只新猫都有属于它自己的id和name,即非静态成员变量id和name是每一个对象都有单独的一份。但对于静态成员变量来说,只有一份,不管new了多少个对象,哪怕不new对象,静态成员变量在数据区也会保留一份。如这里的sid一样,sid存放在数据区,无论new出来了多少只猫在堆内存里面,sid都只有一份,只在数据区保留一份。
静态成员变量是属于整个类的,它不属于专门的某个对象。那么如何访问这个静态成员变量的值呢?首先第一点,任何一个对象都可以访问这个静态的值,访问的时候访问的都是同一块内存。第二点,即便是没有对象也可以访问这个静态的值,通过“类名.静态成员变量名”来访问这个静态的值,所以以后看到某一个类名加上“.”再加上后面有一个东西,那么后面这个东西一定是静态的,如”System.out”,这里就是通过类名(System类)再加上“.”来访问这个out的,所以这个out一定是静态的。
再看下面的这段代码
package cn.galc.test; public class Cat { /** * 这里面的sid不再是静态成员变量了,因为没有static修饰符, * 此时它就是类里面一个普通的非静态成员变量,和id,name一样, * 成为每一个new出来的对象都具有的属性。 */ private int sid = 0; private String name; int id; Cat(String name) { this.name = name; id = sid++; } public void info() { System.out.println("My Name is " + name + ",NO." + id); } public static void main(String[] args) { //Cat.sid = 100;这里不能再使用“类.静态成员变量”的格式来访问sid了,因为sid现在变成了非静态的成员变量了。所以必须要把这句话注释掉,否则无法编译通过。 Cat mimi = new Cat("mimi"); Cat pipi = new Cat("pipi"); mimi.info(); pipi.info(); } }
このコードと前のコードの唯一の違いは、sid 変数の static 修飾子が削除されていることです。現時点では、sid は静的メンバー変数ではなく、非静的メンバー変数です。 new によって生成された cat オブジェクトはそれぞれ、独自の個別の sid 属性を持ちます。したがって、このコードが実行された後のメモリ内のレイアウトは次のようになります:
sid は非静的メンバー変数になったため、カウント機能がなくなりました。 id 属性や name 属性と同様に、sid はすべての新しいオブジェクトが持つ属性となるため、すべての新しい cat に sid 属性が追加されます。 SID は「クラス名.静的メンバー オブジェクト名」の形式でアクセスできなくなったため、コードの最初の文「Cat.sid =100;」をこのように使用することはできません。そうしないとコンパイル エラーが発生します。コンパイルを成功させるには、この文をコメントアウトする必要があります。 sid の値にはアクセスできないため、sid の値は常に初期化時に割り当てられた値 0 になります。コンストラクターが呼び出され、メソッド本体のコード id=sid が実行されるまで、sid は最初に独自の値 0 を id に代入するため、id の値は 0 になり、その後 sid は自分自身に 1 を加算するため、sid は 1 になります。
静的変数と非静的変数の違いは、静的変数はカウントに使用できますが、非静的変数は使用できないということです。
記憶が理解できれば、すべてが理解でき、さまざまな言語も理解できます。すべての言語はこれにほかなりません。ローカル変数に割り当てられたメモリは常にスタック上にあり、新しいものに割り当てられたメモリは常にヒープ上にあり、静的なものに割り当てられたメモリは常にデータ領域にあります。コードの残りの部分はコード領域に存在する必要があります。どの言語もこんな感じです。
静的メソッドでは、非静的メンバー変数に直接アクセスすることはできません。アクセスするには、静的メソッド内で新しいオブジェクトを作成する必要があります。静的メンバー変数が追加された場合、このメンバー変数は静的メンバー変数であり、main メソッドで直接アクセスできます。
main メソッドは静的メソッドです。main メソッドを実行する場合、新しいオブジェクトを作成する必要はありません。
動的メソッドは特定のオブジェクトに対して呼び出されますが、静的メソッドは特定のオブジェクトに対して呼び出されません。これらはオブジェクトなしでも使用できます。したがって、「classname.method()」の形式を使用して静的メソッドを呼び出すことができます。したがって、メイン メソッドで非静的メンバー変数にアクセスすることはできません。また、非静的メソッドは特定のオブジェクトに対してのみ呼び出すことができるため、メイン メソッドで非静的メソッドにアクセスすることもできません。オブジェクトがありません。次に、メソッドの実行者が来ます。
メンバー変数には、オブジェクトが new によって作成されるときにのみヒープ メモリ内の記憶領域が割り当てられます。ローカル変数はスタック メモリに記憶領域を割り当てます。
特定のオブジェクトでは静的メソッドが呼び出されなくなったため、非静的メンバーにアクセスできなくなります。
非静的メンバーは特定のオブジェクトに排他的です。非静的メンバーにアクセスする場合は、それらにアクセスするための新しいオブジェクトを作成する必要があります。
静的変数は、オブジェクト名またはクラス名を通じてアクセスできます。どちらも同じメモリにアクセスします。
上記はこの記事の全内容です。情報がたくさんあるので、Java static キーワードを真に学ぶには根気よく読む必要があります。