Java 객체지향 프로그래밍 - 은닉화(Encapsulation) 와 접근 제한자 (modifier)
🧑‍💻 𝗣𝗿𝗼𝗴𝗿𝗮𝗺𝗺𝗶𝗻𝗴/Java

Java 객체지향 프로그래밍 - 은닉화(Encapsulation) 와 접근 제한자 (modifier)

Java 객체지향 프로그래밍
1. Java 객체지향 프로그래밍 - 상속 (Inheritance)
2. Java 객체지향 프로그래밍 - 메서드 오버라이딩 (Overriding)
3. Java 객체지향 프로그래밍 - 은닉화(Encapsulation) 와 접근 제한자 (modifier)
4. Java 객체지향 프로그래밍 - 싱글톤 패턴 (Singleton)
5. Java 객체지향 프로그래밍 - 다형성 (Polymorphism)

 

 

 

 은닉화 (캡슐화: Encapsulation) 

개요

예를 들어, 수업을 열심히 들어 노트에 필기를 했는데 갑자기 옆에 있던 모르는 사람이 당신의 필기 내용을 바꾼다고 합시다.

기분이 어떻습니까? 좀 이상하죠?

클래스도 마찬가지 입니다. 갑자기 옆에 있던 클래스가 내 멤버 변수를 맘대로 바꾸면 기분이 좋지 않습니다.

그래서 사용하는 것이 바로 캡슐화 입니다.

이러한 캡슐화를 위해서 사용되는 것이 바로 private 접근 제한자 입니다.

 

다시 아까의 경우로 돌아가서, 내 필기를 가지고 다른 옆에 있던 친구한테 보여주니 친구가 어떤 부분이 틀렸다고 정정을 해줍니다.

이건 클래스에서 getter, setter 에 해당합니다.

내가 알고있는 어떠한 안정적인 접근 통로를 가지고 멤버들을 고치는 것은 괜찮습니다.

 

 

예시

package first.subject.m07.encapsulation;


public class MyNote {
	public String title;
	private String content;


	public String getTitle() {
		return title;
	}


	public void setTitle(String title) {
		this.title = title;
	}


	public String getContent() {
		return content;
	}


	public void setContent(String content) {
		this.content = content;
	}


	@Override
	public String toString() {
		return "MyNote [title=" + title + ", content=" + content + "]";
	}

}
package first.subject.m07.encapsulation;


public class Other {

	public static void main(String[] args) {
		MyNote note = new MyNote();
		note.title = "내가 니 노트 제목 바꿨어"; // public
		note.setContent("내용도 바꿔도 되니?"); // private

		System.out.println(note.title);
		System.out.println(note.getContent());
	}
}

MyNote 를 보시면, title 은 public 으로 content 은 private 로 선언을 했습니다.

아래서 다룰 것이지만 잠깐 말해보자면 public 은 공공재, private 는 사유재 입니다.

그래서 title 같은 경우는 그냥 막 값을 할당해도 되지만,

content 같은 경우는 setContent() 라는 접근 통로를 이용해서 변경을 해야합니다.

만약 setContent() 를 이용해서 맘에 안드는 내용이 들어온다면 거절을 해도 됩니다.

이런식으로 은닉화를 이용해 접근 통로 로직을 내가 원하는 식으로 변경을 할 수 있습니다.

 

 

 

 제한자 (modifier) 

접근 제한자: private, ( default ), protected, public
그 외: static, final, abstract, synchronized

접근 제한자

접근 제한자는 클래스, 변수, 메서드 선언부에 함께 사용되어 부가적인 의미를 부여합니다.

보통 접근 제한자를 제일 먼저 씁니다. 예를 들어 public static main() 이런식으로요.

하나의 대상에 여러 제한자가 가능하나, 접근 제한자는 딱 하나만 써야합니다.

참고로 여기서 default 는 진짜 default 키워드를 말하는 것이 아닙니다. 아무것도 쓰여지지 않은 상태를 이릅니다.

 

 

private

package first.subject.m07.encapsulation.Private;


public class MyNote {
	private String content;

}
// 같은 패키지, 다른 클래스
package first.subject.m07.encapsulation.Private;


public class Other {
	public static void main(String[] args) {
		MyNote note = new MyNote();
		note.content = "노트 좀 보여주라";
	}
}

private 는 객체 자기 자신만 쓸 수 있는 것입니다. 그래서 다른 클래스에서는 함부로 접근이 불가능 합니다.

따라서 getter, setter 를 통해서 접근이 가능하여 은닉화가 가능해집니다.

위처럼 코드를 치면 저렇게 에러가 납니다.

 

 

( default )

package first.subject.m07.encapsulation.Private;


public class MyNote {
	String content;
}
// 같은 패키지, 다른 클래스
package first.subject.m07.encapsulation.Private;


public class Friend {
	public static void main(String[] args) {
		MyNote note = new MyNote();
		note.content = "나 니 친구인데, 노트 좀 보여주라";

		System.out.println(note.content);
	}
}

// 다른 패키지, 다른 클래스
package first.subject.m07.encapsulation;


public class Others {
	public static void main(String[] args) {
		MyNote note = new MyNote();
		note.content = "나는 친구는 아니지만, 노트 좀 보여주라";
	}
}

만약 접근 제한자를 아무것도 쓰지 않았다면 같은 클래스, 같은 패키지 내에서만 멤버를 사용할 수 있습니다.

그래서 MyNote 랑 같은 패키지인 Friend 는 content 를 고칠 수 있지만,

패키지가 다른 Other 은 content 를 고칠 수 없어 저렇게 오류가 납니다.

 

 

protected

package first.subject.m07.encapsulation.Protected;


public class MyNote {
	protected String content;

}
// 같은 패키지, 다른 클래스
package first.subject.m07.encapsulation.Protected;


public class Friend {
	public static void main(String[] args) {
		MyNote note = new MyNote();
		note.content = "노트 좀 보여주라";

		System.out.println(note.content);
	}
}

// 다른 패키지, 자손 클래스 
package first.subject.m07.encapsulation;


import first.subject.m07.encapsulation.Protected.MyNote;


public class OtherFriend extends MyNote {
	public static void main(String[] args) {
		OtherFriend of = new OtherFriend();
		of.content = "나는 이미 네가 노트를 줬어.";

		System.out.println(of.content);
	}
}

protected 는 패키지가 달라도 자손이면 그냥 가능합니다. 대신 다른 패키지에서 자손이 아니면 불가능합니다.

멤버 변수를 가져올 때는 MyNote 인스턴스를 생성해서 사용하는 것이 아니라 this 키워드를 사용해야 합니다.

혹은 상속 받았으니까 자기 자신을 인스턴스 생성하여 of.content 이런식으로 사용할 수 있습니다.

 

 

public

package first.subject.m07.encapsulation.Public;


public class MyNote {
	public String content = "그냥 노트를 칠판에 걸어놓을게;";

}
// 다른 패키지, 다른 클래스
package first.subject.m07.encapsulation;


import first.subject.m07.encapsulation.Public.MyNote;


public class Others {
	public static void main(String[] args) {
		MyNote note = new MyNote();
		note.content = "나는 친구는 아니지만, 노트 좀 보여주라";

		System.out.println(note.content);
	}
}

public 은 그냥 다 가능하다고 보시면 됩니다.

다른 패키지여도, 다른 클래스여도, 자손 클래스가 아니어도 다 접근이 가능합니다.

 

 

그외 제한자

static 은 인스턴스를 굳이 생성하지 않아도, 클래스로 바로 접근할 수 있습니다.

보통 알고리즘에서 전역으로 쓸 때 많이 사용하죠.

또한, static {} 같은 initializer 를 통해서 static 멤버를 초기화할 수 있습니다.

이는 여러번 사용이 가능합니다. 실행을 하면 제일 먼저 실행이 됩니다.

 

그리고 final 제한자는 상수를 만들 때 사용합니다.

final 제한자가 붙으면 완벽한 클래스이고, 메서드이고, 변수라는 것이라서

변경의 여지가 없다는 것입니다.

final class : 상속 방지
final method: 오버라이딩 방지
final local variable: 상수화

final 에서 구분해야할 것은 array constant 와 array final 입니다.

// array constant
int[] intArray = {1,2,3};
intArray = {4,5,6}; // error

// array final
final int[] intArray = new int[3];
intArray = new int[4] // error
intArray[1] = 10;
intArray[1] = 20; // ok

보통 배열을 저런식으로 {} 을 이용해서 한번에 초기화를 하면 재할당이 불가합니다.

이와 array final 이 헷갈릴 수 있는데 array final 은 각 요소를 수정할 수 있습니다.

하지만 final 이기 때문에 new 를 사용해서 재할당은 불가합니다.

 

abstract 는 추상 메서드, 클래스를 만듭니다.

해당 메서드를 가진 객체를 상속받은 자식 클래스는 해당 메서드를 꼭 재정의해서 사용해야 합니다.

멤버 변수에는 못만듭니다.

 

 

 

 

 

 

 

# java modifier # 자바 접근 제한자 # 자바 private getter setter # 자바 protected # java 은닉화 # 자바 캡슐화


 

728x90