ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [ch6 자바 OOP] 객체지향 언어의 특징
    프로그래밍 언어/JAVA 2022. 6. 13. 17:36
    객체지향 언어란?

    객체지향언어는 기존의 프로그래밍언어와 다른 전혀 새로운 것이 아니라, 기존의 프로그래밍 언어에 몇 가지 새로운 규칙을 추가한 보다 발전된 형태의 것이다. 이러한 규칙들을 이용해서 코드 간에 서로 관계를 맺어 줌으로써 보다 유기적으로 프로그램을 구성하는 것이 가능해졌다. 객체지향언어의 주요 특징은 아래와 같다.

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

     

    객체지향언어의 가장 큰 장점은 코드의 재사용성이 높고 유지보수가 용이하다는 것이다. 이러한 객체지향언어의 장점은 프로그램의 개발과 유지보수에 드는 시간과 비용을 획기적으로 개선하였다. 앞으로 업로드할 포스팅에서 상속, 다형성과 같은  객체지향개념을 학습할 때 재사용성과 유지보수 그리고 중복된 코드의 제거, 이 세 가지 관점에서 보면 보다 쉽게 이해할 수 있을 것이다. 

     

     

    클래스와 객체

    클래스란 '객체를 정의해놓은 것'. 또는 클래스는 '객체의 설계도 또는 틀'이라고 정의할 수 있다. 클래스는 객체를 생성하는데 사용되며, 객체는 클래스에 정의된 대로 생성된다.

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

     

    객체의 사전적 정의는, '실제로 존재하는 것'이다. 우리가 주변에서 볼 수 있는 책상, 의자, 자동차나 같은 사물들이 곧 객체이다. 객체지향이론에서는 사물과 같은 유형적인 것뿐만 아니라, 개념이나 논리와 같은 무형적인 것들도 객체로 간주한다. 프로그래밍에서의 객체는 클래스에 정의된 내용대로 메모리에 생성된 것을 뜻한다.

    객체의 정의 : 실제로 존재하는 것, 사물 또는 개념
    객체의 용도 : 객체가 가지고 있는 기능과 속성에 따라 다름

    유형의 객체 : 책상, 의자, TV 등...
    무형의 객체 : 수학공식, 프로그램 에러와 같은 논리나 개념

     

    클래스와 객체의 관계를 우리가 살고 있는 실생활에서 예를 들면, 제품 설계도와 제품과의 관계라고 할 수 있다. 예를 들면, TV 설계도(클래스)는 TV라는 제품(객체)를 정의한 것이며, TV(객체)를 만드는데 사용된다. 

    또한 클래스는 단지 객체를 생성하는데 사용될 뿐, 객체 그 자체는 아니다. 우리가 원하는 기능의 객체를 사용하기 위해서는 먼저 클래스로부터 객체를 생성하는 과정이 선행되어야한다. 우리가 TV를 보기 위해서는, TV(객체)가 필요한 것이지 TV(설계도)가 필요한 것은 아니며 TV설계도(클래스)는 단지 TV라는 제품(객체)를 만드는 데만 사용될 뿐이다.

     

    클래스를 정의하고 클래스를 통해 객체를 생성하는 이유는 설계도를 통해서 제품을 만드는 이유와 같다. 하나의 설계도만 잘 만들어 놓으면 제품을 만드는 일이 쉬워지기 때문이다. 

     

     

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

    객체는 속성과 기능, 두 종류의 구성요소로 이루어져 있으며, 일반적으로 객체는 다수의 속성과 다수의 기능을 갖는다. 즉) 객체는 속성과 기능의 집합이라고 할 수 있다. 그리고 객체가 가지고 있는 속성과 기능을 그 객체의 멤버(member, 구성원)라 한다. 클래스란 객체를 정의한 것이므로 클래스에는 객체의 모든 속성과 기능이 정의되어 있다. 클래스로부터 객체를 생성하면, 클래스에 정의된 속성과 기능을 가진 객체가 만들어지는 것이다. 이해하기 쉽게 TV를 예로 들어보자.

    속성 크기, 높이, 길이, 볼륨 등
    기능 켜기,끄기, 볼륨 높이기, 채널 변경하기 등

     

    객체지향 프로그래밍에서는 속성과 기능을 각각 변수와 메서드로 표현한다.

    속성(property) -> 멤버변수(variable)
    기능(function) -> 메서드(method)
    package ch6;
    
    public class TV {
    		
    		String color; //색깔
    		boolean power; //전원 상태
    		int channel; //채널
    		
    		void power() {power = !power;}
    		void channelUp() {channel++;}
    		void channelDown() {channel--;}
    
    }

     

    위에서 분석한 내용을 토대로 Tv 클래스를 만들어보았다. 프로그래밍에서 필요한 속성과 기능만을 선택하여 클래스를 작성하면 된다.

     

     

    객체와 인스턴스

    클래스로부터 객체를 만드는 과정을 클래스의 인스턴스화(instantiate)라고 하며, 어떤 클래스로부터 만들어진 객체를 그 클래스의 인스턴스(instance)라고 한다. 예를 들면, Tv 클래스로부터 만들어진 객체를 Tv클래스의 인스턴스라고 한다. 결국 인스턴스는 어떤 클래스로부터 만들어진 것인지를 보다 강조하는 의미를 갖고있다. 

     

    예를들면 '책상은 인스턴스다'라고 하기 보다는 '책상은 객체다' 라는 쪽이, '책상은 책상 클래스의 객체이다.'라고 하는 것 보다는 ' 책상은 책상 클래스의 인스턴스다'라고 하는 것이 더 자연스럽다. 인스턴스와 객체는 같은 의미이므로 두 용어의 사용을 엄격히 구분할 필요는 없지만, 문맥에 따라 구별하여 사용하는 것이 좋다.

     

    한 파일에 여러 클래스 작성하기

    하나의 소스파일에 하나의 클래스만을 정의하는 것이 보통이지만, 하나의 소스파일에 둘 이상의 클래스를 정의하는 것도 가능하다. 이 때 주의해야할 점은 '소스파일의 이름은 public class의 이름과 일치해야 한다.'는 것이다. 만일 소스파일 내에 public class가 없다면, 소스 파일의 이름은 소스파일 내에 어떤 클래스 이름으로 해도 상관없다. 

     

    소스파일(*.java)과 달리 클래스파일(*.class)은 클래스마다 하나씩 만들어지므로 위 표의 '올바른 작성 예'에 제시된 'Hell2.java'를 컴파일하면 'Hello2.class'와 'Hello3.class'모두 두 개의 클래스 파일이 생성된다. 

     

     

     

    객체의 생성과 사용

    Tv클래스를 선언한 것은 Tv 설계도를 작성한 것에 불과하므로, Tv 인스턴스를 생성해야 제품(Tv)를 사용할 수 있다. 클래스로부터 인스턴스를 생성하는 방법은 여러 가지가 있지만 일반 적으로는 다음과 같이 해야한다.

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

     

     

    ※ 예제 1번 ※

    package ch6;
    
    public class Ex6_1 {
    		
    	public static void main(String[] args) {
    		
    		Tv t; //Tv인스턴스를 참조하기 위한 참조변수를 선언
    		t = new Tv(); //Tv인스턴스를 생성한다.
    		t.channel = 7; //Tv인스턴스의 멤버변수 channel 값을 7로 한다.
    		t.channelDown(); //Tv인스턴스의 메서드 channelDown()을 호출한다.
    		System.out.println("현재 채널은 " + t.channel + " 입니다.");
    		System.out.println("현재 전원 상태는 " + t.power);
    		t.power();
    		System.out.println("t.power() 메서드 호출 후 현재 전원 상태는 " + t.power);
    	}
    
    }
    
    class Tv{
    	//Tv의 속성(멤버변수)
    	int channel;
    	String color;
    	boolean power;
    	
    	void power() { power = !power;}
    	void channelUp() { ++channel;}
    	void channelDown() { --channel;}
    }

    예제 1번 출력 값

     

     

    예제 1을 이해하기 위해 그림으로 한 단계씩 정리해본다.

     

    1. Tv t;

    : tv 클래스 타입의 참조변수 t를 선언한다. 메모리에 참조변수 t를 위한 공간이 마련딘다. 아직 인스턴스가 생성되지 않았으므로 이 참조변수로 할 수 있는 것은 아무것도 없다.

     

    2. t = new Tv();

    : 연산자 new에 의해 Tv 클래스의 인스턴스가 메모리의 빈 공간에 생성된다. 주소가 0x100인 곳에 생성되었다고 가정했을 때, 멤버변수는 각 자료형에 해당하는 기본값으로 초기화된다. color은 String 참조형으로 null, poewr은 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 감소시킨다.

    void channelDown() { --channel;}

    chaeenlDown()에 의해서 channel의 값은 7에서 6이 된다.

     

    5. System.out.println("현재 채널은 " + t.channel + " 입니다.");

    : 참조변수 t가 참조하고 있는 Tv인스턴스의 멤버변수 channel에 저장되어 있는 값을 출력한다. 현재 channel의 값은 6이므로 '현재 채널은 6입니다.'가 화면에 출력된다.

     

     


     

    인스턴스와 참조변수의 관계는 마치 우리가 일상생활에서 사용하는 TV와 TV리모컨의 관계와 같다. TV리모컨(참조변수)를 이용하면 TV(인스턴스)를 다루기 때문이다. 다른 점이라면, 인스턴스는 오직 참조변수를 통해서만 다룰 수 있다는 것이다. 그리고 TV를 사용하려면 TV리모컨을 사용해야 하고, 에어컨을 사용하려면, 에어컨 리모콘을 사용해야 하는 것처럼 TV인스턴스를 사용하려면, TV 클래스 타입의 참조변수가 필요한 것이다. 

     

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

     

     

     

     

    ※ 예제 2번 ※

    package ch6;
    
    public class Ex6_2 {
    
    	public static void main(String[] args) {
    		Tv t1 = new Tv();
    		Tv t2 = new Tv();
    		
    		System.out.println("t1의 channel의 값은? " +t1.channel);
    		System.out.println("t2의 channel의 값은? " +t2.channel);
    		t1.channel = 7;
    		System.out.println("t1의 channel의 값을 7로 변경하였습니다.");
    		System.out.println("t1의 channel의 값은? " +t1.channel);
    		System.out.println("t2의 channel의 값은? " +t2.channel);
    
    
    	}
    
    }

    오답 : t1, t2만 입력
    예제 2번 출력 값

    같은 클래스로부터 생성되었을지라도 각 인스턴스의 속성(멤버변수)는 서로 다른 값을 유지할 수 있으며, 메서드의 내용은 모든 인스턴스에 대해 동이라다. 예제 2번은 Tv 클래스의 인스턴스 t1과 t2를 생성한 후에, 인스턴스 t1의 멤버변수인 channel의 값을 변경한다. 앞에 1번 예제에서 class Tv{}를 생성해뒀기에 같은 이름의 클래스는 생성하지 못한다. 

     

     

     

     

    객체배열

    많은 수의 객체를 다뤄야할 때, 배열로 다루면 편리할 것이다. 객체 역시 배열로 다루는 것이 가능하며, 이를 '객체배열'이라고 한다. 그렇다고 객체 배열 안에 객체가 저장되는 것은 아니고, 객체의 주소가 저장된다. 사실 객체 배열은 참조변수들을 하나로 묶은 참조변수 배열인 것이다.

    Tv tv1, tv2, tv3;     ----> Tv[ ] tvArr = new Tv[3];

     

    길이가 3인 객체 배열 tvArr을 생성하면, 각 요소는 참조변수의 기본값인 null로 자동 초기화 된다. 그리고 이 객체 배열은 3개의 객체, 정확히는 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 =0; i<tvArr.length; i++){
      tvArr[i] = new Tv();
    }

     

    반응형

    댓글

Designed by Tistory.