1. 객체지향 이론, 언어

객체지향 이론

객체 지향 이론은 '실제 세계는 사물(객체)로 이루어져 있으며 발생하는 모든 사건들은 사물간의 상호작용이다.'를 기본개념으로 한다.
객체 지향 이론은 상속, 캡슐화, 추상화 개념을 중심으로 발전하였다.

객체지향 언어

  1. 코드의 재사용성이 높다.
    • 새로운 코드를 작성할 때 기존의 코드를 이용하여 쉽게 작성할 수 있다.
  2. 코드의 관리가 용이하다.
    • 코드간 관계를 이용하여 적은 노력으로 쉽게 코드를 변경할 수 있다.
  3. 신뢰성 높은 프로그래밍을 가능하게 한다.
    • 제어자와 메서드를 이용하여 데이터를 보호하고 올바른 값을 유지하도록 하며, 코드의 중복을 제거하여 코드의 불일치로 인한 오동작을 방지할 수 있다.

2. 클래스, 객체

  • 클래스 : 객체를 정의해 놓은것, 객체를 생성할 때 사용된다.
  • 객체(인스턴스) : 실제로 존재하는 것, 사물 또는 개념

2.1 객체의 구성요소

  • 속성 : member variable, attribute, field, state
  • 기능 : method, function, behavior
// class
class Tv {
   // member variable
   String color;
   boolean power;
   int channel;

   // method
   void power() {power = !power; }
   void channelUp (){ ++this.channel; }
   void channelDown() { --this.channel; }
}

class TvTest {
   public static void main(String args[]) {
      Tv t;          // t : Tv인스턴스를 참조하기위한 변수 t
      t = new Tv();  // 인스턴스 생성
      t.channel = 7;
      t.channelDown();
      ...
   }
}

📋 자바 명명 규칙 가이드

  1. Class, Interface : 명사여야 하며 대문자로 시작하여야 한다.
  2. Method : 동사여야하며, 소문자로 시작한다. 붙이는 단어의 경우 붙이는 단어 첫문자를 대문자로 쓴다. ex) isFunny(){}
  3. 변수 : 소문자로 시작하며, 두글자 이상을 권장한다.
  4. 상수 : 모든 글자에 대문자를 사용한다.
  5. 패키지 : 모든 글자를 소문자로 사용한다.

2.2 인스턴스 생성시 메모리 구조

| color         | <-지역변수-> <--0x100-->
| power         |
| channel       | 
| power()       | <--메서드-->
| channelUp()   |
| channelDown() |

2.3 인스턴스 생성 및 사용

  1. Tv t;
    • 참조 변수 t를 위한 공간 생성
  2. t = new Tv();
    • 연산자 new에 의해 인스턴스가 메모리의 빈공간에 할당.
    • 멤버변수는 각 자료형의 기본값으로 초기화
    • 생성된 인스턴스의 주소값은 참조변수 t에 저장(t를 통해 객체에 접근 가능)
Tv t1 = new Tv();
Tv t2 = new Tv();
  1. t2 = t1
    • t1는 참조변수이므로 인스턴스의 주소를 저장하고있다.
    • t2는 대입연산자에 의해 t1의 주소를 t2에 저장한다.
    • 기존 t2가 가리키고 있던 인스턴스(객체)는 참조변수가 하나도 없게 된다.
      • 이러한 인스턴스는 Garbage Collector에 의해 자동적으로 메모리에서 제거된다.

2.4 프로그래밍 관점에서의 클래스에대한 정의

객체지향이론의 관점에서 클래스는 객체를 생성하기 위한 틀로 속성과 기능으로 정의되어있다.

프로그래밍적 관점에서의 클래스는 다음과 같은 발전과정을 거쳤다.

변수 -> 배열 -> 구조체(자료형이 다른 변수) -> 클래스(구조체 + 함수)

함수는 많은 경우에 있어데이터를 가지고 작업을 하기 때문에 데이터와 함수는 관계가 깊다. 따라서 자바와 같은 객체지향 언어에서는 변수와 함수를 하나의 클래스에 정의하여 서로 관계가 깊은 변수와 함수들을 함께 다룰 수 있게 하였다.

다음과 같이 클래스의 멤버 변수를 직접 접근하지 않고 get(), set()메서드를 통해 접근하게 하면, 보다 정확한 데이터를 유지하는데 도움이 된다.

public class Time() {
   private hour;
   ...
   public int getHour();
   public int setHour();
   ...
}

3. 변수와 메서드

3.1 선언 위치에 따른 변수의 종류

class Variable {
   static int cv;    // 클래스 변수
   int iv;           // 인스턴스 변수

   void method() {
      int lv = 0;    // 지역변수 
   }
}
종류 위치 생성 시기
클래스변수 클래스 영역 클래스가 메모리에 올라갈때
인스턴스 변수 클래스 영역 인스턴스가 생성되었을때
지역변수 클래스 영역 이외의 영역 변수 선언문이 수행되었을 때

클래스 변수

  • 인스턴스를 생성하지 않고도 언제든지 사용할 수 있다.
  • 메모리에 로딩되어 프로그램이 종료될 때 까지 유지된다.
  • 클래스 변수를 통해 모든 인스턴스가 하나의 저장공간을 공유하게 하여 공통된 값을 갖도록 할 수 있다.

인스턴스 변수

  • 인스턴스가 생성될 때 마다 생성되므로 각기 다른 값을 유지할 수 있다.

3.2 메서드

메서드를 사용하는 이유

  1. 높은 재사용성
  2. 중복된 코드의 제거
  3. 프로그램의 구조화
  • 같은 클래스 내의 메서드 끼리는 참조변수를 사용하지 않고도 서로 호출이 가능하지만, static메서드는 같은 클래스 내의 인스턴스 메서드를 호출할 수 없다.
    • 인스턴스 변수는 인스턴스가 생성된 후에나 사용할 수 있음.

3.3 JVM 메모리 구조

  1. Method Area(메서드 영역)
    • 프로그램 실행 중 어떤 클래스가 사용되면, JVM은 해당 클래스의 클래스 파일을 읽어서 분석하여 클래스에 대한 정보를 이곳에 저장한다. 이때 클래스 변수도 이영역에 함께 생성된다.
  2. Call Stack(호출 스택)
    • 메서드의 작업에 필요한 메모리 공간을 제공함. 메서드가 작업을 수행하는 동안 지역 변수, 연산의 중간 결과를 저장하는데 사용되며, 메서드가 반환되면, 메모리공간도 반환되어 비워진다.
    • 참조변수 또한 이영역에 저장되어 힙영역의 인스턴스를 가리키는 역할을 한다.
  3. Heap(힙)
    • 인스턴스가 생성되는 공간으로 인스턴스 변수가 이곳에 생성된다.

3.4 매개변수 : 참조형, 기본형

static void change(int x)              // x는 기본형 매개변수
static void changeClass(Data d)        // d(클래스 인스턴스)는 참조형 매개변수
static void changeArray(int add[] arr) // arr(배열)은 참조형 매개변수

메서드 호출시 매개변수의 타입이 기본형(primitive type)이면 매개변수의 값이 복사되지만, 참조형(reference type)이면 인스턴스의 주소가 복사된다.

기본형 매개변수는 변수의 값을 읽기만 할 수 있지만, 참조형 매개변수는 변수의 값을 읽고 변경할 수 있다.

4. 오버로딩

4.1 오버로딩 조건

  1. 메서드 이름이 같아야 한다
  2. 매개변수의 개수 또는 타입이 달라야 한다.
void println();
void println(boolean x);
void println(char x);
void println(char[] x);
void println(double x);
void println(float x);
...

4.2 가변인자 오버로딩

<타입>... 변수명의 형식으로 선언한다.

public PrintStream printf(String format, Object... args);

가변인자는 매개변수들 중 가장 마지막에 선언되어야 한다.

가변인자는 내부적으로 배열을 이용한다. 하지만 매개변수 타입을 배열로 하는것과 달리 인자를 생략할 수도있고, null이나 길이가 0인 배열도 인자로 포함할 수 있다.

인자로 배열을 사용한 경우

String concatenate(String[] str);
String result = concatenate(new String[0]);
String result = concatencate(null);
String result = concatenate();

가변인자를 사용한 메서드는 가능하면 오버로딩 하지 않는게 좋다. 다음과 같은 경우에 에러가 발생할 수 있다.

static String concatenate(String delim, String... args) {...}
static String concatenate(String... args) {...}

컴파일시 두 오버로딩된 메서드가 구분되지 않아 에러가 발생할 수 있다. 따라서 가능하면 가변인자를 사용한 메서드는 오버로딩 하지 않는것이 좋다.

5. 생성자

5.1 생성자 기본

  1. 생성자의 이름은 클래스의 이름과 같아야 한다.
  2. 생성자는 반환 값이 없다.
class Card {
   Card() { // class name = method(constructor) name
      ...
   }
   Card(String k, int num) {
      ...
   }
}

모든 클래스에는 하나 이상의 생성자가 정의되어있어야 한다. 하지만 실제로 인스턴스 생성시 생성자 없이도 인스턴스를 생성할 수 있었는데 이는 기본 생성자 덕분이다.

기본생성자는 컴파일러가 자동적으로 추가하는 생성자로, 특별히 인스턴스 초기화 작업이 필요하지 않다면, 기본생성자를 사용하는 것도 좋다.

class Data {
   int val;

   Data(int x) {
      this.val = x;
   }
}

class Test {
   public static void main(String argsp[]) {
      Data d1 = new Data();      // 컴파일 에러 발생 
      Data d2 = new Data(5);
   }
}

위의 Data클래스에 대한 인스턴스를 매개변수 없이 생성할때 컴파일 에러가 발생한다. 매개변수가 있는 생성자가 존재하므로 컴파일러는 기본 생성자를 추가하지 않아 매개변수가 없는 생성자는 정의되지 않는다.

즉 기본 생성자가 컴파일러에 의해서 추가되는 경우는 클래스에 정의된 생성자가 하나도 없을 때 뿐이다.

5.2 다른 생성자 호출

  • 생성자의 이름으로 클래스이름 대신 this를 사용한다.
  • 한 생성자에서 다른 생성자를 호출할 때는 반드시 첫 줄에서만 호출이 가능하다.

에러가 발생하는 경우

Car(String color) {
   door = 5;
   Car(color, "auto", 4);
}

수정

Car(String color) {
   this(color, "auto", 4);
   door = 5;
}

this는 참조변수로 인스턴스 자신을 가리킨다. 참조변수를 통해 인스턴스의 멤버에 접근할 수 있듯, this를 통해 인스턴스 변수에 접근할 수 있다.

5.3 생성자를 통한 인스턴스 복사

class Car {
   int a;
   String b;
   float c;
   Car() {
      this(10, "kk", "5.1");
   }
   Car(Car ca) {
      /*
      a = ca.a;
      b = ca.b;
      c = ca.c;
      */
      this(ca.a, ca.b, ca.c); // 기존의 코드를 재활용하는것이 바람직 하다
   }
}

6. 변수의 초기화

6.1 초기화 블럭

클래스 초기화 블럭

  • 클래스 변수의 복잡한 초기화에 사용된다
  • 클래스 로드시 한번만 수행
  • 인스턴스 초기화 블럭*
  • 인스턴스 변수의 복잡한 초기화에 사용된다
  • 인스턴스가 생성될때 마다 수행된다.
    // 클래스 초기화 블럭
    static {
     ...
    }
    

// 인스턴스 초기화 블럭
{
...
}


```java
class BlockTest {
   int a;
   static int[] arr = new int[10];
   static {
      for(int i = 0; i < 10; i++) {
         arr[i] = (int)(Math.random() * 10 + 1);
      }
   }

   {
      a = (int)(Math.random() * 10 + 1);
   }
}
class Car {
    static int num = 0;
    static { 
        System.out.println("Class loaded");
    }

    {
        System.out.println(num++ + "번째 차");

    }
}
public class App {
    public static void main(String[] args) {
        Car c1 = new Car();
        Car c2 = new Car();

    }
}

image

6.2 초기화 시기와 순서

- 클래스 변수 인스턴스 변수
시점 클래스가 처음 로딩될때 단 한번 인스턴스가 생성될때마다 인스턴스 별로
순서 기본값 -> 명시적 초기화 -> 클래스 초기화 블럭 기본값 -> 명시적 초기화 -> 인스턴스 초기화 블럭 -> 생성자

+ Recent posts