[JAVA] final, static, abstract, synchronized

2019. 9. 30. 17:35 JAVA/Java

final, static, abstract, synchronized


변수나 함수 선언시, 해당 변수나 함수 활용 방법에 대한 modifier를 설정할 수 있다.


 modifier

 구분

설명 

final 

 변수 선언

 변수를 상수로 이용하는 경우 사용한다. 

 함수 선언

 오버라이딩이 불가능한 메쏘드를 정의할 때 이용한다.

static 

 변수 선언

 클래스에 소속된 클래스 변수를 의미한다. 클래스 생성시 만들어진다.

 함수 선언

 abstract

함수 선언

 추상 메쏘드를 의미한다. 하위 클래스에 의해 구현된다.

 synchronized

함수 선언

 thread의 동기화를 의한 메쏘드이다. 


final 은 변수를 선언할 때와 함수를 선언할 때 쓰임새가 다르다.



-  상수 : final (변수 선언시)


final을 사용하여 변수를 선언하면 할당된 값을 변화시킬 수 없다는 의미를 가진다. 즉, final이 붙은 변수는 단 한 번 초기화 할 수 있으며 그 이후에는 값을 변경할 수 없다.


enum 객체의 경우 final 변수들을 열거하여 새로운 클래스를 생성하여, 사용할 수 있는 값을 제한하는데 사용한다.


[JAVA] 열거타입 enum



- final (함수 선언시)


클래스에서 함수 선언시 final 을 선언하면, 상속 받은 하위 클래스에서 해당 함수를 오버라이딩 할 수 없다. 


아래와 같이 오버라이딩을 시도하면 컴파일 에러가 발생한다.


 class E1{

     

     final void test(){

            .....

     }
}
        
class E2 extends E1{
            
    void test(){
         ....       
    }
}               


E1을 상속받은 E2의 test() 함수는 E1에서의 final 로 인하여 오버라이딩 할 수 없다.



- 클래스 변수 : static


static이 붙은 변수를 클래스 변수, 그렇지 않은 변수를 객체 변수라고 한다. 객체 변수는 클래스로부터 객체가 생성될 때마다 각 객체의 변수들이 생성되지만, 클래스 변수는 그 클래스로부터 생성된 모든 객체들이 하나의 클래스 변수를 공유한다. 


클래스 변수는 객체가 생성될 때 메모리 영역을 할당하는 것이 아니고 클래스가 로딩되는 과정에서 메모리에 한번만 할당되는 멤버이다. 그러므로 클래스 변수는 하나의 클래스로부터 생성된 객체들 사이의 통신이나 객체들 사이의 공통되는 속성을 표현하는 데 사용될 수 있다. 


클래스 변수는 일반적으로 객체 참조 변수 이름으로 접근하기보다는 클래스 이름을 통해서 접근한다.


 

class Test{
      static final int a = 10;
      int b = 20;
}

public static void main(String[] args) {
   
      System.out.println(Test.a);
}


위에 처럼 Test 객체를 굳이 선언하지 않고 Test.a 와 같이 클래스 이름을 통해 접근할 수 있다.


static을 사용할 때는 조심해야 한다. 한번만 메모리에 올린 후 사용하기에 메모리 효율에는 좋지만, 모든 thread에서 공유되기 때문에 데이터 클래스 같이 고유의 값을 가지고 있어야 할때는 static 사용을 조심해야 한다.



- abstract


abstract는 클래스를 선언할 때 사용하는 modifier이다. 클래스 선언부에 abstract를 사용하면 추상 클래스를 선언하고 있따는 의미가 되며, 함수를 선언할 때 사용하면 추상 메소드를 만들고 있다는 의미가 된다.


추상 클래스는 추상적인 내용만 정의하고 있는 클래스로 구체적인 내용은 하위 클래스에서 구현되도록 해놓은 클래스이다. 추상 클래스가 반드시 추상 메서드를 가지고 있어야 되는다는 제약이 있는 것은 아니지만 일반적으로 하나 이상의 추상 메서드를 가지고 있다.


 

abstract class Shape{
   public abstract void draw();
       .....
}

class Circle extends Shape{
   public void draw(){
       .....
   }
}


Shape 이라는 추상 클래스를 선언하고, 그 안에 draw() 메소드를 추상 메소드로 선언했다.

이 Shape 을 상속받은 Circle 클래스는 추상 메소드인 draw() 도 구현을 해야 한다.

Circle, Rectangle, Triangle 같은 도형 클래스를 선언할 때, 공통 사항을 구현해야 될 때 Shape 이라는 추상 클래스를 만들고 Shape을 상속받으면, 공통된 구현을 할 수 있다.


물론 추상 클래스에 공통 변수나 함수를 선언할 수도 있다.



- synchronized (동기화)


synchronized 는 동기화로 여러 thread에 의해 특정 객체의 메소드들이 동시에 호출되는 것에 대해 잠금(lock)을 설정하는 기능을 가지고 있다.


예를 들어, 특정 객체의 message 라는 변수에,  storeMessage()가 호출되어 메시지가 저장되는 동안 retrieveMessage()가 호출되거나 또는 반대 상황이 발생할 경우, 전달되는 중에 있는 메시지를 가져가거나, 메시지를 가져가고 있는 중에 다른 메시지를 전달하는 경우가 생긴다. 이런 상황이 일어나지 않게 하기 위해 synchronized 를 사용하여 동기화를 해준다.


즉, synchronized가 설정된 메소드들은 동시에 호출 될 수 없다. synchronized가 호출된 메소드들 중 하나가 호출되면 그 객체 정보에 대해 잠금(lock)을 설정해서 이 호출이 완료될 때까지 유지된다.


 

class Mailbox{
   
   private String message;

   public synchronized void storeMessage(String message){
       this.message=message;
   }

   public synchronized String retrieveMessage(){
       return message;
   }
}


위와 같이 synchronized 를 함수에 modifier로 선정해 줌으로써, 해당 함수에 접근할 때 동기화를 시킨다.



출처: https://hyeonstorage.tistory.com/177?category=557602 [개발이 하고 싶어요]