본문 바로가기
Java/Basic

객체지향

by 최로이 2021. 3. 3.

1. 객체지향언어

1.1 객체지향언어의 특성

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

 

2. 클래스와 객체

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

  • 클래스의 정의: 객체를 정의해 놓은 것
  • 클래스의 용도: 객체를 생성하는 것
  • 객체의 정의: 실제로 존재하는 것으로 사물 또는 개념
  • 객체의 용도: 객체의 속성과 기능에 따른 용도

2.2 객체와 인스턴스

클래스가 설계도라면 객체는 설계도에 따라 그 속성과 기능이 실체화 된 것이라고 볼 수 있다.

이때 객체(Object)는 인스턴스(Instance)를 포함하는 일반적인 의미로 사용된다. 쉽게 말해 '객체≒인스턴스'라고도 볼 수있다. 우리가 종종 얘기하다보면 '인스턴스화'라는 얘기를 듣곤 하는데 이때 인스턴스화는 클래스로부터 객체를 생성하는 과정을 의미한다.

 

2.3 객체의 구성요소(변수, 메소드)

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

객체는 속성과 기능으로 구성돼 있는데, 이를 변수와 메소드(함수)라고 한다. 그리고 이 속성과 기능을 객체의 멤버라고도 한다. 만약 TV라는 객체가 있다면 TV클래스의 변수(속성)는 크기, 길이, 높이, 색상  볼륨, 채널 등과 같은 객체의 성질을 나타내며, 메소드(기능)는 켜기, 끄기, 볼륨 변경, 채널 변경 등을 말할 수 있다. 

class Tv{
	String color; //샐깔
    boolean power; //전원상태(on/off)
    int channel; // 채널
    
    void power{} { power = !power; } //전원on/off
    void channelUp {channel++;} //채널 높이기
    void channelDown {channel--;} //채널 낮추기
}

2.4 인스턴스의 생성과 사용

1) 객체(인스턴스)의 생성방법

클래스명 참조변수명 = new 클래스명(); //객체를 다루기 위한 참조변수 선언과 생성된 객체에 주소를 참조변수에 저장.
Tv t = new Tv();

참조변수와 객체

2.5 객체 배열

객체 배열은 말 그대로 객체를 배열형식으로 다루는 것이다. 앞에 설명한 참조형 배열의 선언방식과 비슷하며, 구조도 마찬가지다. 여기서 주의점은 객체의 정보가 직접적으로 저장되는 것이 아니라 객체의 주소가 저장된다는 것. 객체 배열은 참조변수들을 하나로 묶음 참조 변수 배열인 셈이다.

 

Tv tv1, tv2, tv3 → Tv[] tvArr = new Tv[3]; // 길이가 3인 Tv타입의 참조변수 전달

객체의 참조변수 생성

위 그림은 그림과 같이 참조변수와 객체가 생성된 것 뿐이지 값이 초기화 되지 않아 기본 값은 null이 있다. 각 요소에 초기화 블럭을 사용하면, 다음과 같이 한 줄로 간단히 할 수 있다.

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

 

3. 변수와 메소드

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

변수의 종류 선언위치 생성시기
클래스변수 클래스 영역 클래스가 메모리에 올라갈 때
인스턴스변수 인스턴스가 생성되었을 때
지역변수 클래스 영역 이외에(메소드, 생성자, 초기화 블럭 내부) 변수 선언문이 수행되었을 때
class Variable{

int iv;//인스턴스 변수
static int cv;	//클래스 변수(static변수, 공유변수)
	
    void method(){
    	int lv = 1;	//지역변수
    }
}

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

  클래스 영역에 선언되며, 클래스의 인스턴스를 생성할 때 만들어진다. 그렇기 때문에 인스턴스 변수의 값을 읽어 오거나 저장하기 위해서는 먼저 인스턴스를 생성해야 한다.

  인스턴스는 독립적인 저장공간을 가지므로 서로 다른 값을 가질 수 있다. 인스턴스마다 고유한 상태를 유지해야하는 속성의 경우, 인스턴스변수로 선언한다.

 

2) 클래스변수(class variable)

  클래스변수는 인스턴스 변수 앞에 static만 붙이면 된다. 인스턴스마다 독립적인 저장공간을 갖는 인스턴스변수와는 달리, 클래스변수는 모든 인스턴스가 공통된 저장공간(변수)를 공유하게 된다. 그렇기 때문에 클래스변수는 모든 인스턴스가 공통된 값을 유지해야 하는 속성의 경우 선언하여 사용하면 된다.

  클래스변수는 인스턴스변수와 달리 인스턴스를 생성하지 않고도 언제라도 바로 사용할 수 있다는 특징이 있고, '클래스명.클래스변수'와 같은 형식으로 사용한다. 예를 들어 Variable클래스의 클래스변수 cv를 사용하려면 'Variable.cv'와 같이 사용하면 된다.

  클래스가 메모리에 로딩될 때 생성되어 프로그램이 종료될 때까지 유지되고, 'public'을 앞에 붙여 사용하면 같은 프로그램 내에서 어디서나 접근할 수 있는 전역변수의 성격을 갖게 된다.

 

3) 지역변수(local variable)

  메소드 내에 선언되어 메소드 내에서만 사용할 수 있는 변수. 메소드가 종료되면 같기 소멸되어 사용할 수 없다. 조건문이나 반복문과 같이 블럭내에 선언된 지역변수는 블럭내에서만 사용 가능하며, 블럭을 벗어나면 소멸되어 사용할 수 없다. 

 

3.2 메소드(Method)

메소드는 특정 작업을 수행하는 일련의 문장들을 하나로 묶은 것이다. 기본적으로 수학의 함수와 유사하고, 어떤 값을 '입력'하면 작업을 '수행'하여 결과를 '반환(출력)'한다.  하지만 해당 메소드가 내부적으로 어떤 과정을 거쳐 결과를 만들어내닌즈 전혀 몰라도 된다. 즉, 메소드에 넣은 값(입력)과 결과(출력)만 알면 된다. 예를 들어 빈번히 사용하는 println()과 같은 메소드를 내부적으로 어떻게 동작하는지 몰라도 사용하는데 아무런 어려움이 없듯이.

 

메소드를 사용하는 이유

1) 높은 재사용성(reusability)

  -이미 Java API에서 제공하는 메소드들은 몇 번이고 호출할 수 있으며, 다른 프로그램에서도 사용이 가능하다.

2) 중복된 코드의 제거

  -프로그램 작성시 같은 내용의 문장들이 여러 곳에 반복해서 나타나게 되는데 이랗게 반복되는 문장들을 묶어서 하나의 메소드로 작성하면 반복되는 문장들 대신 메소드를 호출하는 한 문장으로 대체할 수 있다. 이렇게 되면 전체 소스 코드의 간략화, 수정량 감소, 오류 발생 가능성 감소로 이어진다. 

3) 프로그램의 구조화

  -만약 프로그램을 작성해야 하는데 그 크기가 몇 만줄이라면? 이럴 경우 메소드별 작업단위로 나눠서 여러 갸의 메소드에 담아 프로그램의 구조를 단순화 시키는 것이 필수적이다.

 

 

 

3. 변수와 메소드

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

**변수의 종류 선언위치 생성시기

-클래스변수 클래스 영역 클래스가 메모리에 올라갈 때

-인스턴스변수 인스턴스가 생성되었을 때

-지역변수 클래스 영역 이외에(메소드, 생성자, 초기화 블럭 내부) 변수 선언문이 수행되었을 때

class Variable{

int iv;//인스턴스 변수
static int cv; //클래스 변수(static변수, 공유변수)

    void method(){
     int lv = 1; //지역변수
    }
}

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

클래스 영역에 선언되며, 클래스의 인스턴스를 생성할 때 만들어진다. 그렇기 때문에 인스턴스 변수의 값을 읽어 오거나 저장하기 위해서는 먼저 인스턴스를 생성해야 한다.

인스턴스는 독립적인 저장공간을 가지므로 서로 다른 값을 가질 수 있다. 인스턴스마다 고유한 상태를 유지해야하는 속성의 경우, 인스턴스변수로 선언한다.

 

2) 클래스변수(class variable)

클래스변수는 인스턴스 변수 앞에 static만 붙이면 된다. 인스턴스마다 독립적인 저장공간을 갖는 인스턴스변수와는 달리, 클래스변수는 모든 인스턴스가 공통된 저장공간(변수)를 공유하게 된다. 그렇기 때문에 클래스변수는 모든 인스턴스가 공통된 값을 유지해야 하는 속성의 경우 선언하여 사용하면 된다.

 

클래스변수는 인스턴스변수와 달리 인스턴스를 생성하지 않고도 언제라도 바로 사용할 수 있다는 특징이 있고, '클래스명.클래스변수'와 같은 형식으로 사용한다. 예를 들어 Variable클래스의 클래스변수 cv를 사용하려면 'Variable.cv'와 같이 사용하면 된다.

 

클래스가 메모리에 로딩될 때 생성되어 프로그램이 종료될 때까지 유지되고, 'public'을 앞에 붙여 사용하면 같은 프로그램 내에서 어디서나 접근할 수 있는 전역변수의 성격을 갖게 된다.

 

3) 지역변수(local variable)

메소드 내에 선언되어 메소드 내에서만 사용할 수 있는 변수. 메소드가 종료되면 같기 소멸되어 사용할 수 없다. 조건문이나 반복문과 같이 블럭내에 선언된 지역변수는 블럭내에서만 사용 가능하며, 블럭을 벗어나면 소멸되어 사용할 수 없다. 

 

 

 

3.2 메소드(Method)

메소드는 특정 작업을 수행하는 일련의 문장들을 하나로 묶은 것이다. 기본적으로 수학의 함수와 유사하고, 어떤 값을 '입력'하면 작업을 '수행'하여 결과를 '반환(출력)'한다. 하지만 해당 메소드가 내부적으로 어떤 과정을 거쳐 결과를 만들어내닌즈 전혀 몰라도 된다. 즉, 메소드에 넣은 값(입력)과 결과(출력)만 알면 된다. 예를 들어 빈번히 사용하는 println()과 같은 메소드를 내부적으로 어떻게 동작하는지 몰라도 사용하는데 아무런 어려움이 없듯이.

 

**메소드를 사용하는 이유**

1) 높은 재사용성(reusability)

  :: 이미 Java API에서 제공하는 메소드들은 몇 번이고 호출할 수 있으며, 다른 프로그램에서도 사용이 가능하다.

2) 중복된 코드의 제거

  :: 프로그램 작성시 같은 내용의 문장들이 여러 곳에 반복해서 나타나게 되는데 이랗게 반복되는 문장들을 묶어서 하나의 메소드로 작성하면 반복되는 문장들 대신 메소드를 호출하는 한 문장으로 대체할 수 있다. 이렇게 되면 전체 소스 코드의 간략화, 수정량 감소, 오류 발생 가능성 감소로 이어진다. 

3) 프로그램의 구조화

  :: 만약 프로그램을 작성해야 하는데 그 크기가 몇 만줄이라면? 이럴 경우 메소드별 작업단위로 나눠서 여러 갸의 메소드에 담아 프로그램의 구조를 단순화 시키는 것이 필수적이다.

 

3.3 메소드의 선언과 구현

메소드는 구성은 '선언부(header)'와 '구현부(body)'로 이루어져 있다.

public class methodEx {
	int add(int x, int y) {	//선언부
		int result = x + y; //구현부
		return result;	    //호출한 메소드로 결과를 반환(구현부2)
	}
}

메소드를 선언하고 구현할 때 주의사항은 선언된 메소드와 반환값의 타입이 일치해야 한다.

add는 int형이고 result도 int형으로 되어 있는 것을 볼 수 있다. 만약 이렇게 안 될 경우 자동 형변환이 가능한 것이어야 한다. 

int add(int x, int y){
	int result = x + y;
    return result; //작업 결과(반환값)를 반환한다.
}

 

1) 메소드 선언부

메소드 선언부는 메소드 명, 매개변수 선언, 반환타입으로 구성되어 있다. 메소드가 작업을 수행하기 위해 어떤 값들을 필요로 하고 작업의 결과로 어떤 타입의 값을 반환하는지에 대한 정보를 제공한다.

아래의 정의된 메소드 add는 두개의 매개변수를 통해 정수를 입력받고 두 값을 더한 결과(int타입의 값)를 반환한다.

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

특히 메소드 선언부는 변경사항이 발생하지 않도록 신중히 작성해야한다. 메소드의 선언부를 변경하게 되면, 그 메소드가 호출되는 모든 곳도 같이 변경되어야 하기 때문에.

 

2) 매개변수 선언

매개변수는 메소드가 작업을 수행하는데 필요한 값들(입력)을 제공받기 위한 것이며, 필요한 값의 개수만큼 변수를 선언하며 각 변수 간의 구분은  쉼표(',')를 사용한다. 한 가지 주의할 점은 일반적인 변수선언과 달리 두 변수의 타입이 같아도 변수의 타입을 생략할 수 없다. 선언할 수 있는 매개변수의 개수는 거의 제한이 없지만, 만약 입력해야 할 값의 개수가 많을 경우 배열이나 참조변수를 사용하면 된다. 만일 값을 전혀 입력받을 필요가 없다면 괄호() 안에 아무 것도 적지 않는다.

**매개변수도 메소드 내에 선언된 것으로 간주되므로 지역변수(lv)다.

 

3) 메소드명

메소드명도 변수의 선언 방식과 같게 작성하면 된다. 메소드명은 특정 작업을 수행하기 때문에 보통 동사인 경우가 많으며, 이름만으로도 해당 메소드가 어떤 기능을 하는지 알 수 있도록 함축적이면서도 의미있는 이름을 짓도록 하는 것이 좋다.

 

4) 반환타입(return type)

메소드의 작업수행 결과(출력)인 반환값의 타입을 적는다. 만약 반환타입이 없을 경우 반환타입으로 void를 적어야 한다.

 

 

5) 메소드의 구현부

메소드의 구현부는 괄호{ } 안에 있는 부분을 말하는데, 메소드를 호출했을 때 수행될 문장들을 넣는다.

 

6) return문

메소드의 반환타입이 void가 아닌 경우, 구현부 { } 안에 'return 반환값;'이 반드시 포함되어 있어야 한다. 이 문장은 작업을 수행한 결과인 반환값을 호출한 메소드로 전달하는데, 이 값의 타입은 반환타입과 일치하거나 적어도 자동 현변환이 가능한 것이어야 한다. 위에서 언급했던 여러 입력값을 받을 수 있던 매개변수와 달리 return문은 하나의 값만 반환할 수 있다.

**배열이나 인스턴스를 이용하면 메소드가 둘 이상의 값을 반환하는 것과 같은 효과를 얻을 수 있다.  

 

3.4 메소드 호출

main메소드는 프로그램 실행시 OS에 의해 자동 호출 되지만 그 외 나머지 메소드는 호출을 해줘야 한다. 특히 메소드는 괄호() 안에 지정해준 값들은 인자(argument)또는 인수라고 하는 값들을 가지고 있는데, 인자의 개수와 순서는 호출된 메소드에 의해 선언된 매개변수와 일치해야 한다. 그리고 인자는 메소드가 호출되면서 매개변수에 대입되므로 인자의 타입은 매개변수의 타입과 일치하거나 자동 형변환이 가능한 것이어야 한다. 

class MyMathTest {
	public static void main(String args[]) {
		MyMath mm = new MyMath();
		long result1 = mm.add(5L, 3L);
		long result2 = mm.subtract(5L, 3L);
		long result3 = mm.multiply(5L, 3L);
		double result4 = mm.divide(5L, 3L);
		System.out.println("add(5L, 3L) = "      + result1);
		System.out.println("subtract(5L, 3L) = " + result2);
		System.out.println("multiply(5L, 3L) = " + result3);
		System.out.println("divide(5L, 3L) = "   + result4);
	}
}

class MyMath {
	long add(long a, long b) {
		long result = a+b;
		return result;
	//	return a + b;	// 위의 두 줄을 이와 같이 한 줄로 간단히 할 수 있다.
	}

	long subtract(long a, long b) {
		return a - b;
	}

	long multiply(long a, long b) {
		return a * b;
	}

	double divide(double a, double b) {
		return a / b;
	}
}

 

① 인스턴스를 생성한다. → MyMath mm = new MyMath();

② 메소드를 호출한다.  → long result1 = mm.add(3L, 5L);

③ 인자값이 호출한 메소드의 매개변수에 대입된다. → long add(long along b)

④ 순차적으로 괄호{ } 안의 작성문이 실행된다. → { 작성된 문장 }

⑤ 호출한 변수로 결과값을 return한다.  → return result; 값을 result1

 

3.5 return문

return문은 현재 실행중인 메소드를 종료하고 호출한 메소드로 되돌아간다. 반환값이 있으면 return문은 당연히 쓰지만, 본래는 반환값의 유무와 상관없이 모든 메소드에는 적어도 하나의 return문이 있어야 한다. 만약 반환타입이 void일 경우 return문 없이도 아무런 문제가 없었지만 사실은 컴파일러가 메소드의 마지막에 return을 자동적으로 추가해줬기 때문이다.

 

반환값(return value)

return문의 반환값으로 주로 변수가 오지만 항상 그런 것은 아니다. 아래 코드는 다음과 같이 좀 더 간략하게 작성할 수 있다. 그리고 자세히 보면 return문의 반환값으로 'x+y'라는 수식이 적혀있다. 그렇다고 해서 수식이 반환되는 것은 아니고, 이 수식을 계산한 결과가 반환된다.

//변경전
int add(int x, int y) {
	int result = x + y;
	return result;
}

//변경후
int add(int x, int y){
	return x + y;
}

'Java > Basic' 카테고리의 다른 글

기본형 매개변수, 참조형 매개변수  (0) 2021.03.19
JVM의 메모리 구조  (0) 2021.03.19
2차원 배열, Arrays클래스  (0) 2021.02.25
String 배열  (0) 2021.02.23
배열(Array)  (0) 2021.02.21

댓글