[Java] 김영한의 실전 자바 기본편 - #2 기본형과 참조형
[김영한의 실전 자바 - 기본편↗️]을 듣고 정리한 글입니다.
1. 기본형 vs 참조형
1.1 자바의 대원칙
대원칙: 자바는 항상 변수의 값을 복사해서 대입한다.⭐⭐⭐⭐
- 자바에서 변수에 값을 대입하는 것은 변수에 들어 있는 값을 복사해서 대입하는 것이다.
- 기본형, 참조형 모두 항상 변수에 있는 값을 복사해서 대입한다.
- 기본형이면 변수에 들어 있는 실제 사용하는 값을 복사해서 대입하고, 참조형이면 변수에 들어 있는 참조값을 복사해서 대입한다.
// 기본형 대입
int a = 10;
int b = a;
// 참조형 대입
Student s1 = new Student();
Student s2 = s1;
1.2 기본형과 참조형
기본형(Primitive Type)
- 기본형 개념
int
,long
,double
,boolean
처럼 변수에 사용할 값을 직접 넣을 수 있는 데이터 타입을 기본형이라 한다.
- 값의 사용
- 기본형은 숫자
10
,20
과 같이 실제 사용하는 값을 변수에 담을 수 있다. 그래서 해당 값을 바로 사용할 수 있다
- 기본형은 숫자
- 복사
- 기본형은 변수에 값을 대입하더라도 실제 사용하는 값이 변수에 바로 들어있기 때문에 해당 값만 복사해서 대입한다.
- 계산
- 기본형은 들어있는 값을 그대로 계산에 사용할 수 있다.
int a = 10, b = 20; int sum = a + b;
- 기본형은 들어있는 값을 그대로 계산에 사용할 수 있다.
참조형(Reference Type)
- 참조형 개념
Student student1
,int[] students
와 같이 데이터에 접근하기 위한 참조(주소)를 저장하는 데이터 타입을 참조형이라 한다.- 참조형은 객체 또는 배열에 사용된다.
- 값의 사용
- 참조형은 실제 사용하는 값을 변수에 담는 것이 아니라 실제 객체의 위치(참조, 주소)를 저장하기 때문에, 참조형 변수를 사용하기 위해선 참조값을 통해 해당 위치로 이동해야 한다.
- 복사
- 참조형의 경우 실제 사용하는 객체가 아니라 객체의 위치를 가리키는 참조값만 복사된다.
- 즉, 실제 건물이 복사가 되는 것이 아니라 건물의 위치인 주소만 복사되는 것이다.
- 계산
- 연산이 불가능하다. 참조형은 들어있는 참조값을 그대로 사용할 수 없는데, 주소지만 가지고는 할 수 있는게 없기 때문이다. 주소지에 가야 실체가 있다.
- 연산을 하려면
.
을 통해 객체의 기본형 멤버 변수에 접근을 해야한다.Student s1 = new Student(); Student s2 = new Student(); s1 + s2 //오류 발생
➡️ [Date Type의 메모리 할당] 포스팅을 보면 기본형과 참조형의 차이 에 대해 조금 더 쉽게 이해할 수 있다.
💡 참고 - String
String
은 기본형처럼 사용할 수 있는 클래스이다.- 즉, 참조형인 것이다.
- 하지만, 기본형처럼 문자 값을 바로 대입할 수 있는데, 문자열은 자주 사용되므로 자바는 String을 편리하게 사용할 수 있도록 설계했기 때문이다. 뒤에서 자세히 살펴보자.
1.2 변수 대입
1.2.1 기본형의 변수 대입
- 값이 대입될 때, 변수에 들어있는 실제 값이 복사된다.
- 따라서
a
와b
는 독립적인 값을 가진다.
int a = 10;
int b = a; // a의 값이 b로 복사됨
a = 20; // a를 변경해도 b는 영향을 받지 않음
System.out.println(a); // 20
System.out.println(b); // 10
1.2.2 참조형의 변수 대입
변수에 들어있는 참조값(객체의 주소)이 복사된다.
Data dataA = new Data();
dataA.value = 10;
Data dataB = dataA; // dataA의 참조값이 dataB로 복사됨
dataA.value = 20;
System.out.println(dataA.value); // 20
System.out.println(dataB.value); // 20 (같은 객체를 참조하므로)
아래 코드의 실행 결과를 맞춰보자.
package ref;
public class Data {
int value;
}
package ref;
public class VarChange2 {
public static void main(String[] args) {
Data dataA = new Data();
dataA.value = 10;
Data dataB = dataA;
System.out.println("dataA 참조값=" + dataA);
System.out.println("dataB 참조값=" + dataB);
System.out.println("dataA.value = " + dataA.value);
System.out.println("dataB.value = " + dataB.value);
//dataA 변경
dataA.value = 20;
System.out.println("변경 dataA.value = 20");
System.out.println("dataA.value = " + dataA.value);
System.out.println("dataB.value = " + dataB.value);
//dataB 변경
dataB.value = 30;
System.out.println("변경 dataB.value = 30");
System.out.println("dataA.value = " + dataA.value);
System.out.println("dataB.value = " + dataB.value);
}
}
실행 결과
dataA 참조값=ref.Data@x001
dataB 참조값=ref.Data@x001
dataA.value = 10
dataB.value = 10
변경 dataA.value = 20
dataA.value = 20
dataB.value = 20
변경 dataB.value = 30
dataA.value = 30
dataB.value = 30
그림을 통해 자세히 알아보기
① 첫 번째
Data dataA = new Data();
dataA.value = 10;
dataA
변수는Data
클래스를 만들었기 때문에 참조형이다.- 이 변수는
Data
형 객체의 참조 값을dataA
에 저장한다. - 그리고 객체의
value
변수에 값10
을 저장한다.
② 두 번째
Data dataB = dataA
- 변수의 대입은 변수에 들어있는 값을 복사해서 대입한다. 변수
dataA
에는 참조 값x001
이 들어있다. - 여기서는 변수
dataA
에 들어있는 참조 값x001
을 복사해서 변수dataB
에 대입한다. (인스턴스를 복사하는 것이 아닌 변수에 들어있는참조 값만 복사에서 전달하는 것) - 이제
dataA
와dataB
의 참조 값은 같다. 따라서 둘다x001
Data
인스턴스를 가리킨다.
③ 세 번째
dataA.value = 20
dataA.value = 20
코드를 실행하면dataA
이 가리키는x001
인스턴스의 value 값을10
에서20
으로 변경한다.- 그런데,
dataA
와dataB
는 같은x001
인스턴스를 참조하기 때문에dataA.value
와dataB.value
둘다 같은 값인20
을 출력한다.
④ 네 번째
dataB.value = 30
dataB.value = 30
코드를 실행하면dataB
가 가리키는x001
인스턴스의 value 값을20
에서30
으로 변경한다.- 그런데,
dataA
와dataB
는 같은x001
인스턴스를 참조하기 때문에dataA.value
와dataB.value
는 같은 값인30
을 출력하게 된다.
1.4 메서드 호출
자바에서 메서드 호출 시, 기본형과 참조형 변수는 다르게 동작한다.
- 그 이유는 자바가 항상 값을 복사해서 메서드로 전달하기 때문인데, 이때 전달되는 값이 기본형 데이터의 실제 값이냐, 아니면 참조형 데이터의 참조값(메모리 주소)이냐에 따라 결과가 달라진다.
- ⭐ 대원칙: 자바는 항상 변수의 값을 복사해서 대입한다.
- 메서드를 호출할 때 사용하는 매개변수(파라미터)도 결국 변수일 뿐이므로 메서드를 호출할 때 매개변수에 값을 전달하는 것도 앞서 설명한 내용과 같이 값을 복사해서 전달한다.
1.4.1 기본형과 메서드 호출
기본형 데이터를 메서드에 전달하면, 변수에 저장된 값 자체가 복사되어 전달된다.
이 경우, 메서드 내부에서 매개변수를 변경해도 원본 변수에는 영향을 미치지 않는다.
package ref;
public class MethodChange1 {
public static void main(String[] args) {
int a = 10;
System.out.println("메서드 호출 전: a = " + a); // 메서드 호출 전: a = 10
changePrimitive(a);
System.out.println("메서드 호출 후: a = " + a); // 메서드 호출 후: a = 10
}
static void changePrimitive(int x) {
x = 20;
}
}
실행 흐름
- 메서드 호출 전에 a는 10의 값을 갖고 있다.
changePrimitive
메서드가 호출될 때, 변수 a의 값(즉, 10)이 복사되어 매개변수 x에 전달된다.- 메서드 내부에서 x의 값이 20으로 변경되지만, 이는 복사된 값에만 적용되므로 a의 값은 변하지 않는다.
- 결과적으로, 메서드 호출 후에도 a는 여전히 10의 값을 유지한다.
➡️ 즉, 메서드 호출 시 실제 값이 복사되어 전달되므로, 메서드 내부에서 매개변수의 값을 변경해도 원본 변수에는 영향을 미치지 않는다.
1.4.2 참조형과 메서드 호출
참조형 데이터를 메서드에 전달하면, 참조값(메모리 주소)이 복사되어 전달된다.
이때 메서드 내부에서 참조를 통해 객체의 상태를 변경하면, 원본 객체의 상태에도 영향을 미친다.
package ref;
public class MethodChange2 {
public static void main(String[] args) {
Data dataA = new Data();
dataA.value = 10;
System.out.println("메서드 호출 전: dataA.value = " + dataA.value); // 메서드 호출 전: dataA.value = 10
changeReference(dataA);
System.out.println("메서드 호출 후: dataA.value = " + dataA.value); // 메서드 호출 후: dataA.value = 20
}
static void changeReference(Data dataX) {
dataX.value = 20;
}
}
class Data {
int value;
}
실행 흐름
- 메서드 호출 전에
dataA.value
는10
이다. changeReference
메서드가 호출될 때, 변수dataA
의 참조값이 복사되어 매개변수dataX
에 전달된다. 즉,dataA
와dataX
는 같은 객체를 참조하게 된다.- 메서드 내부에서
dataX.value
를20
으로 변경하면, 같은 객체를 참조하고 있는dataA.value
도 함께 변경된다. - 결과적으로, 메서드 호출 후
dataA.value
는20
으로 바뀐다.
➡️ 즉, 메서드 호출 시 참조값(메모리 주소)이 복사되어 전달되므로, 메서드 내부에서 참조하는 객체의 상태를 변경하면, 원본 객체의 상태도 변경된다.
1.4.3 참조형과 메서드 호출 - 활용
아래 코드는 값을 할당하는 부분과 학생 정보를 출력하는 부분이 중복된다.
package class1;
public class ClassStart3 {
public static void main(String[] args) {
Student student1;
student1 = new Student();
student1.name = "학생1";
student1.age = 15;
student1.grade = 90;
Student student2 = new Student();
student2.name = "학생2";
student2.age = 16;
student2.grade = 80;
System.out.println("이름:" + student1.name + " 나이:" + student1.age + " 성적:" + student1.grade);
System.out.println("이름:" + student2.name + " 나이:" + student2.age + " 성적:" + student2.grade);
}
}
메서드를 통해 중복을 제거해보자
- 중복되는 코드를 제거하기 위해 객체 초기화와 출력을 별도의 메서드로 분리할 수 있다.
initStudent(Student student, ...)
: 전달한 학생 객체의 필드에 값을 설정한다.printStudent(Student student, ...)
: 전달한 학생 객체의 필드 값을 읽어서 출력한다.
package ref;
public class Student {
String name;
int age;
int grade;
}
package ref;
public class Method1 {
public static void main(String[] args) {
// 학생 객체 생성 및 초기화
Student student1 = new Student();
initStudent(student1, "학생1", 15, 90);
Student student2 = new Student();
initStudent(student2, "학생2", 16, 80);
// 학생 정보 출력
printStudent(student1);
printStudent(student2);
}
// 학생 객체 초기화 메서드
static void initStudent(Student student, String name, int age, int grade) {
student.name = name;
student.age = age;
student.grade = grade;
}
// 학생 정보 출력 메서드
static void printStudent(Student student) {
System.out.println("이름: " + student.name + " 나이: " + student.age + " 성적: " + student.grade);
}
}
➡️ 참조형은 메서드를 호출할 때 참조값을 전달한다. 따라서 메서드 내부에서 전달된 참조값을 통해 객체의 값을 변경하거 나, 값을 읽어서 사용할 수 있다.
하지만, 위 코드에서도 객체를 생성하고, 초기값을 설정하는 부분이 중복된다.
// 중복
Student student1 = new Student();
initStudent(student1, "학생1", 15, 90);
Student student2 = new Student();
initStudent(student2, "학생2", 16, 80);
객체 생성과 초기화를 하나의 메서드로 통합하여 중복을 해결해보자.
package ref;
public class Method2 {
public static void main(String[] args) {
// createStudent 메서드를 이용해 객체 생성과 초기화
Student student1 = createStudent("학생1", 15, 90);
Student student2 = createStudent("학생2", 16, 80);
// 학생 정보 출력
printStudent(student1);
printStudent(student2);
}
// 학생 객체를 생성하고 초기화하는 메서드
static Student createStudent(String name, int age, int grade) {
Student student = new Student(); // 객체 생성
student.name = name; // 이름 초기화
student.age = age; // 나이 초기화
student.grade = grade; // 성적 초기화
return student; // 생성된 객체의 참조값 반환
}
// 학생 정보 출력 메서드
static void printStudent(Student student) {
System.out.println("이름: " + student.name + " 나이: " + student.age + " 성적: " + student.grade);
}
}
createStudent()
라는 메서드를 만들고 객체를 생성하는 부분도 이 메서드안에 함께 포함했다. 이제 이 메서드 하나로 객체의 생성과 초기값 설정을 모두 처리한다.- 그런데 메서드 안에서 객체를 생성했기 때문에 만들어진 객체를 메서드 밖에서 사용할 수 있게 돌려주어야 한다. 따라서 호출 결과를
return
을 사용하여 객체의 참조값을 메서드 밖으로 반환하면 된다.
즉, 진행과정은 아래와 같다.
Student student1 = createStudent("학생1", 15, 90) //메서드 호출후 결과 반환
Student student1 = student(x001) //참조형인 student를 반환
Student student1 = x001 //student의 참조값 대입
student1 = x001
2. 변수와 초기화
2.1 멤버 변수와 지역 변수
멤버 변수(필드): 클래스에 선언
name
, age
, grade
는 멤버 변수이다.
public class Student {
String name;
int age;
int grade;
}
지역 변수: 메서드에 선언, 매개변수도 지역 변수의 한 종류이다. 즉, 지역 변수는 이름 그대로 특정 지역에서만 사용되는 변수라는 뜻이다.
student1
,student2
는 지역 변수이다.- 따라서
main()
메서드가 끝나면 제거된다.
- 따라서
public class ClassStart3 {
public static void main(String[] args) {
Student student1;
student1 = new Student();
Student student2 = new Student();
}
}
a
,x
는 지역 변수이다.- 따라서
a
변수는main()
메서드가 끝나면 제거되며,x
변수는changePrimitive()
메서드가 끝나면 제거된다.
- 따라서
public class MethodChange1 {
public static void main(String[] args) {
int a = 10;
System.out.println("메서드 호출 전: a = " + a);
changePrimitive(a);
System.out.println("메서드 호출 후: a = " + a);
}
public static void changePrimitive(int x) {
x = 20;
}
}
2.2 변수의 값 초기화
멤버 변수: 자동 초기화
- 클래스의 필드로 선언된 멤버 변수는 별도의 초기화를 하지 않아도 기본값으로 자동 초기화된다.
- 기본형 변수는
int=0
,boolean=false
로 초기화 되며 참조형 변수는 기본값으로null
이 할당된다. (null
값은 참조할 대상이 없다는 뜻으로 사용) - 개발자가 초기값을 직접 지정할 수 있다.
package ref;
public class InitData {
int value1; // 초기화하지 않음, 기본값 0으로 자동 초기화
int value2 = 10; // 10으로 초기화
}
package ref;
public class InitMain {
public static void main(String[] args) {
InitData data = new InitData(); // InitData 객체 생성
System.out.println("value1 = " + data.value1); // 자동 초기화된 값 출력 (value1 = 0)
System.out.println("value2 = " + data.value2); // 명시적으로 초기화된 값 출력 (value2 = 10)
}
}
이처럼 value1
은 초기값을 지정하지 않았지만 멤버 변수는 자동으로 초기화 된다. 숫자는 0
으로 초기화 된다.
지역 변수: 수동 초기화
- 지역 변수는 항상 직접 초기화해야 한다.
- 메서드 내에서 선언된 지역 변수는 반드시 사용 전에 초기화해야 하며, 그렇지 않으면 컴파일 오류가 발생한다.
2.3 null
null
은 자바에서 참조형 변수가 가리키는 객체가 없음을 나타내는 특별한 값이다.
예를 들어 택배를 보낼 때 제품은 준비가 되었지만, 보낼 주소지가 아직 결정되지 않아서, 주소지가 결정될 때 까지는 주소지를 비워두어야 할 때 null
을 사용한다.
null 사용 예제
자바에서 참조형 변수는 객체의 메모리 주소를 저장한다. 만약 아직 객체를 생성하지 않았다면, 이 변수는 null
로 초기화할 수 있다.
package ref;
public class Data {
int value; // 데이터 저장을 위한 멤버 변수
}
public class NullMain1 {
public static void main(String[] args) {
Data data = null; // data 변수를 null로 초기화
System.out.println("1. data = " + data); // 출력: null
data = new Data(); // Data 객체를 생성하여 data에 할당
System.out.println("2. data = " + data); // 출력: Data 객체의 참조값
data = null; // data를 다시 null로 할당
System.out.println("3. data = " + data); // 출력: null
}
}
실행 결과
1. data = null
2. data = ref.Data@x001 // 객체의 메모리 주소가 출력됨
3. data = null
실행 흐름
data = null
: data가 null이므로 가리키는 객체가 없음을 의미한다.data = ref.Data@x001
: new Data()를 통해 Data 객체를 생성하고 그 주소값이 data에 할당된다.data = null
: 다시 data에 null을 할당하여 객체에 대한 참조를 제거한다.
메모리 관리와 가비지 컬렉션(GC)
- 객체 참조 해제
- 만약 변수가
null
로 할당되면, 그 변수는 더 이상 해당 객체를 참조하지 않게 된다. - 예를 들어
data = null;
을 수행하면,Data
객체는 더 이상data
를 통해 접근할 수 없게 된다.
- 만약 변수가
- GC 작동
- 자바 가상 머신(JVM)은 메모리에서 더 이상 참조되지 않는 객체를 감지하여 이를 제거한다.
- 이 과정을 GC(가비지 컬렉션)이라고 하며, 주기적으로 수행되어 메모리 누수를 방지한다.
- 메모리 관리
- 자바는 이런 과정을 자동으로 처리해주기 때문에, 사용이 끝난 후 메모리를 수동으로 관리할 필요가 없다.
- 아무도 참조하지 않는 인스턴스가 있으면, JVM의 GC가 자동으로 메모리에서 해당 객체를 제거하기 때문이다.
Data data = null; // 객체를 가리키지 않음
data = new Data(); // 객체를 생성하여 참조
data = null; // 객체 참조 해제 (이제 GC의 대상)
2.4 NullPointerException
NullPointerException
(NPE)은 Java에서 매우 일반적인 예외 중 하나로, 객체를 참조할 때 해당 객체가null
인 경우 발생한다.
- 택배를 보낼 때 주소지가 없으면 배송이 불가능한 것처럼, Java에서 객체를 참조할 때
null
인 경우 그 객체를 찾을 수 없어NullPointerException
이 발생한다. - 예를 들어, 객체가 없는(
null
) 상태에서.
을 통해 멤버 변수에 접근하려고 할 때 이 예외가 발생한다.
package ref;
public class Data {
int value; // 데이터 저장을 위한 멤버 변수
}
public class NullMain2 {
public static void main(String[] args) {
Data data = null; // data를 null로 초기화
data.value = 10; // NullPointerException 예외 발생
System.out.println("data = " + data.value);
}
}
실행 결과
Exception in thread "main" java.lang.NullPointerException: Cannot assign field "value" because "data" is null
2.5 멤버 변수와 null
앞선 예제와 같이 지역 변수의 경우는
null
문제를 파악하는 것은 어렵지 않지만, 멤버 변수가null
인 경우는 주의가 필요하다.
아래 코드에서 bigData.data.value
를 호출하려고 할 때 data
가 null
이므로 NullPointerException
이 발생한다.
package ref;
public class Data {
int value; // int형 멤버 변수
}
package ref;
public class BigData {
Data data; // Data 객체를 참조하는 멤버 변수
int count; // 기본값 0
}
package ref;
public class NullMain3 {
public static void main(String[] args) {
BigData bigData = new BigData(); // BigData 인스턴스 생성
System.out.println("bigData.count=" + bigData.count); // count 출력 (0)
System.out.println("bigData.data=" + bigData.data); // data 출력 (null)
// NullPointerException 발생
System.out.println("bigData.data.value=" + bigData.data.value);
}
}
실행결과
bigData.count=0
bigData.data=null
Exception in thread "main" java.lang.NullPointerException: Cannot read field "value" because "bigData.data" is null
at ref.NullMain3.main(NullMain3.java:10)
NPE 발생 과정
count
멤버 변수는 숫자이므로 기본값인0
으로 초기화되고,BigData
의data
멤버 변수는 참조형이므로null
로 초기화된다.bigData.data.value
에 접근할 때data
가null
이므로 예외가 발생한다.
bigData.data.value
x001.data.value //bigData는 x001 참조값을 가진다.
null.value //x001.data는 null 값을 가진다.
NullPointerException //null 값에 .(dot)을 찍으면 예외가 발생한다.
NPE를 해결하는 방법
data
멤버 변수를 사용하기 전에, Data
객체를 생성하고 bigData.data
에 참조값을 할당하면 된다.
수정된 예제 코드
package ref;
public class NullMain4 {
public static void main(String[] args) {
BigData bigData = new BigData(); // BigData 인스턴스 생성
bigData.data = new Data(); // Data 객체를 생성하여 bigData.data에 할당
System.out.println("bigData.count=" + bigData.count); // 0 출력
System.out.println("bigData.data=" + bigData.data); // Data 객체의 주소 출력
System.out.println("bigData.data.value=" + bigData.data.value); // 0 출력
}
}
실행 결과
bigData.count=0
bigData.data=ref.Data@x002
bigData.data.value=0
실행 과정
bigData.data.value
x001.data.value //bigData는 x001 참조값을 가진다.
x002.value //x001.data는 x002 값을 가진다.
0 // 최종 결과
3. 문제와 풀이
3.1 상품 주문 시스템 개발 - 리팩토링
문제 설명
- [앞서 만든 상품 주문 시스템↗️]을 리팩토링 하자.
- 당신은 온라인 상점의 주문 관리 시스템을 만들려고 한다.
- 먼저, 상품 주문 정보를 담을 수 있는
ProductOrder
클래스를 만들어보자
요구 사항
-
ProductOrder
클래스는 다음과 같은 멤버 변수를 포함해야 한다.- 상품명 (
productName
) - 가격 (
price
) -
주문수량 (
quantity
)// 예시 코드 구조 package ref.ex; public class ProductOrder { String productName; int price; int quantity; }
- 상품명 (
-
다음으로
ref.ex.ProductOrderMain2
클래스 안에main()
메서드를 포함하여, 여러 상품의 주문 정보를 배열 로 관리하고, 그 정보들을 출력하고, 최종 결제 금액을 계산하여 출력하자. 이 클래스에서는 다음과 같은 메서드를 포함 해야 한다.static ProductOrder createOrder(String productName, int price, int quantity)
ProductOrder
를 생성하고 매개변수로 초기값을 설정한다. 마지막으로 생성된ProductOrder
를 반환한다.
static void printOrders(ProductOrder[] orders)
- 배열을 받아서 배열에 들어있는 전체
ProductOrder
의 상품명, 가격, 수량을 출력한다.
- 배열을 받아서 배열에 들어있는 전체
-
static int getTotalAmount(ProductOrder[] orders)
-
배열을 받아서 배열에 들어있는 전체
ProductOrder
의 총 결제 금액을 계산하고, 계산 결과를 반환한다.package ref.ex; public class ProductOrderMain2 { public static void main(String[] args) { // 여러 상품의 주문 정보를 담는 배열 생성 // createOrder()를 여러번 사용해서 상품 주문 정보들을 생성하고 배열에 저장 // printOrders()를 사용해서 상품 주문 정보 출력 // getTotalAmount()를 사용해서 총 결제 금액 계산 // 총 결제 금액 출력 } }
-
입력, 출력 예시
상품명: 두부, 가격: 2000, 수량: 2
상품명: 김치, 가격: 5000, 수량: 1
상품명: 콜라, 가격: 1500, 수량: 2
총 결제 금액: 12000
내 풀이
package _02_ref;
public class ProductOrder {
String productName;
int price;
int quantity;
}
package _02_ref;
public class ProductOrderMain2 {
public static void main(String[] args) {
ProductOrder[] orders = new ProductOrder[3];
orders[0] = createOrder("두부", 2000, 2);
orders[1] = createOrder("김치", 5000, 1);
orders[2] = createOrder("콜라", 1500, 2);
printOrders(orders);
int totalAmout=getTotalAmount(orders);
System.out.println("총 결제 금액: " +totalAmout);
}
static ProductOrder createOrder(String productName, int price, int quantity) {
ProductOrder order = new ProductOrder();
order.productName = productName;
order.price = price;
order.quantity = quantity;
return order;
}
static void printOrders(ProductOrder[] orders) {
for (ProductOrder order : orders) {
System.out.println("상품명: " + order.productName + ", 가격: " + order.price + ", 수량: " + order.quantity);
}
}
static int getTotalAmount(ProductOrder[] orders) {
int totalAmount=0;
for (ProductOrder order : orders) {
totalAmount += order.price * order.quantity;
}
return totalAmount;
}
}
3.2 상품 주문 시스템 개발 - 사용자 입력
문제 설명
앞서 만든 상품 주문 시스템을 사용자 입력을 받도록 개선해보자.
요구사항
- 주문 수량을 입력 받자
- 예) 입력할 주문의 개수를 입력하세요:
- 가격, 수량, 상품명을 입력 받자
- 입력시 상품 순서를 알 수 있게 “n번째 주문 정보를 입력하세요.” 라는 메시지를 출력하세요.
- 입력이 끝나면 등록한 상품과 총 결제 금액을 출력하자.
입력, 출력 예시
입력할 주문의 개수를 입력하세요: 3
1번째 주문 정보를 입력하세요.
상품명: 두부
가격: 2000
수량: 2
2번째 주문 정보를 입력하세요.
상품명: 김치
가격: 5000
수량: 1
3번째 주문 정보를 입력하세요.
상품명: 콜라
가격: 1500
수량: 2
상품명: 두부, 가격: 2000, 수량: 2
상품명: 김치, 가격: 5000, 수량: 1
상품명: 콜라, 가격: 1500, 수량: 2
총 결제 금액: 12000
내 풀이
package _02_ref;
import java.util.Scanner;
public class ProductOrderMain3 {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("입력할 주문의 개수를 입력하세요: ");
int n = scanner.nextInt();
scanner.nextLine();
ProductOrder[] orders = new ProductOrder[n];
for (int i = 0; i < orders.length; i++) {
System.out.println((i + 1) + "번째 주문 정보를 입력하세요.");
System.out.print("상품명: ");
String productName = scanner.nextLine();
System.out.print("가격: ");
int price = scanner.nextInt();
System.out.print("수량: ");
int quantity = scanner.nextInt();
scanner.nextLine();
orders[i] = createOrder(productName, price, quantity);
}
printOrders(orders);
int totalAmount = getTotalAmount(orders);
System.out.println("총 결제 금액: " + totalAmount);
}
static ProductOrder createOrder(String productName, int price, int quantity) {
ProductOrder order = new ProductOrder();
order.productName = productName;
order.price = price;
order.quantity = quantity;
return order;
}
static void printOrders(ProductOrder[] orders) {
for (ProductOrder order : orders) {
System.out.println("상품명: " + order.productName + ", 가격: " + order.price + ", 수량: " + order.quantity);
}
}
static int getTotalAmount(ProductOrder[] orders) {
int totalAmount = 0;
for (ProductOrder order : orders) {
totalAmount += order.price * order.quantity;
}
return totalAmount;
}
}
댓글남기기