자바 - OOP 개념: 초보자의 가이드
안녕하세요, 미래의 자바 프로그래머 여러분! 자바의 객체지향 프로그래밍(OOP)의 세계로 향하는 이 흥미로운 여정에서 여러분의 가이드가 되어 기쁩니다. 컴퓨터 과학을 여러 년간 가르친 저는 여러분에게 이 길이 두려울 수 있지만, 엄청난 보상을 안겨줄 것이라고 확신합니다. 그럼, 손을 씻고 바로 시작해보겠습니다!
객체지향 프로그래밍이란 무엇인가요?
자바의 세부 사항에 뛰어들기 전에, 객체지향 프로그래밍이란 무엇인지 이야기해보겠습니다. 가상의 동물원을 지어보는 것을 상상해보세요. OOP가 없는 세상에서는 각 동물의 모든 세부 사항을 별도로 관리해야 합니다. 하지만 OOP를 사용하면 각 종류의 동물에 대한 청사진(클래스라고 부릅니다)을 만들고, 그 청사진으로 여러 개의 인스턴스(객체)를 만들 수 있습니다. 쿠키 모양을 만들기 위한 쿠키 컷터(클래스)를 사용하여 빠르고 효율적으로 많은 쿠키(객체)를 만드는 것과 같습니다!
OOP의 네 가지 지柱
- 캡슐화
- 상속
- 다형성
- 추상화
이 개념들을 즐겁게 살펴보겠습니다!
캡슐화: 비밀을 지키기
캡슐화는 선물을 包装하는 것과 같습니다. 바깥에서는 내부를 볼 수 없지만, 특정 방식으로 상호작용할 수 있습니다. 자바에서는 private 변수와 public 메서드를 사용하여 이를 달성합니다.
public class BankAccount {
private double balance; // 우리의 비밀입니다!
public void deposit(double amount) {
if (amount > 0) {
balance += amount;
}
}
public double getBalance() {
return balance;
}
}
이 예제에서, balance
는 private이므로 클래스 외부에서 직접 액세스할 수 없습니다. 대신, deposit()
와 getBalance()
와 같은 메서드를 제공하여 상호작용할 수 있습니다. 이렇게 하면 balance가 어떻게 수정되고 액세스되는지 통제할 수 있습니다.
상속: 가족에서 물려받는 것
상속은 부모에서 자식으로 특성을 전달하는 것과 같습니다. 자바에서는 extends
키워드를 사용하여 부모 클래스에서 속성과 메서드를 상속받는 자식 클래스를 만듭니다.
public class Animal {
protected String name;
public void eat() {
System.out.println(name + " is eating.");
}
}
public class Dog extends Animal {
public void bark() {
System.out.println(name + " says Woof!");
}
}
여기서, Dog
는 Animal
에서 name
속성과 eat()
메서드를 상속받지만, 자신만의 bark()
메서드도 가집니다. 모든 강아지는 동물이지만, 모든 동물이 강아지는 아님을 의미합니다!
다형성: 한 이름, 여러 형태
다형성은 각 장치에 대해 약간 다르게 작동하는 리모컨과 같습니다. 자바에서는 메서드 오버라이딩과 메서드 오버로딩을 통해 이를 달성할 수 있습니다.
메서드 오버라이딩
public class Animal {
public void makeSound() {
System.out.println("The animal makes a sound");
}
}
public class Cat extends Animal {
@Override
public void makeSound() {
System.out.println("Meow!");
}
}
public class Dog extends Animal {
@Override
public void makeSound() {
System.out.println("Woof!");
}
}
이제, 다른 동물 객체에 대해 makeSound()
을 호출하면 다른 결과를 얻을 수 있습니다:
Animal myPet = new Cat();
myPet.makeSound(); // 출력: Meow!
myPet = new Dog();
myPet.makeSound(); // 출력: Woof!
메서드 오버로딩
public class Calculator {
public int add(int a, int b) {
return a + b;
}
public double add(double a, double b) {
return a + b;
}
}
여기서, 같은 이름의 두 개의 add
메서드가 있지만 파라미터가 다릅니다. 자바는 제공된 인수에 따라 어떤 메서드를 사용할지 알고 있습니다.
추상화: 복잡한 것을 숨기기
추상화는 자동차를 운전하는 것과 같습니다. 엔진이 어떻게 작동하는지 알 필요는 없지만, 휠과 페달을 사용하는 방법을 알면 됩니다. 자바에서는 추상 클래스와 인터페이스를 사용하여 이를 달성합니다.
abstract class Shape {
abstract double getArea();
}
class Circle extends Shape {
private double radius;
Circle(double radius) {
this.radius = radius;
}
@Override
double getArea() {
return Math.PI * radius * radius;
}
}
class Rectangle extends Shape {
private double length;
private double width;
Rectangle(double length, double width) {
this.length = length;
this.width = width;
}
@Override
double getArea() {
return length * width;
}
}
여기서, Shape
는 모든 도형에 공통적인 메서드 getArea()
를 정의하는 추상 클래스입니다. 구체적인 구현은 Circle
과 Rectangle
서브클래스에게 남겨집니다.
모두 묶어보기
이제 주요 개념을 다루었으니, 더 복잡한 예제에서 이들이 어떻게 모두 작동하는지 보겠습니다:
interface Movable {
void move();
}
abstract class Vehicle implements Movable {
protected String brand;
protected String model;
Vehicle(String brand, String model) {
this.brand = brand;
this.model = model;
}
abstract void startEngine();
}
class Car extends Vehicle {
private int numDoors;
Car(String brand, String model, int numDoors) {
super(brand, model);
this.numDoors = numDoors;
}
@Override
void startEngine() {
System.out.println("Car engine started: Vroom!");
}
@Override
public void move() {
System.out.println("Car is moving on the road");
}
}
class Boat extends Vehicle {
private int maxSpeed;
Boat(String brand, String model, int maxSpeed) {
super(brand, model);
this.maxSpeed = maxSpeed;
}
@Override
void startEngine() {
System.out.println("Boat engine started: Purr!");
}
@Override
public void move() {
System.out.println("Boat is sailing on the water");
}
}
이 예제에서:
- 추상화는
Vehicle
추상 클래스와Movable
인터페이스를 사용합니다. - 상속은
Car
과Boat
가Vehicle
를 확장하여 상속받습니다. - 다형성은
startEngine()
과move()
에서 메서드 오버라이딩을 통해 보여줍니다. - 캡슐화는 private 변수와 public 메서드를 통해 사용됩니다.
자바 OOP의 장점
장점 | 설명 |
---|---|
모듈성 | OOP는 문제를 더 작은, 관리하기 쉬운 조각으로 나눌 수 있게 합니다. |
재사용성 | 상속을 통해 기존 클래스의 코드를 재사용할 수 있습니다. |
유연성 | 다형성을 통해 객체를 부모 클래스의 인스턴스로 취급할 수 있습니다. |
유지보수성 | 캡슐화는 코드를 변경하고 유지하는 데 더 쉬워집니다. |
보안 | 데이터 숨기기(캡슐화)는 데이터 액세스를 더 잘 제어합니다. |
결론
축하합니다! 여러분은 자바의 객체지향 프로그래밍 세계로의 첫 걸음을 내딛었습니다. 프로그래밍을 배우는 것은 새로운 언어를 배우는 것과 같습니다 - 시간과 연습이 필요합니다. 즉시 모든 것을 이해하지 못해도 깊이 울리지 마세요. 계속 코딩하고, 실험하며, 가장 중요한 것은 즐기세요!
다음 수업에서는 자바 제어 문, 파일 처리, 에러 처리, 멀티스레드 및 네트워킹과 같은 더 복잡한 개념에 대해 더 깊이 들어갈 것입니다. 그ingga까지, 즐거운 코딩 되세요!
Credits: Image by storyset