인스턴스 멤버/ this/ 정적 멤버/ static/ 싱글톤/ final필드/ 상수
뭔가 6-5는 새로 배우 것들이 많다!! >_<
인스턴스 멤버: 객체마다 가지고 있는 멤버
정적 멤버: 클래스에 위치시키고 객체들이 공유하는 멤버
>>객체 내부에 포함되느냐, 공유해서 사용하느냐
클래스 멤버(필드, 메소드)는 객체에 포함되어 있다. --> 효율적일까?
ㄴ객체마다 필드값이 다르면, 객체가 필드를 가지고 있어야 하겠지만
ㄴ객체들의 필드값이 모두 같다면.. 객체마다 필드를 갖고 있는게 메모리 낭비
ㄴ그래서 그럴때는 필드를 한 곳에 두고 공유하는 개념으로 쓰는게 좋을 수 있다.
>>그래서 클래스 멤버(필드, 메소드)를 '인스턴스 멤버'와 '정적 멤버'로 구분해 선언하는 것이다.
인스턴스 멤버
>>나는 지금까지 '인스턴스 필드'와 '인스턴스 메소드'를 선언해온 것이다.
>>이런 필드와 메소드는 '인스턴스 멤버이기 때문에' 외부 클래스에서 사용하기 위해서 '인스턴스(객체) 생성을 먼저 하고, 그 객체를 참조하고 있는 참조 변수와 도트 연산자를 통해 해당 인스턴스 필드와 메소드에 접근하였다.
>>인스턴스 필드와 메소드는 객체에 소속된 멤버
>>객체없이는 실행할 수 없다!
책에 있는 예시)
Car myCar = new Car();
myCar.gas = 10;
myCar.setSpeed(60);
Car yourCar = new Car();
yourCar.gas = 20;
yourCar.setSpeed(80);
>>실행 후..
인스턴스 필드 gas는 객체마다 따로 존재
인스턴스 메소드 setSpeed()는 메소드 영역에 저장, 공유
>>인스턴스 메소드가 객체에 소속된 멤버임에도 불구하고 메소드 영역에 존재하고 공유가 된다.
>>메소드 블록 내부에 인스턴스 필드가 사용되는 경우가 있기 때문에
인스턴스 메소드라고 부르는 거다!!
(책에 이렇게 꾸준히 그림으로 영역에 대한 설명이 나오니까 너무 보기 좋다^-^)
this
->참조 변수를 통해 객체 외부에서 인스턴스 멤버에 접근하는 것처럼
->"객체 내부에서도" 인스턴스에 접근하기 위해 this를 사용할 수 있다.
객체는 자신을 this라 칭하고, 자신이 가지고 있는 인스턴스 멤버를 가리킴을 나타낼 때 this.~~라고 쓴다.
this.model : 자신이 갖고 있는 model 필드라는 것.
++ 주로, 생성자와 메소드의 매개변수이름이 필드와 동일할 때
this.model은 '난 인스턴스 멤버 필드다!!'를 명시하기 위해 사용된다.
정적 멤버와 static
ㅇ"클래스에 고정된 멤버"로서, 메소드 영역에 들어간다!
ㅇ객체를 생성하지 않고 사용할 수 있는 필드와 메소드를 말한다.
ㅡㅡㅡ
필드 선언시 인스턴스로 할 지 정적 필드로 할지 잘 판단해야 한다.
객체마다 갖고 있어야 할 데이터면 인스턴스 필드로,
객체마다 다 가질 필요 없는 공용 데이터면 정적 필드로 선언한다.
public class Calculator {
String color; //계산기마다 색이 다를 수 있음
static double pi = 3.14159; //사용하는 파이값은 동일
}
변하지 않는 공용 데이터 파이를 정적 필드로 선언하였다.
메소드도..
블록 내부에 인스턴스필드 갖고 있으면 인스턴스 메소드로 선언하고
아니면 정적 메소드로 선언하면 된다.
ex) Calculator의 연산 기능은 인스턴스 필드 쓰기보다는 외부 데이터 받아서 연산하니까..
정적 메소드로 선언하자.
public class Calculator {
String color;
void setColor(String color) { this.color = color; }
static int plus(int x, int y) { return x + y; }
static int minus(int x, int y) { return x - y; }
}
ㅡㅡㅡㅡ
클래스가 메모리 영역에 로딩되면 정적 멤버를 사용할 수 있다.
(클래스(바이트 코드)를 클래스 로더가 로딩-->메소드 영역에 적재함. 그리고 클래스별로 관리됨.)
(클래스 로딩이 끝나면 바로 사용 가능)
ㅡㅡㅡㅡ
정적 멤버 사용하기
클래스이름.~~
>>
public class Calculator {
String color;
void setColor(String color) { this.color = color; }
static int plus(int x, int y) { return x + y; }
static int minus(int x, int y) { return x - y; }
}
double result1 = 10*10*Calulator.pi;
int result2 = Calculator.plus(10, 5);
int result3 = Calculator.minus(10, 5);
정적 필드와 정적 메소드는 위처럼
원칙적으로 클래스 이름으로 접근한다.
하지만...
다음과 같이 객체 참조 변수로도 접근이 가능하다.
Calculator myCalcu = new Calculator();
double result1 = 10*10*myCalcu.pi;
int result2 = myCalcu.plus(10, 5);
int result3 = myCalcu.minus(10, 5);
!!이클립스에선 정적 멤버를 객체참조변수로 접근했을 때 경고 표시가 나타난다.
정적 요소는 클래스 이름으로 접근하도록 하자.
++
정적 메소드에서 주의할 점!
<객체 내부에 있지 않다!>
ㅇ객체 자신의 참조인 this키워드 사용 불가
ㅇ인스턴스 멤버 사용 불가
>>정적 메소드에서 인스턴스 멤버 사용하고 싶으면
객체 선언이 필요하다.
main() 메소도드 static으로 선언된 정적 메소드다.
그래서 인스턴스 필드와 인스턴스 메소드를 그냥 사용할 수는 없다.
이런 이유로, 지금까지 그래왔듯이 객체 선언이 먼저 필요했던 것이다.
전체 프로그램에서 객체가 단 하나라면??
전체 프로그램에서 단 하나의 객체만 만들도록 보장해야 하는 경우가 있다.
이때 이 객체를
싱글톤
이라고 한다.
!!잠깐만용
new연산자로 생성자를 호출하는 만큼 새로운 객체가 생성됐다.
그러니까.. 싱글톤을 만드려면
클래스 외부에서 new연산자로 생성자를 호출할 수 없게 막아야 한다!!
>>생성자를.. 외부에서 호출 못하게 하려면 어떻게 해야 합니까??
이게 바로 private!!!
생성자 앞에 private 접근 제한자를 붙여주면 된다!!
그럼 생성자를 외부에서 호출할 수 없다.
(클래스 내부에서는 new연산자로 생성자 호출이 가능하다)
<<싱글톤을 만드는 코드>>
public class 클래스 { //정적필드 private static 클래스 singleton = new 클래스(); //생성자 private 클래스() {} //정적 메소드 static 클래스 getInstance() { return singleton; } } |
ㄴ자신타입(클래스)인 정적 필드를 하나 선언하고, 자신의 객체를 생성해 초기화한다.
ㄴ정적 필드도 private 접근 제한자를 붙여, 외부에서 필드값 변경 못하게 막는다.
ㄴ대신 외부 호출 가능한 정적 메소드인 getInstance()를 선언하고,
정적 필드에서 참조하고 있는 자신의 객체를 리턴해준다.
ㄴ아까 '프로그램당 단 하나의 객체'만 있다고 말했다.
ㄴ메소드는 단 하나의 객체만 리턴해주는 상황이고
ㄴ외부에서 객체 얻는 유일한 방법은 저 메소드를 호출하는 방법 하나뿐이다.
그래서 아래 코드에서 변수1, 변수2는 동일한 객체를 참조한다.
클래스 변수1 = 클래스.getInstance(); 클래스 변수2 = 클래스.getInstance(); |
++싱글톤 익히기
final 필드와 상수
final 필드: 말 그대로 최종 필드.. 초기값이 저장되면 이게 최종값이 되어서
프로그램 실행 도중 수정 불가!!
선언은 이렇게 한다.
final 타입 필드 [=초기값];
final필드에 초기값을 주는 방법은 단 두가지뿐!!!!!
1. 필드 선언할때 주거나
2. 생성자에서 주거나.
ㄴ단순 값이면 선언할때 그냥 줘도 되지만
ㄴ뭔가 복잡한 초기화 코드가 필요하거나, 외부 데이터를 통한다면 생성자에서 초기값을 지정한다.
(+만약 끝까지 초기화되지 않는다면 컴파일 에러다.)
<<final 필드 선언과 초기화>>
상수
상수는 static이면서 final이어야 한다.
그냥 final 필드는.. 한번 초기화되면 수정할 수 없는 정해진 값이라서 상수일 것 같은데
상수라고 할 수 없다.
>>그냥 final 필드는 객체마다 저장된다.(인스턴스) : 상수는 불변의 값으로 객체마다 저장할 필요가 없는 공용성이 있다.
>>그냥 final 필드는 생성자의 매개값에 따라 여러 값을 가질 수 있는 가능성이 있다. : 상수는 정해져 있으며, 여러 값으로 초기화될 수 없다.
그래서!! 객체마다 저장할 필요 없는 공공적인 것이 상수이기 때문에 static이면서 final이어야 한다.
static final 필드(상수)는
ㅇ객체마다 존재하지 않는다!! 클래스에만 존재한다.
ㅇ한 번 초기값이 저장되면 변경 불가
ㅇ여러 값으로 초기화될 가능성이 없다.
"상수 이름 -> 모두 대문자로 작성하는 것이 관례!!"
상수 필드를 올바르게 선언한 예..
오로지 정해진 하나의 값으로 초기화된다.
final 필드이기 때문에 변경 불가고
static 필드이기 때문에 공유된다. 객체마다 존재x 클래스에만o
<<상수 사용 익히기>>
(잠깐 복습 : static.. 정적 멤버는 원칙적으로 '클래스 이름'을 통해 접근한다는 거!
+객체를 생성하지 않고 사용할 수 있다.
+객체 생성 없이 클래스를 통해 접근할 수 있다.
++인스턴스 멤버는 객체에 소속된 거기 때문에, 객체 생성 먼저 하고 사용해야 한다.)
확인 문제
03.
ShopService 객체를 싱글톤으로 만들고 싶다....
실행 클래스에서 ShopService의 getInstance()메소드로 싱글톤을 얻을 수 있도록
ShopService클래스를 작성해보자.
답지를 확인해보니까 8줄의 public은 안쓴다.
(검색해보니까 public 등 접근 제한자를 생략하면 default 접근를 제한자 가진다고 하는데.. 어차피 곧 접근 제한자 배우니까 일단 배우고 나서 다시 돌아와보자.)
++4줄의 static.. 실행클래스에서 객체를 생성하지 않고 클래스 이름을 통해 필드에 접근 가능하게 하려고 써 주었다.
'JAVA' 카테고리의 다른 글
[혼자 공부하는 자바] 7/09 07-1 [상속] [자식클래스] [부모클래스] [오버라이딩] [메소드 재정의] (0) | 2020.07.10 |
---|---|
[혼자 공부하는 자바] 7/08 06-6 [패키지와 접근 제한자] (0) | 2020.07.08 |
[혼자 공부하는 자바] 7/07 06-4 [메소드] (0) | 2020.07.07 |
[1주차] 기본미션 + 선택미션 [혼공단] [혼공자] (0) | 2020.07.07 |
[혼자 공부하는 자바] 7/06 06-3 [생성자] [생성자 선언] [생성자 오버로딩] (0) | 2020.07.06 |