이것이 자바다 - Part 06

mj·2023년 1월 12일
0
post-thumbnail

Part 06 클래스

객체 지향 프로그래밍

소프트웨어를 개발할 때 부품에 해당하는 객체들을 먼저 만들고, 이 객체들을 하나씩 조립해서 완성된 프로그램을 만드는 기법을 객체지향 프로그래밍 이라고 한다.

객체

객체란 물리적으로 존재하거나 개념적인 것 중에서, 다른 것과 식별 가능한 것을 말한다.

객체는 속성과 동작으로 구성된다.

객체가 가지는 특성이나 값인 속성을 필드 라고 하고, 객체의 동작을 정의한 것을 메소드 라고 한다.

현실 세계의 객체를 소프트웨어 객체로 설계하는 것을 객체 모델링이라고 한다.

객체의 상호작용

객체 지향 프로그램에서 객체들은 다른 객체와 서로 상호작용하면서 동작한다.

객체들 사이의 상호작용 수단은 메소드인데 객체가 다른 객체의 기능을 이용할 때 이 메소드를 호출한다.

메소드 호출 형태
메소드(매개값1, 매개값2, ...);

int result = add(10, 20);

객체 간의 관계

객체는 단독으로 존재할 수 있지만 대부분 다른 객체와 관계를 맺고 있다.

관계의 종류에는 집합 관계, 사용 관계, 상속 관계가 있다.

집합 관계

완성품과 부품의 관계를 말한다.
예를 들어 자동차 객체는 엔진 객체, 타이어 객체, 핸들 객체 등으로 구성되어 있으므로 자동차와 부품들은 집합 관계라고 볼 수 있다.

사용 관계

다른 객체의 필드를 읽고 변경하거나 메소드를 호출하는 관계를 말한다.
예를 들어 사람 객체가 자동차 객체의 필드를 수정하고 메소드를 호출하면 사람과 자동차 관계는 사용 관계라고 볼 수 있다.

상속 관계

부모와 자식 관계를 말한다.
자동차가 기계의 특징(필드, 메소드)을 물려받는다면 기계(부모)와 자동차(자식)는 상속 관계에 있다고 볼 수 있다.

객체 지향 프로그래밍의 특징

캡슐화

객체의 필드. 메소드를 하나로 묶고 실제 구현 내용을 외부로부터 감추는 것을 의미한다.

캡슐화를 하는 이유는 외부의 잘못된 사용으로 인해 객체가 손상되지 않도록 하는 데 있다.

캡슐화의 정도를 설정할 때는 접근 제한자를 사용한다.

상속

객체 지향 프로그래밍에서는 부모 역할의 상위 객체와 자식 역할의 하위 객체가 있다.

부모 객체가 가지고 있는 특징(필드, 메소드)를 자식엑 물려주어 자식 객체가 사용할 수 있도록 한다.

상속 사용 이유

  • 코드 재사용성을 높임 : 상속을 통해 코드의 중복을 줄일 수 있다.
  • 유지 보수 시간을 최소화시켜 줌 : 부모의 특징만 수정하면 모든 자식 객체들은 수정된 필드와 메소드를 사용할 수 있다.

다형성

다형성이란 사용 방법은 동일하지만 실행 결과가 다양하게 나오는 성질을 말한다.

대표적으로 오버로딩과 오버라이딩이 있다.

  • 오버로딩 : 같은 클래스에서 동일한 이름으로 메소드 구현
  • 오버라이딩 : 상속에서의 개념. 부모에서 정의된 메소드를 자식에서 재정의

객체와 클래스

객체를 생성하려면 설계도에 해당하는 클래스가 필요하다.

클래스로부터 생성된 객체를 해당 클래스의 인스턴스라고 부른다. 그리고 클래스로부터 객체를 만드는 과정을 인스턴스화라고 한다.

클래스 선언

클래스 선언에서는 어떻게 객체를 생성(생성자)하고, 객체의 데이터(필드)는 무엇이고, 객체의 동작(메소드)은 무엇인지 정의한다.

클래스 선언

public class 클래스명 {
}

클래스 명
1. 첫 문자를 대문자
2. 캐멀 스타일로 작성
3. 숫자 포함은 가능하지만 첫 문자는 숫자가 될 수 없음.
4. 특수 문자 중 $, _ 를 포함 가능

객체 생성과 클래스 변수

클래스로부터 객체를 생성하려면 객체 생성 연산자인 new가 필요하다.

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

클래스의 두 가지 용도
1. 라이브러리(library) 클래스 : 실행할 수 없으며 다른 클래스에서 이용하는 클래스
2. 실행 클래스: main() 메소드를 가지고 있는 실행 가능한 클래스

클래스의 구성 멤버

클래스 선언에는 객체 초기화 역할을 담당하는 생성자와 객체에 포함될 필드와 메소드를 선언하는 코드가 포함된다.

그래서 생성자, 필드, 메소드를 클래스 구성 멤버라고 한다.

필드

객체의 데이터를 저장하는 역할.
선언 형태는 변수 선언과 비슷하지만 쓰임새는 다르다.

생성자

new 연산자로 객체를 생성할 때 객체의 초기화 역할을 한다.
선언 형태는 메소드와 비슷하지만 리턴타입은 없고 이름은 클래스 이름과 동일하다.

메소드

객체가 수행할 동작이다. 객체와 객체간의 상호 작용을 위해 호출된다.

필드 선언과 사용

필드는 객체의 데이터를 저장하는 역할을 한다.

필드 선언

필드를 선언하는 방법은 변수를 선언하는 방법과 동일하다. 하지만 반드시 클래스 블록에서 선언되어야만 필드 선언이 된다.

public class Main() {
	타입 필드명 [ = 초기값 ];
}

필드와 로컬 변수의 차이점

구분필드로컬변수
선언 위치클래스 선언 블록생성자, 메소드 선언 블록
존재 위치객체 내부에 존재생성자, 메소드 호출 시에만 존재
사용 위치객체 내, 외부 어디든 사용생성자, 메소드 블록 내부에서만 사용

초기값을 제공하지 않을 경우 필드는 객체 생성 시 자동으로 기본값으로 초기화된다.

분류데이터 타입기본값
기본타입byte0
기본타입char\u0000(빈 공백)
기본타입short0
기본타입int0
기본타입long0L
기본타입float0.0F
기본타입double0.0
기본타입booleanfalse
참조 타입배열null
참조 타입클래스(String 포함)null
참조 타입인터페이스null

필드 사용

필드를 사용한다는 것은 필드값을 읽고 변경하는 것을 말한다.

필드는 객체의 데이터이므로 객체가 존재하지 않으면 필드도 존재하지 않는다.

도트(.) 는 객체 접근 연산자로 객체가 가지고 있는 필드나 메소드에 접근하고자 할 때 참조변수 뒤에 붙인다.

도트 연산자 사용

A a = new A();
a.member;
a.method();

생성자 선언과 호출

new의 역할
1. 객체 생성 후 변수에 번지 대입
2. 생성자 호출

기본 생성자

모든 클래스는 생성자가 존재하며, 하나 이상을 가질 수 있다.
클래스 생성자 선언이 없으면 컴파일러는 다음과 같은 기본 생성자를 바이트 코드 파일에 자동으로 추가시킨다.

public 클래스명() {}

생성자 선언

객체를 다양하게 초기화하기 위해 개발자는 생성자를 다음과 같이 직접 선언할 수 있다.

public class Car {
	Car(String model, String color, int maxSpeed) {}
}

public class Main() {
	public static void main(String[] args) {
    	Car myCar = new Car("그랜저", "검정", 300);
    }
}

필드 초기화

객체마다 동일한 값을 갖고 있다면 필드 선언 시 초기값을 대입하는 것이 좋고
객체마다 다른 값을 가져야 한다면 생성자에게 필드를 초기화하는 것이 좋다.

생성자 오버로딩

매개값으로 객체의 필드를 다양하게 초기화하려면 생성자 오버로딩이 필요하다.

생성자 오버로딩

  • 매개변수를 달리하는 생성자를 여러 개 선언하는 것을 말한다.
public class Car {
    Car() {}

    Car(String model) {
        this.model = model;
    }

    Car(String model, String color) {
        this.model = model;
        this.color = color;
    }

    Car(String model, String color, int maxSpeed) {
        this.model = model;
        this.color = color;
        this.maxSpeed = maxSpeed;
    }
}

다른 생성자 호출

생성자 오버로딩이 많아질 경우 생성자 간의 중복된 코드가 발생할 수 있다.

이 경우에는 공통 코드를 한 생성자에만 집중적으로 작성하고, 나머지 생성자는 this(...) 를 사용하여 공통 코드를 가지고 있는 생성자를 호출하는 방법으로 개선할 수 있다.

public class Car {
    Car() {}

    Car(String model) {
        this(model, "은색", 250);
    }

    Car(String model, String color) {
        this(model, color, 250);
    }

    Car(String model, String color, int maxSpeed) {
        this.model = model;
        this.color = color;
        this.maxSpeed = maxSpeed;
    }
}

메소드 선언과 호출

메소드 선언은 객체의 동작을 실행 블록으로 정의하는 것을 말하고, 메소드 호출은 실행 블록을 실제로 실행하는 것을 말한다.

메소드 선언

메소드 선언

리턴타입 메소드명 (매개변수, ...) {	//선언부
	//실행 블록
}

리턴 타입

리턴 타입은 메소드가 실행한 후 호출한 곳으로 전달하는 결과값의 타입을 말한다.

리턴값이 없는 메소드는 void로 작성한다.

void powerOn() { ... }
double divide(int x, int y) { ... }

메소드명

메소드명은 첫 문자를 소문자로 시작하고, 캐멀 스타일로 작성한다.

void run() { ... }
void setSpeed(int speed) { ... }
String getName() { ... }

매개변수

매개변수는 메소드를 호출할 때 전달한 매개값을 받기 위해 사용된다.
전달할 매개값이 없다면 매개변수는 생략할 수 있다.

double divide(int x, int y) { ... }

실행 블록

메소드 호출 시 실행되는 부분이다.

메소드 호출

메소드를 호출한다는 것은 메소드 블록을 실행하는 것을 말한다.
메소드는 객체의 동작이므로 객체가 존재하지 않으면 메소드를 호출 할 수 없다.

메소드가 리턴값이 있을 경우에는 대입 연산자를 사용해서 다음과 같이 리턴값을 변수에 저장할 수 있다.

가변길이 매개변수

메소드가 가변길이 매개변수를 가지고 있다면 매개변수의 개수와 상관없이 매개값을 줄 수 있다.

가변길이 매개변수 선언

public class Computer {
    int sum(int ... values) {
        int sum = 0;

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

        return sum;
    }
}

return 문

return 문은 메소드의 실행을 강제종료하고 호출한 곳으로 돌아가라는 의미이다.

return [리턴값];

Unreachable code

  • return 문 이후의 실행문은 결코 실행되지 않기 때문에 if문이 아닌 블록에서 return 문 이후에 실행문을 작성하면 Unreadable code 컴파일 에러가 발생한다.

메소드 오버로딩

메소드 오버로딩은 메소드 이름은 같되 매개변수의 타입, 개수, 순서가 다른 메소드를 여러개 선언하는 것을 말한다.

public class Calculator
{
    double areaRectangle(double width){
        return width * width;
    }
    double areaRectangle(double width, double height){
        return width * height;
    }
}

인스턴스 멤버

필드와 메소드는 선언 방법에 따라 인스턴스 멤버와 정적 멤버로 분류할 수 있다.
인스턴스 멤버로 선언되면 객체 생성 후 사용할 수 있고, 정적 멤버로 선언되면 객체 생성 없이도 사용할 수 있다.

구분설명
인스턴스 멤버객체에 소속된 멤버
정적 멤버클래스에 고정된 멤버

인스턴스 멤버 선언 및 사용

인스턴스 멤버란 객체에 소속된 멤버를 말한다.
따라서 객체가 있어야만 사용할 수 있는 멤버이다.

필드와 같은 경우는 객체마다 따로 생성이 되지만 메소드 같은 경우는 메모리 효율 문제로 인해 정적 멤버와 같이 메소드 영역에 단 하나만 정의되고, 객체 없이는 사용하지 못하도록 제한을 걸어둔다.

this 키워드

객체 내부에서는 인스턴스 멤버에 접근하기 위해 this를 사용할 수 있다.
생성자와 메소드의 매개변수명이 인스턴스 멤버인 필드명과 동일한 경우, 인스턴스 필드임을 강조하고자 할 때 this 를 주로 사용한다.

public class Car
{
    String model;
    int speed;

    Car(String model){
        this.model = model;
    }

    void setSpeed(int speed){
        this.speed = speed;
    }
    void run(){
        this.setSpeed(100); // this 생략 가능
        System.out.println(this.model+"가 달립니다.( 시속 :"+this.speed+" km/h)"); //this 생략 가능
    }
}

정적 멤버

자바는 클래스 로더를 이용해서 클래스를 메소드 영역에 저장하고 사용한다.
정적 멤버란 메소드 영역의 클래스에 고정적으로 위치하는 멤버들을 말한다.

그렇기 때문에 정적 멤버는 객체를 생성할 필요 없이 클래스를 통해 바로 사용이 가능하다.

정적 멤버 선언

필드와 메소드는 모두 정적 멤버가 될 수 있다.

정적 필드와 정적 메소드로 선언하려면 다음과 같이 static 키워드를 추가하면 된다.

public class 클래스명 {
	//정적 필드 선언
	static 타입 필드 [= 초기값];
    
    //정적 메소드
    static 리턴타입 메소드( 매개변수, ... ) { ... }
}

객체마다 가지고 있을 필요성이 없는 공용적인 필드는 정적 필드로 선언하는 것이 좋다.

또한 인스턴스 필드를 이용하지 않는 메소드는 정적 메소드로 선언하는 것이 좋다.

정적 멤버 사용

클래스가 메모리에 로딩되면 정적 맴버를 사용할 수 있는데, 클래스 이름과 함게 도트(.) 연산자로 접근할 수 있다.

public class Calculator {
	static double pi = 3.14159;
    static int plus(int x, int y) {... }
}
double result1 = 10 * 10 * Calculator.pi;
int result2 = Calculator.plus(10, 5);

정적 블록

정적 필드는 다음과 같이 필드 선언과 동시에 초기값을 주는 것이 일반적이다.

static double pi = 3.14159;

하지만 복잡한 초기화 작업이 필요하다면 정적 블록을 이용해야 한다.

정적 블록 이용

public class Television {
    static String company = "MyCompany";
    static String model = "LCD";
    static String info;

    static {
        info = company + " - "+model;
    }
}

생성자에서 초기화를 하지 않는 정적 필드

  • 정적 필드는 객체 생성 없이도 사용할 수 있기 때문에 생성자에서 초기화 작업을 하지 않는다. 생성자는 객체 생성 후 실행되기 때문이다.

인스턴스 멤버 사용 불가

정적 멤버는 객체가 없어도 실행된다는 특징 때문에 this 를 포함한 내부에 인스턴스 필드나 인스턴스 메소드를 사용할 수 없다.

정정 멤버에서 인스턴스 멤버를 사용하고 싶다면 객체를 만들어 사용해야 한다.

정적 멤버에서 인스턴스 멤버 사용

static void method() {
	ClassName obj = new ClassName();
    obj.filed1 = 10;
    obj.method();
}

final 필드와 상수

멤버 중에서는 경우에 따라서 값을 변경하는 것을 막아야 할 때가 있다. 이 때 final 필드와 상수를 선언해서 사용한다.

final 필드 선언

final 필드는 초기값이 저장되면 더 이상 값을 변경할 수 없게 된다.

final 필드 초기값 설정 방법
1. 필드 선언 시에 초기값 대입
2. 생성자에서 초기값 대입

final 필드는 초기화 하지 않고, 그대로 남겨두면 컴파일 에러가 발생한다.

상수 선언

상수는 객체마다 저장할 필요가 없고, 단 하나의 값을 가지기 때문에 static final 특성을 가진다.

상수는 static final 특성이기 때문에 생성자에서 초기값을 대입할 수 없고, 선언과 동시에 선언을 하거나 정적 블록을 사용해서 선언을 해야한다.

상수 선언

static final 타입 상수 [= 초기값];

패키지

자바의 패키지는 단순히 디렉토리만을 의미하지는 않는다.
패키지는 클래스의 일부분이며, 클래스를 식별하는 용도로 사용된다.

패키지는 주로 개발 회사의 도메인 이름의 역순으로 만든다.

  • 도메인 : mycompany.com
  • 패키지 : com.mycompany

패키지는 클래스를 식별하는 용도로 사용되기 때문에 클래스의 전체 이름이 포함된다.

패키지에 속한 바이트 코드 파일(~.class)은 따로 떼어내어 다른 디렉토리로 이동할 수 없다.

패키지 선언

패이지 디렉토리는 클래스를 컴파일하는 과정에서 자동으로 생성된다.

컴파일러는 클래스의 패키지 선언을 보고 디렉토리를 자동 생성시킨다.

패키지 이름 작성
1. 패키지 이름은 모두 소문자로 작성하는 것이 관례
2. 패키지 이름이 서로 중복되지 않도록 회사 도메인 이름의 역순으로 작성
3. 마지막에는 프로제긑 이름을 붙여주는 것이 일반적

com.samsung.projectname
com.lg.projectname
org.apache.projectname

import 문

다른 패키지에 있는 클래스를 사용하려면 import 문을 이용해서 어떤 패키지의 클래스를 사용하는지 명시해야 한다.

import 문 특징
1. import 문이 작성되는 위치는 패키지 선언과 클래스 선언 사이이다.
2. import 키워드 뒤에는 사용하고자 하는 클래스의 전체 이름을 기술한다.
3. 만약 동일한 패키지에 포함된 다수의 클래스를 사용해야 한다면 클래스 이름을 생략하고 *를 사용할 수 있다.

접근 제한자

경우에 따라서는 객체의 필드를 외부에서 변경하거나 메소드를 호출할 수 없도록 막아야 할 필요가 있다.

중요한 필드와 메소드가 외부로 노출되지 않도록 해 객체의 무결성을 유지하기 위해서이다.(캡슐화)

접근제한자 종류는 다음과 같다.

접근 제한자제한 대상제한 범위
public클래스, 필드, 생성자, 메소드없음
protected필드, 생성자, 메소드같은 패키지이거나, 자식 객체만 사용 가능
default클래스, 필드, 생성자, 메소드같은 패키지
private필드, 생성자, 메소드객체 내부

클래스의 접근 제한

클래스는 public, default 접근 제한을 가질 수 있다.

[ public ] class 클래스 { ... }

생성자의 접근 제한

생성자는 public, default, private 접근 제한을 가질 수 있다.

public class ClassName {
	[ public | pricate ] ClassName(...) { ... }
}
접근 제한자생성자설명
public클래스(...)모든 패키지에서 생성자 호출 가능
클래스(...)같은 패키지 내에서만 생성자 호출 가능
private클래스(...)클래스 내부에서만 생성자 호출 가능

필드와 메소드의 접근 제한

필드와 메소드는 public, default, private 접근 제한을 가질 수 있다.

// 필드 선언
[ public | private ] 타입 필드;

//메소드 선언
[ public | private ] 리턴타입 메소드(...) { ... }

Getter 와 Setter

객체 지향 프로그래밍에서는 객체의 캡슐화를 위해 직접적인 외부에서의 필드 접근을 막고 메소드를통해 필드에 접근하는 것을 선호한다.

객체는 필드의 접근 제한을 pricate 으로 설정한 후, 필드에 접근하고 필드의 값을 설정하기 위해 , GetterSetter 메소드를 사용한다.

private 타입 fieldName;

//Getter
public 타입 getFieldName() {
	return fieldName;
}

//Setter
public void setFieldName(타입 fieldValue) {
	this.fieldName = fieldValue;
}

싱글톤 패턴

애플리케이션 전체에서 단 한 개의 객체만 생성해서 사용하고 싶다면 싱글톤 패턴을 적용할 수 있다.

싱글톤 패턴의 핵심은 생성자를 private 접근 제한해서 외부에서 new 연산자로 생성자를 호출할 수 없도록 막는 것이다.

싱글톤 코드 예시

public class Singleton {
    private static Singleton singleton = new Singleton();	// 1

    private Singleton() {}

    static Singleton getInstance() {	//2
        return singleton;
    }
}
  • 1 에서는 자신의 타입으로 정적 필드를 선언하고 미리 객체를 생성해서 초기화시킨다. 그리고 private 접근 제한자를 붙여 외부에서 정적 필드값을 변경하지 못하도록 막는다.
  • 2 에서는 정적 필드값을 리턴하는 getInstance() 정적 메소드를 public 으로 선언하였다.

문제

  1. 객체와 클래스에 대한 설명으로 틀린 것은 무엇입니까?
    ➊ 클래스는 객체를 생성하기 위한 설계도(청사진)와 같은 것이다.
    ➋ new 연산자로 클래스의 생성자를 호출함으로써 객체가 생성된다.
    ➌ 하나의 클래스로 하나의 객체만 생성할 수 있다.
    ➍ 객체는 클래스의 인스턴스이다
  • 답 : ➌
  1. 클래스의 구성 멤버가 아닌 것은 무엇입니까?
    ➊ 필드(field)
    ➋ 생성자(constructor)
    ➌ 메소드(method)
    ➍ 로컬 변수(local variable)
  • 답 : ➍
  1. 필드, 생성자, 메소드에 대한 설명으로 틀린 것은 무엇입니까?
    ➊ 필드는 객체의 데이터를 저장한다.
    ➋ 생성자는 객체의 초기화를 담당한다.
    ➌ 메소드는 객체의 동작 부분으로, 실행 코드를 가지고 있는 블록이다.
    ➍ 클래스는 반드시 필드와 메소드를 가져야 한다
  • 답 :➍
  1. 필드에 대한 설명으로 틀린 것은 무엇입니까?
    ➊ 필드는 메소드에서 사용할 수 있다.
    ➋ 인스턴스 필드 초기화는 생성자에서 할 수 있다.
    ➌ 필드는 반드시 생성자 선언 전에 선언되어야 한다.
    ➍ 필드는 초기값을 주지 않더라도 기본값으로 자동 초기화된다.
  • 답 : ➌
  1. 생성자에 대한 설명으로 틀린 것은 무엇입니까?
    ➊ 객체를 생성하려면 생성자 호출이 반드시 필요한 것은 아니다.
    ➋ 생성자는 다른 생성자를 호출하기 위해 this()를 사용할 수 있다.
    ➌ 생성자가 선언되지 않으면 컴파일러가 기본 생성자를 추가한다.
    ➍ 외부에서 객체를 생성할 수 없도록 생성자에 private 접근 제한자를 붙일 수 있다.
  • 답 : ➊
  1. 메소드에 대한 설명으로 틀린 것은 무엇입니까?
    ➊ 리턴값이 없는 메소드는 리턴 타입을 void로 해야 한다.
    ➋ 리턴 타입이 있는 메소드는 리턴값을 지정하기 위해 반드시 return 문이 있어야 한다.
    ➌ 매개값의 수를 모를 경우 “…”를 이용해서 매개변수를 선언할 수 있다.
    ➍ 메소드의 이름은 중복해서 선언할 수 없다.
  • 답 : ➍
  1. 메소드 오버로딩에 대한 설명으로 틀린 것은 무엇입니까?
    ➊ 동일한 이름의 메소드를 여러 개 선언하는 것을 말한다.
    ➋ 반드시 리턴 타입이 달라야 한다.
    ➌ 매개변수의 타입, 수, 순서를 다르게 선언해야 한다.
    ➍ 매개값의 타입 및 수에 따라 호출될 메소드가 선택된다.
  • 답 : ➋
  1. 인스턴스 멤버와 정적 멤버에 대한 설명으로 틀린 것은 무엇입니까?
    ➊ 정적 멤버는 static으로 선언된 필드와 메소드를 말한다.
    ➋ 인스턴스 필드는 생성자 및 정적 블록에서 초기화될 수 있다.
    ➌ 정적 필드와 정적 메소드는 객체 생성 없이 클래스를 통해 접근할 수 있다.
    ➍ 인스턴스 필드와 메소드는 객체를 생성하고 사용해야 한다.
  • 답 : ➋
  1. final 필드와 상수(static final)에 대한 설명으로 틀린 것은 무엇입니까?
    ➊ final 필드와 상수는 초기값이 저장되면 값을 변경할 수 없다.
    ➋ final 필드와 상수는 생성자에서 초기화될 수 있다.
    ➌ 상수의 이름은 대문자로 작성하는 것이 관례이다.
    ➍ 상수는 객체 생성 없이 클래스를 통해 사용할 수 있다.
  • 답 : ➋
  1. 패키지에 대한 설명으로 틀린 것은 무엇입니까?
    ➊ 패키지는 클래스들을 그룹화시키는 기능을 한다.
    ➋ 클래스가 패키지에 소속되려면 패키지 선언을 반드시 해야 한다.
    ➌ import 문은 다른 패키지의 클래스를 사용할 때 필요하다.
    ➍ com.mycom 패키지에 소속된 클래스는 com.yourcom에 옮겨 놓아도 동작한다.
  • 답 : ➍
  1. 접근 제한에 대한 설명으로 틀린 것은 무엇입니까?
    ➊ 접근 제한자는 클래스, 필드, 생성자, 메소드의 사용을 제한한다.
    ➋ public 접근 제한은 아무런 제한 없이 해당 요소를 사용할 수 있게 한다.
    ➌ default 접근 제한은 해당 클래스 내부에서만 사용을 허가한다.
    ➍ 외부에서 접근하지 못하도록 하려면 private 접근 제한을 해야 한다.
  • 답 : ➌
  1. 다음 클래스에서 해당 멤버가 필드, 생성자, 메소드 중 어떤 것인지 ( ) 안에 적어보세요.
public class Member {
	private String name; -------------------->( )
	public Member(String name) {} -------->( )
 	public void setName(String name) {}--->( )
}
  • 답 : 필드, 생성자, 메소드
  1. 현실 세계의 회원을 Member 클래스로 모델링하려고 합니다. 회원의 데이터로는 이름, 아이디,
    패스워드, 나이가 있습니다. 이 데이터들을 가지는 Member 클래스를 선언해보세요.
데이터 이름필드 이름타입
이름name문자열
아이디id문자열
패드워드password문자열
나이age정수
  • 답 :
public class Member {
	String name;
	String id;
	String password;
	int age;
}
  1. 13번 문제에서 작성한 Member 클래스에 생성자를 추가하려고 합니다. 다음과 같이 name 필
    드와 id 필드를 외부에서 받은 값으로 초기화하도록 생성자를 선언해보세요.
Member user1 = new Member("홍길동", "hong");
  • 답 :
public class Member {
	String name;
	String id;
	String password;
	int age;
	Member(String name, String id) {
 		this.name = name;
 		this.id = id;
	}
}
  1. login() 메소드를 호출할 때에는 매개값으로 id와 password를 제공하고, logout() 메소드
    는 id만 매개값으로 제공하려고 합니다. 다음 조건과 예제 코드를 보고 MemberService 클래스에
    서 login(), logout() 메소드를 선언해보세요.
    ➊ login() 메소드는 매개값 id가 "hong", 매개값 password가 "12345" 일 경우에만 true로 리턴
    ➋ logout() 메소드는 id + "님이 로그아웃 되었습니다"가 출력되도록 할 것
리턴 타입메소드 이름매개변수(타입)
booleanloginid(String),password(String)
voidlogoutid(String)
MemberService memberService = new MemberService();
boolean result = memberService.login("hong", "12345");
if(result) {
	System.out.println("로그인 되었습니다.");
	memberService.logout("hong");
} else {
	System.out.println("id 또는 password가 올바르지 않습니다.");
}
  • 답 :
public class MemberService {
	boolean login(String id, String password) {
 		if(id.equals("hong") && password.equals("12345")) {
 			return true;
 		} else {
 			return false;
 		}
	}
	void logout(String id) {
 		System.out.println("로그아웃 되었습니다.");
	}
}
  1. println() 메소드는 매개값을 콘솔에 출력합니다. println() 메소드의 매개값으로는 int,
    boolean, double, String 타입 값을 줄 수 있습니다. 다음 조건과 예제 코드를 보고 Printer 클래
    스에서 println() 메소드를 오버로딩하여 선언해보세요.
리턴 타입메소드 이름매개변수(타입)
voidlogoutvalue(int, boolean, double, String)
Printer printer = new Printer();
printer.println(10);
printer.println(true);
printer.println(5.7);
printer.println("홍길동");
  • 답 :
public class Printer {
	public void println(int value) {
 		System.out.println(value);
	}
	public void println(boolean value) {
 		System.out.println(value);
	}
	public void println(double value) {
 		System.out.println(value);
	}
	public void println(String value) {
 		System.out.println(value);
	}
}
  1. 16번 문제에서는 Printer 객체를 생성하고 println() 메소드를 호출했습니다. 이번에는 Printer
    객체를 생성하지 않고도 다음과 같이 호출할 수 있도록 Printer 클래스를 수정해보세요.
Printer.println(10);
Printer.println(true);
Printer.println(5.7);
Printer.println("홍길동");
  • 답 :
public class Printer {
	public static void println(int value) {
 		System.out.println(value);
	}
 	public static void println(boolean value) {
 		System.out.println(value);
	}
	public static void println(double value) {
 		System.out.println(value);
	}
	public static void println(String value) {
 		System.out.println(value);
	}
}
  1. 다음 예제 코드가 실행되면 “같은 ShopService 객체입니다.”라는 메시지가 출력되도록, 싱글
    톤 패턴을 사용해서 ShopService 클래스를 작성해보세요.
ShopService obj1 = ShopService.getInstance();
ShopService obj2 = ShopService.getInstance();
if(obj1 == obj2) {
	System.out.println("같은 ShopService 객체입니다.");
} else {
	System.out.println("다른 ShopService 객체입니다.");
}
  • 답 :
public class ShopService {
	private static ShopService singleton = new ShopService();
	private ShopService() {}
	static ShopService getInstance() {
 		return singleton;
	}
}
  1. 은행 계좌 객체인 Account 객체는 잔고(balance) 필드를 가지고 있습니다. balance 필드는
    음수값이 될 수 없고, 최대 백만 원까지만 저장할 수 있습니다. 외부에서 balance 필드를 마음대로
    변경하지 못하도록 하고, 0 <= balance <= 1,000,000 범위의 값만 가질 수 있도록 Account 클래
    스를 작성해보세요.
    ➊ Setter와 Getter를 이용
    ➋ 0과 1,000,000은 MIN_BALANCE와 MAX_BALANCE 상수를 선언해서 이용
    ➌ Setter의 매개값이 음수이거나 백만 원을 초과하면 현재 balance 값을 유지
Account account = new Account();

account.setBalance(10000);
System.out.println("현재 잔고: " + account.getBalance()); //현재 잔고: 10000

account.setBalance(-100);
System.out.println("현재 잔고: " + account.getBalance()); //현재 잔고: 10000account.setBalance(2000000);

System.out.println("현재 잔고: " + account.getBalance()); //현재 잔고: 10000

account.setBalance(300000);
System.out.println("현재 잔고: " + account.getBalance()); //현재 잔고: 300000
  • 답 :
public class Account {
	public static final int MIN_BALANCE = 0;
	public static final int MAX_BALANCE = 1000000;
	private int balance;
	public int getBalance() {
 		return balance;
	}
	public void setBalance(int balance) {
 		if((balance < Account.MIN_BALANCE) || (balance > Account.MAX_BALANCE)) {
 			return;
		}
 		this.balance = balance;
	}
}
  1. 다음은 키보드로부터 계좌 정보를 입력받아 계좌를 관리하는 프로그램입니다. 계좌는 Account
    객체로 생성되고 BankApplication에서 길이 100인 Account[ ] 배열로 관리됩니다. 실행 결과를
    보고, Account와 BankApplication 클래스를 작성해보세요(키보드로 입력받을 때는 Scanner
    의 nextLine() 메소드를 사용).
  • 답 :
// Account.java
public class Account {
	private String account;
	private String name;
	private int balance;
	public Account(String account, String name, int balance) {
 		this.account = account;
 		this.name = name;
 		this.balance = balance;
	}
	public String getAccount() { 
    	return this.account; 
    }
	public void setAno(String account) { 
    	this.account = account; 
    }
	public String getName() { 
    	return this.name; 
    }
	public void setName(String name) { 
    	this.name = name; 
    }
	public int getBalance() { 
    	return this.balance; 
    }
	public void setBalance(int balance) { 
    	this.balance = balance; 
    }
}
//BankApplication.java
import java.util.Scanner;
	public class BankApplication {
	private static Account[] accountArray = new Account[100];
	private static Scanner scanner = new Scanner(System.in);
	public static void main(String[] args) {
 		boolean run = true; 
 		while(run) {
 			System.out.println("----------------------------------------------------------");
 			System.out.println("1.계좌생성 | 2.계좌목록 | 3.예금 | 4.출금 | 5.종료");
 			System.out.println("----------------------------------------------------------");
 			System.out.print("선택> ");

 			int selectNo = scanner.nextInt();
 			if(selectNo == 1) {
 				createAccount();
 			} else if(selectNo == 2) {
 				accountList();
 			} else if(selectNo == 3) {
 				deposit();
 			} else if(selectNo == 4) {
 				withdraw();
 			} else if(selectNo == 5) {
 				run = false;
 			}
 		}
 		System.out.println("프로그램 종료");
	}

	private static void createAccount() {
 		System.out.println("--------------");
 		System.out.println("계좌생성");
 		System.out.println("--------------");

 		System.out.print("계좌번호: ");
 		String account = scanner.next();

 		System.out.print("계좌주: ");
 		String name = scanner.next();

 		System.out.print("초기입금액: ");
 		int balance = scanner.nextInt();

 		Account newAccount = new Account(account, name, balance);
 		for(int i=0; i<accountArray.length; i++) {
 			if(accountArray[i] = = null) {
 				accountArray[i] = newAccount;
 				System.out.println("결과: 계좌가 생성되었습니다.");
 				break;
 			}
 		}
	}

	private static void accountList() {
 		System.out.println("--------------");
 		System.out.println("계좌목록");
 		System.out.println("--------------");
 		for(int i=0; i<accountArray.length; i++) {
 			Account account = accountArray[i];
 			if(account != null) {
 				System.out.print(account.getAcount());
 				System.out.print(" ");
 				System.out.print(account.getName());
 				System.out.print(" ");
 				System.out.print(account.getBalance());
 				System.out.println();
 			}
 		}
	}

	private static void deposit() {
 		System.out.println("--------------");
 		System.out.println("예금");
 		System.out.println("--------------");
 		System.out.print("계좌번호: ");
 		String act = scanner.next();
 		System.out.print("예금액: ");
 		int money = scanner.nextInt();
 		Account account = findAccount(act);
 		if(account == null) {
 			System.out.println("결과: 계좌가 없습니다.");
 			return;
 		}
 		account.setBalance(account.getBalance() + money);
 		System.out.println("결과: 예금이 성공되었습니다.");
	}

	private static void withdraw() {
 		System.out.println("--------------");
 		System.out.println("출금");
 		System.out.println("--------------");
 		System.out.print("계좌번호: ");
 		String act = scanner.next();
 		System.out.print("출금액: ");
 		int money = scanner.nextInt();
 		Account account = findAccount(act);
 		if(account == null) {
 			System.out.println("결과: 계좌가 없습니다.");
 			return;
 		}
 		account.setBalance(account.getBalance() - money);
 		System.out.println("결과: 출금이 성공되었습니다.");
	}

	private static Account findAccount(String act) {
 		Account account = null;
 		for(int i=0; i<accountArray.length; i++) {
 			if(accountArray[i] != null) {
 				String dbAno = accountArray[i].getAccount();
 				if(dbAno.equals(act)) {
 					account = accountArray[i];
 					break;
 				}
 			}
 		}
 		return account;
	}
}
profile
사는게 쉽지가 않네요

0개의 댓글