Java

 

is-a 관계와 has-a 관계는 모두 객체(클래스) 간의 관계를 정의한다.


is-a 관계

상속 관계를 표현할 때 사용

'A는 B이다' 로 해석할 수 있는 관계

has-a 관계보다 밀접하게 연관된 관계

개체 간의 일반화(Generalization) 또는 특수화(Specialization) 관계를 나타냄

예시 : 강아지는 동물이다, 학생은 인간이다 ...

// 부모 클래스 (Super Class)
class Animal {
    void eat() {
        System.out.println("동물이 음식을 먹습니다.");
    }
}

// 자식 클래스 (Sub Class)
class Dog extends Animal {  // 상속 (is-a 관계)
    void bark() {
        System.out.println("멍멍!");
    }
}

public class Main {
    public static void main(String[] args) {
        Dog myDog = new Dog();
        myDog.eat();  // 부모 클래스의 메서드 사용
        myDog.bark(); // 자식 클래스의 메서드 사용
    }
}

 

has-a 관계

포함 관계 또는 구성 관계를 표현할 때 사용

'A는 B를 가진다' 로 해석할 수 있는 관계

is-a 관계보다 덜 밀접하게 연관된 관계

일반적으로 is-a 관계보다 has-a 관계를 고려하는 것이 유연성과 유지 보수 측면에서 유리함

두 클래스가 독립적으로 존재할 때, 한 클래스 내에서 다른 클래스를 속성(변수)로 포함할 때 사용

개체 간의 객체 포함(Composition/Aggregation)을 나타냄

예시 : 자동차는 엔진을 가진다, 스마트폰은 배터리를 가진다 ...

// Engine 클래스 (독립적인 클래스)
class Engine {
    void start() {
        System.out.println("엔진이 시작됩니다.");
    }
}

// Car 클래스는 Engine을 '가지고 있음' (Composition)
class Car {
    private Engine engine; // Engine 객체를 포함 (has-a 관계)

    // 생성자를 통해 Engine 객체를 주입
    Car(Engine engine) {
        this.engine = engine;
    }

    void startCar() {
        System.out.println("자동차 시동을 겁니다.");
        engine.start(); // 포함된 Engine 객체의 기능 사용
    }
}

public class Main {
    public static void main(String[] args) {
        Engine myEngine = new Engine(); // Engine 객체 생성
        Car myCar = new Car(myEngine); // Car 객체에 Engine 포함

        myCar.startCar(); // Car의 기능 실행
    }
}

'Programming > Java' 카테고리의 다른 글

[Java] 상속 (Inheritance)  (1) 2025.03.04
[Java] 생성자 (Constructor)  (0) 2025.03.04
[Java] 클래스 변수, 인스턴스 변수, 로컬 변수, 매개 변수  (0) 2025.02.28
[Java] Java란?  (1) 2025.02.28

Java

상속이란?

한 클래스가 다른 클래스의 속성과 메서드를 물려받는 것

중복되는 속성과 메서드를 복사하여 코드의 재사용성을 높이고 유지 보수를 쉽게 함

extends 키워드를 사용 (예시 : class 자식클래스명 extends 부모클래스명)

instanceof 연산자로 상속 관계 확인 가능 (예시 : if(자식클래스명 instanceof 부모클래스명))

  • 상속하는 부모 클래스 = Super Class (Base Class) : 기존 속성과 메서드를 정의한 클래스
  • 상속받는 자식 클래스 = Sub Class (Derived Class) : 기존 속성과 메서드를 확장하여 새로운 기능을 추가하는 클래스

상속의 특징

  • is-a 관계임
  • Sub Class에서 Super Class에 없는 메서드나 인스턴스 변수를 추가할 수 있음 
  • Sub Class에서 Super Class의 속성과 메서드를 사용, 변경, 확장하여 사용할 수 있음
  • Sub Class에서 Super Class의 Private, Static, Final 메서드 또는 변수에 대해서는 접근 불가할 수 있음
  • 특히, Final class는 상속이 불가능하고 Final method는 오버라이딩이 불가능함
  • Super Class의 참조가 Sub Class가 되는 경우는 안전하지 않을 수 있음 (ILLEGAL)
  • Java에서 클래스의 다중 상속은 불가능하지만, 인터페이스(Interfaces)의 다중 상속은 가능함
  • Java의 많은 메서드들은 Object class에서 상속 받은 것임
// Super Class
class Animal {
    String name;

    void eat() {
        System.out.println(name + " is eating food.");
    }
}

// Sub Class (Animal 클래스를 상속)
class Dog extends Animal { // extends로 상속
    void bark() {
        System.out.println(name + " is barking.");
    }
}

public class Main {
    public static void main(String[] args) {
        Dog myDog = new Dog();
        myDog.name = "Poppi";  // Super Class의 필드 사용
        myDog.eat();  // Super Class의 메서드 사용
        myDog.bark(); // Sub Class의 메서드 사용
    }
}

 

매서드 오버라이딩 / Method Overriding

부모 클래스의 메서드를 자식 클래스에서 재정의하여 다르게 동작하게 할 수 있음

@Override 어노테이션을 사용하여 오버라이딩을 명확히 표시

※ 오버로딩(Overloading)과는 다르다 (여기를 참조)

class Animal {
    void makeSound() {
        System.out.println("Animal makes sounds.");
    }
}

class Dog extends Animal {
    @Override  // 어노테이션으로 명시
    void makeSound() {  // 부모 클래스의 메서드를 재정의
        System.out.println("Bow-wow!");
    }
}

public class Main {
    public static void main(String[] args) {
        Animal myAnimal = new Animal();
        myAnimal.makeSound();  // "Animals make sounds."

        Dog myDog = new Dog();
        myDog.makeSound();  // "Bow-wow!" (오버라이딩된 메서드 실행)
    }
}

업캐스팅 & 다운캐스팅 (Upcasting & Downcasting)

상속 관계에서 객체 간 타입 변환이 가능함

  • 업캐스팅 (Upcasting)
    • 자식 클래스 → 부모 클래스
    • 컴파일러에서 자동으로 변환
    • 부모 클래스 타입의 참조 변수로 자식 클래스의 객체를 참조
    • 자식 클래스의 메서드를 부모 클래스 타입으로 호출 가능
    • 하지만, 자식 클래스에만 있는 멤버(필드, 메서드)에는 접근 불가능
    • 오버라이딩된 메서드는 자식 클래스의 메서드를 따름
  • 다운캐스팅 (Downcasting)
    • 부모 클래스 → 자식 클래스
    • 부모 타입을 다시 자식 타입으로 변환
    • 명시적 변환 필요 (자식 클래스명 괄호)
    • 부모 클래스에서 선언되지 않은 자식의 멤버(필드, 메서드)에 접근 가능
    • 잘못된 다운캐스팅은 ClassCastException 발생 가능
    • instanceof 연산자를 사용하여 변환이 안전한지 확인
class Animal {
    void makeSound() {
        System.out.println("Animal makes sounds.");
    }
}

class Dog extends Animal {
    @Override
    void makeSound() {
        System.out.println("Bow-wow!");
    }

    void wagTail() {
        System.out.println("Wagging the tail.");
    }
}

public class Main {
    public static void main(String[] args) {
        Animal myAnimal = new Dog();  // 업캐스팅
        myAnimal.makeSound();  // 출력 : Bow-wow!, 오버라이딩된 메서드 호출

        if (myAnimal instanceof Dog) {  // instanceof로 변환 안전 확인
            Dog myDog = (Dog) myAnimal;  // 다운캐스팅 (명시적)
            myDog.wagTail();  // 출력 : Wagging the tail.
        }
    }
}

super, super()

  • super : 부모 클래스의 필드나 메서드를 호출할 때 사용
    • 부모의 메서드를 자식 클래스에서 오버라이딩 후 호출 가능 (예시 : super.메서드())
  • super() : 자식 클래스에서 부모의 생성자를 호출할 때 사용
    • 생성자는 기본적으로 상속되지 않으나, Sub Class의 생성자 안에 super(); 를 사용하여 가져올 수 있음
    • Sub Class에서는 반드시 super(); 를 이용한 생성자를 만들어야 하며, 생성하지 않으면 default 생성자가 생성됨
class Animal {
    String name;

    Animal(String name) {
        this.name = name;
    }

    void makeSound() {
        System.out.println(name + " makes sounds.");
    }
}

class Dog extends Animal {
    Dog(String name) {
        super(name);  // super()로 부모 클래스의 생성자 호출
    }

    @Override
    void makeSound() {
        super.makeSound();  // super로 부모 클래스의 메서드 호출
        System.out.println("Bow-wow!");
    }
}

public class Main {
    public static void main(String[] args) {
        Dog myDog = new Dog("Poppi");
        myDog.makeSound();
    }
}

Java

생성자란?

클래스의 객체가 생성될 때 자동으로 한 번 호출되는 특수 목적의 멤버 함수

레퍼런스 변수를 메모리 참조하기 전, 객체를 초기화하여 객체의 초기 상태를 설정하는 역할

  • 생성자는 반드시 1개 이상 있어야 함
  • 다른 멤버 함수와 다르게 리턴 타입이 없음
  • 생성자 이름은 클래스 이름과 동일한 이름이어야 함
  • 매개변수 조건에 따라 생성자 여러 개 작성 가능 (오버로딩 / Overloading)
  • 생성자 내에서 매서드를 활용 가능
  • 매개 변수를 가질 수 있음

 

1. 기본 생성자 / Default constructor

객체의 기본값으로 설정하는 매개변수가 없는 생성자

생성자를 생성하지 않으면 기본 생성자를 자동으로 생성

class Display {
    Display() { // 생성자 생성
        System.out.println("This is test text");
    }
}

public class Main {
    public static void main(String[] args) {
        Display view = new Display(); // 출력
    }
}

 

2. 매개 변수가 있는 생성자 / Parameterized Constructor

매개 변수를 사용하여 객체 생성 시 초기 값을 설정할 수 있도록 하는 생성자

class Display {
    String text;
    Display(String txt) { // 생성자 생성
        text = txt;
        System.out.println(text);
    }
}

public class Main {
    public static void main(String[] args) {
        Display view = new Display("test message"); // 출력
    }
}

 

3. 오버로딩 / Overloading

같은 이름의 생성자를 여러 개 사용하는 것

매개변수의 개수나 타입이 다른 여러 개의 생성자를 사용 가능

※ 오버로딩(Overloading)과는 다르다 (여기를 참조)

class Display {
    String text1, text2;
    int number;
    
    Display() {
        System.out.println("This is test text");
    }
    
    Display(String txt) {
        text1 = txt;
        System.out.println(text1);
    }
    
    Display(String txt, int num) {
        text2 = txt;
        number = num;
    	System.out.println(text2 + number);
    }
}

public class Main {
    public static void main(String[] args) {
        Display view1 = new Display(); // This is test text
        Display view2 = new Display("message 1"); // message 1
        Display view3 = new Display("message ", 2); // message 2
    }
}

 

4. this()

하나의 생성자에서 다른 생성자를 호출할 때 this()를 사용하여 코드 중복을 줄일 수 있음

※ this와 this()는 다른 개념

  • this : 인스턴스 매서드의 매개 변수로 선언된 변수명이 인스턴스 변수명과 같을 때, 인스턴스 변수와 지역 변수를 구분하기 위해서 사용
  • this() : 같은 class의 다른 생성자를 호출
class Display {
    String text;
    int number;
    
    Display() {
        this("message ", 0); // this()로 매개 변수가 있는 다른 생성자 호출
    }
    
    Display(String text, int number) { // 인스턴스 변수명과 매개 변수명이 같음
        this.text = text; // this로 구분
        this.number = number;
    }
    
    void show() {
        System.out.println(text + number);
    }
}

public class Main {
    public static void main(String[] args) {
        Display view1 = new Display();
        Display view2 = new Display("message ", 1);
        
        view1.show(); // 출력 : message 0
        view2.show(); // 출력 : message 1
    }
}

 

 

'Programming > Java' 카테고리의 다른 글

[Java] is-a 관계와 has-a 관계  (0) 2025.03.04
[Java] 상속 (Inheritance)  (1) 2025.03.04
[Java] 클래스 변수, 인스턴스 변수, 로컬 변수, 매개 변수  (0) 2025.02.28
[Java] Java란?  (1) 2025.02.28

Java

1. 클래스 변수 / Class Variable

  • 클래스 내부에 static 키워드로 선언된 변수
  • 클래스가 메모리에 로드될 때 메서드 영역(Method Area)에 한 번만 생성됨
  • 모든 인스턴스(객체)에서 공유되어 새로운 객체 생성 없이 기존 클래스명으로 직접 접근 가능
  • 공통 데이터 관리에 유리
class Test {
    static int staticValue = 50; // 클래스 변수 선언

    public void print() {
        System.out.println(staticValue);
    }
}

public class Main {
    public static void main(String[] args) {
        // Test test1 = new Test();
        // 새로운 객체 생성 불필요
        System.out.println(Test.staticValue); // 출력: 50
    }
}

 

2. 인스턴스 변수 / Instance Variable

  • 클래스 내부에 선언되지만, static이 없는 변수
  • 객체가 생성될 때마다 Heap 영역에 개별적으로 할당됨
  • 각 객체마다 독립적인 값을 가짐 (test1.instanceValue와 test2.instanceValue는 다른 값)
  • static으로 선언된 클래스 메서드에서 접근 시, 새로운 객체 생성 필요
class Test {
    static int staticValue = 50; // 클래스 변수 선언
    int instanceValue = 30; // 인스턴스 변수 선언

    public void print() {
        System.out.println(staticValue);
        System.out.println(instanceValue); // 클래스 메서드(static) 이외에서는 직접 사용 가능
    }
}

public class Main {
    public static void main(String[] args) {
        Test test1 = new Test();
        Test test2 = new Test();
        test1.instanceValue = test1.instanceValue + 10;
        test2.instanceValue = test2.instanceValue - 10;
        
        System.out.println(Test.staticValue); // 출력: 50
        System.out.println(test1.instanceValue); // 출력: 40
        System.out.println(test2.instanceValue); // 출력: 20
    }
}

 

3. 로컬 변수 / Local Variable

  • 메서드나 블록 내부에서 선언된 변수 메서드
  • 해당 메서드가 실행될 때 Stack 영역에 생성되고, 종료되면 사라짐
  • 생성된 메서드에서만 접근 가능하며, 다른 메서드에서 접근할 수 없음
  • 반드시 초기화 후 사용해야 함
class Test {
    public void print() {
    	int number = 100; // 로컬 변수 생성
        System.out.println(number + 50);
    }
}

public class Main {
    public static void main(String[] args) {
        Test test1 = new Test();
        test1.print(); // 출력: 150
        // System.out.println(test1.number);
        // 접근 불가
    }
}

 

4. 매개 변수 / Parameter

  • 메서드(함수)에서 입력 값을 전달받기 위해 사용하는 변수
  • 메서드 호출 시 인자(Argument)를 받아서 내부에서 처리할 수 있음
    • Parameter는 선언한 변수, Argument는 전달되는 실제 값
  • 메서드의 입력값을 동적으로 변경 가능
  • 여러 개의 매개변수를 가질 수 있음
class Calculator { 
    public void Sum(int a, int b) { // 매개 변수 선언
        System.out.println(a + b);
    }
}

public class Main {
    public static void main(String[] args) {
        Calculator cal = new Calculator();
        cal.Sum(4, 7); // 출력 : 11
    }
}

 

'Programming > Java' 카테고리의 다른 글

[Java] is-a 관계와 has-a 관계  (0) 2025.03.04
[Java] 상속 (Inheritance)  (1) 2025.03.04
[Java] 생성자 (Constructor)  (0) 2025.03.04
[Java] Java란?  (1) 2025.02.28

Java

Java의 특징

Write once, run anywhere
한 번 쓰면, 어디서든 실행된다
  • 플랫폼 독립적 언어
    • 플랫폼(OS)에 관계 없이, 한 번 작성하면 어디서든 실행 가능
    • 프로그램 실행의 주체가 운영 체제가 아닌 JVM(Java Virtual Machine, 자바 가상 머신)이기 때문
  • 객체 지향 프로그래밍(Object-Oriented Programming, OOP) 언어
    • 캡슐화, 상속, 다형성 등을 지원
    • 코드의 재사용성이 높고, 유지 보수가 쉬움
  • 자동 메모리 관리 / GC(Garbage Collection)
    • GC가 메모리를 자동으로 관리하여 개발자가 직접 메모리를 해제할 필요가 없음

 

Java의 처리 과정

C/C++처럼 소스 코드를 기계어로 직접 컴파일하지 않고, Bytecode를 생성한 뒤 기계어로 바꾸어 실행함

  1. Java program
    • Java 언어를 사용한 프로그램을 작성하여 .java 확장자를 가진 소스 코드 파일을 생성
  2. javac (Java compiler)
    • 생성한 .java 파일을 javac를 사용하여 컴파일
    • .java 파일을 .class 파일(Bytecode)로 변환
  3. Bytecode → JVM
    • JRE의 Java classloader를 통해 Bytecode 파일을 JVM 메모리로 로드
  4. JVM
    • 우선 JVM 실행 엔진에서 Bytecode 파일이 유효한지 검증
    • Bytecode 파일이 유효하다면 JIT(Just-In-Time) 컴파일러로 기계어 변환 및 실행
    • 인터프리터를 사용할 경우, 기계어로 컴파일하지 않고 한 줄씩 실행 (느림)
  5. GC (Garbage Collection)
    • 더 이상 사용되지 않는 객체를 자동으로 제거하여 메모리 관리

 

Java의 주요 구성 요소

  • JVM (Java Virtual Machine)
    • Java Bytecode를 실행하는 가상 머신
    • 운영체제와 독립적으로 작동하여 플랫폼 독립성을 보장함
  • JDK (Java Development Kit)
    • JRE, Javac, Java API, 디버거 등이 포함된 개발 도구
  • JRE (Java Runtime Environment)
    • JVM + 라이브러리
    • Java 프로그램을 실행하는데 필요한 환경

 

Java의 구성 단위

※ Eclipse 환경 기반 설명

계층적 구조로, 상위 단위는 하위 단위를 포함함

  1. Workspace
    • 최상위 작업 공간으로, 여러 Project를 포함함
    • 여러 Project를 그룹화하는 단위
  2. Project
    • 하나의 독립적인 Java 프로그램 또는 라이브러리를 의미
    • 여러 Package, Class 등을 포함함 (최소 1개의 Class를 포함해야 함)
    • 소스 코드 폴더 (src/)에 저장됨
  3. Package
    • Namespace 역할을 하며, Class 간의 이름 충돌 방지 (Class 이름이 같아도 Package 다르면 다르게 인식)
    • 관련 Class 및 Interface를 그룹화하는 단위
  4. Class
    • Object(객체)를 생성하는 기본 단위
    • 모든 Java 프로그램은 하나 이상의 Class를 포함해야 함
    • 하나의 .java 파일 안에 Public Class는 반드시 하나만 있어야 하며 파일명과 동일해야 함
  5. Method & Field
    • Method는 함수, Field는 변수
    • main() Method가 없으면, 해당 Class 직접 실행 불가 (다른 Class에서 호출은 가능)
    • Method 안에 Method 생성 불가
    • 매개변수(Parameter, Argument)를 추가 가능
      • Parameter는 정의된 변수, Argument는 입력되는 값
package com.example;  // Package

public class Car {  // Class
    String brand;  // Field

    public Car(String brand) {  // Constructor (생성자)
        this.brand = brand;
    }

    public void drive() {  // Method
        System.out.println(brand + " car is driving.");
    }
}

+ Recent posts