본문 바로가기
공부기록/Java

4월 13일 (1) Java - 기타 제어자, 생성자

by project100 2023. 4. 13.

문제가 일어났을 때 해결하는 방법 고민

 

초기값은 사용되지 않을 값을 넣은 것이기 때문에 아무런 값도 입력하지 않았을 때 어떻게 표현되게 할 것인지 고민해 보기

 

입출력용 장치(부품 클래스)

InOutClass - Scanner 없이 입출력장치가능하게 만들기

package View;

import java.util.Scanner;

public class InOutClass {
    // 화면에 출력하거나 키보드로부터 값을 받는 기능을 제공하는 부픔 클래스
    // 다른 클래스에서는 print와 Scanner를 사용하지 않고 이 클래스에서만 하도록 제한
    // 제공 기능
    // 1. 출력 : 한줄 출력과 두줄 출력
    // 한줄 출력용 메소드, 화면은 문자열
    public void olPrint(String str){
        System.out.print(str);// 출력 화면이 바뀔 경우 수정하면 되는 부분
    }

    // 두줄 출력용 메소드
    public void tlPrint(String str){
        System.out.println(str);
    }

    // 2. 입력 : 안내문구 출력과 입력, 정수, 실수, 문자열
    private Scanner scan = new Scanner(System.in);

    // 문자열 입력 메소드
    public String inStr(String s){
        // 안내 문구 s를 받아서 먼저 출력하고 입력 받기
        olPrint(s); // 안내문구 출력
        String str = scan.nextLine(); //문자열 입력
        return str; // 입력 받은 문자열 넘겨주기
    }

    // 정수 입력 메소드
    // 문자열 -> 정수변환
    public int intNum(String s){
        int num = -999999;// 생각할 수 있는 최소의 값으로 초기화
        String nstr = inStr(s);//문자를 입력하지 않는다. 숫자만 입력
        if(!nstr.equals("")){
            num = Integer.parseInt(nstr);
        }
        return num;
    }

    // 실수 입력 메소드
    // 문자열 -> 실수변환
    public float intFloat(String s){
        float fnum = -0.0000000000001f;
         String fstr = inStr(s);
         if(!fstr.equals("")){
             fnum = Float.parseFloat(fstr);
         }
         return fnum;
    }
}

test - 초기값이 사용되지 않도록 처리해 주기

package View;

public class InOutTest {
    static InOutClass ioc = new InOutClass();

    public static void main(String[] args) {
        // 타이틀 출력
        ioc.tlPrint("어떤 프로그램 제목");
        int num = ioc.intNum("입력값 : ");
        String str = ioc.inStr("문자열 : ");
        float fnum = ioc.intFloat("실수 : ");

        ioc.olPrint((num + ", " + str + ", " + fnum));

        while (true) {
            ioc.tlPrint("메뉴>");
            ioc.tlPrint("1. 입력");
            ioc.tlPrint("2. 출력");
            ioc.tlPrint("0. 종료");
            num = ioc.intNum("입력 : ");

            if(num == 0){
                ioc.tlPrint("프로그램 종료");
                break;
            }

            switch (num){
                case 1 :
                    ioc.tlPrint("입력");
                    break;
                case 2 :
                    ioc.tlPrint("출력");
                    break;
                default:
                    ioc.tlPrint("잘못 입력하였습니다.");
            }
        }
    }
}

 

종속된다(Dependency) - 라이브러리

A클래스가 B클래스의 인스턴스를 사용할 때, 'A는 B에 종속된다'라고 말한다. (종속관계)

예) 논문, 참고문헌, InOutClass에 test가 종속된다.

 


객체 지향의 특성

1. 캡슐화(+ 정보은닉)

in Java -> class = 필드 + 메소드

정보은닉 -> 접근제어자

 

private사용 - 변수(필드)는 숨긴다.  

public사용 - 메소드는 공개한다.

 

제어자 

1) 접근제어자 - public, protected, default, private

2) 기타 제어자(접근제어자 외) - static, final

 

static - 인스턴스 없이 사용 가능한 필드나 메소드

new로 인스턴스를 만들어 주어야 하는데, 예외적으로 처음 시작할 때 인스턴스를 만들 수 없기 때문에 쓰는 제어자

 

static이 붙은 필드(클래스변수) - 모든 인스턴스 공유하는 공간, 모든 인스턴스에 같은 값이 적용되도록 사용하는 공간

모든 인스턴스는 생성되면 자기만의 공간을 갖는다.

인스턴스 별로 다른 값을 저장할 때 필드를 사용, 모든 인스턴스가 같은 값을 저장할 때 클래스 변수를 사용

 

flash파일 - MemberVar

인스턴스 변수는 Heap 영역에 생성 // 예) 카드모양의 값, 카드의 숫자 heart, 7

클래스 변수는 Method 영역에 생성 //설계도, class에 직접적으로 작용한다. static은 하나만 생성 예) 카드의 너비와 높이

 

// 사용하는 클래스
public class CardTest {
    public static void main(String[] args) {
        Card c1 = new Card();
        c1.kind = "Heart";
        c1.number = 7;
        Card c2 = new Card();
        c2.kind = "Spade";
        c2.number = 4;

        System.out.println("c1은 " + c1.kind + ", " + c1.number + "이며, 크기는 ("
                + c1.width + ", " + c1.height + ")");
        System.out.println("c2은 " + c2.kind + ", " + c2.number + "이며, 크기는 ("
                + c2.width + ", " + c2.height + ")");

        // 인스턴스가 공유되는 공간인지 구별 불가
        Card c3 = new Card();
        System.out.println("c3은 " + c3.kind + ", " + c3.number + "이며, 크기는 ("
                + c3.width + ", " + c3.height + ")");

        // 어느 인스턴스를 바꾸어도 모든 값이 바뀐다. 하나로 처리되는 것을 볼 수 있다.
        c1.width = 50;
        c2.height = 80;

        System.out.println("c1은 " + c1.kind + ", " + c1.number + "이며, 크기는 ("
                + c1.width + ", " + c1.height + ")");
        System.out.println("c2은 " + c2.kind + ", " + c2.number + "이며, 크기는 ("
                + c2.width + ", " + c2.height + ")");
        System.out.println("c3은 " + c3.kind + ", " + c3.number + "이며, 크기는 ("
                + c3.width + ", " + c3.height + ")");

        // 클래스 자체변경을 해도 모든 카드의 너비와 높이가 바뀐다.
        Card.width = 200;
        Card.height = 500;

        System.out.println("c1은 " + c1.kind + ", " + c1.number + "이며, 크기는 ("
                + c1.width + ", " + c1.height + ")");
        System.out.println("c2은 " + c2.kind + ", " + c2.number + "이며, 크기는 ("
                + c2.width + ", " + c2.height + ")");
        System.out.println("c3은 " + c3.kind + ", " + c3.number + "이며, 크기는 ("
                + c3.width + ", " + c3.height + ")");
    }
}

// 카드 클래스
class Card {
    // 카드의 모양과 숫자는 카드마다 달라야한다.
    // 카드의 모양(하트, 클로버, 다이아몬드, 스페이스)
    String kind = "Diamond";
    // 카드의 숫자
    int number = 8;

    // 카드의 가로(너비) 세로(높이)
    // 똑같아야 하기 때문에 static을 붙인다. 미리 값을 정할 수 있다.
    // 인스턴스 없이도 클래스로 접근 가능하다.
    static int width = 100;
    static int height = 250;

}

 

스태틱 멤버(변수, 메소드)와 인스턴스 멤버 사용에 대한 제약

1. 인스턴스 멤버는 스태틱 멤버 메소드에서 사용 불가

인스턴스 멤버는 인스턴스 메소드에서만 사용

 

인스턴스 멤버가 없을 확률이 더 큰데, 불확실한 경우에는 아예 사용되지 않음.

문법적으로 막혀 있음.

 

2. 스태틱 멤버는 모든 경우에 사용 가능

※ private를 붙이지 않는다.(인스턴스 없이도 사용 가능해야 함, 보호하기 어려움)

 

인스턴스가 만들어지기 전부터 존재하기 때문에 모든 경우에 사용이 

가능한 것, 

 

 

final 제어자

마지막! (이후 변경 불가 내포) 더 이상 변형할 수 없다. 

변수, 클래스, 메소드 앞에 붙일 수 있다.

 

변수 앞에 붙으면 - 상수(constant), 초기화 후 값 변경 불가

클래스 앞에 붙으면 - 상속을 할 수 없는 클래스

메소드 앞에 붙으면 - 재정의가 안되는 메소드

 

상수명 작성 요령(권장 규칙)

1. 상수명은 대문자로 작성

2. 스네이크 케이스를 활용

예) final float PI_VALUE = 3.141592f;

 

메소드의 다형성 : Method Overloading (두 가지 중 하나, 다른 하나는 상속과 관련)

하나의 클래스에 같은 이름의 메소드를 다수 정의하는 것.

(이름은 같은데 제공 기능이 다른 메소드들)

 

조건 

1. 메소드의 이름이 같아야 한다. // 어떻게 구분할 것인가?

2. 매개변수의 개수 또는 자료형이 달라야 한다.  // 이름 뒤()

3. 반환형은 고려하지 않는다. // 메소드가 끝나고 난 후에 반환형이 사용되기 때문에  retrun 타입은 고려하지 않는다.

대표 예) System.out.println();

 

이름이 같고, 매개변수가 같은 경우 오버로딩 불가

class SimpleCal{
public int add(int a, int b){
return a + b;
}
// 같은 이름을 작성 가능, 파라미터로 구분
public int add(int a, float b){
//형변환
return (int)(a + b);
}
// 파라미터의 갯수로 구분
public int add(int a, int b, int c){
return a + b + c;
}
/* 오버로딩 아님, 메소드 중복 정의 오류
public double add(int a, int b){
return (double)(a + b);
}*/
}

 

 

생성자(Constructor) <-> 파괴자(Destuctor)는 없음!

인스턴스가 생성될 때 자동으로 호출되는 메소드

인스턴스를 만들 때마다 사용!

 

인스턴스 생성 문법>

클래스명 인스턴스명 = new 클래스명();

()는 메소드를 호출할 때 사용, 단순히 클래스명을 쓰는 것이 아니라 생성자 메소드를 호출한 것!

 

생성자 특수성

1) 클래스의 이름과 같은 이름을 갖는다.(대소문자까지 완전 동일)

    메소드 명 중 유일하게 대문자로 시작하는 메소드

2) 항상 반환하지 않는다. 그래서 반환형을 사용하지 않는다. (void도 사용하지 않는다. 유일한 예외)

3) 모든 클래스는 최소 하나의 생성자가 있어야 한다. (여러 개의 생성자를 작성할 수 있으나 반드시 하나는 있어야 한다.)

 

기본생성자(Default Constructor)

생성자 중에서 매개 변수가 없는 생성자 -> 컴파일러가 자동으로 작성해 준다.

단, 아무런 생성자가 없어야 한다.

Car mycar = new Car(); // // 색상만 지정하는 인스턴스 생성자만 생성할 경우 오류가 뜬다.
public Car(){} -> 컴파일러가 안 만들어준다. 따라서 작성해야 한다.
// 색상만 지정하는 인스턴스 생성자를 생성할 경우
public Car(String color){
this.color = color;
}

 

기본 생성자 작성 문법>

접근제어자 클래스명() {}

 

생성자의 역할

- 인스턴스를 생성할 때 딱 한 번만 호출되는 특수 메소드

=> 필드의 값을 초기화할 때 사용

 

생성자 작성 시 고려 사항

생성자는 인스턴스의 생성과 관련된 메서드가 때문에 public으로 작성(예외 있음. singleton 패턴)

생성자를 통해 인스턴스 생성을 제한할 수 있음

 

참고) 필드의 초기화 방법

1. 필드 선언 시 초기화를 같이 하는 방법

private int a = 10;

2. 인스턴스 생성 후 setter 메소드로 값을 대입

// 기본적으로 0에 해당하는 값에 초기화가 되기 때문에 엄밀히 말하면 초기화가 아니지만 처음으로 값을 넣기 때문에 초기화로 본다.

3. 생성자를 사용하여 생성 시 값을 대입

 

public class ConstructorTest {
    public static void main(String[] args) {
        Car mycar = new Car();
        // 생성자를 통해서 초기화한 값 출력
        System.out.println(mycar.getGearType());
        System.out.println(mycar.getDoor());
        // 사용자가 값을 넣음
        mycar.setColor("초록색");
        System.out.println(mycar.getColor());
    }
}

//
class  Car{
    private String color;
    private String gearType;
    private int door;

    // 1. setter 사용
    // String color 필드와 똑같은 매개변수 사용 시 필드 앞에 this를 붙여주기
    public void setColor(String color){
        this.color = color;
    }
    public String getColor(){
        return color;
    }

    // 기본 생성자
    // 타입 생략, 클래스명과 똑같이
    public Car(){
        gearType = "자동";
        door = 4;
    }

    public String getGearType(){
        return gearType;
    }
    public int getDoor(){
        return door;
    }
}