클래스는 서로 관련있는 데이터들을 하나의 단위로 묶어두기 위한 것이라고 설명할 수 있다. 하지만, 이것이 전부가 아니다.

서로 다른 데이터들뿐 아니라 그 데이터와 관련이 깊은 메서드함께 묶어둘 수 있다.

그 결과 서로 관련성이 높은 것들끼리 하나의 단위로 묶여있게 되고 이는 코드의 응집도(cohesion)를 높이게 된다.

반면, 클래스 간의 연결성은 느슨해지게 되므로 코드의 결합도(coupling)를 낮출 수 있다.

그 결과 어떤 장점이 있는가?

코드를 수정해야 할 때, main 메서드가 존재하는 클래스를 수정하는 것을 최소화하고, 각각의 클래스들이 나뉘어 있으므로 해당 클래스에서 수정해주면 되기 때문에 유지보수가 용이하다는 장점이 있다.

 

 

클래스에 포함된 데이터와 메서드는 어떤 의미를 가질까?

객체지향 프로그래밍에서 객체란 "데이터"와 "메서드"의 집합이라고 말할 수 있다. 데이터는 객체의 "정적" 속성을 표현하며, 메서드는 객체의 "동적" 속성(기능)을 표현한다.

예컨대, 클래스를 자전거에 비유했을 때,  자전거는 "모양, 무게, 크기, 브랜드" 등의 정적 속성(데이터)과 "달린다, 정지한다, 뒤로간다" 등의 기능을 가지게 된다.

 

Theme. 생성자

 

클래스 안에 그 클래스와 동일한 이름을 가지며 return 타입이 없는 특별한 메서드를 둘 수 있다. 이것을 생성자(constructor)라고 부른다.

생성자는 new 명령으로 객체가 생성될 때 자동으로 실행된다. 주 목적은 객체의 데이터 필드의 값을 초기화하는 것이다.

생성자가 반드시 매개변수를 받아야하는 것은 아니다. 

 

 

이전 게시물에서 직사각형에 대한 정보를 입력받아 면적을 기준으로 정렬하여 출력한 예제를 생성자를 활용하여 보다 효율적으로 코드를 작성해보고자 한다.

 

1. 왼쪽 위 점을 나타내는 MyPoint2 class

 

1
2
3
4
5
6
7
8
9
10
11
12
package section2;
 
public class MyPoint2 {
    public int x;
    public int y;
    
    public MyPoint2(int x, int y) {
        this.x = x;
        this.y = y;
    }
}
 
cs

 

2. 직사각형 하나에 대한 데이터와 메서드를 나타내는 MyRectangle2 class

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package section2;
 
public class MyRectangle2 {
    public MyPoint2 lu;
    public int width;
    public int height;
    
    public MyRectangle2(int x, int y, int w, int h) {
        lu = new MyPoint2(x, y);
        width = w;
        height = h;
    }
    
    public int calArea() {
        return width * height;
    }
    
    public String toString() {
        return "(" + lu.x + ", " + lu.y + ") " + width + " " + height + " ";
    }
    
    
}
 
cs

 

3. main class

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
package section2;
 
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
 
public class Code05 {
 
    static MyRectangle2[] rects = new MyRectangle2[100]; // 사각형들의 배열
    static int n = 0// 배열에 저장된 사각형의 개수 n
 
    public static void main(String[] args) {
 
        try {
            Scanner sc = new Scanner(new File("data.txt"));
 
            while (sc.hasNext()) {
                int x = sc.nextInt();
                int y = sc.nextInt();
                int w = sc.nextInt();
                int h = sc.nextInt();
 
                rects[n] = new MyRectangle2(x, y, w, h);
                n++;
            }
            sc.close();
        } catch (FileNotFoundException e) {
            System.out.println("No data file.");
            System.exit(1); // 프로그램 종료
 
        }
 
        bubbleSort();
 
        for (int i = 0; i < n; i++) {
            System.out.println(rects[i].toString());
        }
 
    }
 
    public static void bubbleSort() {
        for (int i = n - 1; i > 0; i--) {
            for (int j = 0; j < i; j++) {
                if (rects[j].calArea() > rects[j+1].calArea()) {
                    MyRectangle2 tmp = rects[j + 1];
                    rects[j + 1= rects[j];
                    rects[j] = tmp;
                }
            }
        }
 
    }
 
}
 
cs

 

아래 예제를 해결해보자.

1. MyPoint2 class

 

1
2
3
4
5
6
7
8
9
10
11
12
package section2;
// 한 점에 대한 class
public class MyPoint2 {
    public int x;
    public int y;
    
    public MyPoint2(int x, int y) {
        this.x = x;
        this.y = y;
    }
}
 
cs

 

 

2. OrthoLine class

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
package section2;
// 평면 상의 하나의 수직(수평) 선분을 나타내는 class
public class OrthoLine {
 
    // 선분을 만들기 위한 두 점(선분의 양 끝점)을 선언
    public MyPoint2 u;
    public MyPoint2 v;
    
    public OrthoLine( MyPoint2 p, MyPoint2 q) {
        u = p;
        v = q;
        // 수직 선분의 경우 위쪽이 u, 아래쪽이 v
        // 수평 선분의 경우 왼쪽이 u, 오른쪽이 v가 되도록 해주었다.
        if(p.x > q.x || (p.x == q.x && p.y > q.y)) {
            swap();
        }
    }
    
    public void swap() {
        MyPoint2 tmp = u;
        u = v;
        v = tmp;
    }
    
    public OrthoLine( int x1, int y1, int x2, int y2) {
        u = new MyPoint2(x1, y1);
        v = new MyPoint2(x2, y2);
    }
    
    // 두 선분이 교차하는가?(수직, 수평 선분만 존재한다고 가정)
    // 메서드를 OrthoLine class에 정의하였으므로 다른 선분과의 교차여부만 파악하면 된다.
    public boolean intersects( OrthoLine other ) {
        // 내가 수직, other는 수평 선분
        if(isVertical() && !other.isVertical()) {
            return (u.x > other.u.x && u.x < other.v.x && u.y < other.u.y && v.y > other.u.y); // true면 교차하는 것
        }
        // 내가 수평, other는 수직 선분
        else if(!isVertical() && other.isVertical()) {
            return (u.x < other.u.x && v.x > other.u.x && u.y > other.u.y && u.y < other.v.y);
        }
        // 둘다 수직, 둘다 수평 선분
        else {
            return false// 두 선분은 만나지 않는다.
        }
        
    }
    // 수직 선분인지 여부
    public boolean isVertical() {
        return (u.x == v.x);
    }
    
    
    
    
    
    
}
 
cs

 

 

3. OrthoPolygon class

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
package section2;
 
// 하나의 직교다각형을 나타내는 class
public class OrthoPolygon {
    public int n = 0;
    public MyPoint2[] vertices;
 
    public OrthoPolygon(int k) {
        vertices = new MyPoint2[k]; // 꼭짓점 개수가 k인 다각형
    }
 
    // 꼭짓점을 추가
    public void addVertex(int x, int y) {
        vertices[n++= new MyPoint2(x, y);
    }
 
    // x좌표 중 가장 큰 x좌표를 구하는 메서드
    public int maxX() {
        int max = 0;
        for (int i = 0; i < n; i++) {
            if (vertices[i].x > max) {
                max = vertices[i].x;
            }
        }
        return max;
    }
 
    // 어떤 점이 다각형의 내/외부에 있는지 판단
    public boolean contains(MyPoint2 p) {
        OrthoLine arrow = new OrthoLine(p, new MyPoint2(maxX() + 1, p.y)); // 오른쪽 방향 수평선
        int count = 0;
        for (int i = 0; i < n; i++) {
            OrthoLine edge = new OrthoLine(vertices[i], vertices[(i + 1) % n]); // i가 n-1일 때는 다시 첫 번째 점(vertices[0])과
                                                                                // 연결돼야 하므로
            if (arrow.intersects(edge)) {
                count++;
            }
        }
        return (count % 2 == 1); // 교점의 개수가 홀수면 내부에 있는 것(짝수면 외부)
    }
}
 
cs

 

 

4. Code10

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
package section2;
 
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
 
public class Code10 {
 
    public static void main(String[] args) {
        try {
            Scanner sc = new Scanner(new File("data.txt"));
            // 꼭짓점의 개수 입력받기
            int n = sc.nextInt();
            
            OrthoPolygon thePolygon = new OrthoPolygon(n);
            // 꼭짓점 좌표 순차적으로 입력 받기
            for (int i = 0; i < args.length; i++) {
                thePolygon.addVertex(sc.nextInt(), sc.nextInt());
            }
            // 테스트 할 점의 좌표 입력 받기
            MyPoint2 thePoint = new MyPoint2(sc.nextInt(), sc.nextInt());
            sc.close();
            if(thePolygon.contains(thePoint)) {
                System.out.println("내부에 위치!");
            }
            else {
                System.out.println("외부에 위치!");
            }
            
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            System.exit(1);
        } 
        
    }
 
}
 
cs

 

끝.

Theme. 클래스, 참조변수, 객체의 관계

 

클래스는 type이다.

클래스에 대해 비유적으로 얘기해보자면, 

어떤 집을 짓는다고 할때, 클래스는 마치 하나의 설계도와 같다고 말할 수 있다. 우리가 설계도 안에서 가구를 놓고 살 수 없듯이  설계도는 집을 만들기 위한 도면일 뿐, 실제로 존재하는 집은 아니다.

마찬가지로 클래스 자체에 어떤 데이터를 저장하거나, 클래스 안에 있는 데이터를 읽거나 등등을 하는 것이 아니라 클래스는 객체나 참조변수 등을 만들어 내기 위해 그 객체나 참조변수의 타입을 정의하는 등의 역할을 하는 하나의 설계도일 뿐이다. 반면에 객체는 설계도가 아니라 이를 통해 지어진 집이라고 표현할 수 있다. 

클래스 vs 참조변수, 객체의 구도를 나눈다고 했을 때, 참조변수나 객체가 실체가 되고, 클래스는 허상이라고 생각할 수 있다. 

Person a = new Person(); 에서 

Person 타입의 객체를 new 연산자를 통해 만들었고, 그 객체의 주소를 저장하는(객체를 가리키는) 참조변수 a가 존재한다. 

이때, new 연산자를 통해 생성된 객체 그 자체는 이름이 없으므로 이때 참조변수가 필요한 것이다.

 

 

Theme. 객체와 참조변수의 사용시 주의할 부분

 

어떤 클래스의 객체를 생성하고, 객체의 참조변수를  통해 객체에 접근하는 구조에 대해 이해를 하고 있더라도 코드를 작성하는 과정에서 놓칠 수 있는 부분이 있다. 그 놓칠 수 있는 부분에 대해 아래 예제와 함께 알아보도록 하자.

 

 

위 예제를 해결하기 위해,  아래와 같이 클래스를 생성하였다.1. MyPoint1.java - x좌표와 y좌표를 선언한 클래스          public class MyPoint1 {
        public int x;
        public int y;
    }

 

2. MyRectangle1.java - 어떤 직사각형에 대한 정보를 나타낸 클래스

 

1
2
3
4
5
6
7
package Section1;
 
public class MyRectangle1 {
    public MyPoint1 lu; // 왼쪽 위의 꼭짓점의 좌표(left-up)
    public int width; // 너비
    public int height; // 높이
}
cs

이때, 주의할 것은 lu라는 변수는 MyPoint1 타입이다. 

 

3. Code05.java - main 메서드가 포함된 클래스

 

먼저, 전체적인 코드를 살펴보고 설명을 하도록 한다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
package Section1;
 
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
 
public class Code05 {
 
    static MyRectangle1[] rects = new MyRectangle1[100]; // 사각형들의 배열
    static int n = 0// 배열에 저장된 사각형의 개수 n
 
    public static void main(String[] args) {
 
        try {
            Scanner sc = new Scanner(new File("data.txt"));
 
            while (sc.hasNext()) {
                rects[n] = new MyRectangle1(); // 배열의 한 칸이 참조할 객체를 생성
                rects[n].lu = new MyPoint1(); 
 
                rects[n].lu.x = sc.nextInt(); // x 좌표
                rects[n].lu.y = sc.nextInt(); // y 좌표
                rects[n].width = sc.nextInt(); // 너비
                rects[n].height = sc.nextInt(); // 높이
                n++;
            }
            sc.close();
        } catch (FileNotFoundException e) {
            System.out.println("No data file.");
            System.exit(1); // 프로그램 종료
 
        }
 
        bubbleSort();
 
        for (int i = 0; i < n; i++) {
            System.out.println(rects[i].lu.x + " " + rects[i].lu.y + " " + rects[i].width + " " + rects[i].height);
 
        }
 
    }
 
    public static void bubbleSort() {
        for (int i = n - 1; i > 0; i--) {
            for (int j = 0; j < i; j++) {
                if (calArea(rects[j]) > calArea(rects[j + 1])) {
                    MyRectangle1 tmp = rects[j + 1];
                    rects[j + 1= rects[j];
                    rects[j] = tmp;
                }
            }
        }
 
    }
 
    // 사각형의 면적을 구하는 함수 calArea
    public static int calArea(MyRectangle1 r) {
        return r.width * r.height;
    }
}
 
cs

 

사각형의 면적을 구하고 이를 정렬하는 것은 간단한 문제이니 생략하도록 하고,

while문을 자세히 살펴보도록 한다.

 

1
2
3
4
5
6
7
8
9
10
while (sc.hasNext()) {
                rects[n] = new MyRectangle1(); // 배열의 한 칸이 참조할 객체를 생성
                rects[n].lu = new MyPoint1(); 
 
                rects[n].lu.x = sc.nextInt(); // x 좌표
                rects[n].lu.y = sc.nextInt(); // y 좌표
                rects[n].width = sc.nextInt(); // 너비
                rects[n].height = sc.nextInt(); // 높이
                n++;
            }
cs

 

MyRectangle1[] rects = new MyRectangle1[100]; 와 같이

먼저, rects라는 참조변수가 가리키는 객체는 MyRectangle1 타입의 배열이다. 

즉, rects라는 참조변수는 "배열"을 가리킨다.

 

rects[n] 또한 MyRectangle1 타입의 참조변수로 배열의 한 "칸"에 해당한다. 

즉, 배열의 각 칸은 rects[n]이라는 참조변수를 통해 객체에 접근한다.

 

처음 배열을 선언할 때, 참조변수 rects가 MyRectangle1의 객체를 참조하도록 하였지만,

참조변수 rects[n]은 아직 그러한 부분이 작성되지 않았고, 이를 위해 while문에 

rects[n] = new MyRectangle1(); // 배열의 한 칸이 참조할 객체를 생성
rects[n].lu = new MyPoint1(); 

과 같이 코드를 작성한 것이다. 

rects[n].lu의 부분은 MyRectangle1의 객체를 가리키는 것이 아니라, MyPoint1의 객체를 가리키고, 그 안에 존재하는 x,y 좌표의 값에 접근하기 위해 작성되었다. 

( main 메서드  -----> MyRectangle1 클래스  -----> MyPoint1 클래스)

 

 

결론적으로, 참조변수가 어떤 값을 참조하도록 할 때, 그 참조변수가 참조할 수 있는 객체가 선언되어 있는지를 반드시 확인하고 그렇지 않다면 선언해주도록 하자!

출처: 권오흠 교수님

 

Theme. 클래스

한 사람의 "이름"과 "전화번호"는 항상 같이 붙어다녀야 하는 데이터이다. 

이 두가지 데이터를 서로 별개의 변수에 저장하면 우리가 이름 데이터를 옮길 때마다 전화번호 데이터도 따로 옮겨줘야 한다. 

만약 각 사람에 대해서 이름과 전화번호뿐만 아니라 주소, 이메일 등 여러 가지 데이터를 저장한다면 이 불편은 더 심해질 것이다. 

이렇듯 서로 관련있는 데이터들을 하나의 단위로 묶어두면 굉장히 편할 것이다. 이것이 클래스라는 개념이 등장하는 가장 기본적인 이유이다.

 

전화번호부 프로그램을 작성하면서 클래스에 대해 좀 더 알아보도록 한다.

먼저, 어떤 한 사람의 이름과 전화번호를 하나의 단위로 묶기 위해 "Person1"이라는 클래스를 만들었다.

주의할 것은,

클래스의 이름은 항상 대문자로 시작한다는 것과 클래스의 이름과 소스파일명의 이름이 일치해야한다는 점이다.

위 코드에서 name과 number는 각각 필드(field) 혹은 data member라고 한다.

 

클래스가 서로 관련 있는 데이터들을 하나의 단위로 묶기 위해 등장했다는 것. 이것이 첫번째 기본이다.

또 하나의 클래스에 대한 기본적인 내용은

클래스도 결국 하나의 "타입(type)"이라는 것이다. 마치, int, double 등 처럼.

다만, int, double처럼 Java가 미리 정해놓은 타입(primitive type, 기본형)이 아니라 사용자가 정의한 새로운 타입이라는 의미에서 "사용자 정의 타입"이라고 부르기도 한다.

 

만약, 어떤 한 사람의 이름, 전화번호 1쌍의 데이터를 "저장"하고 싶다면?

Person1이라는 클래스에 저장하는 것이 아니라 Person1 타입의 어떤 변수를 만들어 저장해야 한다. 

이는 마치 int(기본형 타입)에 4를 저장할 수 없는 것과 같은 논의다.

 

String 혹은 int 형 변수를 선언하고 사용하는 것처럼 Person1형 변수를 선언하고 사용하는 방법은 무엇일까?

Person1 first; // Person1 타입의 first라는 이름의 변수를 선언
first = new Person1(); // Person1의 객체(Person1 타입의 객체)를 만들고 변수 first가 그 객체의 주소(참조)를 저장

이를 다시 적어보면, 

Person1 first = new Person1(); 이다. 이때, new 연산자는 객체를 생성하는 역할을 한다.

클래스명 변수명 = new 클래스();

 

Theme. 프리미티브 타입과 클래스의 차이점

prmitive type(기본형)의 변수는 변수가 만들어지고 그 "변수 안"에 값이 저장된다.

하지만,

클래스는 변수가 만들어지고, 그 변수에 "생성된 클래스의 객체의 주소(참조)"가 저장된다. 그리고 "객체 안"에 값이 저장된다.

new 연산자를 통해 객체가 생성되고, "=" 연산자를 통해 객체의 주소(참조)가 변수에 저장되는 것. 그 결과 변수가 객체를 참조하게 된다.

그래서 클래스 타입의 변수를 선언하고, 클래스의 객체를 생성하여 변수에 그 객체의 주소를 저장하는 과정을 살펴보면,

다음과 같다.

정리하자면,

모든 프리미티브  타입의 변수는 보통 변수이다. 즉, 변수 자체에 값이 저장된다.

프리미티브 타입이 아닌 모든 변수는 참조 변수이다. 즉, 실제 데이터가 저장될 "객체"는 new 명령으로 따로 만들어야 하고, 참조변수에는 그 객체의 주소를 저장한다.

 

이어서, 아래 코드를 살펴보자.

위 코드에서 Person1 second = first; 의 의미에 대해 생각해보자. 

즉,

Person1 second; // Person1 타입의 second라는 이름의 새로운 참조변수를 선언

second = first; // 무슨 의미??

"=" 연산자의 의미를 생각하면 first라는 변수가 가지고 있는 값을 second라는 변수에 저장한다고 이해할 수 있을 것이다.

이때, first는 참조변수이므로 first가 가지고 있는 값은 "Person1의 객체의 주소"이다.

따라서, first가 가지고 있는 객체의 주소가 second라는 변수에 저장되는 것이다. 

결론적으로 참조변수인 first와 second 모두 Person1의 객체를 참조하게 된다. 

 

Person1[] members = new Person1[100]; 에서도 

members라는 배열의 각 칸은 Person1 타입의 변수이다.  즉, 참조변수이다.

그러므로 members[0] = first; 가 가능하다.(자료형이 같으므로)

이 식의 의미도 members[0]이 first가 가리키는 객체의 주소를 저장하게 된다는 것이다.

 

따라서, first, second, members[0], members[1] 모두 동일한 객체(Person1의 객체)를 참조하게 된다.

Theme. 참조변수 그리고 배열

여기서 잠시 "배열"의 자료형에 대해 자세히 알아보자.

int[] numbers = new int[8]; 에서

int[] 는 프리미티브 타입이 아니다! 다시 말해 int[] 타입의 변수인 numbers는 프리미티브 타입(기본형)의 변수가 아니다.

프리미티브 타입의 변수가 아닌 것들은 모두 참조 변수다.

따라서, 참조 변수인 numbers는 new를 통해 생성된 8칸을 가진 배열이 실제로 존재하는 주소를 저장할 뿐이다.

하지만, 배열의 각 칸은 int 타입의 프리미티브 변수이다.

또한,  이전 예제에서

Person1[] members = new Person1[8]; 을 보면

members도 참조 변수, 각 칸도 참조 변수이다.

Person1[] 타입의 배열, Person1 타입의 각 칸 모두 프리미티브 타입의 변수가 아니기 때문이다.

 

현재 Person1[] members = new Person1[8]; 으로 8칸짜리 members라는 배열이 생성되어 있다.

이때,

members[2].name = "John"; 

members[2].number = "010232432";

라고 저장하는 것은 불가능하다. 그 이유를 생각하기 위해 위 배열의 각 칸이 참조 변수인 것에 집중해보자.

참조 변수는 그 변수 안에 값을 저장할 수 없고, 값이 저장된 객체의 주소만을 저장할 수 있다.

따라서, 우선적으로 members[2]에 객체의 주소가 저장되어야 한다.

즉, 아래와 같이 작성해야 한다.

members[2] = new Person1(); // Person1의 객체를 생성하고 객체의 주소를 members[2]에 저장

members[2].name = "John";

members[2].number = "010232432";

 

참조변수와 관련하여 "값에 의한 호출"의 원리를 다시 한번 생각할 수 있다.

예를 들어, 함수를 호출하는 부분에서 bubbleSort(data, count); 라고 호출했다고 가정하자.

이때, data는 배열을 가리키는 참조변수(배열의 이름)이고, count는 int형 변수다.

호출된 메서드 부분에서 public static void bubbleSort(int[] data2, int n); 이라고 작성했다면,

data2를 버블 정렬했을 때, data도 버블 정렬이 됨을 확인할 수 있다. 이는 "값에 의한 호출" 때문인데, 자세히 살펴보면

  1. data와 data2는 모두 자료형이 int[]인, 즉 참조 변수이다.
  2. data와 data2가 저장하고 있는 배열(객체)의 주소는 동일하다.
  3. data2 배열에서 버블 정렬을 하게 되면, 동일한 배열의 주소를 저장하고 있는 data 배열 역시 버블정렬이 된다.

반면에 int형 프리미티브 타입의 변수인 count와 n은 각각 변수 안에 값이 저장되므로, 호출된 메서드에서 n의 값이 변한다 한들, count의 값은 변하지 않는다. 함수가 호출되었을 때, count의 값이 딱 한번! n 안의 값에 복사될 뿐이다.

 

처음 전화번호부를 만드는 것으로 돌아와서 클래스와 객체를 활용하여 작성한 코드를 살펴보자.

먼저, Person1 클래스는 다음과 같다.

 

1
2
3
4
5
6
7
8
9
10
11
package Section1;
 
public class Person1 {
    // 전화번호부 프로그램을 만들기 위한 클래스 생성
    // Person1 클래스는 한 사람의 이름과 전화번호를 하나의 단위로 묶는다.
    
    public String name;  // 각각 field 또는 data member라고 한다.
    public String number; 
 
}
 
cs

 

각 사람의 이름과 전화번호에 대한 정보가 들어있는 input.txt 파일은

John 237-645-2734
James 0283764823
Lee 2387462
Kim 28734628
Kwon 2738644283
Adam 23784628

의 정보가 들어있다.

 

이를 입력받아 전화번호부를 만든다면,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
package Section1;
 
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
 
public class Code02 {
 
    static int n = 0;
    static Person1[] members = new Person1[100]; // 배열의 길이 100
 
    public static void main(String[] args) {
        try {
            Scanner sc = new Scanner(new File("input.txt"));
            while (sc.hasNext()) {
 
                String nm = sc.next(); // 이름
                String nb = sc.next(); // 전화번호
                
                members[n] = new Person1(); // 배열의 각 칸이 Person1의 객체의 주소를 저장
                members[n].name = nm;
                members[n].number = nb;
                n++;
 
            }
            sc.close();
        } catch (FileNotFoundException e) {
            System.out.println("No data file");
        }
 
        for (int i = 0; i < n; i++) {
            System.out.println((i+1+ " name: " + members[i].name + "\tnumber: " + members[i].number);
        }
 
    }
 
}
 
cs

 

추가적으로 이름의 사전식 순서로 정렬하여 결과를 나타내보면, 다음과 같이 작성할 수 있다. (bubble sort 활용)

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
package Section1;
 
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
 
public class Code03 {
 
    static Person1[] members = new Person1[100]; // 배열의 길이 100
    static int n = 0// 배열에 저장할 사람 수
 
    public static void main(String[] args) {
        try {
            Scanner sc = new Scanner(new File("input.txt"));
            while (sc.hasNext()) {
 
                String nm = sc.next(); // 이름
                String nb = sc.next(); // 전화번호
 
                members[n] = new Person1(); // 배열의 각 칸이 생성된 Person1의 객체의 주소를 저장
 
                members[n].name = nm;
                members[n].number = nb;
                n++// 1명을 읽을 때마다 사람 수 증가
 
            }
            sc.close();
        } catch (FileNotFoundException e) {
            System.out.println("No data file");
        }
        bubbleSort();
 
        for (int i = 0; i < n; i++) {
            System.out.println((i + 1+ " name: " + members[i].name + "\tnumber: " + members[i].number);
        }
 
    }
 
    // 매개변수가 없는 함수를 사용할 수 있는 이유는,
    // 사용하려는 배열과 사람 수가 main 함수가 아닌 클래스에 선언된 변수들이기 때문이다.
    private static void bubbleSort() {
 
        for (int i = n - 1; i > 0; i--) {
            for (int j = 0; j < i; j++) {
                if(members[j].name.compareToIgnoreCase(members[j+1].name) > 0) {
                    
                    Person1 tmp = members[j + 1];
                    members[j + 1= members[j];
                    members[j] = tmp;
                }
            }
        }
 
    }
 
}
 
cs

+ Recent posts