2023-12-15 (7일차) - OOP, 상속, 인력관리소 문제

·2023년 12월 15일

📅 2023-12-15, 7일차

OOP의 특징

  1. 캡슐화 (Encapsulation)
    • 외부에 노출할 필요가 없는 정보들은 은닉 (정보은닉)
    • 정보 은닉(information hiding): 필요가 없는 정보는 외부에서 접근하지 못하도록 제한하는 것
    • 높은 응집도, 낮은 결합도를 유지하여 유연함과 유지보수성 증가
    • ex) 마트에서 구매자는 상품명과 가격만 알면될 뿐, 뒤에 원재료와 재질각 종 다양한 정보는 몰라도 된다
      필요한 정보만 보여주게끔 설계해야 된다는 의미
  2. 추상화 (Abstraction)
    • 객체의 공통된 속성들 중 필요한 부분을 포착해서 클래스로 정의하는 설계 기법
    • 구체적인 사물들의 공통적인 특징을 파악해서 이를 하나의 개념(집합)으로 다루는 것
  3. 다형성(Polymorphism)
    • 같은 형태이지만 다른 기능을 하는 것
    • 서로 다른 클래스의 객체가 같은 메시지를 받았을 때 각자의 방식으로 동작하는 능력
    • 오버라이딩(Overriding) 은 상위 클래스가 가지고 있는 메서드를 하위 클래스가 재정의해서 사용
    • 오버로딩(Overloading) 은 이름의 메서드 여러개를 가지면서 매개변수의 유형과 개수가 다르도록 하는 기술
  4. 상속성,재사용(Inheritance)
    - 부모 클래스가 자손 클래스에게 속성을 물려주는 것
    - 코드의 재사용
    - 여러 개체들이 가진 공통된 특성을 부각시켜 하나의 개념이나 법칙으로 성립시키는 과정
    출처 - https://theheydaze.tistory.com/603

상속

  • 클래스에 extends를 사용해서
    다른 클래스에(부모클래스) 있던 메소드를 다른 클래스(자식클래스)로 상속을 시켜주는 개념.

상속을 쓰는 이유?

  • 코드 재사용
  • 클래스들간의 관계 성립

부모클래스

  • (속성과 기능을) 물려주는 클래스

자식클래스

  • (속성과 기능을) 물려받는 클래스
  • 다중상속 불가능
    • 누구의 클래스에서 상속받는건데? 누구꺼?

오버라이딩 과 오버로딩의 차이

  • 오버라이딩: 메소드를 덮어씌우는 과정

  • 오버로딩: 같은 메소드를 사용하는데 각각의 다른 매개변수를 사용해서 두 개의 다른 메소드처럼 처리하는 것

AB Test

  • A is B
  • 자식클래스는(A) 부모클래스이다(B)
  • 예) 청둥오리는 오리이다
class 오리 { // 부모클래스
}

// AB Test 
//       A      is     B
class 청둥오리 extends 오리 { // 자식클래스
}
  • 만약에 A is B = 오리는 청둥오리다 라고하면 말이 안된다
  • 관계 성립이 안된다는 뜻이고 상속을 사용하면 안된다.

복잡한 상속

  • 꼬여있고 복잡하게 상속받은 경우를 복잡한 상속이라고한다
  • AB Test 통과하지 않고 억지로라도 상속받는 경우 나중에 문제가 커질 수 있다
class Main {
  public static void main(String[] args) {

    Parents p = new Parents();
    p.a();

    Child c = new Child();
    c.a();
    c.b();

    // Child pc1 = new Parents(); // 에러 이유: 자식이 여러명의 친부모를 가질 수 없음

    Parents pc2 = new Child(); // 부모는 여러 자식을 낳을 수 있음
    pc2.a();
    pc2.b(); // 에러 이유: 부모는 자식한테 물려받을 수 없으니, 자식이 가지고있는 함수를 받아 실행할 수 없음
    // 형변환(casting) 되는 과정에서 Child객체가 Parents객체처럼 보여야하니, Child객체가 b메서드를 버리고 Parents처럼 보이게 함
    // 버리지않고 가능하게 하고싶다면, Parents 클래스안에 b메서드를 넣어놓으면 됨. abstract void b(); 
      // Parents 클래스를 abstract 클래스로 바꾸기.

    // 실수 정수를 예로 들자면 - 정수는 실수안에 포함되지만, 실수가 정수안에 포함이 되진 않음

    //  A is B . AB Test

  }
}

class Parents {

  void a() {
    System.out.println("a");
  }

  // abstract void b(); 
  // 이거 사용하려면 클래스명도 앞에도 abstract로 바꿔야함

}

class Child extends Parents {

  void b() {
    System.out.println("b");
  }
}

추상메서드 (abstract)

  • 구현하지 않고 버튼유지용으로 사용되는 메서드는 abstract를 붙여준다
    • 건드리면 안됨
  • abstract 메서드를 가지고있는 클래스는 무조건 abstract class로 변경되야 한다
  • abstract 메서드를 상속받는 경우 무조건 오버라이딩을 해야한다
    • 왜? 빈 깡통메서드를 상속받았기 때문에 오버라이딩을 통해 기능을 재정의 해서 넣어야 한다
class Main {
	public static void main(String[] args) {
		
		Parents p = new Parents();
		p.a();

		Child c = new Child();
		c.a();

	}
}

abstract class Parents {

	abstract void hi();

class Child extends Parents { 
	// 오버라이딩 해야함
	
	void a() {
		System.out.println("Hello");
	}
}
  • abstract 클래스 안에 구상메서드 추상메서드 둘다 들어갈 수 있음
  • 순도 100% 추상메서드만 가지는 추상클래스는 interface 클래스
  • interface 클래스에서 상속받는 경우 자식클래스는 extends 대신 implements를 사용해서 상속받고 메서드들 오버라이딩해서 재정의한다
class Main {
	public static void main(String[] args) {
		
		Parents p = new Parents();
		p.a();

		Child c = new Child();
		c.a();

	}
}

interface class Parents {

	void a();
    void b();

class Child implements Parents { 
	// 오버라이딩 해야함
	
	void a() {
		System.out.println("Hello");
	}
    void b() {
		System.out.println("Bye");
	}
}
  • extends를 사용해서 다중상속이 안된다고 했는데, abstract 클래스들로부터는 다중 implements가 가능하다

인력관리소 문제 & 정답풀이

인력관리소 문제

// 문제 : 아래가 실행되도록 해주세요.

class Main {
  public static void main(String[] args) {
    사람인력관리소 a사람인력관리소 = new 사람인력관리소();

    a사람인력관리소.add사람("홍길순", 33);
    // 나이가 33살인 1번째 사람(홍길순)이 추가되었습니다.
    a사람인력관리소.add사람("홍길동", 20);
    // 나이가 20살인 2번째 사람(홍길동)이 추가되었습니다.
    a사람인력관리소.add사람("임꺽정", 30);
    // 나이가 30살인 3번째 사람(임꺽정)이 추가되었습니다.

    사람 a사람1 = a사람인력관리소.get사람(1);
    a사람1.자기소개();
    // 저는 1번, 홍길순, 33살 입니다.

    사람 a사람2 = a사람인력관리소.get사람(2);
    a사람2.자기소개();
    // 저는 2번, 홍길동, 20살 입니다.

    사람 a사람3 = a사람인력관리소.get사람(3);
    a사람3.자기소개();
    // 저는 3번, 임꺽정, 30살 입니다.
  }
}

인력관리소 정답 및 풀이

// 문제 : 아래가 실행되도록 해주세요.

class Main {
  public static void main(String[] args) {
    사람인력관리소 a사람인력관리소 = new 사람인력관리소();

    a사람인력관리소.add사람("홍길순", 33);
    // 나이가 33살인 1번째 사람(홍길순)이 추가되었습니다.
    a사람인력관리소.add사람("홍길동", 20);
    // 나이가 20살인 2번째 사람(홍길동)이 추가되었습니다.
    a사람인력관리소.add사람("임꺽정", 30);
    // 나이가 30살인 3번째 사람(임꺽정)이 추가되었습니다.

    사람 a사람1 = a사람인력관리소.get사람(1);
    a사람1.자기소개();
    // 저는 1번, 홍길순, 33살 입니다.

    사람 a사람2 = a사람인력관리소.get사람(2);
    a사람2.자기소개();
    // 저는 2번, 홍길동, 20살 입니다.

    사람 a사람3 = a사람인력관리소.get사람(3);
    a사람3.자기소개();
    // 저는 3번, 임꺽정, 30살 입니다.
  }
}

class 사람인력관리소 {

  사람[] 사람들 = new 사람[100];

// 전역변수를 사용해서 제대로 된 저장소를 만들면 add사람 함수 안에 있는 사람들의 정보를 꺼내와서 저장할 수 있다
// 그치만 사람이 올때마다 추가해줘야하는 번거로움이 있으니 배열객체를 만들면 조금 더 낫다

//  사람 a사람0;
//	사람 a사람1;
//	사람 a사람2;

  int 마지막사람의번호 = 0;

  void add사람(String 이름, int 나이) {
    int 번호 = 마지막사람의번호 + 1;
    사람 a사람 = new 사람(); // 사람들의 정보를 저장해서 사용 할 저장소를 만들기
    // 객체말고 int 이름; 이런식으로 저장하면 한사람의 정보들이 흩어진다.
    // 그러나 저장하는 행위는 안함. 정보의 조립을 한거다.
    a사람.이름 = 이름;
    a사람.나이 = 나이;
    a사람.번호 = 번호;

    사람들[번호 - 1] = a사람;

//		if (번호 == 1) {
//			a사람0 = a사람;
//		} else if (번호 == 2) {
//			a사람1 = a사람;
//		} else if (번호 == 3) {
//			a사람2 = a사람;
//		}

    System.out.printf("나이가 %d살인 %d번째 사람(%s)이 추가되었습니다.\n", 나이, 번호, 이름);
    마지막사람의번호 = a사람.번호;

  }

  사람 get사람(int 번호) {

//		if (번호 == 1) {
//			return a사람0;
//		} else if (번호 == 2) {
//			return a사람1;
//		} else if (번호 == 3) {
//			return a사람2;
//		}
    return 사람들[번호 - 1];
  }
}

class 사람 {

  String 이름;
  int 번호;
  int 나이;

  void 자기소개() {

    System.out.printf("저는 %d번, %s, %d살 입니다.\n", 번호, 이름, 나이);

  }

}
  • 초반에 실행하면 null pointer exception이 떠서 당황...
    return value를 디폴트로 해놓는다고 null값을 반환해버려서 발생했던 것이었다.
    사람 get사람(int 번호) {
		// return null;
        return new 사람(); // 일단 이렇게 객체하나 return해놓고 문제를 더 풀어가보기
	}
  • get사람 메서드 실행하면
  - "저는 0번, null, 0살 입니다." 

이런식으로 디폴트값만 나와서 멘붕...

  • 디폴트값이라는 뜻은 데이터가 들어가지 않는다라는걸 깨닳았다.
  • 그렇다면 저장하는 공간을 만들어서 데이터를 넣어야하는데, 어떻게 만들지 막막했다.
  • 변수 하나하나 만들어면 코드가 복잡해지는거 같고 이젠 뭐가 어디서 연결되는지 눈으로 쫒아가지 못하는 지경까지 가버려서 결국 다 지우고 처음부터 다시 메서드 만드는 것부터 시작했다
  • 강사님 풀이 듣고도 반은 이해가 가고 반은 그냥 내 멘탈이 날라간듯...같은 코드를 계속 보고있자니 집중력마저 떨어져버림
  • 집에 와서 강사님 풀이를 토대로 다시 해봄
  • 확실히 자기소개() 메서드 실행 시 디폴트 값이 나오는 부분, 그리고 정보를 어디에 어떻게 저장해야하는지가 관건이었고 제일 어려운 부분이었다.
  • add사람() 메서드에 정보를 저장하기는 쉬웠다 매개변수가와 인자가 있었기 때문에, 근데 get사람() 메서드에 정보를 저장하는 방법은 달라야했다.
  • 사람클래스 안에 사람들의 정보를 필드로 생성 후, 그것을 add사람() 메서드에서 객체 하나 만들어 연결해서 정보를 저장 후 그걸 또 사람인력관리소 클래스에 전역변수로 저장해놓는게 핵심이었다.
  • 이후론 조건문을 사용하거나 배열을 사용해서 add사람()과 get사람() 안에서 사람들의 번호만 제대로 불러온다면 전역변수에 저장된 정보가 잘 들어가서 출력 됨!
profile
hello world

0개의 댓글