03. 객체지향 1/3

Last updated - 2024년 11월 21일 Edit Source

    인프런의 부부 개발단 토토님의 즐거운 자바 강의를 정리한 내용


    # 객체지향 프로그래밍

    객체지향 프로그래밍 (Object-Oriented Programming, OOP)은 컴퓨터 프로그래밍의 패러다임 중 하나이다. 객체 지향 프로그래밍은 컴퓨터 프로그램을 명령어의 목록으로 보는 시각에서 벗어나 여러 개의 독립된 단위, 즉 “객체"들의 모임으로 파악하고자 하는 것이다. 각각의 객체는 메시지를 주고 받고 데이터를 처리할 수 있다.


    예를 들어, 자동차를 가지고 싶다고 했을 때, 자동차 설계 도면을 가지고 싶다는 의미는 아니다. 설계 도면을 기반으로 만들어진 자동차를 가지고 싶다는 의미이다. 객체지향 프로그래밍이라는 뜻은 설계도를 통해 돌아가는 프로그래밍이 아니라 이 오브젝트, 인스턴스를 기반으로 돌아간다는 의미이다. 클래스만 가지고는 아무것도 못하고 클래스를 기반으로 인스턴스를 만들어야지만 사용할 수 있는 것이다.


    클래스(Class) : 설계도

    객체(Object) : 설계도를 기반으로 구현하고 싶은 대상

    인스턴스(Instance) : 객체의 생성자를 통해 실체화 한 것


    예시

    1. 컴퓨터(객체)를 만들어보자.
    2. 컴퓨터(객체)는 컴퓨터 설계도(클래스)를 이용해서 만들 것이다.
      • 컴퓨터(객체)에는 CPU, RAM, 파워 등(필드)이 있음
      • 컴퓨터(객체)에는 CPU 구동, RAM에 올리기 등(메서드)이 있음
    3. 컴퓨터(객체)를 만들면 설계도(클래스)대로 작동할 것이라고 기대함
    4. 컴퓨터(객체)를 공장(메모리)에서 만들면 실제 제품(인스턴스)이 생성됨
    5. 컴퓨터(객체)를 실제로 만들 때마다 시리얼 번호(메모리 상 주소)를 붙임

    인스턴스는 우리가 사용하려면 특별한 이름으로 참조(reference)해야 한다.

    • 참조형 변수(Reference Variable)를 선언
    • 참조되지 않은 인스턴스는? 쓰레기(Garbage)
    • new 클래스이름()이라는 것은 클래스 이름에 해당하는 인스턴스를 생성한다는 의미이다.

    1
    
    Book b = new Book();
    
    • 생성자로 인스턴스를 생성해야 책이 만들어지는 것
    • 이 책을 참조하는 변수b이다. Book이라는 생성된 인스턴스를 참조한다.
    • 참조 변수 b 앞의 Book을 레퍼런스 타입이라고 한다.


    • 만약에 참조하는 변수 없이 new Book();만 한다면 Heap에 인스턴스는 생성된 상태이지만, 참조하는 녀석이 없다는 의미
    • 참조하는 변수가 없을 경우 Heap 메모리에 생성된 인스턴스를 사용할 수 없다.
    • 사용할 수 없는 인스턴스는 쓰레기(Garbage)이므로 GC 될 것
    • 다시 말하지만, 참조형 타입은 값을 가지는 것이 아닌 객체를 참조하는 것
      • 참조형 타입의 변수가 주소를 가지는 것처럼 설명하는 사람이나 책이 있는데, 자바는 어떤 주소에 어떤 값이 저장되는 지 알 수 있는 방법이 없다. 자바에는 그런 포인터 연산자가 없으므로 알 수 없다.

    # 클래스

    • 클래스는 필드(Field)와 메서드(Method)를 가진다.
    • 필드는 클래스의 속성이라고 말할 수 있다.
    • 메서드는 클래스의 기능, 행위라고 말할 수 있다.

    # 클래스 선언 방법

    1. 클래스 앞에는 접근제한자(public, private, protected, default(없음))가 붙는다.

    2. 클래스 이름

      1. 첫 문자가 문자, _, $의 특수문자로 시작되어야 하고 숫자로 시작할 수 없다. (참고로 한글도 가능하다)
      2. 첫 문자가 아니라면 문자, _, $, 숫자로 구성될 수 있다. JDK 8에서는 _ 한 글자로 이루어진 변수는 예약어로 정의되어 있기 때문에 사용할 수 없다.
      3. 자바의 예약어는 식별자로 사용할 수 없다.
      4. 자바의 식별자는 대소문자를 구분한다.
      5. 식별자 길이는 제한이 없고 공백은 포함할 수 없다.
    3. 클래스 이름 관례

      • 클래스 명은 대문자로 시작
      • 단어와 단어가 만날 경우 2번째 단어의 시작은 대문자로 시작
        • HelloWorld 같이 적는 것, 이를 카멜 표기법이라고 함
    1
    2
    3
    4
    5
    
    접근제한자 class 클래스이름 {
    	필드들 ;
    	생성자들 ;
    	메서드들 ;
    }
    

    # 클래스 다이어그램



    1. static이 붙은 메서드는 클래스 메서드

      • 클래스 메서드는 인스턴스를 생성하지 않아도 사용 가능
      • 사용 가능하다는 것은 메모리에 올라가있다는 의미
    2. VendingMachineMain은 VendingMachine에 의존한다.

      • main 메서드가 동작하려면 VendingMachine 클래스 필요
        • main 메서드가 쓰고 있으니까 필요한 것, 없으면 컴파일 에러
      • 메서드 안에서 사용하는 것은 의존한다는 의미
      • VendingMachineMain은 main(String[] args)를 쓰니까 당연히 String 클래스에도 의존한다는 의미

    # 클래스의 인스턴스 생성

    인스턴스를 만드는 3가지 방법

    1. new 연산자와 생성자를 이용하여 인스턴스를 만드는 방법
    2. 클래스로더를 이용하는 방법
    3. 메모리에 있는 인스턴스를 복제(clone)하여 만드는 방법

    2번 3번은 나중에 설명, 1번만 일단 이해하자


    인스턴스를 만들 떄마다 메모리에 인스턴스가 생성되기에 필요한 개수만큼 잘 만드는 것은 매우 중요하다. 객체지향 프로그래밍에서 인스턴스 생성은 굉장히 중요하기 때문에 디자인 패턴에도 분류된다.

    • 디자인 패턴 : 클래스를 작성하는 패턴
      • 3가지 카테고리 중 인스턴스 생성 패턴이 있음. 그정도로 굉장히 중요!

    # 메서드

    # 메세지 교환

    앨런 커티스 케이형이 말했다. 객체지향의 핵심은 “메시징"이다 !

    • 훌륭하고 성장 가능한 시스템을 만들기 위한 핵심은 모듈 내부의 속성과 행동이 어떠한가보다 모듈이 어떻게 커뮤니케이션하는가에 달려있다.
    • 객체지향 프로그래밍을 한다는 것은 메서드가 언제 호출되고, 어떻게 호출될까? 메서드의 이름은 어떻게 지어야 할까? 어떻게 호출해야 할까?를 고민해야 한다.

    객체는 자율적인 책임을 가진다.

    • 객체지향의 사실과 오해 책에 나오는 말
    • 자율적인 객체란 스스로 정한 원칙에 따라 판단하고 스스로의 의지를 기반으로 행동하는 객체
    • 객체가 어떤 행동을 하는 유일한 이유는 다른 객체로부터 요청을 수신했기 때문
    • 요청을 처리하기 위해 객체가 수행하는 행동을 책임이라고 함
    • 자율적인 책임의 특징은 객체가 어떻게 해야 하는가가 아니라 무엇을 해야하는가를 설명한다는 것이다.

    메시징은 객체가 다른 객체의 메서드를 호출하는 것이라고 했고, 객체가 어떤 행동을 하는 유일한 이유는 이 객체의 메서드를 다른 객체가 호출했을 때이다. 즉, 핵심은 객체는 기능이 호출되었을 때 그에 맞는 기능을 하는 책임을 가지고 있다는 의미이다.


    자판기의 동전 잔액을 보여주는 디스플레이 장치가 있다고 하면 어떤 책임이 있을까? 사용자가 넣은 동전의 정보를 정확히 표시해주는 책임이 있다. 상품 선택 버튼을 눌렀을때? 버튼은 잘 동작해야한다. 버튼에도 책임이 있다.


    메서드 선언 방법

    1
    2
    3
    4
    5
    6
    
    [접근제한자] [static] 리턴타입 메서드이름([매개변수, ...]) {
    	실행문
    	.....
    }
    
    // [] 대괄호는 생략가능하다는 의미
    
    • 클래스 이름은 대문자로 시작하는 것이 관행
    • 메서드 이름은 소문자로 시작하는 것이 관행

    헷갈리지말자!!!

    매개변수(parameter) : 메서드의 정의부분에 나열되어 있는 변수들을 의미
    전달인자(argument) : 메서드를 호출할 때 전달되는 실제 값


    # 메서드 선언방법

    • 들어가는 것이 매개변수 나오는 것이 return







    # static 메서드

    static한 메서드는 인스턴스를 생성하지 않아도 호출할 수 있다.

    • static 메서드는 인스턴스를 만들지 않아도 사용할 수 있다 !!!!!!!!
    1
    2
    3
    4
    5
    
    public class VendingMachine {  
        public static void printVersion() {  
            System.out.println("v1.0");  
        }  
    }
    

    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    public class VendingMachineMain {
    	public static void main(String[] args) {
    		VendingMachine vm1 = new VendingMachine();
    		// 이렇게 쓰지말자
    		vm1.printVersion();
    		// 이렇게 쓰자. 다른 사람을 위해서!
    		VendingMachine.printVersion();
    	}
    }
    

    이렇게, 인스턴스를 생성하고 사용하는 것도 가능은 하다

    • 하지만, 프로그래머끼리 관례상 static 메서드는 인스턴스.static메서드() 이렇게 쓰지말자
    • 클래스.static메서드() 이렇게 쓰자

    # 메서드 실행 시 발생하는 일

    먼저, 자바 파일이 어떻게 실행되는지 알아보자. JVM은 어떤 경로에서 클래스 파일을 찾을까? 현재 폴더에 Hello.class 파일이 있다고 하더라도 현재 폴더에서 찾는다고 하면 틀렸다.

    javac Hello.java

    • 틀린 답 ) 현재 폴더에서 찾는다.
    • 정답 ) JVM은 CLASSPATH 경로에서 클래스를 찾는다.
      • CLASSPATH=. 이라고 하면 CLASSPATH 경로가 현재 폴더(.)으로 찎혀있다고 하면 현재 폴더에서 찾는 것이다.
      • 인텔리제이는 소스를 컴파일하고 out/production/프로젝트폴더 아래에 class 파일을 생성하기 때문에 해당 경로를 CLASSPATH로 인식하게 해준다.


    블로그 포스팅을 참조하며 글을 읽도록 하자.

    java VendingMachineMain

    1. CLASSPATH에서 VendingMachineMain 클래스를 찾는다.
      • JVM은 읽어들인 클래스 정보를 Metaspace라는 Native Memory 영역에 저장한다.
      • 인스턴스가 아니라 클래스 자체에 대한 정보가 올라가는 것이다.
    2. JVM은 프로그램 시작점인 main 메서드를 metaspace에 저장된 VendingMachineMain에서 먼저 찾고 실행한다.
    3. JVM Stack이라고 불리는 메모리 영역에 실행된 메서드 정보를 올린다.
      • 스택은 FILO (First In Last Out) 자료구조
      • JVM Stack에 저장된 메서드 실행 정보 1개는 스택 프레임(Stack Frame)에 있다.
      • main 메서드 안에 선언된 변수들은 스택 프레임에 저장되고 이러한 변수를 지역(local) 변수라고 한다.
    4. main에 있는 String[] String 배열 인스턴스가 Heap 메모리에 생성된다.
      • 이 인스턴스를 args 변수가 참조한다. Stack Frame -> Heap
    5. PC(Program Counter) Register를 통해 몇 번째 줄을 실행하고 있는지에 대한 정보도 기억하고 있다.

    즉, 메서드가 실행될 때마다 JVM stack에 하나씩 올라가는 것이다.

    • FILO 구조이니까 차곡차곡 쌓이는 것이다.
    • 다쓰고 나면 빼서 제거하는 원리니까 당연히 main 메서드가 제일 아래에 위치
    • 지역 변수는 메서드가 종료되면 사라진다. 스택에서 빠지니까. 즉, 메서드가 호출될 때 생성, 메서드가 종료될 때 지역변수 사라짐
      • 만약, 같은 메서드를 동시에 10번 호출한다고 해도 그 메서드 안의 지역 변수는 각각 다른 영역에 저장되어 사용됨. 스레드마다 영역 다르니까.
      • 즉, 동시에 메서드가 호출되어도 문제가 없다.
      • 하지만, 메서드에서 클래스 안에 선언된 변수를 사용할 경우 문제가 발생할 수 있음

    # Math Class

    자바 API란 자바 개발자가 제공하는 명령어를 의미하고 API 문서란 이런 명령어들의 사용법과 규격을 제공하는 문서이다. Math Class를 Java Math API 문서에서 보도록 하자.


    • Math Class가 가지고 있는 메서드는 모두 static한 메서드
    • 이 말은 인스턴스를 만들 필요 없이 사용하다는 의미! 모든 필드와 메서드를!
    1
    2
    3
    4
    5
    6
    7
    8
    
    public class MathTest {  
        public static void main(String[] args) {  
            int value = Math.abs(-5);  
            System.out.println(value);  
        }  
    }
    
    // 이렇게 인스턴스 안만들고 바로 사용 가능하다는 의미
    

    # private

    그런데, Math 클래스를 인스턴스 생성하여 사용하려고 하면 컴파일에러가 뜬다.

    • 이 클래스를 만든 사람은 일부러 인스턴스 생성 안해도 사용할 수 있게 만든건데, 쓰는 사람이 인스턴스 생성해서 쓰면 메모리 낭비니까 강제로 막아뒀음

    접근제한자를 public이 아닌 private으로 바꾸면, 해당 클래스 안에서만 접근 가능하다.

    • 즉, 다른 클래스에서 인스턴스를 만들어서 사용할 수 없다.
    • 인스턴스를 생성하지 못하면 인스턴스 메서드는 사용할 수 없고 static이 붙은 클래스 메서드만 사용할 수 있다.
    • 여러 개 인스턴스를 생성하지 못하게 하고 강제로 static한 메서드만 사용하도록 하고싶으면 클래스 생성자의 접근제한자를 private으로 하면 됨

    Comment