2018-11-30 수업 내용 정리

  • 과제

    • 이건 좀 어려워서 복습 과제 할 예정(25)!
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    package com.eomcs.lms.handler;

    import java.util.Arrays;
    import com.eomcs.lms.domain.Lesson;

    public class LessonList {

    static final int LENGTH = 10;
    private Lesson[] list;
    private int size = 0;

    public Lesson[] toArray() {
    return Arrays.copyOf(list, size);
    }

    void add(Lesson lesson) {
    if (size >= list.length) {
    int oldLength = list.length;
    // int newCapacity = oldLength + (int)(oldLength + 0.5);
    // 만약 배열의 크기만큼 데이터가 찼다면
    // 새 배열을 만들어서 복제를 해야함
    // 그래서 새 배열을 기존 배열의 1.5배로 늘려준다
    // cpu는 부동 소수점 연산이 복잡함
    // 그래서 이렇게 쓴다
    int newCapacity = oldLength + oldLength >> 1;
    // 소수점을 좌측으로 이동해 우측의 소수점을 버린다
    // 비트 이동 연산자 사용
    list = Arrays.copyOf(list, newCapacity);
    }
    list[size++] = lesson;
    }

    public LessonList() {
    list = new Lesson[LENGTH];
    }

    public LessonList(int initialCapacity) {
    if (initialCapacity > LENGTH) {
    list = new Lesson[initialCapacity];
    } else {
    list = new Lesson[LENGTH];
    }
    }

    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    package com.eomcs.lms.handler;
    import java.sql.Date;
    import java.util.Scanner;
    import com.eomcs.lms.domain.Lesson;

    public class LessonHandler {

    Scanner keyboard;
    LessonList list;

    public LessonHandler(Scanner keyboard) {
    this.keyboard = keyboard;
    list = new LessonList();
    }

    public void listLesson() {

    Lesson[] lessons = list.toArray();

    for (Lesson lesson : lessons) {
    System.out.printf("%3d, %-15s, %10s ~ %10s, %4d\n",
    lesson.getNo(), lesson.getTitle(),
    lesson.getStartDate(), lesson.getEndDate(),
    lesson.getTotalHours());
    }
    }
  • 다형적 변수 사용 과제

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    package com.eomcs.lms.handler;

    import java.util.Arrays;

    public class ArrayList {
    final int DEFAULT_CAPACITY = 10;
    int size = 0;
    // 배열은 어떻게 처리하지?
    // 다형적 변수 사용!
    Object[] list;
    // 그러나 모든 자료형을 받을 수 있기 때문에-오토박싱(자동으로 객체로 포장)로 싸서-
    // 이를 막고자 핸들러 측에서 제네릭 사용

    public ArrayList() {
    list = new Object[DEFAULT_CAPACITY];
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    package com.eomcs.lms.handler;
    import java.sql.Date;
    import java.util.Scanner;
    import com.eomcs.lms.domain.Board;

    public class BoardHandler {

    Scanner keyboard;
    ArrayList<Board> list;

    public BoardHandler(Scanner keyboard) {
    this.keyboard = keyboard;
    this.list = new ArrayList(20);
    }

    public void listBoard() {
    Object[] boards = list.toArray();
    // 여기서 강제 형변환을 할 수 없음

    for (Object obj : boards) {
    Board board = (Board) obj;
    // 여기서는 가능함
    // 실제로 object 배열이기 때문에 board 배열로 바꾸는 건 안되는 것이고,
    // 배열에 들어있는 data는 원래 자료형이 board이기 때문에
    // 형 변환이 여기서는 가능한 것
    System.out.printf("%3d, %-20s, %s, %d\n",
    board.getNo(), board.getContents(),
    board.getCreatedDate(), board.getViewCount());
    }
    }

    오토박싱과 오토언박싱

    1
    2
    3
    4
    5
    6
    > int i = 10;
    > Integer obj = new Integer(100);
    >
    > obj = 200; // 이렇게도 되는데, 사실 오토박싱으로 new Integer(200); 된 것
    > int j = obj; // 이렇게도 되는데, 사실 오토언박싱으로 obj.intValue(); 된 것
    >
  • System.arraycopy의 이용

    • 배열을 복사할 때는 arraycopy(소스가 되는 배열, 소스 배열의 몇 번째 인덱스부터, 저장할 배열, 저장을 시작할 배열 인덱스, 배열 복사할 개수)

      1
      2
      배열.arraycopy(src, srcPos, dest, destPos, length);
      // dest 배열 destPost 번부터 length 개를 복사해 src 배열 srcPost 번째부터 저장
    • 만약 저장할 배열이 복사 받을 배열보다 크기가 작다면 카피를 하되, 자료형을 가져온다.

      1
      2
      3
      if(a.,length < size) {
      (WhatType[]) Arrays.copyOf(list, size, a.getClass());
      }
    • 못 따라감

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      package com.eomcs.util;

      import java.util.Arrays;

      public class ArrayList<T> {
      // T : 어떤 타입
      final int DEFAULT_CAPACITY = 10;
      Object[] elementData;
      // 여기는 T로 쓸 수 없고, 최초이므로 Object로 배열 만들기
      int size = 0;

      public ArrayList() {
      elementData = new Object[DEFAULT_CAPACITY];
      }

      public ArrayList(int initialCapacity) {
      if (initialCapacity > DEFAULT_CAPACITY)
      elementData = new Object[initialCapacity];
      else
      elementData = new Object[DEFAULT_CAPACITY];
      }

      @SuppressWarnings("unchecked") // 에러 체크하지 않는다
      public T[] toArray(T[] a) {
      if (a.length < size) {
      // 만약 size가 a보다 크다면, 즉 배열의 방이 다 찼다면
      return (T[]) Arrays.copyOf(elementData, size, a.getClass());
      }
      System.arraycopy(elementData, 0, a, 0, size);
      if (a.length > size)
      // 보통 빈 배열일 경우 자동으로 null 값이지만
      // 배열을 재사용했을 경우를 대비해 데이터 뒤를 null로 만들어준 것
      // 배열의 끝을 모르기 때문에 null 처리
      a[size] = null;
      return a;
      }

      public void add(T obj) {
      if (size >= elementData.length) {
      int oldCapacity = elementData.length;
      int newCapacity = oldCapacity + (oldCapacity >> 1);
      elementData = Arrays.copyOf(elementData, newCapacity);
      }

      elementData[size++] = obj;
      }

      public int size() {
      return this.size;
      }
      }
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      package com.eomcs.lms.handler;
      import java.sql.Date;
      import java.util.Scanner;
      import com.eomcs.lms.domain.Member;
      import com.eomcs.util.ArrayList;

      public class MemberHandler {

      Scanner keyboard;
      ArrayList<Member> list;

      public MemberHandler(Scanner keyboard) {
      this.keyboard = keyboard;
      this.list = new ArrayList<>(20);
      // 위에서 정의를 했기 때문에 제네릭을 비운 것
      }

      public void listMember() {
      Member[] members = list.toArray[list.size()];
      // 이거는 이렇게 할 수도 있음
      // Member[] members = list.toArray(new members[] {});
      // 빈 배열을 보내도, 어차피 ArrayList에서 조건문을 걸었기 때문에 가능한 것
      for (Member member : members) {
      System.out.printf("%3d, %-4s, %-20s, %-15s, %s\n",
      member.getNo(), member.getName(),
      member.getEmail(), member.getTel(), member.getRegisteredDate());
      }
      }

      Arrays.copyOf와 .clone()의 차이

      • Arrays.copyOf : 배열의 크기만큼 복제
      • .clone() : 배열 안에 들어 있는 인스턴스만큼 복제
  • 뛰어넘음, 인터페이스가 필요한 이유

    • 인터페이스의 메서드는 모두 공개 상태여야 한다. (Default로 접근 제한을 걸었다)

    LinkedList와 ArrayList

    비교 이미지

    • LinkedList

      • List 인터페이스를 구현한 AbstractList를 상속하지 않고 AbstractSequentialList를 상속

      • 자료의 주소 값으로 서로 연결되어 있는 구조

      • inkedList는 몇 개의 참조자만 바꿈으로써 새로운 자료의 삽입이나 기존 자료의 삭제를 위치에 관계없이 빠른 시간안에 수행 가능

      • 자료의 최대 개수에 영향을 받지 않음(무한 개수의 자료를 삽입 가능)
        삽입과정

        삭제과정

      • 순차접근만이 가능(무작위 접근 불가)

      • 자료들을 저장 공간에 불연속적인 단위로 저장

      • 메모리 이곳저곳에 산재해 저장되어 있는 노드들을 접근하는데 ArrayList보다는 긴 지연 시간이 소모

      • 참조자를 위해 추가적인 메모리를 할당해야 함

    • ArrayList

      • List 인터페이스를 구현한 AbstractList를 상속

      • 데이터들이 순서대로 쭉 늘어선 배열의 형식

      • O(N)만큼의 연산 속도가 걸리기 때문에 자료의 최대 개수에 영향을 받음

      • ArrayList는 크기가 한정되어 있음

        삽입과정

        삭제과정

      • 무작위 접근 가능

      • 자료들을 하나의 연속적인 묶음으로 묶어 자료를 저장
  • 스택과 큐

    • 스택
      • LIFO(Last In Frist Out)
      • push, pop
      • FIFO(Frist In Frist OUT)
      • offer, poll
    • interface Cloneable
      • clone을 쓰기 위해 상속 받는 것
      • 사실 clone은 object의 메서드이고, Cloneable에서 override 해야할, 실제로 구현할 메서드는 없으나, clone이 사용 된다는 표기 역할을 함
  • 중첩 클래스의 이용(안드로이드가 대개 이런 문법을 이용한다)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    package com.eomcs.util;

    public class Stack<E> extends LinkedList<E> implements Cloneable {
    // Cloneable는 clone을 쓰기 위함
    // clone은 object의 메서드이나 구현을 하기 위해서는 Cloneable을 상속 받아야 함
    // Cloneable에서 실제로 구현할 메서드는 없으나, clone이 된다는 표기 역할을 함
    private int maxSize;

    public Stack() {
    maxSize = 100;
    }

    public Stack(int maxSize) {
    this.maxSize = maxSize;
    }

    @Override
    public Stack<E> clone() {
    Stack<E> temp = new Stack<>();
    for (int i = 0; i < size(); i++) {
    temp.add(get(i));
    }
    return (Stack<E>) temp;
    }
    // 객체를 생성해서 반복문 돌려서 넣어준 것

    public void push(E value) {
    if (size() == maxSize)
    remove(0);
    add(value);
    }

    public E pop() {
    return remove(size() - 1);
    }

    public Iterator<E> iterator() {
    return new IteratorImpl<>();
    // 중첩 클래스가 실행되기 전에 인스턴스 블록이 실행될 것이기 때문에
    // 게다가 이너 클래스는 외부 클래스에 접근이 가능하기 때문에
    // 굳이 객체 클론해서 보내지 않아도 됨
    }

    // 중첩 클래스의 사용
    // 어차피 stack에서만 쓸 것이기 때문에 이렇게 구현
    class IteratorImpl<T> implements Iterator<T> {

    Stack<?> stack;
    int count;
    int size;

    {
    // 인스턴스 블록
    // 앞에 아무 것도 없는 것이 특징
    // 인스턴스 생성자 호출 전에 먼저 실행되는 블록
    // 클래스 안에서 {} 하면 인스턴스 블록

    // static 블록은 클래스가 로딩될 때 실행됨
    // 이곳의 this는 이너 클래스의 객체 주소를 가리킨다.
    // 만약 외부 클래스의 객체 주소를 말하고자 한다면
    // 클래스명.this로 시작해야 한다.
    this.stack = Stack.this.clone();
    // 이너 클래스는 외부 클래스의 멤버 변수들과 메서드에게 접근 가능
    }

    @Override
    public boolean hasNext() {
    return count < Stack.this.size();
    }

    @Override
    public T next() {
    count++;
    return (T) this.stack.pop();
    // 중첩 클래스 안이라서 강제 형변환 시킴
    }
    }
    }
    • 이너 익명 클래스의 활용
    1
    2
    3
    4
    5
    6
    7
    public Iterator<E> iterator() {
    return new IteratorImpl<>() {
    // 이너 익명 클래스로도 만들 수 있다.
    // 슈퍼 클래스의 기본 생성자가 호출되며
    // 위에서 구현한 메서드 정의가 그대로 들어온다.
    }
    }
  • 커맨드 디자인 패턴

    • 메서드 하나만을 구현한 클래스들로 프로그램을 구현한 것
    • 새로운 기능을 추가할 때도 좋고, 유지보수가 보다 원활하다는 장점이 있다.
    • 메서드가 실제 구현된 클래스들은 특정 메서드가 정의된 인터페이스를 상속함
    • 이 메서드는 이름만 같을 뿐 클래스마다 각각 기능이 다르게 구현
    • 실행 클래스에서는 모든 클래스들의 객체를 생성한 뒤, hashMap()에 객체를 담는다.
    • 이 때 키를 기존에 command에 입력하던 문자열로 준다.
    • 그리고 조건문을 돌릴 때 eqauls를 사용하지 않고, 프롬프트에서 받은 문자열을 키로 이용해 interface 자료형으로 value를 받는다.
    • 이 value가 null인지 확인 후, 인터페이스에서 상속된 메서드를 호출하며 기능을 실행한다.