728x90
안녕하세요. 오늘은 공부해도 시간 지나면 까먹어버리는 객체지향 프로그래밍에 대해 작성해보도록 하겠습니다.
OOP(Object-Oriented Programming)란?
- 프로그램을 객체라는 독립적인 단위로 나누어 설계하고 개발하는 프로그래밍
- 객체는 데이터(속성)와 메서드(행동)을 포함하며 이 두 가지를 하나로 묶어 프로그램을 구조화하며, 이를 통해 코드의 재사용성과 유지보수성을 높이고 현실 세계의 문제를 프로그램으로 자연스럽게 표현할 수 있음
- 4가지 주요 특징으로는 캡슐화, 상속성, 다형성, 추상화가 있음
OOP의 특징
1. 캡슐화(Encapsulation)
객체의 데이터(속성)와 이를 처리하는 메서드(행동)을 하나로 묶고 외부에서 직접 접근할 수 없도록 제한하는 개념
데이터를 보호하고 객체 내부의 구현 세부 사항을 감추는 역할을 함
장점
- 데이터 무결성 유지 : 외부에서 직접 데이터를 변경하지 못하도록 보호함
- 코드의 재사용성과 유지보수성 증가 : 내부 구현 변경이 외부 코드에 영향을 미치지 않음
구현 방식
- 접근 제어자를 사용하여 데이터 접근을 제한함
- private : 클래스 내부에서만 접근 가능. 외부 접근 완전 차단(※정보 은닉의 핵심)
- protected : 같은 패키지 또는 상속받은 클래스에서만 접근 가능
- public : 어디에서나 접근 가능. 외부에 공개
※ 정보 은닉 : 캡슐화의 한 요소이며, 데이터 보호뿐 아니라 객체 내부 구현의 독립성을 보장함(객체 내부의 구현 세부 사항을 감추고, 외부에서 필요한 정보나 기능만 공개하는 개념)
- Getter/Setter 메서드로 외부에서 데이터에 간접적으로 접근하도록 함
예시
class Bank {
private double balance; // 외부에서 직접 접근 불가
// Getter - balance 조회
public double getBalance() {
return balance;
}
// Setter - balance 수정
public void deposit(double amount) {
if (amount > 0) {
balance += amount;
}
}
public void withdraw(double amount) {
if (amount > 0 && amount <= balance) {
balance -= amount;
}
}
}
public class Main {
public static void main(String[] args) {
Bank account = new Bank();
account.deposit(1000); // 1000원 입금
account.withdraw(500); // 500원 출금
System.out.println(account.getBalance()); // 500.0
}
}
2. 상속성(Inheritance)
기존 클래스(부모 클래스)의 속성과 메서드를 새로운 클래스(자식 클래스)가 물려받아 사용하는 것
장점
- 코드 재사용성 : 공통된 기능은 부모 클래스에 정의하고 자식 클래스는 추가 기능만 구현
- 유지보수 용이성 : 수정 사항이 부모 클래스에만 적용되면 자식 클래스에서도 반영됨
- 확장성 : 기존 클래스의 기능을 확장하거나 수정 가능
구현 방식
- extends 키워드 사용
- 부모 클래스의 메서드를 자식 클래스에서 재정의(오버라이딩) 가능
예시
class Animal {
public void eat() {
System.out.println("먹다.");
}
}
class Dog extends Animal {
public void bark() {
System.out.println("짖다.");
}
@Override
public void eat() {
System.out.println("강아지가 밥을 먹다.");
}
}
public class Main {
public static void main(String[] args) {
Dog dog = new Dog();
dog.eat(); // 강아지가 밥을 먹다.
dog.bark(); // 짖다.
}
}
3. 다형성(Polymorphism)
같은 메서드 호출이나 객체 참조가 상황에 따라 다른 방식으로 동작하는 것을 의미함
유형
- 메서드 오버라이딩(Method Overriding) : 부모 클래스의 메서드를 자식 클래스에서 재정의
- 메서드 오버로딩(Method Overloading) : 같은 이름의 메서드를 매개변수의 타입이나 개수 등에 따라 다르게 정의
장점
- 유연성 : 같은 코드로 다양한 객체를 처리
- 확장성 : 객체에 따라 다른 동작을 정의 가능
예시1 (오버라이딩)
// 오버라이딩 예시
// 부모 클래스
class Shape {
public void draw() {
System.out.println("도형을 그린다.");
}
}
// 자식 클래스
class Circle extends Shape {
@Override
public void draw() {
System.out.println("원을 그린다.");
}
}
class Rectangle extends Shape {
@Override
public void draw() {
System.out.println("사각형을 그린다.");
}
}
public class Main {
public static void main(String[] args) {
Shape shape;
shape = new Circle();
shape.draw(); // 원을 그린다.
shape = new Rectangle();
shape.draw(); // 사각형을 그린다.
}
}
예시2 (오버로딩)
// 오버로딩 예시
class Shape {
// 기본 draw 메서드
public void draw() {
System.out.println("도형을 그린다.");
}
// 오버로딩된 draw 메서드 (매개변수 추가)
public void draw(String color) {
System.out.println(color + " 색상의 도형을 그린다.");
}
// 오버로딩된 draw 메서드 (매개변수 타입 다름)
public void draw(int size) {
System.out.println("크기가 " + size + "인 도형을 그린다.");
}
// 오버로딩된 draw 메서드 (매개변수 개수 다름)
public void draw(String color, int size) {
System.out.println(color + " 색상의 크기 " + size + "인 도형을 그린다.");
}
}
public class Main {
public static void main(String[] args) {
Shape shape = new Shape();
// 기본 draw 메서드 호출
shape.draw(); // 도형을 그린다.
// 오버로딩된 draw 메서드 호출
shape.draw("빨간색"); // 빨간색 색상의 도형을 그린다.
shape.draw(10); // 크기가 10인 도형을 그린다.
shape.draw("파란색", 20); // 파란색 색상의 크기 20인 도형을 그린다.
}
}
오버라이딩과 오버로딩의 차이점
구분 | 오버라이딩(Overriding) | 오버로딩(Overloading) |
목적 | 부모 클래스의 메서드를 재정의하여 동작을 변경함 | 같은 이름의 메서드를 다양한 매개변수로 제공 |
조건 | 메서드 이름, 매개변수, 반환 타입이 부모와 동일해야함 | 메서드 이름은 같고 매개변수의 개수나 타입이 달라야 함 |
대상 | 상속 관계에서 사용 | 같은 클래스 내에서 사용 |
사용 시점 | 다형성을 구현하기 위해 사용 | 편리한 메서드 호출을 위해 사용 |
4. 추상화(Abstraction)
복잡한 시스템에서 필요한 핵심 기능만 정의하고 세부 사항은 구현하지 않는 개념(실제 구현이 아닌 구조와 약속을 정의한다는 의미!)
장점
- 코드의 가독성 향상 : 설계와 구현을 분리
- 유지보수 용이성 : 구현을 변경해도 인터페이스는 유지 가능
- 효율적 설계 : 공통된 인터페이스를 기반으로 다양한 구현체를 설계 가능
구현 방식
- 추상 클래스(Abstract Class)
- abstract 키워드 사용
- 추상 메서드는 구현 없이 선언만 가능
- 인터페이스(Interface)
- 객체가 반드시 구현해야 할 메서드 목록을 정의
+) Java 8부터 인터페이스에 기본 메서드와 정적 메서드를 추가할 수 있음. 이를 통해 인터페이스도 일부 구현을 포함할 수 있게 되었지만, 본질적으로 객체 간 공통된 행동(규격)을 정의하는 목적은 변하지 않음!
예시1 (추상 클래스)
// 추상 클래스
abstract class Animal {
abstract void sound(); // 추상 메서드
}
// 자식 클래스
class Dog extends Animal {
@Override
public void sound() {
System.out.println("멍멍!");
}
}
class Cat extends Animal {
@Override
public void sound() {
System.out.println("야옹!");
}
}
public class Main {
public static void main(String[] args) {
Animal dog = new Dog();
dog.sound(); // 멍멍!
Animal cat = new Cat();
cat.sound(); // 야옹!
}
}
예시2 (인터페이스)
interface Animal {
void sound(); // 추상 메서드
}
// Dog 클래스는 Animal 인터페이스를 구현
class Dog implements Animal {
@Override
public void sound() {
System.out.println("멍멍!");
}
}
// Cat 클래스는 Animal 인터페이스를 구현
class Cat implements Animal {
@Override
public void sound() {
System.out.println("야옹!");
}
}
public class Main {
public static void main(String[] args) {
Animal dog = new Dog(); // Animal 인터페이스 타입으로 Dog 객체 참조
dog.sound(); // 멍멍!
Animal cat = new Cat(); // Animal 인터페이스 타입으로 Cat 객체 참조
cat.sound(); // 야옹!
}
}
추상 클래스와 인터페이스의 차이점
구분 | 추상 클래스 | 인터페이스 |
목적 | 공통된 행동(메서드)과 속성(필드)을 정의 | 공통된 행동(메서드)의 규격을 정의 |
구현 여부 | 추상 메서드와 일반 메서드 모두 포함 가능 | 모든 메서드는 기본적으로 추상 메서드(Java 8부터는 기본 메서드와 정적 메서드도 가능) |
다중 상속 | 다중 상속 불가(class MyClass extends AbstractClass) | 다중 구현 가능(class MyClass implements InterfaceA, InterfaceB) |
필드 | private, protected 등 다양한 접근 제어자를 가진 필드 포함 가능 | public static final (상수)만 허용 |
사용 시점 | 공통적인 빌드와 메서드(구현 포함)를 상속받아 사용할 때 | 객체 간 공통된 행동(규격)을 정의 |
정리
- 캡슐화 : 데이터 보호 및 은닉 → Getter/Setter를 통해 무결성 유지
- 상속성 : 코드 재사용 및 확장 → extends
- 다형성 : 동일한 코드로 다양한 동작 구현 → 오버라이딩/오버로딩
- 추상화 : 핵심만 정의하고 구현은 자식 클래스에 위임 → 추상 클래스와 인터페이스 활용 / abstract
728x90
'Languages > JAVA' 카테고리의 다른 글
[JAVA] 스트림(Stream)이란? (개념, 메서드 정리) (0) | 2024.11.04 |
---|---|
[JAVA] JVM(자바 가상 머신)이란? (역할, 동작 과정, 구성 요소) (0) | 2024.09.23 |
[JAVA] 프로토타입 패턴&싱글톤 패턴(new, getInstance()의 차이) (0) | 2023.11.02 |
[JAVA] 자바 MD5, SHA-256 단방향 암호화(feat. MessageDigest)(+코드예제) (2) | 2023.11.01 |