[Java] 객체지향프로그래밍 & 다형성

ina·2022년 8월 18일
0
post-thumbnail

객체지향 프로그래밍(OOP: Object-Oriented-Programming)

  • 데이터를 객체 단위로 나눠서 작업
  • 객체 간의 상호작용을 통해 프로그램이 동작 ex) JAVA, C# …
  • 장점
    • 캡슐화(=은닉화) 클래스의 내부 변수와 메소드를 하나로 패키징하는 특징
    • 다형성, 상속이 가능해서 코드의 재사용성이 증가하고 유지보수에 용이

다형성(Polymorphism)

  • 하나의 객체가 여러 가지 타입을 가질 수 있는 것 ⇒ 하나의 메소드나 클래스가 다양한 방법으로 동작하는 것
  • 구현방법 : 메소드 재정의 + 타입변환
    • 여러 객체들 중 공통 특성으로 타입을 추상화하고 그것을 상속(인터페이스라면 구현)해야 한다 ⇒ 이러한 특성들을 유기적으로 잘 활용했을 때 객체 지향에 가까운 코드를 작성할 수 있다
  • 오버로딩(Overloading)
    • 생성자 오버로딩 : 매개 변수를 달리하는 생성자를 여러 개 선언하는 것
      public class Ex3 {
      
      	public static void main(String[] args) {
      		/*
      		 * 생성자 오버로딩
      		 * - 메서드 오버로딩과 동일
      		 * - 생성자 호출 시 다양한 형태의 파라미터를 전달하여
      		 *   객체를 다양하게 초기화하는 목적
      		 * */
      		
      		// 파라미터 생성자를 하나라도 정의할 경우
      		// 컴파일러에 의해 기본 생성자가 자동적으로 생성되지 않음
      		// 따라서, 기본 생성자를 호출해야 하는 경우 직접 기본 생성자를 정의!
      		Person2 p = new Person2();
      		p.showPersonInfo();
      		
      		System.out.println("------------------------------------");
      		
      		Person2 p2 = new Person2("홍길동", "901010-1234567");
      		p2.showPersonInfo();
      		
      		System.out.println("-------------------------------------");
      		
      		Person2 p3 = new Person2("한국", "홍길동", "901010-1234567");
      		p3.showPersonInfo();
      	}
      
      }
      
      class Person2 {
      	String nation;
      	String name;
      	String jumin;
      	
      	public Person2() {
      		System.out.println("Person2() 생성자 호출됨!");
      	}
      	
      	// 국가는 자동으로 "대한민국"으로 초기화하고
      	// 파라미터 2개(name, jumin)를 전달받아 초기화하는 생성자 정의
      	public Person2(String newName, String newJumin) {
      		System.out.println("Person2(String, String) 생성자 호출됨!");
      		nation = "대한민국";
      		name = newName;
      		jumin = newJumin;
      	}
      	
      	// 파라미터 3개(nation, name, jumin)를 전달받아 초기화하는 생성자 정의
      	public Person2(String newNation, String newName, String newJumin) {
      		System.out.println("Person2(String, String, String) 생성자 호출됨!");
      		nation = newNation;
      		name = newName;
      		jumin = newJumin;
      	}
      	
      	// 국가명, 이름, 주민번호를 출력하는 showPersonInfo() 메서드 정의
      	public void showPersonInfo() {
      		System.out.println("국가 : " + nation);
      		System.out.println("이름 : " + name);
      		System.out.println("주민번호 : " + jumin);
      	}
      	
      }
    • 메소드 오버로딩 : 클래스 내에 같은 이름의 메소드를 여러 개 선언하는 것
      public class Ex2 {
      
      	public static void main(String[] args) {
      		/*
      		 * 메서드 오버로딩(Method Overloading) = 메서드 다중 정의
      		 * - 동일한 이름의 파라미터가 다른 메서드를 여러번 정의하는 것
      		 * - 비슷한 기능을 수행하지만, 전달받은 데이터의 타입이 다른 경우
      		 *   메서드 이름을 각각 따로 정의하지 않고, 동일한 이름으로
      		 *   파라미터만으로 구분되는 메서드를 여러개 정의하는 것
      		 * - 주의사항! 메서드 시그니쳐(이름, 리턴타입, 파라미터, 접근제한자) 중
      		 *   파라미터를 제외한 나머지는 동일하게 정의함
      		 *   
      		 * < 메서드 오버로딩 규칙(택 1) >
      		 * 1. 메서드 파라미터의 데이터타입이 달라야 함
      		 * 2. 메서드 파라미터의 갯수가 달라야 함
      		 * */
      		
      		NormalMethod nm = new NormalMethod();
      		nm.add(10,20);
      //		nm.add(1.0, 3.14); // double, double타입은 전달 불가
      		nm.addDouble(1.0, 3.14); 
      		
      		System.out.println("-----------------------------");
      		
      		// 오버로딩이 적용된 메서드를 정의한 OverloadingMethod 인스턴스 생성
      		OverloadingMethod om = new OverloadingMethod();
      		om.add(20, 30); // add(int, int) 호출됨
      		om.add(1.23, 3.456); // add(double, double) 호출됨
      		om.add(1, 2, 3);
      	}
      
      }
      
      class OverloadingMethod {
      	// 오버로딩 기능을 활용하여 두 수를 전달받아 덧셈 결과를 출력하는 메서드 정의
      	// => 동일한 이름의 파라미터 타입만 서로 다른 메서드를 여러번 정의
      	// 1. 정수 2개를 전달받아 덧셈 수행
      	public void add(int num1, int num2) {
      		System.out.println("add(int, int) 호출됨");
      		System.out.println(num1 + num2);
      	}
      	
      	// 2. 실수 2개를 전달받아 덧셈 수행
      	public void add(double num1, double num2) {
      		System.out.println("add(double, double) 호출됨");
      		System.out.println(num1 + num2);
      	}
      	
      	// 주의! 파라미터의 변수명만 다를 경우 오버로딩 성립되지 않음! => 오류 발생
      //	public void add(int a, int b) {
      //		System.out.println("add(int, int) 호출됨");
      //		System.out.println(num1 + num2);
      //	}
      	
      	// 주의! 리턴타입만 다를 경우 오버로딩 성립되지 않음! => 오류 발생
      //	public int add(int num1, int num2) {
      //		System.out.println("add(int, int) 호출됨!");
      //		return num1 + num2;
      //	}
      	
      	// => 동일한 이름의 파라미터 타입만 서로 다른 메서드를 여러번 정의 
      	// 3. 정수 3개를 전달받아 덧셈을 수행
      	public void add(int num1, int num2, int num3) {
      		System.out.println("add(int, int, int) 호출됨");
      		System.out.println(num1 + num2+ num3);
      	}
      }
      
      class NormalMethod{
      	// 두 수를 전달받아 덧셈 결과를 출력하는 메서드 정의
      	// 1. int형 정수 2개를 전달받을 경우
      	public void add(int num1, int num2) {
      		System.out.println(num1 + num2);
      	}
      	
      	// 2. double형 실수 2개를 전달받을 경우
      	public void addDouble(double num1, double num2) {
      		System.out.println(num1 + num2);
      	}
      	
      	// 일반적으로 메서드명도 식별자에 해당하므로 중복이 불가능함
      	// 따라서, add()와 addDouble() 메서드는 하는 일이 같지만
      	// 서로 다른 파라미터를 전달받으므로 다른 이름으로 정의했음
      	// => 메서드 정의 시 메서드명을 달리해야 하므로 호출 시 구분이 불편할 수 있음!
      	public void printInt(int num) {
      		System.out.println(num);
      	}
      	
      	public void printString(String str) {
      		System.out.println(str);
      	}
      }
  • 오버라이딩(Overriding)
    • 상위 클래스의 메서드를 하위 클래스에서 재정의하는 것
      public abstract class Figure {
          protected int dot;
          protected int area;
      
          public Figure(final int dot, final int area) {
              this.dot = dot;
              this.area = area;
          }
      
          public abstract void display();
      
      	  // getter
      }
      
      public class Triangle extends Figure {
          public Triangle(final int dot, final int area) {
              super(dot, area);
          }
      
          @Override
          public void display() {
              System.out.printf("넓이가 %d인 삼각형입니다.", area);
          }
      }
  • 함수형 인터페이스(Functional Interface)
    • 람다식을 사용하기 위한 API로 자바에서 제공하는 인터페이스에 구현할 메소드가 하나뿐인 인터페이스를 의미
    • 함수형 인터페이스는 enum 열거법과 함께 사용한다면 다형성의 장점을 경험할 수 있다
      public enum Operator {
          PLUS("+", (a, b) -> a + b),
          MINUS("-", (a, b) -> a - b),
          MULTIPLY("*", (a, b) -> a * b),
          DIVIDE("/", (a, b) -> a / b);
      
          private final String sign;
          private final BiFunction<Long, Long, Long> bi;
      
          Operator(String sign, BiFunction<Long, Long, Long> bi) {
              this.sign = sign;
              this.bi = bi;
          }
      
      	  public static long calculate(long a, long b, String sign) {
          	  Operator operator = Arrays.stream(values())
                  	.filter(v -> v.sign.equals(sign))
                  	.findFirst()
                  	.orElseThrow(IllegalArgumentException::new);
      
          	  return operator.bi.apply(a, b);
      	  }
      }
      
      public static void main(String[] args) {
          String question = "4*7";
          String[] values = question.split("");
      
          long a = Long.parseLong(values[0]);
          long b = Long.parseLong(values[2]);
      
          long result = Operator.calculate(a, b, values[1]);
          System.out.println(result); //28
      }

참고자료
도서: 혼자 공부하는 자바 - 신용권
수업 예시 코드
블로그: https://blog.itcode.dev/posts/2021/08/08/encapulation
https://velog.io/@ljinsk3/%EB%8B%A4%ED%98%95%EC%84%B1

profile
🐢 💨 💨

0개의 댓글