본문 바로가기

프로그래밍/개발

자바의 이모저모 : static, final, 그리고 캐스팅

public class PostRepository {
	private static final Logger logger = LoggerFactory.getLogger(PostRepository.class);
    
}

 

자바를 다루다 보면 위와 같은 변수선언들을 정말 자주 볼수 있다. 심지어 static final을 사용하지않으면 intellij에서 사용하라고 권장하기도 한다. 지금까지는 순순히 하라는대로 했지만 이제는 왜 그렇게 해야되는지를 알아보려고한다.

 

public class PostRepository {
	private Logger logger = LoggerFactory.getLogger(PostRepository.class);
    
}

 

아래와 같은 코드도 역시 가능하다. 그리고 C, C++을 사용할때는 이러한 경고창 역시 존재하지않았다.

 

Static

변수에 static을 붙이면 해당클래스의 모든 인스턴스에서 공유되는 변수가 된다. 클래스 변수는 단 한번 메모리에 할당되며 값을 공유한다. 즉 위의 예제 처럼 logger에 이를 붙이게 되면 logger는 모든 인스턴스에서 공유가 된다. 그렇다면 함수(Method)에 이 static을 붙이면 어떻게 될까? 

public class MathUtils {
    public static int add(int a, int b) {
        return a + b;
    }
}

 

이런식으로 되어있다면 MathUtils mathutils; mathutils.add()로 불러야 됐던 기존의 방식과 다르게, Mathuitls.add() 이렇게 부를수 있는게 가능해진다. static 블록을 만든다면 클래스가 로드될때 처음으로 실행을하게된다. 이가 Java에서 어떻게 할당되고 동작하는지는 JVM에 관한 공부가 필요하다고 생각된다.

Final

변수에 final을 사용하면 한번 초기화 한후에 변경할 수 없다. 단, HashMap같은 자료구조에 선언하면 값에 재할당이 불가능해지는것이고 put이나 insert같은 것은 가능하다. 메서드에 final을 사용하면 오버라이딩이 불가능하게된다. 클래스에 final을 사용하면 상속할 수 없는 클래스가 된다. 즉, final을 사용하면 코드의 안정성을 높일 수 있다.

 

Casting

casting이라고 말하면 우리는 보통 double형을 int형으로 바꾸는 명시적, 암시적 캐스팅등을 생각해 낼 것이다. 전에, 면접봤을때 c++의 경우 casting만 가지고 심도 있게 물어보려고 했던것같은데, 나는 캐스팅에 관해서 잘 알지 못했다;

 

우선 우리가 잘 아는 캐스팅의 문제점을 살펴보자. 생각하기 쉽게도 double에서 int로 변환하면 소수점이 날아간다. 이처럼, 데이터의 손실이 발생할 수 있다. 이러한 캐스팅이 변수들 끼리만 일어나는게 아니라 객체들 간에도 일어난다. Upcasting, Downcasting이라는 것들이다.

 

class Animal {}
class Dog extends Animal {}

Dog dog = new Dog();
Animal animal = dog; // 업 캐스팅: Dog -> Animal

Animal animal = new Dog();
Dog dog = (Dog) animal; // 다운 캐스팅: Animal -> Dog

 

업 캐스팅같은 경우에는 안전하고 자동으로 이루어지지만 다운캐스팅의 경우에는 기본타입들이 정보손실을 일으킨것처럼 예외를 일으킬 수 있다. 그리고 항상 명시적으로 이루어져야한다. 그렇다면 이러한 캐스팅을 왜 쓰는걸까?

 

이는 객체지향의 4가지 특징인 다형성에 관한내용이다.

class Animal {
    void sound() {
        System.out.println("Animal makes a sound");
    }
}

class Dog extends Animal {
    @Override
    void sound() {
        System.out.println("Dog barks");
    }

    void wagTail() {
        System.out.println("Dog wags tail");
    }
}

public class Main {
    public static void main(String[] args) {
        Animal animal = new Dog(); // 업캐스팅
        animal.sound(); // Dog의 오버라이딩된 메서드 호출

        // 다운캐스팅 후 추가적인 메서드 호출
        if (animal instanceof Dog) {
            Dog dog = (Dog) animal; // 다운캐스팅
            dog.wagTail(); // Dog의 메서드 호출
        }
    }
}

 

 

다운캐스팅을 사용한 예제인데, 아직까지 프로그래밍을 하면서 다운캐스팅이 필요한 상황을 겪지 못했다. 나중에 이런 상황을 만나게 되면 위 코드를 바꿔야 겠다.

 

참고)

https://chat.openai.com/

'프로그래밍 > 개발' 카테고리의 다른 글

spring에서 api 요청하기  (0) 2024.02.12
IO와 NIO  (0) 2024.02.06
나의 WAS 변경점, 한계 그리고 개선사항  (0) 2024.02.05
MVC패턴 왜 쓸까요  (0) 2024.02.01
if문을 줄이는 방향에 대한 고찰  (0) 2024.01.23