Java/Java 문법

추상클래스의 객체 생성 (추상클래스 인스턴스) - 추상클래스를 사용하는 이유

민돌v 2022. 9. 19. 10:40

👏🏻 요약

더보기

객체생성을 하지 않아도 된다는 의도를 명확히 하기위해서 + 의도치않은 메모리 낭비를 막기위해

 

 

김영한님 강의를 보는 도중

상수 정보만을 가진 클래스를 만들었는데, 이 클래스가 상수 정보만을 담고있기때문에 객체생성을 막기위해 abstract class 로 선언을 하는 것을 보고 조금 의아해서 글을 남겨보고자 합니다.

 

김영한님 왈) 

  • 상수를 모아서 쓴거기 때문에 객체를 생성하면 안되겠죠? 그래서 abstract 로 객체 생성을 막아놓았습니다.
//상수 데이터만 담은 class - 객체 생성하지 않기위해 추상클래스로
public abstract class ConnectionConst {
    public static final String URL = "jdbc:h2:tcp://localhost/~/test";
    public static final String USERNAME = "sa";
    public static final String PASSWORD = "";
}

 

이 말이 도통 이해가 가지않아 추상클래스는 인스턴스가 생성되지않는가 생각해보았습니다.

 


 

 

💡 추상클래스의 인스턴스화

결론은 안된다!

 

 


 

👏🏻  왜 추상클래스를 인스턴스화 시키지 못할까

📌 추상클래스는 보통 동작이 정의되지않은 추상 메소드를 포함한 클래스를 말합니다.

추상클래스를 사용하면, 추상클래스를 상속받는 자식 클래스들은 반드시 추상메소들 재정의해야하고, 같은 이름을 가진, 다른동작을하는 메소드를 얻을 숭수 있는 객체제지향의 댜형성 특징을 가지는 클래스입니다.


본래 추상클래스는, 이처럼 동작이 정의되지않은 추상 메소드를 포함하고 있기 때문에 인스턴스를 생성할 수 없다고 합니다.

추상클래스는 먼저 상속을 통해 자식 클래스르 만들고, 만든 자식 클래스에서 추상 클래스으 ㅣ모든 추상 메소드를 오버라이딩하고 나서야 자식 클래스의 인스턴스를 생성할 수 있게 막아놓았다고 합니다.

 


추상 메소드의 사용 목적

자바에서 추상 메소드를 선언하여 사용하는 목적은 추상 메소드가 포함된 클래스를 상속받는 자식 클래스가 반드시 추상 메소드를 구현하도록 하기 위함입니다.

 


 

👏🏻  그렇다면 굳이 추상클래스를 상수를 담는 용도로 사용하는 이유는?

  • 단순하게 값이 변경되지 않을 이유라면, private 로 선언할 수 있는 방법이 있다고 생각했고
  • 아직까지도 잘 이해가 가지 않아서 질문을 찾아보니,,, 완전 똑같은 고민을 한사람이 있었슴다

 

안녕하세요. Kim Chae Eun님, 공식 서포터즈 David입니다.
abstract 키워드 자체에 '해당 클래스는 객체화 할 수 없음'의 의도가 명확히 드러나고 (객체화 할 수 없음에 대한) 구현이 포함되기 때문입니다.
private 생성자를 쓰더라도 reflection 기술을 사용하면 객체화 할 수 있게 됩니다.
감사합니다.

https://www.inflearn.com/questions/643569

 

🙌🏻 즉, 추상클래스를 사용하는 이유는 의도치않은 외부로부터 객체 생성을 막아 정보의 변경을 막고, 그 의도(객체화 x) 를 명확하게 하기 위함이다!

 

로 이해했습니다..ㅎㅎ

그저 빛영한,,

 

 

 

👏🏻 조금 더 완벽하게 상수 목적 추상클래스로 사용하기

  • 셍성자를 private로
  • 리플렉션으로 생성될 시 아예 exception 을 떨구도록
//상수 데이터만 담은 class - 객체 생성하지 않기위해 추상클래스로
public abstract class ConnectionConst {
    public static final String URL = "jdbc:h2:tcp://localhost/~/test";
    public static final String USERNAME = "sa";
    public static final String PASSWORD = "";
    
    //생성자를 private 로 정의해서 상속도 받지 못하도록 설정
    private ConnectionConst(){
    	// 리플렉션 으로 조작하지 못하게, 생성되면 아예 Exception 떨구기
        throw new NullPointerException("이거 아니야");
    }
}

 

 

 

 


📗 여담

1. Spring Util Class

최근 스프링에서 제공하는 Util 클래스도 대부분 abstract 로 제공이 된다길래 찾아봤더니 진짜 추상클래스로 모두 선언이 되어있었습니다.

추상클래스로 선언되었지만, 추상메소드는 없고 디폴트메서드만 있는 형태였습니다.

아마 같은 이유에서 spring 에서 제공하는 util 클래스의 의도치 않은 외부로 부터의 객체 생성 막아, 변경되는 것을 방지하자.. 라는 건가? 하는 개인적인 생각이 들었습니다.

 

 

2. 익명객체

  • 그렇다고 추상클래스를 무조건 객체화 시킬수 없다! 는 아닙니다.
  • 우리는 1회성 객체화를 시킬 수 있는 익명객체를 알고있기 때문에, 추상클래스도 익명객체를 사용하면 추상클래스도 인스턴스화를 시킬 수 있기는 합니다만...! 의도에는 맞지않는 사용방법인 것 같습니다.
@Test
@DisplayName("추상클래스는 인스턴스화 시키지 못해?")
void chu(){
    ConnectionConst connection = new ConnectionConst() {
        @Override
        public int hashCode() {
            return super.hashCode();
        }

        @Override
        public boolean equals(Object obj) {
            return super.equals(obj);
        }

        @Override
        protected Object clone() throws CloneNotSupportedException {
            return super.clone();
        }

        @Override
        public String toString() {
            return super.toString();
        }

        @Override
        protected void finalize() throws Throwable {
            super.finalize();
        }
    };
}

 

 

 

 

 


참고