보호
보호 된 액세스 권한 문제에 대해 이야기합시다. 아래 예제 1을 참조하십시오.
test.java
클래스 myObject {} public class test {public static void main (String [] args) {myObject obj = new myObject (); obj.clone (); // 오류를 컴파일합니다. }} 유형 객체에서 메소드 클론이 표시되지 않습니다.
우리는 이미 Object.clone ()가 보호 된 방법임을 이해했습니다. 이 방법은 동일한 패키지 (java.lang)와 IT (java.lang.object)의 서브 클래스로 액세스 할 수 있음을 보여줍니다. 다음은 myObject 클래스 (java.lang.object의 기본 상속)입니다.
마찬가지로, 테스트는 Java.lang.object의 서브 클래스이기도합니다. 그러나 두 하위 클래스는 동일한 상위 클래스에서 상속되지만 다른 서브 클래스의 보호 된 방법은 하나의 서브 클래스로 액세스 할 수 없습니다.
예제 2를 다시 살펴 보겠습니다.
test2.java
class myobject2 {Protected Object Clone ()는 ClonenOntSupportedException {return super.clone (); }} public class test2 {public static void main (String [] args)은 clonenotsupportedException {myObject2 obj = new myObject2 (); obj.clone (); // 확인을 컴파일합니다. }} 여기서, 우리는 myObject2 클래스에서 상위 클래스의 clone () 메소드를 무시하고 다른 클래스 test2에서 clone () 메소드를 호출하고 컴파일하고 통과합니다.
컴파일의 이유는 분명합니다. myObject2 클래스에서 clone () 메소드를 무시할 때 myObject2 클래스와 test2 클래스는 동일한 패키지 아래에 있으므로이 보호 된 방법은 test2 클래스에 표시됩니다.
이 시점에서, 우리는 Java의 얕고 깊은 사본 기사에서 2.2 장의 진술을 기억합니다. 이제이 문장의 이유를 이해합니다 (다른 클래스 가이 클래스의 Clone () 메소드를 호출 할 수 있도록 오버로드 후 Clone () 메소드의 속성을 공개해야합니다).
예제 3을 살펴 보겠습니다.
test3.java
패키지 1class myObject3 {보호 된 객체 클론 ()은 ClonenOntSupportedException {return super.clone (); }} 패키지 2public class test3 확장 myobject3 {public static void main (String args []) {myobject3 obj = new myobject3 (); obj.clone (); // 오류를 컴파일합니다. test3 tobj = new test3 (); tobj.clone (); // complie ok. }} 여기서 나는 test3 클래스를 사용하여 myObject3를 상속합니다. 이 두 클래스에는 다른 패키지가 있습니다. 그렇지 않으면 예제 2의 경우입니다. test3 클래스에서는 teST3 클래스의 인스턴스 TOBJ의 clone () 메소드를 호출하고 컴파일 및 패스하십시오. 또한 MyObject3 클래스의 인스턴스 OBJ의 clone () 메소드를 호출하고 컴파일 오류가 호출됩니다!
예기치 않은 결과, 상속 클래스에서 보호 된 방법에 액세스 할 수 없습니까?
클래스 test3가 클래스 myObject3 (클론 방법 포함)을 상속 받으므로 클래스 test3에서 자신의 클론 메소드를 호출 할 수 있습니다. 그러나, 클래스 myObject3의 보호 된 방법은 다른 BUN 서브 클래스 test3에 보이지 않습니다.
다음은 "Java in a Nutshell"의 또 다른 구절입니다.
보호 된 접근은 조금 더 많은 노동이 필요합니다. 클래스 A가 보호 된 필드 X를 선언하고 다른 패키지로 정의 된 클래스 B에 의해 확장된다고 가정합니다 (이 마지막 지점은 중요합니다). 클래스 B는 보호 된 필드 X를 상속받으며 해당 코드는 현재 B의 현재 인스턴스 또는 코드가 참조 할 수있는 B의 다른 인스턴스에서 해당 필드에 액세스 할 수 있습니다. 그러나 클래스 B 코드가 A의 임의의 인스턴스의 보호 된 필드를 읽기 시작할 수 있다는 의미는 아닙니다! 객체가 A의 인스턴스이지만 B의 인스턴스가 아닌 경우, 해당 필드는 분명히 B에 의해 상속되지 않으며 클래스 B 코드는 읽을 수 없습니다.
그건 그렇고, 중국의 많은 Java 책은 일반적으로 액세스 권한 (다양한 형태 및 일관된 내용)을 도입 할 때 이러한 방식으로 설명됩니다.
방법의 액세스 제어 :
공전
1. 키워드 정적 (먼저 기억하고 읽으십시오)
1) 정적 메소드와 정적 변수는 특정 클래스에 속하지만 클래스에는 그렇지 않은 객체입니다.
2) 정적 방법과 정적 변수에 대한 참조는 클래스 이름을 통해 직접 참조됩니다.
3) 정적 메소드 및 비 정적 멤버 변수는 정적 메소드에서 호출 할 수 없습니다. 그렇지 않으면 괜찮습니다.
4) 정적 변수는 일부 프로그램의 다른 언어로 된 글로벌 변수와 유사하며 비공개가 아닌 경우 클래스 밖에서 액세스 할 수 있습니다.
2. 정적을 사용하는시기
클래스 (개체)의 인스턴스를 만들 때 일반적 으로이 클래스의 데이터 공간이 생성되고 메소드를 호출 할 수 있도록 새로운 메소드를 사용합니다.
그러나 때로는 N 객체로 클래스가 생성 될 수 있지만 (분명히이 N 객체의 데이터 공간은 다르지만), 이러한 N 객체의 일부 데이터는 동일합니다. 즉, 클래스가 가지고있는 인스턴스의 수와 상관없이 데이터에는 이러한 인스턴스의 메모리 사본이 있습니다 (예 : 예제 1 참조). 이것은 정적 변수의 경우입니다.
또 다른 시나리오는 클래스가 포함 된 클래스의 객체와 연관되지 않기를 원한다는 것입니다. 즉,이 방법은 객체가 생성되지 않더라도 호출 할 수 있습니다. 정적 방법의 중요한 사용법은 객체를 만들지 않고 호출하는 것입니다 (예 2 참조). 이것은 정적 방법의 경우입니다.
내부 수업에는 특별한 사용이 있습니다. 일반적으로 정상 클래스는 정적으로 선언 될 수 없으며 내부 클래스 만 할 수 있습니다. 이 시점에서,이 내부 클래스는 정적으로 선언 된이 내부 클래스는 외부 클래스를 인스턴스 할 필요없이 정상 클래스로 직접 사용할 수 있습니다 (예 3 참조). 이것은 정적 클래스의 경우입니다.
예 1
공개 클래스 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 = 새로운 tstatic (5); // 객체 참조를 선언하고 인스턴스화합니다. 이때 i = 5 system.out.println (ti); tstatic tt = new tstatic (); // 객체 참조를 선언하고 인스턴스화합니다. 이때 i = 4 system.out.println (ti); System.out.println (tt.i); System.out.println (ti); }}
결과:
05444
정적 변수는 클래스가로드 될 때 생성됩니다. 클래스가 존재하는 한 정적 변수가 존재합니다. 정의 할 때 초기화해야합니다. 위의 예에서는 초기화되지 않으므로 기본 초기 값 0이 얻어집니다. 정적 변수는 한 번만 초기화 할 수 있으며 정적 변수는 마지막 초기화 만 허용합니다.
실제로 이것은 정적 변수를 공유하는 여러 인스턴스의 문제입니다.
예 2
정적으로 선언되지 않았습니다
클래스 클래스 {int b; public void ex1 () {} class classb {void ex2 () {int i; classa a = new classa (); I = AB; // 객체 참조를 통해 멤버 변수 b A.Ex1 ()에 대한 액세스; // 객체 참조를 통해 ex1 ex1}}}}}}}}
정적으로 선언했습니다
클래스 classa {static int b; 정적 void ex1 () {}} classb {void ex2 () {int i; i = classa.b; // 여기에서 클래스 이름을 통해 멤버 변수 b classa.ex1 ()에 대한 액세스; // 여기에서 클래스 이름을 통해 멤버 함수 ex1에 대한 액세스}} 정적 메소드를 사용하는 경우 정적 메소드에서 비 정적 메소드를 호출 할 수 없으며 비 정적 멤버 변수를 참조 할 수 없습니다 (이 또는 슈퍼는 정적 메소드에서 어떤 식 으로든 참조 할 수 없습니다). 그 이유는 매우 간단합니다. 정적 인 경우, JVM이 클래스를로드 할 때 메모리에서 이러한 정적 공간을 열어 클래스 이름을 통해 직접 참조 할 수 있으며, 현재 비 정적 메소드 및 멤버 변수가있는 클래스가 인스턴스화되지 않은 클래스.
따라서 비 정적 메소드 및 멤버 변수를 사용하려면 메소드 또는 멤버 변수가 정적 메소드에있는 클래스를 직접 인스턴스화 할 수 있습니다. 그것이 Public Static Void Main이 수행하는 방식입니다.
예 3
public class staticcls {public static void main (string [] args) {outercls.innercls oi = new autercls.innercls (); //이 전에 새로운 외부 클래스가 필요하지 않습니다} class innercls {내면 () {system.out.println ( "innercls"); }}}
결과:
내부
3. 정적 초기화
정적으로 정의 된 변수는 나타나는 순서에 관계없이 다른 비 정적 변수보다 우선합니다. 정적 코드 블록 (이후 코드)을 사용하여 명시 적 정적 변수 초기화를 수행합니다. 이 코드는 한 번만 초기화되고 클래스가 처음으로로드 된 경우에만 초기화됩니다. 아래 예제를 참조하십시오.
클래스 값 {static int c = 0; 값 () {c = 15; } 값 (int i) {c = i; } static void inc () {c ++; }} class count {public static void prt (문자열 s) {system.out.println (s); } value v = 새 값 (10); 정적 값 v1, v2; static {prt ( "Cals의 정적 블록에서 V1.c =" + v1.c + "v2.c =" + v2.c); v1 = 새로운 값 (27); prt ( "cals count v1.c =" + v1.c + "v2.c =" + v2.c)의 정적 블록에서; v2 = 새로운 값 (); prt ( "cals count v1.c =" + v1.c + "v2.c =" + v2.c)의 정적 블록에서; }} public class tstaticBlock {public static void main (String [] args) {count ct = new count (); count.prt ( "메인 :"); count.prt ( "ct.c =" + ct.vc); 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.vc); }}
결과:
Calss count v1.c = 0 v2.c = 0에서 Calss count v1.c = 27 v2.c = 27의 정적 블록의 정적 블록의 정적 블록의 정적 블록은 메인에서 Cals count v1.c = 15 v2.c = 15의 정적 블록 수 : ct.c = 10v1.c = 10 v2.c = 10v1.c = 11 v2.c = 11ct.c = 11 11ct.c = 11.
V, v1 또는 v2이든, 작동하는 멤버 변수는 동일한 정적 변수 c입니다.
클래스 카운트에서 v1 및 v2 (정적 값 v1, v2;)에서 정적 코드 블록 (static {})을 초기화하고 마지막으로 v를 초기화합니다.