목차
- 클래스 사용 이유
- 사용자 정의 자료형 사용
1. 클래스 사용 이유
앞서 데이터를 저장하는 방법으로 배운 변수와 배열은 다음과 같은 특징이 있다: 예컨대 변수는 하나의 공간에 하나의 값을 저장한다. 배열은 같은 자료형의 값만을 취급할 수 있다. 이는 곧 데이터 관리 측면에서 단점을 낳기도 한다.
- 관리해야 하는 대상이 늘어날수록 사용자(개발자)가 변수명을 일일이 알고 다뤄야 한다는 번거로움이 따른다.
- 메소드 호출 시 전달인자가 그만큼 많아져 단번에 파악하기 어렵게 된다.
- 또한, 메소드에서 return;은 1개의 값만을 보낼 수 있기에 필요로 하는 정보 타입만큼의 메소드를 하나하나 만들어 리턴값을 배부해야 하기에 비효율적이다.
- 이 같은 이유에서 서로 다른 자료형 데이터를 사용자 정의의 새로운 타입으로 정의할 수 있도록 제공된 방법이 바로 클래스(class)이다.
- 클래스는 결국 데이터 관리에 있어 편의성을 높인 자료형(type)인 것이다.
전역변수==필드==인스턴스 변수==속성
- 클래스 내부에서 별도 메소드 없이 곧바로 선언된 변수를 전역변수(global variable)라 한다.
- 함수 밖에서 선언되었기에 클래스의 어느 위치에서든 호출과 사용이 가능하다.
- 반대인 지역변수(local variable)는 자신이 선언된 블럭 {} 안에서만 사용할 수 있다.
package com.reminder.user_type;
public class Member {
/* 전역변수 */
String id;
String pw;
String name;
int age;
char gender;
String[] hobby;
}
2. 사용자 정의 자료형 사용
1. 변수 선언 및 객체 생성
- 객체(instance, 인스턴스) 생성 구문을 선언한다.
- 해당 클래스에서 정의한 필드와 메소드대로 객체(인스턴스)가 생성됨을 말한다.
❗ 자료형 변수명 = new 클래스명();
- 클래스, 즉 사용자 정의 자료형을 사용하기 위해서는 new 연산자로 heap 영역에 할당해야 한다.
- heap 영역에는 값이 없는 채로 저장될 수 없으므로 JVM 기본값으로 자동 초기화된다.
Member member = new Member();
서로 다른 자료형들을 하나의 이름으로 관리할 수 있는 Member.class 공간을 생성한 것이다.
2. 필드에 접근하여 사용
- 필드에 직접 접근해 변수처럼 사용할 수가 있다. 필드로 가기 위해서는 다음 형식에 따른다.
- 여기서 '.'은 참조 연산자로, 레퍼런스 변수가 참조하고 있는 주소로 접근한다는 의미를 가진다.
- 배열은 index로 접근했다면, 객체는 필드명으로 접근하고 있는 것이다.
❗ 레퍼런스명.필드명
member.id = "user001";
member.pw = "pass001";
member.name = "김자바";
member.age = 20;
member.gender = 'F';
member.hobby = new String[] {"축구", "바둑", "클라이밍"};
- member.hobby 배열의 경우 출력문 작성 시 주의하여야 한다. 배열의 이름을 출력하면 참조하고 있는 주소값이 반환된다. 아래처럼 for문을 써서 출력해야 배열 인덱스에 따른 값이 출력된다.
System.out.print("member.hobby : ");
for(int i=0; i < member.hobby.length; i++) {
System.out.print(member.hobby[i] + " ");
}
그러나 필드에 직접 접근하게 되면 문제점들이 따른다.
문제점A. 값 통제 불가
- 필드에 원하지 않는 값, 검증되지 않은 값이 들어간대도 통제가 불가능하다.
- 이때는 필드값을 제한하는 메소드를 추가해 바로 잡을 수도 있다.
문제점B. 변경사항 발생 시 사용 코드 전체 컴파일 에러
- 내부적으로 필드명 등 클래스의 일부를 수정했음에도 해당 필드명을 사용하는 모든 코드에서 컴파일 에러가 발생한다.
- 일일이 수정하거나 코드 전체를 바꿔야 하는 부담이 따르는 것이다. 이는 유지보수성이 현저히 낮은 경우라고 표현할 수 있다.
위 문제점들을 방지하고 해결하기 위해서는 메소드를 활용해 직접 접근하지 않는 구조를 만들어야 한다.
public void setName(String name) {
this.name = name;
}
- this.는 자기자신의 주소값을 가지는 참조변수이다.
- this.name은 필드의 name을, 오른쪽 name은 매개변수를 말한다.
stack | heap |
prod1 (주소값 0x123) prod2 (주소값 0x456) |
setName | setOrigin | setPrice (주소값 0x123) setName | setOrigin | setPrice (주소값 0x456) |
- 사용자(개발자)가 과일 외에 다른 상품들도 겸하게 돼 구분을 위해 String name; 대신 String fruit;로 변수명을 바꿨다고 가정하자.
- 이때는 메소드 내부에서 달라진 점만 수정해주면 된다.
public void setName(String name) {
/* 수정 전 */
// this.name = name;
/* 수정 후 */
this.fruit = name;
}
- 사용자(클라이언트)의 호출 코드는 처음 입력 받을 때부터 간접 접근하도록 설정했기에 변경 없이 계속 정상 출력됨을 확인할 수 있다.
- 이밖에 신선도 유지 위해 1만원 미만 과일 대상으로 할인을 결정함에 따라 값을 절반가로 변경하는 메소드도 활용이 가능하다.
package com.reminder.encapsulation.problems;
public class Product {
// String name;
String fruit;
String origin;
int price;
/**
* <pre>
* 과일 이름에 해당하는 필드값을 반환하는 메소드
* </pre>
* @param name 과일 이름 입력
* */
public void setName(String name) {
/* 수정 전 */
// this.name = name;
/* 수정 후 */
this.fruit = name;
}
/**
* <pre>
* 과일 원산지에 해당하는 필드값을 반환하는 메소드
* </pre>
* @param origin 과일 원산지 입력
* */
public void setOrigin(String origin) {
this.origin = origin;
}
/**
* <pre>
* 신선도 유지 위해 1만원 미만 과일 대상으로 할인을 결정함에 따라 값을 절반가로 변경하는 메소드
* </pre>
* @param price 과일 가격 입력
* */
public void setPrice(int price) {
if(price >= 10000) {
this.price = price;
} else {
this.price = price / 2;
}
}
public String getInfo() {
return "선택하신 과일은 " + this.origin + "산 " + this.fruit + "이고, 가격은 " + this.price + "원입니다.";
}
}
package com.reminder.encapsulation.problems;
public class Application {
public static void main(String[] args) {
Product prod1 = new Product();
prod1.setName("샤인머스캣");
prod1.setOrigin("국내");
prod1.setPrice(15000);
Product prod2 = new Product();
prod2.setName("골드키위");
prod2.setOrigin("뉴질랜드");
prod2.setPrice(12000);
Product prod3 = new Product();
prod3.setName("블루베리");
prod3.setOrigin("칠레");
prod3.setPrice(10000);
Product prod4 = new Product();
prod4.setName("레몬");
prod4.setOrigin("미국");
prod4.setPrice(8000);
System.out.println(prod1.getInfo());
System.out.println(prod2.getInfo());
System.out.println(prod3.getInfo());
System.out.println(prod4.getInfo());
}
}
선택하신 과일은 국내산 샤인머스캣이고, 가격은 15000원입니다.
선택하신 과일은 뉴질랜드산 골드키위이고, 가격은 12000원입니다.
선택하신 과일은 칠레산 블루베리이고, 가격은 10000원입니다.
선택하신 과일은 미국산 레몬이고, 가격은 4000원입니다.
✅ 사용자 정의 자료형을 이해할 수 있다.
✅ 클래스와 인스턴스의 차이를 이해하고 설명할 수 있다.
✅ 사용자 정의 자료형을 작성하고 활용할 수 있다.
✅ 캡슐화를 적용하지 않은 경우에 어떤 문제점이 따르는지 이해할 수 있다.
'Java' 카테고리의 다른 글
[JAVA/수업 과제 practice] 클래스와 객체 Lv. 1~2 (0) | 2021.12.29 |
---|---|
[JAVA] 6-2. 객체 지향 언어, 캡슐화, 추상화, 생성자 (0) | 2021.12.29 |
[자바/수업 Quiz] 배열 (0) | 2021.12.28 |
[JAVA] 5-2. 배열의 복사 및 정렬 (0) | 2021.12.28 |
[JAVA/수업 과제 practice] 배열 | 다차원 배열 Lv. 1~2 (0) | 2021.12.27 |