[자바의 정석] CHAPTER 6: 객체지향 프로그래밍 Ⅰ

26603 단어 자바자바

1. 객체지향언어

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

2. 클래스와 객체

객체와 인스턴스

class Tv{ 
    // TV의 속성(멤버변수)
    String color; // 색상
    boolean power; // 전원상태(on/off)
    int channel; // 채널

    void power(){power = !power;} // tv를 켜거나 끄는 기능을 하는 메서드
    void channelUp(){++channel;} // tv의 채널을 높이는 기능을 하는 메서드
    void channelDown(){--channel;} // tv의 채널을 낮추는 기능을 하는 메서드
}

public class TvTest {
    public static void main(String args[]){
        Tv t1 = new Tv(); // tv 인스턴스를 참조하기 위한 변수 t를 선언하고, 인스턴스 생성한다.
        Tv t2 = new Tv();
        t1.channel = 7; // tv 인스턴스의 멤버변수 channel의 값을 7로 한다.
        t1.channelDown(); // tv 인스턴스의 메서드를 호출한다.
        System.out.println("현재 채널은 " + t1.channel + "입니다.");
    }
}
  • 참조변수에는 하나의 값(주소)만 저장될 수 있으므로 둘 이상의 참조변수하나의 인스턴스를 가리키는 것은 가능하지만 하나의 참조변수여러 개의 인스턴스를 가리키는 것은 가능하지 않다.

클래스

  • 객체지향이론의 관점
    • 객체를 생성하기 위한 틀 / 클래스는 속성과 기능으로 정의되어있다.
  • 프로그래밍적인 관점
    • 데이터와 함수의 결함
    • 데이터와 함수는 관계가 깊다.

c언어에서는 문자열을 문자의 배열로 다루지만, 자바에서는 String이라는 클래스로 다루는 이유?
문자열과 문자열을 다루는데 필요한 함수들을 함께 묶기 위해서이다.

3. 변수와 메서드

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

  • 멤버변수
    • 클래스변수(static 변수, 공유변수)
      • 인스턴스를 생성하지 않고도, 언제라도 바로 사용할 수 있다.
    • 인스턴스변수
      • 인스턴스 생성후에 사용가능하다.
  • 지역변수
    • 지역변수가 선언된 블럭{} 내에서만 사용가능하다.

    메서드를 사용하는 이유

  1. 높은 재사용성
    한번 만들어 놓은 메서는 몇번이고 호출할 수 있다.
  2. 중복된 코드의 제거
    반복적으로 나타나는 문장들을 메서드로 만들어서 사용하면 코드의 중복이 제거되고, 변경사항이 발생했을 때 이 메서드만 수정하면 된다.
  3. 프로그램의 구조화
    전체흐름이 한눈에 들어올 정도록 단순하게 구조화하는 것이 좋다. 프로그램에 문제가 발생해도 해당 부분을 쉽게 찾아서 해결할 수 있다.

JVM의 메모리 구조

  • 기본형 매개변수
    • 원본이 아니라 복사본이 변경
class Data{
    int x;
}

public class PrimitiveParamEx {
    public static void main(String args[]) {
        Data d = new Data();
        d.x = 10;
        System.out.println("main() : x = " + d.x);

        change(d.x);
        System.out.println("After change(d.x)");
        System.out.println("main() : x = " + d.x);
    }

    static void change(int x) {
        x = 1000;
        System.out.println("change() : x = " + x);
    }
}
change() : x = 1000
After change(d.x)
main() : x = 10
  • 참조형 매개변수
    • 값이 아니라 값이 저장된 주소를 넘겨준다.
class Data{
    int x;
}

public class ReferenceParamEx {
    public static void main(String[] args) {
        Data d = new Data();
        d.x = 10;
        System.out.println("main() : x = " + d.x);

        change(d);
        System.out.println("After change(d)");
        System.out.println("main() : x = " + d.x);
    }

    static void change(Data d) {
        d.x = 1000;
        System.out.println("change() : x = " + d.x);
    }
}
main() : x = 10
change() : x = 1000
After change(d)
main() : x = 1000
  • 반환타입이 참조형이라는 것은 메서드가 객체의 주소를 반환한다는 것을 의미한다.

클래스 메서드와 인스턴스 메서드

  1. 클래스를 설계할 때, 멤버변수 중 모든 인스턴스에 공통으로 사용하는 것에 static을 붙인다.
  • 생성된 각 인스턴스는 서로 독립적이기 때문에 각 인스턴스 변수는 서로 다른 값을 유지한다. 그러나 모든 인스턴스에서 같은 값이 유지되어야 하는 변수는 static을 붙여서 클래스변수로 정의해야 한다.
  1. 클래스 변수(static변수)는 인스턴스를 생성하지 않아도 사용할 수 있다.
  • static이 붙은 변수는 클래스가 메모리에 올라갈 때 이미 자동적으로 생성되기 때문이다.
  1. 클래스 메서는 인스턴스 변수를 사용할 수 없다.
  • 인스턴스변수는 인스턴스가 반드시 존재해야만 사용할 수 있는데, 클래스메서드는 인스턴스 생성 없이 호출이 가능하므로 클래스 메서드가 호출되었을 때 인스턴스가 존재하지 않을 수도 있다.
  • 인스턴스변수나 인스턴스메서드에는 static이 붙은 멤버들을 사용하는 것이 언제나 가능하다.
  1. 메서드 내에서 인스턴스 변수를 사용하지 않는다면, static을 붙이는 것을 고려한다.
  • 메서드의 작업내용 중에서 인스턴스 변수를 필요로 한다면, static을 붙일 수 없다.
  • 인스턴스 변수를 필요로 하지 않는다면, static을 붙이자.
    • 메서드 호출시간이 짧아지므로 성능이 향상된다.
 class MyMath{
    long a, b;
    
    long add() { return a + b;}
    long subtract() { return a - b;}
    
    static long add(long a, long b) { return a + b;}
    static long subtract(long a, long b) { return a - b;}
}

public class MyMathTest {
    public static void main(String[] args) {
    	// 클래스 메서드 호출. 인스턴스 생성없이 호출가능
        System.out.println(MyMath.add(200, 201));
        System.out.println(MyMath.subtract(200, 201));

        MyMath mm = new MyMath();
        mm.a = 200; 
        mm.b = 201;
        // 인스턴스 메서드는 객체생성 후에만 호출이 가능함
        System.out.println(mm.add());
        System.out.println(mm.subtract());
    }
}

4. 오버로딩

오버로딩의 조건

  1. 메서드 이름이 같아야 한다.
  2. 매개변수의 개수 또는 타입이 달라야 한다.
  3. 반환타입은 오버로딩을 구현하는데 아무런 영향을 주지 못한다.

가변인자와 오버로딩

public class VarArgxEx {
    public static void main(String[] args) {
        String[] strArr = {"100", "200"};

        System.out.println(concatenate("", "100", "200")); // 컴파일에러 발생
        System.out.println(concatenate("", strArr));


    }

    static String concatenate(String delim, String... args) {
        String result = "";
        for (String str : args) {
            result += str + delim;
        }
        return result;
    }

    static String concatenate(String... args) {
        return concatenate("", args);
    }
}
  • 가변인자를 선언한 메서드를 오버로딩하면, 메서드를 호출했을 때 구별되지 못하는 경우가 발생하기 쉽다.
  • 가능하면 가변인자를 사용한 메서드는 오버로딩하지 않는 것이 좋다.

5. 생성자

생성자란?

인스턴스가 생성될 때 호출되는 인스턴스 초기화 메서드이다.
인스턴스 생성 시에 실행되어야 할 작업을 위해서도 사용된다.

생성자에서 다른 생성자 호출하기 - this(), this

  • 생성자의 이름으로 클래스이름 대신 this를 사용한다.
  • 한 생성자에서 다른 생성자를 호출할 때는 반드시 첫줄에서만 호출이 가능하다.
    • 생성자 내에서 초기화 작업도중에 다른 생성자를 호출하게 되면, 호출된 다른 생성자 내에서도 멤버변수들을의 값을 초기화할 것이므로 다른 생성자를 호출하기 이전의 초기화 작업이 무의미해질 수 있다.(로직이 복잡해져서?)
  • this : 인스턴스 자신을 가리키는 참조변수, 인스턴스의 주소가 저장되어 있다. 모든 인스턴스 메서드에 지역변수로 숨겨진 채로 존재한다.
  • this(), this(매개변수) : 생성자, 같은 클래스의 다른 생성자를 호출할 때 사용한다.

6. 변수의 초기화

  • 멤버 변수는 초기화를 하지 않아도 자동적으로 변수의 자료형에 맞는 기본값으로 초기화가 이루어진다.
  • 지역변수는 사용하기 전에 반드시 초기화해야 한다.

멤버 변수의 초기화 방법

  1. 명시적 초기화
  • 변수를 선언과 동시에 초기화하는 것
  1. 생성자
  2. 초기화 블럭
  • 인스턴스 초기화 블럭: 인스턴스변수를 초기화 하는데 사용
  • 클래스 초기화 블럭: 클래스변수를 초기화 하는데 사용

클래스 초기화 블럭은 클래스가 메모리에 처음 로딩될 때 한번만 수행
인스턴스 초기화 블럭은 생성자와 같이 인스턴스를 생성할 때마다 수행
생성자보다 인스턴스 초기화 블럭이 먼저 수행
클래스가 처음 로딩될 때 클래스 변수들이 자동적으로 메모리에 만들어지고, 클래스 초기화블럭이 클래스변수들을 초기화

멤버변수의 초기화 시기와 순서

  • 클래스 변수의 초기화 시점: 클래스가 처음 로딩될 때 단 한번 초기화된다.
  • 클래스 변수의 초기화 순서: 기본값 -> 명시적 초기화 -> 클래스 초기화 블럭
  • 인스턴스 변수의 초기화 시점: 인스턴스가 생성될 때마다 각 인스턴스별로 초기화가 이루어진다.
  • 인스턴스 변수의 초기화 순서: 기본값 -> 명시적 초기화 -> 인스턴스 초기화 블럭 -> 생성자

좋은 웹페이지 즐겨찾기