保護された
保護されたアクセス権について話しましょう。以下の例 1 を見てください:
Test.java
class MyObject {} public class Test { public static void main(String[] args) { MyObject obj = new MyObject(); obj.clone(); // Compile error. } }
この時点で上記のエラーが発生します: Object 型からのメソッド clone は可視ではありません。
Object.clone() が保護されたメソッドであることはすでにわかっています。これは、このメソッドが同じパッケージ (java.lang) とその (java.lang.Object) サブクラスからアクセスできることを示しています。これは MyObject クラスです (デフォルトでは java.lang.Object から継承されます)。
同様に、Test も java.lang.Object のサブクラスです。ただし、2 つのサブクラスが同じ親クラスから継承している場合でも、1 つのサブクラスの保護されたメソッドに別のサブクラスからアクセスすることはできません。
例 2 をもう一度見てください:
Test2.java
class MyObject2 { protected Object clone() throws CloneNotSupportedException { return super.clone(); } } public class Test2 { public static void main(String[] args) throws CloneNotSupportedException { MyObject2 obj = new MyObject2(); obj.clone(); // Compile OK. } }
ここでは、MyObject2 クラスの親クラスの clone() メソッドをオーバーライドし、別のクラス Test2 の clone() メソッドを呼び出し、コンパイルに成功します。
コンパイルが成功する理由は明白です。MyObject2 クラスの clone() メソッドをオーバーライドすると、MyObject2 クラスと Test2 クラスが同じパッケージの下にあるため、この保護されたメソッドが Test2 クラスに表示されます。
この分析の時点で、Java の浅いコピーと深いコピーの記事の第 2.2 章のステートメントを思い出します。 ② 派生クラスの基本クラスの clone() メソッドをオーバーライドし、それを public として宣言します。これで、この文の理由が理解できました (他のクラスがこのクラスの clone() メソッドを呼び出せるようにするには、オーバーロード後に clone() メソッドのプロパティを public に設定する必要があります)。
例 3 を見てみましょう:
Test3.java
package 1 class MyObject3 { protected Object clone() throws CloneNotSupportedException { return super.clone(); } } package 2 public class Test3 extends MyObject3 { public static void main(String args[]) { MyObject3 obj = new MyObject3(); obj.clone(); // Compile error. Test3 tobj = new Test3(); tobj.clone();// Complie OK. } }
ここでは、Test3 クラスを使用して MyObject3 を継承しています。それ以外の場合は例 2 と同じになります。 Test3 クラスでは、Test3 クラスのインスタンス tobj の clone() メソッドが呼び出され、コンパイルが成功します。 MyObject3 クラスのインスタンス obj の clone() メソッドも呼び出すと、コンパイル エラーが発生します。
予期しない結果、継承されたクラスは保護されたメソッドにアクセスできませんか?
クラス Test3 がクラス MyObject3 (そのクローン メソッドを含む) を継承していることは明らかなので、クラス Test3 で独自のクローン メソッドを呼び出すことができます。ただし、クラス MyObject3 の保護されたメソッドは、その別のサブクラス Test3 からは見えません。
メソッドアクセス制御:
静的
1.キーワード static (最初にこれらを覚えてから読み進めてください)
1) 静的メソッドと静的変数は、クラスのオブジェクトではなく、特定のクラスに属します。
2) 静的メソッドと静的変数への参照は、クラス名を通じて直接参照されます。
3) 静的メソッドでは、非静的メソッドおよび非静的メンバー変数を呼び出すことはできません。逆に言えばOKです。
4) 静的変数は、ある点では他の言語のグローバル変数に似ていますが、プライベートでない場合は、クラスの外部からアクセスできます。
2. static を使用する場合
クラスのインスタンス (オブジェクト) を作成するときは、通常、新しいメソッドを使用して、このクラスのデータ空間を作成し、そのメソッドを呼び出すことができるようにします。
ただし、場合によっては、1 つのクラスに対して n 個のオブジェクトを作成できても (これらの n 個のオブジェクトのデータ空間は明らかに異なります)、これらの n 個のオブジェクトの一部のデータは同じである、つまり、オブジェクトがいくつあるかに関係なく、同じであることを期待することがあります。このデータのメモリ コピーを持つこのクラス インスタンス (例 1 を参照)。これは静的変数の場合に当てはまります。
別の状況は、メソッドを、それを含むクラスのオブジェクトに関連付けたくない場合です。つまり、オブジェクトが作成されていなくても、このメソッドを呼び出すことができます。静的メソッドの重要な用途は、オブジェクトを作成せずにメソッドを呼び出せることです (例 2 を参照)。これは静的メソッドの場合に当てはまります。
内部クラスでは、通常、通常のクラスを静的に宣言することはできず、内部クラスのみが静的に宣言することができます。このとき、static として宣言された内部クラスは、外部クラスをインスタンス化せずに、通常のクラスとして直接使用できます (例 3 を参照)。これは静的クラスの場合に当てはまります。
例 1
public class TStatic { static int i; public TStatic() { i = 4; } public TStatic(int j) { i = j; } public static void main(String args[]) { System.out.println(TStatic.i); TStatic t = new TStatic(5); // 声明对象引用,并实例化。此时i=5 System.out.println(t.i); TStatic tt = new TStatic(); // 声明对象引用,并实例化。此时i=4 System.out.println(t.i); System.out.println(tt.i); System.out.println(t.i); } }
結果:
0 5 4 4 4
静的変数はクラスがロードされるときに作成され、静的変数はクラスが存在する限り存在します。定義時に初期化する必要があります。上記の例では、i は初期化されていないため、デフォルトの初期値 0 が取得されます。静的変数は 1 回だけ初期化でき、静的変数は最後の初期化のみを受け取ります。
実際には、これは静的変数を共有する複数のインスタンスの問題です。
例 2
static として宣言されていません
class ClassA { int b; public void ex1() {} class ClassB { void ex2() { int i; ClassA a = new ClassA(); i = a.b; // 这里通过对象引用访问成员变量b a.ex1(); // 这里通过对象引用访问成员函数ex1 } } }
static として宣言されています
class ClassA { static int b; static void ex1() {} } class ClassB { void ex2() { int i; i = ClassA.b; // 这里通过类名访问成员变量b ClassA.ex1(); // 这里通过类名访问成员函数ex1 } }
在使用静态方法时要注意,在静态方法中不能调用非静态的方法和引用非静态的成员变量(在static方法中也不能以任何方式引用this或super)。理由很简单,对于静态的东西,JVM在加载类时,就在内存中开辟了这些静态的空间(所以可以直接通过类名引用),而此时非静态的方法和成员变量所在的类还没有实例化。
所以如果要使用非静态的方法和成员变量,可以直接在静态方法中实例化该方法或成员变量所在的类。public static void main就是这么干的。
示例3
public class StaticCls { public static void main(String[] args) { OuterCls.InnerCls oi = new OuterCls.InnerCls();// 这之前不需要new一个OuterCls } } class OuterCls { public static class InnerCls { InnerCls() { System.out.println("InnerCls"); } } }
结果:
InnerCls
3.静态初始化
static定义的变量会优先于任何其它非static变量,不论其出现的顺序如何。静态代码块(在“static{”后面跟着一段代码),是用来进行显式的静态变量初始化,这段代码只会初始化一次,且在类被第一次装载时。看下面示例。
class Value { static int c = 0; Value() { c = 15; } Value(int i) { c = i; } static void inc() { c++; } } class Count { public static void prt(String s) { System.out.println(s); } Value v = new Value(10); static Value v1, v2; static { prt("in the static block of calss Count v1.c=" + v1.c + " v2.c=" + v2.c); v1 = new Value(27); prt("in the static block of calss Count v1.c=" + v1.c + " v2.c=" + v2.c); v2 = new Value(); prt("in the static block of calss Count v1.c=" + v1.c + " v2.c=" + v2.c); } } public class TStaticBlock { public static void main(String[] args) { Count ct = new Count(); Count.prt("in the main:"); Count.prt("ct.c=" + ct.v.c); Count.prt("v1.c=" + Count.v1.c + " v2.c=" + Count.v2.c); Count.v1.inc(); Count.prt("v1.c=" + Count.v1.c + " v2.c=" + Count.v2.c); Count.prt("ct.c=" + ct.v.c); } }
结果:
in the static block of calss Count v1.c=0 v2.c=0 in the static block of calss Count v1.c=27 v2.c=27 in the static block of calss Count v1.c=15 v2.c=15 in the main: ct.c=10 v1.c=10 v2.c=10 v1.c=11 v2.c=11 ct.c=11
不管是v,v1还是v2,它们操作的成员变量都是同一个静态变量c。
在类Count中先初始化v1,v2(static Value v1, v2;),再初始化静态代码块(static{}),最后初始化v。
更多Javaプログラミングにおけるprotected修飾子とstatic修飾子の機能を詳しく解説相关文章请关注PHP中文网!