멤버 변수에는 인스턴스 변수와 클래스 변수가 존재한다.
static변수는 클래스 변수, 정적 변수라고도 불린다.
1. 인스턴스 변수 : static이 붙지 않음
- 인스턴스를 생성해야 사용할 수 있고, 인스턴스에 소속되어 있다.
- 인스턴스를 만들 때 마다 새로 만들어진다.
2. 클래스 변수 : static 붙음
- static이 붙은 멤버변수. 클래스에 바로 접근해서 사용할 수 있다. 클래스 자체에 소속되어 있다.
- 자바 프로그램을 시작할 때 딱 1개가 만들어진다. 보통 여러곳에서 공유하는 목적으로 사용된다.
static을 이해하기 위해 코드를 통해 먼저 알아볼 필요가 있다.
1. Static 변수
1) static 사용 전
아래의 예제는 Data1클래스의 객체를 3개 생성하고 생성할 때마다 count를 1씩 증가시켜 count를 3으로 할당 시키려고 시도한 예제이다.
public class Data1 {
public String name;
public int count;
public Data1(String name){
this.name = name;
count++;
}
}
public class DataCountMain1 {
public static void main(String[] args) {
Data1 data1 = new Data1("A");
System.out.println("A count = " + data1.count);
Data1 data2 = new Data1("B");
System.out.println("B count = " + data2.count);
Data1 data3 = new Data1("C");
System.out.println("C count = " + data2.count);
}
}
/*실행 결과
A count = 1
B count = 1
C count = 1
/*
실행결과는 당연히 1이 된다.
객체를 생성할 때마다 변수 count는 data1, data2, data3 에 각각 존재하기 때문에, 같은 count를 공유하고 있는것이 아니므로 1씩 할당받게 되는것이다. 그렇다면 세 개의 객체가 같은 count를 공유하고 1씩 증가시키려면 어떻게 해야할까?
static을 이용하면 된다.
2) static 사용 후
public class Data3 {
public String name;
public static int count;
public Data3(String name){
this.name = name;
count++;
}
}
public class DataCountMain3 {
public static void main(String[] args) {
Data3 data1 = new Data3("A");
System.out.println("A count = " + Data3.count);
Data3 data2 = new Data3("B");
System.out.println("B count = " + Data3.count);
Data3 data3 = new Data3("C");
System.out.println("C count = " + Data3.count);
//추가
//인스턴스를 통한 접근
Data3 data4 = new Data3("D");
System.out.println(data4.count);
//클래스를 통한 접근
System.out.println(Data3.count);
}
}
/*실행 결과
A count = 1
B count = 2
C count = 3
4
4
*/
이렇게 count라는 필드에 static을 붙여주면, 자바 메모리 구조에서 method영역에 count라는 변수가 존재하게 되고, 자바가heap 영역에 count라는 변수가 없는 것을 확인한 후 method영역에서 count를 꺼내서 쓴다고 이해를 하였다. method영역은 프로그램의 모든 영역에서 공유하기 때문에, 어떤 객체에서 접근해서 수정해도 모든 영역에 반영된다.
//추가 이 부분은 static 변수에 접근하는 방법 2가지를 나타낸 것이다.
인스턴스를 이용해서(data4.count)접근을 할 수도 있고, 클래스를 통해 접근(Data3.count)할 수도 있다.
2. Static 메서드
1) static 사용 전
public class DecoUtil1 {
public String deco(String str){
return "*" + str + "*";
}
}
public class DecoMain1 {
public static void main(String[] args) {
String s = "hello java";
DecoUtil1 utils = new DecoUtil1();
String deco = utils.deco(s);
System.out.println("before = " + s);
System.out.println("after = " + deco);
}
}
/*실행 결과
before = hello java
after = *hello java*
*/
DecoUtil1이라는 클래스는 deco메서드를 가지고 있고, deco메서드는 멤버 변수도 없고, 단순히 기능만 제공한다. 이 메서드를 사용하려면 인스턴스를 생성해야 하는데, 인스턴스가 필요한 이유는 멤버 변수등을 사용하려는 목적이 크다. 그렇기 때문에 static을 붙여 정적 메서드로 만들고, 객체 생성도 따로 하지 않고 deco메서드를 사용할 수 있다. 아래에서 적용해보자.
2) static 사용 후
public class DecoUtil2 {
public static String deco(String str){
return "*" + str + "*";
}
}
public class DecoMain2 {
public static void main(String[] args) {
String s = "hello java";
String deco = DecoUtil2.deco(s);
System.out.println("before = " + s);
System.out.println("after = " + deco);
}
}
/*실행 결과
before = hello java
after = *hello java*
*/
위의 배운 내용을 적용해보자.
DecoUtil2의 deco메서드에 static을 붙여 main메서드에서 객체 생성없이 클래스로 접근하여 바로 사용하였고, 불필요한 객체 생성을 하지 않게 되었다.
3) static메서드 사용법
- static메서드는 static만 사용할 수 있다 - static메서드는 static이 붙은 정적 메서드나 정적 변수만 사용할 수 있다.
- 반대로 모든 곳에서 static을 호출할 수 있다.
말로는 이해가 잘 안간다. 코드로 알아보자
public class DecoData {
private int instanceValue;
private static int staticValue;
public static void staticCall(){
// instanceValue++; //인스턴스 변수 접근, 컴파일 에러
// instanceMethod();//인스턴스 메서드 접근, 컴파일 에러
staticValue++; //정적 변수 접근
staticMethod(); //정적 메서드 접근
}
public void instanceCall(){
instanceValue++;//인스턴스 변수 접근
instanceMethod();//인스턴스 메서드 접근
staticValue++; //정적 변수 접근
staticMethod(); //정적 메서드 접근
}
public static void staticCall(DecoData data){
data.instanceValue++;
data.instanceCall();
}
private void instanceMethod(){
System.out.println("instanceValue = " + instanceValue);
}
private static void staticMethod(){
System.out.println("staticValue = " + staticValue);
}
}
staticCall메서드에서 instance메서드와 변수를 사용하려고 하면 컴파일 에러가 뜬다.
하지만 static변수와 메서드를 사용할 수는 있다.
instanceCall메서드에서는 static변수와 메서드, instance변수와 메서드를 모두 사용할 수 있다.
public class DecoDataMain {
public static void main(String[] args) {
System.out.println("1. 정적 호출");
DecoData.staticCall();
System.out.println("2. 인스턴스 호출1");
DecoData data1 = new DecoData();
data1.instanceCall();
System.out.println("3. 인스턴스 호출1");
DecoData data2 = new DecoData();
data2.instanceCall();
//추가
//인스턴스를 통한 접근
DecoData data3 = new DecoData();
data3.staticCall();
//클래스를 통한 접근
DecoData.staticCall();
}
}
/*실행 결과
1. 정적 호출
staticValue = 1
2. 인스턴스 호출1
instanceValue = 1
staticValue = 2
3. 인스턴스 호출1
instanceValue = 1
staticValue = 3
staticValue = 4
staticValue = 5
*/
static메서드가 instance 기능을 사용할 수 없는 이유는,
static메서드는 클래스의 이름을 통해 바로 호출한다. 그래서 인스턴스처럼 참조값의 개념이 없고, 특정 인스턴스의 기능을 사용하려면 참조값을 알아야 하지만, static메서드는 참조값 없이 호출하기에 instance변수나 메서드를 사용할 수 없다.
하지만 매개변수에 직접 참조값을 전달하면, 인스턴스의 변수나 메서드를 호출할 수 있다.
//추가 이부분은 static변수와 마찬가지로 인스턴스와 클래스를 통해 모두 접근 가능하다는 것을 보여주는 예제이다.
'JAVA' 카테고리의 다른 글
| [자바/JAVA] 상속(Inheritance) (0) | 2024.06.14 |
|---|---|
| [자바/JAVA] final(상수) (3) | 2024.06.13 |
| [자바/JAVA] 자바 메모리 구조와 스택(Stack) (1) | 2024.06.13 |
| [자바/JAVA] 접근 제어자(Access Modifier)와 캡슐화(Encapsulation) (2) | 2024.06.12 |
| [자바/JAVA] 생성자(Constructor) (0) | 2024.05.26 |