객체(Object)란 구체적이거나 추상적인 데이터 단위입니다.
객체 지향 프로그래밍(Object Oriented Programming, OOP)
은 이 객체를 기반으로 하는 프로그래밍입니다.
객체 간의 협력이 이루어지는, 이른바 모듈화된 프로그래밍이 가능해지는 것입니다.
<-> 절차 지향 프로그래밍(Procedural Programming)
클래스
는 객체에 대한 속성과 기능을 코드로 구현한 것입니다. 클래스를 정의하는 형식은 아래와 같습니다.
(접근 제어자) class 클래스명 {
멤버 변수;
메서드;
}
사용 방식은 아래 화면과 같습니다.
또는 아래처럼 객체 구성과 작동을 위한 클래스 파일로 각각 나누어 실행할 수도 있습니다.
자바에서 네이밍 컨벤션(명명 규칙)이 특별히 정해진 것은 없지만 통상적으로 사용하는 방법은 있습니다.
- 프로젝트명 : 대문자로 시작
- 패키지명 : 소문자
- 클래스명 : 대문자로 시작, 단어 첫 글자마다 대문자
- 변수명 : 소문자로 시작, 단어 첫 글자마다 대문자( Camel Case / Camel Rotation )
- 메서드명 : 소문자로 시작, 단어 첫 글자마다 대문자
함수
는 하나의 기능을 수행하는 일련의 코드 뭉치입니다. 중복되는 기능의 코드는 함수로 구현하고 호출하여 사용합니다.
함수를 정의하는 형식은 위와 같습니다. 반환 값이 없는 경우에는 함수 반환형에 'void'를 추가로 적습니다.
함수가 호출될 때 사용하는 메모리는 스택(stack)
이라고 합니다. 함수의 기능 수행이 끝나면 자동으로 반환됩니다.
이 '스택 메모리'는 데이터가 후입선출(Last In First Out, LIFO)
합니다.
나중에 들어온 데이터가 먼저 나간다는 뜻입니다.
이후에 나오겠지만, 함수가 호출되기 전에 구현된 상태에서는 또 다른 영역에 존재하고 있습니다.
메서드
는 함수의 일종이며 객체의 기능을 제공하기 위해 클래스 내부에 구현됩니다.
이 글의 상단 1. Class
의 첫번째 캡쳐화면에서 이미 메서드를 구현해보았습니다.
여기에서는 객체 속성값에 직접 데이터를 저장했지만, 이 또한 메서드를 만들어 속성값을 부여하거나 반환받을 수 있습니다.
public class Student {
// 멤버 변수
int studentID;
String studentName;
int grade;
String address;
// 학생 정보를 출력하는 메서드
public void showStudentInfo() {
System.out.println(studentName + "," + address);
}
// 클래스 객체 학생 이름을 반환하는 메서드
public String getStudentName() {
return studentName;
}
// 매개변수로 입력받은 데이터를 객체 학생 이름으로 저장하는 메서드
// 이때 반환값이 없어 'void'가 추가되었습니다.
public void setStudentName(String name) {
studentName = name;
}
}
객체(인스턴스)
는 클래스를 통해 생성합니다.
클래스를 사용하기 위해서는 new
예약어를 이용해 클래스 객체를 생성해야합니다.
하나의 클래스 코드로부터 서로 다른 여러 인스턴스를 생성할 수 있고, 이는 Heap
메모리에 생성됩니다.
클래스형 변수명 = new 생성자();
이때 객체로 생성한 변수를 '참조 변수'라 하고
인스턴스가 생성되는 힙 메모리 주소를 '참조 값(Reference Value)'이라 합니다.
참조변수를 통해 호출할 수 있는 멤버변수, 메서드 등 참조 값 확인 코드를 볼 수 있습니다.
함수가 호출됨과 동시에 지역변수 등이 '스택 메모리'에 생성이 되고 함수 작동이 끝남과 동시에 사라지는 반면
힙 메모리
는 사용자에 의해 메모리 공간이 동적으로 할당되고 해제됩니다.
인스턴스는 'new' 예약어를 통해 '힙 영역'에 생성 되고 가비지 컬렉터(Garbage Collector
가 없애줍니다.
5. Instance
에 쓴 것처럼 객체 생성 시 'new' 키워드와 함께 입력했던 '클래스명()'을 생성자
라고 합니다.
생성자는 인스턴스를 초기화 할 때의 명령어 집합입니다.
생성자는 그 클래스의 이름과 같아야하고, 메서드와는 다른 존재입니다.
매개변수나 구현부가 없는 생성자를 디폴트 생성자(Default Constructor)
라고 합니다.
하나의 클래스에는 반드시 하나 이상의 생성자가 존재해야 합니다.
클래스에 생성자가 하나도 없는 경우에(프로그래머가 생성자를 기술하지 않은 경우)
자바 컴파일러가 자동으로 '프리컴파일(precompile)' 단계에 디폴트 생성자를 넣어줍니다.
만약 사용자가 클래스에 매개변수가 있는 생성자를 추가하면 컴파일러는 기본 생성자를 제공하지 않습니다.
필요에 의해 하나의 클래스 내에 기본 생성자 외에도 매개변수가 있고 이름은 같은 여러 개의 생성자를 생성할 수도 있습니다.
이를 생성자 오버로딩(Constructor Overloading)
이라고 합니다.
변수의 자료형은 '기본 자료형'과 참조 자료형
으로 나눌 수 있습니다.
'참조 자료형'은 'String' 같이 기존에 자바 라이브러리에 제공되기도 하고
위에서 만든 'Student'처럼 사용자가 직접 클래스로 선언해 사용할 수도 있습니다.
객체의 속성을 숨기는 '정보은닉'이란, 접근 제어자 private
을 사용해
클래스 외부에서 클래스 내부의 멤버 변수나 메서드에 접근하지 못하게 하는 것입니다.
필요에 따라 변수에 대해 접근할 수 있는 get(), set() 메서드를 제공할 수 있습니다.
생성된 인스턴스 스스로를 가리키는 예약어로 쓰입니다.
위 코드의 결과는 인스턴스마다 주소값이 달라지지만
인스턴스 자체의 주소값과 인스턴스의 'this'의 주소값은 똑같이 출력됩니다.
이외에도 클래스 안에 아래와 같이 작성하고 이후 참조변수를 통해 메서드를 출력문으로 출력하면
위와 같이 인스턴스 자신의 주소값을 출력합니다.
public 클래스명 returnSelf() {
return this;
}
public Person() {
this("이름없음", 1);
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
💭 '.. 타임패러독스 아녀..? 아무튼 그래서 이거 왜 쓰는 거..'라고 생각하던 차에
강사님이 예시 코드를 보여주었습니다. 결론부터 말하자면 디폴트 값을 설정하기 위함입니다.
아래 코드에서는 'Person'의 인스턴스를 생성할 때 매개변수로 이름과 나이를 입력받는데
만약 아무것도 입력하지 않은 경우 "이름없음", 1이 기본값으로 설정됩니다.
class Person {
String name;
int age;
public Person() {
this("이름없음", 1);
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
public class CallAnotherConst {
public static void main(String[] args) {
Person p1 = new Person();
System.out.println(p1.name);
}
}
'this'를 이용해 다른 생성자를 호출할 때에는 그 이전에 어떠한 'statement'도 사용할 수 없습니다. 예를 들어
아래 코드의 표시(👉)한 부분처럼 다른 문장이 올 수 없습니다.
class Person {
String name;
int age;
public Person() {
👉 int i = 0;
this("이름없음", 1);
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
클래스 생성자에 다른 클래스의 생성자를 매개변수로 받아 객체 간의 협업이 가능합니다.
static
변수는 여러 인스턴스가 같은 메모리의 값을 공유하기 위해 사용합니다.
이 정적 변수의 정의와 사용 방법입니다.
static 자료형 변수명;
객체가 가진 멤버변수 등의 경우 'new'로 객체를 생성할 때 'Heap' 메모리 영역에 올라갔다가 객체가 사라지면 소멸되지만
이 'static' 변수는 전체 프로그램이 로드 될 때 '데이터 영역', '정적 영역', '상수 영역'이라 불리는 메모리 영역에 할당됩니다.
그렇다보니 '인스턴스'의 생성과 관계없이 클래스 이름으로 직접 참조하며 그런 의미에서 클래스 변수
라고도 합니다.
반면 멤버변수는 다른 말로 인스턴스 변수
라고 합니다.
실제 코드를 작성하면 참조변수의 클래스변수 부분이 위처럼 노란선이 그어지는데
경고메시지의 내용은 "The static field Student.serialNum should be accessed in a static way" 입니다.
인스턴스가 아니라 클래스명으로 스태틱 변수를 참조하라는 뜻입니다.
아래는 데이터가 할당되는 메모리 영역을 그림으로 그린 것입니다.
만약 외부에서 접근하는 것을 막으려면 'private'을 사용하면 됩니다.
이때 get(), set() 메서드를 만들어 값을 가져오고, 세팅할 수 있는데
'getter' 메서드만 만들면 해당 스태틱 변수를 변경하지 못하지만 가져올 수는 있습니다.
public class Student {
👉 private static int serialNum = 10000;
int studentID;
String studentName;
public Student() {
serialNum++;
studentID = serialNum;
}
public static int getSerialNum() {
return serialNum;
}
}
위 코드의 'getSerialNum()' 스태틱 메서드에서
아래처럼 인스턴스 변수 'studentID'를 출력하려고 하면 에러가 납니다.
에러메시지는 다음과 같습니다. "Cannot make a static reference to the non-static field studentID"
스태틱이 아닌 필드의 변수를 스태틱 영역에서 참조할 수 없다는 뜻입니다.
public static int getSerialNum<() {
int i = 10; // 메서드의 지역변수
i++;
System.out.println(i);
👉 System.out.println(studentID); // 인스턴스 변수 (에러)
return serialNum; // 클래스 변수
}
변수 유형 | 선언 위치 | 사용 범위 | 메모리 | 생성과 소멸 |
---|---|---|---|---|
지역 변수 | 함수 내부 | 함수 내에서만 사용 | STACK - - - - | 함수가 호출될 때 생성되고 함수가 끝나면 소멸 |
멤버 변수 | 클래스 멤버 변수 | 클래스 내에서 사용하고 private이 아니면 다른 클래스에서 참조 변수로 사용 가능 | HEAP | 객체가 생성될 때 힙에 생성되고, 가비지 컬렉터가 메모리를 수거할 때 소멸 |
클래스 변수 - - - - - - - | static 예약어를 사용하여 클래스 내부에 선언 | 클래스 내부에서 사용하고 private이 아니면 클래스 이름으로 다른 클래스에서 사용 가능 | DATA | 프로그램이 처음 시작할 때 상수와 함께 데이터 영역에서 생성되고 프로그램이 끝나고 메모리를 해제할 때 소멸 |
싱글톤 패턴
이란, 전 시스템에 단 하나의 인스턴스만이 존재하도록 구현하는 방식입니다.
이때 외부에서 생성자 자체를 호출할 수 없도록 하는데, 위에서 언급한 '클래스 변수'의 특성을 이용해 'static'을
사용하면 하나의 인스턴스만 존재할 수 있도록(여러 인스턴스를 만들어도 결국 하나의 주소값) 할 수 있습니다.