이 글에서는 Java에서 사용하는 static과 final에 대해 알아볼 것이다.
static
class 내에서 static으로 선언된 member는 class로 정의된 모든 instance에서 같은 값을 가진다. (class와는 별도로 생성되기 때문에 class를 정의하지 않고도 사용할 수 있다)
해당 member는 class가 메모리에 로드될 때 heap에 올라가기 때문에 instance가 생성되기 전에도 사용할 수 있으며, object와는 별도로 만들어지기 때문에 class 크기에 영향을 주지 않는다. static member는 GC가 관리하긴 하지만, 해당 class가 static member를 참조하지 않는 경우가 거의 없기 때문에 계속 남아 있게 되므로 남발하는 경우 메모리 효율이 나빠진다는 점을 고려해야 한다.
static field
static field는 해당 class가 모두 공유하는 값이다. 아래 예시와 같이 class 내부에서 접근 가능하다.
// StaticExample.java
public class StaticExample {
static int count = 0;
public void addCount() { // static field 접근
count += 1;
}
public int getCount() {
return count;
}
}
// App.java
public class App {
public static void main(String[] args) throws Exception {
StaticExample classExample1 = new StaticExample();
StaticExample classExample2 = new StaticExample();
System.out.println(classExample1.getCount()); // 0
classExample1.addCount();
System.out.println(classExample1.getCount()); // 1
System.out.println(classExample2.getCount()); // 2
}
}
// 모든 class에서 공유하기 때문에 위와 같이 classExample 1에서 값을 증가시킨 후
// classExample2에서 해당 변수에 접근하면 값이 바뀌어 있는 것을 확인할 수 있다.
static method
static method는 static field와 동일하게 class를 정의하지 않고 해당 method를 사용할 수 있다. 그러나 이 방식의 경우 객체지향보다는 절차지향에 좀 더 가깝기 때문에 지양해야 할 것이다.
// StaticExample.java
public class StaticExample {
static int count = 0;
static public void addCount() { // static method 정의
count += 1;
}
static public int getCount() {
return count;
}
}
// App.java
public class App {
public static void main(String[] args) throws Exception {
// StaticExample classExample1 = new StaticExample();
// StaticExample classExample2 = new StaticExample();
System.out.println(StaticExample.getCount()); // 0
StaticExample.addCount();
System.out.println(StaticExample.getCount()); // 1
System.out.println(StaticExample.getCount()); // 2
}
}
// static method는 객체의 정의 없이 사용할 수 있다.
또한 class 내부에서 static method로는 접근할 수 있지만 static method에서는 class member로 접근할 수 없다!(this도 포함) class를 정의하지 않았을 때를 생각해 보면 이해하기 쉽다. class가 정의되지 않아 메모리에 올라가지 않은 상태인데 static method로 class member를 조작한다? 메모리에 있지 않은 값을 조작하는 것이며, 뭔가 이상하다는 것을 알아차릴 수 있다. class가 여러 개 정의되었을 때도 문제가 생긴다. static method가 class member 값을 사용한다고 가정했을 때 어떤 class의 member에 접근해야 하는가? 이러한 문제 때문에 static method에서 class member로의 접근은 막혀있다.
// StaticExample.java
public class StaticExample {
static int staticField = 0;
private int attribute = 0;
public void add(){
this.attribute++;
staticField++;
}
public int getStaticField(){
return staticField;
}
public int getAttribute(){
return this.attribute;
}
static public void addStatic(){
this.attribute++; // compile error
staticField++; // OK
}
}
// non-static method에서 static을 call하는 것은 허용되지만
// static method에서 non-static을 call하는 것은 허용되지 않음
// App.java
public class App {
public static void main(String[] args) throws Exception {
StaticExample staticExample = new StaticExample();
System.out.println(staticExample.getStaticField()); // 0
System.out.println(staticExample.getAttribute()); // 0
staticExample.add();
System.out.println(staticExample.getStaticField()); // 0
System.out.println(staticExample.getAttribute()); // 0
}
}
final
java에서 final은 variable(field), method, class에 사용할 수 있다.
final variable
c++에서 const와 유사하다. class로 정의한 객체 내에서 상수 값이며 이 변수는 초기화할 때를 제외하고 값을 할당할 수 없다.
member variable이라면 생성자에서는 값을 할당할 수 있고, static final variable이라면 static block에서 초기화할 수 있다. 또한 final 변수는 선언과 동시에 값을 정의하거나 생성자에서 값을 정의하지 않으면 complie error가 발생한다.
// FinalExample.java
public class FinalExample {
/* final */
final private int finalAttribute1 = 1; // initialize with declaration
final private int finalAttribute2; // initialize with constructor
final private int finalAttribute3; // compile error : finalAttribute3 must be initialized
public FinalExample(){
finalAttribute2 = 2; // initialize with constructor
}
public int getFinalAttribute1(){
return this.finalAttribute1;
}
public int getFinalAttribute2(){
return this.finalAttribute2;
}
public void setFinalAttribute1(int input){
this.finalAttribute1 = input; // compile error : final field cannot be assigned
}
public void setFinalAttribute2(int input){
this.finalAttribute2 = input; // compile error : final field cannot be assigned
}
/* static final */
static final private int staticFinalAttribute1 = 1; // initialize with declaration
static final private int staticFinalAttribute2; // initialize with static block
static final private int staticFinalAttribute3; // compile error : finalAttribute3 must be initialized
static {
staticFinalAttribute2 = 2;
}
}
* static final vs final
final은 각각의 instance에 존재하는 상수라고 이해하면 쉽다. constructor에 따라 다른 값이 할당될 수 있기 때문이다.
반면 static final은 class에 존재하는 유일한 상수라고 이해하면 쉽다. static field는 모든 instance에서 공유하기 때문이다.
// FinalExample.java
public class FinalExample {
/* final */
final private int finalAttribute;
public FinalExample(int input){
this.finalAttribute = input;
}
public int getFinalAttribute(){
return this.finalAttribute;
}
/* static final */
static final private int staticFinalAttribute = 0;
public int getStaticFinalAttribute(){
return staticFinalAttribute;
}
}
// App.java
public class App {
public static void main(String[] args) throws Exception {
FinalExample finalExample1 = new FinalExample(1);
FinalExample finalExample2 = new FinalExample(2);
System.out.println(finalExample1.getFinalAttribute()); // 1
System.out.println(finalExample2.getFinalAttribute()); // 2
System.out.println(finalExample1.getStaticFinalAttribute()); // 0
System.out.println(finalExample2.getStaticFinalAttribute()); // 0
}
}
// final로 선언한 것은 각 객체에서는 상수이지만 객체별로 다른 값을 가질 수 있음
// static final로 선언한 것은 해당 class로 만든 모든 객체에서 상수임.
final method
해당 method는 override가 불가하다.
// Parent.java
public class Parent {
final public int get(){
return 20;
}
}
public class Child extends Parent {
@Override
public int get(){ // compile error : Cannot override the final method from Parent
return 10;
}
}
final class
해당 class는 inheritance가 불가하다.
// Parent.java
final public class Parent {
// ...
}
public class Child extends Parent {
// compile error : The type Child cannot subclass the final class Parent
// ...
}
'Development > Java' 카테고리의 다른 글
[Java] Polymorphism - static polymorphism, dynamic polymorphism, casting (0) | 2023.02.23 |
---|---|
[Java] Inheritance - access modifier, super, overriding (0) | 2023.02.23 |
[Java] Class - constructor, access modifier, identity & equality & hashCode (2) | 2023.02.22 |
[Java] Data types, 예외적인 String, 그리고 call by value (0) | 2023.02.21 |
[Java] HttpURLConnection으로 HTTP 통신하기 (0) | 2022.09.13 |