🏃♂️ 들어가기 앞서..
본 게시물은 스터디 활동 중에 작성한 게시물로 자바의 정석-기초편 교재를 학습하여 정리하는 글입니다.
※ 스터디 Page : 〔투 비 마스터 : 자바〕
*해당 교재의 목차 순서와 구성을 참고하여 작성하며
각 내용마다 부족할 수 있는 내용이나 개인적으로 궁금한 점은
추가적인 검색을 통해 채워나갈 예정입니다.
OOP : Object-Oriented Programming
이전에 자바 관련 첫 게시글이였던
「Java란」 글에서 자바에 대해 간략하게 짚고 넘어갔었는데
그 중에서도
자바를 사용하는 가장 큰 이유는 객체 지향 언어라는 점이라고 했던 것을 기억할 것이다.
이번엔 이 " 객체 지향 프로그래밍(OOP : Object-Oriented Programming) " 에 대해
더 자세히 알아보도록 하자.
사실 객체지향~ 객체지향~ 유난스러워서 그렇지
기존의 프로그래밍 언어와 다른 전혀 새로운 언어가 아니라
기존의 프로그래밍 언어에 몇 가지 새로운 규칙을 추가한
보다 발전한 형태의 언어라고 보면된다.
언급한 새로운 규칙들을 이용해
코드 간에 서로 관계를 맺어주면서
보다 유기적인 프로그램 구성이 가능해진 것이다.
" 코드의 재사용성이 높고 유지보수가 용이하다 "
높은 코드 재사용성
: 새로 코드를 작성할 때, 기존 코드를 이용해서 쉽게 작성 가능하다.
코드 관리 용이
: 코드 간 관계를 이용해서 쉽게 코드를 변경할 수 있다.
신뢰성 높은 프로그래밍 가능
: 제어자와 메서드를 이용해 데이터를 보호하고
코드 중복을 제거해서 불일치로 인한 오동작을 방지할 수 있다.
① 클래스 (Class)
- 정의 : [ 클래스 ]라는 객체를 정의해 놓은 것
- 용도 : 객체를 생성(정의) 하는데 사용
즉, " 객체를 정의해놓은 것 "이라고 볼 수도 있고
" 객체의 틀/설계도 " 라고 볼 수도 있다.
② 객체 (Object)
- 정의 : 실제로 존재하는 것
- 용도 : 해당 객체의 기능과 속성에 따라 다름
- 분류 : 무형 : 책상, 의자, 자동차 ... / 유형 : 공식, 프로그램 에러 ...
클래스는 단지 객체를 생성하는데 사용되는 수단이다.
실질적으로 프로그램에서 사용하는 것은 객체이지만
원하는 기능의 객체를 얻기 위해서는 클래스가 필요하고
클래스 하나만 잘 작성해놓으면
이 후, 객체를 원활하게 생성할 수 있다.
따라서
프로그래밍에서는
먼저 클래스를 작성한 후,
이 클래스를 통해 객체를 생성하여 사용한다.
객체(Object)는 "속성(Property)"과 "기능(function)"
이 두 가지의 요소로 구성되어 있다.
위에서 설명했듯이 클래스는 객체를 정의(생성)하기 때문에
클래스에는 해당 객체의
모든 속성과 기능이 정의되어 있다.
즉, 속성과 기능은 객체의 "구성" 요소인 것이고
클래스에는 이 속성과 기능을 "정의"하는 것이다.
또한
객체 지향 프로그래밍에서는
"속성(Property)"은 멤버 변수 (variable)로
"기능(function)"은 메서드(method)로 표현한다.
class Object {
// 변수 선언
String name;
boolean activation;
int value;
// 메서드 선언
void activate() {activation = !activation ;}
void valueUp() { value++ ;}
void valueDown() { value-- ;}
}
우선 인스턴스화 (instantiate)에 대해 알아보자.
" 클래스(Class)로부터 객체를 만드는 과정 "을 이르는 말인데
이 과정을 거쳐 만들어진 객체를 인스턴스 (instance)라고 한다.
그렇다면
" 둘 다 객체라면 객체와 인스턴스의 차이는 무엇인가 "라는 의문이 든다.
개인적으로 이해한 것을 설명하자면
인스턴스는 특정 클래스에 의해 만들어진 특정 객체라는 것이고
객체라는 표현은 이 인스턴스까지 모두 포함된 포괄적인 의미인 것이다.
예를 들어
지금 두 객체 A와 B가 보이는데
A 객체는 A 클래스에서 인스턴스화되어 생성된 A 클래스의 인스턴스인 것이고
B 객체는 B 클래스에서 인스턴스화되어 생성된 B 클래스의 인스턴스인 것이다.
이처럼 인스턴스는 클래스와의 관계에 집중되어 있는 것이고
객체라는 표현은 보이는 그 존재 자체를 나타내는 것이다.
"인스턴스는 객체이다." 라고 표현할 수 있지만
"객체는 인스턴스이다."라는 표현은 '어느 클래스에서 인스턴스화 된것인지' 확실히 밝히는 부분이 필요한 부적절한 표현이다.
🔧 한 파일에 다수의 클래스 작성
보통 "하나의 소스파일"에 "하나의 클래스"만을 정의하지만
그 이상의 클래스 정의가 불가능한 것은 아니다.단 소스파일의 이름은 public class의 이름과 일치해야한다.
(만약 파일 내 public class가 없다면, 소스파일의 이름은 파일 내 어떤 클래스의 이름으로 해도 상관없다.)
* [소스파일 이름] - (A클래스 이름) | (B클래스 이름)
Java1.java
-public class Java1 {}
|class Java2 {}
( O )Java1.java
-class Java1 {}
|class Java2 {}
( O )Java2.java
-class Java1 {}
|class Java2 {}
( O )
Java1.java
-public class Java1 {}
|public class Java2 {}
( X )
: 하나의 소스파일에 둘 이상의 public class 불가능Java2.java
-public class Java1 {}
|class Java2 {}
( X )
: public class가 있다면 소스파일의 이름은 public class의 이름이여야 한다.java1.java
-public class Java1 {}
|class Java2 {}
( X )
: 대소문자도 구분되는 점 주의# 소스파일 확장자 =
*.java
/ 클래스파일 확장자 =*.class
만약 두 개의 클래스를 작성한 하나의 소스파일을 컴파일하면
소스파일 1개와 각 클래스 파일 1개씩 총 2개의 클래스 파일이 생성된다.
지금부터 클래스를 통해 인스턴스를 만들어 보겠다.
인스턴스 생성 방법에는 여러가지가 있지만
일반적으로 쓰이는 방법은
우리에게 아마 익숙할 것이다.
이전부터 봐왔던 형식인
class Simulation {
public static void main(String[] args) {
// 당연히 " Object o = new Object() ; " 가능
Object o ; // 클래스 타입의 "참조변수" 선언
o = new Object() ; // Object 클래스의 인스턴스가 메모리 빈 공간에 생성됨. (new 연산자)
// 구성하고 있는 멤버 변수는 각 자료형에 해당하는 기본값으로 초기화
// ( name : [String] -> null / activation : [boolean] -> false / value : [int] -> 0 )
o.value = 5 ;
o.valueDown() ;
System.out.println("현재 Object 값은 " + o.value + "이다.") ;
}
}
class Object {
// 변수 선언
String name;
boolean activation;
int value;
// 메서드 선언
void activate() {activation = !activation ;}
void valueUp() { ++value ;}
void valueDown() { --value ;}
}
주의해야할 점은
인스턴스를 다룰 때,
해당 클래스 타입의 참조 변수로 다루어야한다.
( 인스턴스 타입 == 참조변수 타입 == 클래스 )
얼마 전 배열에 대해서도 공부를 해봤는데
만약 많은 수의 객체를 다루려고 할 때,
객체도 배열로 생성하는 것이 가능하기 때문에
배열로 다루면 편리하다.
Object o1, o2, o3 ;
▶ Object[] oArr = new Object[3] ;
( 단, 객체 배열 안에는 객체가 저장되는 것이 아니라 객체 주소가 저장되는 것이다. )
객체 배열의 생성과 저장은 앞서 배웠던 보통 배열들과 다를 바 없다.
여기서도 주의해야할 점을 다시 한 번 얘기하자면
배열을 생성만하지 말고
각 요소에 저장하는 것을 잊지않고 꼭 해주어야한다
// 배열 생성
Object[] oArr = new Object[3] ;
// 배열의 각 요소에 객체 생성& 저장 (!!주의!!)
oArr[0] = new Object();
oArr[1] = new Object();
oArr[2] = new Object();
// 한 줄로
Object[] oArr = { new Object(), new Object(), new Object() } ;
// for문으로 ( 굉장히 많을 때 )
Object[] oArr = new Object[50] ;
for (int i = 0 ; i < oArr.length ; i++) {
oArr[i] = new Object() ;
}
구조체 + 함수
데이터를 다루는데에 있어 가장 중요한 부분 중 하나는 저장일 것이다.
어딘가에 저장해서 계산이 필요할 때 상황에 알맞는 저장값을 가져와 사용해야 한다.
그래서 이 데이터들을 어떻게 저장하느냐?!
하나의 데이터를 저장할 수 있는 변수 ,
같은 종류의 여러 데이터를 하나의 집합으로서 저장할 수 있는 배열 ,
종류 관계없이 서로 관련된 여러 데이터를 하나의 집합으로서 저장할 수 있는 구조체(structure)가 있다.
방금까지는 데이터를 저장하는 형태만 언급이 되었는데
사실 데이터는 여러 함수에서 효용가치가 커지고
함수 또한 대부분이 데이터가 있어야만 쓸모가 있다.
이렇게 서로 관계가 깊은데
이 클래스(class)가
서로 연관이 깊은 '구조체(데이터)'와 '함수'를 묶어서
관리하고 다룰 수 있게 해주는 것이다.
비유하자면 특정 데이터들과 전담 보디가드 함수를 같이 다니게 해주는 것이다.
함수도 그렇고 데이터 타입도 그렇고
대부분 프로그래밍 언어 내에는
자체적으로 제공하는 기본적인 것들이 있다.
데이터 타입
즉, 자료형의 경우,
언어 내에서 제공하는 기본적인 자료형을 【기본 자료형 (primitive type)】이라 하고
프로그래머가 서로 관련된 변수들을 모아서
" 사용자가 하나의 타입을 새로 추가하여 만든 자료형 "을 【사용자 정의 타입 (user-defined type)】이라고 한다.
Java와 같은 객체지향언어에서는
클래스가 곧 사용자 정의 타입이다.
만약
이름과 나이를 표현한다고 하면
String name ;
int age ;
이렇게 변수를 선언할 것이고
만약 3명의 이름과 나이를 표현한다고 하면
String name1, name2, name3 ;
int age1, age2, age3 ;
// 점점 인원수가 많아질때마다 변수를 추가해줘야하기 때문에
// 배열을 사용한다면
String[] name = new String[3];
int[] age = new int[3];
위와 같이 배열을 사용해서 매번 선언할 필요는 없어졌지만
한 명에 대한 데이터가 분리되어 있어서
다른 사람에게 다른 나이가 매치되는 등
뒤죽박죽 될 수도 있다.
이.럴.때.!
클래스를 사용하면 아주 편리하다.
class Student {
String name ;
int age ;
}
이 클래스를 사용하게 되면
// 같은 결과 다른 코드
String name1, name2, name3 ;
int age1, age2, age3 ;
Student s1 = new Student();
Student s2 = new Student();
Student s3 = new Student();
// 같은 결과 다른 코드
String[] name = new String[3];
int[] age = new int[3];
Student[] s = new Student[3] ;
s[0] = new Student();
s[1] = new Student();
s[2] = new Student();
이렇게 뒤죽박죽될 걱정없이
서로 연관된 값끼리 묶여서 관리할 수 있게 되는 것이다.