본문 바로가기

개발일지/TIL

객체지향 복습

반응형

객체지향언어 클래스,인스턴스,메소드

 1.클래스(Class)란?

  • 클래스는 표현하고자 하는 대상의 공통 속석을 한 군데에 정의해 놓은 것이라고 할 수 있다. 즉, 클래스는 객체의 속성을 정의해 놓은 것.
  • 또한 클래스 내부의 정보를 맴버 변수라고 한다.
  • 붕어빵을 예로 들면 붕어빵을 만드는 틀이 곧 클래스가 되며 붕어빵 틀로부터 만들어진 붕어빵이 곧 인스턴스가 되는것이다.

  인스턴스(Instance)란?

  • 어떠한 클래스로부터 만들어진 객체를 그 클래스의 인스턴스라고 한다.

 2.메소드(method)

  • 메소드는 어떠한 작업을 수행하는 코드를 하나로 묶어놓은 것.

 메소드가 필요한 이유

  • 재사용성 - 메소드를 만들어 놓으면 이후 반복적으로 재사용이 가능. 물론, 다른 프로그램에서도 사용이 가능.
  • 중복된 코드 제거 - 프로그램을 작성하다 보면 같은 코드가 여러번 반복되어 작성되곤 한다. 이럴 때, 메소드를 활용하면 중복된 부분을 없애므로 보다 효율적인 코드가 된다.
  • 프로그램 구조화 - 긴 코드를 관리 할 때 메소드를 이용해 보다 쉽게 수정 및 관리를 할 수 있다.
  • 메소드를 만들 때는 메소드 안에서  동작하는 내용을 잘 표현할 수 있도록 이름을 잘 지어주면, 메소드 안을 들여다 보지 않고도 한 눈에 코드를 읽어내려갈 수 있어서 좋다. 이것을 readability가 좋다고 표현하며, 기본 품질을 위해서 Java로 메소드를 만들 때 지켜줘야 하는 기본 약속은 다음 두가지가 있다.
    1. 동사로 시작해야한다.
    2. camel case로 작성해야 한다. ( 첫 단어는 소문자로, 이후 단어의 구분에 따라서 첫 글자만 대문자인 단어가 이어진다. 중간에 띄어쓰기나 특수문자는 들어가지 않는다. ex)SpringcoreApplication

 

메소드 선언과 구현

  • 메소드는 다음의 형식으로 정의할 수 있다.
반환타입 메소드이름 (타입 변수명,타입 변수명, ...){
    수행되어야 할 코드
}
int add(int x, int y) {
    int result = x + y;
    return result;
}
  • 메소드의 반호나타입은 int이며 이는 반환되어지는 변수인 result와 일치해야 한다.
    • 반환타입중 void는 '아무 것도 없음'을 의미한다. 메소드내에서 출력 할 경우 등등.

 

객체지향언어 생성자

 1.생성자

  • 생성자는 인스턴스가 생성될 때 사용되는 '인스턴스 초기화 메소드'이다. 즉 new와 같은 키워드로 해당 클래스의 인스턴스가 새로 생성될 때, 자동으로 호출되는 메소드이다. 이 생성자를 이용해서 인스턴스가 생성될 때 수행할 동작을 코드로 짤수 있는데, 대표적으로 인스턴스 변수를 초기화 하는 용도로 사용한다.
  • 생성자의 형식
클래스이름 (타입 변수명, 타입 변수명, ...){
    인스턴스 생성 될 때에 수행하여할 코드
    변수의 초기화 코드
}
  • 생성자에게도 생성자만의 조건이 있다.
    1. 생성자의 이름은 클래스명과 같아야 한다.
    2. 생성자는 리턴 값이 없다.
  • 모든 클래스는 반드시 하나 이상의 생성자가 있어야 한다. (클래스에 생성자가 1개도 작성이 되어있지 않을 경우, 자바 컴파일러가 기본 생성자를 추가해주기 때문에 우리는 기본 생성자를 작성하지 않고도 편리하게 사용할 수 있다.

 2.인스턴스(맴버) 변수의 기본값

class에 선언된 변수는 instance 가 생성될 때 값이 초기화 된다. 이 때, 변수의 선언부나 생성자를 통해서 초기화를 해주지 않는다면, 기본값을 가진다.

byte default: 0 // 1byte 를 구성하는 8개의 bit가 모두 0이라는 뜻.
        short default: 0
        int default: 0
        long default: 0
        float default: 0.0
        double default: 0.0
        reference default: null

 

 

객체지향언어 상속

https://t1.daumcdn.net/cfile/tistory/994CCA505B5F2D051A

→ 상속을 보여주는 UML Class Diagram. 자동차의 하위 계층으로 SUV와 SEDAN이 존재한다. 

  • 상속이란 기존의 클래스를 재사용하는 방식 중의 하나이다. 한 번 작성한 코드가 재사용이 필요하다면, 변경사항만 코드로 작성하므로 상대적으로 적은 양의 코드를 작성할 수 있게 된다. 이렇게 코드를 재사용하면, 코드와 클래스가 많아질수록 관리가 용이하다는 장점이 있다.
  • 상속을 통해 클래스간의 계층구조를 만들게 된다.
  • 상속의 특징
    1. 부모 클래스로에서 정의된 필드와 메소드를 물려받는다.
    2. 새로운 필드와 메소드를 추가할 수 있다.
    3. 부모 클래스에서 물려받은 메소드를 수정할 수 있다.

          상속은 extends를 이용하여 사용할 수 있다.

  • 자식 객체(Dog)는 자식 타입으로 선언된 변수에도 할당할 수 있고, 부모(Animail) 타입으로 선언된 변수에도 할당 할 수 있다. 단, 부모(Animail)타입의 변수로 사용할 때는, 실제 객체를 만들(new)때 사용한 자식(Dog) 타입에 있는 함수를 호출할 수 없다. 컴파일러 에러

 

오버로딩(overloading) vs 오버라이딩(overriding)

 오버로딩이란?

한 클래스 내에 동일한 이름의 메소드를 여러개 정의하는 것

👉 동일한 이름의 메소드를 정의한다고 해서 무조건 오버로딩인 것은 아닙니다!
  • 오버로딩의 조건
    • 메소드 이름이 동일해야 한다.
    • 매개변수의 개수 혹은 타입이 달라야 한다.
int add(int x, int y, int z) {
    int result = x + y + z;
    return result;
}
long add(int a, int b, int c) {
    long result = a + b + c;
    return result;
}
// 반환타입은 다르지만 매개변수의 자료형과 개수는 같기에 오버로딩이 아닙니다.
    int add(int x, int y, int z) {
        int result = x + y + z;
        return result;
    }
    long add(int a, int b, long c) {
        long result = a + b + c;
        return result;
    }
    int add(int a, int b) {
        int result = a + b;
        return result;
    }
// 오버로딩의 조건에 부합하는 예제입니다.

 

 오버라이딩이란?

 -부모 클래스로부터 상속받은 메소드의 내용을 변경하는 것

 -상속받은 메소드를 그대로 사용하기도 하지만, 필요에 의해 변경해야할 경우 오버라이딩을 한다.

  • 오버라이딩의 조건
    • 부모 클래스의 메소드와 이름이 같아야 한다.
    • 보모 클래스의 메소드와 매개변수가 같아야 한다.
    • 보무 클래스의 메소드와 반환타입이 같아야 한다.
class Animal {
    String name;
    String color;
    public void cry() {
        System.out.println(name + " is crying.");
    }
}
class Dog extends Animal {
    Dog(String name) {
        this.name = name;
    }
    public void cry() {
        System.out.println(name + " is barking!");
    }
}
public class Main {
    public static void main(String[] args) {
        Animal dog = new Dog("코코");
        dog.cry();
    }
}
👉 두 가지 개념을 혼동하기 쉽지만 차이는 명백히 존재한다.
        오버로딩 : 기존에 없는 새로운 메소드를 정의하는 것
        오버라이딩 : 상속받은 메소드의 내용을 변경하는 것

 

 

객체지향언어 접근제어자

 1.접근 제어자(access modifier)

  • 접근 제어자는 맴버 변수/함수 혹은 클래스에 사용되며 외부에서의 접근을 제한하는 역할을 한다.

 -private: 같은 클래스 내에서만 접근이 가능.

 -default(nothing): 같은 패키치 내에서만 접근이 가능.

 -protected: 같은 패키지 내에서, 그리고 다른 패키지의 자손클래스에서 접근이 가능.

 -public: 접근 제한이 전혀 없다.

👉 위의 설명을 토대로 접근 범위에 대해 정리를 하면 다음과 같습니다.
        (좁음) (넓음)
private → default → protected → public

 

왜? 접근 제어자를 사용할까?

 - 객체지향 프로그래밍이란 객체들 간의 상호작용을 코드로 표현하는 것이다.

 - 이 때 객체들간의 관계에 따라서 접근 할 수 있는 것과 아닌 것, 권한을 구분할 필요가 생긴다.

 - 클래스 내부에 선언된 데이터의 부적절한 사용으로부터 보호하기 위해서!

      - 이런 것을 캡슐화(encapsulation)라고 한다.

 - 접근 제어자는 캡슐화가 가능할 수 있도록 돕는 도구이다.

 

 

객체지향언어 추상클래스, 인터페이스

 1. 추상클래스(abstract class)

  • 추상클래스란?
    • 추상클래스는 추상메소드를 선언할 수 있는 클래스를 의미한다. 또한 추상클래스는 클래스와 다르게 상속받는 클래스 없이 그 자체로 인스턴스를 생성할 수는 없다.
  • 추상 메소드란?
    • 추상메소드는 설계만 되어있으며 수행되는 코드에 대해서는 작성이 안된 메소드입니다.
    • 이처럼, 미완성으로 남겨두는 이유는 상속받는 클래스 마다 반드시 동작이 달라지는 경우에 상속받는 클래스 작성자가 반드시 작성하도록하기 위함입니다.

-추상 메소드 형식

abstract 리턴타입 메소드이름();

예제)

public class Main {
    public static void main(String[] args) {
    }
}
abstract class Bird {
    private int x, y, z;
    void fly(int x, int y, int z) {
        printLocation();
        System.out.println("이동합니다.");
        this.x = x;
        this.y = y;
        if (flyable(z)) {
            this.z = z;
        } else {
            System.out.println("그 높이로는 날 수 없습니다");
        }
        printLocation();
    }
    abstract boolean flyable(int z);
    public void printLocation() {
        System.out.println("현재 위치 (" + x + ", " + y + ", " + z + ")");
    }
}
class Pigeon extends Bird {
    @Override
    boolean flyable(int z) {
        return z < 10000;
    }
}
class Peacock extends Bird {
    @Override
    boolean flyable(int z) {
        return false;
    }
}
public class Main {
    public static void main(String[] args) {
        Bird pigeon = new Pigeon();
        Bird peacock = new Peacock();
        System.out.println("-- 비둘기 --");
        pigeon.fly(1, 1, 3);
        System.out.println("-- 공작새 --");
        peacock.fly(1, 1, 3);
        System.out.println("-- 비둘기 --");
        pigeon.fly(3, 3, 30000);
    }
}
  • fly(x,y,z) 함수는 Bird를 상속받는 모든 클래스에서 동일한 동작을 한다. 다만, 그 안에서 호출된 flyable(z)의 동작만 그것을 구현하는 자식 클래스에서 구현한대로 동작하는 것.
  • 공작새(peacok)는 새이지만 전혀 날 수가 없다. 그래서 공작새의 flyable()은 항상 false를 리턴해서 언제나x,y좌표로만 움직인다. 반면에 비둘기(pigeon)는 일정 높이까지는 날아갈 수 있기 때문에 그 기준(여기서는 10000)이 되기 전까지는 z좌표로도 움직일 수 있다. 이것을 새의 종류마다 중복코드 없이 구현하려면 추상클래스와 추상메소드를 이용해서 이렇게 구현할 수 있다. 이렇게 코드를 짜면, 중복코드가 없으면서도 새의 종류마다 주어진 위치까지 날 수 있는지를 판단할 수 있는 유연성을 허용하며 구현할 수 있다.

 

 2. 인터페이스(Interface)

  • 인터페이스는 객체의 특정 행동의 특징을 정의하는 간단한 문법이다. 인터페이스는 함수의 특징(method signature)인 접근 제어자, 리턴타입, 메소드 이름만을 정의한다. 함수의 내용은 없다. 인터페이를 구현하는 클래스는 인터페이스에 존재하는 함수의 내용을 반드시 구현해야한다.

- 인터페이스 형식

interface 인터페이스명{
    public abstract void 추상메서드명();
}

  -> 인터페이스의 메소드는 추상메소드, static메소드, default 메소드 모두 허용된다. (JDK 1.8부터)

 

예제)

public class Main {
    public static void main(String[] args) {
    }
}
interface Bird {
    void fly(int x, int y, int z);
}
class Pigeon implements Bird{
    private int x,y,z;
    @Override
    public void fly(int x, int y, int z) {
        printLocation();
        System.out.println("날아갑니다.");
        this.x = x;
        this.y = y;
        this.z = z;
        printLocation();
    }
    public void printLocation() {
        System.out.println("현재 위치 (" + x + ", " + y + ", " + z + ")");
    }
}
public class Main {
    public static void main(String[] args) {
        Bird bird = new Pigeon();
        bird.fly(1, 2, 3);
// bird.printLocation(); // compile error
    }
}
  • interface인 Bird타입으로 선언한 bird변수는 실제로 pigeon객체이지만, interface인 Bird에 선언되지 않은 printLocation()이라는 함수는 호출할 수 없다. interface type으로 선언되어있는 부분에서 실제 객체가 무엇이든지, interface에 정의된 행동만 할 수 있다.

인터페이스 vs 추상클래스

  • 인터페이스
    1. 구현하려는 객체의 동작의 명세
    2. 다중 상속 가능
    3. implements를 이용하여 구현
    4. 메소드 시그니처(이름, 파라미터, 리턴 타입)에 대한 선언만 가능
  • 추상클래스
    1. 클래스를 상속받아 이용 및 확장을 위함
    2. 다중 상속 불가능, 단일 상속
    3. extends를 이용하여 구현
    4. 추상메소드에 대한 구현 가능

 

반응형

'개발일지 > TIL' 카테고리의 다른 글

JPA 영속성 컨텍스트 이해  (0) 2022.07.18
JPA 이해  (0) 2022.07.18
JPA  (0) 2022.07.17
Getter, Setter의 이해  (0) 2022.07.17
테스트의 필요성  (0) 2022.07.15