클래스와 객체

양성빈·2022년 6월 11일

참고
자바의 정석

클래스와 객체

클래스와 객체의 정의와 용도

클래스는 객체를 생성하는데 사용되며, 객체는 클래스에 정의된 대로 생성된다.

클래스 정의: 클래스란 객체를 정의해 놓은 것이다.
클래스의 용도: 클래스는 객체를 생성하는데 사용된다.

객체란, '실제로 존재하는 것'이며, 우리가 주변에서 보는 책상, 의자, 자동차등 각종 사물들이 객체라고 불린다. 객체가 꼭 실존하는 눈에 보이는것만 생각하시는 분들도 많은데 개념이나 논리적인 즉, 추상적인 개념 혹은 무형적인 것들도 객체라고 불릴 수 있다. 프로그래밍에서 객체는 클래스에 정의된 내용대로 메모리에 생성된 것을 뜻한다.

객체의 정의: 실제로 존재하는 것, 사물 또는 개념
객체의 용도: 객체가 가지고 있는 기능과 속성에 따라 다름
유형의 객체: 책상, 의자, TV, 스마트폰등..
무형의 객체: 수학공식, 프로그램 에러와 같은 논리나 개념

클래스는 객체를 생성하는데 사용될 도구일 뿐 그 이상 그 이하도 아니다. 우리가 객체를 사용하기 위해서는 클래스로부터 객체를 생성하는 과정이 선행되어야 한다.

이론적으로 클래스와 객체의 관계는 힘들수 있어서 아래의 표를 보면 클래스와 객체의 관계를 잘 알 수 있을 것이다.

클래스객체
제품 설계도제품
TV 설계도TV
붕어빵 기계붕어빵

객체를 사용한다는 것은 객체가 가지고 있는 속성과 기능을 사용한다는 뜻이다.

그럼 여기서 의문점이 들것이다. 굳이 클래스를 정의하고 클래스를 통해 객체를 생성하는 이유는 설계도를 통해서 제품을 만드는 것과 같다. 설계도를 구체적으로 잘 만들고 작성해야 제품을 잘 만들듯이 클래스를 잘 작성해야 잘 만들어진 객체를 사용할 수 있을 것이다. 그리고 이 잘 만들어진 객체를 무한대로 만들 수 있어서 개발효율을 늘릴 수 있을 것이다.

JDK에서는 프로그래밍을 위해 많은 수의 유용한 클래스를 기본적으로 제공함으로 이 클래스들을 이용하여 원하는 기능의 프로그램을 쉽게 작성 할 수 있다.

객체와 인스턴스

클래스로부터 객체를 만드는 과정을 클래스의 인스턴스화라고 불리며, 어떤 클래스로부터 만들어진 객체를 그 클래스의 인스턴스라고 한다. 여기서 객체와 인스턴스가 같다고 생각하시는 분들이 많다고 생각할 것이다. 사실 같은 개념은 맞지만 정확히 들어가면 객체는 넓은 의미로 그 하위로 인스턴스가 있다고 생각하면 될것이다. 여러 사물들이 객체가 될수있지만 Tv클래스에서 만든 tv라는 객체는 인스턴스라고 불릴 수 있다.

객체의 구성요소 - 속성과 기능

객체는 속성과 기능이라는 2가지 구성요소로 이루어져 있으며, 일반적으로 객체는 다수의 속성과 기능을 가지고 있다. 그리고 객체가 가지고 있는 속성과 기능을 그 객체의 멤버라고 한다. 즉, 클래스로부터 객체를 생성하면, 클래스에 정의된 속성과 기능을 가진 객체가 만들어지는 것이다.
개발쪽에서 클래스에 정의된 속성을 멤버변수, 기능을 메서드라고 불린다.

속성 = 멤버변수 = 특성 = 필드 = 상태
기능 = 메서드 = 행위

예를 들어서 살펴보자, Tv에 속성으로 색상, 파워, 채널이 존재하며, 기능으로 파워 끄기, 켜기, 채널 올리기, 채널 내리기라는 것이 있다. 이것을 코드로 나타내면 다음과 같다.

class Tv {
	String color;
    boolean power;
    int chanel;
    
    void power() {
		power = !power;
    }
    
    void channelUp() {
		channel++;
    }
    
    void channelDown() {
    	channel--;
    }
}

클래스에 멤버변수와 메서드를 선언하는데 순서는 관계가 없지만, 일반적으로 메서드보단 멤버변수를 먼저 선언하고 멤버변수끼리 메서드는 메서드끼리 모아 놓은것이 일반적이다.

인스턴스의 생성과 사용

클래스명 변수명; // 클래스의 객체를 참조하기 위한 참조변수 선언
변수명 = new 클래스명(); // 객체를 생성 후, 객체의 주소를 참조변수에 저장

Tv t;
t = new Tv();

위의 코드로 어떻게 인스턴스가 생성되고 사용되는지 이해가 안될 수도 있다. 아래의 코드 예제를 보고 확인해보자.

class Tv {
    String color;
    boolean power;
    int channel;

    void power() {
        power = !power;
    }

    void channelUp() {
        ++channel;
    }

    void channelDown() {
        --channel;
    }
}

public class TvTest {
    public static void main(String[] args) {
        Tv t;
        t = new Tv();
        t.channel = 7;
        t.channelDown();
        System.out.println("현재 채널은 " + t.channel + " 입니다.");
    }
}
  1. TV t;
    Tv클래스 타입의 참조변수 t를 선언한다. 메모리에 참조변수 t를 위한 공간이 마련된다. 아직 인스턴스가 생성되지 않았으므로 참조변수로 아무것도 할 수 없다.
  2. t = new Tv();
    연산자 new에 의해 Tv클래스의 인스턴스가 메모리의 빈 공간에 생성된다. 주소가 0x100인 곳에 생성되었다고 가정하자. 이 때 멤버변수는 각 자료형에 해당하는 기본값으로 초기화된다. color는 참조형으로 null이고, power는 boolean형이므로 false, channel은 int형으로 0으로 초기화된다.
    그 다음에는 대입연산자 =에 의헤서 생성된 객체의 주소값이 참조변수 t에 저장된다. 이 후부터 t를 통해서 Tv 인스턴스에 접근할 수 있다. 인스턴스를 다루기 위해서 참조변수가 반드시 필요하다.
  3. t.channel = 7;
    참조변수 t에 저장된 주소에 있는 인스턴스의 멤버변수 channel에 7을 저장한다. 여기서 알수있는 것처럼 인스턴스의 멤버변수를 사용하려면 참조변수.멤버변수와 같이 하면 된다.
  4. t.channelDown();
    참조변수 t가 참조하고 있는 Tv 인스턴스의 channelDown 메서드를 호출한다. channel Down에서 드는 멤버변수 channel에 저장되어 있는 값을 1 감소시킨다.

결론적으로, 인스턴스와 참조변수의 관계는 Tv와 Tv 리모콘 관계라고 생각하면 쉬울 것이다. Tv를 사용하려면 Tv 리모콘으로 제어를 해야하며, 에어컨 리모콘으로 백날 해봤자 작동이 되지 않는다. 즉, 인스턴스와 참조변수는 타입이 일치해야한다.

인스턴스는 참조변수를 통해서만 다룰 수 있으며, 참조변수의 타입은 인스턴스의 타입과 일치해야한다.

⚠️ 주의
같은 클래스로부터 생성되었을지라도, 각 인스턴스의 멤버변수는 서로 다른 값을 유지할 수 있으며, 메서드의 내용은 모든 인스턴스에 대해 동일하다.

그러면 좀 더 심화된 내용을 학습해보자.

class Tv3 {
    String color;
    boolean power;
    int channel;

    void power() {
        power = !power;
    }

    void channelUp() {
        ++channel;
    }

    void channelDown() {
        --channel;
    }
}

public class TvTest3 {
    public static void main(String[] args) {
        Tv3 t1 = new Tv3();
        Tv3 t2 = new Tv3();

        System.out.println("t1의 channel 값은 " + t1.channel + "입니다.");
        System.out.println("t2의 channel 값은 " + t2.channel + "입니다.");

        t2 = t1;
        t1.channel = 7;
        System.out.println("t1의 channel 값을 7로 변경하였습니다.");

        System.out.println("t1의 channel 값은 " + t1.channel + "입니다.");
        System.out.println("t2의 channel 값은 " + t2.channel + "입니다.");
    }
}

위에 코드에서 중요한 코드는 t2 = t1;이다.

t1은 참조변수이므로, 인스턴스의 주소를 저장하고 있다. 이 코드가 수행이 되면, t2가 가지고 있던 값은 잃어버리고 t1에 저장되어 있던 값이 t2에 저장되게 된다. 그렇게 된다면 t2 역시 t1이 참조하고 있던 인스턴스를 같이 참조하게 되고, t2가 참도하던 인스턴스는 더 이상 사용할 수 없게 된다.

자신을 참조하고 있는 참조변수가 없는 인스턴스는 더 이상 사용될 수 없으므로 가비지 컬렉터에 의해 자동적으로 메모리에서 제거된다.

위의 예제를 통해 알 수 있듯이 참조변수에는 하나의 주소만이 저장될 수 있으므로 둘 이상의 참조변수가 하나의 인스턴스를 가리키는 것은 가능하지만, 하나의 참조변수가 여러개의 인스턴스를 가리키는 것은 불가능하다.

객체 배열

많은 수의 객체를 다룰 때는 배열로 다루면 편리할 것이다. 객체 역시 배열로 다루는 것이 가능하며, 이를 객체 배열이라고 한다. 이름이 객체 배열이라고 해서 실제 객체를 담을 수 있는 것은 아니고, 객체의 주소가 저장된다. 사실 객체 배열은 참조변수들을 하나로 묶어놓은 변수 배열인것이다.

Tv t1, t2, t3;

위의 코드를 아래와 같이 배열형태로 바꿀 수 있다.

Tv[] tvArr = new Tv[3];

위의 코드가 수행되면, 길이가 3인 객체 배열인 tvArr이 생성이 되고 각 요소는 참조변수의 기본 값인 null로 초기화 된다. 그리고 이 객체 배열은 3개의 객체의 주소를 저장 할 수 있다.

그런데 가끔 객체배열을 위와 같이 선언하면 객체가 생성된 것이라고 생각하시는 분들이 있다. 객체배열을 선언하는 것은 객체를 다루기 위한 참조변수들이 만들어진 것뿐이지, 객체가 저장되지 않는다. 반드시, 객체를 생성해서 객체배열에 저장하는 것을 잊으면 안된다.

Tv[] tvArr = new Tv[3];

tvArr[0] = new Tv();
tvArr[1] = new Tv();
tvArr[2] = new Tv();

위의 초기화 코드를 간단히 블록형태로 바꿀 수 있다.

Tv[] tvArr = {new Tv(), new Tv(), new Tv()};

객체의 수가 너무 많으면 for문을 이용하여 초기화 작업을 해줄 수 있다.

Tv[] tvArr = new Tv[100];

for (int i = 0; i < tvArr.length; i++) {
	tvArr[i] = new Tv();
}

모든 배열형태가 그랬듯이 객체 배열도 같은 타입의 객체만 저장이 가능하다. 하지만 뒤에 다형성 개념을 배우면 다른 타입의 객체도 저장할 수 있다.

클래스의 또 다른 정의

클래스는 객체를 생성하기 위한 틀이며, 클래스는 속성과 기능으로 정의되어 있다. 이 정의는 객체지향점 관점이고 이번에 프로그래밍 관점에서 생각해보자.

  1. 클래스 - 데이터와 함수의 결합
    변수 -> 배열 -> 구조체 -> 클래스
    하나의 데이터를 다루기 위해 변수를 사용했으며, 같은 종류의 데이터를 효율적으로 사용하기 위해 배열이 나왔으며, 그 후에 구조체라는 것이 등장하여 자료형의 종류에 상관없이 서로 관계가 깊은 변수들을 하나로 묶어서 다뤘다.
    이제까지 우리는 데이터와 함수가 관계없는 것들인걸로 알고 있지만, 사실 함수는 데이터를 다뤄서 실행을 하기 때문에 관계가 정말 깊다. 그래서 자바같은 경우 하나의 클래스에 변수와 함수를 같이 정의하여 함께 다룰수 있게 했다.
    서로 관련된 변수를 정의하고 이들에 대한 작업을 수행하는 함수들을 함께 정의한 것이 클래스이다.
    즉, 이렇게 변수와 이 변수와 관련된 함수를 묶어서 사용하면 서로 유기적으로 연결되어 있어서 작업이 명료해지고 간결해진다.
  1. 변수: 하나의 데이터를 저장할 수 있는 공간
  2. 배열: 같은 종류의 여러 데이터를 하나의 집합으로 저장할 수 있는 공간
  3. 구조체: 서로 관련된 여러 데이터를 종류에 관계없이 하나의 집합으로 저장할 수 있는 공간
  4. 클래스: 데이터와 함수의 결합 (구조체 + 함수)
  1. 클래스 - 사용자정의 타입
    프로그래밍 언어에서 기본적으로 제공해주는 자료형 외에 개발자가 서로 관련된 변수들을 묶어서 하나의 타입으로 새로 추가하는 것을 사용자정의 타입이라고 한다. 자바에서 클래스가 곧 사용자정의 타입이다.
profile
모든 것을 즐길줄 아는 개발자입니다!

0개의 댓글