오전 12:57 2025-01-21

추가 필요

더보기

 generic
 제네릭은 모든 알파벳으로 지정할 수 있다
 관습적으로 많이 사용하는 키워드
 E: Element, 배열기반 구조에서 요소를 의미
 T : 일반적인 Type
 K : Key
 V : Value

 <k, v> : 제네릭은 여러 개 지정할 수 있다.</k, v>
  : T를 구현 또는 상속하고 있는 타입이 제네릭으로 지정되어야 함
  : T의 부모 또는 선조 타입 이어야 한다

 

 

 

Generic

  • Java에서 제네릭(generic)이란 데이터의 타입을 일반화하는 것을 의미함
    • 하나의 클래스에서 다양한 매개 자료형을 사용하고 싶은 경우에 사용함
    • Template 자료 형태 (자료형 변수)
  • 형식은 <자료형>
    • <> 사이에는 반드시 Class가 들어가야 한다.
    • 예시로, 정수형을 사용하고 싶다면 <int> - 불가, <Integer> - 가능
    • int는 일반 자료형이고, Integer는 Wrapper Class이기 때문이다.
  • 모든 클래스를 제네릭으로 선언할 수 있다.

 

(참고) int와 Integer의 차이

Wrapper Class에 대해서 언급한 적이 있다.

2024.12.30 - [Java/Java 문법] - Java 기본 문법 - Wrapper Class, String 메소드, 진수 변환

 

Java 기본 문법 - Wrapper Class, String 메소드, 진수 변환

public class MainClass { public static void main(String[] args) { /* wrapper class 일반 자료형(int, char, double...)을 클래스(기능추가)화 해 놓은 것 일반자료형 wrapper class byte Byte short Short int Integer long Long float Float dou

kungfugay.tistory.com

 

더보기

1. 기본형 vs. 참조형
int: Java의 기본 데이터 타입 중 하나로, 32비트 정수를 나타냅니다. 메모리에 직접 값을 저장합니다.
Integer: Java의 래퍼 클래스(Wrapper Class)로, 기본형 int를 객체로 감싸는 역할을 합니다. 객체이기 때문에 메모리에 참조가 저장됩니다.


2. null 값
int: 기본형이므로 null 값을 가질 수 없습니다. 항상 초기화되어야 하며 0이라는 기본값을 가집니다.
Integer: 객체이므로 null 값을 가질 수 있습니다. 이를 통해 값이 없음을 표현할 수 있습니다.


3. 사용 용도
int: 성능이 중요하고, 단순한 수치 연산이 필요할 때 사용합니다.
Integer: 컬렉션(예: ArrayList)과 같은 객체를 필요로 하는 곳에서 사용됩니다. 또한, 객체로서 메서드를 호출할 수 있습니다.

 

코드 예시

Class를 생성할 때 클래스명 옆에 <T> 라고 적어준다..

// T는 커스터마이징임. A, Area, 아무거나 써도 됨
class Box<T> {
    T temp;
    public Box (T temp) {
        this.temp = temp;
    }

    public T getTemp() {
        return temp;
    }

    public void setTemp(T temp) {
        this.temp = temp;
    }
}

 

제네릭 타입의 클래스 객체를 참조하는 인스턴스를 생성할 때

클래스명<자료형> 변수명 = new 클래스명<>(파라미터);

    // 메인함수
    Box<Integer> iBox = new Box<>(123);
    System.out.println(iBox.getTemp());

출력 결과

java.util.Calendar 클래스

Calendar 클래스는 자바에서 날짜와 시간에 관한 데이터를 손쉽게 처리할 수 있도록 제공하는 추상 클래스입니다.

이 클래스가 추상 클래스로 선언된 이유는 나라마다 사용하는 달력 체계가 조금씩 다를 수 있기 때문입니다.

 

이러한 Calendar 클래스에는 날짜와 시간을 처리하기 위한 다양한 필드와 메소드가 포함되어 있습니다.

Calendar 클래스의 모든 필드는 클래스 변수(static variable)이므로, 객체를 생성하지 않고도 바로 사용할 수 있습니다.

 

add() 메소드

add() 메소드는 전달된 Calendar 필드에서 일정 시간 만큼을 더하거나 빼줍니다.

즉, 특정 시간을 기준으로 일정 시간 전후의 날짜와 시간을 알 수 있습니다.

 

다음 예제는 add() 메소드를 이용하여 현재 시각에 120초를 더하는 예제입니다.

예제

Calendar time = Calendar.getInstance();

System.out.println(time.getTime());

 

time.add(Calendar.SECOND, 120);

System.out.println(time.getTime());

코딩연습 ▶

실행 결과

Thu Feb 16 08:57:29 KST 2017

Thu Feb 16 08:59:29 KST 2017

 

Calendar 클래스의 메소드는 현재 시각을 기준으로 동작하므로, 여러분의 결과는 위의 실행 결과와는 다를 것입니다.

before()와 after() 메소드

두 시간상의 전후 관계만을 알고 싶을 경우에는 before()와 after() 메소드를 사용할 수 있습니다.

before() 메소드는 현재 Calendar 인스턴스가 전달된 객체가 나타내는 시간보다 앞서는지를 판단합니다.

반대로 after() 메소드는 현재 Calendar 인스턴스가 전달된 객체가 나타내는 시간보다 나중인지를 판단합니다.

 

예제

Calendar time1 = Calendar.getInstance();

Calendar time2 = Calendar.getInstance();

Calendar time3 = Calendar.getInstance();

 

time2.set(1982, 2, 19);

time3.set(2020, 2, 19);

 

System.out.println(time1.before(time2));

System.out.println(time1.before(time3));

코딩연습 ▶

실행 결과

false

true


get() 메소드

get() 메소드는 전달된 Calendar 필드에 저장된 값을 반환합니다.

 

예제

Calendar time = Calendar.getInstance();

 

System.out.println(time.getTime());

System.out.println(time.get(Calendar.DAY_OF_WEEK));

System.out.println(time.get(Calendar.MONTH) + 1);

System.out.println(time.get(Calendar.DAY_OF_MONTH));

System.out.println(time.get(Calendar.HOUR_OF_DAY));

System.out.println(time.get(Calendar.MINUTE));

System.out.println(time.get(Calendar.SECOND));

System.out.println(time.get(Calendar.YEAR));

코딩연습 ▶

실행 결과

Thu Feb 16 08:57:44 KST 2017

5

2

16

8

57

44

2017


roll() 메소드

roll() 메소드는 전달된 Calendar 필드에서 일정 시간 만큼을 더하거나 빼줍니다.

하지만 add() 메소드와는 달리 다른 Calendar 필드에는 영향을 주지 않습니다.

즉, 계산 결과가 해당 필드의 최댓값이나 최솟값을 넘어가도 다른 필드에 영향을 주지 않습니다.

 

예제

Calendar time1 = Calendar.getInstance();

Calendar time2 = Calendar.getInstance();

System.out.println(time1.getTime());

 

time1.add(Calendar.SECOND, 60);

System.out.println(time1.getTime());

 

time2.roll(Calendar.SECOND, 60);

System.out.println(time2.getTime());

코딩연습 ▶

실행 결과

Thu Feb 16 08:58:23 KST 2017

Thu Feb 16 08:59:23 KST 2017

Thu Feb 16 08:58:23 KST 2017

 

위의 예제에서 add() 메소드를 사용하여 Calendar.SECOND 필드를 60초 증가시키면 결과적으로 Calendar.MINUTE 필드가 1 증가해야 합니다.

하지만 roll() 메소드를 사용하여 Calendar.SECOND 필드를 60초 증가시키면 Calendar.MINUTE 필드에는 아무런 영향을 주지 않습니다.

즉, Calendar.SECOND 필드만이 60초 증가하여 결과적으로 같은 값이 출력되게 됩니다.


set() 메소드

set() 메소드는 전달된 Calendar 필드를 특정 값으로 설정합니다.

 

다음 예제는 set() 메소드에 다양한 형태의 인수를 전달하여 시간을 설정하는 예제입니다.

예제

Calendar time = Calendar.getInstance();

System.out.println(time.getTime());

 

time.set(Calendar.YEAR, 2020);

System.out.println(time.getTime());

 

time.set(1982, 1, 19); // 1은 2월을 나타냄.

System.out.println(time.getTime());

 

time.set(1982, 1, 19, 12, 34, 56);

System.out.println(time.getTime());

코딩연습 ▶

실행 결과

Thu Feb 16 08:58:01 KST 2017

Sun Feb 16 08:58:01 KST 2020

Fri Feb 19 08:58:01 KST 1982

Fri Feb 19 12:34:56 KST 1982


대표적인 Calendar 메소드

Calendar 클래스의 메소드는 매우 다양하며, 그중에서 많이 사용되는 메소드는 다음과 같습니다.

메소드설명

void add(int field, int amount) 전달된 Calendar 필드에서 특정 시간 만큼을 더하거나 뺌.
boolean after(Object when) 현재 Calendar 인스턴스가 전달된 객체가 나타내는 시간보다 나중인지를 확인함.
boolean before(Object when) 현재 Calendar 인스턴스가 전달된 객체가 나타내는 시간보다 앞서는지를 확인함.
void clear(int field) 현재 Calendar 인스턴스의 모든 필드의 값을 undefined로 설정함.
int get(int field) 전달된 Calendar 필드에 저장된 값을 반환함.
static Calendar getInstance() 시스템의 현재 날짜와 시간으로 Calendar 인스턴스를 생성하여 반환함.
Date getTime() 현재 Calendar 인스턴스의 시간 정보를 나타내는 Date 인스턴스를 생성하여 반환함.
void roll(int field, int amount) 전달된 Calendar 필드에서 특정 시간 만큼을 더하거나 뺌.
void set(int field, int value)
void set(int year, int month, int date)
void set(int year, int month, int date, int hourOfDay, int minute)
void set(int year, int month, int date, int hourOfDay, int minute, int second)
전달된 Calendar 필드를 특정 값으로 설정함.

코드 예시

import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;

public class MainClass {
    public static void main(String[] args) {

        Calendar cal = Calendar.getInstance();

        // 날짜 getter
        int year = cal.get(Calendar.YEAR);      // cal.get(1);
        int month = cal.get(Calendar.MONTH) + 1;    // cal.get(2);
            // 0~11월로 반환되기 때문임
        int day = cal.get(Calendar.DATE);       // cal.get(5);
        System.out.printf("year: %d month: %d day: %d \n", year, month, day);

        // 날짜 setter
        cal.set(Calendar.YEAR, 2026);
        cal.set(Calendar.MONTH, 2 -1);  // 2월
        cal.set(Calendar.DATE, 14);

        // 시간도 사용가능 (현재 시간으로 가져옴)
        int hour = cal.get(Calendar.HOUR);
        int minute = cal.get(Calendar.MINUTE);
        int second = cal.get(Calendar.SECOND);

        // 다시 대입
        year = cal.get(Calendar.YEAR);      // cal.get(1);
        month = cal.get(Calendar.MONTH) + 1;    // cal.get(2);
        // 0~11월로 반환되기 때문임
        day = cal.get(Calendar.DATE);       // cal.get(5);
        System.out.printf("year: %d month: %d day: %d\n", year, month, day);

        // 요일 (1~7) 일 ~토
        int weekday = cal.get(Calendar.DAY_OF_WEEK);
        // System.out.println("weekday: " + weekday); // 5 = 목요일
        switch (weekday) {
            case 1:
                System.out.println("일요일");
                break;
            case 2:
                System.out.println("월요일");
                break;
            case 3:
                System.out.println("화요일");
                break;
            case 4:
                System.out.println("수요일");
                break;
            case 5:
                System.out.println("목요일");
                break;
            case 6:
                System.out.println("금요일");
                break;
            case 7:
                System.out.println("토요일");
                break;
        }

        // 지정한 날짜의 마지막 날짜 ( 28, 29, 30, 31 )
        int lastDay = cal.getActualMaximum(Calendar.DAY_OF_MONTH);
        System.out.println("lastday: " + lastDay);


    }
}

 

참고자료: https://www.tcpschool.com/java/java_api_calendar

'Java' 카테고리의 다른 글

[Java] java.lang.Object 클래스  (1) 2025.01.09

자료출처: https://www.tcpschool.com/java/java_api_object

Object 클래스


java.lang 패키지

java.lang 패키지는 자바에서 가장 기본적인 동작을 수행하는 클래스들의 집합입니다.

따라서 자바에서는 java.lang 패키지의 클래스들은 import 문을 사용하지 않아도 클래스 이름만으로 바로 사용할 수 있도록 하고 있습니다.


java.lang.Object 클래스

java.lang 패키지 중에서도 가장 많이 사용되는 클래스는 바로 Object 클래스입니다.

Object 클래스는 모든 자바 클래스의 최고 조상 클래스가 됩니다.

따라서 자바의 모든 클래스는 Object 클래스의 모든 메소드를 바로 사용할 수 있습니다.

 

이러한 Object 클래스는 필드를 가지지 않으며, 총 11개의 메소드만으로 구성되어 있습니다.


toString() 메소드

toString() 메소드는 해당 인스턴스에 대한 정보를 문자열로 반환합니다.

이때 반환되는 문자열은 클래스 이름과 함께 구분자로 '@'가 사용되며, 그 뒤로 16진수 해시 코드(hash code)가 추가됩니다.

16진수 해시 코드 값은 인스턴스의 주소를 가리키는 값으로, 인스턴스마다 모두 다르게 반환됩니다.

 

다음 예제는 toString() 메소드를 이용하여 인스턴스의 정보를 출력하는 예제입니다.

예제

Car car01 = new Car();

Car car02 = new Car();

 

System.out.println(car01.toString());

System.out.println(car02.toString());

코딩연습 ▶

실행 결과

Car@15db9742

Car@6d06d69c

 

자바에서 toString() 메소드는 기본적으로 각 API 클래스마다 자체적으로 오버라이딩을 통해 재정의되어 있습니다.

equals() 메소드

equals() 메소드는 해당 인스턴스를 매개변수로 전달받는 참조 변수와 비교하여, 그 결과를 반환합니다.

이때 참조 변수가 가리키는 값을 비교하므로, 서로 다른 두 객체는 언제나 false를 반환하게 됩니다.

 

다음 예제는 equals() 메소드를 이용하여 두 인스턴스를 서로 비교하는 예제입니다.

예제

Car car01 = new Car();

Car car02 = new Car();

 

System.out.println(car01.equals(car02));

car01 = car02; // 두 참조 변수가 같은 주소를 가리킴.

System.out.println(car01.equals(car02));

코딩연습 ▶

실행 결과

false

true

 

자바에서 equals() 메소드는 기본적으로 각 API 클래스마다 자체적으로 오버라이딩을 통해 재정의되어 있습니다.

clone() 메소드

clone() 메소드는 해당 인스턴스를 복제하여, 새로운 인스턴스를 생성해 반환합니다.

하지만 Object 클래스의 clone() 메소드는 단지 필드의 값만을 복사하므로, 필드의 값이 배열이나 인스턴스면 제대로 복제할 수 없습니다.

따라서 이러한 경우에는 해당 클래스에서 clone() 메소드를 오버라이딩하여, 복제가 제대로 이루어지도록 재정의해야 합니다.

 

이러한 clone() 메소드는 데이터의 보호를 이유로 Cloneable 인터페이스를 구현한 클래스의 인스턴스만이 사용할 수 있습니다.

 

다음 예제는 clone() 메소드를 이용하여 인스턴스를 복제하는 예제입니다.

예제

import java.util.*;

 

class Car implements Cloneable {

    private String modelName;

  private ArrayList<String> owners = new ArrayList<String>();


    public String getModelName() { return this.modelName; }                    // modelName의 값을 반환함

    public void setModelName(String modelName) { this.modelName = modelName; } // modelName의 값을 설정함

 

    public ArrayList getOwners() { return this.owners; }                      // owners의 값을 반환함

    public void setOwners(String ownerName) { this.owners.add(ownerName); }   // owners의 값을 추가함

 

    public Object clone() {

        try {

          Car clonedCar = (Car)super.clone();

          // clonedCar.owners = (ArrayList)owners.clone();

            return clonedCar;

      } catch (CloneNotSupportedException ex) {

            ex.printStackTrace();

            return null;

        }

    }

}

 

public class Object03 {

    public static void main(String[] args) {

      Car car01 = new Car();

        car01.setModelName("아반떼");

        car01.setOwners("홍길동");

      System.out.println("Car01 : " + car01.getModelName() + ", " + car01.getOwners() + "\n");

 

      Car car02 = (Car)car01.clone();

      car02.setOwners("이순신");

      System.out.println("Car01 : " + car01.getModelName() + ", " + car01.getOwners());

      System.out.println("Car02 : " + car02.getModelName() + ", " + car02.getOwners());

    }

}

코딩연습 ▶

실행 결과

Car01 : 아반떼, [홍길동]

 

Car02 : 아반떼, [홍길동, 이순신]

Car02 : 아반떼, [홍길동, 이순신]

 

위 예제의 ②번 라인에서는 부모 클래스의 clone() 메소드를 호출하여 clone() 메소드를 오버라이딩하고 있습니다.

⑤번 라인에서는 Car 클래스의 인스턴스인 car01을 생성하고, ⑦번 라인에서는 오버라이딩한 clone() 메소드를 호출하여 복제를 수행하고 있습니다.

 

하지만 ②번 라인처럼 clone() 메소드를 재정의하면, 필드의 값이 ①번 라인처럼 인스턴스일 때는 제대로 된 복제를 수행할 수 없습니다.

⑧번 라인에서는 복제된 인스턴스인 car02의 owners 필드에 새로운 값을 하나 추가합니다.

하지만 ⑨번 라인의 실행 결과를 보면, ⑦번 라인의 결과와는 달리 원본 인스턴스인 car01의 owners 필드에도 새로운 값이 추가되었음을 확인할 수 있습니다.

이처럼 단순히 부모 클래스의 clone() 메소드를 호출하여 clone() 메소드를 재정의하면, 배열이나 인스턴스인 필드는 복제되는 것이 아닌 해당 배열이나 인스턴스를 가리키는 주소값만이 복제되는 것입니다.

 

따라서 정확한 복제를 위해서는 ③번 라인처럼 배열이나 인스턴스인 필드에 대해서는 별도로 clone() 메소드를 구현하여 호출해야 합니다.

③번 라인의 주석을 해제하고 결과보기를 다시 실행하면, 다음과 같이 정확한 실행 결과가 출력될 것입니다.

실행 결과

Car01 : 아반떼, [홍길동]

 

Car02 : 아반떼, [홍길동]

Car02 : 아반떼, [홍길동, 이순신]


Object 메소드

Object 클래스의 메소드는 다음과 같습니다.

메소드설명

protected Object clone() 해당 객체의 복제본을 생성하여 반환함.
boolean equals(Object obj) 해당 객체와 전달받은 객체가 같은지 여부를 반환함.
protected void finalize() 해당 객체를 더는 아무도 참조하지 않아 가비지 컬렉터가 객체의 리소스를 정리하기 위해 호출함.
Class<T> getClass() 해당 객체의 클래스 타입을 반환함.
int hashCode() 해당 객체의 해시 코드값을 반환함.
void notify() 해당 객체의 대기(wait)하고 있는 하나의 스레드를 다시 실행할 때 호출함.
void notifyAll() 해당 객체의 대기(wait)하고 있는 모든 스레드를 다시 실행할 때 호출함.
String toString() 해당 객체의 정보를 문자열로 반환함.
void wait() 해당 객체의 다른 스레드가 notify()나 notifyAll() 메소드를 실행할 때까지 현재 스레드를 일시적으로 대기(wait)시킬 때 호출함.
void wait(long timeout) 해당 객체의 다른 스레드가 notify()나 notifyAll() 메소드를 실행하거나 전달받은 시간이 지날 때까지 현재 스레드를 일시적으로 대기(wait)시킬 때 호출함.
void wait(long timeout, int nanos) 해당 객체의 다른 스레드가 notify()나 notifyAll() 메소드를 실행하거나 전달받은 시간이 지나거나 다른 스레드가 현재 스레드를 인터럽트(interrupt) 할 때까지 현재 스레드를 일시적으로 대기(wait)시킬 때 호출함.



'Java' 카테고리의 다른 글

[Java] java.util.Calendar 클래스  (1) 2025.01.09

객체지향프로그래밍의 다형성(Polymorphism)이란?

상속 후에 여러 형태의 자식 클래스 & Over Ride를 의미한다

코드 예시

  • 부모 클래스: Animal
  • Animal을 부모로 하는 자식 클래스:Cat, Dog
public class Animal {
    public void speech() {
        System.out.println("Animal speech()");
    }
}
public class Cat extends Animal {
    @Override
    public void speech() {
        System.out.println("야옹야옹");
    }

    public void cat_method() {
        System.out.println("저는 야옹이에요");
    }
}
public class Dog extends Animal {
    @Override
    public void speech() {
        System.out.println("멍멍");
    }

    public void dog_method() {
        System.out.println("난 강아지다");
    }
}

만약

최대 10개까지의 Dog 또는 Cat 클래스로 인스턴스를 만들고, 각 클래스의 메소드를 호출해보고 싶다.

Dog로만 10개를 만들 수도 있고, Cat으로만 10개를 만들 수도 있다.

Dog 타입의 배열을 10개, Cat 타입의 배열을 10개 선언해서 각자 만들어야 하나?

    // dog + cat = 10
    Dog[] dogArr = new Dog[10];
    Cat[] catArr = new Cat[10];
    dogArr[0] = new Dog();
    catArr[0] = new Cat();
    catArr[1] = new Cat();
    dogArr[1] = new Dog();

이럴 때 Dog 클래스와 Cat 클래스의 부모 클래스인 Animal을 사용할 수 있다.

Animal ani = new Dog();
  • ani는 Animal 타입으로 선언되었지만, Dog 클래스의 객체를 참조하고 있다.
  • Dog 클래스의 객체가 할당되어 있기 때문에 Dog에 정의된 메서드를 실행할 수 있어야 함
  • 그러나 ani는 Animal 타입이기 때문에, Animal 클래스에서 정의된 속성이나 메서드만 직접적으로 호출할 수 있다.
  • Dog 클래스에서 추가된 속성이나 메서드는 ani를 통해 접근할 수 없다

 

(참고) 한편, instanceof 로 인스턴스 타입을 확인할 수 있다.

    if (ani instanceof Dog) {
        System.out.println("Dog 인스턴스입니다.");
    }

 

즉, ani는 Dog 객체를 참조하고 있지만, Animal에서 상속받아 Dog에서 오버라이드한 메서드만 접근할 수 있다는 것이다.

Dog의 고유 메소드에는 어떻게 접근할 수 있을까?

 

강제 형변환

    Dog d = (Dog)ani;

Dog 객체에서 super를 참조하고 있던 포인터가 this로 포인터를 바꾼 것과 같은 결과이다.

 

 

 

정상적으로 Dog의 고유 메소드에 접근할 수 있는 것을 확인할 수 있다.

 

 

최종 코드

// 하나의 인스턴스로 관리
Animal[] animal = new Animal[10];
animal[0] = new Dog();
animal[1] = new Cat();
animal[2] = new Cat();
animal[3] = new Dog();

for (Animal a: animal) {
    if (a != null) {
        a.speech();                 // Animal으로부터 상속받은 Cat과 Dog의 오버라이드 메소드
    }
    if (a instanceof Dog) {
        Dog d = (Dog)a;             // 강제형변환 (포인터 변경)
        d.dog_method();             // Dog의 고유 메소드
    } else if (a instanceof Cat) {
        ((Cat)a).cat_method();      // 간결한 표현식
    }
}

실행결과

OOP 특징 2 - 상속성

상속(Inheritance)란?

  • 부모 클래스로부터 속성 또는 특성 (attribute, property)을 상속받는 것
    즉, variable(변수), method(함수)를 물려받는 것임
  • 다중 상속은 불가능하다. (Java의 특징, 타언어는 가능)
    예를 들어, class Child extends Human, Animal { ... 등은 불가

구문 형식 : extends

    class 부모클래스명 {
        부모변수
        부모메소드
    }

    class 자식클래스명 extends 부모클래스명 {
        ((부모변수))
        ((부모메소드))
        자식변수
        자식메소드
    }

 

코드 예시 1: 기본적인 형태

- 부모변수: number, name

- 부모메소드: parent_method()

- 자식클래스 (=Child)에서 부모의 변수와 함수를 모두 사용할 수 있음

class Parent {
    int number;
    String name;

    void parent_method() {
        System.out.println("Parent parent_method()");
    }
}

class Child extends Parent {
}
// 메인함수
Child child = new Child();

child.number = 123;
child.name = "홍길동";
child.parent_method();

실행 결과

 

(참고) 자식 클래스의 인스턴스를 생성할 때 호출되는 생성자를 확인해보자

부모 생성자가 먼저 호출된 후, 자식의 생성자가 호출되는 것을 볼 수 있다

실행 결과

오버라이드 (Override)

- 상속 받은 클래스에서 추가/보강을 기입하는 것

- super: 부모 클래스를 가리키는 주소 (pointer; 참조 또는 reference라고도 함)

 

코드 예시 2: 부모 메소드를 오버라이딩 하는 경우

실행 결과

 

코드 예시 3: 부모 메소드를 오버라이딩 했으나, 부모 메소드를 호출하는 경우

이 때 접근지정자 super를 활용할 수 있다.

 

(참고) 부모 클래스의 멤버 변수의 접근제어자가 private 혹은 protected 일 때

private

- 자식 클래스에서 접근이 불가능하다

- 외부에서 접근이 불가능하다

- setter, getter로 외부에서 접근이 가능하다

 

코드 예시

(좌) 부모 클래스 / (우) 자식 클래스
메인 함수
실행 결과

protected

- 자식 클래스에서는 접근이 가능하다

- 외부에서는 접근이 불가능하다

- setter와 getter로 외부에서 접근이 가능하다

 

작업 순서는 DTO -> DAO -> MainClass

 

 

지금 해놓은 코드에서 더 할 만한 것은

1. MainClass 의 while 문 종료 조건 추가

2. DAO 클래스에서 코드가 겹치는 작업이 있음 (select, update, delete)

- 일단 '삭제/수정/검색'할 항목이 존재하는지 검증해야 하는 루틴

3. 검색 루틴에서 검색 조건을 구체화 할 수 있음

4. 업데이트 루틴에서 업데이트 할 항목을 구체화 할 수 있음

5. 삭제 루틴에서 배열을 앞으로 옮겨줘야 함, 그 이후에 삭제하는 것으로 중간에 비는 항목 처리 가능

- 이것은 ArrayList를 사용하면 의미가 없는 작업이기는 함.


DTO 클래스

package dto;

// Data Transform Object : DTO
public class StudentDTO {
    private int number;
    private String name;
    private double height;
    private String address;

    public StudentDTO() { }

    public StudentDTO(int number, String name, double height, String address) {
        this.number = number;
        this.name = name;
        this.height = height;
        this.address = address;
    }

    public int getNumber() {
        return number;
    }

    public void setNumber(int number) {
        this.number = number;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public double getHeight() {
        return height;
    }

    public void setHeight(double height) {
        this.height = height;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return "StudentDTO{" +
                "number=" + number +
                ", name='" + name + '\'' +
                ", height=" + height +
                ", address='" + address + '\'' +
                '}';
    }
}

 

DAO 클래스

- CRUD 메소드의 이름을 insert, delete, select, update로 변경함

- print, search 메소드 추가

package dao;

import dto.StudentDto;

import java.util.Scanner;

// Data Access Object : DAO (CRUD) -> insert, delete, select, update로 변경
public class StudentDao {
    private Scanner sc;
    private StudentDto[] students = new StudentDto[10];
    private int count;  // 배열 크기 관리를 위한 저장용 변수

    public StudentDao() {
        sc = new Scanner(System.in);
        count = 0;  // 초기화

        // 테스트용 데이터
        students[0] = new StudentDto(1, "김일성", 169, "평양시");
        students[1] = new StudentDto(2, "김정일", 170, "평양시");
        students[2] = new StudentDto(3, "김정은", 175, "평양시");
        students[3] = new StudentDto(4, "김여정", 160, "평양시");
        students[4] = new StudentDto(5, "리설주", 164, "평양시");
    }

    // 함수 4개 만들어야 함
    public void insert() {  // 추가
        System.out.println("학생 추가");
        System.out.print("번호 >>> ");
        int number = sc.nextInt();

        System.out.print("이름 >>> ");
        String name = sc.next();

        System.out.print("신장 >>> ");
        double height = sc.nextDouble();

        System.out.print("주소 >>> ");
        String address = sc.next();

        students[count] = new StudentDto(number, name, height, address);
/*        // 객체 생성 후 배열에 삽입 (같은 내용)
        StudentDTO dto = new StudentDTO(number, name, height, address);
        students[count] = dto;*/
        count++;
    }

    public int search(String name) {
        int index = -1;
        for (int i=0; i<students.length; i++) {
            StudentDto dto = students[i];
            if (dto != null && name.equals(dto.getName())) {
                index = i;
                break;
            }
        }
        return index;
    }

    public void delete() {  // 삭제
        System.out.println("학생 삭제");
        System.out.print("삭제할 학생 이름 >>> ");
        String name = sc.next();

        // 방법1 - 인덱스 번호로 삭제하기
        // 검색
        int index = -1;
        for (int i=0; i<students.length; i++) {
            StudentDto dto = students[i];
            if (dto != null && name.equals(dto.getName())) {
                index = i;
                break;
            }
        }

        // 삭제
        if (index == -1) {
            System.out.println("학생정보를 찾을 수 없습니다!");
            return;
        }
        students[index] = null;
        System.out.println("학생이 삭제되었습니다");

        // 방법2 - 배열이 아니고 컬렉션을 사용한다면, 이렇게
/*        StudentDto dto = null;
        for (StudentDto st : students) {
            if (st != null && name.equals(st.getName())) {
                dto = st;   // 이 부분에 주목
            }
        }

        if (dto == null) {
            System.out.println("학생정보를 찾을 수 없습니다");
            return;
        }

        // 배열이기 때문에 이 부분 추가
        for (int i=0; i<students.length; i++) {
            if (dto == students[i]) {
                students[i] = null;
            }
        }

        dto = null;
        System.out.println("학생 데이터가 삭제되었습니다");*/
    }

    public void select() {  // 검색
        System.out.println("학생 검색");
        System.out.print("검색할 학생 이름 >>> ");
        String name = sc.next();

        int index = search(name);

        if (index == -1) {
            System.out.println("학생정보를 찾을 수 없습니다!");
            return;
        }
        System.out.println("학생정보입니다.");
        System.out.println(students[index]);
    }

    public void update() {  // 수정
        System.out.println("학생 수정");
        System.out.print("수정할 학생 이름 >>> ");
        String name = sc.next();

        int index = search(name);

        System.out.println("학생정보입니다.");
        System.out.println(students[index]);

        System.out.println("수정할 주소 입력");
        String address = sc.next();

        students[index].setAddress(address);
        System.out.println("수정이 완료되었습니다.");
    }

    public void print() {
        for (int i=0; i< students.length; i++) {
            StudentDto st = students[i];
            if (st != null) {
                System.out.println(st.toString());
            }
        }
    }
}

MainClass 코드

package main;

import dao.StudentDAO;

import java.util.Scanner;

public class MainClass {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);

        // menu
        StudentDAO dao = new StudentDAO();

        while (true) {
            System.out.println("<  행복관리 프로그램  >");
            System.out.println("1. 학생추가");
            System.out.println("2. 학생삭제");
            System.out.println("3. 학생검색");
            System.out.println("4. 학생수정");
            System.out.println("5. 모두출력");

            System.out.print("메뉴번호를 입력 >>> ");
            int menu = sc.nextInt();

            switch (menu) {
                case 1:
                    dao.insert();
                    break;
                case 2:
                    dao.delete();
                    break;
                case 3:
                    dao.select();
                    break;
                case 4:
                    dao.update();
                    break;
                case 5:
                    dao.print();
                    break;
            }

        }

    }
}

+ Recent posts