자바 객체제향에 대해 알아보자
Updated:
ch6. 객체지향 프로그래밍1
Created: Apr 13, 2020 4:42 PM
1. 객체 지향 언어
-
객체지향 언어의 역사
→ 실제 세계는 객체로 이루어져 있고 발생하는 모든 사건들은 객체간의 상호작용이라고 정의
→ 1960년대 중반에는 주로 절차적 언어들이 주를 이루었지만 프로그램의 규모가 점점 커지고 사용자들의 요구가 빠르게 변화해가는 상황을 극복하기 어렵다는 한계를 느끼고 그에 대한 대안으로 객체지향언어가 선택됨 - 객체지향 언어의 특징
- 코드의 재사용성
- 코드의 관리가 용이
- 신뢰성이 높은 프로그래밍이 가능하도록 함 ← 중복된 코드의 제거
—> 너무 객체지향 개념에 얽매이지 말고 일단 프로그램을 기능적으로 완성한 후에 어떻게 하면 보다 객체지향적으로 코드를 개선해나갈지 고민하여 점차 개선해나가는 것이 좋다
2. 클래스와 객체
-
클래스와 객체의 정의와 용도
→ 객체는 실제로 존재하는 어떤 사물을 의미하고 이것을 클래스라는 틀(?)에 정의한 내용대로 생성한다 -
객체와 인스턴스
→ 클래스의 내용대로 생성된 객체를 그 클래스의 인스턴스 라고 하고 만드는 과정을 인스턴스화 라고 한다
→ 어찌됐든 인스턴스도 객체의 개념이기 때문에 엄격히 구분할 필요는 없지만 알아두긴하자 -
객체의 구성요소 - 속성 & 기능
→ 어떤 객체든 클래스에서 다양한 속성과 기능이 정의되어 생성된다
→ 속성=맴버 변수=필드
→ 기능=메소드=함수 -
인스턴스의 생성과 사용
→ 클래스를 만들기만 해서는 객체를 사용할 수 없다. 객체를 사용하려면 아래 같이 인스턴스를 생성해야 된다
→ 클래스명 참조변수명=new 클래스명(); —> 이것을 참조변수가 해당 객체를 참조하고 있다고 함
→ 위와 같이 작성하면 new 클래스명()에 의해서 메모리에 클래스의 인스턴스가 생성되고 그 메모리의 주소값이 참조변수에 저장된다. 이 참조변수를 통해 해당 인스턴스에 접근할 수 있다
→ new 클래스명()이 일어날때 해당 클래스의 필드들은 기본값으로 초기화 된다(int → 0, String → null, boolean → false …)
tip) 참조변수의 참조를 받지 못하는 인스턴스는 가비지 컬렉터에 의해서 자동적으로 메모리에서 제거된다 -
객체 배열
→ 많은 수의 객체를 다뤄야 할때 객체를 배열 형식으로 다룰수 있게 도와준다
→ Demo[] demoArr=new Demo[2] 라고 선언하면 demoArr[0], demoArr[1]이 생성된다. 하지만 객체를 다루기 위한 참조변수가 만들어진 것일 뿐 아직 객체가 저장되지 않았다. 각각의 참조변수에 new Demo()를 통해 인스턴스를 생성해주어야 한다 - 클래스의 또다른 정의
- 데이터와 함수의 결합
- 사용자 정의 타입(프로그래밍 언어에서 제공하는 자료형외에 프로그래머가 서로 관련된 변수들을 묶어서 하나의 타입(=클래스)으로 새로 추가하는 것)
3. 변수와 메서드
- 선언위치에 따른 변수의 종류
→ 크게는 2가지로 나뉜다. 바로 맴버 변수와 지역 변수이다. 메소드 내에서 선언되어 있는 변수를 지역 변수라 하고 그 외는 모두 맴버 변수이다. 맴버 변수 중에서도 static이 붙은 것을 클래스 변수, 붙지 않은 것을 인스턴스 변수라고 한다
-인스턴스 변수
→ 인스턴스가 생성될 때 만들어지며 그렇기 때문에 인스턴스를 생성한 이후에나 사용가능하다
→ 생성한 인스턴스들마다 서로 다른 속성값을 가질 수 있으므로 인스턴스마다 다른 값을 가져야하는 속성의 경우에 사용한다
-클래스 변수
→ 클래스가 메모리에 올라갈 때 만들어지며 그렇기 때문에 인스턴스를 생성하기 전에도 사용가능하다
→ 모든 인스턴스가 공통된 저장공간(변수)를 공유하게 되므로 모든 인스턴스들이 공통적인 값을 유지해야 하는 속성의 경우에 사용한다
-지역 변수
→메서드 내에 선언되어 메서드 내에서만 사용 가능하며 메서드가 종료되면 사용할 수 없게 된다
-
클래스 변수와 인스턴스 변수
→ 인스턴스 변수는 인스턴스가 생성될 때마다 생성되므로 인스턴스마다 각기 다른 값을 유지할 수 있지만, 클래스 변수는 모든 인스턴스가 하나의 저장공간을 공유하므로 항상 공통된 값을 가진다
→ 인스턴스 변수는 ‘ 참조변수명.인스턴스변수명 ‘ 의 형식으로 사용하면 되고 클래스 변수는 ‘ 클래스명.클래스변수명 ‘ 의 형식으로 사용하면 된다 -
메서드
→ 메서드는 특정 작업을 수행하는 일련의 문장들을 하나로 묶은 것이다
→ 높은 재사용성, 중복된 코드의 제거, 프로그램의 구조화 등의 장점이 있다 -
메서드의 선언과 구현
→ 메서드는 크게 선언부와 구현부로 나누어져 있다
→ 선언부는 반환타입, 메서드의 이름, 매개변수 선언으로 구성되어 있다
→ 구현부는 메서드를 호출했을 때 수행할 문장들을 적는다
→ 선언부에서 선언한 반환타입이 void인 경우를 제외하고는 모두 구현부에서 return으로 반환값을 정해줘야 한다. 또한, 반환값은 하나 이상이 될 수 없다
tip) 메서드 선언 시에 괄호안의 값은 매개변수라고 부르고 메서드 호출 시에 괄호안의 값은 인자라고 불린다 -
메서드의 호출
→ 메서드의 호출 없이 선언만으로는 메서드를 실행시킬 수 없다. ‘ 메서드이름(인자값1, 인자갑2 …) ‘ 의 형식으로 메서드를 호출한다
→ 같은 클래스 내의 메서드끼리는 참조변수를 사용하지 않고도 서로 호출이 가능하지만 static 메서드는 같은 클래스 내의 인스턴스 메서드를 호출할 수 없다 -
return 문
→ return 문은 현재 실행 중인 메서드를 종료하고 호출한 메서드로 되돌아간다
→ 모든 메서드에는 적어도 하나의 return문이 있어야 한다(반환값이 void인 메서드도 사실은 return; 이 생략되어있는 것임) -
JVM의 메모리 구조
→ 응용프로그램이 실행되면 JVM은 시스템으로부터 프로그램을 수행하는데 필요한 메모리를 할당받고 이 메모리를 용도에 따라 여러 영역으로 나누어 관리한다
→ 3가지 주요 영역에 대해 설명해보자면 메서드 영역(method area), 힙(heap), 호출스택(call stack)이 있다
-메서드 영역: 프로그램 실행 중 어떤 클래스가 사용될 때 JVM이 해당 클래스의 클래스 파일을 읽어서 정보를 이곳에 저장한다
-힙: 프로그램 실행 중 생성되는 인스턴스들을 이곳에 저장한다
-호출스택: 메서드의 작업에 필요한 메모리 공간을 제공한다. 메서드가 호출되면 호출스택에 그 메서드를 위한 저장공간이 할당되며 메서드가 종료되면 그 공간은 반환되어 비워진다. 여러 메서드를 사용할 경우 나중에 호출한 메서드들이 먼저 호출한 메서드 위에 쌓여 위부터 차례차례 반환되어 비워지는 구조이다 -
기본형 매개변수와 참조형 매개변수
→ 기본형 매개변수를 값을 읽기만 할 수 있을 뿐 변경할 수 없지만 참조형 매개변수는 값을 읽고 변경까지 할 수 있다(참조 변수는 따른 기본형 변수들과 달리 생성한 인스턴스의 주소값을 저장하기 때문이다)
→ 아래의 2종류의 코드를 참고해보자public class PrimitiveParam { public static void main(String[] args) { Data d=new Data(); d.x=10; System.out.println("x="+d.x); change(d.x); System.out.println("x="+d.x); } private static void change(int x) { x=100; System.out.println("x="+x); } } public class ReferenceParam { public static void main(String[] args) { Data d=new Data(); d.x=10; System.out.println("x="+d.x); change(d); System.out.println("x="+d.x); } private static void change(Data d) { d.x=100; System.out.println("x="+d.x); } } -
참조형 반환타입
→ 매개변수뿐만 아니라 반환타입 또한 참조형이 될 수 있는데 결국 객체의 주소를 반환한다는 의미이다
→ 이 역시 아래의 코드를 참고하자public class ReferenceReturn { public static void main(String[] args) { Data d=new Data(); d.x=10; Data d2=copy(d); System.out.println("d.x="+d.x); System.out.println("d2.x="+d2.x); } private static Data copy(Data d) { Data tmp=new Data(); tmp.x=d.x; return tmp; } } -
재귀호출
→ 메서드의 내부에서 자신을 다시 호출하는 것을 재귀호출이라고 한다
→ 개발자의 입장에서는 메서드가 다시 자신을 호출하는 것이 어색하게 느껴질 수 있겠지만 메서드의 입장에서는 그저 특정 위치에 있는 명령을 수행할 뿐 그 이상도 이하도 아니다
→ 호출된 메서드는 값에 의한 호출을 통해 원래의 값이 아닌 복사된 값으로 작업하기 때문에 호출한 메서드와 관계없이 독립적인 작업수행이 가능하다
→ 다만 잘못 쓴다면 무한반복문 처럼 되서 오버플로가 발생할 수 있으니 꼭 조건문을 넣어주어야 하고 매개변수의 유효성 검사는 필수로 해야 한다 -
클래스 메서드와 인스턴스 메서드
→ 변수에서도 그랬듯이 메서드 앞에 static이 붙어있으면 클래스 메서드, 그렇지 않으면 인스턴스 메서드이다
→ 즉, 클래스의 맴버변수 중 모든 인스턴스에 공통된 값을 유지해야하는 것이 있다면 static을 붙여주고 또한, 작성한 메서드 중에서 인스턴스 변수나 인스턴스 메서드를 사용하지 않는 메서드에 static을 붙인다
→ 아래 코드를 참조하자class MyMath{ long a,b; long add(){return a+b;} long substract(){return a-b;} long multiply(){return a*b;} double divide(){return a/b;} static long add(long a, long b){ return a+b; } static long substract(long a, long b){ return a-b; } static long multiply(long a, long b){ return a*b; } static double divide(double a, double b){ return a/b; } } class MyMathTest { public static void main(String[] args) { System.out.println(MyMath.add(4,2)); System.out.println(MyMath.substract(4,2)); System.out.println(MyMath.multiply(4,2)); System.out.println(MyMath.divide(4,2)); MyMath myMath=new MyMath(); myMath.a=4; myMath.b=2; System.out.println(myMath.add()); System.out.println(myMath.substract()); System.out.println(myMath.multiply()); System.out.println(myMath.divide()); } } -
클래스 맴버와 인스턴스 맴버간의 참조와 호출
→ 클래스 메서드에서는 인스턴스 변수와 인스턴스 메서드를 사용할 수 없다(인스턴스 맴버나 메서드가 존재하는 시점에 클래스 맴버나 메서드는 반드시 존재하지만 역은 성립하지 않을 수도 있기 때문이다)
Leave a comment