본문 바로가기
개발/자바

[JAVA] 자바의 인스턴스화, 생성자

by 루 프란체 2022. 4. 13.

인스턴스화, 생성자

간만에 네이버 블로그를 로그인해서 보다보니 옛날옛날에 갓 자바를 배우기 시작했을 때 작성했던 글이 보였다. 무려 2011. 9. 6. 12:51 작성글. 이 때는 나도 어렸는데 말이지. 하여튼 예전엔 뭔가를 새롭게 알게 되면 바로바로 이렇게 글도 써가면서 열심히 공부를 했던 기억이 있는데 이제 짬밥이 좀 찼다고 이런 것도 너무 귀찮다.

 

아무 것도 모르던 시절에 적은 글이라 내용은 틀릴 수 있다. 틀렸으면 고쳐야 하는데 사실 지금도 짬밥만 찼지, 아는 건 하나도 없는 쩌리라 고칠 수 있을 지 모르겠다. 그냥 예전에 적었던 글의 느낌을 살리기 위해 문법적인 에러를 제외하고는 그대로 옮긴다.

 


 

올해 6월 달에 처음 자바를 배우기 시작했을 때 생성자라는 것에 대해서 엄청 고민을 했었고 무슨 뜻인지 모르겠어서 엄청 헤맸던 기억이 있어서 그냥 글을 한번 남겨본다.

 

생성자라고 하니까 뭔가 엄청 있어보이지만 사실 그냥 메소드의 일종이라고 생각하면 된다. 기본적으로 생성자라고 하면 객체가 생성될 때 단 한 번 실행되는 메소드 라고 생각하면 되는데 이게 어떤 구조인지 생각해보면 어찌보면 당연하다고도 할 수 있겠다.

 

우리가 객체를 생성할 때는 new 라는 예약어를 사용하는데 이 예약어에 대해서도 엄청나게 고민을 했던 기억이 있다. 그게 아마 생성자를 찾아볼 때였으니 이제 생각해보면 난 참 쓰잘데기 없는 걸 고민한 것 같다.

 

new 라는 예약어는 그냥 객체를 새롭게 메모리에 올린다. 즉, 인스턴스화라고 생각하면 된다. 객체를 사용하기 위해서는 반드시 인스턴스화(static 클래스, 메소드인 경우는 제외)를 해야 하는데 이걸 쉽게 예로 들어보면 가방을 메모리라고 한다면 내가 밖에서 어떠한 물건을 사용하기 위해서는 집에서 나오기 전에 가방에 해당 물건을 넣어놓아야 한다. 아무리 내 물건이라고는 하지만 집에 있는 물건을 집 밖에서는 쓸 수 없으니까.

 

이 때 가방을 메모리라고 할 수 있겠고, 내가 사용자가 되는 것이고, 집이 해당 프로젝트가 되는 것이겠다. 물건이 클래스 및 객체겠고. 그리고 가방에 물건을 챙겨넣는 행위를 new 라고 보면 되는 것이다. 

 

예를 들어 핸드폰을 가방에 넣는 행위를 자바 문법으로 옮겨보자면 핸드폰 아이폰 = new 핸드폰(); 이 되는데 아이폰이라는 이름을 가진 핸드폰이라는 객체를 내가 사용하기 위해 가방에 챙겨넣은 것이다. 이것이 바로 인스턴스화이고 new 예약어의 용도인 것이다.

 

그런데, 또 다른 예를 들어보자. 우리가 변신합체로봇도 아닌데 걸어가야하니까 다리를 장착하고 나가야겠어. 이런 건 아니다. 항상 우리 몸에 달려있고 언제든 사용할 준비가 되어 있는 것이다. 즉, new 를 사용해 메모리에 올리지 않는다는 것이다. 이런 것이 위에서 말한 인스턴스화를 하지 않는 static 클래스 혹은 메소드인 것이다.

 

그럼 생성자가 무엇이냐. 위의 핸드폰 아이폰 = new 핸드폰(); 구문에서 바로 핸드폰(); 이것이 생성자를 호출하는 구문인 것이다. 그런데 자바를 처음 배우는 경우엔 따로 생성자를 생성하지 않고 클래스를 만들 것이다. 하지만 에러는 나지 않는다. 원래 클래스나 메소드가 없으면 빨간 밑줄이 그어지며 에러가 나는 것이 당연한 일인데.

 

그 매직은 바로 JVM 자바가상머신이 클래스를 실행할 때에 생성자가 하ㅡ나도 없으면 디폴트 생성자를 생성해 주기 때문이다. 하지만 디폴트 생성자의 경우에는 아무런 기능도 없다. 당연히 개발자가 아무 내용도 입력하지 않았으니까. 예를 들어 다음과 같은 클래스를 만들었다고 치자.

 

class Aquamiz {
 public void drink() {
   System.out.println("물을 마시자.");
 }
 public void main(String[] args) {
   Aquamiz am = new Aquamiz();
   am.drink();
 }
}

 

이런 클래스가 있다고 쳤을 때 코드 상에는 없지만 저 코드를 실행하면 자바가상머신이 친절하게도 디폴트 생성자를 낑겨넣어서 다음과 같은 코드로 실행이 된다는 것이다.

 

class Aquamiz {
 Aquamiz() {
 }
 public void drink() {
   System.out.println("물을 마시자.");
 }
 public void main(String[] args) {
   Aquamiz am = new Aquamiz();
   am.drink();
 }
}

 

그런데... 위의 설명 중에서도 말했지만 생성자는 메소드의 형태를 띄고 있지만 재사용이 불가능하다. 재사용이 불가능하다라고 하면 뭔가 좀 어감이 안 맞는것 같지만 더 쉽게 말해 다시 불러올 수 없다는 것이다.

 

즉, 처음에 말했듯이 객체가 생성될 때 단 한번만 실행이 가능한 것이다. 일반 메소드처럼 am.drink(); 이런식으로 사용을 할 수는 없다. 만약 다시 한 번 더 불러오고 싶다고 new Aquamiz(); 를 한번 더 하게 되면 두 개는 전혀 다른 객체가 되어버린다. 무슨 말이냐면 생성자를 한 번 더 불러오는 것이 아니라 또 하나의 객체를 인스턴스화 하는 것이 되는 것이다.

 

하지만 형식은 메소드의 형식을 그대로 따르고 있기 때문에 () 안에 파라미터 값을 넣을 수도 있고, 오버로딩을 통해 여러 개를 만들 수는 있다. 메소드와 다른 점이라고 한다면 낙타표기법을 따르지 않고 클래스의 이름을 그대로 가져다 쓴다는 것이다. Aquamiz(); 처럼.

 

생성자를 사용하는 것에 대한 이유를 짧막하게 설명해보자면 객체를 생성하면서 인자값을 넘겨줘서 초기값을 지정해줘야 할 때. 정도만 알아두면 되는데, 초기값을 지정해주는건 보통 멤버 변수에 한한다... 지역변수를 초기화해줘봤자 생성자에서 밖에 사용을 못하니까. 즉, 보통 아래와 같은 형식으로 사용한다.

 

class Aquamiz {
 private String msg;
 Aquamiz(String msg) {
  this.msg = msg;
 }
 public void drink() {
   System.out.println(msg);
 }
 public void main(String[] args) {
   Aquamiz am = new Aquamiz("물을 마시자");
   am.drink();
 }
}

 

이렇게 다른 클래스 또는 메소드에 있는 값을 가져다 쓰거나 할 때 주로 생성자를 이용한다. 흠... 뭔가 설명이 부족한것 같은데 뭘 더 써야할지 모르겠어서 여기서 마치겠다. 언젠가는 더 추가할 지도 모르지.

 

아, 중요한 게 빠졌는데 만약 코딩을 하면서 Aquamiz(String msg) 같은 생성자를 개발자가 직접 만들어준다면 JVM 께서는 Aquamiz(); 라는 디폴트 생성자를 만들지 않는다. 즉, Aquamiz am = new Aquamiz(); 는 사용할 수 없다. 왜 그러는 건가 궁금하다면 메소드의 법칙을 보면 알 거라고 생각한다.

 

그리고 왜 디폴트 생성자를 만들어주지 않느냐!! 라는 궁금증이 생긴다면 Ctrl+F 를 눌러 매직이라는 단어로 검색해보기 바란다. 끝.

 

아아, 또 중요한 것 한 가지. 생성자는 리턴형을 가질 수 없다. 끝.

댓글