JAVA - 캡슐화

흑이·2022년 5월 18일
0

캡슐화

캡슐화란 특정 객체 안에 관련된 속성기능하나의 캡슐로 만들어 데이터를 외부로부터 보호하는 것을 말합니다.

  1. 데이터 보호의 목적
  2. 내부적으로만 사용되는 데이터에 대한 불필요한 외부 노출을 방지하기 위함


캡슐화 장점

캡슐화의 가장 큰 장점은 정보 은닉(Data Hiding)

  • 즉, 외부로부터 객체의 속성과 기능이 함부로 변경되지 못하게 막고
  • 데이터가 변경되더라도 다른 객체에 영향을 주지 않기에 독립성을 확보할 수 있다.
  • 유지보수코드 확장 시에도 오류의 범위를 최소화할 수 있다.


패키지

패키지란 특정한 목적을 공유하는 클래스인터페이스의 묶음을 의미한다.

  • 패키지는 클래스들을 그룹 단위로 묶어 효과적으로 관리하기 위한 목적을 가지고 있다.
    (우리가 컴퓨터를 사용할 때 폴더를 만들어 관련한 내용들을 넣는 것과 같다고 생각할 수 있다.)

자바에서 패키지는 물리적인 하나의 디렉토리라 할 수 있으며

이 디렉토리는 하나의 계층구조를 가지고 있는데, 계층 구조간 구분은 점(.)으로 표현

  • 패키지가 있는 경우 소스 코드의 첫 번째 줄에 반드시 ‘package 패키지명'이 표시되어야 하고
  • 패키지 선언이 없으면 이름없는 패키지에 속하게 됩니다.
// 패키지를 생성했을 때
package practicepack.test; // 패키지 구문 포함. 패키지가 없다면 구문 필요없음

public class PackageEx {

}

패키지로 클래스를 묶어놓는 것의 장점은

  • 규모가 큰 프로젝트에서는 클래스명 중복이 빈번하게 발생할 수 있는데 패키지명 설정은 클래스명 간의 충돌을 효과적으로 방지할 수 있는 장치


Import문

Import문은 다른 패키지 내의 클래스를 사용하기 위해 사용하며, 패키지 구문과 클래스문 사이에 작성한다.

  • import문은 컴파일러에게 소스파일에 사용된 클래스의 패키지에 대한 정보를 제공
package practicepack.test2; // import문을 사용하는 경우

import practicepack.test.ExampleImp // import문 작성

public class PackageImp {
		public static void main(String[] args) {
			ExampleImp x = new ExampleImp(); // 이제 패키지명을 생략 가능
		}
}

import문은 컴파일 시에 처리가되므로 프로그램의 성능에는 영향을 주지 않는다.



접근 제어자

자바에서 제어자는 클래스, 필드, 메서드, 생성자 등에 부가적인 의미를 부여하는 키워드를 의미

  • (‘파란 하늘', ‘붉은 노을'에서 ‘파란'과 ‘붉은'처럼 명사를 꾸며주는 형용사의 역할)

자바에서 제어자는 크게 접근 제어자와 기타 제어자로 구분 한다.


접근 제어자

public(접근 제한 없음) > protected(동일 패키지 + 하위클래스) > default(동일 패키지) > private(동일 클래스)

  • 이중 default의 경우는 아무런 접근 제어자를 붙이지 않는 것을 의미한다.
  • 변수명 앞에 아무런 접근제어자가 없을 경우, 자동으로 해당 변수의 접근 제어자는 default가 됩니다.

package package1; // 패키지명 package1 

//파일명: Parent.java
class Test { // Test 클래스의 접근 제어자는 default
    public static void main(String[] args) {
        Parent p = new Parent();

//        System.out.println(p.a); // 동일 클래스가 아니기 때문에 에러발생!
        System.out.println(p.b);
        System.out.println(p.c);
        System.out.println(p.d);
    }
}

public class Parent { // Parent 클래스의 접근 제어자는 public
    private int a = 1; // a,b,c,d에 각각 private, default, protected, public 접근제어자 지정
    int b = 2;
    protected int c = 3;
    public int d = 4;

    public void printEach() { // 동일 클래스이기 때문에 에러발생하지 않음
        System.out.println(a);
        System.out.println(b);
        System.out.println(c);
        System.out.println(d);
    }
}

// 출력값
2
3
4

다른 패키지에 속한 경우
package package2; // package2 

//파일명 Test2.java
import package1.Parent;

class Child extends package1.Parent { // package1으로부터 Parent 클래스를 상속
    public void printEach() {
        // System.out.println(a); // 에러 발생!
        // System.out.println(b);
        System.out.println(c); // 다른 패키지의 하위 클래스
        System.out.println(d);
    }
}

public class Test2 {
    public static void main(String[] args) {
        Parent p = new Parent();

//        System.out.println(p.a); // public을 제외한 모든 호출 에러!
//        System.out.println(p.b);
//        System.out.println(p.c);
        System.out.println(p.d);
    }
}
  • package1의 Parent 클래스로부터 상속을 받아 만들어진 Child 클래스를 살펴보면, 같은 클래스와 같은 패키지 안에 있는 private(a)과 default(b) 제어접근자를 사용하는 멤버에는 접근이 불가능한 반면

  • 다른 패키지의 하위 클래스에 접근가능한 protected(c)와 어디서나 접근이 가능한 public(d)에는 접근이 가능하다는 사실을 확인

  • Test2 클래스는 상속받은 클래스가 아니기 때문에 다시 protected(c)에는 접근이 불가능하고 public(d)에만 접근이 가능한 것을 확인할 수 있다.



getter와 setter 메서드

객체지향의 캡슐화의 목적을 달성하면서도 데이터의 변경이 필요한 경우 어떻게 할 수 있나!?

  • private 접근제어자가 포함되어 있는 객체의 변수의 데이터 값을 추가하거나 수정하고 싶을 때
  • 이런 경우 getter와 setter 메서드를 사용할 수 있다.
public class GetterSetterTest {
    public static void main(String[] args) {
        Worker w = new Worker();
        w.setName("김코딩");
        w.setAge(30);
        w.setId(5);

        String name = w.getName();
        System.out.println("근로자의 이름은 " + name);
        int age = w.getAge();
        System.out.println("근로자의 나이는 " + age);
        int id = w.getId();
        System.out.println("근로자의 ID는 " + id);
    }
}

class Worker {
    private String name; // 변수의 은닉화. 외부로부터 접근 불가
    private int age;
    private int id;

    public String getName() { // 멤버변수의 값 
        return name;
    }

    public void setName(String name) { // 멤버변수의 값 변경
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        if(age < 1) return;
        this.age = age;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }
}

//Output
근로자의 이름은 김코딩
근로자의 나이는 30
근로자의 ID는 5

setter 메서드는 외부에서 메서드에 접근하여 조건에 맞을 경우 데이터 값을 변경 가능하게 해준다.

getter 메서드는 이렇게 설정한 특정 데이터를 읽어오는 데 사용하는 메서드

0개의 댓글