[혼공자] 06-1. 객체 지향 프로그래밍

Benjamin·2023년 3월 3일
0

혼공자

목록 보기
15/27

06. 클래스

06-1. 객체 지향 프로그래밍

현실세계에서 제품만들 때 부품 먼저 개발하고 이 부품들을 하나씩 조립해 제품을 완성하듯이 소프트웨어를 개발할 때에도 부품에 해당하는 객체를 먼저 만든다.
그리고 객체를 하나씩 조립해서 완성된 프로그램을 만드는 기법을 객체 지향 프로그래밍(OOP)라고 한다.

객체란 물리적으로 존재하거나 추상적으로 생각할 수 있는 것(학과, 강의, 주문 ...) 중에서 자신의 속성을 가지고 있으면서 식별가능한 것을 말한다.

객체는 속성과 동작으로 구성되어있다.
자바는 이 속성과 동작을 각각 필드와 메소드라고 부른다.

현실 세계의 객체를 소프트웨어 객체로 설계하는 것을 객체 모델링이라고 한다.
객체 모델링은 현실 세계 객체의 속성과 동작을 추려내어 소프트웨어 객체의 필드와 메소드로 정의하는 과정이라고 볼 수 있다.

객체의 상호작용

현실세계에서 일어나는 모든 현상은 객체와 객체 간의 상호작용으로 이루어져있다.

소프트웨어에서도 마찬가지다.객체들은 각각 독립적으로 존재하고, 다른 객체와 서로 상호작용하면서 동작한다.
객체들 사이의 상호작용 수단은 메소드이다,
이때 객체가 다른 객체의 기능을 이용하는것이 메소드 호출이다.

메소드 호출은 다음과 같은 형태를 갖고있다.

리턴값 = 전자계산기객체.메소드(매개값1, 매개값2 ...);

  1. 객체에 도트(.)연산자를 붙이고 메소드 이름을 기술한다.
    도트 연산자는 객체의 필드와 메소드에 접근할 때 사용한다.
  2. 매개값은 메소드를 실행하기 위해 필요한 데이터이다.
    리턴값은 메소드가 실행되고 난 후 호출한 곳으로 돌려주는 값이다.

객체의 상호작용은 객체 간의 메소드 호출을 의미하며 매개값과 리턴값을 통해 데이터를 주고받는다,

객체 간의 관계

객체는 개별적으로 사용될 수 있지만, 대부분 다른 객체와 관계를 맺고있다.
이 관계의 종류에는 집합 관계, 사용 관계, 상속 관계가 있다.

  1. 집합 관게에 있는 객체는 하나는 부품이고 하나는 완성품에 해당한다.
    예를들어, 자동차와 자동차의 부품들은 집합 관계라고 볼 수 있다.

  2. 사용 관계는 객체 간의 상호작용을 말한다.
    객체는 다른 객체의 메소드를 호출하여 원하는 결과를 얻어낸다.

  3. 상속 관계는 상위(부모) 객체를 시반으로 하위(자식) 객체를 생성하는 관계이다.
    일반적으로 상위 객체는 종류를 의미하고, 하위 객체는 구체적인 사물에 해당한다.

객체 지향 프로그래밍은 만들고자 하는 완성품인 객체를 모델링하고, 집합 관계에 있는 부품 객체와 사용 관계에 있는 객체를 하나씩 설계한 후 조립하는 방식으로 프로그램을 개발하는 기법이다.

객체와 클래스

메모리에서 사용하고 싶은 객체가 있다면 우선 설계도로 해당 객체를 만드는 작업이 필요하다.

자바에서는 설계도가 바로 클래스이다.
클래스에는 객체를 생성하기 위한 필드와 메소드가 정의되어있다.
클래스로부터 만들어진 객체를 해당 클래스의 인스턴스라고 한다.

자동차 객체는 자동차 클래스의 인스턴스인 셈이다.
그리고 클래스로부터 객체를 만드는 과정을 인스턴스화라고 한다.
하나의 클래스로부터 여러 개의 인스턴스를 만들 수 있다.

객체 지향 프로그래밍 개발은 세 가지 단계가 있다.
1단계 : 클래스를 설계한다.
2단계 : 설계된 클래스를 가지고 사용할 객체를 생성한다.
3단계 : 생성된 객체를 이용한다.

클래스는 객체를 만들기 위한 설계도이지만 지금까지는 아직 객체로 만들어보지 않고 단순히 main()메소드만 작성해서 실행할 목적으로 클래스를 이용했다.
하지만 main()메소드가 없는 클래스는 객체 생성 과정을 거쳐 사용해야한다.

클래스 선언

사용하고자 하는 객체를 구상했다면 그 객체의 대표 이름을 하나 결정하고 이것을 클래스 이름으로 정한다.

클래스 이름은 다른 클래스와 식별할 목적으로 사용되므로 자바의 식별자 작성 규칙에따라 만들어야한다.
식별자 작성 규칙은 다음과 같다.

  1. 하나 이상의 문자로 이루어져야한다. 예)Car ...
  2. 첫 글자에는 숫자가 올 수 없다.
  3. '$', '_'외에 특수 문자는 사용할 수 없다,
  4. 자바 키워드는 사용할 수 없다.

클래스 이름은 한글이든 영어든 상관없지만, 한글로 만드는경우는 거의 없다.
자바는 영어 대소문자를 다른 문자로 취급하기때문에 클래스 이름도 영어 대소문자를 구분한다.
통상적으로는 클래스 이름이 단일 단어라면 첫 글자를 대문자로하고 나머지는 소문자로 작성한다.
만약 서로 다른 단어가 혼합되었다면 각 단어의 첫 글자는 대문자로 작성하는게 일반적이다.
예) Car, Member, CharServer ...

클래스 이름을 정했다면 '클래스이름.java'로 소스파일을 생성해야한다.
소스파일 이름 역시 대소문자를 구분하므로 반드시 클래스 이름과 대소문자가 같도록 해야한다.

소스파일을 생성하면 파일을 열고 다음과 같이 클래스를 선언한다.

public class 클래스이름{
}

여기서 public class 키워드는 클래스를 선언할 때 사용하며 반드시 소문자로 작성해야한다.
클래스 이름 뒤에는 반드시 중괄호{}를 붙여주는데, 시작 중괄호{는 클래스 선언의 시작을 알려주고, 끝 중괄호}는 클래스 선언의 끝을 알려준다.

일반적으로 소스 파일당 하나의 클래스를 선언한다.
하지만 2개 이상의 클래스 선언도 가능하다.

public class Car{
}

class Tire{
}

2개 이상의 클래스가 선언된 소스 파일을 컴파일하면 바이트 코드 파일(.class)은 클래스를 선언한 개수만큼 생긴다.
결국 소스파일은 클래스 선언을 담고있는 저장단위일 뿐, 클래스 자체가 아니다.

상기 코드를 컴파일하면 Car.class와 Tire.class가 각각 생성된다.

  • public 접근 제한자
    public 접근 제한자는 파일 이름과 동일한 이름의 클래스 선언에만 붙일 수 있다.
    만약 파일 이름과 일치하지 않는 클래스 선언에 public 접근제한자를 붙이면 컴파일에러가 발생한다.
    가급적이면 소스 파일 하나당 동일한 이름의 클래스 하나르 선언하는것이 좋다.

객체 생성과 클래스 변수

클래스를 선언한 다음, 컴파일을 했다면 객체를 생성할 설계도가 만들어진셈이다.
클래스로부터 객체를 생성하려면 다음과 같이 new 연산자를 사용하면된다.
new 클래스();

new는 클래스로부터 객체를 생성시키는 연산자이다.
new연산자는 객체 생성연산자이며,생성자를 호출하고 객체 생성번지를 리턴한다.
new 연산자 뒤에는 생성자가 오는데, 생성자는 클래스() 형태를 갖고있다.
new 연산자로 생성된 객체는 메모리 힙 영역에 생성된다.

객체 지향 프로그램에서 메모리 내에서 생성된 객체의 위치를 모르면 객체를 사용할 수 없다.
그래서 new 연산자는 힙 영역에 객체를 생성시킨 후 객체의 번지를 리턴하도록 되어있다.
이 주소를 참조 타입인 클래스 변수에 저장해두면 변수를 통해 객체를 사용할 수 없다.

다음은 클래스로 선언된 변수에 new연산자가 리턴한 객체의 번지를 저장하는 코드이다.

클래스변수는 클래스로 선언한 변수를 말하며 해당 클래스의 객체 번지가 저장된다.

클래스 변수;
변수 = new 클래스();

클래스 변수 = new 클래스();

이렇게 new 연산자로 객체를 생성하고, 리턴된 객체의 번지를 변수에 저장하면 다음과 같이 변수가 객체를 참조하게된다.

다음 예제는 Student 클래스를 선언하고 StudentExample 클래스의 main()메소드에서 Student 객체를 생성한다.

package sec01.exam01;

public class Student {
}
package sec01.exam01;

public class StudentExample {
	public static void main(String[] args) {
    	Student s1 = new Student();
        System.out.println("s1 변수가 Student 객체를 참조합니다.");
        
        Student s2 = new Student();
        System.out.println("s2 변수가 또 다른 Student 객체를 참조합니다.");
    }
}

StudentExample을 실행하면 다음 그림과 같이 메모리에 클래스 변수와 객체가 생성된다.
Student 클래스는 하나지만 new 연산자를 사용한 만큼 객체가 메모리에 생성된다.
이러한 객체들은 Student 클래스의 인스턴스이다. 같은 클래스로부터 생성됐지만 각각의 Student 객체는 자신만의 고유 데이터를 가지면서 메모리에서 활동한다.
s1과 s2가 참조하는 Student객체는 완전히 독립된 서로 다른 객체다.

Student와 StudentExample클래스의 용도

클래스는 두 가지 용도가 있다.
하나는 라이브러리(API:Application Program Interface)용이고 다른 하나는 실행용이다.
라이브러리 클래스는 다른 클래스에서 이용할 목적으로 설계된다.
프로그램 전체에서 사용되는 클래스가 100개라면 99개는 라이브러리 클래스이고 단 하나가 실행 클래스이다.
실행 클래스는 프로그램 실행 진입점인 main()메소드를 제공하는 역할을 한다.

Student는 라이브러리 클래스이고 StudentExample은 실행 클래스이다.
다음과 같이 Student에 main()메소드를 작성해서 라이브러리인 동시에 실행 클래스로 만들 수도 있다.

public class Student {
//라이브러리로서의 코드(필드, 생성자, 메소드)
...
	//실행하기위한 코드
    public static void main(String[] args) {
    	Student s1 = new Student();
        System.out.println("s1 변수가 Student 객체를 참조합니다.");
        
        Student s2 = new Student();
        System.out.println("s2 변수가 또 다른 Student 객체를 참조합니다.");
    }
}

프로그램이 단 하나의 클래스로 구성된다면 위와같이 작성하는것이 좋지만, 대부분 객체 지향 프로그램은 라이브러리(부품 객체 및 완성 객체)와 실행 클래스가 분리되어 있다.

클래스의 구성 멤버

클래스에는 객체가 가져야 할 구성멤버가 선언된다.
구성멤버에는 필드, 생성자, 메소드가 있다.
이 구성 멤버들은 생략되거나 복수의 개수로 작성될 수 있다.

public class ClassName {
	int fieldname; // 필드 : 객체의 데이터가 저장되는 곳
    
    ClassName() { ...} // 생성자 : 객체 생성 시 초기화 역할 담당
    
    void methodName() {...} // 메소드 : 객체 동작에 해당하는 실행 블록
}

필드

객체의 고유 데이터, 부품 객체, 상태 정보를 저장하는 곳이다.
선언 형태는 변수와 비슷하지만, 필드를 변수라고 부르지는 않는다.
변수는 생성자와 메소드 내에서만 사용되고 생성자와 메소드가 실행 종료되면 자동 소멸된다.
하지만 필드는 생성자와 메소드 전체에서 사용되며 객체가 소멸되지 않는 한 객체와 함께 존재한다.

생성자

new 연산자로 호출되는 특별한 중괄호{} 블록이다.
역할은 객체 생성 시 초기화를 담당한다. 필드를 초기화하거나 메소드를 호출해서 객체를 사용할 준비를 한다.
매소드와 비슷하게 생겼지만 클래스 이름으로 되어있고 리턴 타입이 없다.

메소드

객체의 동작에 해당하는 중괄호{}블록이다.
중괄호 블록의 이름이 메소드 이름이다. 메소드를 호출하게 되면 중괄호 블록에 있는 모든 코드들이 일괄적으로 실행된다, 이때 메소드는 필드를 읽고 수정하는 역할도 하지만, 다른 객체를 생성해서 다양한 기능을 수행하기도 한다.
메소드는 객체 간 데이터를 전달하는 수단이다. 외부(호출한 곳)로부터 매개값을 받아 실행에 이용하고, 실행 후 결과 값을 외부(호출한 곳)로 리턴할수도있다.


출처
혼자 공부하는 자바

0개의 댓글