객체(Object)

일반적으로 사물은 속성과 기능을 갖는다. 속성은 정적인 정보를, 기능은 동적으로 수행할 수 있는 역할, 움직임을 가르킨다.

연관성이 있는 사물은 분류할 수 있다. 공통적으로 가지고 있는 특성을 묶고 그 관계를 코드로 구현하는 것이 자바 객체지향이라고 본다. 사물이 가진 어떤 속성이나 기능이 프로그래밍에서 속성은 맴버 변수, 기능은 메서드(함수)로 대응할 수 있다.

사물을 생산하기 위해 설계하는 것이 클래스, 생산이 된 결과를 인스턴스로 볼 수 있다.(사전이나 서적에 따라 인스턴스 자체를 객체로 보기도 한다.)

 

 

클래스

은행의 계좌에서 일어나는 여러가지 속성과 기능을 나누어 구현해보자.

public class BankAccount {
	//맴버 변수
	int bankCode;
    int accountNo;
    String owner;
    int balance;
    boolean isDormant;
    int passward;
    
    //메서드
    void inquiry() {}
    void deposit() {}
    void withdraw() {}
    void heldInDormant() {}
}

맴버 변수와 메서드를 작성한다.

클래스를 작성할 때, 현실세계의 사물을 어떤 식으로 일반화 시킬지, 공통적인 속성이 무엇인지 파악하는 것이 중요하다.

실제 프로그램을 구현할 때에도 전체적인 업무를 하나하나 개별적으로 구현하는 것이 아니라 공통적인 속성과 기능을 분리한 후, 클래스로 나타내는 것이 좋다.

 

 

생성자

생성자는 클래스 내부에 정의되어야 하며, 생성자 메서드명은 클래스명과 일치해야한다.

BankAccount(
		int bankCode,
        int accountNo,
        String owner,
        int balance,
        int passward,
        boolean isDormant
) {
	this.bankCode = bankCode;
    this.accountNo = accountNo;
    this.owner = owner;
    this.balance = balance;
    this.passward = passward;
    this.isDormant = isDormant;
}

전체적인 코드를 구성하는 클래스명이 BankAccount이기 때문에 생성자 또한 BankAccount로 한다. 생성자는 new 연산자와 함께 사용해야한다. 클래스 내부에 생성자가 없는 경우, 자바에서 생성자 내부에 값이 없는 빈생성자를 자동으로 추가한다. 사용자가 어떤 파라미터를 받는 생성자 함수를 만들어주면 더이상 생성자를 자동으로 만들어주지 않는다.

생성에 필요한 정보들은 생성자 함수 옆 괄호 안에 넣어주어야한다.

중괄호는 데이터를 할당해서 실제적으로 의미있는 값을 가지는 인스턴스를 만드는 과정이다. this는 인스턴스 자기자신을 가르키는 특수한 변수이다. this 뒤에는 클래스에 정의된 맴버 변수가 온다. 맴버 변수를 통해 인스턴스 자기자신에 입력받은 값, 인자로써 입력받은 값을 전달받게 된다. 즉, 왼쪽의 bankCode는 클래스에 정의된 맴버 변수의 의미를 가지며, 오른쪽의 bankCode는 사용자로부터 혹은 프로그램으로부터 입력받은 값을 의미한다.

 

생성자를 사용해서 만드는 것은 다른 곳에서 진행하는 것이 일반적이다. 지금까지 만든 것이 설계도라면 실제로 사용하는 것들은 로직이 구현된 파일에서 진행된다.

public static void main(String[] args) {

    BankAccount bankAccount = new BankAccount();
    System.out.println(account);
    System.out.println(account.bankCode); // 0
    System.out.println(account.isDormant);  // false
}

main 함수에서 실행할 수 있는 상태로 만들어준 뒤, BankAccount라고 입력하면 우리가 기존에 만들었던 클래스를 불러오게 된다.

위에서 만들었던 생성자 중, 기본 빈생성자를 불러오면 인스턴스의 맴버 변수를 출력했을 때 데이터가 아무것도 할당되어 있지 않기 때문에 객체는 존재하지만 기본값이 출력된다.

 

 

상속

객체지향에서는 상속이라는 개념이 존재한다.

상속을 받는 클래스를 자식 클래스라고 하고 상속의 대상이 되는 클래스를 부모 클래스라고 한다.

객체지향은 재사용과 범주화가 핵심이다. 공통 속성에 수정사항이 생기면 코드 하나하나를 수정하는 것은 비효율적이다.

public class SavingsAccount extends BankAccount {
	boolean isOverdraft;
    void transfer() {};
}

부모 클래스 BankAccount를 재활용하기 위해 자식 클래스인 extends 키워드를 사용한다. 이렇게하면 SavingsAccount 클래스는 부모 클래스인 BankAccount가 가진 모든 것들을 가지고 시작한다. 그리고 맴버 변수를 정의하여 추가하면 된다.

public class DollarAccount extends BankAccount {

    void transfer() {}
}
public class SubscriptionAccount extends BankAccount {

    int numOfSubscription;
}

위처럼 부모 클래스를 상속받아 재활용할 수 있다.

상속을 할 때에는 하나의 클래스만 상속받을 수 있다. 이것을 단일상속이라고 한다. 자바 언어는 단일상속 언어이며, 다른 언어에서는 다중상속을 하는 경우도 있다. 다중상속에는 장단점이 있는데 어떤 부모클래스에서 온 속성인지 파악하기 어렵기 때문에 모호성을 제거하기 위해 자바에서는 단일상속을 지원한다.

 

오버로딩과 오버라이딩

오버로딩과 오버라이딩은 부모 자식관계의 클래스들을 효과적으로 정의하고 활용하기 위해 나온 개념이다.

오버로딩은 부모 클래스에서 상속받은 메서드에서 파라미터를 변경하는 것이다. 이것을 통해 새로운 메서드를 정의한다.

inquiry는 부모 클래스에서는 계좌를 조회하는 메서드이다. 다른 파라미터를 넘겨받고 싶거나 다른 형태의 인자를 넘겨받고 싶다면 인자를 추가할 수 있다.

오버라이딩은 덮어쓰기라는 뜻이다. 부모 클래스에서 상속받은 메서드의 내용을 자식 클래스의 상황에 맞게 변경한다.

오버로딩은 파라미터가 바뀌는 것이고 오버라이딩은 중괄호, 메서드의 코드블락이 변경되는 것이다.

public class DollarAccount extends BankAccount {

    void inquiry(double currencyRate) {}

    void deposit() {

    }
}

위 코드는 double로 달러 환율을 추가해서 함수를 재정의 했다. 잔액을 조회했을 때, 환율을 계산해서 미화로 결과를 확인할 수 있는 오버로딩된 메서드이다.

deposit의 경우, 원화와 달러 입금방식이 다르기 때문에 부모 클래스 BankAccount에 정의된 내용을 쓰지 않고 DollarAccount만의 고유한 입금방식을 취하기 위해 재정의 한다. 오버라이딩이 된 메서드는 부모 클래스의 파라미터 설정을 그대로 따른다.

즉, 파라미터 설정은 오버로딩을 통해 만들고 오버라이딩 된 것은 파라미터는 그대로고 중괄호 안의 내용을 바꿔주는 것이다.

 

 

접근제어자

클래스, 멤버 변수, 메서드, 생성자 등의 접근을 제어한다. 그 중 가장 많이 쓰이는 멤버 변수의 접근제어자에 대해 알아보자.

접근제어자는 일반적으로 타입 앞에 나타내게 되는데 타입 앞에 접근제어자가 없이 선언이 된 경우, 아무나 이 클래스에서 생성된 인스턴스의 코드를 임의로 변경할 수 있다. 즉, 객체 멤버 변수를 무분별하게 접근하고 수정할 수 있다. 보안과 안정성에 큰 문제를 야기할 수 있다.

public static void main(String[] args) {

    BankAccount bankAccount = new BankAccount();
    bankAccount.password = 123456;
    System.out.println(bankAccount.password());

}

bankAccount의 password를 임의로 지정한 뒤, 출력하면 그대로 덮어씌워져서 출력된다. 비밀번호를 임의로 바꾸는 것도 문제지만 비밀번호를 바꾸는 일정한 규칙이 있다면 그 규칙에 맞지 않는 데이터가 들어갈 수 있다. 그렇기 때문에 하나의 클래스에 정의된 멤버 변수, 그리고 인스턴스에 저장된 속성을 각각 역할에 맞는 함수를 만들어서 변경시켜야한다. 이렇게 마음대로 활용할 수 없도록 하는 것이 접근제어자이다.

 

public class BankAccount {

    // 멤버변수
    private int bankCode;
    private int accountNo;
    private String owner;
    private int balance;
    private boolean isDormant;
    private int password;
    
    // 메서드
    public void inquiry() {}
    public void deposit() {}
    public void withdraw() {}
    public void heldInDormant() {}
    public void changePassword(int password) {
        this.password = password;
    }
 }

 

접근제어자 private은 동일한 클래스에서만 수정과 참조가 가능하다. this를 통해 비밀번호를 대입해준다. 메서드는 접근제어자 public을 통해 외부에서 활용 가능한 형태로 만들어준다.

private은 값을 수정하는 것 뿐만 아니라 조회도 불가능하게 만든다. 그렇기 때문에 멤버 변수의 값을 조회하고 수정하기 위해 GetterSetter를 활용한다.

우클릭을 하여 Generate를 누르면 Getter와 Setter를 지정할 수 있다.

이렇게 하면 기존의 함수에 get과 set이 붙은 형태로 만들어진다.

public int getBankCode() {
        return bankCode;
}

public void setBankCode(int bankCode) {
    this.bankCode = bankCode;
}

public int getAccountNo() {
    return accountNo;
}

public void setAccountNo(int accountNo) {
    this.accountNo = accountNo;
}

public String getOwner() {
    return owner;
}

public void setOwner(String owner) {
    this.owner = owner;
}

public int getBalance() {
    return balance;
}

public void setBalance(int balance) {
    this.balance = balance;
}

public boolean isDormant() {
    return isDormant;
}

public void setDormant(boolean dormant) {
    isDormant = dormant;
}

public int getPassword() {
    return password;
}

public void setPassword(int password) {
	this.password = password;
}

getter와 setter가 만들어졌기 때문에 passward를 .으로 직접 조회하는 것이 아니라

public static void main(String[] args) {

    BankAccount bankAccount = new BankAccount();
    bankAccount.changePassword(123456);
    System.out.println(bankAccount.getPassword());

}

getPassward를 통해 바뀐 비밀번호를 조회한다.

 

 

인터페이스

클래스와 인터페이스는 다르다. 클래스가 상세한 설계도라면 인터페이스는 스케치 수준의 설계도이다. 파라미터, 반환, 타입만 가질 수 있으며 실제 코드를 구현할 수 있는 중괄호로 어떤 작업이 실행되는지는 정의할 수 없다.

인터페이스는 기능의 표준화를 달성하기 위한 도구이다. 공통적인 기능을 일정한 단위와 범주로 묶어 처리하고 그것을 구현할 클래스에서 각 업무 로직에 맞게 구현할 수 있도록 한 것이다. 그렇기 때문에 클래스에 신규 기능이 생기거나 삭제되는 기능이 생긴다면 인터페이스를 통해 효율적인 작업을 할 수 있다.

우클릭을 하면 New - Java Class에서 인터페이스를 생성할 수 있다.

public interface Withdrawable {
    void withdraw();
}

 

public class SavingsAccount extends BankAccount implements Withdrawable {

    boolean isOverdraft;

    void transfer() {};
    public void withdraw() {
    	System.out.println("Withdraw");
    };
}

추가한 인터페이스를 가져다 활용하려면 클래스 옆에 implements라는 키워드와 인터페이스명을 입력한다. 인터페이스를 명시하면 구현한 인터페이스의 함수를 반드시 클래스에서 구현해야한다. 인터페이스에서 함수를 가져와 재정의 할 때에는 접근제어자 public을 붙여주어야한다.

 

 

'Back-End > Java' 카테고리의 다른 글

Web - 클라이언트와 서버  (0) 2023.05.22
예외 - 예외 처리  (0) 2023.05.19
회원가입 프로그램 실습 - 자바(Java) 편  (1) 2023.05.16
함수  (0) 2023.05.15
자료구조 - 배열, 리스트, 맵  (0) 2023.05.12

오늘의 단어

controversial / dispite / in spite of / including / excluding

 

 

controversial

논란이 많은

 

예문

As controversial as it is popular, from the beginning drill has been accused of encouraging violence among its youthful audience.

논란이 많은만큼의 인기가, 드릴은 초기부터 젊은 청중 사이에 폭력을 조장한다고 비난 받았다.

 

He wrote a very controversial book.

그는 매우 논란이 많은 책을 썼다.

 

 

dispite

(= in spite of)

1. ...에도 불구하고

2. 자기도 모르게, 엉겁결에

 

예문

Despite these measuresthe economy remains in the doldrums.

이러한 조치에도 불구하고, 경제는 여전히 정체되어 있다.

 

He had to laugh despite himself.

그는 자기도 모르게 웃고 말았다.

 

 

in spite of

(= dispite)

1. ...에도 불구하고

 

예문

They duly arrived at 9.30 in spite of torrential rain.

그들은 양동이로 들이붓듯이 오는 비에도 불구하고 때를 맞춰 도착했다.

 

They fell in love in spite of the language barrier.

그들은 언어의 장벽에도 불구하고 사랑에 빠졌다.

 

 

including

(<-> excluding)

...을 포함하여

 

예문

I’ve got three days’ holiday including New Year’s Day.

나는 새해를 포함하여 3일 휴가이다.

 

Six people were killed in the riotincluding a policeman.

그 폭동에 경찰을 포함하여 6명이 사망했다.

 

 

excluding

(<-> including)

...을 제외하고

 

예문

Excluding emergencies and illnesses we ask employees to abide by the following conditions.

응급상황이나 아픈 경우를 제외하고 직원분들은 이 규정을 지켜주시길 바랍니다.

 

Travel expenses were about five hundred dollarsexcluding meals.

여행경비는 식비를 제외하고 500달러 정도 들었다.

 

 

오늘의 단어

frank / candid / indisputable / undeniable / disputable

 

 

frank

솔직한, 노골적인

 

예문

What is needed is a frank exchange of views.

필요한 것은 솔직한 견해를 교환하는 것이다.

 

To be frank with youI hardly ever study math.

솔직하게 말하자면, 나는 수학을 거의 공부하지 않는다.

 

 

candid

1. 솔직한

2. 자연스러운 모습 그대로

 

예문

Some were against the genre's candid depiction of violence, but this was the real world these rappers lived, and thus rapped about, a world borne of conditions that racism helped to create.

어떤 이들은 폭력에 대한 솔직한 묘사를 한 이 장르에 반대했지만, 이것은 래퍼들의 실제 삶이며 인종차별을 조장하는 상태의 세계를 랩으로 전했다.

 

I take it that you have been quite candid with me.

나는 당신이 나에게 꽤 솔직했다고 믿는다.

 

He shoots at different angles and takes candid pictures of people.

그는 다른 각도에서 찍으며 사람들의 자연스러운 모습을 사진으로 담는다.

 

 

indisputable

(= undeniable)

(<-> disputable)

반론의 여지가 없는

 

예문

But drill's impact is indisputable, placing it among the most important cultural phenomena in a generation.

하지만 드릴의 영향이 한 세대의 문화현상을 차지하고 있다는 것은 반론의 여지가 없다.

 

It is indisputable that the crime rate has been rising.

범죄율이 증가하고 있다는 것은 반론의 여지가 없다.

 

 

undeniable

(= indisputable)

부인할 수 없는, 명백한

 

예문

He had undeniable charm.

그는 부인할 수 없는 매력을 가지고 있다.

 

The fact that everyone will die eventually is undeniable.

모두가 결국 죽는다는 것은 명백한 사실이다.

 

 

indisputable

(<-> disputable)

반론[논란]의 여지가 있는

 

예문

It’ s claimed that they produce the best athletes in the world but I think that’s disputable.

세계에서 가장 뛰어난 운동선수를 배출해왔다는 그들의 주장은 반론의 여지가 있다고 본다.

 

The existence of Godis probably the most disputable topic throughout the history of time.

신의 존재는 아마 역사상 가장 논란의 여지가 있는 주제이다.

 

 

지금까지 공부한 내용을 바탕으로 회원가입 프로그램을 만들어보자.

import java.util.Scanner;

public class UserRegister {

    public static void main(String[] args) {

        System.out.println("======================");
        System.out.println("회원등록");
        System.out.println("======================");

        boolean register = false;
        Scanner sc = new Scanner(System.in);

        while (!register) {

            System.out.println("회원가입을 하시겠습니까?\ny: 진행    n:취소");
            System.out.print(">> ");
            String register_input = sc.nextLine();

            if (register_input.equalsIgnoreCase("y")) {
                register = true;
                System.out.println("======================");
                System.out.println("회원가입이 진행됩니다.");
                System.out.println("======================");
            } else if (register_input.equalsIgnoreCase("n")) {
                System.out.println("======================");
                System.out.println("회원가입이 종료됩니다.");
                System.out.println("======================");
                System.exit(0);
            } else {
                System.out.println("입력 값을 확인해주세요.");
            }
        }

다른 것과 혼동할 수 있기 때문에 구분할 수 있도록 꾸민다. 사용자에게 입력 받기 위해 Scanner를 자바 라이브러리에서 불러온다.(ctrl + space를 눌러 java.util 스캐너 객체를 불러온다.) in 인자를 통해 외부의 입력을 받도록 한다.

사용자로 하여금 올바르지 않은 값을 입력했거나 값을 다시 입력해야할 때, 프롬프트(입력창)를 띄우는 반복작업을 위해 반목문을 작성한다. println은 무조건 문자를 출력하고 개행한다. 개행하지 않고 사용자가 입력하는 커서가 되기 위해 print 함수를 쓴다. nextLine 함수는 문자열을 입력 받았을 때, 사용자의 입력을 대기하고 값을 입력한 뒤 엔터를 치면 변수에 값이 할당되며 다음 로직으로 이어진다.

if 문을 통해 문자를 입력 받았을 때, while 문의 불리언 값을 true로 만들어 반복문을 빠져나오도록 한다. y를 입력 받았을 때는 다음 로직이 실행되고, n을 입력 받았을 때는 프로그램이 종료되도록 한다. 만약 y와 n이 아닌 다른 문자를 입력 받았을 경우, 다시 처음으로 돌아가도록 한다.

 

ArrayList users = new ArrayList();

while (true) {

    HashMap user = new HashMap();

    // ID
    System.out.print("ID: ");
    String username = sc.nextLine();

	// PW
	String password = "";
	while (true) {
		System.out.print("PW: ");
		password = sc.nextLine();
		System.out.print("PW 확인: ");
		String password_confirm = sc.nextLine();

        if (password.equals(password_confirm)) {
            break;
		} else {
            System.out.println("======================");
            System.out.println("패스워드가 일치하지 않습니다.");
            System.out.println("패스워드를 다시 입력해주세요.");
	        System.out.println("======================");
        }
    }

	// 이름
	System.out.print("성명: ");
	String name = sc.nextLine();

	// 생년월일(6자리)
	String birth_date = "";
	while (true) {
		System.out.print("생년월일(6자리): ");
		birth_date = sc.nextLine();
		if (birth_date.length() == 6) {
			break;
		} else {
			System.out.println("======================");
			System.out.println("생년월일 자릿수가 올바르지 않습니다.");
	        System.out.println("생년월일을 다시 입력해주세요.");
         	System.out.println("======================");                    
		}
	}

	// 이메일
	System.out.print("이메일: ");
	String email = sc.nextLine();

가입된 회원정보를 저장하기 위해 ArrayList를 만들어준다. 회원가입을 진행할 것인지 묻기 위해 while 문을 작성해준다. while 문이 무조건 실행되도록 true를 입력한다. 각각의 유저 한 명씩을 담아 항목별로 관리할 수 있도록 HashMap으로 변수를 선언한다.

입력받는 값이 아이디라는 것을 알려주고 값을 입력 받은 뒤 엔터를 치면 다음으로 넘어가도록 한다.

변수를 선언한 뒤, while 문으로 입력받은 비밀번호와 확인칸의 비밀번호 값을 비교한다. if 문을 통해 값이 같다면 while 문을 break를 통해 빠져나오고, 값이 다르면 다시 입력받도록 돌아간다.

이름과 생년월일, 이메일을 입력받는다. 생년월일은 6자리로 제한한다. 6자리가 아닌 경우, 처음부터 다시 입력받도록 while 문을 쓴다. 변수는 밖에서 참조해야하는 데이터이기 때문에 외부에서 변수를 선언한다. length 함수로 6자리인지 확인한다.

 

user.put("username", username);
user.put("password", password);
user.put("name", name);
user.put("birth_date", birth_date);
user.put("email", email);

users.add(user);

System.out.println("------------------------");
System.out.println(user.get("name") + " 님, 가입을 환영합니다.");
System.out.println("ID는 " + user.get("username") + " 입니다.");
System.out.println("------------------------");

System.out.println("회원가입을 이어서 진행하시겠습니까?\ny: 진행    N:취소");
System.out.print(">> ");
String register_again = sc.nextLine();

if (register_again.equalsIgnoreCase("y")) {
	;
} else if (register_again.equalsIgnoreCase("n")) {
    System.exit(0);
}

put을 통해 HashMap에 각각 키-값 쌍으로 데이터를 구성하여 추가한다.

모든 회원이 저장되는 ArrayList에 우리가 지금까지 만든 user라는 HashMap 객체를 추가하여 전체 회원장부에 가입한 회원정보를 등록한다.

 

 

'Back-End > Java' 카테고리의 다른 글

예외 - 예외 처리  (0) 2023.05.19
객체지향 - 객체지향 프로그래밍  (0) 2023.05.18
함수  (0) 2023.05.15
자료구조 - 배열, 리스트, 맵  (0) 2023.05.12
제어문 - 조건문과 반복문  (0) 2023.05.11

+ Recent posts