지구정복
[JAVA] 인스턴스 멤버와 정적멤버 본문
어떠한 객체의 필드값이 객체마다 다르다면 해당 필드를 각 객체마다 가지고 있어야 한다.
하지만 객체의 필드값이 모두 같다면 각 객체마다 해당 필드를 가지고 있는 것은 메모리 낭비이다.
이런 필드는 한 곳에 위치시키고 객체들이 공유하는 것이 효율적이다.
이때 객체마다 가지고 있는 멤버를 인스턴스 멤버
하나의 클래스에 위치되어서 공통되는 필드를 공유해주는 멤버를 정적 멤버라고 한다.
ㅁ인스턴스 멤버와 this
인스턴스 멤버란 객체(인스턴스)를 생성한 후 사용할 수 있는 필드와 메소드를 말한다.
이들을 각각 인스턴스 필드, 인스턴스 메소드라고 부른다.
ㅇ인스턴스 멤버 선언
아래 코드로 예시를 든다.
gas와 setSpeed() 메소드는 인스턴스 멤버이기 때문에 외부 클래스에서 사용할 때에는 Car 객체를 생성하고
참조변수(mycar, yourcar)로 접근해야 한다.
이때 메소드는 객체 내부에 존재하지 않고 메소드 영역에 저장되고 공유된다.
이 이유는 메소드는 코드블럭이므로 객체마다 동일한 코드 블록을 가지고 있을 필요가 없기 때문이다.
그런데 인스턴스 메소드로 불리는 이유는 메소드 안에 인스턴스 필드가 사용되는 경우에 인스턴스 메소드라 불린다.
public class Car {
//field
int gas;
//method
void setSpeed(int speed) { }
}
public class CarExample {
public static void main(String[] args) {
Car mycar = new Car();
mycar.gas = 10;
mycar.setSpeed(60);
Car yourcar = new Car();
yourcar.gas = 20;
yourcar.setSpeed(80);
}
}
ㅇthis
객체 내부에서도 인스턴스 멤버에 접근하기 위해 this를 사용할 수 있음.
this는 주로 생성자와 메소드의 매개 변수 이름이 필드와 동일한 경우 인스턴스 멤버인 필드임을 명시하고자 할 때 사용.
ㅁ정적 멤버와 static
정적(static)은 '고정된' 이란 의미입니다.
정적 멤버는 클래스에 고정된 멤버로서 객체를 생성하지 않고 사용할 수 있는 필드와 메소드를 말한다.
각각 정적필드, 정적메소드라고 불린다.
ㅇ정적 멤버 선언
필드와 메소드 선언 시 static 키워드를 추가하면 된다.
하지만 필드를 선언할 때 인스턴스 필드로 선언할 것인가 아니면 정적 필드로 선언할 것인가에 대한 기준이 필요하다.
이에 대한 기준은
만약 객체마다 가지고 있어야 할 데이터라면 인스턴스 필드로 선언,
객체마다 가지고 있을 필요가 없는 공용 데이터라면 정적 필드로 선언한다.
메소드 또한 기준은 비슷하다.
메소드 안에 인스턴스 필드를 포함하고 있다면 인스턴스 메소드로 선언,
메소드 안에 인스턴스 필드를 포함하고 있지 않다면 정적 메소드로 선언한다.
아래 예시에서 pi는 고정된 값이므로 정적 필드로 선언한다.
public class Calculator {
//필드 선언
String color;
static double pi = 3.14159;
//메소드 선언
void setColor(String color) {}
static int plus(int x, int y) {return x+y;}
}
ㅇ정적 멤버 사용
클래스가 메모리로 로딩되면 정적 멤버를 바로 사용할 수 있다.
위의 예시에서 선언한 정적 필드와 메소드를 사용해본다.
정적 요소(정적 필드와 메소드)는 객체를 생성해서 참조변수를 통해서 사용하는 것이 아니라
클래스 이름으로 바로 접근하는 것이 좋다.
public class CalculatorExample {
public static void main(String[] args) {
//정적 필드사용
double result1 = 10 * 10 * Calculator.pi;
//정적 메소드 사용
int result2 = Calculator.plus(10, 5);
}
}
ㅇ정적 메소드 선언 시 주의할 점
정적 메소드를 선언할 때는 이들 내부에 인스턴스 필드나 인스턴스 메소드를 사용할 수 없다.
또한 객체 자신의 참조인 this키워드도 사용이 불가능하다.
정적 메소드에서 인스턴스 멤버를 사용하고 싶다면 객체를 먼저 생성하고 참조 변수로 접근해야 한다.
아래 예시에서 정적 메소드인 Method3에 인스턴스필드 field1을 사용하려면 obj 객체를 생성하고 사용한다.
public class ClassName {
//인스턴스 필드와 메소드
int field1;
void Method1() {}
//정적 필드와 메소드
static int field2;
static void Method2() {}
//정적 메소드
static void Method3 () {
ClassName obj = new ClassName();
obj.field1 = 10;
obj.Method1();
}
}
ㅁ싱글톤
가끔 전체 프로그램에서 단 하나의 객체만 만들도록 보장해야 하는 경우가 있다.
이러한 단 하나만 생성되는 객체를 싱글톤(Singleton)이라고 한다.
싱글톤을 만드려면 외부 클래스에서 new 연산자로 생성자를 호출할 수 없도록 막아야 한다.
이를 위해서 생성자 앞에 private 접근 제한자를 붙여 준다.
그리고 자신의 타입인 정적 필드를 하나 선언하고 자신의 객체를 생성해 초기화한다.
이때 정적 필드도 private 접근 제한자를 붙여 외부에서 필드값을 변경 못하도록 막는다.
대신 외부에서 이 필드를 호출할 수 있도록 정적 메소드인 getInstance() 를 선언하고 정적 필드에서 참조하고 있는
자신의 객체를 리턴해준다. 즉, 외부에서 객체를 얻는 유일한 방법은 getInstance() 메소드를 호출하는 방법밖에 없다.
아래는 싱글톤을 만드는 코드이다.
public class Singleton {
//정적필드
private static Singleton singleton = new Singleton();
//생성자
private Singleton() {}
//정적 메소드
static Singleton getInstance() {
return singleton;
}
}
ㅁfinal 필드와 상수
ㅇfinal 필드
final은 '최종적' 이란 뜻을 가지고 있다. final 필드는 초기값이 저장되면 이것이 최종값이기 때문에 프로그램 실행
도중에 수정할 수 없다는 뜻이다.
final 필드의 초기값을 줄 수 있는 방법은 두 가지 뿐이다.
첫 번째는 필드 선언 시에 주는 방법
두 번째는 생성자에서 주는 방법
만일 객체 생성 시에 외부 데이터로 final 필드를 초기화해야한다면 생성자에서 초기값을 지정해야 한다.
아래 예시를 확인
public class Person {
final String nation = "Korea"; //필드 생성 시 final 필드 초기화
final String ssn;
String name;
//외부 클래스에서 객체 생성시 final 필드 초기화될 수 있도록 생성자에서 설정
public Person(String ssn, String name) {
this.ssn = ssn;
this.name = name;
}
}
public class PersonExample {
public static void main(String[] args) {
Person p1 = new Person("000101-1234567", "홍길동");
System.out.println(p1.nation);
System.out.println(p1.name);
System.out.println(p1.ssn);
}
}
출력결과
Korea
홍길동
000101-1234567
ㅇ상수
일반적으로 불변의 값을 상수(static final)라고 한다. 예를들면 원주율 파이, 지구의 무게 및 둘레 등
자바에서는 상수(constant)라고 부른다.
하지만 final필드를 상수라고 부르지 않는다. 불변의 값은 객체마다 저장할 필요가 없는 공용성을 띄며,
여러 가지 값으로 초기화될 수 없기 때문이다.
따라서 상수는 static 이면서 final 이어야 한다.
또한 상수 이름은 모두 대문자로 작성하는 것이 관례이다.
아래 예시 참고
public class Earth {
//상수선언
static final double EARTH_RADIUS = 6400;
static final double EARTH_AREA = 4 * Math.PI * EARTH_RADIUS * EARTH_RADIUS;
}
public class EarthExample {
public static void main(String[] args) {
System.out.println("지구의 반지름: "+Earth.EARTH_RADIUS);
System.out.println("지구의 표면적: "+Earth.EARTH_AREA);
}
}
ps. 혼자공부하는자바-신용권
'데이터 엔지니어링 정복 > JAVA & JSP' 카테고리의 다른 글
[JAVA] 상속 (0) | 2020.10.28 |
---|---|
[JAVA] 패키지와 접근 제한자 (0) | 2020.10.28 |
[JAVA] 메소드 (0) | 2020.10.26 |
[JAVA] 생성자 (0) | 2020.10.26 |
[JAVA] 필드 (0) | 2020.10.26 |