캡슐화가 필요한 이유 : 정보를 보호하고, 필요한 경우에만 안전하게 접근할 수 있도록 하기 위해서
접근제어자(Access Modifier) : 클래스, 변수, 메서드, 생성자의 접근 범위를 제한하는 키워드
| 접근제어자 | 클래스 내부 | 패키지 내부 | 상속한 클래스 | 전체 공개 |
|---|---|---|---|---|
| public | O | O | O | O |
| protected | O | O | O | X |
| default | O | O | X | X |
| private | O | X | X | X |
public class Person { // 외부에서 접근 가능
public String name; // 외부에서 접근 가능
private String secret; // 외부에서 접근 불가
public Person() {} // 외부에서 접근 가능
public void methodA() {} // 외부에서 접근 가능
private void methodB() {} // 외부에서 접근 불가
}
void main() {
Person person = new Person(); // 접근 가능
person.name; // 접근 가능
person.secret; // 접근 불가능
person.methodA(); // 접근 가능
person.methodB(); // 접근 불가능
}
캡슐화 된 데이터에 접근 방법 : 게터(Getter), 세터(Setter)
게터(Getter)
public class Person {
private String secret;
public String getSecret() {
return this.secret; // 객체의 secret 속성 반환
}
}
public class Main {
public static void main(String[] args) {
Person p1 = new Person();
p1.secret; // ❌ 직접 접근 불가능
String newSecret = p1.getSecret(); // 게터를 활용해 접근가능
}
}
세터(Setter)
public class Person {
private String secret;
public void setSecret(String secret) {
this.secret = secret; // secret 속성 설정 및 변경
}
}
public class Main {
public static void main(String[] args) {
Person p1 = new Person();
p1.secret = "password"; // 직접 접근, 변경 불가능
p1.setSecret("newPassword"); // 세터를 활용해 접근, 변경가능
}
}
extends : 상속 관계 구현
→ 코드 중복을 줄이고, 유지 보수성을 높일 수 있음
super : 부모클래스의 변수, 메서드에 접근할 때 사용하는 키워드
public class Parent {
public String familyName = "이씨";
}
public class Child extends Parent {
private String familyName = "김씨"
public void superExample() {
System.out.println("자식 클래스의 이름: " + this.familyName);
// super을 통해 부모 클래스의 familyName에 접근
System.out.println("부모 클래스의 이름: " + super.familyName);
}
}
public class Main {
public static void main(String[] args) {
Child child = new Child();
child.superExample();
}
}
// 자식 클래스의 이름: 김씨
// 부모 클래스의 이름: 이씨
super() : 부모 인스턴스의 생성자
public class Child extends Parent {
...
// 생성자 (작성하지 않으면 기본적으로 super()만 들어가있음
public Child() {
super(); // 부모클래스 생성자를 먼저 호출
// 추가 로직은 여기에 작성
}
}
상속의 장점
재사용성 : 부모 클래스의 내용을 물려받아 그대로 재사용할 수 있음
public class Parent {
public String familyName = "이씨";
public int honor = 10;
public void introduceFamily() {
System.out.println("우리 " + this.familyName + " 가문은 대대로 명성을 이어온...");
}
}
class Child extends Parent { // extends 키워드 활용
}
public class Main {
public static void main(String[] args) {
Child child = new Child();
System.out.println(child.honor); // 부모의 속성을 물려받아 사용
System.out.println(child.familyName); // 부모의 속성을 물려받아 사용
child.introduceFamily(); // 부모의 메서드를 물려받아 사용
}
}
확장 : 부모 클래스의 기능을 유지하면서 자식 클래스에서 기능을 확장할 수 있음
→ 자식 클래스에서 새로운 메서드 추가
public class Child extends Parent {
...
// 부모에는 없지만 자식에만 있는 기능
public void showSocialMedia() {
System.out.println("우리 가문은 이제 SNS도 합니다. 팔로우 부탁드려요!");
}
}
메서드 오버라이딩(overriding) : 부모 메서드를 자식 클래스에서 변경하여 재정의하는 것