스터디플래너/공부하기

[자바의 정석] Chapter06-1. 객체지향 프로그래밍1

2022. 2. 3. 08:20

  1.  객체지향언어
    1. 객체지향언어의 역사
      1. 1960년대 중반 상속, 캡슐화, 추상화 개념을 중심으로 객체지향이론을 프로그래밍언어에 적용한 최초의 객체지향언어 시뮬라(Simula) 탄생 ➡️ FORTRAN, COBOL과 같은 절차적 언어가 주류를 형성하여 많이 쓰이지 못함 ➡️ 1980년대 중반 C++ 등 여러 객체지향언어 발표되었으나 분위기는 비슷 ➡️ 절차적 언어의 대안으로 객체지향언어를 이용한 개발 방법론이  떠오름 ➡️ 1995년 자바 발표 후 인터넷의 발전으로 객체지향언어가 프로그래밍 언어의 주류로 자리잡음
    2. 객체지향언어
      1. 코드의 재사용성이 높다; 새로운 코드를 작성할 때 기존의 코드를 이용하여 쉽게 작성할 수 있다.
      2. 코드의 관리가 용이하다; 코드간의 관계를 이용해서 적은 노력으로 쉽게 코드를 변경할 수 있다.
      3. 신뢰성 높은 프로그래밍을 가능하게 한다; 제어자와 메소드를 이용하여 데이터를 보호하고 올바른 값을 유지하도록 하며, 코드의 중복을 제거하여 코드의 불일치로 인한 오동작을 방지할 수 있다.
  2. 클래스와 객체
    1. 클래스와 객체의 정의와 용도
    2. 객체와 인스턴스
      1. 클래스로부터 객체를 만드는 과정을 클래스의 인스턴스화(instantiate)라고 하며, 어떤 클래스로부터 만들어진 객체를 그 클래스의 인스턴스(instance)라고 한다.
      2. 우리가 문자열을 입력받을 때 자주 사용하는 코드를 예로 들어보자. Scanner scan; scan = new Scannere(system.in); 이란 코드는 Scanner 클래스를 인스턴스화하여 scan인스턴스(객체)를 사용하는 것이다.

    3. 객체의 구성요소 - 속성과 기능
      1. 객체는 속성과 기능의 집합이라 할 수 있다. 그리고 객체가 가지고 있는 속성과 기능을 그 객체의 멤버라 한다. 속성은 멤버변수라 하고, 기능은 메소드라 한다.

    4. 인스턴스의 생성과 사용
      1. 아까 사용한 코드를 다시 예로 들어보자. Scanner scan; scan = new Scannere(system.in); 이란 코드는 Scanner 클래스의 객체를 참조하기 위한 참조변수 scan을 선언하고, Scanner 인스턴스를 선언하여 생성된 인스턴스(객체)의 주소를 참조변수에 저장하는 것이다. 
      2. 인스턴스는 참조변수를 통해서만 다룰 수 있으며, 참조변수의 타입은 인스턴스의 타입과 일치해야 한다.
      3. 참조변수에는 하나의 값(주소)만이 저장될 수 있으므로 둘 이상의 참조변수가 하나의 인스턴스를 가리키는 것은 가능하지 않다.
      4. 자신을 참조하고 있는 참조변수가 하나도 없는 인스턴스는 더이상 사용되어질 수 없으므로 '가비지 컬렉터'에 의해서 자동으로 메모리에서 제거된다.
    5. 객체 배열
      1. 여러 개의 변수를 배열로 다루면 편리한 것처럼 객체도 배열로 다룰 수 있다. 객체의 참조변수가 클래스의 멤버변수와 메소드를 직접 저장하는 것이 아니라 그 주소값을 저장하듯 객체의 배열 역시 객체가 직접 담기는 것이 아니고 그 객체의 주소가 저장된다. 따라서 객체배열은 참조변수의 배열이라 볼 수 있다.
    6. 클래스의 또 다른 정의
      1. 객체지향이론의 관점에서 클래스를 객체를 생성하기 위한 틀, 멤버변수와 메소드로 정의했다면 프로그래밍 관점에서 클래스의 정의와 의미를 정할 수 있다.
      2. 클래스 - 데이터와 함수의 결합
        1. 프로그래밍언어에서 데이터 저장형태는 변수 - 배열 - 구조체 - 클래스의 형태로 발전해왔다. 하나의 데이터를 저장할 수 있던 변수에서 같은 종류인 여러 개의 데이터를 하나의 집합으로 저장할 수 있는 배열로, 배열에서 서로 관련된 여러 데이터를 종류에 관계 없이 하나의 집합으로 저장할 수 있는 구조체로, 구조체에서 데이터와 함수의 결합인 클래스로 발전해왔다.
        2. 데이터와 함수는 구분하여 다뤘지만 함수는 주로 데이터를 가지고 작업하기 때문에 대부분 관계가 깊다. 이를 함께 수행할 수 있도록 정의한 것이 클래스이다. 문자열을 String클래스로 정의한 것도 문자열과 문자열을 다루는데 필요한 함수를 함께 정의하기 위해서이다. 
      3. 클래스 - 사용자정의 타입(user-defined type)
        1. 프로그래밍언어에서 제공하는 기본 자료형(primitive type)외에 프로그래머가 서로 관련된 변수들을 묶어서 하나의 타입으로 새로 추가하는 것을 사용자정의 타입(user-defined type)이라고 한다. 
  3. 변수와 메소드
    1. 선언위치에 따른 변수의 종류
      1. 변수는 선언하는 위치에 따라 클래스변수, 인스턴스변수, 지역변수로 나뉜다. 
      2. 인스턴스변수(instance variable)
        1. 클래스의 인스턴스를 만들기위해 클래스 영역에 선언된다. 인스턴스 변수의 값을 읽어오거나 저장하기 위해서는 먼저 인스턴스를 생성해야한다. 독립적인 저장공간을 가지므로 서로 다른 값을 가질 수 있다. 
      3. 클래스변수(class variable)
        1. 인스턴스변수 앞에 static을 붙이면 클래스변수를 선언할 수 있다. 인스턴스마다 독립적인 저장공간을 갖는 인스턴스 변수와 달리 클래스 변수는 모든 인스턴스가 공통된 저장공간을 공유한다. 인스턴스를 생성하지 않고 바로 사용할 수 있다. 클래스가 메모리에 로딩될 때 생성되어 종료시까지 유지된다. public을 앞에 붙이면 같은 프로그램 내에서 어디서나 접근할 수 있는 전역변수(global variable)의 성격을 갖는다.
      4. 지역변수(local varibale)
        1. 메서드 내 선언되어 메서드 내에서만 사용할 수 있어 메소드가 조욜되면 소멸된다. for과 while문에서 사용된 지역변수도 블럭{}을 벗어나면 소멸되어 사용할 수 없다.
    2. 클래스 변수와 인스턴스 변수
      1. 인스턴스변수는 인스턴스가 생성될 때마다 생성되므로 인스턴스마다 각기 다른 값을 유지할 수 있지만, 클래스 변수는 모든 인스턴스가 하나의 저장공간을 공유하므로 항상 공통된 값을 갖는다.
    3. 메서드
      1. 메서드(method)는 특정 작업을 수행하는 일련의 문장들을 하나로 묶은 것이다. 기본적으로 수학의 함수와 유사하다. 메서드를 사용하여 얻을 수 있는 이점은 크게 세가지로 높은 재사용성(high reusability), 중복된 코드의 제거, 프로그램의 구조화이다. 첫번째로 한번 만들어 놓은 메소드는 여러 번 호출할 수 있고, 다른 프로그램에서도 사용할 수 있다. 두번째로 같은 내용의 문장들이 반복되는 경우 하나의 메소드로 작성하면 전체 소스 코드의 길이도 줄어들고 변경할 때 관리도 쉬워 오류의 가능성이 줄어든다. 
    4. 메서드의 선언과 구현
      1. 메서드는 선언부(header, 머리)와 구현부(body, 몸통)로 이루어져 있다.
      2. 메서드 선언부(method declaration, method header)
      3. 매개변수 선언(parameter declaration)
      4. 메서드의 이름(method name)
      5. 반환타입
      6. 메서드의 구현부
      7. return문
      8. 지역변수: 메서드 내에 선언된 변수를 지역변수라 한다. 
    5. 메서드의 호출
      1. 메서드를 호출해야 구현부{}의 문장들을 수행할 수 있다. 위 sum메소드를 호출하기 위해서는 long sum(int[] a)를 호출해야 한다.
      2. 인자와 매개변수
        1. 메서드를 호출할 때 괄호()안에 지정해준 값을 인자(argument) 또는 인수라고 한다. 인자의 개수와 순서는 매개변수의 개수와 순서에 일치해야 한다.
      3. 메서드의 실행흐름
        1. 같은 클래스 내의 메서드끼리 참조변수를 사용하지 않고도 서로 호출할 수 있지만 static 메서드는 같은 클래스 내의 인스턴스 메소드를 호출할 수 없다. 
    6. return문
      1. 반환값이 있을 때만 return문을 작성했지만 반환값의 유무와 관계없이 모든 메서드에는 하나 이상의 return문이 있어야 한다. 반환타입이 void일 때, return문이 없어도 오류가 나지 않은 이유는 컴파일러가 자동으로 추가했기 때문이다.
      2. 메서드 구현부 작성시 매개변수의 값이 적절한지 확인해야 한다. 적절하지 않은 값이 매개변수를 통해 넘어온다면 그 값을 보정하거나 보정이 불가능하다면 return문을 이용하여 작업을 중단하여 호출한 메소드로 돌아가야 한다.
    7. JVM의 메모리 구조
       JVM은 용도에 따라 메모리를 여러 영역으로 나누어 관리한다. 책에서는 주요 영역인 method area, call stack, heap에 대해 설명하고 있다. 검색해봤을 때 이 영역에는 method area, heap, java stack, pc registers, native method stacks가 있다고 하였다. 책과 내용이 조금 다르므로 나중에 찾아봐야할 것 같다. 일단은 책을 정리하는 것이므로 책의 내용을 기준으로 정리한다.
      1. 메서드 영역(mehotd area): 프로그램 실행 중 어떤 클래스가 사용되면 JVM은 해당 클래스의 클래스파일(*.class)을 읽어 분석하여 클래스 데이터를 이 곳에 저장한다.
      2. 힙(heap): 인스턴스가 생성되는 공간으로 프로그램 실행 중 생성되는 인스턴스는 모두 이 곳에서 생성된다.
      3. 호출스택(call stack 도는 executive stack): 메서드 작업을 위한 메모리 공간을 제공한다. 메소드가 호출되면 호출스택에 호출된 메서드를 위한 메모리가 할당되고, 메서드가 작업을 수행하는 동안 이 메모리에서 지역변수와 연산의 중간결과가 저장된다. 메서드가 작업을 마치면 메모리 공간은 반환되고 비어진다.
         
         호출스택은 메서드가 호출되면 수행에 필요한 만큼의 메모리를 스택에 할당받는다. 메서드가 수행을 마치고나면 사용했던 메모리를 반환하고 스택에서 제거된다. 호출스택의 제일 위에 있는 메서드가 현재 실행중인 메서드이다. 아래에 있는 메서드가 바로 위에 있는 메서드를 호출한 메서드이다. 
    8. 기본형 매개변수와 참조형 매개변수
      1. 자바에서 메서드를 호출할 때 매개변수로 지정한 값을 메서드의 매개변수에 복사해서 넘겨준다. 매개변수 타입이 기본형(primitive type)일 때는 기본형 값이 복사되지만 참조형(reference type)이면 인스턴스의 주소가 복사된다. 따라서 기본형 매개변수는 값을 읽어오기만 할 수 있고 참조형 매개변수는 변수의 값을 읽고 변경할 수 있다.
    9. 참조형 반환타입
      1. 반환타입이 참조형이라는 것은 메서드가 객체의 주소를 반환한다는 것을 의미한다.
    10. 재귀호출(recursive call)
      1. 메서드 내부에서 메서드 자신을 다시 호출하는 것을 재귀호출(recursive call)이라 한다. 재귀호출은 복잡한 코드를 단순하게 바꿀 수 있어 논리적으로 간결하여 알아보기 쉽다. 하지만 비효율적이므로 재귀호출에 드는 비용과 간결함이 주는 이득을 비교하여 후자가 더 큰 경우에만 사용해야 한다. 
      2. return문에서 얘기한 것처럼 재귀호출을 했을 때, 메서드가 종료되지 않는다면 스택에 계속 데이터가 쌓여 스택오버플로우에러가 발생할 것이다.  어떤 값이 매개변수로 들어와도 에러 없이 처리할 수 있도록 매개변수 유효성 검사를 철저하게 해야한다. 
    11. 클래스 메서드(static 메서드)와 인스턴스 메서드
      1. 메서드 앞에 static이 붙어있으면 클래스메서드이고 붙어있지 않으면 인스턴스 메서드이다. 클래스 메서드는 객체를 생성하지 않고도 클래스이름.메서드이름(매개변수)와 같은 형식으로 호출할 수 있지만 인스턴스 메서드는 객체를 생성해야 호출할 수 있다.
      2. 클래스를 설계할 때, 멤버변수 중 모든 인스턴스에 공통으로 사용하는 것에 static을 붙인다.
      3. 클래스 변수(static변수)는 인스턴스를 생성하지 않아도 사용할 수 있다.
      4. 클래스 메서드(static 메소드)는 인스턴스 변수를 사용할 수 없다.
      5. 메서드 내에서 인스턴스 변수를 사용하지 않는다면, static을 붙이는 것을 고려한다.
      6. 클래스의 멤버변수 중 모든 인스턴스에 공통된 값을 유지해야하는 것이 있는지 살펴보고 있으면 static을 붙여준다. 작성한 메서드 중에서 인스턴스 변수나 인스턴스 메서드를 사용하지 않는 것에 static을 붙일 것을 고려한다.
    12. 클래스 멤버와 인스턴스 멤버간의 참조와 호출
      1. 같은 클래스에 속한 멤버들은 인스턴스를 생성하지 않고 참조/호출할 수 있다. 클래스 멤버가 인스턴스 멤버를 참조/호출할 때는 인스턴스를 생성해야한다. 인스턴스 멤버가 존재하는 시점에 클래스 멤버는 항상 존재하지만 클래스 멤버가 존재하는 시점에 인스턴스 멤버가 존재하지 않을 수 있기 때문이다. 하지만 인스턴스멤버끼리 호출할 때는 인스턴스가 존재한다는 것은 이미 인스턴스가 생성된 것이므로 다른 인스턴트도 존재하기 때문에 문제 없다.
        class Oop{
        	void instanceMethod(){}
            static void staticMethod(){}
            
            void instanceMethod2(){
            	instanceMethod(); //O
                staticMethod(); //O
            }
            
            static void staticMethod2(){
            	staticMethod(); //O
                instanceMethod(); //X
                Oop o = new Oop();
                o.instanceMethod(); //O
            }
        }​