on
JAVA - 2
Object와 OOP(Object-Oriented Programming)
Fastcampus 강의, programmers 강의와 부족한 부분들을 검색하면서 공부할 예정이다.
Object
사전적 정의 : 실제로 존재하는 것. 의사나 행위가 미치는 대상.
구체적, 추상적 데이터의 단위이다.(학생, 회원, 주문, 책 한권 등등)
OOP vs Procedural Programming
예시 상황 : 아침에 일어나서 학교를 가는 상황
-
Procedural programming : 시간이나 사건의 흐름에 따른 프로그래밍.
일어난다 → 씻는다 → 밥을 먹는다 → 버스를 탄다 → 요금을 지불한다 → 학교에 도착
-
OOP : Object의 관점에서 하는 프로그래밍 하는 것.
사진 출처 : fastcampus 강의
각각의 객체는 메세지를 주고받고, 데이터를 처리할 수 있다.
Class
-
객체의 blueprint(청사진). 객체의 속성을 정의하고, 기능을 구현하여 만들어놓은 코드 상태.
-
객체를 정의해 놓은 것. 객체를 생성하는데 사용됨.
-
학생이라는 객체를 정의해보자. == 학생이라는 클래스를 만들어보자.(
Student class
)class Student { int studentID; // ID int grade; // 성적 String name; // 학생 이름 String majorName; // 전공명 }
현재 위 코드에서는
학생
이라는 객체를 정의한 것이다. 내가 정의한학생
이라는 객체는 ID가 있고, 성적정보, 이름, 전공명 이라는 속성을 갖는다. 이러한 객체의 속성들을 member variable이라고 부른다.-
member variable과 헷갈릴 수 있는 용어 정리 - 출처1 출처2
fields
: class의 member variables를 부르는 말.Class variable(Static Fields)
: static modifier로 선언된 field. class가 얼마나 인스턴스화 됐는가는 관계없이 해당 class에는 오직 하나만 존재하는 변수. 쉽게 말하자면, 모든 인스턴스가 class variable이라는 공통된 값을 가지는 것. class가 loading되어 생성될 때 생성된다.Instance variable(Non-static Fields)
: 객체는 상태를non-static fields
에 저장한다. 이 뜻은 field가static
이라는 키워드 없이 선언됐다는 것. 이 변수는 생성된 인스턴스만의 변수이다. 인스턴스가 생성될 때 생성되고 이 때 초기화가 된다.local variables
: method 내에서만 사용될 수 있는 변수. Method가 실행될 때 메모리를 stack 영역에 할당받으며 생성되고 끝나면 소멸되어 사용할 수 없다. 자동으로 초기화 되지 않는다.
class Test{ static String name = "생성됨!! 모든 instance들의 공용 변수!"; // class variable. boolean flag; // instance variable. 각각의 인스턴스 마다 다른 값을 가진다. void methodTest() { int i = 0; // local variable. } }
이렇게 코드로 표시할 수 있을 것 같다.
-
보통 현실의 무언가와 class, instance를 비교할 때 다음과 같이 표현한다. 예를 들면 자동차를 생각해보자. 자동차란 무엇인가? 자동차를 정의해보면,
자동차 정의 : 번호판 달렸고, 한국은 운전석이 왼쪽이고, 배기량이 있고…
위와 같이 정의할 수 있다. (물론 저게 완벽한 정의라고 할 수는 없다.) 우리가 이렇게 생각하여 정의한 것을 class라고 한다. 그리고 실제로 자동차공장에서 생성된 자동차를 객체(object)라고 한다. 여기서 자동차공장==Class, 생성된 자동차==Object 라고 할 수 있다.
- class : 객체를 만들기 위한 틀.
- object : 틀에 의해 만들어진 실제의 무언가.
Method
-
객체의 기능을 구현하기 위해 class 내부에 구현되는 함수.
-
member function 이라고도 함.
-
method를 구현함으로써 객체의 기능이 구현 됨.
-
method의 이름은 그 객체를 사용하는 객체(Client)에 맞게 짓는것이 좋음
예) getStudentName()
class Test{
int a; // instance variable
String b; // instance variable
int addNum(int n1, int n2) { // addNum이라는 method 정의
int result; // Stack에 result만큼의 메모리 할당.
result = n1 + n2;
return result; // 함수가 끝나면서 Stack에 있던 result 메모리 해제.
}
}
Object and Instance
Class로 부터 객체를 만드는 과정을 class의 인스턴스화
라고 한다. 어떤 class로 부터 만들어진 객체를 그 class의 instance라고 한다.
객체나 instance나 비슷한 말이다. new
키워드를 사용하여 instance를 생성한다.
Student studentLee = new Student();
// Student : user defined datatype
// studentLee : reference variable
// new : instance 생성
// Student() : Constructor(생성자)
Student
라는 class가 있다고 가정했을 때, 위와 같이 instance를 생성할 수 있다.
Heap Memory
-
생성된 instance는 heap memory에 할당된다. → 동적 메모리 할당.
-
C/C++ 에서는 사용자가
free(), delete
를 이용하여 사용한 동적 메모리를 해제함. → Java에서는 GC(Garbage Collector)가 주기적으로 사용하지 않는 메모리를 수거. -
하나의 class로부터 여러개의 instance가 생성되고, 각각 다른 메모리 주소를 가진다.
class Student{ int studentId; String name }
라는 class가 정의되어 있다고 해보자.
class StudentTest{ public static void main(String[] args) { Student studentKim = new Student(); Student studentPark = new Student(); System.out.println(studentKim + " " + studentPark); } }
Student@2a139a55 Student@15db9742
Student
class에서 2개의 instance를 생성했다고 해보자. 아래는 그 때의 memory를 나타낸 그림이다.-
StudentKim
: reference variable이다. 해당 instance가 있는 곳의 주소를 가리킨다. 따라서 이러한 변수의 값을 reference value라고 부르고,CLASS_NAME@ADDRESS
라는 값을 가진다. 여기서 ADDRESS는 JVM이 준 virtual address이다.studentKim.name = "Xi-JJun"; // reference variable이 가리키는 주소의 name이라는 instance variable에 접근할 수 있다.
위와 같이 참조변수를 통해서 생성된 instance에 접근할 수 있다.
-
Constructor
Java에서는 객체의 생성과 동시에 instance variables를 원하는 값으로 초기화할 수 있는 생성자(constructor)라는 메소드를 제공.
- Constructor의 이름은 Class의 이름과 같아야 한다.
- 객체를 생성할 때
new
라는 키워드와 함께 사용된다. - 일반 함수처럼 기능을 호출하는 것이 아니다. 객체를 생성하기 위해
new
와 함께 호출된다. - 반환값이 없다.
- 반환값이 없다.
Student studentKim = new Student();
위 코드에서 생성자는 Student()
라고 인스턴스 설명하면서 한번 언급했었다. 다음과 같은 과정으로 인스턴스가 생성된다.
new
라는 키워드에 의해 class가 Heap에 인스턴스로 생성됨.- 그리고 해당 인스턴스는 Constructor에 의해 초기화 됨. → instance variable 초기화
- 초기화된 인스턴스의 주소가 reference variable에 리턴되어 저장됨.
Default Constructor
Class에는 적어도 한개 이상의 생성자가 존재한다. 근데 현재 포스팅에서 정의했던 모든 class 코드들 중에서 나는 한번도 Constructor를 정의한적이 없다. 과연 어떻게 된걸까? 바로 default constructor
이다. class에 생성자를 구현하지 않았어도 new
키워드와 함께 생성자를 호출할 수 있다. 컴파일러가 해당 class에 생성자가 하나도 없는 경우 default constructor code
를 넣어주기 때문이다.
class Student{
int studentId;
String name;
Student() {} // default constructor
}
기본 생성자 코드는 위와 같다.
내가 만드는 Constructor
class Student{
int studentId;
String name;
// Constructor
Student(int studentId, String name) {
this.studentId = studentId;
this.name = name;
}
}
직접 constructor를 정의했다. 아래는 테스트용 코드이다.
class StudentTest{
public static void main(String[] args) {
Student studentKim = new Student(11, "Kjj");
Student studentPark = new Student(12, "Yjp");
System.out.println(studentKim.name + " " + studentPark.name);
}
}
Kjj Yjp
보다시피 초기화가 잘 된 모습을 볼 수 있다. 이렇게 우리가 Constructor를 정의했다면, 기본 생성자는 제공되지 않는다.
this
우리가 원하는 것은 instance variable에 우리가 constructor로 받아온 값을 넣는 것이다. 그러나 아래와 같은 상황이 발생한다.
class Student{
int studentId;
String name;
// Constructor
Student(int studentId, String name) {
studentId = studentId;
name = name;
}
}
studentId
라는 매개변수에 우리가 받아온 매개변수 값을 대입하는 것이다. 우리가 원하는 것은 instance variable에 우리가 constructor로 받아온 값을 넣는 것. 따라서 위처럼 코드를 작성하면 안된다. 따라서 this
라는 키워드를 사용한다.
this(reference variable)는 인스턴스가 바로 자기 자신을 참조하는 데 사용하는 변수 - 출처
this
라는 reference variable은 해당 인스턴스의 주소를 가리키고 있다. 생성자의 매개변수 이름과 인스턴스 변수의 이름이 같을 경우에는 인스턴스 변수 앞에 this
키워드를 붙여 구분해만 한다.
변수 이름을 같게 하는 이유는 나중에 찾아보기가 좋아서라고 강의에서 말했다.
Overloading
같은 함수 이름을 가지고 있으나 매개변수, 리턴타입 등의 특징은 다른 여러개의 서브프로그램 생성을 가능하게 한다. - 출처
class Student{
int studentId;
String name;
// Constructor1
Student() {} // Student stdKim = new Student(); - OK
// Constructor2
// Student stdKim = new Student(123, "Kjj"); - OK
Student(int studentId, String name) {
studentId = studentId;
name = name;
}
}
이렇게 constructor overloading으로 인스턴스를 생성(초기화)하는 2개의 방법을 만들었다.