🏷 인스턴스 멤버
필드와 메소드는 선언 방법에 따라 인스턴스 멤버와 정적 멤버로 분류 할 수 있다.
인스턴스 멤버
- 객체에 소속된 멤버 - 객체를 생성해야지만 사용할 수 있는 멤버
정적 멤버
- 클래스에 고정된 멤버 = 객체 없이도 사용할 수 있는 멤버
✔️ 인스턴스 멤버 선언 및 사용
필드와 메소드는 인스턴스 멤버이기 때문에 외부 클래스에서 사용하기 위해서는
Car 객체를 먼저 생성하고 참조 변수로 접근해서 사용해야 한다.
Car myCar = new Car();
myCar gas = 10;
myCar.setSpeed(60);
Car yourCar = new Car();
yourCar gas = 20;
yourCar.setSpeed(70);
위와 같이 인스턴스를 생성했을 때,
gas 필드는 각각의 인스턴스 마다 따로 존재하며
setSpeed() 메소드는 각 객체마다 존재하지 않고 메소드 영역에 저장되고 공유된다.
그림 첨부하자 !!
gas 필드는 객체에 소속된 멤버가 분명하지만, setSpeed() 메소드는 객체에 포함되지 않는다.
여기서 !! 포함을 소속됨으로 혼동하지 말자 !!!
메소드는 코드 덩어리이므로 객체마다 저장한다면 중복 저장으로 인해 메모리 효율이 떨어진다.
따라서, 메소드는 메소드 영역에 두되, 공유해서 사용하고 이때 ! 객체 없이는 사용하지 못하도록 제한을 걸어둔 것이다.
🏷 정적 멤버
자바는 클래스 로더를 사용하여 클래스를 메소드 영역에 저장하고 사용한다.
정적 멤버란, 메소드 영역의 클래스에 고정적으로 위치하는 멤버를 말한다.
그렇기 때문에, 정적 멤버는 객체 생성할 필요 없이 클래스를 통해 바로 사용이 가능하다.
즉,
[ 메소드 영역 ]
클래스 - 정적 필드, 정적 메소드
✔️ 정적 멤버 선언
필드와 메소드 모두 정적 멤버가 될 수 있다.
정적 필드와 정적 메소드로 선언하려면 static 키워드를 추가하면 된다.
객체마다 가지고 있을 필요성이 없는 공용적인 필드는 정적 필드로 선언하는 것이 좋다.
또한, 인스턴스 필드를 이용하지 않는 메소드는 정적 메소드로 선언하는 것이 좋다.
당연히, 인스턴스 변수를 사용하는 메소드는 인스턴스 메소드로 선언해야 한다.
✔️ 정적 멤버 사용
정적 멤버는 클래스가 로드된 후 바로 사용할 수 있다.
클래스 이름에 도트(.) 연산자로 접근하면 된다.
정적 필드와 정적 메소드는 다음과 같이 객체 참조 변수 로도 접근이 가능하다.
- 하지만 !! 정적 요소는 클래스 이름으로 접근하는 것이 정석이며, 객체 참조 변수로 접근 시 경고(⚠️) 표시를 낸다.
Calculator myCalcu = new Calculator();
double result = 10 * 10 * myCalcu.pl;
int result2 = myCalcu.plus(1,2);
int result3 = myCalcu.minus(3,2);
✔️ 정적 블록
정적 필드는 다음과 같이 필드 선언과 동시에 초기값을 주는 것이 일반적이다.
static double pi = 3.14159;
하지만, 복잡한 초기화 작업이 필요하다면 정적 블록을 이용해야 한다.
다음은 정적 블록의 형태를 보여준다!
static {
...
}
정적 블록은 클래스가 메모리로 로딩될 때 자동으로 실행된다.
정적 블록이 클래스 내부에 여러개가 선언되어 있을 경우, 선언된 순서대로 실행된다.
public class Television {
static String company = "MyCompany";
static String model = "LCD";
static String info;
static {
info = company + "-" + model;
}
}
❌ 정적 필드는 객체 생성 없이도 사용할 수 있기 때문에 생성자에서 초기화 작업을 하지 않는다.
❌ 인스턴스 멤버 사용 불가
- 정적 메소드와 정적 블록은 객체가 없어도 실행된다는 특징 때문에 내부에 인스턴스 필드나 인스턴스 메소드를 사용할 수 없다.
- 또한 객체 자신의 참조인 this도 사용할 수 없다.
- 정적 메소드 및 정적 블록에서 인스턴스 멤버를 사용하고 싶다면, 객체를 먼저 생성한 후, 참조 변수로 접근해야 한다.
🏷 final 필드와 상수
인스턴스 필드와 정적 필드는 언제든지 값을 변경할 수 있다.
그러나, 경우에 따라서는 값을 변경하는 것을 막고 읽기만 허용할 때가 있다.
이럴 때, final 필드와 상수를 선언하여 사용한다.
✔️ final 필드 선언
final 은 최종적 이라는 뜻을 가지고 있다.
final 필드는 초기값이 저장되면 이것이 최종적인 값이 되어서 프로그램 실행 도중에 수정할 수 없게 된다.
final 필드에 초기값을 줄 수 있는 방법
1. 필드 선언 시에 초기 값 대입
2. 생성자에서 초기 값 대입
고정된 값이라면, 필드 선언 시에 주는 것이 제일 간단
복잡한 코드가 필요하거나 객체 생성 시에 외부에서 전달된 값으로 초기화를 해야 한다면 생성자에서 진행
이 두 방법을 사용하지 않고 final 필드를 그대로 남겨두면 컴파일 에러 발생
✔️ 상수 선언
불변의 값을 저장하는 필드
상수는 객체마다 저장할 필요가 없고, 여러개의 값을 가져도 안되기 때문에 static 이면서 final인 특성을 가져야 한다.
상수의 초기값은 선언 시에 주는 것이 일반적이지만, 복잡한 초기화가 필요할 경우에는 정적 블록에서 초기화 할 수도 있다.
static final 타입 상수;
static {
상수 = 초기화;
}
또한, 상수는 정적 필드이므로 클래스로 접근해서 읽을 수도 있다.
🏷 패키지
자바의 패키지는 단순히 디렉토리만을 의미하지 않는다.
패키지는 클래스의 일부분이며, 클래스를 식별하는 용도로 사용된다.
패키지는 상위 패키지와 하위 패키지를 도트(.)로 구분한다.
도트는 물리적으로 하위 디렉토리임을 뜻한다.
패키지는 클래스를 식별하는 용도로 사용되기 때문에 클래스의 전체 이름에 포함된다.
예를들어 Car 클래스가 com.mycompany 패키지에 속해 있다면 Car 클래스의 전체 이름은 com.mycompany.Car이 된다.
✔️ 패키지 선언
패키지 디렉토리는 클래스를 컴파일 하는 과정에서 자동으로 생성된다.
컴파일러는 클래스의 패키지 선언을 보고 디렉토리를 자동 생성시킨다.
✔️ import 문
같은 패키지에 있는 클래스는 아무런 조건 없이 사용할 수 있지만, 다른 패키지에 있는 클래스를 사용하려면 import 문을 이용해서 어떤 패키지의 클래스를 사용하는지 명시해야 한다.
import 문은 하위 패키지를 포함하지 않는다.
따라서 com.hankook 패키지에 있는 클래스도 사용해야 하고, com.hankook.project 패키지에 있는 클래스도 사용해야 한다면,
다음과 같이 두개의 import 문이 필요하다.
import com.hankook.*;
import com.hankook.project.*
만약,
서로 다른 패키지에 동일한 이름의 클래스가 존재하고 다른 클래스에서 동일한 이름의 클래스 2개를 import 하여 사용하려고 할때,
컴파일 에러를 발생시킨다.
이 경우, 클래스의 전체 이름을 사용해서 정확히 어떤 패키지의 클래스를 사용하는지 알려야 한다.
전체 이름을 사용할 경우 import문은 따로 필요하지 않다.
🏷 접근 제한자
경우에 따라서 객체의 필드를 외부에서 변경하거나 메소드를 호출할 수 없도록 막아야 한다.
중요한 필드와 메소드가 외부로 노출도지 않도록 하여 객체의 무결성을 유지하기 위해서이다.
접근 제한자의 종류
- public
- protected
- private
✔️ 클래스의 접근 제한
클래스가 어떤 접근 제한을 갖느냐에 따라 사용 가능 여부가 결정된다.
사용 가능한 접근 제한자
- public
- 같은 패키지 뿐만 아니라 다른 패키지에도 사용할 수 있다.
- default
- 같은 패키지에서는 제한 없이 사용 가능하지만 다른 패키지에서는 사용 할 수 없다.
✔️ 생성자의 접근 제한 + 필드의 접근 제한
생성자 또한 어떤 접근 제한을 갖느냐에 따라 호출 가능 여부가 결정된다.
사용 가능한 접근 제한자
- public
- 모든 패키지
- default
- 같은 패키지
- private
- 클래스 내부
🏷 Getter와 Setter
객체의 필드를 외부에서 마음대로 읽고 변경할 경우 객체의 무결성이 깨질 수 있다.
이러한 문제점 때문에 객체 지향 프로그래밍에서는 직접적인 외부에서의 필드 접근을 막고 대신 메소드를 통해 필드에 접근하는 것을 선호한다.
그 이유는 !!
메소드는 데이터를 검증해서 유효한 값만 필드에 저장할 수 있기 때문이다. -> 이러한 역활을 하는 메소드가 setter() 이다.
또한, 외부에서 객체의 필드를 읽을 때에도 메소드가 필요한 경우가 있다.
필드 값이 객체 외부에서 사용하기에 부적절한 경우, 메소드로 적절한 값으로 변환해서 리턴할 수 있기 때문이다. -> 이러한 역활을 하는 메소드가 getter() 이다.
필드 타입이 boolean 형 일 경우에는 getter() 는 get으로 시작하지 않고 is 로 시작하는 것이 관례이다.
🏷 싱글톤 패턴
아래 포스팅 참고
'📝 이것이 자바다' 카테고리의 다른 글
Chapter 08. 인터페이스 (0) | 2022.12.29 |
---|---|
Chapter 07. 상속 (0) | 2022.12.15 |
Chapter 06. 객체 지향 프로그래밍 - 1 (0) | 2022.11.14 |
Chapter 05. 참조 타입 (0) | 2022.11.07 |
Chapter 04. 조건문과 반복문 (0) | 2022.11.02 |