본문 바로가기
Java

[JAVA] 객체지향 언어의 특징 & 캡슐화 & 상속

by 코코형아 2024. 2. 12.

7. 객체지향 언어의 특징 & 캡슐화 & 상속

 

객체지향 언어의 특징


 

객체지향 언어의 특징 - A PIE

 

 

그 중 캡슐화와 상속에 대해 좀 더 자세히 알아보자.

 

 

 

 

 

Encapsulation(데이터 은닉과 보호)


 

누군가가 내 정보를 마음대로 바꿀 수 있다면 => 개인정보의 탈취 위험도 있고, 시스템에 심각한 오류를 줄 가능성도 있다!

 

따라서 정보를 보호하기 위해서는

  • 변수는 private로 접근제한자를 설정하여 외부에서의 접근을 막고
  • 공개되는 메서드를 통한 접근 통로를 마련하는 것이 좋다 (setter / getter)

 

객체의 생성 제어와 Singleton 디자인 패턴

  • 변수를 private로 설정하여 외부의 접근을 막듯이, 객체의 생성을 제한해야 한다면 어떻게 해야 할까?

 

  • 객체의 생성을 제한해야 하는 이유
    1. 여러 개의 객체가 필요 없는 경우
      • 객체를 구별할 필요가 없는 경우 = 수정 가능한 멤버 변수가 없고 기능만 있는 경우
      • 이러한 객체를 stateless한 객체라고 한다.
    2. 객체를 계속 생성/삭제 하는데 많은 비용이 들어서 재사용이 유리한 경우

 

  • 객체의 생성을 제한하기 위해 나온 Singleton 디자인 패턴
    • 외부에서 생성자 접근 금지 → 생성자의 접근 제한자를 private로 설정
    • 내부에서는 private에 접근 가능하므로 직접 객체 생성 → 멤버 변수이므로 private 설정
    • 외부에서 private member에 접근 가능한 getter 생성 → setter는 불필요
    • 객체 없이 외부에서 접근할 수 있도록 getter와 변수에 static 추가
    • 외부에서는 언제나 getter를 통해서 객체를 참조하므로 하나의 객체 재사용

 

 

 

 

Polymorphism(다형성)


 

다형성 : 하나의 객체가 많은 형(타입)을 가질 수 있는 성질

 

다형성의 활용 예1 - 다른 타입의 객체를 다루는 배열”

  • 배열의 특징 : 같은 타입의 데이터를 묶음으로 다룬다.
  • 다형성으로 다른 타입의 데이터 (Person, SpiderMan)을 하나의 배열로 관리
void beforePoly() {
	Person[] persons = new Person[10];
	persons[0] = new Person();
	SpiderMan[] spiderMans = new SpiderMan[10];
	spiderMans[0] = new SpiderMan();
}

void afterPoly() {
	Person[] persons = new Person[10];
	persons[0] = new Person();
	persons[1] = new SpiderMan();
}

 

  • Object는 모든 클래스의 조상!
    • Object의 배열은 어떤 타입의 객체라도 다 저장할 수 있음
  • 자바의 자료 구조를 간단하게 처리할 수 있음
    • 이와 같은 특성을 이용하여 Collection API가 등장하게 됨
  • 기본형은 Object가 아니므로 담을 수 없다!
    • 하지만 밑에 예시를 보자
public void useObjectArray() {
      // TODO:Object []을 선언하고 다양한 객체를 저장하고 저장된 클래스 타입을 출력하세요.
    	Object[] objs = new Object[4];
    	objs[0] = "hello";
    	objs[1] = objs;
    	objs[2] = new SpiderMan();
    	objs[3] = 3; // 기본형은 안된다고 했는데?! -> auto boxing
//    	objs[3] = Integer.valueOf(3); // 실제로는 Integer라는 refer클래스로 들어간다.
    	
    	for (Object obj : objs) {
    		System.out.println(obj.getClass().getName());
    	}
        // END
}

 

분명 기본형은 Object가 아니므로 담을 수 없다 했지만, 기본형을 담으려고 할 때 auto boxing이 일어나

Integer라는 refer클래스로 담아지게 된다.

💡 결론 : 기본형(primitive type)이 Wrapper클래스의 auto boxing을 통해 참조형(reference type)으로 바껴 담을 수 있음!

 

 

다형성의 활용 예2 - 매개변수의 다형성”

  • API에서 파라미터로 Object를 받는다는 것은 모든 객체를 처리한다는 말이다.
  • 조상을 파라미터로 처리한다면 객체의 타입에 따라 메서드를 만들 필요가 없어진다.
public void println(Object x) {
	String s = String.valueOf(x);
	synchronized(this) {
		print(s);
		newLine();
	}
}

 

 

 

 

다형성과 참조형 객체의 형 변환


  • 메모리에 있는 것과 사용할 수 있는 것의 차이
  • 메모리에 있더라도 참조하는 변수의 타입에 따라 접근할 수 있는 내용이 제한됨
  • 하위 타입을 상위 타입으로 형 변환 → 묵시적 형 변환(캐스팅)
    • 자손 타입의 객체를 조상 타입으로 참조 : 형 변환 생략 가능
    • → 왜냐면 조상의 모든 내용이 자식에 있기 때문에 걱정할 필요 없다
byte b = 10;
int i = b;

Phone phone = new Phone();
Object obj = phone;

 

 

  • 상위 타입을 하위 타입으로 형 변환 → 명시적 형 변환(캐스팅)
    • 조상 타입을 자손 타입으로 참조 : 형 변환 생략 불가
int i = 10;
byte b = (byte)i;

Phone phone = new SmartPhone();
SmartPhone sPhone = (SmartPhone)phone;

 

 

  • 조상을 무작정 자손으로 바꿀 수는 없음.
    • instanceof 연산자
      • 실제 메모리에 있는 객체가 특정 클래스 타입인지 boolean으로 리턴
if (superman isinstanceof Person)

 

 

 

 

 

 

참조 변수의 레벨에 따른 객체의 멤버 연결 (매우 중요한 내용!)


class SuperClass {
	String x = "super";

	public void method() {
		System.out.println("super class method");
	}
}

class SubClass extends SuperClass {
	Stirng x = "sub";

	@override
	public void method() {
		System.out.println("sub class method");
	}
}



public class MemberBindingTest {
	
	public static void main(String[] args) {
		SubClass subClass = new SubClass();
		System.out.println(subClass.x); // sub
		subClass.method(); // sub class method
	
		SuperClass superClass = subClass;
		System.out.println(superClass.x); // super(정적바인딩)
		superClass.method(); // sub class method(동적바인딩)
		// superClass의 method가 실행되는 것이 아니라 override로 재정의 된 subClass의 method가 실행된다.
		// -> 동적 바인딩(dynamic binding)
	}
}

 

  • 정적 바인딩(static binding)
    • 정적 바인딩은 컴파일 시 호출되는 바인딩을 뜻하며, 점프 (연결)할 주소가 결정되어있어 미리 바인딩되는 형태를 뜻한다.
    • 상속 관계에서 객체의 멤버 변수(static/instance)가 중복될 때 또는 static method가 정적바인딩이다.
  • 동적 바인딩(dynamic binding)
    • 동적 바인딩은 프로그램 실행 시에 호출되며, 실행파일 생성 시에는 아직 바인딩이 되지 않고 보류되는 형태이다. 프로그램 실행 시, 사용될 객체의 클래스 형에 의해 호출될 함수가 결정된다.
    • 다형성을 이용해서 메서드 호출이 발생할 때 runtime에 메모리의 실제 객체의 타입으로 결정
    • 상속 관계에서 객체의 instance method가 재정의 되었을 때 마지막에 재정의 된(가장 자식) 자식 클래스의 메서드가 호출
      • 최대한 메모리에 생성된 실제 객체의 최적화 된 메서드가 동작한다.