객체와 객체지향 프로그래밍
객체 object
의사, 행위가 미치는 대상 구체적, 추상적 데이터의 단위 (학생, 회원, 생산, 주문, 배송) |
객체 지향 프로그램과 절차 지향 프로그래밍
절차 지향 프로그래밍
시간이나 사건의 흐름에 따른 프로그래밍 일어난다 → 씻는다 → 밥 먹는다 → 버스 탄다 → 요금 지불한다 → 학교 도착한다 |
객체 지향 프로그래밍
객체 지향 프로그램은 어떻게 구현하는가?
객체를 정의하고 각 객체 제공하는 기능들을 구현하고 각 객체가 제공하는 기능들 간의 소통(메세지 전달)을 통하여 객체 간의 협력 구현 |
생활 속에서 객체 찾아 클래스로 구현해 보기
객체
온라인 쇼핑몰에 회원 로그인을 하고 여러 판매자가 판매하고 있는 제품 중 하나를 골라 주문을 한다. 아침에 회사에 가는 길에 별다방 카페에 들려 아이스 카페 라떼를 주문했다. 성적 확인을 위해 학사 관리 시스템에 로그인하여 수강 한 과목들의 성적을 확인했다. |
클래스는 객체를 추상화해서 코딩화하는 것
// 학생 클래스
public class Student {
int studentNumber;
String studentName;
int majorCode;
String majorName;
int grade;
}
// 주문 클래스
public class Order {
int orderId;
String buyerId;
String sellerId;
int productId;
String orderDate;
}
// 회원 클래스
public class UserInfo {
String userId;
String userPassWord;
String userName;
String userAddress;
int phoneNumber;
}
함수와 메소드
함수 정의하기
- 함수는 이름, 매개 변수, 반환 값, 함수 몸체(body)로 구성 됨
int add(int num1, int num2) {
int result;
result = num1 + num2;
return result;
}
public class FunctionTest {
public static int addNum(int num1, int num2) {
int result;
result = num1 + num2;
return result;
}
public static void sayHello(String greeting) { // return 값 없으면 void 사용
System.out.println(greeting);
}
public static int calcSum()
{
int sum = 0;
int i;
for(i=0; i<=100; i++) {
sum += i;
}
return sum;
}
public static void main(String[] args) {
int n1 = 10;
int n2 = 20;
int total = addNum(n1, n2);
System.out.println(total); // 30
sayHello("안녕하세요"); // 안녕하세요
total = calcSum();
System.out.println(total); // 5050
}
}
// 결과 값
30
안녕하세요
5050
메소드 Method
객체의 기능 구현 위해 클래스 내부에 구현되는 함수 멤버 함수 (member function)이라고도 함 메소드를 구현함으로서 객체의 기능이 구현 됨 메소드의 이름은 그 객체를 사용하는 객체(클라이언트)에 맞게 짓는 것이 좋음 ex) getStudentName() |
객체 속성은 멤버 변수로, 객체 기능은 메소드로 구현한다.
학생 클래스를 정의하고 사용해 보자.
- 학생 클래스 속성을 멤버 변수로 선언하고 메소드를 구현한다.
public class Student {
public int studentID;
public String studentName;
public String address;
public void showStudentInfo() {
System.out.println( studentID + "학번의 이름은 " + studentName + "이고, 주소는 " + address + "입니다.");
}
public String getStudentName() {
return studentName;
}
public void setStudentName(String name) {
studentName = name;
}
}
학생 클래스를 생성하여 생성된 객체(인스턴스)에 각각 다른 이름과 주소를 대입한다.
// 인스턴스 생성
public class StudentTest {
public static void main(String[] args) {
Student studentLee = new Student();
studentLee.studentID = 12345;
studentLee.setStudentName("Lee");
studentLee.address = "서울 강남구";
studentLee.showStudentInfo();
Student studentKim = new Student();
studentKim.studentID = 54321;
studentKim.studentName = "Kim";
studentKim.address = "경기도 성남시";
studentKim.showStudentInfo();
}
}
// 결과 값
12345학번의 이름은 Lee이고, 주소는 서울 강남구입니다.
54321학번의 이름은 Kim이고, 주소는 경기도 성남시입니다.
인스턴스 생성과 힙 메모리 (heap memory)
인스턴스 Instance
클래스는 객체 속성을 정의하고, 기능을 구현해 만들어 놓은 코드 상태 실제 클래스 기반으로 생성된 인스턴스는 각각 다른 멤버 변수 값을 가지게 됨 가령, 학생의 클래스에서 생성된 각각의 인스턴스는 각각 다른 이름, 학번, 학년 등의 값을 가지게 됨 new 키워드를 사용하여 인스턴스 생성 |
힙 메모리
.. 딱히 필요 없는 것 같기도?
참조 변수, 참조 값
Student studentLee = new Student();
studentLee.studentName = "홍길동"
System.out.println(studentLee);
용어 정리
객체: 객체 지향 프로그램의 대상, 생성된 인스턴스 클래스: 객체를 프로그래밍 하기 위해 코드로 정의해 놓은 상태 인스턴스: new 키워드를 사용하여 클래스를 메모리에 생성한 상태 멤버 변수: 클래스의 속성, 특성 메소드: 멤버 변수를 이용하여 클래스의 기능을 구현한 함수 참조 변수: 메모리에 생성된 인스턴스를 가리키는 변수 참조 값: 생성된 인스턴스의 메모리 주소 값 |
생성자 constructor 에 대해 알아보자
생성자
따로 작성한 글 참고
여러가지 생성자를 정의하는 생성자 오버로딩 overloading
생성자 정의하기
생성자를 구현해서 사용할 수 있음 클래스에 생성자를 따로 구현하면 기본 생성자는 제공되지 않음 생성자를 호출하는 코드 (client 코드)에서 여러 생성자 중 필요에 따라 호출해서 사용할 수 있음 |
// UserInfo.java
public class UserInfo {
public String userId;
public String userPassWord;
public String userName;
public String userAddress;
public String phoneNumber;
public UserInfo(){}
public UserInfo(String userId, String userPassWord, String userName) {
this.userId = userId;
this.userPassWord = userPassWord;
this.userName = userName;
}
public String showUserInfo() {
return "고객님의 아이디는 " + userId +"이고, 등록된 이름은 " + userName + "입니다.";
}
}
// UserInfoTest.java
public class UserInfoTest {
public static void main(String[] args) {
UserInfo userLee = new UserInfo();
userLee.userId = "a12345";
userLee.userPassWord = "zxcvbn12345";
userLee.userName = "Lee";
userLee.phoneNumber = "01011111111";
userLee.userAddress = "Seoul, Korea";
System.out.println(userLee.showUserInfo());
UserInfo userKim = new UserInfo("b12345", "09876mnbvc", "Kim");
System.out.println(userKim.showUserInfo());
}
}
객체 구현하기 복습
다음 설명에 해당하는 객체를 구현하고 해당 정보를 출력하자.
1. 키가 180이고 몸무게가 78킬로인 남성이 있다. 이름은 Tomas이고 나이는 37세다.
2. 음식점에 배달 주문이 들어왔다.
주문 접수 번호 : 202011020003
주문 핸드폰 번호 : 01023450001
주문 집 주소 : 서울시 강남구 역삼동 111-333
주문 날짜 : 20201102
주문 시간 : 130258
주문 가격 : 35000
메뉴 번호 : 0003
public class Order {
// Date나 Calendar 객체를 사용할 줄 알면 시간이나 날짜에 대한 값은 해당 객체를 사용하면 된다.
// 여기서 숫자에 해당하는 자료형을 String으로 표현한 건 0으로 시작될 가능성이 있는 숫자에 해당한다.
public String orderNumber;
public String customerPhone;
public String customerAddress;
public String orderDate;
public String orderTime;
public int price;
public String menuId;
public void showOrderDetail() { // public void 쓰는 이유?
System.out.println("주문 접수 번호: " + orderNumber);
System.out.println("주문 핸드폰 번호: " + customerPhone);
System.out.println("주문 집 주소: " + customerAddress);
System.out.println("주문 날짜: " + orderDate);
System.out.println("주문 시간: " + orderTime);
System.out.println("주문 가격: " + price);
System.out.println("메뉴 번호: " + menuId);
}
}
참조 자료형 변수
참조 자료형
변수의 자료형 클래스형으로 변수 선언 기본 자료형은 사용하는 메모리의 크기가 정해져 있지만, 참조 자료형은 클래스에 따라 다름 참조 자료형을 사용할 때는 해당 변수에 대해 생성해야 함 (String 클래스는 예외적으로 생성하지 않고 사용할 수 있음) |
참조 자료형 정의하여 사용하기
- 학생 Student과 과목 Subject에 대한 클래스를 분리하여 사용하고 Subject 클래스를 활용하여 수강한 과목들을 변수 타입으로 선언
- 선언된 Subject 변수는 생성된 인스턴스가 아니므로 Student의 생성자에서 생성하여 사용
// Subject.java
public class Subject {
String subjectName;
int score;
int subjectID;
}
과목 클래스
- 과목 명
- 과목 점수
- 과목 아이디
선언
// Student.java
public class Student {
int studentID;
String studentName;
Subject korea;
Subject math;
public Student(int id, String name) {
studentID = id;
studentName = name;
korea = new Subject();
math = new Subject();
}
public void setKoreaSubject(String name, int score) {
korea.subjectName = name;
korea.score = score;
}
public void setMathSubject(String name, int score) {
math.subjectName = name;
math.score = score;
}
public void showStudentScore() {
int total = korea.score + math.score;
System.out.println(studentName + " 학생의 총점은 " + total + "점입니다.");
}
}
학생 클래스
|
과목 클래스 인스턴스로 선언해
|
학생 클래스와 과목 클래스 각각의 값을 한 문장에 넣어 가져오기
korea = new Subject(); math = new Subject(); total = korea. score + math.score; studentName + " 학생의 총점은 " + total + "점입니다." |
public class SubjectTest {
public static void main(String[] args) {
Student studentLee = new Student(100, "Lee");
studentLee.setKoreaSubject("국어", 100);
studentLee.setMathSubject("수학", 95);
Student studentKim = new Student(101, "Kim");
studentKim.setKoreaSubject("국어", 50);
studentKim.setMathSubject("수학", 65);
studentLee.showStudentScore();
studentKim.showStudentScore();
}
}
public 클래스들 가져와서 각각 클래스에 맞는 값 삽입하기
Student(int id, String name)
setKoreaSubject(String name, int score)
setMathSubject(String name, int score)
showStudentScore
// 결과 값
Lee 학생의 총점은 195점입니다.
Kim 학생의 총점은 115점입니다.
많이 많이 봐야할 듯!!
접근 제어 지시자(access modifier) 와 정보 은닉(information hiding)
클래스 외부에서 클래스 멤버 변수, 메소드, 생성자를 사용할 수 있는지 여부를 지정하는 키워드 private: 같은 클래스 내부에서만 접근 가능 (외부 클래스, 상속 관계의 클래스에서도 접근 불가) 아무 것도 없음 (default): 같은 패키지 내부에서만 접근 가능 (상속 관계라도 패키지가 다르면 접근 불가) protected: 같은 패키지나 상속 관계의 클래스에서 접근 가능하고 그 외 외부에서는 접근할 수 없음 public: 클래스의 외부 어디서나 접근 할 수 있음 |
get() / set() 메소드
private로 선언된 멤버 변수(필드)에 대해 접근, 수정할 수 있는 메소드를 public으로 제공 get() 메소드에만 제공되는 경우 read-only 필드 이클립스에서 자동으로 생성됨 ex) eclipse class 화면 > 우 클릭 > Source > Generate Getter and Setter |
* 왜 굳이 class 멤버 변수를 public으로 하지 않고 private로 접근 제어를 하는지?
만약 public이나 default로 설정해서 다른 클래스 객체에서 직접 변수에 접근을 하게 되면 해당 변수를 오용해서 사용할 수 있다. 예를 들어, int month라는 변수에 접근하여 설정할 때 month는 1~12까지만 유효한 value이다. 그러나 객체에서 직접 값을 설정한다면 integer 범위 내에서 어떤 수라도 넣을 수 있다. 그러나 setter(메소드)를 이용하면 메소드에서 예외처리를 해 변수 사용의 오용을 예방할 수 있다. setter 메소드에 1~12 사이의 값만 month에 들어가게끔 설정하고 그 이외의 값은 예외처리를 해 구현 가능하다. |
정보 은닉
- private로 제어한 멤버 변수도 public 메소드가 제공되면 접근 가능하지만 변수가 public으로 공개되었을 때보다 private일 때 각 변수에 대한 제한을 public 메소드에서 제어할 수 있다.
public void setMonth(int month) {
if ( month < 1 || month > 12) {
isValid = false;
}
else {
this.month = month;
}
}
- 객체 지향 프로그램에서 정보 은닉은 필요한 외부에서 접근 가능한 최소한의 정보를 오픈함으로서 객체 오류를 방지하고 클라이언트 객체가 더 효율적으로 객체를 활용할 수 있도록 해준다.
// Birthday.java
public class BirthDay {
private int day;
private int month;
private int year;
private boolean isValid; // 참인지 거짓인지
public int getDay() {
return day;
}
public void setDay(int day) {
this.day = day;
}
public int getMonth() {
return month;
}
public void setMonth(int month) {
if(month < 1 || month > 12) // 1~12 사이의 값만 출력
{
isValid = false;
}
else {
isValid = true;
this.month = month;
}
}
public int getYear() {
return year;
}
public void setYear(int year) {
this.year = year;
}
public void showDate()
{
if(isValid) {
System.out.println(year + "년 " + month + "월 " + day + "일입니다.");
}
else {
System.out.println("유효하지 않은 날짜입니다.");
}
}
public boolean getIsValid() {
return isValid;
}
}
// BirthdayTest.java
public class BirthdayTest {
public static void main(String[] args) {
BirthDay date = new BirthDay();
date.setYear(2019);
date.setMonth(12);
date.setDay(30);
date.showDate();
}
}
// 결과 값
2019년 12월 30일입니다.
// setMonth(13) 입력 시
유효하지 않은 날짜입니다.
캡슐화 encapsulation
정보 은닉을 활용한 캡슐화
꼭 필요한 정보와 기능만 외부에 오픈함 = 객체 지향 설계 파트에서 중요한 부분 대부분의 멤버 변수와 메소드를 감추고 외부에 통합된 인터페이스만을 제공하여 일관된 기능을 구현하게 함 각각의 메소드나 멤버 변수를 접근함으로서 발생하는 오류를 최소화 시킨다. |
public class MakeReport {
StringBuffer buffer = new StringBuffer();
private String line = "=======================================\n";
private String title = " 이름\t 주소\t\t 전화번호 \n ";
private void makeHeader()
{
buffer.append(line);
buffer.append(title);
buffer.append(line);
}
private void generateBody()
{
buffer.append("James \t");
buffer.append("Seoul Korea \t");
buffer.append("010-2222-3333\n");
buffer.append("Tomas \t");
buffer.append("NewYork US \t");
buffer.append("010-7777-0987\n");
}
private void makeFooter()
{
buffer.append(line);
}
public String getReport()
{
makeHeader();
generateBody();
makeFooter();
return buffer.toString();
}
}
// MakeReportTest.java
public class MakeReportTest {
public static void main(String[] args) {
MakeReport builder = new MakeReport();
String report = builder.getReport();
System.out.println(report);
}
}
// 결과 값
=======================================
이름 주소 전화번호
=======================================
James Seoul Korea 010-2222-3333
Tomas NewYork US 010-7777-0987
=======================================
객체 자신을 가리키는 this
1. this가 하는 일
1. 인스턴스 자신의 메모리를 가리킴 2. 생성자에서 또 다른 생성자를 호출할 때 사용 3. 자신의 주소(참조 값)을 반환 함 |
2. 생성된 인스턴스 메모리 주소를 가짐
클래스 내에서 참조 변수가 가지는 주소 값과 동일한 주소 값을 가지는 키워드
this는 참조변수 day와 동일하게 인스턴스 주소 값을 가리키고 있다.
public void setYear(int year){
this.year = year;
}
3. 생성자에서 다른 생성자를 호출하는 this
클래스에서 생성자가 여러 개인 경우, this를 이용해 생성자에서 다른 생성자를 호출할 수 있다. 생성자에서 다른 생성자를 호출하는 경우, 인스턴스의 생성이 완전하지 않은 상태이므로 this() statement 이전에 다른 statement를 쓸 수 없다. |
public class Person {
String name;
int age;
public Person()
{
// int num = 10; (불가)
// name = "test"; (불가)
this("no name", 1); //this() statement 이전에 다른 statement를 쓸 수 없다
// name = "aaa"; (가능)
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
4. 자신의 주소를 반환하는 this
import java.nio.file.ReadOnlyFileSystemException;
public class Person {
String name;
int age;
public Person() {
this("no name", 1);
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public Person getPerson() {
return this;
}
public static void main(String[] args) {
Person p = new Person();
p.name = "James";
p.age = 37;
Person p2 = p.getPerson();
System.out.println(p);
System.out.println(p2);
}
}
// 결과 값
Person@5ca881b5 // this
Person@5ca881b5 // this
객체 간의 협력 collaboration
객체 지향 프로그래밍에서의 협력
객체 지향 프로그램에서 객체 간에는 협력이 이루어짐 협력을 위해서는 필요한 메세지를 전송하고 이를 처리하는 기능이 구현되어야 함 매개 변수로 객체가 전달되는 경우 발생 |
객체 협력의 예
버스 타고 학교 가는 학생의 과정을 객체 지향 프로그래밍으로 구현하기
버스와 지하철을 타는 예제 프로그래밍
James와 Tomas는 각각 버스와 지하철을 타고 학교에 간다.
James는 5,000원을 가지고 있었고, 100번 버스를 타면서 1,000원을 지불한다.
Tomas는 10,000원을 가지고 있었고, 초록색 지하철을 타면서 1,200원을 지불한다.
두 학생이 버스와 지하철을 타는 상황을 구현하자.
// Bus.java
package ch14;
public class Bus {
// 1
int busNumber;
int passengerCount;
int money;
// 2
public Bus(int busNumber) {
this.busNumber = busNumber;
}
// 3
public void take(int money) { // 승차
this.money += money;
passengerCount++;
}
// 4
public void showBusinfo() {
System.out.println(busNumber + "번의 승객 수는 " + passengerCount + "명이고, 수입은 " + money + "원입니다.");
}
}
1. Bus 클래스를 생성하고 필요한 3가지 멤버 변수를 선언한다.
2. busNumber를 매개 변수로 하는 Bus 클래스의 생성자를 생성한다.
3. Student가 bus를 탔을 때 매개 변수 money만큼 멤버 변수 money를 증가 시키면서 passengerCount도 증가시키는 take 매서드 작성한다.
4. busNumber의 passengerCount와 money를 출력하는 showBusinfo를 작성한다.
// Subway.java
package ch14;
public class Subway {
int lineNumber;
int passengerCount;
int money;
public Subway(int lineNumber) {
this.lineNumber = lineNumber;
}
public void take(int money) { // 승차
this.money += money;
passengerCount++;
}
public void showSubwayInfo() {
System.out.println(lineNumber + "번의 승객 수는 " + passengerCount + "명이고, 수입은 " + money + "원입니다.");
}
}
Bus 클래스와 동일한 기능을 하는 Subway 클래스를 생성한다.
package ch14;
public class Student {
// 1
String studentName;
int grade;
int money;
// 2
public Student(String studentName, int money) {
this.studentName = studentName;
this.money = money; // 내는 돈은 변하지 않아서 그런가?
}
// 3
public void takeBus(Bus bus) {
bus.take(1000); // 버스 타고 1000원 지불
this.money -= 1000; // 내 돈 1000원 줄어듬
}
// 4
public void takeSubway(Subway subway) {
subway.take(1200);
this.money -= 1200;
}
// 5
public void showInfo() {
System.out.println(studentName + "님의 남은 돈은 " + money + "원입니다.");
}
}
1. Student 클래스를 생성하고 3가지 멤버 변수 생성한다.
2. Student 생성자 생성한다. 매개 변수는 studentName과 money 사용한다.
3. takeBus 메소드 만들어 학생이 버스 탔을 때 Bus 클래스의 take 메소드를 통해
Bus의 money에 1000원이 증가, passengerCount가 1 증가, Student의 money 변수에서 1000원 빠져 나간다.
4. 3번과 같은 역할을 하는 Subway 클래스의 takeSubway 메소드 작성한다.
5. studentName과 money 출력하는 showInfo 메소드 작성한다.
- 3, 4번이 객체 간의 협력이 일어나는 부분으로 Student 메소드의 매개 변수로 Bus가 들어가있다. 또한, 구현문에서 Bus 클래스의 메소드인 take가 사용돼 Student 메소드 안에서 다른 클래스의 메소드와 멤버 변수가 협력하고 있는 것을 알 수 있다.
// TakeTransTest.java
package ch14;
public class TakeTransTest {
public static void main(String[] args) {
// 1
Student studentJ = new Student("James", 5000);
Student studentT = new Student("Tomas", 10000);
// 2
Bus bus100 = new Bus(100);
Bus bus500 = new Bus(500);
// 3
Subway greenSubway = new Subway(2);
// 4
studentJ.takeBus(bus100);
studentT.takeSubway(greenSubway);
// 5
studentJ.showInfo(); // James님의 남은 돈은 4000원입니다.
studentT.showInfo(); // Tomas님의 남은 돈은 8800원입니다.
// 6
bus100.showBusInfo(); // 100번 버스의 승객은 1명이고, 수입은 1000원입니다.
bus500.showBusInfo(); // 500번 버스의 승객은 0명이고, 수입은 0원입니다.
// 7
greenSubway.showSubwayInfo(); // 2번의 승객 수는 1명이고, 수입은 1200원입니다.
}
}
1. TakeTransTest 클래스 생성하고 Student 인스턴스 2개 생성한다.
2. Bus 인스턴스 2개 생성한다.
3. Subway 인스턴스 생성한다.
4. Student 인스턴스들이 Bus와 Subway를 탔다고 가정하여 각각 takeBus, takeSubway 메소드 사용한다.
5. showInfo 메소드 사용해 Student 인스턴스들의 현재 남은 money를 출력한다.
6. BusInfo 메소드 사용해 greenSubway의 passengerCount와 money를 출력한다.
7. SubwayInfo 메소드 사용해 greenSubway의 passengerCount와 money를 출력한다.
- 테스트 결과 값을 통해 3개의 클래스에 협력이 잘 이루어진 것을 알 수 있다.
추가 예제
앞의 예제에서 Edward는 지각을 해서 택시를 타야 했습니다.
20,000원을 가지고 있었는데 10,000원을 택시비로 사용했습니다.
// taxi.java
package ch14;
public class Taxi {
int taxiNumber;
int passengerCount;
int money;
public Taxi(int taxiNumber) {
this.taxiNumber = taxiNumber;
}
public void take(int money) {
this.money += money;
passengerCount++;
}
public void showTaxiInfo() {
System.out.println(taxiNumber + "번 택시의 승객 수는 " + passengerCount + "명이고 수입은 " + money + "원입니다.");
}
}
Taxi 클래스를 생성하고 Bus, Subway 클래스와 동일한 기능을 하는 코드 작성한다.
public void takeTaxi(Taxi taxi1) {
taxi1.take(10000);
money -= 10000;
}
Student 클래스에 taxi Taxi 메소드를 추가한다.
Student studentE = new Student("Edward", 20000);
Taxi taxi1 = new Taxi(1);
studentE.takeTaxi(taxi1);
studentE.showInfo(); // Edward님의 남은 돈은 10000원입니다.
taxi1.showTaxiInfo(); // 1번 택시의 승객 수는 1명이고 수입은 10000원입니다.
TakeTransTest 클래스에 위의 코드를 추가한다.
여러 인스턴스에서 공통으로 사용하는 변수를 선언하자 - static 변수
클래스 하나에서 생성되는 여러 개의 인스턴스가 하나의 값을 공유할 필요가 있을 때 사용하는 하나의 변수 인스턴스가 힙 메모리에 생성되는 것과 다르게 그림과 같이 데이터 영역 메모리에 생성되며 인스턴스의 생성과 상관 없이 사용할 수 있다. 클래스 이름으로 참조되며 Student 클래스에 serialNumber라는 static 변수를 참조한다면 Student.serialNumber로 사용할 수 있다. |
여러 인스턴스가 공유하는 기준 값이 필요한 경우
학생마다 새로운 학번 생성 카드 회사에서 카드를 새로 발급 받을 때마다 새로운 카드 번호 부여 회사에 사원이 입사할 때마다 새로운 사번 부여 |
static 변수 선언과 사용하기
Student 클래스에 학생 Student 인스턴스가 새로 생성될 때마다 Student ID를 부여하자.
// Student.java
package ch16;
public class Student {
// 1
private static int serialNum = 1000;
private int studentID;
public String studentName;
// 2
public Student(String name) {
studentName = name;
serialNum++;
studentID = serialNum;
}
// 3
public int getStudentID() {
return studentID;
}
public static int getSerialNum() {
return serialNum;
}
}
1. 인스턴스가 생성될 때마다 Student ID를 부여하기 위해서는 기준점이 되는 하나의 값이 필요한데 그 것을 static 변수로 선언하기 위해 serialNum 변수를 선언하고 초기 값을 1000 대입한다.
2. 인스턴스가 생성될 때마다 serialNum이 1씩 증가해야하기 때문에 2개의 Student 생성자에 serialNum++을 한다. 그리고 증가된 serialNum을 생성된 인스턴스의 StudentID 값에 대입한다.
3. private로 선언한 studentID와 serialNum을 읽기 위한 get 메소드를 각각 작성하되 serialNum은 static 변수이니 static 메소드로 작성한다.
// StudentIdTest.java
public class StudentIdTest {
public static void main(String[] args) {
//1
Student studentLee = new Student("Lee");
System.out.println(Student.getSerialNum()); //1001
Student studentSon = new Student("Son");
System.out.println(Student.getSerialNum()); //1002
//2
System.out.println(studentSon.getStudentID()); //1002
System.out.println(studentLee.getStudentID()); //1001
}
1. 테스트를 위해 Student 인스턴스를 2개 생성하고 static 변수인 serialNum을 출력하기 위해 클래스명, 메소드를 사용해 출력하면 인스턴스가 생성될 때마다 serialNum이 증가하는 것을 확인할 수 있다.
2. studentId를 출력하니 인스턴스가 생성될 때마다 증가된 serialNum이 잘 대입된 것을 확인할 수 있다.
예제의 static 변수인 serialNum과 참조변수, 각 인스턴스의 관계는 위와 같다.
증가된 serialNum이 대입되는 studentID 변수는 각각의 인스턴스에 담기게 된다.
static 메소드
static 변수를 위한 기능을 제공하는 메소드로 클래스명을 참조한다.
public static int getSerialNum() {
int i = 0; // 지역변수는 사용가능
studentName = "Lee"; //에러 - 멤버변수는 사용불가
return serialNum;
}
위의 예제와 같이 static 메소드 안에서 int i =0 과 같은 지역변수는 함수 안에서만 사용하고 소멸되는 변수이기에 사용 가능하다.
하지만 studentName 같은 멤버변수는 사용할 수 없는데 static 메소드는 인스턴스 생성 여부와 상관 없이 사용할 수 있는 메소드지만 멤버변수는 인스턴스 생성이 필수이기 때문이다.
static 메소드를 사용하는 순간에 인스턴스가 없다면 오류가 날 수 밖에 없는 변수이기 때문에 사용이 불가하다.
변수 유형 별로 어디에서 어떤 변수를 사용해야 하는지를 알아야 메모리 사용을 최적화하고 에러를 줄이는 프로그래밍을 할 수 있다.
static 응용
싱글톤 패턴 singleton pattern
단 하나만 존재하는 인스턴스인 singleton pattern
학교와 학생의 클래스가 있다면 학생은 여러 명일 수 있으나 학교는 하나여야 한다. 이렇게 한 클래스에 인스턴스가 하나만 구현하는 것을 singleton pattern이라 한다. singleton pattern에서는 생성자를 private로 만들고 클래스 내부에 인스턴스를 생성한다. 또한, 외부에서 해당 인스턴스를 사용할 수 있게 하는 static 메소드를 생성한다. |
예제
public class Company {
//2
private static Company instance = new Company();
//1
private Company(){}
//3
public static Company getInstance() {
if(instance == null) {
instance = new Company();
}
return instance;
}
}
1. Company 클래스를 생성하고 외부에서 생성자를 사용할 수 없게 private Company 생성자를 생성한다.
2. 지금까지 클래스 외부에서 인스턴스를 생성했지만 하나의 클래스만을 만들기 위해 클래스 내부에 private를 붙이고 인스턴스 외부에서도 사용할 수 있게 static을 붙여 인스턴스를 생성한다.
3. 인스턴스를 호출하기 위한 getInstance 메소드를 작성하되 외부에서 사용할 수 있게 public을 붙이고, 인스턴스를 생성하지 않아도 사용할 수 있도록 static을 붙인다.
조건문을 통해 하나의 인스턴스도 생성되지 않는 것을 방지하고 인스턴스가 있다면 return 한다.
import java.util.Calendar;
public class CompanyTest {
public static void main(String[] args) {
//1
Company company1 = Company.getInstance();
Company company2 = Company.getInstance();
//2
System.out.println(company1);//staticex.Company@5305068a
System.out.println(company2);//staticex.Company@5305068a
//3
Calendar calendar1 = new Calendar(); // 생성이안됨
Calendar calendar2 = Calendar.getInstance();
}
}
1. 테스트 용으로 CompanyTest 클래스를 만들고 company1 인스턴스를 생성하는 것이 아닌 Company.getInstance()를 통해 불러온다. 테스트 용으로 company2를 통해 한 번 더 불러온다.
2. 출력문을 통해 두 인스턴스에 주소 값을 출력한 결과 2개의 주소가 같은 것을 알 수 있고 인스턴스를 생성한 것이 아닌 한 곳에 인스턴스를 불러온 것을 알 수 있다.
3. 자바에서 제공하는 Calendar 클래스의 경우 calendar1처럼 java.util에 있는 Calendar 클래스를 생성하려고 하면 오류가 생기지만 calendar2처럼 불러와서 사용할 수 있다.
이 처럼 자바 내부에서 제공하는 클래스나, 단 하나의 인스턴스만 생성하는 경우 singleton pattern을 사용하는 것을 알 수 있다.
static과 singleton pattern
예제
카드 회사가 있다. 카드 회사는 유일한 객체이고, 카드를 발급하면 고유번호가 자동으로 생성된다.
10001부터 시작하여 카드가 생성될 때 마다 10002, 10003식으로 증가된다.
다음 코드가 수행 되도록 Card클래스와 CardCompany 클래스를 구현해보자.
// Card.java
public class Card {
//1
private static int serialNum = 10000;
private int cardNum;
//2
public Card() {
serialNum++;
cardNum=serialNum;
};
//3
public int getCardNum() {
return cardNum;
}
}
1. Card 클래스를 생성하고 cardNum과 cardNum을 카운트하기 위한 serialNum을 선언한다.
serialNum은 static으로 선언해 여러 인스턴스에서 접근 가능하도록 한다.
2. Card 생성자를 생성하고 인스턴스가 생길 때마다 serialNum이 증가하고 증가한 수가 cardNum이 되도록 한다.
3. private인 cardNum을 읽기 위한 getCardNum 메소드를 작성한다.
// Company.java
public class Company {
// 2
private static Company instance = new Company();
//1
private Company () {}
//3
public static Company getInstance() {
return instance;
}
//4
public static Card createCard() {
Card card = new Card();
return card;
}
}
1. Company 클래스를 만들고 Company 생성자를 private로 지정해 외부에서 인스턴스를 생성할 수 없게 한다.
2. private로 클래스 내부에서 단 하나의 인스턴스를 생성한다.
3. 외부에서 Company 인스턴스를 읽기 위해 사용할 getInstance 메소드를 작성하고 static을 통해 인스턴스를 생성하지 않고도 메소드를 사용할 수 있게 한다.
4. Card 인스턴스를 생성할 createCard 메소드를 만들고 이것 또한 인스턴스 생성 없이 사용할 수 있게 static을 붙인다.
// CardTest.java
public class CardTest {
public static void main(String[] args) {
//1
Company company = Company.getInstance();
//2
Card myCard = company.createCard();
Card yourCard = company.createCard();
//3
System.out.println(myCard.getCardNum()); //10001
System.out.println(yourCard.getCardNum()); //1002
}
}
1. Company 인스턴스를 불러오기 위해 Company.getInstance 메소드 사용한다.
2. Card 인스턴스를 사용하기 위해 company.createCard 메소드 사용한다.
3. cardNum을 확인하기 위해 출력문에 getCardNum 메소드 사용한다.
배열과 ArrayList
배열이란?
배열은 자료들을 모아놓는 자료 구조의 일종으로 동일한 자료형을 순차적으로 관리하는 기능을 한다. 자료형[] 변수명 = new 자료형[인덱스 크기] ex. int[] arr = new int[10]; 배열은 0부터 시작한다. int[10]이면 위치가 1~10이 아닌 0~9다. |
int[] arr1 = new int[] {1, 2, 3};
int[] arr2 = {1, 2, 3};
int[] arr3;
arr2 = new int[]{1, 2, 3};
int[] arr4 = new int[3];
arr4[0] = 1;
arr4[1] = 2;
arr4[2] = 3;
위와 같이 배열을 입력한다.
배열을 이용해 1~10까지의 합을 구하는 예제
public static void main(String[] args) {
// 1
int[] arr = new int[10];
// 2
for(int i=0, num=1; i<arr.length; i++, num++) {
arr[i] = num;
}
// 3
int sum = 0;
for(int i = 0; i < arr.length; i++) {
sum += arr[i];
}
System.out.println(sum); // 55
}
1. int arr 배열을 선언하고 10개의 인덱스 입력한다.
2. for문 이용해 배열 arr에 1~10까지 대입하는 반복문 작성한다.
3. sum 변수를 만들고 arr 배열에 대입한 1~10을 더하는 반복문 작성한다. 그 후 sum을 출력한다.
double[] dArr = new double[5];
dArr[0] = 1.1;
dArr[1] = 2.1;
dArr[2] = 3.1;
double mtotal = 1;
for(int i=0; i<dArr.length; i++) {
mtotal *= dArr[i];
}
System.out.println(mtotal); // 0.0
다음과 같이 5개의 배열 중 3개만 입력한 상황에서 length만큼 반복해 곱셈을 했더니 결과 값으로 0.0이 나왔다.
이는 값을 입력하지 않은 dArr[3], dArr[4]가 초기값인 0.0으로 잡혀있기 때문이다.
double[] dArr = new double[5];
int count = 0;
dArr[0] = 1.1; count++;
dArr[1] = 2.1; count++;
dArr[2] = 3.1; count++;
double mtotal = 1;
for(int i=0; i<count; i++) {
mtotal *= dArr[i];
}
System.out.println(mtotal); // 7.161
이 문제를 해결하기 위해 위와 같이 count 변수를 선언하고 배열에 변수를 대입할 때마다 count++를 한다.
그리고 조건에 dArr.length 대신 count를 넣으면 결과 값을 얻을 수 있다.
대문자를 A-Z까지 배열에 저장하고 이를 다시 출력하는 프로그램을 만들어보자.
public static void main(String[] args) {
// 1
char[] alphabets = new char[26];
char ch = 'A';
// 2
for (int i=0; i<alphabets.length; i++) {
alphabets[i] += ch++;
}
// 3
for (int i=0; i<alphabets.length; i++) {
System.out.println(alphabets[i] + "," + (int)alphabets[i]);
}
}
1. char alpabets 배열을 먼저 생성하고 시작 값인 A를 ch 변수로 선언한다.
2. for문을 생성하고 length까지 반복되게 범위를 지정한다. alphabets 배열에 A부터 ++해서 더한다.
3. for문을 생성하고 출력문에
alphabets[i]
(int)alphabets[i]
출력한다.
// 결과 값
A,65
B,66
C,67
.
.
Y,89
Z,90
객체 배열
기본 자료형 배열과 참조 자료형 배열 (객체 배열)
int[] arr = new int[10];
Book[] library = new Book[5];
객체 배열은 자료 값을 담는 기본 자료형 배열과는 다르게 객체를 담는 배열이다. 여기서 객체는 생성자를 통해 만드는 인스턴스를 뜻한다.
위의 식은 Book이라는 클래스의 생성된 인스턴스를 담는 역할을 하는 객체 배열 library를 뜻한다.
또한, 기본 자료형이 직접 값을 메모리에 담는 것과는 다르게 객체 배열은 직접 인스턴스를 메모리에 기억하는 것이 아닌 주소 값을 담는다. 객체 배열을 사용해 인스턴스를 담는다고 해도 인스턴스는 여전히 힙 메모리에 저장 되고 그 메모리의 주소만이 각 객체 배열의 null 값을 채운다.
public class Book {
private String title;
private String author;
public Book() {}
public Book (String title, String author) {
this.title = title;
this.author = author;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public void showInfo() {
System.out.println(title + "," + author);
}
}
예제를 위해 Book 인스턴스를 생성하고 변수, 생성자, get/set 메소드, showInfo 메소드 작성한다.
public class BookArrayTest {
public static void main(String[] args) {
// 1
Book[] library = new Book[5]; // 책이 5권 생긴게 아니고 address다.
// 3
library[0] = new Book("태백산백1", "조정래");
library[1] = new Book("태백산백2", "조정래");
library[2] = new Book("태백산백3", "조정래");
library[3] = new Book("태백산백4", "조정래");
library[4] = new Book("태백산백5", "조정래");
// 2
for(int i=0; i<library.length; i++) {
System.out.println(library[i]);
library[i].showInfo();
}
}
}
1. BookArrayTest 클래스를 생성하고, 객체 배열 library를 생성한다. (여기서 new는 배열 생성의 new지 인스턴스 생성자가 아니다)
2. for문으로 객체 배열을 출력하면 배열에 담겨있는 인스턴스 주소 값이 출력되는데 아직 배열 입력 전이라 null 값이 5개 출력된다.
3. 객체 배열 library를 채우기 위해 생성자로 Book의 인스턴스를 5개 선택한다. 이 후 2번을 다시 출력하면
1. 각 인스턴스의 주소 값
2. showInfo 메소드를 통해 title과 author가 출력된다.
// 결과 값
Book@372f7a8d
태백산백1,조정래
Book@2f92e0f4
태백산백2,조정래
Book@28a418fc
태백산백3,조정래
Book@5305068a
태백산백4,조정래
Book@1f32e575
태백산백5,조정래
ArrayCopy
기본 자료형의 ArrayCopy
public class .. {
public static void main(String[] args) {
// 1
int[] arry1 = {10, 20, 30, 40, 50};
int[] arry2 = {1, 2, 3, 4, 5};
// 2
System.arraycopy(arry1, 0, arry2, 1, 3);
// 3
for(int i=0; i<arry2.length; i++) {
System.out.println(arry2[i]);
}
}
}
1. 배열을 복사해주는 ArrayCopy 실습 위해 2개의 int 배열 생성한다.
2. System.arraycopy를 사용하면 다음이 뜬다.
src 복사할 배열
srcPos 복사를 시작할 위치
dest 붙여넣기할 배열
destPos 붙여넣기할 위치
length 복사하는 길이
array1의 0부터 3개를 복사해 arry2에 1번부터 붙여넣기하라고 입력한다.
3. for문 이용해 배열 arry2를 출력하면 1~3번의 내용이 복사되었음을 알 수 있다.
// 결과 값
1
10
20
30
5
객체 배열의 ArrayCopy
public class BookArrayTest {
public static void main(String[] args) {
// 1
Book[] library = new Book[5];
Book[] copyLibrary = new Book[5];
// 2
library[0] = new Book("태백산맥1", "조정래");
library[1] = new Book("태백산맥2", "조정래");
library[2] = new Book("태백산맥3", "조정래");
library[3] = new Book("태백산맥4", "조정래");
library[4] = new Book("태백산맥5", "조정래");
// 3
System.arraycopy(library, 0, copyLibrary, 0, 5);
// 4
for(Book book : copyLibrary) {
book.showInfo();
}
}
}
1. BookArrayTest에서 library와 2번에 생성된 클래스들을 복사하고 library 내용을 복사할 copyLibrary 배열을 생성한다.
3. 기본 자료형 배열과 동일한 방법으로 arraycopy 이용해 library에 내용을 copyLibrary로 복사한다.
4. for(자료형, 변수명: 배열)을 이용하면 배열의 처음부터 끝까지 돌면서 해당 변수에 값이 하나씩 대입된다.
showinfo() 메소드를 사용해 객체 배열의 내용을 출력하면 결과물 같이 모두 복사된 것을 알 수 있다.
// 결과 값
태백산맥1,조정래
태백산맥2,조정래
태백산맥3,조정래
태백산맥4,조정래
태백산맥5,조정래
다차원 배열
2차원 이상의 배열로 지도, 게임, 평면이나 공간을 구현하는 배열이다.
아래의 예시처럼 하나 이상의 배열이 결합되어 구성되어 있다.
다차원 배열의 length
public class Test {
public static void main(String[] args) {
// 1
int[][] arr = {{1,2,3},{4,5,6}};
// 2
System.out.println(arr.length);
System.out.println(arr[0].length);
System.out.println(arr[1].length);
}
}
1. new를 사용하지 않고 바로 값을 대입해 2차원 배열을 생성했다.
2. arr.length는 행의 개수인 2가 출력된다. 즉, 몇 차원 배열인지 알려준다.
각 열을 뜻하는 arr[0]과 arr[1]의 length는 값이 3개이기 때문에 3이 출력된다.
2차원 배열의 값 출력
public class Test {
public static void main(String[] args) {
// 1
int[][] arr = {{1,2,3},{4,5,6,7}};
// 2
for(int i=0; i<arr.length; i++) {
for(int j=0; j<arr[i].length; j++) {
System.out.println(arr[i][j]+" ");
}
System.out.println();
}
}
}
1. 2차원 배열의 열 length를 다르게 하기 위해 arr[1]에 7을 추가 입력한다.
2. 이중 for문 사용해 행을 반복시킬 동안 열의 길이만큼 출력될 수 있도록 한다.
i<arr.length는 행의 길이만큼 반복 되는 것을 뜻하고,
j<arr[i].length는 해당 열의 길이만큼 반복 되는 것으로
arr[1]과 arr[2]의 길이가 다르더라도 올바르게 값을 출력하는 역할을 한다.
위와 같이 다차원 배열은 for문을 통해 출력할 수 있고 차원이 많아질 수록 for문의 중첩이 늘어나게 된다.
바깥에 있는 for문일수록 큰 공간을 표현한다고 생각하면 어렵지 않게 사용할 수 있다.
// 결과 값
1
2
3
4
5
6
7
ArrayList 클래스
ArrayList는 자바에서 제공되는 객체 배열 메소드가 구현된 클래스다.
주요 메소드 알아보기
배열 입력하고 값을 출력하자.
import java.util.ArrayList;
public class ArrayListTest {
public static void main(String[] args) {
// 1
ArrayList<String> list = new ArrayList<String>();
// 2
list.add("aaa");
list.add("bbb");
list.add("ccc");
// 3
for(int i=0; i<list.size(); i++) {
String str = list.get(i);
System.out.println(str);
}
System.out.println("=========");
// 4
for(String s: list) {
System.out.println(s);
}
}
}
1. ArrayList 클래스 사용 위해 list 인스턴스 생성한다.
<>에는 자료형이 들어가는데, 생략하면 자료형에 상관 없이 값 입력이 가능하지만 형 변환이 필요하다.
2. .add 메소드 이용해 list 배열에 값 입력한다. String은 생성할 필요 없이 바로 입력이 가능하지만 다른 객체는 생성 후 입력해야 한다.
3. for문 이용해 배열 값을 하나씩 출력하는데 범위를 .size 통해 현재 배열 크기인 3을 지정한다.
.size는 현재 배열 크기를 뜻하고 .length는 전체 배열 길이를 뜻한다.
만약 list[10]이었다면 size에는 입력된 값의 크기인 3이 되지만 length는 여전히 10을 유지한다.
// 결과 값
aaa
bbb
ccc
=========
aaa
bbb
ccc
학생의 수강 과목 학점 출력하기
Lee 학생은 두 과목을 수강하고, Kim 학생은 세 과목을 수강한다.
Stuent 클래스의 ArrayList 멤버 변수를 가지고 각 학생이 수강하는 과목을 관리하도록 한다.
각 학생의 학점과 총점을 아래와 같이 출력하자
// Subject.java
// 1
public class Subject {
public String name;
public int score;
// 2
public Subject(String name, int score) {
this.name = name;
this.score = score;
}
// 3
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getScore() {
return score;
}
public void setScore(int score) {
this.score = score;
}
}
1. 각 과목 역할을 할 Subject 클래스 생성하고 멤버 변수로 name, score 선언한다.
2. Subject 생성자 생성해 name, score 입력할 수 있게 한다.
3. name, score를 활용할 수 있게 get/set 메소드를 각각 생성한다.
여기서는 멤버 변수가 private가 아니어도 get/set 생성
// Student.java
import java.util.ArrayList;
// 1
public class Student {
public int studentId;
public String studentName;
ArrayList<Subject> subjectList;
// 2
public Student(int studentId, String studentName) {
this.studentId = studentId;
this.studentName = studentName;
subjectList = new ArrayList<Subject>();
}
// 3
public void addSubject(String name, int score) {
Subject subject = new Subject(name, score);
subjectList.add(subject);
}
// 4
public void showInfo() {
int total = 0;
for(Subject subject : subjectList) {
total = 0;
total += subject.getScore();
System.out.println(studentName + " 학생의 " + subject.getName() + "과목 점수는 " + subject.getScore() + "입니다.");
}
System.out.println(studentName + " 학생의 총점은 " + total + "입니다.");
}
}
1. Student 클래스를 생성하고 studentId, studentName을 담는 ArrayList subjectList를 멤버 변수로 선언한다.
2. Student 생성자로 studentId와 score를 입력할 수 있게 하고 Subject가 생성될 때 ArrayList도 함께 생성될 수 있도록 생성자를 같이 작성한다.
3. 과목을 추가할 수 있는 addSubject 메소드를 생성하고 name, score을 입력하는데 그게 Subject 생성자에 입력되도록 한다.
이 후 .add 메소드로 생성된 Subject가 ArrayList인 subjectList에 추가되도록 한다.
4. 정보를 출력하는 showInfo() 메소드 작성한다. 향상된 for문 사용해 subject의 subjectList 배열에 내용들이 하나씩 담기게 해 total에 더해주면서 총점을 구하고 출력문을 통해 각 subject 안에 name, score을 get 메소드 통해 출력한다.
// StudentTest.java
public class StudentTest {
public static void main(String[] args) {
//1
Student Lee = new Student(1001, "Lee");
Lee.addSubject("국어", 100);
Lee.addSubject("수학", 90);
//2
Student Kim = new Student(1001, "Kim");
Kim.addSubject("국어", 100);
Kim.addSubject("수학", 90);
Kim.addSubject("영어", 80);
//3
Lee.showInfo();
System.out.println("==================================");
Kim.showInfo();
}
}
1. Lee 학생의 인스턴스를 생성하고 addSubject 통해 각 과목의 이름, 점수 입력한다.
2. Kim 학생의 인스턴스를 생성하고 addSubject 통해 각 과목의 이름, 점수 입력한다.
3. showInfo로 정보 출력한다.
// 결과 값
Lee 학생의 국어 과목 점수는 100점입니다.
Lee 학생의 수학 과목 점수는 90점입니다.
Lee 학생의 총점은 90점입니다.
==================================
Kim 학생의 국어 과목 점수는 100점입니다.
Kim 학생의 수학 과목 점수는 90점입니다.
Kim 학생의 영어 과목 점수는 80점입니다.
Kim 학생의 총점은 80점입니다.
ArrayList 예제
어느 학교에 학생 3명이 있고 각 학생마다 읽은 책을 기록하고 있다.
Student 클래스를 만들고 각 학생마다 읽은 책을 Student 클래스 내에 ArrayList를 생성해 관리하도록 한다.
Student, Book, StudentTest 클래스를 생성해 실행하자.
// Book.java
public class Book {
public String title;
public String author;
public Book (String title, String author) {
this.title = title;
this.author = author;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
}
import java.util.ArrayList;
public class Student {
public String studentName;
ArrayList<Book> bookList;
public Student(String studentName) {
this.studentName = studentName;
bookList = new ArrayList<Book>();
}
public void addBook(String title, String author) {
Book book = new Book(title, author);
bookList.add(book);
}
public void showInfo() {
System.out.print(studentName + " 학생이 읽은 책은 : ");
for(Book book : bookList) {
System.out.println(book.getTitle() + " ");
}
System.out.println("입니다.");
}
}
public class StudentTest {
public static void main(String[] args) {
Student Lee = new Student("Lee");
Lee.addBook("태백산맥1", "조정래");
Lee.addBook("태백산맥2", "조정래");
Student Kim = new Student("Kim");
Kim.addBook("토지1", "박경리");
Kim.addBook("토지2", "박경리");
Kim.addBook("토지3", "박경리");
Student Cho = new Student("Cho");
Cho.addBook("해리포터1", "조앤 롤링");
Cho.addBook("해리포터2", "조앤 롤링");
Cho.addBook("해리포터3", "조앤 롤링");
Cho.addBook("해리포터4", "조앤 롤링");
Cho.addBook("해리포터5", "조앤 롤링");
Cho.addBook("해리포터6", "조앤 롤링");
Lee.showInfo();
Kim.showInfo();
Cho.showInfo();
}
}
// 결과 값
Lee 학생이 읽은 책은 : 태백산맥1
태백산맥2
입니다.
Kim 학생이 읽은 책은 : 토지1
토지2
토지3
입니다.
Cho 학생이 읽은 책은 : 해리포터1
해리포터2
해리포터3
해리포터4
해리포터5
해리포터6
입니다.
직전에 한 예제와 같이 Student 인스턴스 안에 Array List를 생성하고
그 안에 Book 인스턴스 내용을 입력해 담는 메소드 생성하고
showInfo 메소드 통해 ArrayList 안의 내용을 출력한다.
객체 배열을 구현한 클래스 ArrayList
java.util 패키지에서 제공되는 ArrayList
기존의 배열 선언과 사용 방식은 배열의 길이를 정하고 요소의 개수가 배열의 길이보다 커지면 배열을 재할당하고 복사해야 했다.
배열의 요소를 추가하거나 삭제하면 다른 요소들의 이동해 대한 구현을 해야 한다.
ArrayList는 객체 배열을 좀 더 효율적으로 관리하기 위해 자바에서 제공하는 클래스다.
이미 많은 메서드들이 최적의 알고리즘으로 구현되어 있어 각 메소드의 사용 방법만 익히면 우용하게 사용할 수 있다.
// ArrayList를 활용한 간단 예제
import java.util.ArrayList;
public class ArrayListTest {
public static void main(String[] args) {
ArrayList<Book> library = new ArrayList<>();
library.add(new Book("태백산백1", "조정래"));
library.add(new Book("태백산백2", "조정래"));
library.add(new Book("태백산백3", "조정래"));
library.add(new Book("태백산백4", "조정래"));
library.add(new Book("태백산백5", "조정래"));
for(int i=0; i<library.size(); i++) {
library.get(i).showInfo();
}
}
}
ArrayList를 활용한 간단한 성적 산출 프로그램
1001학번 Lee와 1002학번 Kim, 두 학생이 있다.
Lee 학생은 국어와 수학 2과목을 수강했고, Kim 학생은 국어, 수학, 영어 3과목을 수강했다.
Lee 학생은 국어 100점, 수학 50점이다.
Kim 학생은 국어 70점, 수학 85점, 영어 100점이다.
Student와 Subject 클래스를 만들고 ArrayList를 활용해 두 학생의 과목 성적과 총점을 출력하자.
// Student.java
import java.util.ArrayList;
public class Student {
int studentID;
String studentName;
ArrayList<Subject> subjectList;
public Student(int studentID, String studentName){
this.studentID = studentID;
this.studentName = studentName;
subjectList = new ArrayList<Subject>();
}
public void addSubject(String name, int score){
Subject subject = new Subject();
subject.setName(name);
subject.setScorePoint(score);
subjectList.add(subject);
}
public void showStudentInfo()
{
int total = 0;
for(Subject s : subjectList){
total += s.getScorePoint();
System.out.println("학생 " + studentName + "의 " + s.getName() + " 과목 성적은 " +
s.getScorePoint() + "입니다.");
}
System.out.println("학생 " + studentName + "의 총점은 " + total + "입니다.");
}
}
// Subject.java
public class Subject {
private String name;
private int scorePoint;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getScorePoint() {
return scorePoint;
}
public void setScorePoint(int scorePoint) {
this.scorePoint = scorePoint;
}
}
// StudentTest.java
public class StudentTest {
public static void main(String[] args) {
Student studentLee = new Student(1001, "Lee");
studentLee.addSubject("국어", 100);
studentLee.addSubject("수학", 50);
Student studentKim = new Student(1002, "Kim");
studentKim.addSubject("국어", 70);
studentKim.addSubject("수학", 85);
studentKim.addSubject("영어", 100);
studentLee.showStudentInfo();
System.out.println("================================");
studentKim.showStudentInfo();
}
}
// 결과 값
학생 Lee의 국어 과목 성적은 100입니다.
학생 Lee의 수학 과목 성적은 50입니다.
학생 Lee의 총점은 150입니다.
================================
학생 Kim의 국어 과목 성적은 70입니다.
학생 Kim의 수학 과목 성적은 85입니다.
학생 Kim의 영어 과목 성적은 100입니다.
학생 Kim의 총점은 255입니다.
'Java > 패스트캠퍼스' 카테고리의 다른 글
싱글톤 패턴 (0) | 2022.05.30 |
---|---|
static 변수, static 메소드 (0) | 2022.05.30 |
패스트캠퍼스 자바 알고리즘 문제 (0) | 2022.05.17 |
패스트캠퍼스 객체 지향 핵심 (0) | 2022.04.09 |
패스트캠퍼스 자바 프로그래밍 (0) | 2022.03.17 |