05.2 인스턴스 멤버 사용법: 인스턴스 메서드 활용하기

인스턴스 메서드를 사용하여 ArrayList의 인스턴스 필드 다루기

static 멤버와 non-static 멤버

클래스 멤버와 인스턴스 멤버

① static 필드(클래스 변수)와 static 메서드(클래스 메서드)
클래스 필드와 클래스 메서드

같은 클래스 소속인 static 필드에 직접 접근 가능

② non-static 필드(인스턴스 변수)와 static 메서드(클래스 메서드)
인스턴스 필드와 클래스 메서드

변수 : 인스턴스 소속
메서드 : 클래스 소속
⟹ 직접 접근 불가능!
⟹ 메서드 호출시 파라미터로 인스턴스 주소를 알려줘야 한다.

③ non-static 필드(인스턴스 변수)와 non-static 메서드(인스턴스 메서드)
인스턴스 필드와 인스턴스 메서드

변수 : 인스턴스 소속
메서드 : 인스턴스 소속
⟹ built-in 변수인 this를 사용하여 인스턴스 멤버에 접근한다.
⟹ 메서드 호출시 파라미터로 인스턴스 주소를 알려줄 필요가 없다.
⟹ 대신, 메서드 앞에 인스턴스 주소를 적어야 한다.

인스턴스 메서드 활용하기

1단계 - ArrayList 메서드를 호출할 때 인스턴스 주소를 파라미터로 넘기지 않고 메서드 호출 앞부분에 넘긴다.

1단계 - ArrayList 메서드를 호출할 때 인스턴스 주소를 파라미터로 넘기지 않고 메서드 호출 앞부분에 넘긴다.

‐ ContactController 변경

‐ ArrayList의 메서드를 호출할 때 인스턴스 주소를 앞쪽에 넘긴다.

contactList를 앞쪽으로 넘긴다

contactList.toArray();

contactList.add(contact);

contactList.set(index, contact) == null ? 0 : 1;

contactList.remove(index);

package com.eomcs.mylist;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController 
public class ContactController {

  // Contact 객체 목록을 저장할 메모리 준비
  // => Object[] list = new Object[5];
  // => int size = 0;
  ArrayList contactList = new ArrayList();

  @RequestMapping("/contact/list")
  public Object list() {
    return contactList.toArray(); 
  }

  @RequestMapping("/contact/add")
  public Object add(Contact contact) {
    //    System.out.println(contact);
    contactList.add(contact);
    return contactList.size;
  }


  @RequestMapping("/contact/get")
  public Object get(String email) {
    int index = indexOf(email);
    if (index == -1) {
      return "";
    }

    return contactList.list[index];
  }

  @RequestMapping("/contact/update")
  public Object update(Contact contact) {
    int index = indexOf(contact.email);
    if (index == -1) {
      return 0;
    }

    return contactList.set(index, contact) == null ? 0 : 1;
  }

  @RequestMapping("/contact/delete")
  public Object delete(String email) {
    int index = indexOf(email);
    if (index == -1) {
      return 0;
    }

    contactList.remove(index);
    return 1;
  }

  int indexOf(String email) {
    for (int i = 0; i < contactList.size; i++) {
      Contact contact = (Contact) contactList.list[i];
      if (contact.email.equals(email)) { 
        return i;
      }
    }
    return -1;
  }
}

2단계 - ArrayList의 메서드를 인스턴스 메서드로 전환한다.

‐ 메서드를 호출할 때 앞쪽에서 전달한 인스턴스 주소를 받을 수 있도록 인스턴스 메서드로 선언한다.
‐ 메서드 정의에서 static 키워드를 제거한다.
‐ 파라미터로 인스턴스 주소를 받는 대신에 built-in 변수 this를 사용한다.

  void add(Object obj) {
    if (this.size == this.list.length) { 
      this.list = grow(this);
    }
    this.list[this.size++] = obj;
  }

static이 안 붙은 모든 메서드는 this라는 내장 변수가 있다
앞쪽으로 인스턴스를 받고 싶으면 static을 지운다.
this라는 built-in 변수에 들어 있는 주소가
내장 변수 this ← 레퍼런스 변수
this라는 변수에 저장되어 있으니까 this라는 변수를 사용한다

this.copy(arr);

인스턴스 필드(변수)를 다루는 방법

TodoController에서 빼먹은 거 있었음
기존의 체크 정보를 그대로 가져가야 한다.

  @RequestMapping("/todo/update")
  public Object update(int index, Todo todo) {
    if (index < 0 || index >= todoList.size) {
      return 0;
    }

    Todo old = (Todo) todoList.list[index];
    todo.done = old.done;  // 기존의 체크 정보를 그대로 가져가야 한다.

    return todoList.set(index, todo) == null ? 0 : 1;
  }

패키지 사용법: 클래스 분류하기 + public 접근 제어

패키지 사용법: 클래스 분류하기 + public 접근 제어
‐ 클래스를 관리하기 쉽도록 역할별로 패키지에 분류한다.

1단계 - 도메인 역할을 수행하는 클래스를 별도의 패키지로 분류한다.

데이터 타입 역할을 수행하는 클래스를 도메인 클래스라 부른다.

‐ com.eomcs.mylist.domain 패키지 생성
‐ Contact, Todo, Board 클래스를 domain 패키지로 이동

public이 붙지 않은 건 직접 접근 불가능

‐ 필드의 기본 접근 범위는 패키지다.
‐ 즉 같은 패키지에 소속된 클래스만이 접근 가능하다.
‐ 다른 패키지에서 접근하고 싶다면 직접 변수를 사용하지 말고 setter/getter를 이용하라.

com.eomcs.mylist.xxxController 클래스 변경
‐ 도메인 클래스의 필드를 사용할 때 setter/getter를 사용한다.

board.viewCount++;board.setViewCount(board.getViewCount() + 1);

직접 변수에 접근하는 것보다 메서드를 통해서 접근하는 게 유지보수에 좋다

board.setViewCount(old.getViewCount());

board.setCreatedDate(old.getCreatedDate());

todo.setDone(old.isDone());

((Todo) todoList.list[index]).setDone(done);

2단계 - 여러 프로젝트에서 일반적인 용도로 사용하는 클래스는 util 패키지로 분류한다.

2단계 - 여러 프로젝트에서 일반적인 용도로 사용하는 클래스는 util 패키지로 분류한다.

‐ com.eomcs.util 패키지 생성
‐ 특정 프로젝트에서만 사용되는 클래스가 아니라면 보통 그룹 패키지 밑에 둔다.
‐ ArrayList 클래스를 util 패키지로 이동한다.

utility ← 일상적으로 늘 쓰는 거

‐ 다른 패키지에서 메서드를 사용할 수 있도록 public으로 공개한다.
‐ 외부에서 직접 필드를 접근하지 못하도록 만든다.
‐ 대신 그 값을 꺼내거나 설정할 수 있도록 setter/getter를 추가한다.

ArrayList 메서드에 public 붙이기
다 public 붙이는 게 아니라 밖에서 쓸 것만 public 붙이는 거

getSize만 체크

  public int getSize() {
    return size;
  }

getSize() → size()

  public int size() {
    return size;
  }

내부에 있는 변수값 리턴

this 붙이기

  public int size() {
    return this.size;
  }

this가 안 붙었다는 것은, 컴파일러가 자동으로 this 붙인 거
생략하도록 허락을 한 거
컴파일러가 컴파일할 때는 자동으로 this 붙임
this가 생략됐다는 사실을 알고 있어야 됨

(변경 전) boardList.size → (변경 후) boardList.size()

  public Object get(int index) {
    return this.list[index];
  }

직접 변수에 접근하면 안 된대
대신 변수에 접근할 수 있는 메서드를 만들어서 그 메서드를 호출해서 사용

(변경 전) Board board = (Board) boardList.list[index];
(변경 후) Board board = (Board) boardList.get(index);

3단계 - 페이지 컨트롤러 역할을 수행하는 클래스를 controller 패키지로 분류한다.

3단계 - 페이지 컨트롤러 역할을 수행하는 클래스를 controller 패키지로 분류한다.

‐ com.eomcs.mylist.controller 패키지 생성

XxxController 클래스를 controller 패키지로 이동한다.

클래스 문법의 활용
1) 사용자 정의 데이터 타입과 그 타입의 값을 다루는 연산자를 정의할 때 사용한다.
2) 서로 관련된 일을 하는 메서드를 관리하기 쉽게 분류하여 묶는 용도로 사용한다.

전치사구 형태로 짓는 경우도 있
대부분은 명사구 형태

메소드는 주로 동사구 형태

com.eomcs.oop.ex01.Exam0113.java

🔹 자바 기본 데이터 타입의 변수 선언 vs 클래스의 변수 선언
int a;
‐ 자바 기본 데이터 타입은 변수를 선언하는 순간 메모리에 생성된다.

Score s;
‐ 주소를 담는 메모리만 준비된다.

new Score();
‐ 클래스의 설계도에 따라 메모리를 준비하려면 따로 new 명령을 사용해야 한다.

s = new Score();
‐ 생성된 메모리를 사용하려면 주소를 잘 보관해 두어야 한다.

🔹 클래스 vs 배열

🔹 primitive 데이터 타입 변수와 레퍼런스
primitive type : byte, short, int, long, float, double, boolean, char
‐ primitive type의 메모리를 만들 때 변수 선언 만으로 완료된다.
‐ 클래스(사용자 정의 데이터 타입)로 메모리를 만들 때는 반드시 new 명령을 사용해야 한다.
‐ 메모리를 만든 후에는 그 주소를 변수에 저장해야만 그 메모리를 사용할 수 있다.

아직 변수가 존재하는 게 아님

이렇게 메모리의 주소를 저장하는 변수를 "레퍼런스(reference)"라 부른다.

s가 가리키는 메모리 → s 인스턴스 → s 객체
인스턴스의 각 변수 → 인스턴스의 각 필드

주소를 담는 메모리만 준비된다.

메모리 주소를 저장하는 변수(레퍼런스)이다.

인스턴스 레퍼런스 관계 머릿속에 그림

com.eomcs.oop.ex01.Exam0114

프로그램을 실행하는 순간 모든 클래스 코드는 Method Area에 있다.
소스코드가 아니라 바이트코드가 올라오는 거
바이트코드가 그냥 올라가는 게 아니라 분류한다
JVM이 바보가 아님
클래스에 인스턴스 변수도 있고, 메서드도 있고,
그거에 따라서 적절하게 분류를 함

Exam0114$Score.class

클래스 파일을 로딩한다.
따로 로딩

클래스 코드를 로딩한다. (클래스 로딩)
클래스 이름
클래스에 대한 변수 선언
메서드 선언
적절하게 분리해서 배치

Score 클래스 있음

.class 파일에 있는 코드
클래스 파일을 로딩한다
클래스 코드(바이트 코드)

Exam0114.class
Exam0114$Score.class
클래스 코드 따로 로딩함

main() 메서드 호출
JVM Stack에 메모리를 준비한다.
main() 메서드가 사용할 로컬 변수가 만들어짐
args, s

main()에서 createScore()를 호출하면
createScore() 메서드가 사용할 로컬변수가 JVM Stack에 만들어진다.
JVM Stack에 메모리 준비
name, kor, eng, math, s

로컬 변수
메서드가 호출될 때 만들어져서 메서드 호출이 끝나면 사라지는 변수
로컬 변수는 메서드가 호출될 때 JVM Stack에 만들어진다.

new 명령어로 만들어진 건 Heap에 만들어진다.
Score 설계도에 따라서 메모리를 만든다

main()에서 printScore() 호출
printScore() 메서드가 사용할 변수가 JVM Stack에 만들어진다.

0113번처럼 바깥에서 객체를 만들면 불편함
그래서 0114번 createScore() 메서드 같이 객체를 메서드 안에서 만들어서 리턴
객체를 만들어주는 메서드라고 해서 팩토리 메서드라고 한다.
팩토리 메서드 패턴
설계기법 중 하나

인스턴스 생성 과정이 복잡할 때
직접 new 명령으로 만드는 게 아니라
인스턴스를 직접 생성하지 않고
메서드를 통해서 인스턴스를 생성하는 예 ⟹ createElement()
createScore()랑 똑같은 개념
객체 생성 과정이 복잡할 때 메서드를 통해서 객체를 생성한다.
⟹ 설계 기법 중 하나인 "팩토리 메서드 패턴"

new 어쩌구가 아니라 메서드()
직접 객체를 생성하는 게 아니라 메서드를 통해서 생성

gof factory pattern 검색

팩토리 메서드 패턴(Factory method pattern)

"패턴" ← 이론이 아니라 경험으로 얻은 기술·기법

객체 생성하는 과정이 복잡하면
인스턴스를 만드는 걸로 끝나는 게 아니라
만들어진 인스턴스에 기본값들을 세팅도 해야 되는 상황이라면
차라리 별도의 메서드에서 객체를 생성해서 생성된 객체를 리턴하는 게 낫다

객체 생성 과정이 복잡한 경우, 메서드를 통해서 객체를 생성하는 방법을 많이 쓴다.

com.eomcs.oop.ex01.Exam0210

로컬 클래스
메서드 안에 선언된 클래스

나중에 중첩 클래스 배움

new 명령은 다 Heap에 만들어진다

com.eomcs.oop.ex01.Exam0240

다음과 같이 메서드를 통해 인스턴스를 생성하는 코딩 기법을 "팩토리 메서드(factory method)" 패턴이라 부른다.

com.eomcs.oop.ex01.Exam0320
레퍼런스와 인스턴스 - 가비지

인스턴스를 생성하면 각 필드에 기본값이 설정된다.
레퍼런스 변수 = null
정수 변수 = 0
부동소수점 변수 = 0.0
논리 변수 = false
⟹ 결국엔 다 0으로 처리됨

이 인스턴스의 주소를 갖고 있는 레퍼런스가 단 한 개도 없다면 사용할 수 없다. (접근할 수 없다.) ⟹ "Garbage"라 부른다.

가비지 컬렉터(garbage collector)
Heap 메모리에 존재하는 가비지를 찾아 제거(?)하는 일을 한다.
다른 용도로 사용할 수 있도록 메모리를 해제하는 일을 한다.
가비지는 가비지 컬렉터에 의해 메모리에서 해제된다.

가비지 컬렉터(garbage collector)의 실행
‐ JVM이 관리하는 메모리가 부족할 때
‐ CPU가 한가할 때

com.eomcs.oop.ex01.Exam0330
레퍼런스와 인스턴스 - 레퍼런스 카운트와 가비지

JVM은 인스턴스 주소를 레퍼런스에 저장할 때 내부적으로 인스턴스의 레퍼런스 카운트를 관리한다.

레퍼런스 카운트 개수가 0이면 "garbage"가 된다.

0개의 댓글