자바 수업 6일차 (마지막)



☞ 스윙 이어서...


* 자바에서는 클래스 내부에 새로운 클래스를 포함하여 사용하는 것을 허용한다.

  - 이러한 클래스를 내부inner 클래스라 한다.

  - 내부 클래스는 다른 용도로도 사용할 수 있지만, 이벤트를 처리할 때 유용하다.


1
2
3
4
5
6
7
class OutClass {
    ......
    class InnerClass {  // 내부 클래스 선언.
        ......          // 외부 클래스의 모든 요소 사용 가능.
    }
    ......
}
cs


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
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
 
class Event2 extends JFrame {
    JLabel jl;  // 버튼과 라벨을 클래스의 속성으로 지정.
    JButton jb1, jb2;
    
    public Event2() {
        Container ct = getContentPane();
        ct.setLayout(new FlowLayout());
        
        jb1 = new JButton("사랑합니다.");
        jb2 = new JButton("행복합니다.");
        jl = new JLabel("버튼을 누르세요.");
        jb1.addActionListener(new EventProcess());  // 두 개의 버튼에 리스너를 등록.
        jb2.addActionListener(new EventProcess());  // 처리 객체로 내부 클래스 지정.
        ct.add(jb1);
        ct.add(jb2);
        ct.add(jl);
        
        setTitle("Event Test2");
        setSize(250150);
        setVisible(true);
    }
    private class EventProcess implements ActionListener {
    // 내부 클래스로 인터페이스를 포함하는 클래스 작성.
        public void actionPerformed(ActionEvent e) {  // 이벤트 처리 루틴 작성.
            jl.setText(e.getActionCommand());  // 외부 클래스의 속성인 라벨을 직접 사용.
                                               // ActionEvent 객체를 이용하여
                                               // 버튼의 라벨값을 추출.
        }
    }
}
public class EventTest2 {
    public static void main(String[] args) {
        new Event2();
    }
}
cs



* 이벤트 처리를 위한 클래스를 별도로 작성하여 이벤트를 처리하는 방법


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
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
 
class EventClass implements ActionListener {  // 별도의 이벤트 처리 클래스 생성.
    JLabel jl;
    public EventClass(JLabel jl) {
        this.jl = jl;
    }
    public void actionPerformed(ActionEvent e) {
        jl.setText(e.getActionCommand());
    }
}
class Event3 extends JFrame {
    JLabel jl;
    JButton jb1, jb2;
    public Event3() {
        Container ct = getContentPane();
        ct.setLayout(new FlowLayout());
        
        jb1 = new JButton("사랑합니다.");
        jb2 = new JButton("행복합니다.");
        jl = new JLabel("버튼을 누르세요.");
        jb1.addActionListener(new EventClass(jl));  // 리스너를 등록.
        jb2.addActionListener(new EventClass(jl));  // 처리 객체를 지정할 때 JLabel 객체 전달.
        ct.add(jb1);
        ct.add(jb2);
        ct.add(jl);
        
        setTitle("Event Test3");
        setSize(250150);
        setVisible(true);
    }
}
public class EventTest3 {
    public static void main(String[] args) {
        new Event3();
    }
}
cs



* ImageIcon 클래스

  - 이미지를 아이콘화하여 제공하는 클래스이다.

  - [형식]

ImageIcon(String filename)

ImageIcon(URL url)

※ filename : 이미지 파일을 지정하여 아이콘을 생성.

   url : 웹 주소를 지정하여 아이콘을 생성.


* JLabel 클래스

  - 라벨을 만드는 클래스이다.

  - [형식]

JLabel(ImageIcon i)

JLabel(String s)

JLabel(String s, ImageIcon i, int align)

※ i : ImageIcon 객체로 라벨 생성.

   s : 문자열을 사용하여 라벨 생성.

   align : 아이콘과 문자열의 위치를 의미.

           SwingConstants 인터페이스의 상수를 사용.

           (SwingConstants.LEFT, SwingConstants.RIGHT, SwingConstants.CENTER, SwingConstants.LEADING, SwingConstants.TRAILING)


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
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
 
class JLabel1 extends JFrame implements ActionListener {
    private JLabel result = new JLabel();  // 이벤트 처리를 위해 속성으로 선언.
    public ImageIcon i1, i2;
    
    public JLabel1() {
        i1 = new ImageIcon("image/apple.jpg");  // 이미지 아이콘 객체 생성.
        i2 = new ImageIcon("image/pear.jpg");
        
        JButton apple = new JButton("사과");
        JButton pear = new JButton("배");
        
        Container ct = getContentPane();
        
        ct.setLayout(new FlowLayout());
        ct.add(apple);
        ct.add(pear);
        ct.add(result);
        
        apple.addActionListener(this);  // 버튼 객체에 리스너 등록.
        pear.addActionListener(this);
        
        setTitle("JLabel Test1");
        setSize(300250);
        setVisible(true);
    }
    public void actionPerformed(ActionEvent ae) {
        if(ae.getActionCommand() == "사과") {  // 버튼에 따라 결과를 출력.
            result.setText("맛있는 사과입니다.");
            result.setIcon(i1);  // 라벨의 아이콘을 설정.
        } else {
            result.setText("맛있는 배입니다.");
            result.setIcon(i2);
        }
    }
}
public class JLabelTest1 {
    public static void main(String[] args) {
        new JLabel1();
    }
}
cs



* 텍스트 클래스

  - 한 줄 : JTextField

  - 여러 줄 : JTextArea

  - [형식]

JTextField()

JTextField(int cols)

JTextField(String str, int cols)

JTextField(String str)

JTextArea()

JTextArea(String str)

JTextArea(int rows, int cols)

JTextArea(String str, int rows, int cols)

※ str : 생성될 때 나타낼 문자열.

   cols, rows : 텍스트 필드 또는 텍스트 에리어의 화면에서의 크기.

                입력되는 문자의 수와는 상관 없음.


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
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
 
class JTFJTA1 extends JFrame implements ActionListener {
    JTextField jtf;  // 텍스트 객체 선언.
    JTextArea  jta;
    JLabel jl = new JLabel("입력하세요.");  // 라벨 객체 생성.
    public JTFJTA1() {
        jtf = new JTextField(20);
        jta = new JTextArea(1020);
        jta.setEditable(false);  // 텍스트 에리어 수정 불가 설정.
        
        Container ct = getContentPane();
        ct.setLayout(new FlowLayout());
        
        JPanel jp = new JPanel();  // 패널 객체 생성.
        jp.add(jtf);  // 패널에 추가.
        jp.add(jta);
        
        ct.add(jp);  // 컨테이너에 패널 추가.
        ct.add(jl);
        
        jtf.addActionListener(this);
        
        setTitle("JTextField, JTextArea Test1");
        setSize(500300);
        setVisible(true);
    }
    public void actionPerformed(ActionEvent ae) {
        if(jta.getLineCount() <= jta.getRows()) {
        // 텍스트의 크기(줄)보다 작을 때만 추가.
            jta.append(ae.getActionCommand()+"\n");
            jtf.setText("");  // 새로운 입력을 받기 위해, 기존의 내용을 비움.
        } else {
            jl.setText("입력이 종료되었습니다.");  // 크기를 넘어서면 라벨을 출력하고,
            jtf.setEditable(false);              // 텍스트 필드 수정 불가 설정.
        }
    }
}
public class JTFJTATest1 {
    public static void main(String[] args) {
        new JTFJTA1();
    }
}
cs




* JList 클래스

  - [형식]

JList()

JList(Object[] items)

※ items : 리스트로 생성할 배열.


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
import javax.swing.*;
import java.awt.*;
import javax.swing.event.*;  // 스윙 이벤트 패키지 포함.
 
class JList1 extends JFrame implements ListSelectionListener {
    private String[] fruitlist = {"persimmon""banana""apple""grape""cherry""pear"};  // 과일 이름 배열 생성.
    private JList jlst = new JList(fruitlist);  // 이름 배열로 리스트 객체 생성.
    private ImageIcon[] fruiticons = {  // 아이콘 객체 배열 생성.
            new ImageIcon("image/persimmon.jpg"),
            new ImageIcon("image/banana.jpg"),
            new ImageIcon("image/apple.jpg"),
            new ImageIcon("image/grape.jpg"),
            new ImageIcon("image/cherry.jpg"),
            new ImageIcon("image/pear.jpg")
    };
    private JLabel[] jlicon = new JLabel[6];  // 아이콘을 위한 라벨 객체 배열 생성.
    private JLabel jlname = new JLabel();  // 라벨을 저장할 객체 생성.
    
    public JList1() {
        Container ct = getContentPane();
        
        JPanel jp1 = new JPanel();
        jp1.setLayout(new GridLayout(3,2,5,5));  // 아이콘 패널 Grid 배치 관리자 설정.
        for (int i=0; i<6; i++) {
            jp1.add(jlicon[i] = new JLabel());
        }
        
        JPanel jp2 = new JPanel();
        jp2.add(jlname);
        ct.add(jlst, BorderLayout.WEST);  // Border 배치 관리자로 설정.
        ct.add(jp1, BorderLayout.CENTER);
        ct.add(jp2, BorderLayout.EAST);
        
        jlst.addListSelectionListener(this);  // 리스트에 리스너 등록.
        
        setTitle("JList Test1");
        setSize(700300);
        setVisible(true);
    }
    public void valueChanged(ListSelectionEvent lse) {
        for (int i=1; i<6; i++) {  // 아이콘을 모두 삭제.
            jlicon[i].setIcon(null);
        }
        int[] indices = jlst.getSelectedIndices();  // 선택된 항목을 배열로 추출.
        String s = "당신이 선택한 항목은 : ";
        for (int j=0; j<indices.length; j++) {  // 선택된 아이콘을 표시.
            jlicon[j].setIcon(fruiticons[indices[j]]);
            s = s + fruitlist[indices[j]] + " ";  // 선택된 아이콘의 문자열을 생성.
        }
        jlname.setText(s);  // 선택한 아이콘의 문자열 표시.
    }
}
public class JListTest1 {
    public static void main(String[] args) {
        new JList1();
    }
}
cs




수고하셨습니다.



자바 수업 5일차



* 메소드를 오버라이딩하는 경우 상위 클래스의 메소드 한정자보다 허용 범위가 넓은 경우에만 허용되고, 그 반대 경우는 허용되지 않는다.

  - 상위 클래스에서 public으로 사용된 메소드를 하위 클래스에서 한정자 없이 사용하거나 protected로 메소드를 오버라이딩 할 수 없다.

  - 한정자의 허용 범위는 "public" -> "protected" -> "한정자 사용 안 함" 순서

  - private는 상속되지 않기 때문에 오버라이딩의 대상이 되지 않는다.


  a. 한정자의 허용 범위가 넓어지는 경우는 허용된다.


1
2
3
4
5
6
7
8
9
10
class AAA {
    void aa(int a, int b) {         // 한정자 없이 메소드 선언
        System.out.println(a+b);
    }
}
class BBB extends AAA {
    public void aa(int a, int b) {  // public 한정자 사용. 허용됨.
        System.out.println(a*b);
    }
}
cs


  b. 한정자의 허용 범위가 좁아지는 경우는 허용되지 않는다. 컴파일 오류.


1
2
3
4
5
6
7
8
9
10
class AAA {
    public void aa(int a, int b) {     // public 메소드 선언
        System.out.println(a+b);
    }
}
class BBB extends AAA {
    protected void aa(int a, int b) {  // protected 한정자 사용. 허용 안 됨.
        System.out.println(a*b);
    }
}
cs



* 메소드를 오버라이딩하여 사용할 때 유용하게 쓸 수 있는 주석

  - @Override 주석 : 자바 컴파일러는 @Override 주석이 사용되어 메소드가 선언되면 상위 클래스의 메소드와 정확하게 일치하는지 검사하여 일치하지 않는 경우에는 컴파일 오류를 발생시킨다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class OIa {
    public void show(String str) {
        System.out.println("상위 클래스의 메소드 show(String str) 수행 " +str);
    }
}
class OIb extends OIa {
    @Override public void shaw(String str) {  // @Override 주석을 사용하여 메소드를 선언.
                                              // 상위 클래스의 오버라이딩 메소드와 일치하지 않아
                                              // 오류를 발생시킨다.
        System.out.println("하위 클래스의 메소드 show(String str) 수행 " +str);
    }
}
public class OverridingTest3 {
    public static void main(String args[]) {
        OIb oib = new OIb();
        oib.show("처음 시작하는 자바");
    }
}
cs



* 예약어 super


  1. 하위 클래스에 의해 가려진 상위 클래스의 멤버 변수나 메소드에 접근할 때 사용한다.

super.멤버 변수

super.메소드 이름(매개 변수)


  2. 상위 클래스의 명시적 생성자를 호출하기 위해 사용한다.

super(매개 변수)


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
class SD1 {
    public int i1;
    public double d1;
    public SD1(int i1) {
        System.out.println("SD1(int i1) 생성자 수행");
        this.i1 = i1 * i1;  // this.i1은 객체 변수를 의미
        System.out.println(i1 + "의 2제곱은 : " +this.i1);
    }
    public SD1(double d1) {
        System.out.println("SD1(double d1) 생성자 수행");
        this.d1 = d1 * d1;
        System.out.println(d1 + "의 2제곱은 : " +this.d1);
    }
}
class Sub1 extends SD1 {
    public Sub1(int i1) {
        super(i1);  // 상위 클래스의 생성자 호출
        System.out.println("Sub1(int i1) 생성자 수행");
        this.i1 = this.i1 * i1;  // this.i1은 상속받은 객체 변수를 의미
        System.out.println(i1 + "의 3제곱은 : " +this.i1);
    }
    public Sub1(double d1) {
        super(d1);  // 상위 클래스의 생성자 호출
        System.out.println("Sub1(int d1) 생성자 수행");
        this.d1 = this.d1 * d1;
        System.out.println(d1 + "의 3제곱은 : " +this.d1);
    }
}
public class SuperTest3 {
    public static void main(String[] args) {
        Sub1 sub1 = new Sub1(10);  // 생성자에 의해 결과가 출력된다.
        Sub1 sub2 = new Sub1(10.5);
    }
}
cs



* Object 클래스

  - java.lang 패키지에 속해 있는 라이브러리 클래스이다.

  - 모든 자바 클래스의 최상위 클래스이다.

  - 명시적으로 상위 클래스가 지정된 경우에도, 그 상위 클래스의 상위 클래스가(계속 반복 가능) 최종적으로는 Object 클래스이다.

  - 즉, Object 클래스에서 선언된 모든 속성과 기능은 모든 자바 클래스에 상속되기 때문에 자유롭게 사용할 수 있다.


* Object 클래스에 선언된 toString() 메소드

  - 객체의 클래스명과 메모리에서의 주소를 16진수로 반환하는 메소드이다.


1
2
3
4
5
6
7
8
public String toString() {
    return getClass().getName() +   // 현재 클래스의 이름을 반환한다.
    "@" + Integer.toHexString(hashCode());
    // hashCode()의 값은 객체가 저장된 메모리의 10진 주소이다.
    // 이 값을 10진수로 변환하여 반환한다.
    // Integer 클래스의 toHexString()은 클래스 메소드로서
    // 10진수를 16진수로 변환하는 메소드이다.
}
cs


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class AAA {
    public int a;
}
public class ObjectMethodTest1 {
    public static void main(String args[]) {
        AAA aa = new AAA();
        System.out.println(aa);  // 객체 aa의 toString() 메소드가 자동으로 호출된다.
                                 // (Object 클래스로부터 상속되었음)
        System.out.println(aa.toString());  // 객체 aa의 toString() 메소드를 명시적으로 호출한다.
                                            // 결과가 같다.
        Integer ii = new Integer(99);       // Integer 클래스로부터 객체 ii를 생성한다.
                                            // 객체의 값은 99.
        System.out.println(ii);             // 객체 ii의 toString() 메소드가 자동으로 호출된다.
        System.out.println(ii.toString());  // 명시적으로 toString() 메소드를 호출한다.
                                            // 결과가 같다.
    }
}
cs



* 동등 연산자(==)

  - 참조 자료형의 변수에 적용할 수는 있지만, 예상치 않은 결과를 나타낸다.

  - 참조 자료형 변수는 값이 실제 값이 아니라 객체가 저장된 주소이기 때문이다.


* Object 클래스에 선언된 equals() 메소드


1
2
3
public boolean equals(Object obj) {
    return (this == obj);  // 두 객체 변수의 값(주소)이 같으면 true, 아니면 false 반환
}
cs


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Box11 {
    public int width;
    public int height;
    public int depth;
    public Box11(int w, int h, int d) {
        width = w;
        height = h;
        depth = d;
    }
}
public class ObjectMethodTest4 {
    public static void main(String[] args) {
        Box11 b1 = new Box11(10,20,30);
        Box11 b2 = new Box11(10,20,30);
        Box11 b3 = b2;
        System.out.println(b1.equals(b2) ? "b1과 b2는 같다" : "b1과 b2는 같지 않다");  // equals() 메소드를 이용하여 객체를 비교
        System.out.println(b2.equals(b3) ? "b2와 b3는 같다" : "b2와 b3는 같지 않다");  // (동등 연산자와 같은 결과)
        String s1 = new String("처음 시작하는 자바");
        String s2 = new String("처음 시작하는 자바");
        System.out.println(s1.equals(s2) ? "s1과 s2는 같다" : "s1과 s2는 같지 않다");  // String 클래스의 객체를 이용하여 비교
           // (String 클래스에 오버라이딩된 equals() 수행)
    }
}
cs




* final : 모두 변하는 것을 방지하기 위해 사용한다.


  1. 메소드 지역 변수나 객체 변수에 final을 붙여 상수로 사용한다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class AAA {
    public final int MAX = 100;  // 객체 변수에 final을 사용하여 상수로 지정.
    ......
    public void temp() {
        final int max = 50;  // 메소드 지역 변수를 final로 지정.
        ......
        max++;  // 오류 발생. final로 지정된 지역 변수의 값을 변경할 수 없음.
    }
}
class BBB {
    ......
    AAA aa = new AAA();
    aa.MAX = 200;  // 오류 발생. final로 지정된 객체 변수의 값을 변경할 수 없음.
    ......
}
cs



  2. 메소드에 final을 붙여 선언하는 경우, 하위 클래스에서 이 메소드를 오버라이딩 할 수 없다는 의미이다.


1
2
3
4
5
6
7
8
9
10
class AAA {
    final void calculate() {  // 메소드를 final로 선언.
        System.out.println("이 메소드는 final 메소드");
    }
}
class BBB extends AAA {
    void calculate() {  // 오류 발생. final로 선언된 메소드 오버라이딩 금지.
        System.out.println("final 메소드를 중첩하는 메소드");
    }
}
cs



  3. 클래스 선언에도 사용할 수 있다. final이 붙은 클래스는 상속을 허용하지 않는다.


1
2
3
4
5
6
final class AAA {  // 클래스를 final로 선언.
    ......
}
class BBB extends AAA {  // 오류 발생. final로 선언된 클래스 상속 금지.
    ......
}
cs




☞ 다형성, 추상 클래스, 인터페이스


* 상속된 관계에서 객체의 형 변환

  - 상위 클래스 형의 객체 변수에 하위 클래스에서 생성된 객체의 배정을 허용한다.

  - 반대로 하위 클래싀 형의 객체 변수에 상위 클래스에서 생성된 객체의 배정은 허용하지 않는다.


1
2
3
4
Object o1 = new Scanner();  // 가능. 단, 이 객체 변수를 통해서는
Object o2 = new Box();      // Object 클래스의 속성과 기능만 사용 가능.
Scanner s = new Object();   // 오류 발생.
Random r = new Object();    // 상위 클래스의 객체를 배정할 수 없음.
cs



* instanceof 연산자

  - 객체가 특정 클래스로부터 생성된 객체인지를 판별하여 true 또는 false를 반환한다.

  - [형식]

객체 변수 instanceof Class-Type


* 다형성

  - 객체 지향에서 다향성은 서로 다른 객체가 동일한 메시지에 대하여 서로 다른 방법으로 응답할 수 있는 기능이라고 정의할 수 있다.

  - 상속, 객체의 형 변환, 메소드 오버라이딩을 통하여 구현될 수 있다.


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
class Am {
    void callme() {
        System.out.println("클래스 Am의 callme() 메소드 실행");
    }
}
class Bm extends Am {
    void callme() {  // 상위 클래스의 메소드 오버라이딩
        System.out.println("클래스 Bm의 callme() 메소드 실행");
    }
}
class Cm extends Am {
    void callme() {  // 상위 클래스의 메소드 오버라이딩
        System.out.println("클래스 Cm의 callme() 메소드 실행");
    }
}
class PolymorphismTest1 {
    public static void main(String[] args) {
        Am r = new Am();  // 객체 생성
        r.callme();       // 클래스 Am의 callme() 메소드 수행
        r = new Bm();      // 상위 클래스의 객체 변수에 하위 클래스 객체를 배정
        r.callme();       // 하위 클래스 Bm의 callme() 메소드 수행
        r = new Cm();     // 상위 클래스의 객체 변수에 하위 클래스 객체를 배정
        r.callme();       // 하위 클래스 Cm의 callme() 메소드 수행
    }
}
cs



* 추상화

  - 복잡한 문제들 중에 공통적인 부분을 추출하여 추상 클래스로 제공하고, 상속을 이용하여 나머지 클래스들을 하위 클래스로 제공하는 기법이다.

  - 추상화의 단계

  1단계 : 현실 세계의 문제들이 가지는 공통적인 속성을 추출

  2단계 : 공통 속성을 가지는 추상 클래스 작성

  3단계 : 추상 클래스의 하위 클래스로 현실 세계의 문제들을 구현


* 추상화 클래스와 추상 메소드

  - [형식]


1
2
3
4
5
6
7
abstract class 클래스 이름 {  // 추상 클래스(이 클래스로부터 객체를 생성할 수 없다.)
    ......
    클래스에 기술할 수 있는 일반적인 멤버 변수와 메소드
    abstract void 추상 메소드 이름();    // 추상 메소드(선언 부분만 기술한다.).
                                       // 메소드의 몸체가 없기 때문에
                                       // 끝에 ";"을 붙여야 한다.
}
cs


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
abstract class Shape {  // 추상 클래스 선언
    ......
    abstract void computeArea();  // 추상 메소드 선언. 선언부만 기술.
    ......
}
public class Circle extends Shape {  // 추상 클래스로부터 상속받아 Circle 클래스 생성.
    ......
    void computeArea() {  // 추상 메소드를 오버라이딩하여 클래스 고유의 기능을 기술.
        실제 원의 면적을 계산하는 기능이 기술됨;
    }
}
public class Triangle extends Shape {
    ......
    void computeArea() {  // 추상 메소드를 오버라이딩하여 클래스 고유의 기능을 기술.
        실제 삼각형의 면적을 계산하는 기능이 기술됨;
    }
}
cs



* 추상 클래스와 추상 메소드의 오버라이딩을 이용하면 더욱 효율적인 다형성을 구현할 수 있다.


* 인터페이스

  - 추상 클래스와 유사하지만, 더 완벽한 추상화를 제공한다.

  - 추상 클래스는 추상 메소드 외에 다른 멤버 변수나 일반 메소드를 가질 수 있지만, 인터페이스는 추상 메소드(메소드 선언만 있는)와 상수만을 가질 수 있다.

  - 인터페이스를 사용함으로써 완벽한 다중 상속은 아니지만 다중 상속을 흉내낼 수 있다.

  - [형식]


1
2
3
4
5
interface 인터페이스 이름 [extends 인터페이스 이름, [인터페이스 이름], ...] {
    // 인터페이스끼리 상속 관계를 구성할 수 있다.
    ......상수 선언;
    ......메소드 선언;
}
cs



  a. 인터페이스의 예


1
2
3
4
5
interface Sleeper {                  // 인터페이스 선언.
    public long ONE_SECOND = 1000;   // 상수 선언. 반드시 초기화해야 한다.
    public long ONE_MINUTE = 60000;  // 메소드 선언. 끝에 ";"을 붙인다.
    public void wakeup();
}
cs



  b. 인터페이스 상속의 예


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
interface Sleeper {  // 인터페이스 Sleeper 선언.
    public long ONE_SECOND = 1000;
    public long ONE_MINUTE = 60000;
    public void wakeup();
}
interface Worker {  // 인터페이스 Worker 선언.
    public long WORK_TIME = 8;
    public void sleep();
}
interface People extends Sleeper, Worker {  // 두 개의 인터페이스로부터 상속받아
                                            // People 인터페이스 선언.
    public int MAX = 24;
    public int MIN = 0;
    public void work();
}
public class InterfaceClass implements People {  // People 인터페이스를 포함하는 클래스 작성.
    ......
    public void wakeup() {  // 인터페이스 메소드 오버라이딩.
        ...오버라이딩
    }
    public void sleep() {   // 인터페이스 메소드 오버라이딩.
        ...오버라이딩
    }
    public void work() {   // 인터페이스 메소드 오버라이딩.
        ...오버라이딩
    }
}
cs



* 클래스에서 인터페이스를 사용하기 위해서는 implements 예약어를 사용해야 한다.

  - 클래스가 인터페이스를 포함하면, 인터페이스에서 선언된 모든 메소드를 오버라이딩 해야 한다.


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
import java.util.Random;
interface IStack {  // 인터페이스 선언.
    public void push(int item);  // 두 개의 메소드 선언.
    public int pop();
}
class FixedStack implements IStack {  // 인터페이스를 포함한 클래스 작성.
    private int stack[];
    private int tos;
    FixedStack(int size) {
        stack = new int[size];
        tos = -1;
    }
    public void push(int item) {  // 인터페이스 메소드 오버라이딩.
        if(tos==stack.length-1)
            System.out.println("스택이 꽉 찼음");
        else
            stack[++tos] = item;
    }
    public int pop() {  // 인터페이스 메소드 오버라이딩.
        if(tos < 0) {
            System.out.println("스택이 비었음");
            return 0;
        } else {
            return stack[tos--];
        }
    }
}
public class InterfaceTest1 {
    public static void main(String[] args) {
        Random r = new Random();
        FixedStack mystack1 = new FixedStack(10);  // 10개의 요소를 가지는 정수 스택 객체 생성.
        for(int i=0; i<10; i++)
            mystack1.push(r.nextInt(10));  // 난수를 발생시켜 스택에 저장.
        System.out.println("스택 : mystack1");
        for(int i=0; i<10; i++)
            System.out.println(mystack1.pop() + " ");  // 스택의 내용 출력.
    }
}
cs



* 인터페이스도 추상 클래스와 같이 다형성을 구현하는데 사용될 수 있다.

  - 추상 클래스를 이용하여 다형성을 구현하는 것과 동일한 형태이다.


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
abstract class Figure1 {  // 추상 클래스 선언.
    abstract void draw();
}
interface Shape1 {  // 인터페이스 선언.
    public void computeArea(double a, double b);
}
class Triangle3 extends Figure1 implements Shape1 {  // 추상 클래스와 인터페이스를 포함하는 클래스 작성.
    void draw() {  // 메소드 오버라이딩.
        System.out.println("삼각형을 그리는 기능");
    }
    public void computeArea(double a, double h) {  // 메소드 오버라이딩.
        System.out.println("삼각형의 넓이 : " + (a * h / 2));
    }
}
class Rectangle3 extends Figure1 implements Shape1 {
    void draw() {
        System.out.println("사각형을 그리는 기능");
    }
    public void computeArea(double h, double v) {  // 메소드 오버라이딩.
        System.out.println("사각형의 넓이 : " + (h * v));
    }
}
class Oval3 extends Figure1 implements Shape1 {
    void draw() {
        System.out.println("원을 그리는 기능");
    }
    public void computeArea(double r1, double r2) {  // 메소드 오버라이딩.
        System.out.println("원의 넓이 : " + (3.14 * r1 * r2));
    }
}
class Polydraw1 {
    public void pdraw(Figure1 f) {
        f.draw();
    }
    public void pcomputeArea(Shape1 s, double a, double b) {
        s.computeArea(a, b);
    }
}
public class InterfaceTest2 {
    public static void main(String[] args) {
        Polydraw1 p = new Polydraw1();
        Figure1 fg1 = new Triangle3();
        Figure1 fg2 = new Rectangle3();
        Figure1 fg3 = new Oval3();
        Shape1 sp1 = new Triangle3();   // 인터페이스 형의 객체 변수에
        Shape1 sp2 = new Rectangle3();  // 클래스의 객체를 배정.
        Shape1 sp3 = new Oval3();
        p.pdraw(fg1);
        p.pcomputeArea(sp1, 44);  // 인터페이스 형의 객체 변수로 메소드 호출.
        p.pdraw(fg2);
        p.pcomputeArea(sp2, 44);  // 인터페이스 형의 객체 변수로 메소드 호출.
        p.pdraw(fg3);
        p.pcomputeArea(sp3, 44);  // 인터페이스 형의 객체 변수로 메소드 호출.
    }
}
cs




☞ 자바 GUI


* AWT(Abstract Window Toolkit)

  - 자바 언어에서 제공하는 GUI 패키지.


* AWT 컴포넌트의 단점

  - 운영체제가 제공하는 그래픽 컴포넌트와 일대일로 연결되어 작동하여야 하는 부담과 실행되는 시스템에 따라 겉모양이 다르게 보인다.


* 스윙(Swing)

  - 썬(Sun)사가 넷스케이프사와 공동으로 개발한 그래픽 툴킷.

  - 자바의 표준 클래스인 JFC(Java Foundation Classes)로 제공되고 있으며, JDK에 포함되어 있다.

  - 스윙은 AWT와 달리 그래픽을 JVM이 자체적으로 처리한다.


* java.awt 패키지

  - GUI 구축을 위한 컴포넌트 클래스 뿐만 아니라 다른 클래스들도 많이 제공한다.


    · 컴포넌트 배치와 관련된 클래스 :

BorderLayout, FlowLayout, GridLayout, GridBagLayout, GridBagConstraints, CardLayout


    · GUI 구성과 관련된 클래스 :

Button, Label, Canvas, Checkbox, Choice, Scrollbar, Component, List, Menu, TextComponent, TextArea, MenuBar, MenuItem, TextField, CheckboxGroup, CheckboxMenuItem, MenuComponent


    · 그래픽 출력과 관련된 클래스 :

Color, Font, FontMetrics, Rectangle, Point, Polygon, Graphics, Image


    · 컨테이너 클래스 : Frame, Panel, Window, Container, FileDialog, Dialog

    · 기타 클래스 : Insets, Dimension, Toolkit, Event, MediaTracker


* Component 클래스

  - 추상 클래스

  - 그래피컬 사용자 인터페이스(GUI) 구축에 필요한 많은 하위 클래스를 가지고 있다.

  - 약 100여 개의 메소드가 제공된다.


* Container 클래스

  - Component 클래스의 하위 클래스로서, 컴포넌트를 담는 쟁반 역할을 한다.

  - 사용되는 쟁반 역할을 하는 클래스는 JFrame, JPanel, Applet, JApplet 클래스.


* 응용 프로그램에서 GUI를 구축하기 위해서는 프레임 클래스를 이용한다.

  - JFrame 클래스 : Component -> Container -> Window -> Frame -> JFrame 형태로 상속된 클래스

  - [형식]

JFrame()

JFrame(String title)

title : 프레임의 제목에 나타낼 문자열


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import javax.swing.*;
import java.awt.*;
 
class FirstFrame1 {
    public FirstFrame1() {  // 생성자
        JFrame jf = new JFrame("첫 번째 GUI 프로그램");  // 프레임 객체 생성
        Container ct = jf.getContentPane();         // 프레임으로부터 판(컨테이너) 생성
        JButton jb = new JButton("테스트 버튼");       // 버튼 컴포넌트 생성
        ct.add(jb);  // 버튼을 판(컨테이너)에 추가
        jf.setSize(400300);  // 프레임 크기 설정
        jf.setVisible(true);   // 프레임을 화면에 출력
    }
}
public class FrameTest1 {
    public static void main(String[] args) {
        new FirstFrame1();
    }
}
cs


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import javax.swing.*;
import java.awt.*;
 
class FirstFrame3 extends JFrame {  // JFrame을 상속하여 클래스 생성
    public FirstFrame3() {
        Container ct = getContentPane();  // 컨테이너 객체 생성
        JButton jb = new JButton("테스트 버튼");
        ct.add(jb);
        setTitle("두 번째 GUI 프로그램");  // 프레임의 제목 설정
        setSize(400300);
        setVisible(true);
    }
}
public class FrameTest2 {
    public static void main(String[] args) {
        new FirstFrame3();
    }
}
cs



* 컴포넌트들은 그릇 역할을 하는 컨테이너(또는 패널)에 담기게 되며, 자바에서는 컨테이너에 컴포넌트를 배치하는 다양한 방법을 배치 관리자 클래스로 제공한다.


* 컨테이너에 컴포넌트를 수평 방향으로 배치하기.

  - [형식]

FlowLayout()

FlowLayout(int align)

FlowLayout(int align, int hgap, int vgap)

※ align : 정렬 방식을 지정하는 상수(LEFT, CENTER, RIGHT)

   hgap, vgap : 컴포넌트 사이의 수직, 수평 간격(픽셀값)


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import javax.swing.*;
import java.awt.*;
 
class FlowLayout1 extends JFrame {
    public FlowLayout1() {
        Container ct = getContentPane();
        FlowLayout fl = new FlowLayout(FlowLayout.RIGHT, 1015);
        ct.setLayout(fl);
        for (int i=1; i<=15; i++)
            ct.add(new JButton("버튼"+i));
        setTitle("FlowLayout Test1");
        setSize(400300);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setVisible(true);
    }
}
public class FlowLayoutTest1 {
    public static void main(String[] args) {
        new FlowLayout1();
    }
}
cs



* 컨테이너에 컴포넌트를 추가할 때 방향을 지정하여 추가하기.

  - 지정할 수 있는 방향 : East, West, South, North, Center

  - [형식]

BorderLayout()

BorderLayout(int hgap, int vgap)


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import javax.swing.*;
import java.awt.*;
 
class BorderLayout1 extends JFrame {
    public BorderLayout1() {
        Container ct = getContentPane();
        BorderLayout bl = new BorderLayout(1010);
        ct.setLayout(bl);
        ct.add(new JButton("오른쪽 버튼"), BorderLayout.EAST);
        ct.add(new JButton("왼쪽 버튼"), BorderLayout.WEST);
        ct.add(new JButton("위쪽 버튼"), BorderLayout.NORTH);
        ct.add(new JButton("아래쪽 버튼"), BorderLayout.SOUTH);
        ct.add(new JButton("중앙 버튼"), BorderLayout.CENTER);
        setTitle("BorderLayout Test1");
        setSize(400300);
        setVisible(true);
    }
}
public class BorderLayoutTest1 {
    public static void main(String[] args) {
        new BorderLayout1();
    }
}
cs



* 컨테이너에 컴포넌트를 추가할 때 행과 열을 가진 배열 형태로 배치하기.

  - [형식]

GridLayout()

GridLayout(int rows, int cols)

GridLayout(int rows, int cols, int hgap, int vgap)

※ rows, cols : 배치할 행과 열을 지정.


* 그릇 역할을 하는 클래스 : Container, JPanel

  - Container 클래스는 JFrame 객체의 getContentPane() 메소드에 의해 생성하여 사용한다.

  - JPanel 클래스는 직접 생성하여 사용한다.


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
import javax.swing.*;
import java.awt.*;
 
class JPanel2 extends JFrame {
    public JPanel2() {
        Container ct = getContentPane();
        ct.setLayout(new BorderLayout(5,5));  // 컨테이너에 Border 배치 관리자 설정
        
        JPanel jp1 = new JPanel();  // 패널 객체 생성
        jp1.setLayout(new GridLayout(5,1));  // 패널에 Grid 배치 관리자 설정
        jp1.add(new JRadioButton("Java"));   // 패널에 컴포넌트 추가
        jp1.add(new JRadioButton("C"));
        jp1.add(new JRadioButton("Visual Basic"));
        jp1.add(new JRadioButton("JSP"));
        jp1.add(new JRadioButton("PHP"));
        
        JPanel jp2 = new JPanel();  // 패널 객체 생성
        jp2.setLayout(new GridLayout(5,1));  // 패널에 Grid 배치 관리자 설정
        jp2.add(new JButton("Java"));        // 패널에 컴포넌트 추가
        jp2.add(new JButton("C"));
        jp2.add(new JButton("Visual Basic"));
        jp2.add(new JButton("JSP"));
        jp2.add(new JButton("PHP"));
        
        ct.add(jp1, BorderLayout.EAST);
        ct.add(jp2, BorderLayout.WEST);
        
        setTitle("JPanel Test2");
        setSize(300,200);
        setVisible(true);
    }
}
public class JPanelTest2 {
    public static void main(String[] args) {
        new JPanel2();
    }
}
cs




* 이벤트(event)

  - 사용자의 입력, 즉 키보드, 마우스 등의 장치로부터 발생하는 모든 사건을 의미한다.


* 이벤트 지향(event-driven) 프로그램

  - 프로그램은 무한 루프를 돌면서 사용자의 이벤트가 발생하기를 기다린다.

  - 이벤트가 발생하면, 그 이벤트를 처리하고 다시 무한 루프에 빠지게 된다.


* 위임형 이벤트 모델(delegation event model)

  - 자바의 이벤트 처리 모델

  - 컴포넌트에 등록된 이벤트가 발생하면 리스너를 호출한다.


* 자바에서의 대부분의 이벤트는 GUI 관련 컴포넌트에서 발생한다.


  - JComponent ┬ AbstractButton ┬ JMenuItem ┬ JCheckBoxMenuItem

               │                │           │ JMenu

               │                │           └ JRadioButtonMenuItem

               │                ├ JButton

               │                └ JToggleButton ┬ JCheckBox

               │                                └ JRadioButton

               ├ JComboBox

               ├ JLabel

               ├ JMenuBar

               ├ JPanel

               ├ JScrollPane

               ├ JTabbedPane

               ├ JTextComponent ┬ JTextArea

               │                └ JTextField

               ├ JTable

               └ JTree


* 자바에서는 이벤트를 객체로 처리한다.


* 자바에서는 이벤트와 연관된 클래스들을 java.awt.event 패키지로 제공한다.


* 자바 가상 기계(JVM)의 이벤트 전달

  - JVM은 컴포넌트에 등록된 이벤트가 발생하면 관련 이벤트 클래스로부터 객체를 생성하여 리스너를 호출한다.

  - 리스너는 전달받은 이벤트 객체를 이용하여 이벤트를 처리한다.


* EventObject 클래스

  - 대부분의 주요 이벤트 클래스들이 EventObject 클래스로부터 상속된다.

  - [형식]

EventObject(Object src)

※ src : 이벤트를 생성하는 객체.


* AWTEvent 클래스

  - EventObject 클래스로부터 상속된 클래스이다.

int getID() : 이벤트의 형을 반환한다.


* Action 이벤트

  - 버튼이 눌려졌거나, 리스트 항목이 선택되었을 때, 메뉴의 한 항목이 선택되었을 때 발생한다.

  - 가장 많이 사용되는 이벤트 클래스이다.

  - [형식]

ActionEvent(Object src, int type, String cmd)

ActionEvent(Object src, int type, String cmd, int modifiers)

※ src : 이벤트를 발생한 객체.

  type : 이벤트의 타입.

  cmd : 이벤트를 발생시킨 컴포넌트의 레이블.

  modifiers : 이벤트가 발생할 때 같이 사용된 수정키를 의미하는 상수.


* 수정자(modifier) 키를 구분하기 위한 상수

  - ALT_MASK : 수정자 키로 ALT 키를 사용.

  - CTRL_MASK : 수정자 키로 CTRL 키를 사용.

  - META_MASK : 수정자 키로 META 키를 사용.

  - SHIFT_MASK : 수정자 키로 SHIFT 키를 사용.


* Adjustment 이벤트

  - 스크롤 바의 위치가 이동되면 발생한다.

  - BLOCK_DECREMENT : 스크롤 바의 값을 감소시키는 경우.

  - BLOCK_INCREMENT : 스크롤 바의 값을 증가시키는 경우.

  - TRACK : 스크롤 바를 드래그(drag)하는 경우.

  - UNIT_DECREMENT : 스크롤 바의 값을 하향 버튼을 사용하여 감소시키는 경우.

  - UNIT_INCREMENT : 스크롤 바의 값을 상향 버튼을 사용하여 증가시키는 경우.


* ItemEvent

  - 체크박스나 리스트 항목이 선택되었을 때 또는 메뉴의 한 항목이 선택되었거나 선택된 항목이 해제될 때 발생한다.

  - SELECTED : 한 항목이 선택되었을 때.

  - DESELECTED : 선택된 항목이 해제되었을 때.


* KeyEvent, MouseEvent 등등


* 이벤트 리스너 인터페이스를 이용하여 이벤트를 처리하기 위한 순서

  1. 처리할 이벤트의 종류를 결정한다.

  2. 이벤트에 적합한 이벤트 리스너 인터페이스를 사용하여 클래스를 작성한다.

  3. 이벤트를 받아들일 각 컴포넌트에 리스너를 등록한다.

  예) addActionListener(ActionListener l)

      addItemListener(ItemListener l)

      addKeyListener(KeyListener l)

      addMouseListener(MouseListener l) 등

  ※ 리스너 제거는 add 대신 remove.

  4. 리스너 인터페이스에 선언된 메소드를 오버라이딩하여 이벤트 처리 루틴을 작성한다.


* ava.awt.event 패키지

  - 각각의 이벤트 클래스와 연관된 이벤트 리스너 인터페이스를 제공한다.


* 자바에서는 다양한 방법으로 이벤트를 처리할 수 있다.

  1. GUI를 제공하는 클래스에서 직접이벤트를 처리하는 방법

  2. 이벤트 처리를 위한 클래스를 따로 만들어 사용하는 방법

  3. 내부 클래스를 사용하여 이벤트를 처리하는 방법

  4. 무명(anonymous) 클래스를 이용하는 방법

  5. 람다식(Java 1.8)을 이용하는 방법


* GUI를 제공하는 클래스 내에서 처리하는 방법

  1. 처리가 요구되는 이벤트를 결정한다.

  2. 관련된 리스너 인터페이스를 포함하여 클래스를 작성한다.

  3. 인터페이스에 선언된 메소드를 오버라이딩하여 이벤트 처리 루틴을 작성한다.


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
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
 
class Event1 extends JFrame implements ActionListener {
// 버튼에 동작하는 이벤트를 처리하기 위해 ActionListener를 포함.
    JLabel jl;  // JLabel 객체를 속성으로 등록.
    public Event1() {
        Container ct = getContentPane();
        ct.setLayout(new FlowLayout());
        
        JButton jb = new JButton("버튼");  // 버튼 객체 생성.
        jl = new JLabel("버튼을 누르세요.");  // 라벨 객체 생성.
        jb.addActionListener(this);  // 버튼 객체에 리스너를 등록.
                                     // (this는 자체 처리를 의미.)
        ct.add(jb);
        ct.add(jl);
        
        setTitle("Event Test1");
        setSize(200100);
        setVisible(true);
    }
    public void actionPerformed(ActionEvent e) {  // 이벤트 처리 메소드 작성.
        jl.setText("잘 하셨어요.");  // 라벨의 값을 새로운 값으로 설정.
    }
}
public class EventTest1 {
    public static void main(String[] args) {
        new Event1();
    }
}
cs



오늘도 수고하셨습니다!

자바 수업 4일차



* 엘리베이터 코딩 깜빡했다.


* 다른 시각으로 바라보는 것이 필요하다.

  - 고정관념 버리기

  - 새로운 방법으로 시도하기

  - 자바 관련 도서, 다른 저자가 쓴 것도 봐라.


* 다이어그램 등에서 상속을 설명할 때 화살표 방향은 일반적으로 생각하는 것과 반대이다.

  - 객체 생성의 화살표 방향은 일반적으로 생각하는 대로이다.


* 클래스 상속의 이점

  - 코드를 간결하게 할 수 있다.

  - 코드의 재사용성을 높인다.


* 캡슐화

  - 캡슐로 된 감기약과 같은 개념

    ~ 캡슐에는 많은 성분이 포함되어 있지만, 단순히 감기를 낫게 해 준다고 생각

    ~ 개별 성분은 알 수 없지만, 약의 효과만 알고 선택하는 것과 같다.

  - 꼭 필요한 내용만 보여주고, 불필요한 내용을 감춘다는 개념이다.

  - 클래스를 작성할 때는 꼭 필요한 내용만 공개해야 한다.

  - 클래스를 작성할 때 캡슐화 개념을 적용하지 않으면, 클래스가 잘못 사용될 수 있다.

  - 캡슐화의 개념을 적용하여 정보 은폐(information hiding)를 달성할 수 있다.

  

* 캡슐화를 통한 '정보의 은폐(information hiding)'의 장점

  - 객체에 포함된 정보의 손상과 오용을 막을 수 있다.

  - 객체 내부의 조작 방법이 바뀌어도 사용법은 바뀌지 않는다.

  - 데이터가 바뀌어도 다른 객체에 영향을 주지 않아 독립성이 유지된다.

  - 처리된 결과만 사용하므로 객체의 이식성이 좋다.

  - 객체를 부품화 할 수 있어 새로운 시스템의 구성에 부품처럼 사용할 수 있다.


* 캡슐화의 방법

  - private 한정자(접근 제한자)를 지정하여 캡슐화가 가능하다.


* 추상화

  - 실세계의 문제를 객체로 변환할 때 적용할 수 있는 개념이다.

  - 여러 개의 문제에서 공통적인 속성을 추출하여 상위 클래스에 작성하고, 나머지 클래스를 하위 클래스로 구성하는 것이 추상화의 핵심이다.

  - 추상화와 상속은 다형성을 제공하는 기반이다.


* 추상화의 단계

  - 1단계 : 현실 세계의 문제들이 가지는 공통적인 속성을 추출

  - 2단계 : 공통 속성을 가지는 추상 클래스 작성

  - 3단계 : 추상 클래스들의 하위 클래스로 현실 세계의 문제들을 구현


* 다형성(Polymorphism)

  - 객체지향의 중요한 개념 중 하나. 다양한(poly) 변신(morphism)을 의미한다.

  - 서로 다른 객체가 동일한 메시지에 대하여 서로 다른 방법으로 응답할 수 있는 기능이다.



☞ 클래스


* 자바 프로그램은 클래스로부터 객체를 생성하여 프로그램이 작성된다.

  - 객체를 생성하기 위해서는 클래스를 작성해야 한다.


* 클래스의 구성 요소

  - 멤버 변수, 생성자(또는 생성자 메소드), 메소드로 구성된다.

  - 클래스가 항상 3가지 요소를 모두 가지는 것은 아니다.


* 클래스의 예

  a. 멤버 변수, 생성자 메소드를 가지는 클래스

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class Box {
    int width;   // 속성 - 멤버 변수
    int height;
    int depth;
    public Box(int w, int h, int d) {   // 기능 - 생성자 메소드
        width = w;
        height = h;
        depth = d;
    }
    public void volume() {   // 기능 - 메소드
        int vol;
        vol = width * height * depth;
        System.out.println("Volume is " +vol);
    }
}
cs


  b. 속성만 가지는 클래스

1
2
3
4
5
public class Box {
    int width;   // 속성 - 멤버 변수
    int height;
    int depth;
}
cs


  c. 속성과 메소드를 가지는 클래스

1
2
3
4
5
6
7
8
9
10
public class Box {
    int width;   // 속성 - 멤버 변수
    int height;
    int depth;
    public void volume() {   // 기능 - 메소드
        int vol;
        vol = width * height * depth;
        System.out.println("Volume is " +vol);
    }
}
cs


* 클래스 선언

  - [형식]

1
2
3
4
5
[public/final/abstractclass Class-name {
    ......
    ......  // 클래스의 속성과 기능을 기술
    ......
}
cs


* 클래스의 한정자

  - public : 모든 클래스에서 접근 가능

  - 한정자 사용 안 함 : 같은 패키지 내의 클래스에서만 접근 가능

  - final : 서브 클래스를 가질 수 없는 클래스

  - 추상(abstract) : 객체를 생성할 수 없는 클래스


* 다수 개의 클래스가 하나의 프로그램에 정의될 때

  - 클래스에 붙이는 public 한정자는 main() 메소드를 가진 클래스에만 붙여야 한다.

  - 프로그램의 이름은 main() 메소드를 가진 클래스의 이름과 동일해야 한다.

  - 한 패키지에는 동일한 이름의 클래스가 중복될 수 없다.


* 객체의 생성

  - [형식]

객체 변수명 = new 클래스명;

1
2
3
mybox1 = new Box();
student1 = new Avg();
name = new String("J.Hong");
cs


* 객체의 선언과 생성

  - [형식]

클래스명 객체 변수명 = new 클래스명;

1
2
3
Box mybox1 = new Box();
Avg student1 = new Avg();
String name = new String("J.Hong");
cs


* 멤버 변수

  - 클래스 내에 메소드 밖에 선언된 변수

  - 객체 변수, 클래스 변수, 종단 변수로 구분된다.


* 생성자, 메소드 변수

  - 생성자나 메소드에는 자체적으로 선언하여 사용하는 지역 변수와 호출 시 지정되는 매개 변수로 구분된다.


1
2
3
4
5
6
7
8
9
10
11
class A {
    int a;   // 멤버 변수
    int b;
    public int A1()    {
        int c;   // 지역 변수
        return 7;
    }
    public int A2(int d) {   // 매개 변수
        return 8;
    }
}
cs


* 멤버 변수의 선언

  - [형식]

[public/private/protected][static][final] 변수형 변수명;

1
2
3
4
5
6
7
public int width;
private double rate;
static int idnumber;
final int MAX = 100;
public Box mybox1;
private String passwd;
public final int MIN = 1;
cs


- static : 클래스 변수

- final : 종단 변수


생성자나 메소드의 변수(매개 변수와 지역 변수)

  - [형식]

[final] 변수형 변수명;

1
2
3
4
5
public void cc(final int x, final int y) {   // 메소드의 매개 변수에 final을 지정
    final int Max = 10;      // 메소드의 지역 변수로 final을 선언
    String name = "J.Hong";  // 지역 변수로 문자열 변수 선언
    private int num;         // 오류 발생. 객체 변수에만 사용 가능.
}
cs


* 객체 변수나 지역 변수는 변수가 가지는 값의 형에 따라 다른 특성을 가진다.

  - 기본 자료형 : 값을 가진다.

  - 참조 자료형 : 주소를 가진다.


1
2
3
4
5
6
......
int my_count1 = 100;
int my_count2 = my_count1;  // 별도의 기억 장소에 값을 복사
Box mybox1 = new Box();
Box mybox2 = mybox1;  // 두 객체 변수가 같은 장소를 가리킨다.
......
cs


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
class Box2 {
    int width = 10;  // 3개의 속성과 값을 설정
    int height = 20;
    int depth = 30;
}
public class Box2Test1 {
    public static void main(String args[]) {
        int myint1 = 100;  // 기본 자료형 변수값을 배정
        int myint2 = myint1;
        
        System.out.println("첫 번째 값 : " + myint1 + ", 두 번째 값 : " + myint2);
        
        myint1 = 200;  // 한 변수의 값을 변경하여 출력
        System.out.println("첫 번째 값 : " + myint1 + ", 두 번째 값 : " + myint2);
        
        Box2 mybox1 = new Box2();  // 두 개의 서로 다른 참조 자료형 변수 생성
        Box2 mybox2 = new Box2();
        
        mybox1.width = 20;  // 각각의 변수를 통하여 속성값을 변경
        mybox2.depth = 123;
        
        System.out.println("mybox1.width : " + mybox1.width);
        System.out.println("mybox1.height : " + mybox1.height);
        System.out.println("mybox1.depth : " + mybox1.depth);
        
        System.out.println("mybox2.width : " + mybox2.width);
        System.out.println("mybox2.height : " + mybox2.height);
        System.out.println("mybox2.depth : " + mybox2.depth);
        // 서로 영향을 받지 않는다.
        
        Box2 mybox3 = mybox2;  // 참조 자료형 변수에 다른 참조 자료형 변수를 대입
        mybox2.width = 1000;  // 값을 변경
        mybox2.height = 2000;
        
        System.out.println("mybox3.width : " + mybox3.width);
        System.out.println("mybox3.height : " + mybox3.height);
        System.out.println("mybox3.depth : " + mybox3.depth);
        // 다른 자료형 변수의 변경에 따라 값이 바뀐다.
    }
}
 
cs



* 객체 변수와 지역 변수들은 초기화 과정에서 약간의 차이가 있다.

  - 객체 변수들은 변수를 초기화하지 않아도 객체가 생성되면 묵시적 값이 자동으로 설정된다. (사실은 객체가 생성되면서 묵시적 값으로 초기화를 수행한다.)

  - 메소드 지역 변수는 변수의 값을 명시적으로 초기화하지 않으면 구문 오류가 발생한다.


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
class Initial {
    int number;   // 클래스의 속성으로 값을 지정하지 않고
    double rate;  // 객체 변수만 선언
    String name;
    int[] score;
    public void aMethod() {  // 메소드 선언
        int count;           // 메소드 지역 변수 선언
        System.out.println(number);   // 객체 변수의 값 출력
        //System.out.println(count);  // 오류 발생. 초기화되지 않은
                                      // 지역 변수값 출력 불가.
    }
}
public class InitialTest1 {
    public static void main(String args[]) {
        int var1;  // 메소드의 지역 변수로 값을 지정하지 않고 변수 선언
        double var2;
        Initial ob1 = new Initial();  // 객체의 생성. 객체 변수의 초기화 수행.
//        System.out.println("지역 변수 var1의 값은 : " + var1);  // 오류 발생. 초기화가
//        System.out.println("지역 변수 var2의 값은 : " + var2);  // 이루어진 다음 사용 가능.
        System.out.println("객체 변수 number의 값은 : " + ob1.number);  // 묵시적인 값이 출력
        System.out.println("객체 변수 rate의 값은 : " + ob1.number);
        System.out.println("객체 변수 name의 값은 : " + ob1.name);
        System.out.println("객체 변수 score의 값은 : " + ob1.score);
        ob1.aMethod();  // 객체의 메소드 호출
    }
}
cs



* 클래스 변수

  - static을 사용하여 선언한다.

  - 전역 변수(global variable)의 개념이다.

  - [형식]

static [final] 변수형 변수명;

1
2
static idnumber;  // 클래스 변수 idnumber 선언
static final fixnumber;  // 클래스 변수이면서 값이 변할 수 없는 종단 변수
cs


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
class Box3 {
    int width;
    int height;
    int depth;
    long idNum;
    static long boxID = 0;  // 클래스 변수로 boxID 선언
    public Box3() {         // 생성자에서 클래스 변수값을 증가시켜 속성 idNum에 배정
        idNum = ++boxID;
    }
}
class Box3Test1 {
    public static void main(String args[]) {
        Box3 mybox1 = new Box3();  // 객체를 생성. 생성자 수행.
        Box3 mybox2 = new Box3();
        Box3 mybox3 = new Box3();
        Box3 mybox4 = new Box3();
        
        // 객체의 idNum이 증가되면서 출력
        System.out.println("mybox1의 id 번호 : " + mybox1.idNum);
        System.out.println("mybox2의 id 번호 : " + mybox2.idNum);
        System.out.println("mybox3의 id 번호 : " + mybox3.idNum);
        // 객체명을 통하여 클래스 변수값 출력
        System.out.println("mybox4의 id 번호 : " + mybox4.idNum);
        // 클래스명을 통하여 클래스 변수값 출력
        System.out.println("마지막 생성된 박스 번호는 " + Box3.boxID + "번입니다.");
    }
}
cs



* 종단 변수

  - final을 사용하여 선언하며, 변할 수 없는 상수값을 갖는다.

  - [형식]

final 변수형 변수명 = 초기값;

1
2
3
4
5
6
7
8
9
final int MAX = 100;
static final int SONATA_LENGTH = 3200;
final int MIN;  // 오류 발생. 종단 변수는 반드시 초기화 요구.
public void inc() {
    MAX = ++MAX;  // 오류 발생. 종단 변수값은 변경할 수 없다.
}
public void max(final int x) {  // 메소드 매개 변수를 final로 선언.
    x++;  // 오류 발생. 종단 변수값은 변경할 수 없다.
}
cs



* 변수의 유효 범위

  - 그 변수가 사용될 수 있는 영역을 의미한다.


* 유효 범위 측면에서의 변수들을 구분

  - 멤버 변수

  - 메소드 매개 변수와 지역 변수(블록 변수)

  - 예외 처리기 매개 변수(exception handler parameter)


* 접근 제한자(한정자)

  - 클래스 내의 멤버 변수 접근을 제한할 수 있는 방법이다.

  - 접근 제한은 캡슐화와 정보 은폐를 제공한다.

  - 자바의 명시적인 접근 한정자 : public/private/protected


* public 접근 한정자는 항상 접근 가능함을 의미한다.

  - 꼭 공개해야 하는 정보만 public으로 선언한다.


* private 접근 한정자는 소속된 클래스 내에서만 사용 가능하다.


* 접근 한정자를 지정하지 않은 경우

  - 같은 패키지 내의 클래스에서 사용 가능하다.

  - 접근 한정자를 지정하지 않는 것은 좋은 습관이 아니다.


* 생성자는 메소드와 비슷하지만, 주로 객체의 초기화 과정을 수행한다.

  - 생성자는 객체가 생성될 때 자동으로 수행된다.

  - 주로 객체의 초기화를 위해 사용한다.

  - 생성자의 이름은 클래스의 이름과 동일하다.

  - [형식]

[public/private] 클래스 이름([매개 변수], [매개 변수], ...) {

    초기화 문장들

}

※ 생성자는 반환값이 없다.


  a. 묵시적 생성자가 없는 경우

1
2
3
4
5
6
7
8
class Cons1 {  // 생성자 없이 클래스 생성
    public int num;
}
public class ConsTest1 {
    public static void main(String args[]) {
        Cons1 cons = new Cons1();  // 클래스로부터 객체 생성
    }
}
cs


  b. 묵시적 생성자를 지정하는 경우

1
2
3
4
5
6
7
8
9
10
11
12
13
class Cons2 {
    public int num;
    public Cons2() {  // 매개 변수가 없는 묵시적 생성자 선언
        System.out.println("묵시적 생성자");
    }
}
public class ConsTest2 {
    public static void main(String args[]) {
        Cons2 cons = new Cons2();  // Cons 클래스로부터 객체 생성.
                                   // new 명령어에 의해 묵시적 생성자가
                                   // 수행되어 "묵시적 생성자"가 출력된다.
    }
}
cs


  c. 명시적 생성자가 있는 경우

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Cons3 {
    public int num;
    public Cons3(String s) {  // 매개 변수가 있는 명시적 생성자 선언
        System.out.println(s + " 명시적 생성자");
    }
}
public class ConsTest3 {
    public static void main(String args[]) {
        Cons3 cons1 = new Cons3("1번째");  // 매개 변수를 지정하여 객체 생성.
                                          // "1번째 명시적 생성자" 출력
        //Cons3 cons2 = new Cons3();      // 오류 발생. 해당되는 생성자가 없다.
                                          // 클래스에 어떠한 생성자도 없는 경우에는 묵시적 생성자가 없어도 객체가 생성되지만,
                                          // 명시적 생성자가 하나라도 있으면 묵시적 생성자를 사용하기 위해서는
                                          // 반드시 정의해야 한다. (생성자 오버로딩)
    }
}
cs



* 하나의 클래스에 여러 개의 생성자가 있다 : 생성자 오버로딩

  - 생성자 매개 변수의 타입과 개수가 달라져야 한다.


* 생성자나 메소드에서 this가 사용되면, this는 자신을 가동시킨 객체를 의미한다.


* this의 또 다른 용도 : 생성자 내에서 단독으로 사용

  - 다른 생성자를 호출한다.

  - 생성자 내에서 사용될 경우에는 반드시 첫 번째 라인에 위치해야 한다.


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
class Box7 {
    int width;
    int height;
    int depth;
    public Box7() {
        this(111);  // this를 이용하여 매개 변수를 가진 생성자 호출
        System.out.println("매개 변수 없는 생성자 수행");  // 생성자 내에서 출력문 수행
    }
    public Box7(int width) {
        this(width, 11);  // this를 이용하여 3개의 매개 변수를 가진 생성자 호출
        System.out.println("매개 변수(1개) 생성자 수행");
    }
    public Box7(int width, int height) {
        this(width, height, 1);  // this를 이용하여 3개의 매개 변수를 가진 생성자 호출
        System.out.println("매개 변수(2개) 생성자 수행");
    }
    public Box7(int width, int height, int depth) {
        System.out.println("매개 변수(3개) 생성자 수행");
        this.width = width;  // 객체의 속성에 매개 변수의 값을 배정
        this.height = height;
        this.depth = depth;
    }
}
public class Box7Test1 {
    public static void main(String args[]) {
        Box7 mybox1 = new Box7();
        int vol = mybox1.width * mybox1.height * mybox1.depth;
        System.out.println("박스의 부피(매개 변수 없음) : " + vol);
        mybox1 = new Box7(10);
        vol = mybox1.width * mybox1.height * mybox1.depth;
        System.out.println("박스의 부피(매개 변수 1개) : " + vol);
        mybox1 = new Box7(1020);
        vol = mybox1.width * mybox1.height * mybox1.depth;
        System.out.println("박스의 부피(매개 변수 2개) : " + vol);
        mybox1 = new Box7(102030);
        vol = mybox1.width * mybox1.height * mybox1.depth;
        System.out.println("박스의 부피(매개 변수 3개) : " + vol);
    }
}
cs


※ 내일까지 <윤성우의 열혈 Java 프로그래밍> 21~24장 읽어오기


* 메소드
  - 클래스의 핵심으로서 클래스의 기능을 나타낸다.
  - [형식]
[public/private/protected][static/final/abstract/synchronized] 반환값형 메소드 이름([매개 변수들])
{
    ......
    지역 변수 및 메소드의 행위 기술
    ......
}

// static : 클래스 메소드
// final : 종단 메소드
// abstract : 추상 메소드
// synchronized : 동기화 메소드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Box8 {
    int width;
    int height;
    int depth;
    public Box8(int width, int height, int depth) {
        this.width = width;
        this.height = height;
        this.depth = depth;
    }
    int volume() {  // 메소드 volume()에서 부피를 계산하여 결과를 반환 
        int vol = width * height * depth;
        return vol;
    }
}
public class Box8Test1 {
    public static void main(String args[]) {
        Box8 mybox1 = new Box8(10,20,30);
        //mybox1.width = 20;  // 접근 한정자를 사용하지 않았으므로,
                              // 값을 변경할 수 있다.
        int vol1 = mybox1.volume();  // 메소드를 호출하여 부피를 구한다.
        System.out.println("정수 박스의 부피 : " + vol1);
    }
}
 
cs


* 메소드 선언 시 사용되는 접근 한정자는 멤버 변수와 같이 public, private, protected가 사용된다.
1
2
3
4
5
6
7
8
public class Test1 {
    public int a;  // public으로 선언된 객체 변수
    int b;         // 접근 한정자를 지정하지 않고 선언된 객체 변수
    private int c;              // private로 선언된 객체 변수
    public void method1() { }   // public으로 선언된 메소드
    void method2() { }          // 접근 한정자를 지정하지 않고 선언된 메소드
    private void method3() { }  // private로 선언된 메소드
}
cs

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
class Box9 {
    private int width;  // 객체의 모든 속성들을 private로 선언
    private int height;
    private int depth;
    private int vol;
    public Box9(int width, int height, int depth) {
        this.width = width;
        this.height = height;
        this.depth = depth;
        volume();  // 생성자에서 volume() 메소드 호출
    }
    private void volume() {  // volume() 메소드를 private로 선언
        vol = width * height * depth;
    }
    public int getvolume() {  // 부피를 단순하게 변환하는 메소드,
                              // public으로 선언
        return vol;
    }
}
public class Box9Test1 {
    public static void main(String args[]) {
        Box9 mybox1 = new Box9(10,20,30);
        // mybox1.width = 20;           // 객체의 속성값을 변경하거나
        // int vol1 = mybox1.volume();  // 메소드를 호출하면 오류 발생
        
        // 부피를 읽어오는 메소드를 호출하여 값을 출력
        System.out.println("정수 박스의 부피 : " + mybox1.getvolume());
    }
}
 
cs


* 클래스 변수와 같이 메소드에도 static을 붙여 클래스 메소드로 선언한다.
  - 클래스 변수와 같이 클래스 이름으로 접근한다.
  - 객체를 생성하지 않아도 사용 가능한 함수같은 메소드이다.
1
2
3
4
Arrays.toString(a);
Arrays.sort(b);
Integer.parseInt(args[0]);
String.valueOf(number);
cs

  - 클래스 메소드 내에서는 클래스 변수만 사용이 가능하다.
1
2
3
4
5
6
7
8
9
10
11
12
13
class Box {
    int width;
    int height;
    int depth;
    long idNum;
    static long boxID = 100;
    static long getcurrentID() {
        int count = 1;
        idNum = idNum + count;
        boxID = boxID + count;
        return boxID++;
    }
}
cs


* final로 선언된 메소드
  - 서브 클래스에서 오버라이딩overriding 될 수 없음을 의미한다.

* abstract로 선언된 메소드
  - 추상 메소드로서 추상 클래스 내에서 선언될 수 있다.
  - 추상 메소드는 선언 부분만 가지고 몸체 부분이 없는 메소드로서 하위 클래스에서 오버라이딩된다.

* synchronized 메소드
  - 스레드를 동기화할 수 있는 기법을 제공하기 위해 사용되는 메소드이다.

* 메소드는 상호 호출될 수 있다.
  - 하나의 메소드에서 다른 메소드가 호출되면, 그 메소드는 수행이 중지되고 호출된 메소드로 제어가 넘어간다.
  - 호출된 메소드의 수행이 완료되면 호출한 메소드는 중지된 시점에서 다시 실행된다.

* 메소드 선언부에서 반환값의 자료형이 지정되어야 한다.
  - 반환값의 자료형이 지정된 경우, 명시적으로 return문에 의해 값이 반환되어야 한다.
  - 반환값은 기본 자료형 뿐만 아니라 참조 자료형도 반환될 수 있다.
  - 반환값이 없는 경우에는 void로 지정한다.

1
2
3
4
5
public int sum(int a, int b) {  // 반환되는 값의 형을 int로 지정한다.
    int c;
    c = a + b;
    return c;  // 정수값을 반환한다.
}
cs

1
2
3
4
5
public void calc(int x, int y) {  // 반환되는 값이 없다는 의미이다.
    ......
    if ( a < 0 ) return;  // 조건이 참이면 메소드의 실행을 종료한다.
    ......
}
cs

1
2
3
4
5
6
7
8
9
public Box volume_compute(Box instance_box) {  // 반환되는 값의 형을 Box로 지정한다.
    ......
    Box v_box = new Box();  // Box 객체를 생성하여 반환값으로 사용한다.
    v_box.width = instance_box.width;
    v_box.height = instance_box.height;
    v_box.depth = instance_box.depth;
    v_box.volume = v_box.width * v_box.height * v_box.depth;
    return v_box;  // Box 객체를 반환한다.
}
cs

* main() 메소드
  - 특수한 메소드로서 자바 프로그램의 실행이 시작되는 첫 메소드를 의미한다.

* 클래스 메소드 main()의 의미
  - main() 메소드는 클래스 메소드이므로 이 메소드에서 사용 가능한 속성 역시 클래스 속성만 사용할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class Sample {
    int count=10;       // 객체 변수 선언
    static int num=20;  // 클래스 변수 선언
    public int sum(int x, int y) {  // 메소드 선언
        return x+y;
    }
    static int mul(int x, int y) {  // 클래스 메소드 선언
        return x*y;
    }
 
    public static void main(String[] args) {
        int same;
        same = count;      // 오류 발생. 클래스 메소드는 클래스 변수만 사용 가능.
        same = num;        // 사용 가능.
        same = sum(55);  // 오류 발생. 클래스 메소드에서는 클래스 메소드만 사용 가능.
        same = mul(55);  // 사용 가능.
    }
}
cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class Sample1 {
    int count=10;
    static int num=20;
    public int sum(int x, int y) {
        return x+y;
    }
    static int mul(int x, int y) {
        return x*y;
    }
 
    public static void main(String[] args) {
        Sample1 s = new Sample1();  // main() 메소드가 속한 클래스로부터 객체 생성.
        int same = s.count;  // 객체(객체의 속성)에 접근 가능.
        same = s.num;        // Sample1.num도 가능.
        same = s.num(55);  // 객체(객체의 메소드)에 접근 가능.
        same = s.mul(55);  // Sample1.mul(5, 5)도 가능.
    }
}
cs


* main() 메소드의 매개 변수
  - 문자열의 배열로 정의
1
2
3
4
5
6
7
8
public class Sample2 {
    public static void main(String[] args) {
        String s1 = args[0];
        String s2 = args[1];
        System.out.println("첫 번째 매개 변수값 : " + s1);
        System.out.println("두 번째 매개 변수값 : " + s2);
    }
}
cs

* 생성자의 오버로딩과 같이 메소드도 오버로딩 할 수 있다.
  - 같은 클래스에 같은 이름의 메소드를 중첩하여 사용한다.
  - 메소드 매개 변수의 개수와 형이 달라야 한다.
  
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
class Box11 {
    private int ivol;
    private double dvol;
    public Box11(int w, int h, int d) {
        volume(w,h,d);  // 오버로딩된 메소드 volume()을 호출함.
    }
    public Box11(double w, double h, double d) {
        volume(w,h,d);
    }
    private void volume(int w, int h, int d) {
        ivol = w * h * d;  // 오버로딩된 메소드 volume()을 호출함.
    }
    private void volume(double w, double h, double d) {  // 동일한 이름의 메소드가 오버로딩으로 선언.
        dvol = w * h * d;
    }
    public int get_ivol() {
        return ivol;
    }
    public double get_dvol() {
        return dvol;
    }
}
public class Box11Test1 {
    public static void main(String args[]) {
        Box11 mybox1 = new Box11(10,20,30);
        System.out.println("박스의 부피(정수 매개 변수) : " + mybox1.get_ivol());
        mybox1 = new Box11(10.520.530.5);
        System.out.println("박스의 부피(실수 매개 변수) : " + mybox1.get_dvol());
        mybox1 = new Box11(102030.5);
        System.out.println("박스의 부피(정수와 실수 혼합) : " + mybox1.get_dvol());
    }
}
cs

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
class Overload {
    public void calc() {  // 오버로딩된 메소드
        System.out.println("매개 변수가 없습니다.");
    }
    public void calc(int width) {
        System.out.println("정사각형의 넓이 : " + width * width);
    }
    public void calc(int width, int height) {
        System.out.println("직사각형의 넓이 : " + width * height);
    }
    public void calc(int width, int height, int depth) {
        System.out.println("직육면체의 부피 : " + width * height * depth);
    }
}
public class OverloadTest1 {
    public static void main(String args[]) {
        Overload ol = new Overload();  // 객체를 생성.
        int input[] = new int[args.length];  // 입력한 매개 변수의 크기와 같은 정수 배열 생성.
        for(int i=0; i<args.length; i++)           // 실행 시 입력한 문자열 배열의 요소를
            input[i] = Integer.parseInt(args[i]);  // 정수로 바꾸어 정수 배열에 저장.
        switch (args.length) {  // 정수 배열의 길이를 기준으로 switch문 수행.
        case 0:                 // 배열의 길이에 따라 메소드 호출.
            ol.calc();
            break;
        case 1:
            ol.calc(input[0]);
            break;
        case 2:
            ol.calc(input[0], input[1]);
            break;
        case 3:
            ol.calc(input[0], input[1], input[2]);
            break;
        default:
            System.out.println("인수의 개수가 많습니다.");
        }
    }
}
cs


* 메소드 호출 시 매개 변수로 지정되는 실매개 변수
  - 기본 자료형과 참조 자료형

* 자바의 매개 변수 전달 기법은 call by value(값을 복사) 기법을 사용한다.
  - 값-전달 기법은 메소드 호출 시 실매개 변수의 값을 형식 매개 변수에 복사해 주는 방식이다.

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
class Argument {
    public void change(int i, int j[]) {
        i = 20;      // 기본 자료형 변수 i의 값을 변경.
        j[3= 400;  // 참조 자료형 배열의 4번째 요소의 값을 변경.
    }
    public void display(int i, int j[]) {  // 변수 i의 값과 배열을 출력.
        System.out.println("객체 변수 i의 값 : " + i);
        System.out.print("배열의 값 : ");
        for(int value : j)
            System.out.print(value + " ");
        System.out.println();
    }
}
 
class ArgumentTest1 {
    public static void main(String args[]) {
        Argument d = new Argument();
        int a = 10;
        int b[] = { 1234 };
        System.out.println("첫 번째 display() 메소드 호출");
        d.display(a, b);
        d.change(a, b);
        System.out.println("===============================");
        System.out.println("값을 변환한 다음 두 번째 display() 호출");
        d.display(a, b);
    }
}
 

cs




☞ 상속

* 자바에서의 상속은 확장(extends)의 개념
  - 하위 클래스 = 상위 클래스 + 하위 클래스에 추가된 기능과 속성

* 상속의 효과
  - 클래스 검색이 쉽다.
    ~ 상속을 통하여 클래스를 체계화할 수 있다.
  - 클래스 확장이 쉽다.
    ~ 상속을 통하여 새로운 클래스를 생성하기가 용이하다.
  - 클래스 변경이 쉽다.
    ~ 상속을 통하여 기존 클래스의 기능을 쉽게 변경할 수 있다.

* 자바 상속의 특징
  - 다중 상속을 허용하지 않는다.
  - 자바의 모든 클래스는 Object 클래스로부터 상속된다.
    ~ Object 클래스 : 자바의 최상위 클래스. 명시적으로 상속하지 않아도 묵시적 상속이 이루어진다.

* 클래스 선언 시 상속을 지정하기 위해 extends라는 예약어를 사용한다.
  - [형식]
class 클래스 이름 extends 상위 클래스 이름 {
    ......추가되는 멤버 변수
    ......생성자(생성자는 상속되지 않는다.)
    ......추가되는 메소드
}

* 자바에서 한정자를 사용할 수 있는 대상
  - 클래스
  - 멤버 변수
  - 메소드
  ※ 생성자(생성자의 한정자는 별 의미가 없다. public이나 붙이지 않거나, private가 사용될 수 있다.)

* public, 한정자 없음, private 외에 추가로 protected가 있다.
  - public : 동일 패키지나 상속 관계 등에 상관없이 모든 클래스에서 사용 가능하다.
  - protected : 동일한 패키지이면 상속 여부에 상관없이 사용 가능하고, 다른 패키지의 클래스에서는 상속된 경우에만 사용 가능하다.
  - default(한정자 없음) : 동일한 패키지이면 상속 여부에 상관없이 사용 가능하다.
  - private : 어떠한 경우에도 사용이 불가능하다. 해당 클래스 내부에서만 사용 가능하다.

* 클래스의 상속에서 생성자는 상속되지 않지만, 다음과 같은 특성을 가진다.
  - 상속 관계에서 하위 클래스에 묵시적 생성자가 있는 경우, 하위 클래스로부터 객체가 생성될 때 상위 클래스의 묵시적 생성자가 우선 수행된다.
  - 상속 관계에서 하위 클래스에 명시적(매개 변수가 있는) 생성자만 있는 경우, 상위 클래스의 묵시적 생성자가 우선 수행된다.
  - 상속 관계에서 하위 클래스에 명시적 생성자와 묵시적 생성자가 모두 있는 경우, 하위 클래스의 어떠한 생성자가 호출되더라도 상위 클래스의 묵시적 생성자가 우선 수행된다.
  - 결론, 상위 클래스의 생성자가 먼저 실행된다.

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
class DA1 {
    public double d1;
    public DA1() {
        System.out.println("클래스 DA1의 묵시적 생성자 수행");
        d1 = 10*10;
    }
}
class DA2 extends DA1 {
    public double d2;
    public DA2() {
        System.out.println("클래스 DA2의 묵시적 생성자 수행");
        d2 = 10*10*10;
    }
}
class DA3 extends DA2 {
    public double d3;
    public DA3() {
        System.out.println("클래스 DA3의 묵시적 생성자 수행");
        d3 = 10*10*10*10;
    }
}
public class DefaultInheritanceTest1 {
    public static void main(String args[]) {
        DA3 super1 = new DA3();
        System.out.println("10의 2제곱 : " + super1.d1);
        System.out.println("10의 3제곱 : " + super1.d2);
        System.out.println("10의 4제곱 : " + super1.d3);
        DA2 super2 = new DA2();
    }
}
cs

* 오버라이딩(overriding)
  - 상속 관계에 있는 클래스들간에 같은 이름의 메소드를 정의하는 경우이다.
  - 상위 클래스의 메소드와 하위 클래스의 메소드가 메소드 이름은 물론 매개 변수의 타입과 개수까지도 같아야 한다.
  ※ 메소드 오버로딩(overloading)과 혼동하지 말 것.

* 동일한 클래스 내에서 이루어지는 오버로딩을 중첩(같은 메소드 여러 개 존재)으로 표현한다면, 오버라이딩은 치환(상위 클래스의 메소드를 하위 클래스의 메소드로 교체)으로 표현할 수 있다.


오늘도 수고 많으셨습니다.


자바 수업 3일차



☞ 반복문 이어서...


* 프로그램의 특정 부분을 레이블 블록으로 지정할 수 있다.

  - break, continue문 등에서 사용 가능

  - 추천하는 방법은 아니다.


* break문

  - 레이블이 있는 곳에서, 잘못된 break문의 예


1
2
3
4
5
6
7
8
9
10
11
ff : {
    ......
}
 
gg : {
    ......
    hh : {
        ......
        if (a == 10) break ff;  // 오류 발생. 내포된 블록만 break 사용 가능.
    }
}
cs

* continue문

  - 프로그램의 제어를 반복 블록 처음으로 이동시킨다.

  - 반복문 안에서만 사용할 수 있다.



☞ 여기부터는 '배열'


* 배열

  - 같은 형의 데이터를 하나의 자료 구조에 저장할 수 있게 만든 것이다.

  - 데이터가 여러 개일 때, 변수를 단독으로 쓰는 것보다 관리하기가 편하다.


* 배열은 기본 자료형이 아니라 참조 자료형이다.

  - 배열 각각의 요소는 기본 자료형, 참조 자료형 모두 가능하다.


* 자바에서 배열 사용 : 선언, 생성 필요


  - 배열의 선언

1
2
3
4
5
type name[];     // 1차원 배열
type[] name;  
type[][] name;   // 2차원 배열
type name[][];
type[] name[];
cs


   - 배열의 생성

1
2
name = new type[size];         // size 크기의 1차원 배열 생성
name = new type[size][size];   // size 크기의 1차원 배열 생성
cs


  - 배열의 선언과 생성 : 한 문장으로 가능

1
2
3
4
5
type[] name = new type[size];
type name[] = new type[size];
type[][] name = new type[size][size];
type name[][] = new type[size][size];
type[] name[] = new type[size][size];
cs


  - 배열의 선언과 생성의 예

1
2
3
4
5
6
7
8
9
10
11
12
13
14
int[] id;
id = new int[3];   // 3개의 int 요소를 가진 배열 생성
 
또는
 
int[] id = new int[3];
String[] student_name;
student_name = new String[3];   // 3개의 문자열 요소를 가진 배열 생성
 
또는
 
String[] student_name = new String[3];
int[][] id_and_score = new int[5][2];   // 5행 2열의 정수 2차원 배열 생성
String add_and_name[][] = new String[10][10];   // 10행 10열의 문자열 배열 생성
cs


  - 배열 요소의 사용 : 배열 이름과 첨자를 이용하여 접근

1
2
3
4
int[] id = new int[3];       // 3개의 요소를 가진 int 배열
int sum = int[0+ int[1];   // 첨자는 0부터 시작
int[][] stnum = new int[3][3];
stnum[0][2= stnum[0][0+ stnum[0][1];   // 2차원 배열 첨자 사용
cs

* 2차원 배열은 1차원 배열의 배열이다.
예)
a. 2차원 배열과 메모리
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
int[][] num2 = new int[3][2]
 
num2        // 주소
 
num2[0][]   // 주소
num2[1][]
num2[2][]
 
num2[0][0]  // 데이터
num2[0][1]
 
num2[1][0]  // 데이터
num2[1][1]
 
num2[2][0]  // 데이터
num2[2][1]
cs

b. 배열의 요소 수가 다른 2차원 배열과 메모리
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
int[][] num3 = new int[3][];
num3[0= new int[2];
num3[1= new int[3];
num3[2= new int[4];
 
num3        // 주소
 
num3[0][]   // 주소
num3[1][]
num3[2][]
 
num3[0][0]  // 데이터
num3[0][1]
 
num3[1][0]  // 데이터
num3[1][1]
num3[1][2]
 
num3[2][0]  // 데이터
num3[2][1]
num3[2][2]
num3[2][3]
cs



* 배열의 초기화 : 처음 생성된 배열에 데이터를 저장하는 과정

  - 변수와 달리 배열은 초기화하지 않아도 사용이 가능하다. (오류 발생 안 한다.)

  - 배열이 초기화되지 않을 경우에는 묵시적인 값으로 자동 설정된다.

  - 가능하면 초기화는 해 주는 것이 좋다.


* 배열의 생성과 초기화

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
int[] id = new int[5];   // 1차원 배열 선언과 생성
id[0= 201195041;       // 각 요소에 값을 하나씩 저장하여 초기화.
id[1= 201195042;
id[2= 201195043;
id[3= 201195044;
id[4= 201195045;
 
또는
 
int id[] = {201195041201195042201195043201195044201195045}
// 배열의 선언과 생성. 초기화 과정을 한 문장으로 작성.
String[][] name_addr = new String[3][2]   // 2차원 배열 선언과 생성
name_addr[0][0= "kim";                  // 초기화
name_addr[0][1= "seoul";
name_addr[1][0= "park";
name_addr[1][1= "busan";
name_addr[2][0= "hong";
name_addr[2][1= "daegu";
 
또는
 
String[][] name_addr = {{"kim","seoul"},{"park","busan"},{"hong","daegu"}};
// 배열의 선언과 생성, 초기화 과정을 한 문장으로 작성
cs


* 배열이 초기화되지 않을 경우 가지는 묵시적인 값

  - byte, short, int, long : 0

  - float, double : 0.0

  - char : 공백 문자

  - boolean : 거짓(false)

  - 참조 자료형 : null


* 배열의 길이를 나타내는 length 속성

1
2
3
4
5
6
7
int a[] = { 1020304050 };
System.out.println(a.length);   // 5를 출력
 
int b[][] = {{102030}, {40506070}};
System.out.println(b.length);      // 배열 b의 행의 길이 2를 출력
System.out.println(b[0].length);   // 배열 b 첫 번째 행의 길이 3을 출력
System.out.println(b[1].length);   // 배열 b 두 번째 행의 길이 4를 출력
cs


* 확장된 for문

  - 자바는 배열의 처리를 편리하게 하기 위해 제공

  - 배열의 요소를 순차적으로 처리하는 간결한 구문 제공

  - 형식

for (type 변수명 : 배열 이름)

※ 배열 이름으로 지정된 배열의 첫 번째 요소부터 마지막 요소까지를 변수명에 배정하여 반복 처리 수행.


예)

1
2
3
4
5
6
sum = 0;
int[] inum = { 1020304050 };
for (int x : inum)   // inum 배열의 첫 번째 요소부터 마지막 요소까지를
                     // 차례로 변수 x에 저장하여 반복 처리한다.
    sum = sum + x;
System.out.println(sum);
cs



* 변수의 복사와 배열의 복사

  (a) 변수의 복사

1
2
3
4
5
int a = 100;
int b = 200;
b = a;     // b에 a의 값을 복사
a = 300;   // a에 300을 배정
// a=300, b=100
cs


  (b) 배열의 복사

  - 값이 복사되기는 하지만, 배열은 참조 자료형이므로 그 값을 주소로 취급하게 되어 두 배열명은 같은 기억 장소를 가리키게 된다.

    이 경우 한 쪽 배열 요소의 변경이 발생하면 다른 한 쪽도 변경되는 부작용(side effect)이 발생하게 된다.

  - 의도적으로 잘 사용하면 문제 없다.

1
2
3
4
5
6
7
int num1[] = {102030};   // 40200번지
int num2[] = {405060};   // 50012번지
num2 = num1;     // num2에 num1을 복사
                 // 주소가 복사되어 둘 다 40200번지를 가리킨다.
                 // 50012번지는 접근 불가
num2[2= 200;   // num2[2]에 200을 저장
                 // 50012번지는 자바의 쓰레기 수집 기능에 의해 제거된다.
cs


* 실습

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
import java.util.Random;  // 랜덤 기능을 가진 클래스 추가
public class MultiArraysTest1 {
    public static void main(String[] args) {
        // 배열 : 복수개의 데이터를 한꺼번에 모아서 지정할 수 있는 공간 생성
        // 16개의 정수를 저장 -> 정수 4개씩 그룹지어서 4개의 그룹으로 생성
        Random ran = new Random();  // Random 클래스 내의 메소드를 사용하기 위해
                                    // 복사본(객체, 인스턴스) 생성
        int score[][] = new int[4][4];  // 4개의 그룹, 각 그룹은 4개씩
                                        // 2차원 배열 score 생성
        
        for (int i=0; i<4; i++)  // 그룹을 순회(0~3번 그룹까지)
            for (int j=0; j<4; j++)  // 각 그룹 내에서 4개의 저장 공간을 순회
                score[i][j] = ran.nextInt(10);  // 임의의 숫자(0~9 사이의 정수) 배정
        
        // 배열의 각 저장 장소의 내용을 꺼내어, 표시하고, 그 총합을 표시.
        for (int k=0; k<4; k++) {  // 그룹 순회
            System.out.print((k+1+ "번째 { ");
            int sum=0;  // 각 행의 합계를 구하기 위한 변수
            for (int value : score[k]) {        // 각 그룹 내의 저장 공간 순회
                System.out.print(value + " ");  // 저장된 데이터를 출력
                sum = sum + value;
            }
            System.out.println("} 그룹의 데이터 합계는 " + sum);  // 각 행의 합계를 출력
        }
    }
}
 
cs



* 로또 번호 생성기 만들기

  - 배운 것 써먹어 보자.


※ 주의! 아래 코드는 미완성입니다.

  실행 결과, 중복값도 튀어나옵니다. ㅠ


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
import java.util.Random;
public class Lotto_645 {
    public static void main(String[] args) {
        // Lotto 6/45 번호 생성기
        
        // Random 클래스 객체 생성
        Random Ball = new Random();
        
        // 1차원 배열을 사용할 경우
        // 1~45까지의 공을 한 그릇(배열)에 저장한다.        
        int Lotto[] = new int[45];
        
        for (int i=0; i<45; i++)
            Lotto[i] = i+1;
        
        // 중복되지 않은 정수 6개를 저장할 공간을 만든다.
        int Selected[] = new int[6];
        int count = 0;
        int curNum;
        
        while (count <= 5) {
        // 중복되지 않은 숫자 6개가 모두 나올 때까지 번호를 랜덤 생성한다.
        // Random 클래스 메소드 사용
            curNum = 1 + Ball.nextInt(45);
            
            // 중복되지 않은 공 비교, 숫자가 다 나올 때까지 반복.
            for (int oldNum : Selected) {
                if(curNum != oldNum) {  // 방금 뽑은 숫자가, 과거에 뽑힌 숫자가 아니면
                    System.out.println(curNum + "가 선택되었습니다.");
                    Selected[count] = curNum;
                    count++;
                    break;
                }  // 방금 뽑은 숫자가, 과거에 이미 뽑힌 숫자라면(중복이면)
            }
        }
 
        // 6개의 공간에 들어있는 숫자를 다 빼서 출력한다.
        System.out.println("이번 주의 로또 번호는 아래와 같습니다.");
        for(int y : Selected)
            System.out.print(y + " ");
    }
}
cs



* 랜덤도 프로그램 상에서 패턴이 존재한다. (!!!)

  - 돌리다 보면, 동일한 패턴이 다시 나온다.

  - 패턴을 깨기 위해서는, 랜덤 시드 값을 변경해야 한다.


* 자바의 배열 관련 라이브러리 클래스

  - Arrays 클래스와, 배열을 복사하기 위한 메소드(arraycopy())을 제공하는 System 클래스를 제공한다.

  - Arrays 클래스 사용 예

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
int[] a = new int[10];
Arrays.fill(a, 1);   // 배열 a의 모든 요소를 1로 채운다.
Arrays.fill(a,1,5,10);   // a[1]부터 a[4]까지의 값을 10으로 채운다.
System.out.println(Arrays.toString(a));   // 배열 a를 문자열로 출력한다.
 
int[] b = { 371089 };
Arrays.sort(b);   // 배열 b의 요소들을 오름차순으로 정렬한다.
System.out.println(Arrays.toString(b));   // 정렬된 결과를 출력한다.
System.out.println(Arrays.binarySearch(b, 7));   // 7의 인덱스 값 3을 출력한다.
 
int[] c = {123};
int[] d = {123};
int[] e = {456};
System.out.println(Arrays.equals(c, d));   // true 출력
System.out.println(Arrays.equals(c, e));   // false 출력
cs




☞ 객체지향


* 객체지향(Object-Oriented) 이론

  - 컴퓨터를 통하여 실세계와 같은 환경을 흉내(simulation)내기 위해 발전한 이론

  - (실세계의) 사물 = 속성 + 기능


* 1960년 노르웨이의 달Dahl과 뉘고르Nygaard가 개발한 시뮬라Simula라는 언어를 최초의 객체 지향 언어라 할 수 있다.


* 객체지향의 장점

  - 문제를 쉽고 자연스럽게 프로그램화(모델링) 할 수 있다.

  - 쉬운 프로그램의 개발로 인한 생산성을 향상시킬 수 있다.

  - 프로그램 모듈을 재사용할 수 있다.


* 클래스

  - 하나의 클래스로부터 여러 개의 객체를 생성하기 위해 사용하는 형판이다.

  - 먹을 수 없는 붕어빵 틀(클래스)로부터 먹을 수 있는 붕어빵(객체)를 만들어 낸다.


* 객체

  - "속성 + 기능"으로 구성된다.

  - 객체를 생성하는 클래스 역시 "속성 + 기능"으로 구성된다.


* 실체화(instantiation)

  - 클래스로부터 객체를 생성하는 과정이다.

  - 객체를 인스턴스(instance)라고 부르기도 한다.

  - 즉, 객체 = 인스턴스


1
2
3
4
5
6
7
8
9
10
class PlusMinusTest1 {
    public static void main(String args[]) {
        PlusMinus ob1 = new PlusMinus();   // PlusMinus 클래스로부터 ob1 객체 생성
        String sum, minus;
        sum = ob1.plus(5030);   // 생성된 객체에 메시지를 보내 합과 차를 구한다.
        minus = ob1.minus(5030);
        System.out.println(sum);   // 합과 차를 출력한다.
        System.out.println(minus);
    }
}
cs


* 기존 클래스의 기능을 가지면서 추가적인 기능을 가진 클래스를 만들려면?

  - 기존 클래스를 그대로 복사하고, 추가적인 기능을 넣을 수도 있지만, 코드의 중복과 중복으로 인해 추후 수정이 힘들어진다.

  - 객체지향에서는 이러한 문제를 상속이라는 기능으로 해결한다.

  - 즉, 새로운 클래스를 만들 때 상위 클래스를 지정함으로써 상위 클래스의 모든 속성과 기능을 상속받고, 자신의 클래스에는 추가적인 속성과 기능만을 추가하는 방법이다.


예)

1
2
3
4
5
6
7
8
9
10
class A {
    int a;
    int b;
    public int A1() {
        return 7;
    }
    public int A2() {
        return 8;
    }
}
cs


1
2
3
4
5
6
7
8
9
10
class B extends A {
    int x;
    int y;
    public int B1() {
        return 11;
    }
    public int B2() {
        return 12;
    }
}
cs


1
2
3
4
5
6
7
8
9
public class ClassObjectInheritanceTest1 {
    public static void main(String[] args) {
        B objB = new B();
        int aa = objB.B2();
        int bb = objB.A1();
        System.out.println(aa);
        System.out.println(bb);
    }
}
cs


* 클래스 예제

1
2
3
4
5
6
7
8
9
10
11
class PlusMinus {
    int plus, minus;
    public String plus(int x, int y) {
        plus = x + y;
        return "두 수의 합은 " + plus;
    }
    public String minus(int x, int y) {
        minus = x - y;
        return "두 수의 차는 " + minus;
    }
}
cs


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
class MultiDiv extends PlusMinus {   // MultiDiv 클래스의 상위 클래스로 PlusMinus 클래스 지정
    int multi;   // 두 개의 속성을 지정
    double div;
    public String multi(int x, int y) {   // multi 메소드 지정
        multi = x * y;
        return "두 수의 곱은 " + multi;
    }
    public String div(int x, int y) {   // div 메소드 지정
        div = (double) x / y;
        return "두 수의 나눈 값은 " + div;
    }
}
 
public class FourRulesTest1 {
    public static void main(String[] args) {
        String plus, minus, multi, div;
        MultiDiv ob1 = new MultiDiv();   // MultiDiv 클래스로부터 객체 생성
        plus = ob1.plus(5030);   // 객체의 메소드 호출
        minus = ob1.minus(5030);
        multi = ob1.multi(5030);
        div = ob1.div(5030);
        System.out.println(plus);   // 결과 출력
        System.out.println(minus);
        System.out.println(multi);
        System.out.println(div);
    }
}
cs


* 과제

  - 엘리베이터를 코딩해 봐라.



오늘도 수고하셨습니다.




자바 수업 2일차



* 하드웨어에도 관심을 가지면 좋다.

  - 라즈베리파이, 아두이노


* 비트 연산자

  - 2진수로 표현된 정수를 비트 단위로 취급하는 연산자

  - 비트 논리 연산자

    · & : AND  (예) 5&7

    · | : OR  (예) 5|7

    · ^ : XOR(eXclusive OR)  (예) 5^7

    · ~ : NOT(부정, 1의 보수)  (예) ~5


* 시프트 연산자

  - 비트 단위로 이동하는 연산자

  - 하드웨어에서 많이 사용

  - 정수를 좌우로 시프트하면 곱셈과 나눗셈의 결과가 나온다.

    · << : 곱하기  (예) a << n, 정수 a를 비트 단위로 왼쪽으로 n비트 시프트한다. 비게 된 비트에는 0으로 채운다.

    · >> : 나누기  (예) a >> n, 정수 a를 비트 단위로 오른쪽으로 n비트 시프트한다. 비게 된 비트에는 시프트 전의 부호 비트로 채운다.

    · >>> : (예) a >>> n, 정수 a를 비트 단위로 오른쪽으로 n비트 시프트한다. 비게 된 비트에는 0으로 채운다. 부호 비트를 고려하지 않기 때문에 a가 음수일 경우 시프트 결과는 양수로 나타낸다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import java.util.Scanner;
 
public class ShiftOPTest1 {
    public static void main(String[] args) {
        Scanner stdin = new Scanner(System.in);
 
        System.out.println("두 개의 숫자를 입력 : ");
 
        int a = stdin.nextInt();
        int b = stdin.nextInt();
 
        System.out.println("    a = " + a + "(" + Integer.toBinaryString(a) +")");
        System.out.println("    b = " + b + "(" + Integer.toBinaryString(b) +")");
        System.out.println(" a<<2 = " + (a<<2+ "(" + Integer.toBinaryString(a<<2+ ")");
        System.out.println(" a>>2 = " + (a>>2+ "(" + Integer.toBinaryString(a>>2+ ")");
        System.out.println(" b<<2 = " + (b<<2+ "(" + Integer.toBinaryString(b<<2+ ")");
        System.out.println(" b>>2 = " + (b>>2+ "(" + Integer.toBinaryString(b>>2+ ")");
        System.out.println("b>>>2 = " + (b>>>2+ "(" + Integer.toBinaryString(b>>>2+ ")");
        System.out.println("b>>>3 = " + (b>>>3+ "(" + Integer.toBinaryString(b>>>3+ ")");
        System.out.println("b>>>4 = " + (b>>>4+ "(" + Integer.toBinaryString(b>>>4+ ")");
        System.out.println("b>>>30 = " + (b>>>30+ "(" + Integer.toBinaryString(b>>>30+ ")");
    }
}
cs


    ※ 이클립스 콘솔에서는, 앞에 채운 0이 생략되어 찍힌다.

      CMD에서도 마찬가지로 0이 생략됨을 확인하였음!


* 3항 연산자

  - 수식1 ? 수식2 : 수식3

  예) int a = 11;

      flag = a>=10 ? true : false

      System.out.println(flag);


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import java.util.Scanner;
 
public class TernaryOPTest {
    public static void main(String[] args) {
        Scanner stdin = new Scanner(System.in);
 
        System.out.println("한 개의 숫자를 입력 : ");
        int a = stdin.nextInt();  // 정수를 입력받는다.        
 
        boolean flag;
        flag = (a % 2 == 0) ? true : false;        
 
        System.out.println(a + "이(가) 짝수입니까? : ");
        System.out.println(flag);
    }
}
cs

* 자바의 문자열
  - 기본 자료형이 아닌 String 클래스로 구현되는 참조 자료형이다.
  - 문자열과 정수를 연산할 때는 정수의 연산이 먼저 계산된다.
    예) System.out.println(a + b + "리 금수강산"); -> (a+b)가 먼저 계산됨.

* 선택문
  - if문 / 조건식 / switch문

* 이중 if문
if (grade >= 90)
  System.out.println("A학점 취득 성공");
else
  System.out.println("A학점 취득 실패");

위의 문장을 3항 연산자를 이용하면
System.out.println(grade >= 90 ? "A학점 취득 성공" : "A학점 취득 실패");

한 문장으로 표현 가능하다.

* 선택문 안에 선택문이 내포될 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
if (조건식)
{
    if (조건식)
    {
        ...
    }
    else
    {
        if (조건식)
        {
            ...
        }
    }
}
cs

※ 하지만 이딴 식으로 작성하면 읽기가 곤란해진다.
  들여쓰기를 잘 해서(확실하게 눈에 띄게), 줄을 잘 맞추자.

* 개발하려는 프로그램의 핵심은 조건식
  - 일반적인 문제에서 조건식을 명확하게 추출하는 것이 프로그램의 핵심
  - 많이 해보는 수밖에 없다.

* 드모르간의 법칙
  - 특히 소프트웨어에서는 굳이 알 필요 없다.
  - a && b는 !(!a || !b)과 같습니다.
  - a || b는 !(!a && !b)와 같습니다.
    예)
    1. (score1 >= 80 || score2 >= 80)  ==  !(score1 < 80 && score2 < 80)
    2. (score > 60 && score <= 100)  ==  !(score <= 60 || score > 100)
    3. (input1 % 2 == 0 && input2 % 2 == 0)  ==  !(input1 % 2 != 0 || input2 % 2 != 0)

* 논리 연산자와 비트 논리 연산자는 다르게 동작한다.
int a=10, b=20;
System.out.println((a >= 20) & (b >= 20));  <- false 출력
System.out.println((a >= 20) && (b >= 20));  <- false 출력

  - 결과는 같지만 실제 실행은 다르다.
  - 논리 연산자는 단락 평가 연산자로서 한 쪽을 평가하여 다른 한 쪽을 평가할 필요가 없는 경우 바로 결과를 반환하지만, 비트 논리 연산자는 그 경우에도 남은 부분을 수행한다.

* switch-case문
  - if-else문과의 차이점
    ~ if문에서는 조건식에서 판단이 다 끝나버린다.
    예)
    if (a == 1)
    else if (a == 2)
    else if (a == 3)
    ~ switch문에서는
    예)
    switch(n)
      case 1:
      case 2:
      case 3:
  - switch문에서 주의할 점
    ~ true가 나오는 case부터 시작한다.
      위의 코드에서 n=2라면, case 2부터 시작해서 3, 4, ... 식으로 계속 진행한다.
      필요한 경우 case마다 break를 넣어줘야 한다.
  - switch문의 default문 == if문의 else문

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
import java.util.Scanner;
public class SwitchTest1 {
    public static void main(String[] args) {
        Scanner stdin = new Scanner(System.in);
        System.out.println("월을 입력하세요 : ");
        int month = stdin.nextInt();
        String MtoS;
        switch (month)
        {
            case 12:
            case 1:
            case 2:
                MtoS = "겨울입니다.";
                break;
            case 3:
            case 4:
            case 5:
                MtoS = "봄입니다.";
                break;
            case 6:
            case 7:
            case 8:
                MtoS = "여름입니다.";
                break;
            case 9:
                System.out.print("멋진 9월과 ");
            case 10:
                System.out.print("아름다운 10월과 ");
            case 11:
                System.out.print("낙엽의 11월은 ");
                MtoS = "가을입니다.";
                break;
            default:
                MtoS = "제대로 입력하세요. -_-";
                break;
        }
        System.out.println(MtoS);
    }
}
cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import java.util.Scanner;
public class SwitchTest1_2 {
    public static void main(String[] args) {
        Scanner stdin = new Scanner(System.in);
        System.out.println("월을 입력하세요 : ");
        int month = stdin.nextInt();
 
        if ( (month == 12|| (month == 1|| (month == 2) )
            System.out.println("겨울입니다.");
        else if ( (month == 3|| (month == 4|| (month == 5) )
            System.out.println("봄입니다.");
        else if ( (month == 6|| (month == 7|| (month == 8) )
            System.out.println("여름입니다.");
        else if ( (month == 9|| (month == 10|| (month == 11) )
            System.out.println("가을입니다.");
        else
            System.out.println("제대로 입력하세요. -_-");
    }
}
cs


* 반복문

  - for문

1
2
3
4
5
6
7
8
9
public class ForTest1 {
    public static void main(String[] args) {
        int i, sum=0;
        for (i = 1; i <= 10; i++) {
            sum = sum + i;
        }
        System.out.println("1부터 10까지의 합은 " + sum + "입니다.");
    }
}
cs

1
2
3
4
5
6
7
8
9
10
11
12
public class ForTest1_2 {
    public static void main(String[] args) {
        int sum = 0;
        int count;
        int num = 1;
        
        for (count = 1; count <= 10; count++, num++) {
            sum = sum + num;
        }
        System.out.println("1부터 10까지의 합은 " + sum + "입니다.");
    }
}
cs


  - 반복문 기초 필수 코스, 바로... 구구단

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class Test_9x9 {
    public static void main(String[] args) {
        // 구구단 9단
        // for문 사용
        
        // 반복 횟수 : 8회(1단 제외) 안에서 다시 9회 반복
        // 반복 시, 변화되는 내용 : 곱하는 숫자가 1씩 증가, 곱해지는 숫자도 1씩 증가.
        // 출력 내용 : ? x ? = ?
        
        int x = 0;
        int y = 0;
        
        System.out.println("구구단 출력하기");
        
        for (x=2; x<=9; x++) {   // 1단은 제외하고 2단부터 시작
            System.out.println("\n구구단 " + x + "단");
            for (y=1; y<=9; y++) {
                System.out.println(x + " x " + y + " = " + (x*y));
            }
        }
    }
cs


* 코딩 과제
  - 음료 자동 판매기
    ~ 음료 종류 : 콜라(800원), 생수(400원), 주스(1,000원)
    ~ 시나리오
      1. 지폐 1,000원 투입
      2. 생수 2개를 선택
      3-1. 반환 버튼 -> 200원 반환
      3-2. 1,000원 지폐 더 투입
      4. 콜라 1개 선택
      5. 생수 1병 선택


※ 주의 : 아래의 코드는 완벽하게 동작하지 않는 미완성 코드입니다.


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
62
63
64
65
66
67
68
import java.util.Scanner;
public class VendingMachine {
    public static void main(String[] args) {
    //  - 음료 자동 판매기
    //      ~ 음료 종류 : 콜라(800원), 생수(400원), 주스(1,000원)
    //      ~ 시나리오
    //        1. 지폐 1,000원 투입
    //        2. 생수 2개를 선택
    //        3-1. 반환 버튼 -> 200원 반환
    //        3-2. 1,000원 지폐 더 투입
    //        4. 콜라 1개 선택
    //        5. 생수 1병 선택
        
        int totalMoney = 0;  // 잔액 기억 변수
        Scanner objDrink = new Scanner(System.in);
        int yourChoice = -1;
        
        System.out.println("어서오세요. 음료 한 잔 하고 가세요 ^^");
        System.out.println("잔액은 " + totalMoney + "원입니다.");
        
        while(true)    {
            System.out.print("음료를 뽑으시려면 돈을 투입해주세요.\n금액 : ");
            Scanner objMoney = new Scanner(System.in);
            int moneyInput = objMoney.nextInt();
            
            if (moneyInput > 0) {  // 투입된 금액이 있으면
                totalMoney = totalMoney + moneyInput;
                System.out.println("현재 잔액은 " + totalMoney + "원입니다.");
                
                // 선택 가능한 메뉴 표시
                if (totalMoney >= 1000)
                    System.out.print("메뉴를 선택하세요.\n[반환:0, 생수:1, 콜라:2, 쥬스:3] : ");
                else if (totalMoney >= 800)
                    System.out.print("메뉴를 선택하세요.\n[반환:0, 생수:1, 콜라:2] : ");
                else if (totalMoney >= 400)
                    System.out.print("메뉴를 선택하세요.\n[반환:0, 생수:1] : ");
                else
                    System.out.println("선택할 수 있는 메뉴가 없습니다. 돈을 더 넣으세요.");
                
                // 메뉴 선택
                if (totalMoney >= 400) {
                    yourChoice = objDrink.nextInt();
                }
                
                switch (yourChoice) {
                    case 0:
                        System.out.println("잔액 " + totalMoney + "원이 반환되었습니다. 잘 가세요.");
                        totalMoney = 0;  // 잔액 재계산
                        break;
                    case 1:
                        System.out.println("생수를 선택하셨네요^^ 여기 있어요.");
                        totalMoney = totalMoney - 400;  // 잔액 재계산
                        break;
                    case 2:
                        System.out.println("코카콜라~");
                        totalMoney -= 800;  // 잔액 재계산
                        break;
                    case 3:
                        System.out.println("오렌지 주스 받으세요.");
                        totalMoney -= 1000;  // 잔액 재계산
                        break;
                }
                // 잔액 표시
                System.out.println("현재 잔액은 " + totalMoney + "원입니다.");
            }
        }
    }
}
cs


+ Recent posts