BlueNyang
[멀티캠퍼스] 풀스택 개발자 아카데미 (8) - Java(2)
Java 풀스택 아카데미
· 멀티캠퍼스 JAVA 풀스택 개발자 아카데미 6회차 (8편)

[멀티캠퍼스] 풀스택 개발자 아카데미 (8) - Java(2)

BlueNyangBlueNyang
·
·
약 5분
·
# 부트캠프후기# 멀티캠퍼스it부트캠프# [현대이지웰] JAVA 풀스택 개발자 아카데미 6회차# oop# encapsulation# inheritance# polymorphism# grasp
시리즈·멀티캠퍼스 JAVA 풀스택 개발자 아카데미 6회차(30개의 글)
  • ···
  • 7.[멀티캠퍼스] 풀스택 개발자 아카데미 (7) - Java(1)
  • 8.[멀티캠퍼스] 풀스택 개발자 아카데미 (8) - Java(2)현재
  • 9.[멀티캠퍼스] 풀스택 개발자 아카데미 (9) - Java(3)
  • ···
원본: Magnific - Flaticon
원본: Magnific - Flaticon

1. 객체지향 - 클래스와 객체

객체 지향 프로그래밍(OOP;Object-Oriented Programming)은우리가 현실 세계를 인식하는 방식과 유사하다. 현실의 모든 사물(객체)을 코드로 표현하는 방식이며, 이때 객체를 만들기 위한 '설계도'가 바로 클래스(Class) 이고, 이 설계도를 바탕으로 메모리에 실제화된 '제품'이 객체(Object) 또는 인스턴스(instance) 이다.

  • Class: Object의 속성(데이터)과 기능(동작)을 정의한 설계도이며, Car클래스는 '차량번호', '색상', '모델명' 등의 속성과, '달리기()', '멈춤기()' 등의 기능을 가질 수 있다.
  • Object: Class라는 설계도를 바탕으로 실제 메모리에 생성된 존재로, new 연산자를 통해 생성되며, 각 객체는 자신만의 속성 값을 가진다. 예를 들어, 같은 Car class로 부터 '11가1234' 번호의 흰색 자동차 객체와 '22나5678' 번호의 검은색 자동차 객체를 만들 수 있다.
  • Instance: 클래스로부터 객체를 만드는 과정을 인스턴스화(Instantiate)라고 하고, 이렇게 만들어진 객체(Obejct)를 Instance라고 한다.
클래스와 Objct
클래스와 Objct
java
// Car.java
public class Car {
    // 1. 속성(Field)
    String carNo;
    String color;

    // 2. Constructor(생성자) - 객체 생성 시 초기화 담당
    public Car(String carNo, String color) {
        this.carNo = carNo;
        this.color = color;
    }

    // 3. 메소드 (기능/동작)
    public void drive() {
        System.out.println(this.carNo + " is driving");
    }
}

// CarMain.java
public class CarMain {
  public static void main(String[] args) {
    Car car1 = new Car("11가1234", "White");
    Car car2 = new Car("22나5678", "검은색");

    car1.drive(); // output: 11가1234 is driving
    car2.drive(); // output: 22나5678 is driving
  }
}

2. OOP의 특성

자바의 객체 지향 프로그래밍(OOP)는 크게 Encapsulation(캡슐화), Inheritance(상속), Polymorphism(다형성), Abstaction(추상화) 4가지로 이루어져있다.

2.1. Encapsulation - 캡슐화

캡슐화는 관련된 field(데이터)와 method(기능)을 하나의 클래스 묶고, 외부의 직접적인 데이터 접근을 막아 정보를 보호하는 것이다.

필드를 private 접근 한정자로 선언하여 외부의 접근을 차단 및 은닉하고, public 접근 한정자로 선언된 메소드(Getter/Setter)를 통해서만 데이터에 접근할 수 있도록 허용하는 방식이다. 이를 정보 은닉(Information Hiding) 이라고 한다.

java
public class Person {
    // private으로 인해 외부에서 직접 접근 불가
    private String name;
    private int age;

    // Getter: 외부에서 name 필드를 읽을 수 있도록 하는 통로
    public String getName() {
        return this.name;
    }

    // Setter: 외부에서 name 필드의 값을 변경하도록 하는 통로
    public void setName(String name) {
        this.name = name;
    }

  // Setter에 값을 검증하는 로직을 추가할 수 있음
    public void setAge(int age) {
        if (age > 0) {
            this.age = age;
        } else {
            System.out.println("나이는 0보다 커야합니다.");
            throw new Error("Invalid age value");
        }
    }
}

이를 통해 외부에서 함부로 객체의 데이터를 수정할 수 없으며, 데이터의 관리 책임을 해당 객체에게 확실히 전가할 수 있게된다.

Important

데이터와 그 데이터를 사용하는 로직(logic)을 하나의 객체에 모아 관리 관리책임을 부여하는 것은 객체 지향 설계의 매우 중요한 원칙으로, 정보 전문가 패턴(Information Expert Pattern) 원칙에서 제시하고 있는 원칙이다. 이는 "어떤 객체에게 책임을 할당해야 하는가?"라는 질문에 대한 답을 제시해주며, GRASP(General Responsibility Assignment Software Patterns) 설계 패턴 중 하나이다.

이는 쉽게 말해, 자신의 데이터는 자신이 제일 잘 안다는 개념이며, 객체는 자신이 가진 데이터의 처리를 스스로 책임지고 처리한다. 이를 통해 객체 사이에 결합도가 약해지고, 객체가 변경(수정)되더라도 다른 객체에 미치는 영향이 작아지는 효과를 볼 수 있으며, 결과적으로 유지보수성의 향상을 꾀할 수 있다.

2.2. Access Modifiers - 접근 제한자

접근 제한자는 클래스, 필드, 메소드, 생성자에 대한 접근 권한을 지정하는 키워드로, 캡슐화를 지키면서 외부로부터의 접근 수준을 정밀하게 제어하는 역할을 한다.

제한자같은 클래스같은 패키지자식 클래스(다른 패키지)전체(anywhere)
publicOOOO
protectedOOOX
defaultOOXX
privateOXXX
  • public: 완전 공개. 어떤 클래스에서도 접근할 수 있다. 가장 개방적인 접근 수준이다.
  • protected: 상속자에게만 공개. 같은 패키지에 있거나, 다른 패키지에 있더라도 상속받은 자식 클래스에서는 접근할 수 있다.
  • default (no keyword): 이웃에게만 공개. 아무 제한자도 명시하지 않으면 default가 되며, 같은 패키지 내의 클래스에서만 접근할 수 있다.
  • private: 나만 볼 수 있음. 해당 멤버를 선언한 클래스 내부에서만 접근할 수 있다. 가장 폐쇄적인 접근 수준으로, 주로 정보 은닉을 위해 필드에 사용된다.
java
// access/Parent.java (패키지: access)
package access;

public class Parent {
    public String publicVar = "public";
    protected String protectedVar = "protected";
    String defaultVar = "default";
    private String privateVar = "private";

    public void printVars() {
        // 같은 클래스 내에서는 모두 접근 가능
        System.out.println(publicVar);
        System.out.println(protectedVar);
        System.out.println(defaultVar);
        System.out.println(privateVar);
    }
}

// access/ChildInSamePackage.java (패키지: access)
package access;

public class ChildInSamePackage extends Parent {
    public void testAccess() {
        // private을 제외하고 모두 접근 가능
        System.out.println(publicVar);
        System.out.println(protectedVar);
        System.out.println(defaultVar);
        // System.out.println(privateVar); // 에러! private은 접근 불가
    }
}

// other/ChildInOtherPackage.java (패키지: other)
package other;

import access.Parent;

public class ChildInOtherPackage extends Parent {
    public void testAccess() {
        // public과 protected만 접근 가능
        System.out.println(publicVar);
        System.out.println(protectedVar);
        // System.out.println(defaultVar); // 에러! 다른 패키지이므로 default 접근 불가
        // System.out.println(privateVar); // 에러! private은 접근 불가
    }
}

2.3. Inheritance - 상속

상속은 부모 클래스(Superclass)의 필드와 메소드를 자식 클래스(Subclass)가 물려받아 사용할 수 있게 하는 기능으로 ,extends키워드를 사용하며, 코드의 재사용성을 높이고, 클래스 간의 계층구조를 만들 수 있다. 자식 클래스는 부모의 기능을 그대로 사용하거나, 메소드 오버라이딩을 통해 자신에게 맞게 기능을 재정의할 수 있다.

상속관계도
상속관계도
java
// Animal.java
public class Animal {
    String name;

    public void eat() {
        System.out.println(name + "eats the feed");
    }
}

// Cat.java
public class Cat extends Animal { // Animal 상속
    public void sound() {
        System.out.println(name + "meow");
    }
}

// InheritanceMain.java
public class InheritanceMain {
    public static void main(String[] args) {
        Cat myCat = new Cat();
        myCat.name = "nabi"; // 상속받은 필드에 접근
        myCat.eat();      // 부모 클래스 메소드
        myCat.sound();     // 자식 클래스 메소드
    }
}

2.3. Polymorphism - 다형성

다형성은 '여러가지 형태를 가질 수 있는 능력'을 의미하며, 하나의 타입 참조 변수로 여러 종류의 자식 객체를 다룰 수 있는 특성이다. 예를 특어, 탈 것라는 부모 클래스 타입의 변수에 버스 객체나 택시 객체를 모두 대입할 수 있다. 이를 통해 코드의 유연성과 확장성을 크게 높일 수 있다.

게시글 이미지
java
// Driver.java
public class Driver {
    public void drive(Vehicle vehicle) {
        vehicle.run();
    }
}

// Vehicle.java
public class Vehicle {
    public void run() {
        System.out.println("차량이 달립니다.");
    }
}

// Bus.java
public class Bus extends Vehicle {
    @Override
    public void run() {
        System.out.println("버스가 승객을 싣고 달립니다.");
    }
}

// Taxi.java
public class Taxi extends Vehicle {
    @Override
    public void run() {
        System.out.println("택스가 승객을 태우고 달립니다.");
    }
}

// PolymorphismMain.java
public class PolymorphismMain {
    public static void main(String[] args) {
        Driver driver = new Driver();
        Vehicle myVehicle = new Vehicle();
        Bus myBus = new Bus();
        Texi myTexi = new Texi();

        driver.drive(myVehicle); // output: 차량이 달립니다.
        driver.drive(myBus);     // output: 버스가 승객을 싣고 달립니다.
        driver.drive(myTexi);    // output: 택스가 승객을 태우고 달립니다.
    }
}

2.4. Abstraction - 추상화

추상화는 객체들의 공통된 특징을 추출하여 클래스를 정의하는 과정으로, 자바에서는 추상 클래스(Abstract Class) 와 **인터페이스(Interface) 를 통해 추상화를 구현한다.

3. 추상 클래스와 인터페이스

3.1. 추상 클래스 (abstract class)

추상 클래스는 미완성된 설계도로, 스스로 객체를 생성할 수 없다. 일부 메소드는 구현되어 있지만, 추상 메소드(선언만 있고, 본문({ })이 없는 메소드)를 하나 이상 포함할 수 있다. 또한 추상 클래스를 상속받는 자식 클래스는 반드시 부모의 추상 메소드를 오버라이딩하여 완성해야 한다.

게시글 이미지
java
// Phone.java
public abstract class Phone {
    public String owner;

    public void turnOn() {
        System.out.println("폰 전원을 켭니다.");
    }

    // 추상 메소드
    public abstract void ring();
}

// SmartPhone.java
public class SmartPhone extends Phone {
    @Override // 오버라이딩 강제
    public void ring() {
        System.out.println("스마트폰 벨소리가 울립니다.");
    }
}

3.2. 인터페이스 (interface)

인터페이스는 모든 메소드가 추산 메소드인, 더욱 완전한 '규격' 또는 '계약'에 가까우며, 클래스는 implements 키워드를 통해 여러 인터페이스를 동시에 구현할 수 있다.

게시글 이미지
java
// IRemoteControl.java
public interface IRemoteControl {
    // 인터페이스의 필드는 자동으로 public static final
    int MAX_VOLUME = 10;

    // 인터페이스의 메소드는 자동으로 public abstract 추상 메소드가 됨
    void turnOn();
    void setVolume(int volume);
}

// Television.java
public class Television implements IRemoteControl {
    private int volume;

    // interface의 모든 추상 메소드 구현 강제
    @Override
    public void turnOn() {
        System.out.println("TV를 켭니다.");
    }

    @Override
    public void setVolume(int volume) {
        if (volume > IRemoteControl.MAX_VOLUME) {
            this.volume = RemoteControl.MAX_VOLUME;
        } else {
            this.volume = volume;
        }
        System.out.println("현재 TV 볼륨: " + this.volume);
    }
}

3.3. 추상클래스와 인터페이스의 비교

구분Abstract Class(추상클래스)Interface(인터페이스)
목적관련 클래스들의 공통된 기능을 공유 (IS-A 관계)클래스가 따라야 할 동작의 규약/명세를 정의(HAS-A, CAN-DO 관계)
상속/구현extends (단일 상속)implements (다중 구현)
멤버생성자, 필드(모든 종류), 메소드(일반, 추상)static final 필드, default, static, private 메소드, 추상 메소드
키워드abstractinterface
용도상속받는 자식 클래스들이 공통 로직을 재사용하면서 일부 기능을 확장하고 싶을 때서로 관련 없는 클래스들에게 공통기능(역할) 부여가 필요한 경우

4. Exception Handling - 예외처리

예외 처리try-catch-finally 구문을 사용하여 프로그램 실행 중 발생하는 예기치 못한 오류를 관리하는 기능이다.

게시글 이미지
java
public class ExceptionHandlingMain {
    public static void main(String[] args) {
        try {
            String data = "abc";
            int value = Integer.parseInt(data); // 문자열을 숫자로 변환 시도 -> NumberFormatException
            System.out.println("변환된 숫자: " + value);
        } catch (NumberFormatException e) {
            // 예외 발생 시 처리할 코드
            System.out.println("숫자로 변환할 수 없는 데이터입니다.");
            e.printStackTrace();
        } finally {
            // 예외 발생 여부와 상관없이 항상 실행
            System.out.println("작업을 종료합니다.");
        }
    }
}

5. Generic과 Collection

5.1. Collection Framework

Collection Framework는 데이터 그룹을 효율적으로 관리할 수 있도록 표준화된 클래스들의 모음으로, List, Set, Map 등이 있다.

  • List: 순서가 있는 데이터 집합으로, 데이터 중복이 허용된다.
  • Set: 순서가 없는 데이터 집합으로, 데이터 중복을 허용하지 않는다.
  • Map: Key와 Value의 쌍으로 데이터를 저장하며, Key는 중복될 수 없다.(Hash Map)
게시글 이미지

5.2. Generic - 제네릭

제네릭은 Collection에 저장할 데이터의 타입을 미리 지정하여 코드의 안정성과 가독성을 높이는 기능이다.

java
// 1. ArrayList 예제
List<String> userList = new ArrayList<>();
userList.add("Alice");
userList.add("Bob");
System.out.println("First User: " + userList.get(0));

// 2. HashMap 예제
Map<String, String> capitalMap = new HashMap<>();
capitalMap.put("Korea", "Seoul");
capitalMap.put("Japan", "Tokyo");
System.out.println("capital of korea: " + capitalMap.get("Korea"));

6. 추가한 내용

본 수업 때 없었으나 추가한 내용

  • GRASP(General Responsibility Assignment Software Patterns) 설계 패턴 - 정보 전문가 패턴(Information Expert Pattern)
BlueNyang
작성자BlueNyang
라이선스
CC BY NC
BlueNyang

BlueNyang

BlueNyang의 개발 log

카테고리

  • Development
  • Framework
  • Language
  • Dev Tools
  • DevOps & Infra
  • Studies

페이지

© 2026 BlueNyang. All rights reserved.

Made with Nuxt.js and Directus