우당탕탕 좌충우돌 개발일기
static(정적)의 의미와 사용 본문
자바를 사용하면서 static이란 키워드를 정말 많이 보게된다.
가장 대표적인게 메인 함수에서 쓰이는 static이다.
public static void main(String[] args)
그러다 static을 너무 대충 겉핥기 식으로만 이해하고 있는 것 같아서 공부해보려한다.
Java Static Keyword
자바에서 static 키워드는 주로 메모리 관리를 위해 사용된다.
우리는 변수, 메서드, 블록 그리고 중첩 클래스에 static 키워드를 적용할 수 있다.
static 키워드는 클래스의 인스턴스가 아닌 클래스 자체에 해당한다.
1. 변수(Variable - 클래스 변수로도 알려져있음)
2. 메서드(Method - 클래스 메서드로도 알려져있음)
3. 블럭(Block)
4. 중첩 클래스(Nested class)
1) Java static variable (자바 정적 변수)
만약 변수를 static으로 선언한다면, 이를 정적 변수라고 한다.
정적 변수는 모든 객체의 공통 속성을 참조하는데 사용할 수 있다.
예를 들면 직원들의 회사 이름이나 학생들의 대학 이름 등이 해당된다.
정적 변수는 클래스가 로드될 때 클래스 영역에서 단 한 번만 메모리를 할당받게된다.
👍 정적 변수의 장점
프로그램의 메모리 효율성을 높여준다. (즉, 메모리 절약 가능)
그럼 정적 변수가 없을 때 발생하는 문제를 예시를 통해 살펴보자.
예를 들어, 내 대학에 500명의 학생이 있다고 가정하면, 객체가 생성될 때마다 모든 인스턴스 데이터 멤버가 메모리를 할당 받게된다.
모든 학생은 고유의 학번(rollno)과 이름(name)을 가지고 있으므로, 인스턴스 데이터 멤버는 이런 경우에 적합하다.
그러나, "college"는 모든 객체의 공통 속성을 나타낸다.
해당 필드를 static으로 만들면, 이 필드는 메모리를 한 번만 할당받게 된다.
class Student{
int rollno;
String name;
String college="ITS";
}
💻 정적 변수의 예제
//정적 변수를 사용하는 자바 프로그램 예시
class Student{
int rollno;//인스턴스 변수
String name;
static String college ="ITS";//정적 변수
Student(int r, String n){//생성자
rollno = r;
name = n;
}
void display (){//값을 나타내기 위한 메서드
System.out.println(rollno+" "+name+" "+college);
}
}
//객체들의 값을 보여주기 위한 테스트 클래스
public class TestStaticVariable1{
public static void main(String args[]){
Student s1 = new Student(111,"Karan");
Student s2 = new Student(222,"Aryan");
//모든 객체의 college값을 한 줄의 코드로 변경할 수 있다.
//Student.college="BBDIT";
s1.display();
s2.display();
}
}
[출력 결과값]
111 Karan ITS
222 Aryan ITS
💻 정적 변수가 없는 count 프로그램 예제코드
다음은, 객체가 생성될 때마다 메모리를 할당 받는 인스턴스 변수를 사용한 예제이다.
이 예제에서는 count라는 인스턴스 변수를 생성자에서 증가시키고 있다.
인스턴스 변수는 객체가 생성될 때 메모리를 할당받기 때문에, 각 객체는 인스턴스 변수의 복사본을 갖게 된다.
변수가 증가하더라도, 다른 객체에는 영향을 주지 않으므로,각 객체의 count 변수는 1값을 갖게 된다.
//객체가 생성될 때마다 메모리를 할당받는 인스턴스 변수를 사용하는 Java 프로그램
class Counter{
int count=0; //객체가 생성될 때마다 메모리를 할당받음
Counter(){
count++; //값을 증가시킨다
System.out.println(count);
}
public static void main(String args[]){
//객체 생성
Counter c1=new Counter();
Counter c2=new Counter();
Counter c3=new Counter();
}
}
[출력 결과값]
1
1
1
💻 정적 변수를 이용한 count 프로그램 예제코드
위에서 언급했듯이, 정적 변수는 메모리를 한 번만 할당받는데, 어떤 객체가 정적 변수의 값을 변경하더라도 그 값은 유지된다.
//모든 객체와 공유되는 static 변수의 사용을 설명하는 Java 프로그램
class Counter2{
static int count=0; //메모리를 한 번만 할당받고 값을 유지
Counter2(){
count++; //값을 증가시킨다.
System.out.println(count);
}
public static void main(String args[]){
//객체 생성
Counter2 c1=new Counter2();
Counter2 c2=new Counter2();
Counter2 c3=new Counter2();
}
}
[출력 결과값]
1
2
3
2) Java static method (자바 정적 메서드)
만약 static 키워드를 메서드에 적용한다면, 이를 정적 메서드라고 한다.
정적 메서드는 클래스의 객체가 아니라 클래스 자체에 해당한다.
정적 메서드는 클래스의 인스턴스를 생성할 필요 없이 호출될 수 있다.
정적 메서드는 정적 데이터 멤버에 접근할 수 있고 그 값을 변경할 수 있다.
💻 정적 메서드의 예제
//정적 메서드의 사용을 나타내기 위한 Java 프로그램
class Student{
int rollno;
String name;
static String college = "ITS";
//정적 변수의 값을 변경하기 위한 정적 메서드
static void change(){
college = "BBDIT";
}
//변수를 초기화하기 위한 생성자
Student(int r, String n){
rollno = r;
name = n;
}
//값을 보여주기 위한 메서드
void display(){
System.out.println(rollno+" "+name+" "+college);
}
}
// 객체의 값을 생성하고 보여주기 위한 테스트 클래스
public class TestStaticMethod{
public static void main(String args[]){
Student.change(); //변경 메서드를 호출한다.
//객체 생성
Student s1 = new Student(111,"Karan");
Student s2 = new Student(222,"Aryan");
Student s3 = new Student(333,"Sonoo");
//값을 보여주기 위한 메서드를 호출한다.
s1.display();
s2.display();
s3.display();
}
}
[출력 결과값]
111 Karan BBDIT
222 Aryan BBDIT
333 Sonoo BBDIT
💻 일반 계산을 수행하는 정적 메서드의 예제코드
//정적 메서드를 사용하여 주어진 숫자의 세제곱을 구하는 Java 프로그램
class Calculate{
static int cube(int x){
return x*x*x;
}
public static void main(String args[]){
int result=Calculate.cube(5);
System.out.println(result);
}
}
[출력 결과값]
125
🚫 정적 메서드에 대한 제한사항 🚫
정적 메서드에 대한 2가지 주요 제한 사항이 있다.
1. 정적 메서드는 비정적 데이터 멤버를 사용할 수 없고 비정적 메서드를 직접적으로 호출할 수 없다.
2. this와 super 키워드는 정적 컨텍스트에서 사용할 수 없다.
💻 예제 코드
class A {
int a=40;//비정적
public static void main(String args[]){
System.out.println(a);
}
}
[출력 결과값]
Compilation Error
Main.java:5: error: non-static variable a cannot be referenced from a static context
System.out.println(a);
^
1 error
[코드 설명]
위의 예제 코드에는 클래스 A가 있다.
이 A 클래스에는 값이 40으로 설정된 인스턴스 변수 a가 있고, 해당 변수는 비정적 변수로 선언 되있다.
그런데, System.out.println(a) 를 통해 a 인스턴스 변수를 클래스 A의 main 메서드에서 직접 접근하려고 시도하고 있다.
앞서 제한사항에 언급했듯이, Java에서 정적 메서드는 비정적 변수를 직접 접근할 수 없기 때문에, 결과값처럼 컴파일 오류를 유발하게 된다.
비정적 변수 a에 접근하려면 먼저 A클래스의 인스턴스를 생성해야한다.
그 다음에, 해당 인스턴스를 사용하여 변수 a를 접근할 수 있다.
따라서, 아래와 같이 작성하여 main 메서드에서 a에 접근하는 것이 적절하다.
class A{
int a=40;//non static
public static void main(String args[]){
A obj = new A();
System.out.println(obj.a);
}
}
[출력 결과값]
40
❓ 왜 Java main() 메서드는 정적인가?
자바에서, main() 메서드는 정적으로 선언된다. 그 이유는 객체를 생성하지 않고도 정적 메서드를 호출할 수 있기 때문이다.
만약 main() 메서드가 비정적 이라면, JVM 이 먼저 객체를 생성하고나서 main() 메서드를 호출해야 할 것이다.
이런 경우, 추가적인 메모리 할당 문제가 발생하게 된다.
따라서 main() 메서드를 정적으로 선언함으로써 이러한 불필요한 메모리 소비를 피하고, 프로그램의 시작 지점으로 바로 호출할 수 있게 된다.
3) Java Static Block (자바 정적 블럭)
정적 데이터 멤버를 초기화하는데 사용한다.
클래스가 로드될 때 main() 메서드 전에 실행된다.
💻 예제 코드
class A2 {
static{
System.out.println("static block is invoked");
}
public static void main(String args[]){
System.out.println("Hello main");
}
}
[출력 결과값]
static block is invoked
Hello main
[코드 설명]
위의 예제 코드에는 클래스 A2가 있다.
해당 클래스 내부에는 중괄호로 둘러싸인 정적(static) 키워드가 붙은 정적 블록이 포함되어 있다.
정적 블록은 클래스가 메모리에 로드될 때 단 한 번 실행되며, 이는 main 메서드 실행이나 클래스 객체의 생성전에 수행된다.
이런 경우, 정적 블록에는 System.out.println("static block is invoked"); 라는 문이 포함되어 있어, A2 클래스가 메모리에 로드될 때 "static block is invoked"라는 메시지를 콘솔에 출력한다.
또한, A2 클래스에는 main() 메서드가 포함되있으며, 이 메서드가 실행될 때 "Hello main"을 콘솔에 출력한다.
main 메서드는 프로그램의 진입점이기 때문에 Java Virtual Machine(JVM)에 의해 명시적으로 호출되어야 한다.
따라서 프로그램을 실행하면 정적 블록이 먼저 실행되어 정적 블록의 메시지가 출력되고, 그 다음으로 main 메서드가 실행되어 콘솔에 "Hello main"을 출력하게 된다.
❓ main() 메서드 없이 프로그램을 실행할 수 있을까?
아니다. 한 가지 방법은 정적 블록인데, JDK 1.6버전까지만 가능했고 1.7 버전 부터는 main() 메서드 없이 자바 클래스를 실행할 수 없다.
class A3 {
static{
System.out.println("static block is invoked");
System.exit(0);
}
}
[1.6 버전의 출력 결과값]
static block is invoked
[1.7 버전의 출력 결과값]
Error: Main method not found in class A3, please define the main method as:
public static void main(String[] args)
or a JavaFX application class must extend javafx.application.Application
[코드 설명]
위의 예제 코드에는 클래스 A3가 있다. 해당 클래스는 'static block is invoked'라는 메시지를 콘솔에 출력한 후 프로그램을 종료하기 위해 System.exit(0);를 사용하는 정적 블록을 가지고 있다.
이로 인해 정적 블록은 클래스가 메모리에 로드될 때 실행되어 메시지를 출력하고 프로그램을 즉시 종료하여 더 이상 코드가 실행되지 않도록 한다.
4) Java Nested Classes (자바 중첩 클래스)
자바에서, 중첩 클래스는 다른 클래스내에 선언된 클래스를 말한다.
중첩 클래스에는 4가지 유형이 있다.
1. 정적 중첩 클래스 (Static Nested Class)
static 키워드로 선언된 클래스다. 일반적인 최상위 클래스처럼 동작하지만 패키지 편의를 위해 중첩된다.
정적 중첩 클래스는 외부 클래스의 비정적 멤버에 직접 접근할 수 없다.
2. 비정적 중첩 클래스 (Inner Class)
static 키워드 없이 선언된 내부 클래스다. 내부 클래스는 외부 클래스의 멤버(비공식 멤버 포함)에 접근할 수 있다.
주로 다른 클래스의 문맥에서만 의미가 있는 클래스를 논리적으로 그룹화하는 데 사용된다.
3. 로컬 내부 클래스 (Local Inner Class)
메서드나 코드 블록 내에서 선언된 내부 클래스다.
로컬 내부 클래스는 외부 메서드의 변수를 접근할 수 있으며, 외부 클래스의 멤버에도 접근할 수 있다.
4. 익명 내부 클래스 (Anonymous Inner Class)
이름이 없는 로컬 내부 클래스로, 보통 인터페이스를 구현하거나 클래스를 확장하기 위해 한 번만 사용되는 작은 클래스를 생성하는 데 사용된다.
중첩 클래스는 한 번만 사용되는 클래스를 함께 그룹화하여 외부 클래스의 구현 세부 사항을 숨김으로써 코드 조직과 캡슐화를 개선하는 방법을 제공한다.
또한 한 곳에서만 사용되는 클래스를 논리적으로 그룹화할 수 있는 방법을 제공하여 캡슐화와 코드 조직을 증가시킨다.
출처 : https://www.javatpoint.com/static-keyword-in-java
'Programming > JAVA' 카테고리의 다른 글
Math 클래스 (1) | 2024.10.16 |
---|---|
스트링(String) 클래스의 문제점 (0) | 2024.10.16 |
StringBuffer(스트링버퍼) (0) | 2024.10.15 |
java.lang 패키지/오토박싱(Autoboxing) (0) | 2024.10.14 |
Object와 오버라이딩(Overriding) (0) | 2024.10.10 |