본문 바로가기
공부기록/알고리즘

Chapter 02-2. 기본 자료구조_클래스란

by 루팽 2024. 6. 22.

클래스(class)

서로 다른 여러 데이터형을 자유로이 조합하여 만들 수 있는 자료구조

// 클래스 선언의 예
class XYZ {
	int x; // int형 필드 x
	long y; // long형 필드 y
	double z; // double형 필드 z
}

XYZ a; // XYZ형의 클래스형 변수 a 선언
a = new XYZ(); // XYZ형의 클래스 인스턴스를 생성하고 참조하는 곳을 대입

XYZ a = new XYZ(); // 변수 선언, 인스턴트 생성, 연결 짓기를 한꺼번에 수행
// 클래스형 변수 a가 참조하는 클래스 인스턴스 안의 필드는 a.x, a.y, a.x로 접근

 

신체검사 데이터용 클래스 배열에서 평균 키와 시력의 분포를 구하기

package ch02_2;

import java.util.Scanner;

// 신체검사 데이터용 클래스 배열에서 평균 키와 시력의 분포를 구하기
public class Ex01_physicalExamination {
    static final int VMAX = 21; // 시력 분포(0.0부터 0.1 단위로 21개)

    static class PhyscData {
        String name; // 이름
        int height; // 키
        double vision; // 시력

        // 생성자
        PhyscData(String name, int height, double vision) {
            this.name = name;
            this.height = height;
            this.vision = vision;
        }
    }

    // 키의 평균 값 구하기
    static double aveHeight(PhyscData[] dat) {
        double sum = 0;

        for (int i = 0; i < dat.length; i++) {
            sum += dat[i].height;
        }

        return sum / dat.length;
    }

    // 시력 분포를 구함
    static void distVision(PhyscData[] dat, int[] dist) {
        int i = 0;
        dist[i] = 0;
        for (i = 0; i < dat.length; i++) {
            if (dat[i].vision >= 0.0 && dat[i].vision <= VMAX / 10.0) {
                dist[(int) (dat[i].vision * 10)]++;
            }
        }
    }

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

        PhyscData[] x = {
                new PhyscData("강민하", 162, 0.3),
                new PhyscData("김찬우", 173, 0.7),
                new PhyscData("박준서", 175, 2.0),
                new PhyscData("유서범", 171, 1.5),
                new PhyscData("이수연", 168, 0.4),
                new PhyscData("장경오", 174, 1.2),
                new PhyscData("황지안", 169, 0.8),
        };

        int[] vdist = new int[VMAX]; // 시력 분포

        System.out.println("<< 신체 검사 리스트 >>");
        System.out.println("이름     키     시력");
        System.out.println("------------------");

        for (int i = 0; i < x.length; i++) {
            System.out.printf("%-8s%3d%5.1f\\n",
                    x[i].name, x[i].height, x[i].vision);
        }

        System.out.printf("\\n평균 키: %5.1fcm\\n", aveHeight(x));

        distVision(x, vdist); // 시력 분포 구하기

        System.out.println("\\n시력 분포");
        for (int i = 0; i < VMAX; i++) {
            System.out.printf("%3.1f~: %2d명\\n", i / 10.0, vdist[i]);
        }
    }
}

/*
<< 신체 검사 리스트 >>
이름     키     시력
------------------
강민하     162  0.3
김찬우     173  0.7
박준서     175  2.0
유서범     171  1.5
이수연     168  0.4
장경오     174  1.2
황지안     169  0.8

평균 키: 170.3cm

시력 분포
0.0~:  0명
0.1~:  0명
0.2~:  0명
0.3~:  1명
0.4~:  1명
0.5~:  0명
(... 생략 ...)
 */

 

평균 키와 시력 분포(그래프 출력)

package ch02_2;

import java.util.Scanner;

// 평균 키와 시력 분포(그래프 출력)
public class Ex02_physicalExaminationEx {
    static final int VMAX = 21; // 시력 분포(0.0부터 0.1간격으로 21개)

    static class PhyscData {
        String name; // 이름
        int height; // 키
        double vision; // 시력

        // 생성자
        public PhyscData(String name, int height, double vision) {
            this.name = name;
            this.height = height;
            this.vision = vision;
        }
    }

    // 평균 키 구하기
    static double avgHeight(PhyscData[] dat) {
        double sum = 0;

        for (int i = 0; i < dat.length; i++) {
            sum += dat[i].height;
        }

        return sum / dat.length;
    }

    // 시력 분포 구하기
    static void distVision(PhyscData[] dat, int[] dist) {
        int i = 0;

        dist[i] = 0;
        for (i = 0; i < dat.length; i++) {
            if (dat[i].vision >= 0.0 && dat[i].vision <= VMAX / 10.0) {
                dist[(int) (dat[i].vision * 10)]++;
            }
        }
    }

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

        PhyscData[] x = {
                new PhyscData("강민하", 162, 0.3),
                new PhyscData("김찬우", 173, 0.7),
                new PhyscData("박준서", 175, 2.0),
                new PhyscData("유서범", 171, 1.5),
                new PhyscData("이수연", 168, 0.4),
                new PhyscData("장경오", 174, 1.2),
                new PhyscData("황지안", 169, 0.8),
        };

        int[] vdist = new int[VMAX]; // 시력의 분포

        System.out.println("<< 신체 검사 리스트 >>");
        System.out.println("이름     키     시력");
        System.out.println("------------------");
        for (int i = 0; i < x.length; i++) {
            System.out.printf("%-8s%3d%5.1f\\n", x[i].name, x[i].height, x[i].vision);
        }
        System.out.printf("\\n평균키: %5.1fcm\\n", avgHeight(x));

        distVision(x, vdist);
        System.out.println("\\n시력의 분포");
        for (int i = 0; i < VMAX; i++) {
            System.out.printf("%3.1f~: ", i / 10.0);
            for (int j = 0; j < vdist[i]; j++) {
                System.out.print("*");
            }
            System.out.println();
        }
    }
}

/*
<< 신체 검사 리스트 >>
이름     키     시력
------------------
강민하     162  0.3
김찬우     173  0.7
박준서     175  2.0
유서범     171  1.5
이수연     168  0.4
장경오     174  1.2
황지안     169  0.8

평균키: 170.3cm

시력의 분포
0.0~: 
0.1~: 
0.2~: 
0.3~: *
0.4~: *
(...생략...)
 */

 

날짜 클래스

package ch02_2;

import java.util.Scanner;

// 날짜 클래스
public class Ex03_YMD {
    static class YMD {
        int y; // 년
        int m; // 월(1~12)
        int d; // 일(1~31)

        // 각 월의 일수
        static int[][] mdays = {
                {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, // 평년
                {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, // 윤년
        };

        // year년의 윤년 여부 - 평년: 0 / 윤년: 1
        static int isLeap(int year) {
            return (year % 4 == 0 && year % 10 != 00 || year % 400 == 0) ? 1 : 0;
        }

        // 생성자
        YMD(int y, int m, int d) {
            this.y = y;
            this.m = m;
            this.d = d;
        }

        // n일 후의 날짜 반환
        YMD after(int n) {
            YMD temp = new YMD(this.y, this.m, this.d);

            if (n < 0) {
                return before(-n);
            }

            temp.d += n;

            while (temp.d > mdays[isLeap(temp.y)][temp.m - 1]) {
                temp.d -= mdays[isLeap(temp.y)][temp.m - 1];
                if (++temp.m > 12) {
                    temp.y++;
                    temp.m = 1;
                }
            }

            return temp;
        }

        // n일 전의 날짜 반환
        YMD before(int n) {
            YMD temp = new YMD(this.y, this.m, this.d);

            if (n < 0) {
                return after(-n);
            }

            temp.d -= n;

            while (temp.d < 1) {
                if (--temp.m < 1) {
                    temp.y--;
                    temp.m = 12;
                }
                temp.d += mdays[isLeap(temp.y)][temp.m - 1];
            }

            return temp;
        }
    }

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

        System.out.println("날짜를 입력하세요");
        System.out.print("년: ");
        int y = scanner.nextInt();
        System.out.print("월: ");
        int m = scanner.nextInt();
        System.out.print("일: ");
        int d = scanner.nextInt();

        YMD date = new YMD(y, m, d);

        System.out.print("며칠 전/후의 날짜를 구할까요?: ");
        int n = scanner.nextInt();

        YMD d1 = date.after(n);
        System.out.printf("%d일 후의 날짜는 %d년 %d월 %d일입니다.\\n", n, d1.y, d1.m, d1.d);

        YMD d2 = date.before(n);
        System.out.printf("%d일 전의 날짜는 %d년 %d월 %d일입니다.\\n", n, d2.y, d2.m, d2.d);
    }
}

/*
날짜를 입력하세요
년: 2024
월: 6
일: 22
며칠 전/후의 날짜를 구할까요?: 28
28일 후의 날짜는 2024년 7월 20일입니다.
28일 전의 날짜는 2024년 5월 25일입니다.
 */

 

클래스 본체와 멤버

클래스 본체에서 아래와 같은 내용 선언 가능

  • 멤버(필드, 메서드, 중첩(nested) 클래스, 중첩 인터페이스)
  • 클래스 초기화, 인스턴스 초기화
  • 생성자

 

클래스 문법 규칙 및 특징

  • 필드, 메서드, 생성자를 선언할 때 public, protected, private를 지정 가능
  • 메서드, 생성자는 다중으로 정의(오버로드) 할 수 있음
  • final로 선언한 필드는 값을 한 번만 대입 가능
  • 생성자는 새로 생성하는 인스턴스를 초기화하기 위해 사용
class A {
	private int f1; // 비공개 필드
	protected int f2; // 한정 공개 필드
	public int f3; // 공개 필드
	
	static final int S1 = 0; // 정적 상수 피 ㄹ드
	
	public A() {
		f1 = f2 = f3 = 0;
	}
	
	// 생성자
	public A(int f1, int f2, int f3) {
		this.f1 = f1;
		this.f2 = f2;
		this.f3 = f3;
	}
	
	// 메서드 f1의 setter
	public void setF1(int f) {
		f1 = f;
	}
	
	// 메서드 f1의 getter
	public int getF1() {
		return f1;
	}
}

 

공개 클래스(public class)

접근 제한자 public을 붙여 클래스 선언

다른 패키지에서 사용할 수 있는 클래스

 

파이널 클래스(final class)

접근 제한자 final을 붙여 클래스 선언

하위 클래스를 가질 수 없는(다른 클래스가 상속할 수 없는) 클래스

 

파생 클래스

클래스 A를 직접 상위 클래스(direct superclass)로 하려면 선언할 때 extends A를 추가해야 함

이때 선언한 클래스는 클래스 A의 직접 하위 클래스(direct subclass)가 됨

클래스 선언에 extends가 없는 클래스의 경우, 직접 상위 클래스는 Object 클래스

class C extends A {
// Object는 모든 클래스의 상위 클래스로 java.lang 패키지 소속
// 클래스 A는 Object에서 파생되었고 슈퍼 클래스는 Object, 하위 클래스는 C
// 클래스 C는 클래스 A에서 파생되었고 상위 클래스는 A
}

 

인터페이스 구현

인터페이스 X를 구현하려면 선언에 implements X를 추가해야 함

class Y implements X {
}

 

추상 클래스(abstract class)

클래스 수식자인 abstreact를 붙여 클래스를 선언하면 추상 메서드(실체가 정의되지 않은 메서드, 실체는 하위 클래스에서 정의함)를 가질 수 있는 클래스

추상 클래스형은 불완전한 클래스이므로 인스턴스를 만들 수 없음

 

중첩 클래스(nested class)

클래스 또는 인터페이스 안에 선언한 클래스

 

멤버 클래스(member class)

그 선언이 다른 클래스 또는 인터페이스 선언에 의해 직접 둘러싸인 클래스

 

내부 클래스(inner class)

명시적으로 암묵적으로 정적(static)이라고 선언하지 않은 중첩 클래스

정적 초기화나 멤버 인터페이스 선언을 할 수 없음

컴파일을 할 때 상수 필드가 아니면 정적 멤버를 선언할 수 없음

 

지역 클래스(local class)

이름이 주어진 중첩클래스인 내부클래스

어떤 클래스의 멤버도 될 수 없음

댓글