ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [ch6 자바 객체] 클래스의 정의와 변수의 종류
    프로그래밍 언어/JAVA 2022. 6. 14. 17:33

     

    클래스의 정의 1 - 데이터와 함수의 결합

    클래스는 '객체를 생성하기 위한 틀'이며 '클래스는 속성과 기능으로 정의되어있다.' 이것은 객체지향이론의 관점에서 내린 정의이고, 프로그래밍적인 관점에서 살펴보자.

    1. 변수 : 하나의 데이터를 저장하는 공간
    2. 배열 : 같은 종류의 여러 데이터를 하나의 집합으로 저장할 수 있는 공간
    3. 구조체 : 서로 관련된 여러 데이터를 종류에 관계없이 하나의 집합으로 저장할 수 있는 공간
    4. 클래스 : 데이터와 함수의 결합(구조체 + 함수)

     

    그동안 데이터와 함수가 서로 관계없는 것처럼 데이터는 데이터끼리, 함수는 함수끼리 따로 다루어져 왔지만, 사실 함수는 주로 데이터를 가지고 작업을 하기 때문에 많은 경우에 있어서 데이터와 함수는 관계가 깊다. 

    그래서 자바와 같은 객체지향언어에서는 변수(데이터)와 함수를 하나의 클래스에 정의하여 서로 관계가 깊은 변수와 함수들을 함께 다룰 수 있게 했다.  서로 관련된 변수들을 정의하고 이들에 대한 작업을 수행하는 것이 바로 클래스이다. C언어에서는 문자열을 문자의 배열로 다루지만, 자바에서는 String이라는 클래스로 문자열을 다룬다. 문자열을 단순히 문자의 배열로 정의하지 않고 클래스로 정의한 이유는 문자열과 문자열을 다루는데 필요한 함수들까지 함께 묶기 위해서이다. 

     

     

    클래스의 정의2 - 사용자 정의 타입

    프로그래밍언어에서 제공하는 기본 자료형(primitive type) 외에 프로그래머가 서로 관련될 변수들을 묶어 하나의 타입으로 새로 추가하는 것을 '사용자 정의 타입(user0defined type)'이라고 한다.

    다른 프로그래밍언어에서도 사용자정의 타입을 정의할 수 있는 방법을 제공하고 있으며 자바와 같은 객체지향언어에서는 클래스가 곧 사용자 정의 타입이다. 기본형의 개수는 8개로 정해져 있지만 참조형의 개수가 정해져 있지 않은 이유는 이처럼 프로그래머가 새로운 타입을 추가할 수 있기 때문이다. 

     

    int hour; 
    int minute;
    float second; 

    시간을 표현하기 위해서 위와 같이 3개의 변수를 선언했다. 만일 3개의 시간을 다뤄야 한다면 다음과 같이 해야 할 것이다.

     

    int hour1, hour2, hour3;
    int minute1, minute2, minute3;
    float second1, second2, second3;

    위에처럼 다뤄야 하는 시간의 개수가 늘어날 떄마다 시, 분, 초를 위한 변수를 추가해야 하는데 데이터의 개수가 많으면 이런식으로는 곤란하다. 항상 100개,, 1000개,, 수만개가 있다고 생각해보자.

     

    int [] hour = new int[3];
    int [] minute = new int[3];
    float [] second = new float[3];

    위와 같이 배열로 처리하면 다뤄야 하는 시간 데이터의 개수가 늘더라도 배열의 크기만 변겨앻주면 되므로, 변수를 매번 새로 선언해줘야 하는 불편함과 복잡함은 없어졌다. 그러나 하나의 시간을 구성하는 시, 분, 초가 서로 분리되어 있기 때문에 프로그램 수행과정에서 시, 분, 초가 때로 뒤섞여서 올바르지 않은 데이터가 될 가능성이 있다. 따라서 이런 경우 시, 분, 초를 하나로 묶는 사용자정의 타입, 클래스를 정의해서 사용한다.

     

    class Time{
    int hour;
    int minute;
    int second;
    }

     

    비객체지향적 코드 객체지향적 코드
    int hour1, hour2, hour3;
    int minute1, minute2, minute3;
    float second1, second2, second3;
    Time t1 = new Time();
    Time t2 = new Time();
    Time t3 = new Time();
    int [] hour = new int[3];
    int [] minute = new int[3];
    float [] second = new float[3];
    Time [ ] t = new Time [3];
    t[0] = new Time();
    t[1] = new Time();
    t[2] = new Time();

     

    위에 표를 객체지향적 코드로 묶어서 다루면 다른 시간 데이터와 섞이는 일은 없겠다. 여기서 만약 추가적인 제약조건이 있다면? 객체지향언어가 아닌 언어에서는 조건들을 반영하기 어렵겠지만 객체지향언어에서는 이러한 조건들을 코드에 쉽게 반영할 수 있다. 

     

    1. 시, 분, 초는 모두 0보다 크거나 같아야 한다.

    2. 시의 범위는 0~23, 분과 초의 범위는 0~59이다.

    public class Time{
    private int hour;
    private int minute;
    private float second;

    public void setHour(int h) {
    if(h<0 || h>23) return;
    hour = h; //지정된 값(h)이 유효한 경우에만 hour를 변경한다.
    }
    }

    제어자를 이용해서 변수의 값을 직접 변경하지 못하게 했고, 대신 메서드를 통해서 값을 변경하도록 했다. 값을 변경할 때 지정된 값의 유효성을 조건문으로 점검한 다음에 유효한 갑일 경우에만 변경한다.

     

     

     

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

    변수는 클래스 변수, 인스턴스 변수, 지역변수 모두 세 종류가 있다. 변수의 종류를 결정짓는 중요한 요소는 '변수의 선언 위치'이므로 변수의 종류를 파악하기 위해서 변수가 어느 영역에 선언되었는지를 확인하는 것이 좋다 멤버변수를 제외한 나머지 변수들은 모두 지역변수이며, 멤버변수 중 static이 붙은 것은 클래스 변수, 붙지 않은 것은 인스턴스 변수이다. 

     

    1. 인스턴스 변수 (instance variable) 

    : 클래스 영역에서 선언되면, 인스턴스를 생성할 때 만들어진다. 그래서 인스턴스 변수(iv)의 값을 읽어오거나 저장하려면 먼저 인스턴스를 생성해야한다. 인스턴스마다 별도의 저장공간을 가지므로 서로 다른 값을 가질 수 있다. 인스턴스마다 고유한 상태를 유지해야하는 속성의 경우, 인스턴스 변수로 선언한다.

     

     

    2. 클래스 변수(class variable)

    : 클래스 변수를 선언하는 방법은 인스턴스 변수(iv) 앞에 static을 붙이기만 하면 된다. 인스턴스마다 독립적인 저장공간을 갖는 인스턴스 변수와는 달리, 클래스 변수는 모든 인스턴스가 공통된 저장공간(변수)을 공유하게 된다. 한 클래스의 모든 인스턴스들이 공통적인 값을 유지해야하는 속성의 경우, 클래스 변수로 선언해야 한다. (예를들어 게임을 만든다고 할 때 화면의 가로&세로 길이 같은 것?) 클래스 변수는 인스턴스 변수와 달리 인스턴스를 생성하지 않고 언제라도 바로 사용할 수 있는 특징이 있으며, '클래스이름.클래스변수'와 같은 형식으로 사용한다.

     

     

    3.  지역변수(local variable)

    : 메서드 내에 선언되어 메서드 내에서만 사용 가능하며, 메서드가 종료되면 소멸되어 사용할 수 없게 된다. for문 또는 while문의 블럭 내에 선언된 지역 변수는, 지역변수가 선언된 블럭{ } 내에서만 사용가능하며, 블럭{ }을 벗어나면 소멸되어 사용할 수 없게 된다. 

     

     

     

    클래스 변수와 인스턴스 변수

    클래스 변수와 인스턴스 변수의 차이를 이해하기위해 카드를 예를들어 클래스를 만들어보자. 카드  클래스를 작성하기 위해서 먼저 카드를 분석해서 속성과 기능을 알아내야 한다. 속성으로는 카드의 무늬, 숫자, 폭, 높이 정도를 생각할 수 있을 것이다. 

    각 Card인스턴스는 자신만의 무늬(kind)와 숫자(number)를 유지하고 있어야 하므로 이들을 인스턴스 변수로 선언하였고, 각 카드의 폭(width)과 높이(height)는 모든 인스턴스가 공통적으로 같은 값을 유지해야하므로 클래스 변수로 선언한다. 카드의 폭을 변경해야할 필요가 있을 경우, 한 카드의 width값만 변경해도 모든 카드의 width값이 변경되는 셈이다. 

     

    인스턴스 변수는 인스턴스가 생성될 때 마다 생성되므로 인스턴스마다 각기 다른 값을 유지할 수 있지만, 클래스 변수는 모든 인스턴스가 하나의 저장공간을 공유하므로, 항상 공통된 값을 가진다.

     

    ※ 예제 1번 ※

    package ch6;
    
    public class Ex6_3 {
    
    	public static void main(String[] args) {
    		System.out.println("Card.width = " + Card.width);
    		System.out.println("Card.height = " + Card.height);
    		
    		Card c1 = new Card();
    		c1.kind = "heart";
    		c1.number = 7;
    		
    		Card c2 = new Card();
    		c2.kind = "spade";
    		c2.number = 4;
    		
    		System.out.println("c1은" + c1.kind + ", "+c1.number +"이며, 크기는 (" +Card.width+"," +Card.height+")");
    		System.out.println("c2은" + c2.kind + ", "+c2.number +"이며, 크기는 (" +Card.width+"," +Card.height+")");
    		
    		c1.width=50;
    		c1.height=80;
    		System.out.println("c1은" + c1.kind + ", "+c1.number +"이며, 크기는 (" +Card.width+"," +Card.height+")");
    		System.out.println("c2은" + c2.kind + ", "+c2.number +"이며, 크기는 (" +Card.width+"," +Card.height+")");
    	}
    
    }
    
    class Card{
    	String kind;
    	int number;
    	static int width =100;
    	static int height = 250;
    }

    예제 1번 출력 값

    Card클래스의 클래스 변수(static 변수)인 width, height는 Card 클래스의 인스턴스를 생성하지 않고도 '클래스이름.클래스 변수'와 같은 방식으로 사용할 수 있다. Card.kind 이런식으로 인스턴스 변수는 사용 불가능!  Card 인스턴스인 c1과 c2는 클래스 변수인 width와 height를 공유하기 때문에, c1의 width와 height를 변경하면 c2의 width와 height값도 바뀐 것과 같은 결과를 얻는다. Card.width, c1.width, c2.width는 모두 같은 저장공간을참조하므로 항상 같은 값이다. 클래스 변수를 사용할 때는 Card.width와 같이 '클래ㅅ이름.클래스변수'의 형태로 하는 것이 좋다. 참조변수 c1, c2를 통해서도 클래스 변수를 사용할 수 있지만 이렇게 하면 클래스 변수를 인스턴스 변수로 오해하기 쉽다. 

     

     

     

    반응형

    댓글

Designed by Tistory.