인스턴스 멤버

객체(인스턴스)를 생성한 후 사용할 수 있는 필드와 메소드를 말하며
이들을 각각 인스턴스 필드, 인스턴스 메소드라고 한다.

 

지금까지 작성한 필드와 메소드들이 인스턴스 멤버들인 셈이다.

인스턴스 멤버들은 객체에 소속된 멤버이기 때문에 객체 없이는 사용할 수 없다.

 

우선 인스턴스 멤버들(필드와 메소드)을/를 만들어보자.

 

인스턴스 멤버, 전에 했던 필드와 메소드 활용하여 mine / yours 만들기

이 때

인스턴스 필드 gas는 객체마다 따로 존재하나, 

인스턴스 메소드 setSpeed()는 객체마다 존재하지 않고 메소드 영역에 저장되고 공유된다.

 

객체 외부에서 인스턴스 멤버에 접근하기 위해 참조 벼수를 사용하는 것고 마찬가지로

객체 내부에서도 인스턴스 멤버에 접근하기 위해 this를 사용한다. 

 

우리가 본인 스스로를 '나'라고 하듯이 객체는 자신을 'this'라고 한다.

즉, this.model은 자신이 갖고 있는 model 필드를 의미한다.

 

this는 생성자와 메소드의 매개 변수 이름이 필드와 동일한 경우,

인스턴스 멤버인 필드임을 명시할 때 사용된다.

 

 


[보충지식]

 

 

 

메소드

메소드는 객체의 동작에 해당하는 중괄호 블록을 말한다. 

중괄호 블록은 이름을 가지고 있는데, 이것이 메소드의 이름이다. 

메소드를 호출하게 되면 중괄호 블록 내 모든 코드들이 일괄적으로 수행된다.

 

  • 필드를 읽고 수정하는 역할도 하지만 다른 객체를 생성해서 다양한 기능을 수행하기도 한다.
  • 객체 간의 데이터 전달의 수단으로 사용된다.
  • 외부로부터 매개값을 받을 수도 있고 실행 후 어떤 값을 리턴할 수도 있다. 

 

[메소드 선언]

메소드 선언은 선언부와 실행블록으로 구성된다.

리턴타입 메소드이름 ( [매개변수선언] ) {
    // 실행 코드 작성
}
  1. 리턴타입: 메소드가 리턴하는 결과 타입 표시 
  2. 변수선언: 메소드가 실행될 때 필요한 데이터를 받기 위한 변수
  3. 코드작성: 실행되어지는 블록

 

1. 리턴타입

메소드가 실행 후 리턴하는 값의 타입을 말한다.

이 때 메소드는 리턴값이 있을 수도 있고 없을 수도 있다. 

메소드가 실행 후 결과를 호출한 곳에 넘겨줄 경우에는 리턴값이 있어야 한다. 

 

책에서는 전자계산기를 예로 들었다.

예시에 사용된 메소드는 전원을 켜는 powerOn() 메소드와 두 수를 나누는 divide() 기능이다.

 

divide() 메소드의 경우 나눈 결과값을 리턴해야 하지만

powerOn() 메소드는 전원을 키면 할 일을 다한 것이다. 

 

powerOn() 처럼 리턴값이 없는 메소드는 리턴타입에 void가 와야 하며

divide() 처럼 결과값이 있는 메소드는 리턴값의 타입이 와야 한다. 

 

divide()의 결과가 double이면 리턴타입에 double을 주면 된다는 의미이다. 

 

다음은 리턴값이 있는 메소드와 없는 메소드를 작성하고 호출하는 예시이다.

 

리턴 타입 


리턴타입 예시 만들다가 경험한 'static' 에러

static 에러

ElecCalc과 ElecCalc2가 있다. 

둘의 차이점은 메소드에 static이 붙냐 안 붙냐의 차이이다.

 

책에서는 안 붙은 채로 예시가 적혀 있어서 그대로 따라해보려 했지만 ElecCalc2와 같이 빨간줄이 뜬 걸 볼 수 있었다.

에러 메시지의 내용은 다음과 같다.

 

에러 메시지 내용

 

뭔 내용인진 잘 모르겠지만 static에 관한 문제가 생겼다는 것을 짐작할 수 있었다.

2번째 줄의 Change 'divide()' to 'static'을 뜨는 곳마다 누르다 보니 리턴타입의 예시 같이 결과물을 완성할 수 있었다.

 

쉬는 시간 맞이 후 돌아오시는 선생님께 여쭤보니

static에 대해 간략하게 설명을 해 주셨다. 

 

static은 하나의 공간이고 이 공간 안에 존재한 메소드를 호출하기 위해서 메소드마다 static을 달아주거나

new 연산자를 통해 메소드와 연결하여 실행시켜주면

메소드에서 static을 붙여주지 않아도 에러가 뜨지 않는 것을 볼 수 있다.

(이해하는 과정에서 변형이 생긴 것 같기는 한데..)

 

[메소드 이름]

메소드 작성 규칙

  • 숫자로 시작하면 안 된다.
  • 달러표시와 언더바 ( $, _ )를 제외한 특수문자는 사용하지 말아야 한다.
  • 관례적으로 메소드명은 소문자로 작성한다.
  • 서로 다른 단어가 혼합된 이름이면 뒤에 오는 단어의 첫 글자는 대문자로 한다. ex) powerOn()
void run() {}
void startEngine() {}
String getName() {}
int[] get Scores() {}

메소드명은 너무 짧게 해서 그 의미를 알지 못하게 하는 것보다는 

메소드가 어떤 기능을 하는지를 이름에 표현해주는 것이 좋다.

 

2. 변수 선언

매개 변수는 메소드가 실행할 때 필요한 데이터를 외부로부터 받기 위해 사용된다.

이 때도 마찬가지로 매개 변수가 필요한 변수가 있고 아닌 변수가 있는데

powerOn() 메소드는 매개 변수가 필요 없고

divide() 메소드는 매개 변수로 나눗셈에 쓰일 두 수가 필요하다.

 

매개변수를 사용하여 방금전 보다는 좀 더 기능이 많은 계산기 객체를 하나 만들어보겠다.

 

기능 추가 (더하기, 전원 끄기)

CalcuExam에서는 Calcu 객체를 생성하고 참조 변수로 cal을 선언하였다. 

이후 참조 변수를 통해 도트(.)와 메소드이름 형태로 호출하여 메소드 블록을 실행시킨다. 

 

[매개 변수의 수를 모를 경우]

메소드의 매개 변수는 개수가 이미 정해져 있는 것이 일반적이지만, 경우에 따라서 알 수 없는 때도 있다고 한다.

이 때 해결책으로 매개 변수를 배열 타입으로 선언한다.

int sum1 (int[] values) { ... }

 

매개 변수를 배열 타입으로 선언하면, 메소드를 호출하기 전에 배열을 생성해야 하는 불편함이 있다. 

그래서 배열을 생성하지 않고 값의 리스트만넘겨주는 방법도 있으며

" ... "을 사용해서 선언하게 되면 메소드 호출 시 넘겨준 값의 수에 따라

자동적으로 배열이 생성되고 매개값으로 사용된다.

int sum2(int ... values) { ... }

 

예제) 매개 변수를 배열로 선언한 sum1()과 "..."로 선언한 sum2() 작성방법

int[] values / int ... values

한눈에 봐도 int ... values가 사용하기 쉽다는 것을 알 수 있다. 

선언 방법이 좀 다르긴 하지만 new를 두 번 선언해줘야하는 int[] values 보다는

값만 넣어주면 알아서 계산하는 int ... values를 더 자주 채택할 것 같다.

 


 

[리턴값이 있는 메소드]

위에서도 언급했지만, 리턴 타입이 있는 메소드는 반드시 리턴 문을 사용해서 리턴값을 지정해야 한다.

만약 return문이 없다면 컴파일 에러가 발생한다. 

return문 아래에는 어떤 문장도 오지 않으며 return문을 만나는 즉시 메소드는 종료된다.

 

return 리턴값;

int plus (int x, int y) {
    int res = x + y;
    retrun res;
    System.out.println(res); // 오류발생
}

진짜 나타나는지 이클립스에서 실행시켜보자.

확실히 눈이 편하다.

 

하지만 if문을 사용하면 return문 아래에 작성을 하여도 에러문이 뜨지 않는다.

if문과 return문

if문의 조건식이 정상적으로 실행될 경우 빨간줄은 그이지 않는다는 것을 볼 수 있다.

 

if문과 while문을 사용하여 내 자동차 내에 기름이 얼마나 남았는지 작성해보자.

결과물

결과물이 나올 때 스레드를 사용하면 oil잔량이 떨어지는 것을 초 단위로 찍혀나오게 할 수 있다는 것을 알지만 일단은 

오늘의 내용을 마치는데에 집중하고자 한다. 

 

[메소드 호출]

메소드는 클래스 내, 외부의 호출에 의해 실행된다.

클래스 내부의 다른 메소드에서 호출할 경우에는 단순한 메소드 이름으로 호출하면 되지만

 

클래스 외부에서 호출할 경우에는 

클래스로부터 객체를 생성한 뒤 참조변수를 이용해서 메소드를 호출해야 한다.

외부 호출시 객체 생성, 참조변수 이용 + 메소드 호출
void 외부메소드() {
    Car car = new Car();
    car.run();
    car.stop();
}
[메소드선언]
void run() { ... }
void stop() { ... }

void 내부메소드() {
    run();
    stop();
}

 

클래스 내부에서 메소드 호출한 예시와 호출 순서를 알아보자.

호출한 문장과 호출된 메소드들

 

다음은 클래스 외부에서 호출한 예제를 살펴보자.


[메소드 오버로딩]

클래스 내에 같은 이름의 메소드를 여러 개 선언하는 것을 메소드 오버로딩이라고 한다.

메소드 오버로딩의 조건은 '매개변수의 타입', '매개변수의 개수', '매개변수의 순서' 중 하나가 달라야 한다.

 

int plus(int x, int y) {
    int result = x + y;
    return result;
}

double plus(double x, double y) {
    double result = x + y;
    return result;
}

이후 plus() 메소드를 호출할 때 값에 정수를 주면 int plus()가 호출되고

값에 소숫점을 주면 double plus()가 호출된다. 

 

이처럼 메소드 오버로딩 할 때 주의할 점은 

매개 변수의 타입과 개수, 순서가 똑같을 경우 매개 변수 이름만 바꾸는 것은 메소드 오버로딩이라고 볼 수 없다.

또한 리턴 타입만 다르고 매개변수가 동일하다면 이도 메소드 오버로딩이라고 하지 않는다. 

 

이런 메소드 오버로딩의 대표적인 예는 표준 출력 메소드이다.

System.out.println()

 

마지막으로 메소드 오버로딩의 예제를 살펴보고 오늘의 포스팅을 마치고자 한다.

메소드 오버로딩을 통한 넓이 구하기

 

클래스가 가져야 할 구성 멤버

  1. 필드(Field) : 객체의 데이터가 저장되는 곳
  2. 생성자(Constructor) : 객체 생성 시 초기화 역할 담당
  3. 메소드(Method) : 객체의 동작에 해당하는 실행 블록

 

[필드]

객체의 고유 데이터, 부품 객체, 상태 정보를 저장하는 곳이다.
선언 형태는 변수와 비슷하지만 필드를 변수라고 부르지 않는다. 

변수는 생성자와 메소드 내에서만 사용되고 생성자와 메소드가 종료되면 자동 소멸되지만
필드는 생성자와 메소드 전체에서 사용되며 객체가 소멸되지 않는 한 객체와 함께 존재한다.

 

[생성자]

new 연산자로 호출되는 특별한 {} 블록이다.

생성자는 객체 생성 시 초기화를 담당하는데, 
필드를 초기화하거나 메소드를 호출해서 객체를 사용할 준비를 한다.

생성자는 메소드와 비슷하게 생겼지만, 클래스 이름으로 되어 있고 리턴 타입이 없다.

 

[메소드]

객체의 동작에 해당하는 {} 블록이다. 

이 때 {} 블록의 이름이 메소드 이름이다.

메소드를 호출하게 되면 { ... } 안의 모든 코드들이 일괄적으로 실행된다.

메소드는 필드를 읽고 수정하는 역할도 하지만 다른 객체를 생성해서 다양한 기능을 수행한다.
또한 객체 간의 데이터 전달의 수단으로도 사용되며 외부로부터 매개값을 받을 수 있고 
실행 후 어떤 값을 리턴할 수도 있다. 

 


필드

객체의 고유 데이터, 객체가 가져야 할 부품, 객체의 현재 상태 데이터를 저장하는 곳이다.

오늘도 많이 본 자동차를 예로 들어보자.

 

자동차 객체   자동차 클래스 | public class Car { ... }
[고유 데이터] 제작회사 고유 데이터
클래스
String company;
모델 String model;
색깔 String color;
최고속도 int maxSpeed;
[상태] 현재속도 상태
클래스
int speed;
엔진 회전 수 int rpm;
[부품] 차체 부품
클래스
Body body;
엔진 Engine engine;
타이어 Tire tire;

 

필드의 초기값은 필드 선언 시 주어질 수도 있고 생략될 수도 있다.

위의 표에 나온 '자동차 클래스'는 생략된 케이스이다.

 

[필드 선언 예시]

public class Car {

// 필드 초기값 선언
String company = "현대자동차";
String model = "그랜저";
int maxSpeed = 300;

// 필드 초기값 생략
int productionYear;
int currentSpeed;
boolean engineStart;

}

 

[필드 타입별 초기값]

분류 데이터 타입 초기값
기본 정수  - byte
 - char
 - short
 - int
 - long
 - 0
 - ' ' (공백)
 - 0
 - 0
 - 0L
int와 long의 차이:
L의 유무
실수  - float
 - double
 - 0.0F
 - 0.0
float과 double의 차이:
F의 유무
논리  - boolean false
참조  - 배열
 - 클래스 (String 포함)
 - 인터페이스
 - null
 - null
 - null

 


생성자

new 연산자와 같이 사용되어 클래스로부터 객체를 생성할 때 호출되어 객체의 초기화를 담당한다.

객체 초기화란, 필드 초기화 또는 메소드를 호출해서 객체를 사용할 준비를 하는 것을 말한다.

 

생성자를 실행시키지 않고는 클래스로부터 객체를 만들 수 없다.

 

[기본 생성자 (디폴트 생성자, default Constructor)]

모든 클래스는 생성자가 반드시 존재하며, 하나 이상을 가질 수 있다.

+++

[오답노트]

프로그래밍 언어 활용 시험 5번문제 - 디폴트 생성자를 생성하시오. 

기본 생성자는 매개변수를 하나도 가지지 않으며, 어떤 명령어도 포함하지 않는다.
문법으로는 클래스명을 따 온다.

클래스명() {}

+++

클래스가 public class로 선언되면 기본생성자에서도 public이 붙지만

클래스가 public 없이 선언되면 기본생성자에도 public이 붙지 않는다.

 

[public] 클래스() { ... }

 

[생성자 선언]

// 생성자블록
클래스(매개변수선언) {
	// 객체의 초기화 코드
}

// 객체의 초기화 코드에는 필드에 초기값을 작성하거나 메소드를 호출하여 객체 사용 전 필요한 준비를 한다.

매개변수선언은 생략할 수도 있고, 여러 개를 선언할 수도 있다. 

매개변수는 new 연산자를 통해 외부의 값을 생성자 블록 내부로 전달하는 역할을 한다.

Car myCar = new Car("그랜저", "검정", 300);

========

public class Car {
// 생성자
Car(String model, String color, int maxSpeed) { ... }
}

Car 클래스에 생성자 선언이 있기 때문에

기본생성자 [Car()]를 호출해서 객체를 생성할 수 없고

Car(String color, int cc)를 호출해서 객체를 생성해야 한다.

 

[필드 초기화]

클래스로부터 객체가 생성될 때 필드는 기본 초기값으로 자동설정된다.

이때 만약 다른 값으로 주고 싶다면 '필드를 선언할 때 초기값을 주는 방법'과 '생성자에서 초기값을 주는 방법'이 있다.

 

 

(1) 필드 선언 시 부여 (String nation;)

동일한 클래스로부터 생성되는 객체들은 모두 같은 데이터를 갖게 된다.

객체 생성 후 변경할 수 있지만, 객체 생성 시점에는 필드의 값이 모두 같다.

 

(2) 생성자 초기값 부여 (String name; / String birth;)

객체 생성 시점에 외부에서 제공되는 다양한 값들로 초기화되어야 할 때 사용한다.

name과 ssn의 필드값은 클래스를 작성할 때 초기값을 줄 수 없고 객체 생성 시점에 다양한 값을 가져야 한다.

 

11번째 줄을 보면 String n, s를 사용한 것을 볼 수 있다.

하지만 실제 코드를 작성할 때는 확 줄여서 그 의미를 모르게 하는 것보다 필드명을 그대로 사용함으로 

매개변수가 무엇을 의미한 것인지를 표시해주는 것을 추천한다.

 

우리가 스스로를 '나'라고 칭하듯이 객체가 객체 자신을 스스로 칭하는 것을 'this'라고 한다.

 

"this.필드"는 this라는 참조 변수로 필드를 사용하는 것과 동일하다. 

 

this.name = name; 에서

앞의 name은 필드이고, 뒤의 name은 매개변수이다. 

 

객체의 필드는 하나가 아니라 여러개 가 있고, 이 필드들을 모두 생성자에서 초기화한다면

생성자의 매개 변수의 수는 객체의 필드 수만큼 선언되어야 한다. 

 

하지만 실제로는 중요 몇 개 필드만 매개 변수를 통해 초기화되고 나머지는 필드 선언 시 초기화하거나

생성자 내부에서 임의의 값 또는 계산된 값으로 초기화한다. 

 

[생성자 오버로딩]

Car 객체를 생성할 때 외부에서 제공되는 데이터가 없다면 기본 생성자로 Car 객체를 생성해야 하고

외부에서 model 데이터가 제공되거나 model, color가 제공될 경우에도 Car 객체를 생성할 수 있어야 한다.

 

이에 자바는 다양한 방법으로 객체를 생성할 수 있도록 생성자 오버로딩(Overloading)을 제공한다.

 

'오버로딩'이란, 매개 변수를 달리하는 생성자를 여러 개 선언하는 것을 말한다. 

 

 

생성자 오버로딩

 

주의할 점이 있다면, 아래와 같이 다른 건 다 같으나 순서가 바뀐 것은 오버로딩이라고 볼 수 없다.

생성자 오버로딩 시 주의할 점

 

생성자가 오버로딩 되어 있을 경우 new 연산자로 생성자를 호출할 때 제공되는 

매개값의 타입과 수에 의해 호출될 생성자가 결정된다. 

 

 

생성자 선택 예시

 

[생성자 호출 this()]

생성자 오버로딩이 많아질 경우 생성자 간의 중복된 코드가 발생할 수 있다.

이런 현상은 매개 변수의 수만 달리하고 필드 초기화 내용이 비슷한 생성자에서 많이 목격된다.

이 때 필드 초기화 내용은 한 생성자에만 집중적으로 작성하고 나머지에서는 초기화 내용을 가지고 있는 생성자 호출방법을 사용한다.

 

다음은 생성자에서 다른 생성자를 호출할 때에 쓰이는 코드와 사용방법이다.

클래스 ( [매개변수선언] ) {
    this( 매개변수, ..., 값, ...); 	// 클래스의 다른 생성자 호출
    실행문;
}

this() 는 자신의 다른 생성자를 호출하는 코드로 반드시 생성자의 첫줄에서만 허용된다. 

this() 다음에는 추가적인 실행문들이 올 수 있다. 

--> 호출되는 생성자의 실행이 끝나면 원래 생성자로 돌아와서 다음 실행문을 진행한다는 뜻이다. 

 

아래는 중복코드와 변화된 코드이다.

생성자 호출 this()

왼쪽의 CarThis 클래스를 적으면서 느낀 점은 이걸 이렇게 쓰기는 할까? 라는 의문인데 

아직 이렇다 할 경험이 없으니 일단 적고 넘어가겠다. 

 

아무튼 왼쪽의 CarThis를 오른쪽의 CarThis2로 변화시켜 보았다. 확실히 줄은 줄었으나

'굳이?'라는 생각은 사라지지 않는다.


이 글을 적으면서 느끼는 것은 객체에 관한 것은 직접 만들어봐야 는다는 것이다.

(뭐든 이렇지 않겠나마는...)

 

오늘은 책에 적힌 자동차로 공부를 하였다면 

내일은 우리가 하루도 빠짐없이 보는 스마트폰을 예제로 사용할 수 있고 

그 다음날은 또 다른 것으로 예를 들어볼 수 있을 것이다. 

 

결론:

공부도 당연하지만 직접 만들고 고민해보는 시간을 가지자.

지금 머리가 아파야 훗날이 편하다. (아마도)

[새로운 용어: new]  

new는 클래스로부터 객체를 생성시키는 연산자이다.

new 연산자 뒤에는 생성자가 따라오며, 생성자의 형태는 "클래스()" 형태를 가지고 있다.

 

현실세계에서 물건의 위치를 모르면 물건을 사용할 수 없듯이

객체 지향 프로그램에서도 메모리 내 생성된 객체의 위치를 모르면 객체를 사용할 수 없다.

 

new 연산자는 힙 영역에 객체를 생성시킨 후 객체의 주소를 리턴하도록 되어 있으며 

이 주소를 참조 타입인 클래스 변수에 저장 후 변수를 통해 객체를 사용할 수 있게 한다. 

 

// 자동차 클래스 선언
public class Car {

}
public class CarExam {
	public static void main(String[] args) {
    	// 표현1
//        Car car;
//        car = new Car();
        
        // 표현2
        Car car = new Car();
    }
}

표현 1과 표현2는 둘 다 클래스 변수 선언과 객체 생성을 하는 것이지만 보통 표현2를 더 자주 쓴다.

 

Car와 CarExam의 차이는 Car의 경우 라이브러리(API : Application Program Interface) 용이고CarExam의 경우 실행용이다.

 

프로그램 전체에 사용되는 클래스가 n개라면, 1개는 실행용이고, n-1개는 모두 라이브러리라고 보면 된다. 

 

실행 클래스는 main() 메소드를 가지고 있다.물론 main() 메소드가 있는 곳에서도 라이브러리를 만들 수 있다.

public class Car {

	String name;
    int maxSpeed;
    int releaseYear;
    
    public static void main (String[] args) {
    	Car car1 = new Car();
        Car car2 = new Car();
    }
}

 

사용하고자 하는 객체 : 자동차, 사람, 동물 등 상위 카테고리 중 결정

 

[클래스 이름 작성 규칙]

번호 작성 규칙
1  하나 이상의 문자로 이루어져야 한다.  Car, SportsCar
2  첫 번째 글자는 숫자가 올 수 없다.  Car (o)  / 3Car (x)
3  달러($), 언더바(_) 외의 특수 문자는 사용할 수 없다.  $Car, _Car (o) / @Car, !Car (x)
4  자바 키워드는 사용할 수 없다.  int, for (x)

 

클래스 이름은 한글로 지어도 상관은 없지만 한글로 이름을 짓는 경우는 거의 없다.

또한 자바는 영어 대소문자를 다른 문자로 취급하기 때문에 클래스 이름도 대소문자로 구분한다.

 

관례적으로 첫 자는 대문자로 하고 뒤이어 나오는 문자들은 소문자로, 

따라나오는 단어가 하나 더 붙으면 두 번째 단어의 첫 자도 대문자로 적는다.

 

ex.)

  • Car, Calculator, Person
  • SportsCar, EngineerCalculator, MedicalPerson

 

[클래스 선언]

// 자동차 클래스 생성
public class Car {

}

가급적이면 소스 파일 하나 당 하나의 클래스만 선언한다. 

 

두 개 이상의 클래스를 선언해도 되지만 소스 파일을 컴파일하면 2개의 바이트 코드 파일이 생성된다.

아래 예제의 경우 컴파일 시 Car.class 파일과 Tire.class 파일 2개가 생성된다고 보면 된다.

 

// public : 파일 이름과 동일한 클래스 선언에서만 사용 가능
public class Car {

}

class Tire {

}

 

public의 경우 파일과 동일한 이름의 클래스가 아닌 상황에 사용을 하게 된다면

컴파일 에러가 날 수 있다. 

객체는 클래스라는 설계도를 바탕으로 만들어진다.

 

클래스라는 설계도에는 객체라는 재료와 메소드라는 기능이 들어간다.

재료를 핸들이라고 했을 때, 기능은 왼쪽과 오른쪽으로 돌아가는 기능이 들어갈 것이고

재료를 타이어라고 했을 때, 기능은 앞으로 나가는 것과 뒤로 가는 것이 있을 것이며

재료를 라이트라고 했을 때, 기능은 켜지는 것과 꺼지는 것이 있을 것이다.

 

핸들은 자동차에 한 개만 들어가지만 타이어는 4개, 라이트는 많은 곳에 들어간다.

그런 부품들을 각기 객체화한 후 조립하면 자동차라는 설계도가 만들어지게 된다.

 

클래스로부터 만들어진 객체를 해당 클래스의 인스턴스라고 하는데 

이 때 자동차 객체는 자동차 클래스의 인스턴스라고 부를 수 있다.

 

더하여 클래스로부터 객체를 만드는 과정을 인스턴스화라고 하며 

둘을 이어 붙여 객체의 인스턴스화라고 한다. 

 

얼마 전에 수업 내용 중에 "객체의 인스턴스화 다들 알지요~?" 하는 질문에 머리가 하얘졌던 적이 있다.

 

객체도 만드는데 한참 걸리는데 객체의 인스턴스화가 뭔데.. 

 

그러다 흔히들 말하는 '바보 도 터지는 소리'를 내며 자주 가는 식당의 물잔이 떠올랐다.

늘 4명이서 함께 밥을 먹다 보니 물잔이 겹쳐져 있는 상태로 상 위에 놓여져 있는데 

이 때 하나의 물잔을 클래스로부터 만들어낸 인스턴스라고 한다면 

나머지 3개의 물잔을 보고 객체의 인스턴스화라고 할 수 있는 것이 아닐까 하는 생각이 든 것이다. 

 

식당에 가면 흔히 나오는 스테인리스 물잔 하나. 

하지만 한 상에 사람이 4명이 앉는다 하면 그 물잔은 총 4잔이 나와야 한다.

 

그럼 똑같은 물잔 4개가 나오는데 각기 한 사람 앞에 하나의 물잔이 가니 물잔마다 역할을 하는 것이기에

이 때 물잔 4개를 객체의 인스턴스화를 겪은 물잔들이라고 볼 수 있지 않을까 하는 생각이 든 것이다. 

 

--- 

 

[객체 지향 프로그래밍 개발, 3단계]

1. 클래스 설계

 

2. 클래스 내 객체 설계

 

3. 생성된 객체 이용

 

next : 클래스 선언

 

 

1. 객체란? 

물리적으로 존재하거나 추상적으로 생각할 수 있는 것 중에서 자신의 속성을 가지고 있고 다른 것과 식별 가능한 것을 말한다.
물리적으로 존재하는 것 : 자동차, 자전거, 책, 사람 등등
추상적으로 생각할 수 있는 것 : 학과, 강의, 주문 등등

 

  • 객체는 속성과 동작으로 구성되어 있다.
  • 사람은 이름과 나이라는 속성이 있고 걷다, 뛰다 등의 동작이 있다.
  • 자동차는 모델명, 색상이라는 속성이 있고, 달린다와 멈춘다는 동작이 있다.
  • 자바에서는 속성을 필드, 동작을 메소드라고 부른다. 

 

(1) 객체 모델링(Object Modeling)

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

 

2. 객체의 상호작용

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

 

계산기로 예를 들어보자.
사람이 계산기에 어떤 값을 입력하여 주면 계산기는 그에 맞는 결과값을 사람에게 보여준다.

 

소프트웨어에 적용시켜보자.

객체들은 각각 독립적으로 존재하고 타 객체와 상호작용하면서 동작한다.

 

객체들 사이의 상호작용 수단은 '메소드'이다.

객체가 타 객체의 기능을 이용하는 것을 '메소드 호출'이라고 한다.

 

메소드 호출을 해보기 전에 계산기의 속성과 동작을 간단하게 알아보자.

 

계산기의 속성은 모델명과 회사명으로 하고 동작은 더하기와 빼기로 해보자.

원하는 결과가 나왔으니 패스한다.

메소드 호출은 맨 아래에 보이듯 

객체명.메소드명(매개값1, 매개값2)로 표현한다.

 

3. 객체 간의 관계

객체는 개별적으로 사용될 수도 있지만 대부분 다른 객체와 관계를 맺고 있다.

이런 관계의 종류에는 집합, 사용, 상속 관계가 존재한다.

 

[집합 관계 : 집약 + 합성]

집합관계 특징
집약(Aggregation)  - 전체 객체의 부분 객체의 생명 주기가 다르다. 
 - 부분 객체를 여러 전체 객체가 공유할 수 있다.
합성(Compositon)  - 전체 객체가 없어지면 부분 객체도 없어진다.
 - 부분 객체를 여러 전체 객체가 공유할 수 없다.

 

[사용 관계 / Use A]

  • 가장 일반적이다.
  • 다른 클래스의 객체를 메소드 인자로 받아 사용하거나 메소드 내에서 다른 클래스의 객체를 생성하여 사용한다.
  • 사용 관계이지만 사용하는 객체를 멤버 변수로 유지할 수 있다.
  • 사용 관계이면서 포함 관계도 가능하다.
  • 예를 들어, 사람은 자동차를 사용하므로 사람과 자동차는 사용관계라고 볼 수 있다.

 

[상속 관계 / Is A]

  • BMW is a car.
  • Audi is a car.
  • Child class is a Parent class.
개념
상위(부모) 객체를 기반으로 하위(자식) 객체를 생성하는 관계를 말한다.
일반적으로 상위 객체는 종류를, 하위 객체는 구체적인 사물에 해당한다. 

장점 
(1) 코드의 재사용이 가능하다. 
→ 자식 클래스를 만들 때 편하다.

(2) 다양한 객체를 처리할 수 있는 공통 리모컨이 생긴다.

 

[객체 지향 프로그래밍(OOP, Object Oriented Programming)]

만들고자 하는 완성품인 객체를 모델링하고

집합 관계에 있는 부품객체와 사용관계에 있는 객체를 하나씩 설계 후

조립하는 방식으로 프로그램을 개발하는 기법이다.

 

4. 객체 지향 프로그래밍의 특징

객체 지향 프로그램의 특징으로는 캡슐화, 상속, 다형성이 있다. 

(1) 캡슐화 : 정보은닉

객체의 필드와 메소드를 하나로 묶고 실제 구현 내용을 감추는 것을 말한다.

목적으로는 외부의 잘못된 사용으로 인해 객체가 손상되지 않도록 한다.
자바는 접근제한자를 사용하여 캡슐화된 멤버를 노출시킬지, 숨길지를 결정한다.

즉, 접근 제한자는 객체의 필드와 메소드의 사용 범위를 제한함으로써 외부로부터 보호한다.

 

[접근제어자]

접근제어자는 클래스 접근제어자와 메소드 접근제어자로 나뉜다.

 

클래스 접근제어자
default  - 동일 패키지의 클래스(class)에만 인스턴스(객체)를 생성가능
public  - 다른 패키지에서 인스턴스(객체)를 생성가능

 

메소드 접근제어자
public  - 모든 객체에서 접근 가능하다.
private  - 동일한 클래스 안에서만 접근이 가능하고, this를 사용하는 것들은 외부에서 접근 불가능하고 상     속도 안 된다.
default  - 접근제어자가 없는 형태로 동일한 패키지 안에서만 접근이 가능하다.
protected  - 동일한 패키지 안에서 사용가능하고, 다른 패키지라도 상속받은 클래스에는 접근이 가능하다.

 

(2) 상속

일반적으로 상속이라 했을 때 자식이 부모의 재산을 물려받는다라는 개념을 떠올린다.

 

객체 지향 프로그래밍에서도 부모 역할의 상위 객체자식 역할의 하위 객체가 있다.

상위 객체는 자기가 갖고 있는 필드와 메소드를 하위 객체에게 물려주어 하위 객체가 사용할 수 있도록 해준다.

 

상속은 상위 객체를 재사용하여 하위 객체를 쉽고 빨리 설계할 수 있도록 도와주고

이미 잘 개발된 객체를 재사용하여 새로운 객체를 만들기 때문에 반복된 코드의 중복을 줄여준다.

 

게시글 상속 응용

코드를 보면 Board 클래스 안에 변수들 4개를 선언할 걸 볼 수 있다.

 

그에 반해 Gallery 클래스와 Notice 클래스에는 그림파일 첨부값만 있거나

아무 내용이 없다는 것을 볼 수 있다.

Board 클래스로부터 상속받아 오기에 Gallery 클래스는 기존에 이미지파일 첨부 값만 넣어준 것이며

Notice 클래스는 받아오기만 하고 아무것도 입력 안 한 모습을 볼 수 있다. 

 

상속을 받아올 때는 '자식클래스명 extends 부모클래스명'이라고 입력하면 된다.

 

(3) 다형성

같은 타입이지만 실행 결과가 다양한 객체를 이용할 수 있는 성질을 말한다.

코드 측면에서 보면 다형성은 하나의 타입에 여러 객체를 대입함으로써 다양한 기능을 이용할 수 있도록 해 준다.

 

타이어를 예로 들면, 타이어의 규격이 정해져 있다고 하면 타이어 사는 규격에 맞춰서 자신들만의 타이어를 제품으로 내 놓는다고 생각하면 된다.  

 

[참조변수의 다형성]

class Samsung {...}
class Samsung extends Company {...}
...
Company com = new Company(); // 허용
Samsung ss = new Samsung(); // 허용
Company co = new Samsung(); // 허용
Samsung sam = new Company(); // 오류.

 

[참조 변수의 타입 변환]

  • 서로 상속 관계에 있는 클래스 사이에만 타입 변환을 할 수 있다.
  • 자식 클래스 타입에서 부모 클래스 타입으로서 타입 변환은 생략할 수 있다.
  • 부모 클래스 타입에서 자식 클래스 타입으로의 변환은 반드시 명시해야 한다.
class Samsung {...}
class Posco {...}
class Samsung extends Company {...}
...
Company com1 = null;
Samsung ss = new Samsung();
Company com2 = new Company();
Posco po = null;

com1 = ss; 		// com1 = (Company) ss; 와 같으며, 타입변환 생략가능.
po = (Posco) com2; 	// 타입변환 생략불가.
po = (Posco) ss; 	// 직접적인 상속관계가 아니므로 오류 발생

 

* 참고사이트 및 서적 *

[서적]

이것이 자바다 - ch6-1. 클래스 - 객체지향프로그래밍

 

[사이트]

  1. https://velog.io/@eunseo-kim/%EC%9E%90%EB%B0%94-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-%ED%81%B4%EB%9E%98%EC%8A%A4-%EA%B0%84-%EA%B4%80%EA%B3%84-%EA%B0%9D%EC%B2%B4-%EA%B0%84-%EA%B4%80%EA%B3%84
 

[자바 프로그래밍] 클래스 간 관계, 객체 간 관계 - (1)

클래스 간 관계 상속 (inheritance, is-a) 관계 구체화 (realization) 관계 > ⛔ 주의 : 클래스 간 관계에서 '클래스'는 class와 interface 모두를 아우르는 개념임 자바에서 클래스 간 관계는 정적 관계(클래스

velog.io

 

2. https://defacto-standard.tistory.com/104

 

집합관계

집합 관계 UML 연관 관계의 특별 경우로 전체와 부분의 관계를 명확하게 명시하고자 할 때 사용. 집약과 합성 두 종류의 집합 관계가 존재. has a 관계 집약 관계는 한 객체가 다른 객체를 포함하는

defacto-standard.tistory.com

 

3. https://radait.tistory.com/5 

 

자바[Java] 캡슐화[Encapsulation]란? 무엇인가?

캡슐화는 관련이 있는 변수와 함수를 하나의 클래스로 묶고 외부에서 쉽게 접근하지 못하도록 은닉하는게 핵심입니다. 객체에 직접적인 접근을 막고 외부에서 내부의 정보에 직

radait.tistory.com

 

4. http://www.tcpschool.com/java/java_polymorphism_concept

 

코딩교육 티씨피스쿨

4차산업혁명, 코딩교육, 소프트웨어교육, 코딩기초, SW코딩, 기초코딩부터 자바 파이썬 등

tcpschool.com

 

목차

[클래스]

 

1. 객체(object)

  (1) 객체란?

  • 특성과 기능을 가지는 하나의 독립적인 개체
  • 특성 : 객체가 가지는 데이터
  • 기능 : 객체의 특성을 이용한 실행 방법

  (2) 객체 모델링

  • 객체의 특성과 기능을 분석하고 정리하는 작업 (예시 : 스마트폰)
  • 특성 :  색상, 크기, 모델명, 전화번호
  • 기능 : 전화 걸기, 사진 찍기, 앱 실행하기 

  (3) 클래스 정의

  • 객체 모델링 후 특성과 기능을 정의하는 도구
  • 특성은 변수로 정의
  • 기능은 메소드로 정의 후 구현
class SmartPhone {

// 변수
double lcdSize;
String caseColor;
String cameraPixel;
String modelName;
String phoneNumber;

// 메소드

void MakeACall() { ... }
void TakingPictures() { ... }
void playApp() { ... }

}

  (4) 객체 생성 후 사용

  • 정의된 클래스를 new 연산자를 이용하여 메모리에 할당
  • 메모리에 할당된 클래스 : 객체, 인스턴스(instance), 클래스의 변수
  • 객체 사용 : 점(.)을 이용하여 클래스에 정의된 변수를 사용하거나 메소드를 호출
SmartPhone galaxy = new SmartPhone(); 
SmartPhone iPhone = new SmartPhone();
// galaxy, iPhone == SmartPhone 클래스의 객체 (참조형 변수)

// 변수
galaxy.modelName = "galaxy s21+";
iPhone.modelName = "iPhone 11";

// 메소드
galaxy.turnOff(); 
galaxy.turnOn(); 
iPhone.turnOff();
iPhone.turnOn();

 

 

2. 객체지향 프로그램 구현

  (1) 클래스 이름 정의

  • 변수명 규칙과 동일
  • 관행적으로 첫 문자는 대문자로 한다.

  (2) 멤버변수와 메소드

  • 멤버변수 (필드) : 클래스 내부에 정의된 변수
  • 멤버메소드 (메소드) : 클래스 내부에 정의된 메소드
  • 멤버변수와 메소드는 관행적으로 소문자로 시작한다.

  (3) 메소드 구현하기

  • 메소드 : 반복되어 실행될 명령문들을 모아놓은 모듈

메소드 구조

  (4) 반환값 규칙

  • 반환값 (O) : return문에서 반환하는 값의 자료형과 일치해야 한다.
  • 반환값 (X) : void로 정의하고, return문을 생략할 수 있다.

  (5) 입력 매개 변수

  • 입력 매개 변수를 지정하지 않아도 된다.
  • 입력 매개 변수의 개수는 원하는 만큼 정의하여 사용할 수 있다.
// 입력 매개변수 == (int a, int b)
int running (int a, int b)
{
int c = a * b;
...
return c;
}

// 입력 매개변수가 없는 경우 == ()
int running()
{
int c = a * b;
...
return c;
}

 

  (6) main() 메소드

  • 프로그램의 시작 메소드
  • 클래스 내부에 정의되지만 멤버 메소드는 아니다.
class SmartPhone {

	public static void main (String[] args) {
    
    }
}

  (7) 객체 생성하기

  • main() 메소드에서 생산한다.
class SmartPhone {
	public static void main (String[] args) {
    	// 객체 생성
        SmartPhone g = new SmartPhone();
        SmartPhone i = new SmartPhone();
    }
}

  (8) 멤버 변수와 메소드 사용하기

  • 멤버 변수는 객체 생성 시 자동 초기화 됨
  • 수치관련 변수는 0, 문자 관련 변수는 null
  • 멤버 변수와 메소드는 객체 생성 후 사용
class SmartPhone {
	public static void main (String[] args) {
    	SmartPhone g = new SmartPhone();
        SmartPhone i = new SmartPhone();
        
        g.modelName = "galaxy s21+";
        i.modelName = "iPhone 11";
        
        g.turnOn();
        g.turnOff();
        i.turnOn();
        i.turnOff();
    }
}

 

 

3. 생성자 메소드

  (1) 생성자 메소드란?

  • 객체를 생성 시 호출되는 메소드
  • 멤버 변수의 초기화 작업

  (2) 메소드 생성자 규칙

  • 클래스 이름과 동일해야 한다.
  • public 키워드 지정해줘도 되나 필수는 아니다.
  • 반환값 자료형은 지정하지 않으며 반환값이 없다는 의미의 void도 지정하지 않는다.

  (3) 디폴트 생성자 메소드 

  • 매개변수가 없는 생성자 메소드

  (4) 사용자 정의 생성자 메소드

  • 매개변수가 있는 생성자 메소드

  (5) 생성자 메소드 정의 시 유의할 점

  • 클래스 정의 시 디폴트 생성자 메소드를 항상 정의하면 문제 없음.

+ Recent posts