1. 객체 지향 언어객체 지향 언어의 특징은 다음과 같다.
- 기존의 프로그래밍 언어와 크게 다르지 않으면서 몇 가지 규칙을 추가한 것 뿐이다.
- 코드의 재사용성이 높다. 새로운 코드를 작성할 때 중복되는 것은 기존의 코드를 이용해서 쉽게 작성할 수 있다.
- 코드의 관리가 쉬워진다. 코드 간의 관계를 맺어줌으로써 보다 적은 노력으로 코드 변경이 가능하다
- 신뢰성이 높은 프로그램의 개발을 가능하게 한다. 제어자(public, protected, default, private, static 등)와 메서드를 이용해서 데이터를 보호하고 코드의 중복을 제거하여 코드의 불일치로 인한 오류를 방지할 수 있다.
2. 클래스와 객체
2.1 클래스와 객체의 정의와 용도
클래스의 정의 : 클래스는 객체를 정의해 둔 것이다.
클래스의 용도 : 클래스는 객체를 생성하는 데 사용된다.
객체의 정의 : 실제로 존재하는 것. 사물 또는 개념.
객체의 용도 : 객체의 속성과 기능에 따라 다르다.
2.2 객체와 인스턴스
객체 ≒ 인스턴스
- 객체는 인스턴스를 포함하는 일반적인 의미
책상은 인스턴스다. = 책상은 책상 클래스의 객체이다.
책상은 객체이다. = 책상은 책상 클래스의 인스턴스이다.
- 인스턴스화 : 클래스로부터 인스턴스를 생성하는 것.
즉, 한 클래스를 정의해두고 정의된 클래스를 하나 새로 만들기로 선언하면 그 선언된 것이 인스턴스!
2.3 객체의 구성요소 - 속성과 기능
객체 = 속성 + 기능
각각의 속성과 기능을 객체의 멤버(구성요소)라고 한다.
속성은 클래스의 변수로, 기능은 클래스의 메서드로 정의한다.
2.4 인스턴스의 생성과 사용
인스턴스의 생성 방법은 다음과 같다.
Tv t; // 변수 t는 클래스 T 형태임을 선언
t = new Tv(); // Tv의 새 인스턴스를 변수 t에 저장
// 혹은 합쳐서 다음과 같이 선언도 가능
Tv t = new Tv();
좀 더 구체적으로 다음과 같은 클래스가 있다고 할 때, 사용하는 사례는 다음과 같다.
/**
* TV 라는 클래스 생성
*/
class Tv{
String color;
boolean power;
int channel;
void power(){
power = !power;
}
void channelUp(){
channel++;
}
void channelDown(){
channel--;
}
}
Tv t1 = new Tv();
Tv t2 = new Tv();
t1.channel = 8;
System.out.println("t1.channel = " + t1.channel);
System.out.println("t2.channel = " + t2.channel);
3. 변수와 메서드
3.1 변수
변수의 선언 위치가 변수의 종류와 범위를 결정한다.
변수의 종류 | 선언 위치 | 생성 시기 |
클래스 변수 | 클래스 영억 | 클래스가 메모리에 올라갈 때 |
인스턴스 변수 | 인스턴스 생성 시 | |
지역 변수 | 메서드 영역 | 변수 선언문 수행 시 |
class example {
int instanceVariable; // 인스턴스 변수
static int classVariable; // 클래스 변수 (공유 변수)
void method(){
int localVariable; // 지역 변수
}
}
인스턴스 변수는 인스턴스 생성 시에 생성되고, 참조변수가 없으면 가비지 컬렉터에 의해 자동 제거된다.
클래스 변수는 클래스가 로딩될 때 생성되고, 프로그램이 종료될 때 소멸된다.
지역 변수는 메서드 내에 선언되고, 메서드 종료와 함께 소멸된다. 만약 조건문이나 반복문 안에서 생성된 변수라면, 해당 블럭을 벗어나면 소멸된다.
3.2 메서드
메서드란 작업을 수행하기 위한 명령문의 집합이다. 이 때 어떤 값을 입력받아서 처리하고 그 결과를 돌려주는 함수로 이해하면 되는데, 입력받는 값이 없거나, 결과를 돌려주지 않을 수도 있다. 메서드는 반복되는 코드를 줄이고 코드를 관리하기에 용이해진다. 하나의 메서드는 한 가지 기능만 수행하도록 작성하는 것이 좋다.
3.3 메서드의 종료 : return 문
return 문을 통해 메서드의 결과값을 반환해주고 메서드를 종료시킬 수 있다. 이 때 주의사항은 다음과 같다.
- 반환값이 있는 메서드(메서드의 선언부에 리턴타입이 void가 아닌 모든 경우)는 return문이 있어야 한다. (단지 하나의 return 문이 아니라, 해당 메서드에서 발생할 수 있는 모든 경우에 대해서 return 문이 필요)
- return 문의 개수는 최소화하는 것이 좋다.
3.4 JVM의 메모리 구조
메서드 영역(Method area)은 클래스 정보와 클래스 변수가 저장되는 곳이다.
호출 스택(Call stack)은 메서드의 작업공간으로, 메서드가 호출되면 메서드 수행에 필요한 메모리공간을 할당받고, 메서드가 종료되면 사용하던 메모리를 반납한다. (지역 변수를 사용하는 메모리 공간이 여기에 해당)
힙(Heap)은 인스턴스가 생성되는 공간으로 new 연산자에 의해서 생성되는 배열과 객체(그리고 객체 포함되는 인스턴스 변수)는 모두 여기에 생성된다.
호출 스택의 특징
메서드가 호출되면 수행에 필요한 메모리를 스택에 할당 받는다. 메서드가 수행을 종료하면 사용했던 메모리를 반환한다. 호출 스택의 가장 위에 있는 메서드가 현재 실행중인 메서드이다. 아래에 있는 메서드가 바로 위의 메서드를 호출한 메서드이다.
3.5 클래스 메서드(static)와 인스턴스 메서드
인스턴스 메서드는 인스턴스 생성 한 후에 '인스턴스명(참조변수).메서드이름()' 으로 호출한다. 메서드 내에서 인스턴스변수 사용이 가능하다. 반면 클래스 메서드는 객체 생성 없이 '클래스이름.메서드이름()'으로 호출한다. 인스턴스변수나 인스턴스메서드와 관련없는 작업을 한다. 메서드 내에서 인스턴스 변수를 사용할 수 없다. 메서드 내에서 인스턴스 변수를 사용하지 않는다면 static을 붙이는 것을 고려하면 된다.
3.6 멤버간의 참조와 호출 - 메서드의 호출
같은 클래스의 멤버간에는 객체 생성이나 참조변수 없이 참조할 수 있지만, static 멤버들은 인스턴스 변수들을 참조할 수 없다.
class ExampleClass {
int instanceVariable;
static int classVariable;
void instanceMethod();
static void staticMethod();
void instanceMethod2(){
system.out.println(instanceVariable);
system.out.println(classVariable);
instanceMethod();
staticMethod();
}
static void staticMethod2(){
system.out.println(instanceVariable); // 에러 발생 -> 인스턴스 변수 호출 불가
system.out.println(classVariable);
instanceMethod(); // 에러 발생 -> 인스턴스 메서드 호출 불가
staticMethod();
}
}
4. 오버로딩(overloading)
4.1 메서드 오버로딩
메서드 오버로딩이란 하나의 클래스에 같은 이름의 메서드를 여러 개 정의하는 것을 의미한다. 오버로딩의 조건은 다음과 같다.
- 메서드의 이름이 같아야 한다.
- 매개변수의 개수 또는 타입이 달라야 한다.
- 매개변수는 같고 리턴 타입이 달라지는 경우는 오버로딩이 성립하지 못한다. (리턴 타입은 오버로딩 구현에 아무런 영향이 없음)
오버로딩의 대표적인 예는 다음과 같다.
5. 생성자(constructor) / 291
5.1 생성자
생성자는 인스턴스가 생성될 때마다 호출되는 인스턴스 초기화 메서드이다. 인스턴스 변수의 초기화 또는 인스턴스 생성 시 수행되어야 할 작업에 사용할 수 있다. 모든 클래스에는 반드시 하나 이상의 생성자가 있어야 한다. 대부분의 경우 메서드와 동일하지만 몇 가지 조건이 있다.
5.2 생성자의 조건
- 생성자의 이름은 클래스명과 동일해야 한다.
- 생성자는 리턴값이 없다. (하지만 void를 쓰지는 않는다)
5.3 기본 생성자 & 매개변수가 있는 생성자
class Data1 {
int value;
}
class Data2 {
int value;
Data2 (int x){
value = x;
}
}
public class DataClass {
public static void main(String[] args) {
Data1 data1 = new Data1();
Data2 data2 = new Data2(); // 컴파일 오류
System.out.println("data1 = " + data1.value);
}
}
5.4 생성자에서 다른 생성자 호출하기 - this()
this() – 같은 클래스의 다른 생성자를 호출할 때 사용. 다른 생성자 호출은 생성자의 첫 문장에서만 가능
5.5 참조변수 this
this는 인스턴스 자신을 가리키는 참조변수로, 인스턴스의 주소로 저장되어 있다. 모든 인스턴스 메서드에 지역변수로 숨겨진 채 존재한다. 인스턴스 변수와 지역변수를 구분하기 위해서 주로 사용한다.
5.6 생성자를 이용한 인스턴스의 복사
인스턴스 간의 차이는 인스턴스 변수의 값 뿐이고 나머지는 다 동일하다.
생성자에서 참조변수를 매개변수로 받아서 인스턴스 변수들의 값을 복사한다.
이렇게 하면 똑같은 속성값을 갖는 독립적인 인스턴스가 하나 더 생긴다.
class Car {
String color;
String gearType;
int door;
Car(){
this("white", "auto", 4);
}
Car(String color, String gearType, int door){
this.color = color;
this.gearType = gearType;
this.door = door;
}
Car (Car c){ // 인스턴스 복사를 위한 생성자
// this(c.color, c.gearType, c.door);
this.color = c.color;
this.gearType = c.gearType;
this.door = c.door;
}
}
6. 변수의 초기화
6.1 변수의 초기화
변수를 선언하고 처음 값을 설정해주는 것을 초기화라고 한다. 멤버변수(인스턴스 변수, 클래스 변수)와 배열은 각 타입의 기본값으로 자동초기화되므로 초기화를 생략할 수 있다. 반면 지역변수는 사용 전에 꼭 초기화를 해줘야 한다.
6.2 멤버 변수의 초기화
멤버 변수의 초기화 방법에는 3가지가 있다.
- 명시적 초기화
class Car {
String color = "Red";
String gearType = "auto";
int door = 4;
...
}
- 생성자 초기화
Car(String color, String gearType, int door){
this.color = color;
this.gearType = gearType;
this.door = door;
}
- 초기화 블럭
- 클래스 초기화 블럭 : static {}
- 인스턴스 초기화 블럭 : {}
6.3 초기화 블럭
클래스 초기화 블럭은 클래스 변수의 복잡한 초기화에 사용되며 클래스가 로딩될 때 실행된다.
인스턴스 초기화 블럭은 생성자에서 공통적으로 수행되는 작업에 사용되며 인스턴스가 생성될 때 마다(생성자보다 먼저) 실행된다.
class StaticBlockTest {
static int[] arr = new int[10]; // 명시적 초기화
int value;
static { // 클래스 초기화 블럭
for (int i = 0; i < arr.length; i++){
arr[i] = (int) (Math.random() * 10) + 1;
}
}
{ // 인스턴스 초기화 블럭
value = 3;
}
}
public class javaStudy {
public static void main(String[] args) {
StaticBlockTest s = new StaticBlockTest();
System.out.println("arr = " + StaticBlockTest.arr);
System.out.println("s = " + s.value);
}
}
6.4 멤버변수의 초기화 시기와 순서
클래스변수 초기화 시점 : 클래스가 로딩될 때 단 한번
인스턴스변수 초기화 시점 : 인스턴스가 생성될 때마다
실행 되는 순서는
- 클래스 초기화 : 변수의 기본값(6.1 참고) -> 명시적 초기화 -> 클래스 초기화 블럭
- 인스턴스 초기화 : 변수의 기본값(6.1 참고) -> 명시적 초기화 -> 인스턴스 초기화 블럭 -> 생성자
순이다.
* 추가 내용:
스터디를 진행하다가 다음과 같은 내용을 공유할 수 있게 되었다.
참조 변수와 기본형 변수 (파이썬과 동일한 점 immutable, mutable)
기본형 변수는 주소에 할당된 값을 참조하고, 참조형 변수는 주소값을 참조한다. 기본형 변수에는 boolean, char, byte, short, int, long, float, double와 같은 실제 연산에 사용되는 자료형이 포함된다. 참조형 변수는 이 기본 8가지를 제외한 나머지 타입이 전부 해당된다. 이는 각각 파이썬의 mutable, immutable과 비슷하다고 볼 수 있다. immutable에 call by reference 성향이 있기 때문이다. mutable과 immutable의 기본 정의는 각각 변경 가능한 변수와 변경이 불가능한 변수로, 변경이 가능하다는 것은 같은 주소값을 참조하면서 그 주소값 내의 value를 수정할 수 있다는 뜻(참조형 변수에 해당), 변경이 불가능하다는 것은 그 값을 변경하기 위해서는 다른 주소의 값을 저장해야 한다는 뜻(기본형 변수에 해당)이다.
출처: https://sambalim.tistory.com/73 [삼바의 성장 블로그]
생성자 오버로딩 파이썬에서도 가능한가요?
: 자바는 가능하지만 파이썬은 불가하다. 파이썬은 생성자가 하나만 유효하다. 여러 개 존재할 경우는, 가장 마지막 생성자 하나만 작동한다.
초기화 -> 명시적 초기화 , 초기화 블럭 차이점.
: 초기화 블록은 복잡한 초기화가 가능하다. 명시적 초기화는 x = 10+5; x += 7; 이런 내용을 적을 수 없지만 초기화 블럭에서는 가능하다.
public class Square {
int x;
int y;
boolean b = true;
{
x = Math.abs(-10);
x += 10;
y = 7;
b = !true;
}
}
this() 가 가장 윗 줄에 나와야 하는 이유는 무엇일까요?
: 여러 개가 등장할 시, 가장 마지막에 나오는 this()에 의해 그 위의 초기화가 모두 사라진다.
'TIL > Java | Spring Boot' 카테고리의 다른 글
[Java] 스터디 2주차_객체지향프로그래밍2 (1) - 상속, 오버라이딩, 제어자, 다형성 (0) | 2022.05.01 |
---|---|
[Spring boot] Jenkins를 이용한 spring boot 자동 배포 CI (0) | 2022.04.29 |
[Spring Boot] 영속성 컨텍스트 (0) | 2022.02.27 |
[Spring Boot] IoC, DI, 그리고 컨테이너 (0) | 2022.01.21 |
[Spring Boot] AOP (0) | 2022.01.20 |
댓글