캡슐? 💊 너무 귀여워
📌 접근 제어자 복습하기
👉 접근제어자 포스팅
public
: 어디에서나
protected
: 내부 패키지와 외부 패키지의 자식 클래스의 경우
default
: 동일 패키지에서만 접근 가능
private
: 내부 클래스에서만 접근할 수 있음
접근 제어자 | 같은 클래스의 멤버 | 같은 패키지의 멤버 | 외부 패키지이면서 자식 클래스의 멤버 | 그 외의 영역 |
---|---|---|---|---|
public | ○ | ○ | ○ | ○ |
protected | ○ | ○ | ○ | X |
default | ○ | ○ | X | X |
private | ○ | X | X | X |
😎 이정도면 된거아니야?
🤮 절대 이님!! 멤버변수와 스태틱 변수간에 , 정적 메서드와 인스턴스 메서드별로 확신 있어?
🙅 없어요
🔖 UML 표기법에서의 접근 제어자 표시
private
: -
default
: ~
protected
: #
public
: +
정적 메서드 : 밑줄 (_
)
📍 어떤 변수에 접근해야한다 🟰 메모리에 해당 변수가 올라와있어야한다.
즉, 상속 받은 경우에는 상위 클래스의 인스턴스 변수를 가지고 있기 때문에 객체를 생성하지 않고도 접근할 수 있다.
그러나 따로 상속 받지 않은 경우에는 객체를 생성 후 객체 참조 변수를 통해 접근 해야한다.
📍 인스턴스 멤버에 접근하는 경우 :
해당 클래스를 상속 받은 경우에는 this
예약어를 통해서 접근할 수 있다.
상속받지 않은 경우에는 객체 참조 변수를 사용한다.
📍 정적 메서드가 접근할 수 있는 변수란?!
정적 메서드는 객체가 생성되기 전에 스태틱으로 올라간다. ✔️ 따라서 이때에 메모리에 올라가 있는 변수만 사용이 가능하다.
🤔 그러면 정적 메서드가 메모리에 올라가 있을 때 올라가 있는 변수는 어떤 것이 있을까..?
👉 static
으로 선언된 클래스 변수이거나, 해당 메서드 내에서 직접 객체를 선언해야한다.
package OOP03.encapsulation01.packageOne;
public class ClassA {
private int pri = 1;
int def = 1;
protected int pro = 1;
public int pub;
void runSomeThing(){
int pri1 = this.pri;
int def1 = this.def;
int pro1 = this.pro;
int pub1 = this.pub;
}
static void runStaticThing() {
// 📌 정적 메서드는 정적 변수(클래스 변수)만 접근 가능!!
// 정적 메서드에서 멤버 변수로의 접근은 객체를 생성 후에 객체 참조 변수를 통해 접근
ClassA classA = new ClassA();
int pri1 = classA.pri;
int def1 = classA.def;
int pro1 = classA.pro;
int pub1 = classA.pub;
}
}
package OOP03.encapsulation01.packageOne;
public class ClassAA extends ClassA{
ClassA classA = new ClassA();
void runSomeThing(){
// int pri1 = this.pri;
// private는 내부 클래스에서만 접근이 가능하다.
int def1 = this.def;
int pro1 = this.pro;
int pub1 = this.pub;
}
static void runStaticThing() {
//📌 정적 메서드는 정적 변수(클래스 변수)만 접근 가능!!
}
}
package OOP03.encapsulation01.packageOne;
public class ClassB {
ClassA classA = new ClassA();
void runSomeThing(){
//📌 상속 받지 않아도 동일 패키지로 private로 선언된 변수를 제외하면 모두 접근이 가능하다.
// int pri1 = classA.pri;
int def1 = classA.def;
int pro1 = classA.pro;
int pub1 = classA.pub;
}
static void runStaticThing() {
//📌 정적 메서드는 클래스 변수만 접근 가능!!
}
}
package OOP03.encapsulation01.packageTwo;
import OOP03.encapsulation01.packageOne.ClassA;
//다른 패키지로 import문이 필요하다.
public class ClassAB extends ClassA {
void runSomeThing(){
// int pri1 = this.pri; private 접근 ❌
// private는 내부 클래스에서만 접근이 가능하다.
// int def1 = this.def; default 접근 ❌
// default는 동일한 패키지에서만 접근할 수 있다.
int pro1 = this.pro; //다른 패키지이지만, 상속을 받아서 protect 접근이 가능하다.
int pub1 = this.pub; //public 접근 가능
}
static void runStaticThing() {
//📌 정적 메서드는 클래스 변수만 접근 가능!!
// 따라서 메서드 내에서 객체를 생성 후 객체 참조 변수를 이용해 접근
ClassAB classAB = new ClassAB();
// 상속을 받았지만 default는 사용 ❌
// default는 동일한 패키지에서만 접근할 수 있다.
int pro1 = classAB.pro; // 상속했기 때문에 protect 접근 가능 ⭕
int pub1 = classAB.pub;
}
}
package OOP03.encapsulation01.packageTwo;
import OOP03.encapsulation01.packageOne.ClassA;
public class ClassC {
void runSomeThing(){
//📌 ClassA를 상속받지 않았기 때문에 객체를 생성 후 객체 참조 변수를 이용 접근 가능
ClassA classA = new ClassA();
// pri,def,pro ❌
int pub = classA.pub;
//📌 ClassA가 속한 패키지와 다른 패키지이기 때문에, public 변수만 접근이 가능하다.
}
static void runStaticThing() {
//📌 정적 메서드는 클래스 변수만 접근이 가능하다.
}
}
📍 클래스 변수는 어떻게 사용하는 것이 적절할까?
클래스명.정적멤버
형식으로 접근하는 것이 권장된다.
🤔 클래스 변수의 메모리 위치는? -> 스태틱 메모리에 저장되어 모든 곳에서 공유된다.
🤔 클래스 변수는 인스턴스마다 존재하는 것이 아니라, 클래스에 존재한다.
사람 클래스의 다리 개수 -> 클래스 변수 : 2
홍길동의 다리개수...?
강감찬의 다리개수...? 보다는
클래스의 변수로 저장하는 것이 의미적으로도 적절하다.
package OOP03.encapsulation02.packageOne;
public class ClassA {
private int pri = 1;
int def = 1;
protected int pro = 1;
public int pub;
static private int priSt = 2;
static int defSt = 3;
static protected int proSt = 2;
static public int pubSt = 2;
void runSomeThing(){
int priSt1 = ClassA.priSt;
int defSt1 = ClassA.defSt;
int proSt1 = ClassA.proSt;
int pubSt1 = ClassA.pubSt;
int priSt2 = priSt;
int defSt2 = defSt;
int proSt2 = proSt;
int pubSt2 = pubSt;
}
static void runStaticThing() {
int priSt1 = ClassA.priSt;
int defSt1 = ClassA.defSt;
int proSt1 = ClassA.proSt;
int pubSt1 = ClassA.pubSt;
int priSt2 = priSt;
int defSt2 = defSt;
int proSt2 = proSt;
int pubSt2 = pubSt;
}
}
package OOP03.encapsulation02.packageOne;
public class ClassA {
private int pri = 1;
int def = 1;
protected int pro = 1;
public int pub;
static private int priSt = 2;
static int defSt = 3;
static protected int proSt = 2;
static public int pubSt = 2;
void runSomeThing(){
int priSt1 = ClassA.priSt;
int defSt1 = ClassA.defSt;
int proSt1 = ClassA.proSt;
int pubSt1 = ClassA.pubSt;
int priSt2 = priSt;
int defSt2 = defSt;
int proSt2 = proSt;
int pubSt2 = pubSt;
}
static void runStaticThing() {
int priSt1 = ClassA.priSt;
int defSt1 = ClassA.defSt;
int proSt1 = ClassA.proSt;
int pubSt1 = ClassA.pubSt;
int priSt2 = priSt;
int defSt2 = defSt;
int proSt2 = proSt;
int pubSt2 = pubSt;
}
}
package OOP03.encapsulation02.packageOne;
public class ClassB {
ClassA classA = new ClassA();
void runSomeThing(){
// int priSt1 = ClassA.priSt;
int defSt1 = ClassA.defSt;
int proSt1 = ClassA.proSt;
int pubSt1 = ClassA.pubSt;
// 상속받지 않았기 때문에 ClassB에는 해당 변수들이 없음...
// int priSt2 = priSt;
// int defSt2 = defSt;
// int proSt2 = proSt;
// int pubSt2 = pubSt;
}
static void runStaticThing() {
// int priSt1 = ClassA.priSt;
int defSt1 = ClassA.defSt;
int proSt1 = ClassA.proSt;
int pubSt1 = ClassA.pubSt;
// 📌 정적 멤버를 객체 참조 변수를 이용해서도 접근할 수 있지만 이런 방식은 추천되지 않는다.
// 클래스 변수는 클래스명.변수명이 적절하다.
ClassA classA1 = new ClassA();
// int priSt2 = classA1.priSt;
int defSt2 = classA1.defSt;
int proSt2 = classA1.proSt;
int pubSt2 = classA1.pubSt;
}
}
\package OOP03.encapsulation02.packageTwo;
import OOP03.encapsulation02.packageOne.ClassA;
public class ClassAB extends ClassA {
void runSomeThing(){
// int priSt1 = ClassA.priSt;
// int defSt1 = ClassA.defSt;
int proSt1 = ClassA.proSt;
int pubSt1 = ClassA.pubSt;
// ClassAB는 CalssA를 상속받아서 바로 접급할 수 있음.
// int priSt2 = priSt;
// int defSt2 = defSt;
int proSt2 = proSt;
int pubSt2 = pubSt;
}
static void runStaticThing() {
// int priSt1 = ClassA.priSt;
// int defSt1 = ClassA.defSt;
int proSt1 = ClassA.proSt;
int pubSt1 = ClassA.pubSt;
// int priSt2 = priSt;
// int defSt2 = defSt;
int proSt2 = proSt;
int pubSt2 = pubSt;
}
}
package OOP03.encapsulation02.packageTwo;
import OOP03.encapsulation02.packageOne.ClassA;
public class ClassC {
void runSomeThing(){
// 📌 public으로만 가능
int pubSt = ClassA.pubSt;
ClassA classA = new ClassA();
int pubSt1 = classA.pubSt;
}
static void runStaticThing() {
int pubSt = ClassA.pubSt;
ClassA classA = new ClassA();
int pubSt1 = classA.pubSt;
}
}
👉 단순 값이 복사되며, 서로에게 영향을 주지 않는다.
🖥️ 예제코드
package OOP03.reference;
public class CallByValue {
// 기본 자료형 변수를 복사하는 경우 : 단순 복사, 관계 없음
public static void main(String[] args) {
int a = 10;
int b = a;
b = 20;
System.out.println("a = " + a);
System.out.println("b = " + b);
}
}
👉 실행화면
a = 10
b = 20
🤔 객체 참조 변수를 복사하는 경우는 무엇이 복사될까..?
👉 T 메모리내의 힙 메모리에 있는 인스턴스의 주소가 복사된다.
따라서, 각기 다른 객체 참조 변수가 동일한 인스턴스를 참조하게 되고, 서로의 값에 영향을 받게 된다.
방어적 복사, Getter
🖥️ 실습 코드
package OOP03.reference;
import OOP03.polymorphism01.Anlimal;
public class CallByReference01 {
public static void main(String[] args) {
Anlimal ref_a = new Anlimal();
Anlimal ref_b = ref_a;
ref_a.age = 10;
ref_b.age = 20;
System.out.println("ref_a = " + ref_a);
System.out.println("ref_b = " + ref_b);
System.out.println("ref_a.age = " + ref_a.age);
System.out.println("ref_b.age = " + ref_b.age);
}
}
👉 실행화면
ref_a = OOP03.polymorphism01.Anlimal@4c873330
ref_b = OOP03.polymorphism01.Anlimal@4c873330
ref_a.age = 20
ref_b.age = 20