되자!백엔드개발자

JAVA(자바) - Class와 객체/생성자/this.와 this()/객체배열 본문

개발공부/JAVA

JAVA(자바) - Class와 객체/생성자/this.와 this()/객체배열

HyunJng 2022. 7. 24. 14:53

클래스와 객체


클래스는 객체를 만들어내기 위한 설계도, 객체는 이 설계도 대로 생성된 실체이다.

*** 객체란 속성과 행동을 가져 다른 것과 구별될 수 있는 것을 뜻한다. 자세한건 앞에 글 참고 ***

//클래스 설계도의 역할을 한다.
public class Circle{
	int radius; //필드
	
	public Circle(int radius) { //생성자, 뒤에 설명 나옴
		this.radius = radius;
	}
	public double getArea() { // 메소드
		return 3.14 * radius * radius;
	}
}

위는 원에 관해만든 class이다. 반지름(radius)이라는 속성을 가지고 있고 넓이를 구하는 getArea()라는 메소드를 가지고 있다.

//앞으로 이 설계도대로 만든 객체를 여러개 생성이 가능하다.
Circle c1 = new Circle();
Circle c2 = new Circle();

위는 Circle이라는 설계도대로 만든 c1, c2객체이다 이 내부에는 각자 radius와 getArea()가 고유하게 존재하고 있다.

 

어떤 사람은 객체를 인스턴스라고 부르기도 하고 오브젝트라고 부르기도 한다. 용어마다 부르는 방법이 여러가지라서 여러 블로그 글을 참고하려면 헷갈리지 않도록 다 익혀두는 편이 좋다.

 


레퍼런스변수와 객체생성


Circle c1; //레퍼런스 변수, 아직 객체가 아니다.
c1 = new Circle(); //객체 생성

Circle c2 = new Circle();

자바에선 레퍼런스변수를 먼저 생성하고 반드시 new연산자를 이용하여 Circle타입 크기의 메모리를 할당하고 Circle()의 생성자 코드를 실행하여 객체를 생성한다. 

 

+) C++에서는 이것만으로도 객체가 생성하고 c1자체가 객체이다. 

//C++에서 객체 생성
Circle c1;

 

 

생성자(Constructor)


클래스의 이름과 동일한 메소드를 특별히 생성자라고 한다. 객체가 생성될 때 필드를 초기화를 하거나 생성 당시 꼭 필요한 작업을 해두기 위해 자동으로 실행된다. 

  • 반드시 class와 생성자의 이름이 동일해야한다.
class Book{
	String title, author;
    
    public Book(){	// 생성자
    	title = "NULL";
        author = "작자 미상";
    }    
}
  • 함수이지만 return 되는 값이 없어야 한다 - 그러나 리턴타입도 void가 되서는 안된다.
class Book{
	String title, author;
    
    public void Book(){	}    //컴파일 오류. 리턴타입을 설정해선 안된다.
}
  • 여러개 오버로딩 할 수 있다.
class Book{
	String title, author;
    
    public Book(){	
    	title = "NULL";
        author = "작자 미상";
    }
    
    public Book(String t, String a){ //생성자 오버로딩
    	title = t;
        author = a;
    }
}
  • new를 통해 객체가 생성될 때 단 한번만 호출된다.
Book b1 = new Book(); //생성자 호출

b1.Book("어린왕자", "생텍쥐"); //컴파일 오류, 생성자는 객체 생성 외에는 호출 불가능
  • 생성자를 따로 작성하지 않으면 기본생성자가 호출된다.
    생성자가 없는 클래스는 없다. 내가 작성하지 않으면 컴파일러가 기본 생성자를 자동으로 생성한다. 만약 내가 하나라도 생성자를 작성하였다면 컴파일러는 기본 생성자를 삽입해주지 않는다.

 

레퍼런스 변수 this


this()와 비슷하지만 기능이 완전 다르다. 꼭 명확하게 익혀둬야한다.

this는 현재 실행되고 있는 메소드가 속한 객체 자신을 가리키는 레퍼런스이다. 이렇게 설명하면 너무 어렵게 느껴져서 예시를 들어보겠다.

Circle c1 = new Circle(2); // 1. 생성자를 호출

내가 객체를 만들기 위해 생성자를 생성했다. 이것이 현재 실행되고 있는 메소드이고 인자로 정수값  2가 전달되었다.

생성자가 호출되었으니 Circle 클래스로 가보자

public class Circle{
	int radius; 	// << 좌변 this.radius가 가리키는 것
	
    // 2. 아래 실행
	public Circle(int radius) { // <<우변 radius가 가리키고 있는 것
		this.radius = radius; 	
	}
}

생성자가 실행되는데 radius변수가 두개가 있다.

하나는 생성자에 전달된 매개변수인 radius와 다른 하나는 멤버변수(필드) radius이다. 이 둘을 구분하기 위해 this가 필요하다. this는 객체 자신을 가리키는 레퍼런스 이므로 좌변의 this.radius는 멤버변수 필드인 radius를 가리킨다. 반면 우변은 매개변수로 전달된 radius로 정수값 2가 내포된 변수이다.

 

그렇다면 굳이 this를 쓰는 것이 아니라 인자의 radius를 다른 이름으로 설정하면 더 편하지 않을까?

앞에 글에서 말했듯 변수명은 항상 그 용도를 나타내는 적합한 이름을 붙이는 것이 중요하다. 그러므로 같은 매개변수 값도 명확하게 radius로 표현하는 편이 좋으며 이렇게 매개변수와 필드변수를 구별하기 위해 레퍼런스변수 this가 필요한 것이다.

 

🚫주의.  this. 는 객체를 가리키므로 static변수를 가리키도록 하면 안된다.

 

생성자호출 this()


this()는 생성자가 다른 생성자를 호출할 때 사용하는 메소드이다. 이것도 예시를 들어보자.

// this()를 사용하기 전
class Book{
	String title, author;
    
    public Book(){	
    	title = "NULL";
        author = "작자 미상";
    }
    
    public Book(String t, String a){
    	title = t;
        author = a;
    }
}

앞에서 사용한 Book 클래스이다. 여기선 생성자가 두개이고 둘 다 멤버변수인 title과 author을 설정한다.

이 것을 this()를 사용하여 더 간편하게 작성할 수 있다.

// this()를 사용한 후 
class Book{
	String title, author;
    
    public Book(){	
    	this("NULL", "작자 미상"); //아래 String 매개변수가 2개인 생성자가 호출된다.
    }
    
    public Book(String t, String a){
    	title = t;
        author = a;
    }
}

즉 내가 매개변수가 없는 객체를 생성한다면

Book b1 = new Book();

먼저 아래의 생성자가 호출되고

    public Book(){	
    	this("NULL", "작자 미상");
    }

this()에 의해 아래 생성자가 다시 호출된다.

    public Book(String t, String a){ ... } // t = "NULL", a = "작자 미상" 전달

 

그렇다면 this()를 왜 사용할까?

유효성을 확인하는 코드를 생성자마다 다 써주는건 낭비기 때문이다.

하나만 만들어두고 나머지 생성자에 this()로 연결해주면 코드 하나로 여러개를 유효검사할 수 있어 코드가 간결해진다.

 

this()사용시 주의할 점이 있다.

  • 반드시 생성자 내부에서만 사용할 수 있다.
  • 반드시 같은 클래스 내의 생성자 사이에서만 사용할 수 있다.
  • 반드시 생성자의 첫번째 문장으로 사용해야한다.

 

객체 배열


C/C++과 달라서 작성해본다. 자바에서 객체배열은 객체에 대한 레퍼런스를 원소로 갖는 배열이다.

    Circle[] arr; // 배열에 대한 레퍼런스(안의 값도 레퍼런스)
    arr = new Circle[5]; // 5개의 레퍼런스 배열

    for(int i = 0; i<5; i++) {
        arr[i] = new Circle(i); // 각 레퍼런스안에 객체 생성
        }

즉 변수 arr 의 내부도 레퍼런스를 담는 변수이므로 그 안에 각각 객체를 생성하여 하나씩 대입해야한다.

그림으로 표현하면 아래와 같다. C++에서는 배열 내부 자체가 객체라는 점에서 차이가 있다.