프로그래밍/TIL(국비과정)

TIL #12 - 클래스, 생성자

양아무개 2020. 4. 10. 17:53

 

# Setter / getter 

필드를 private으로 선언할 경우, 

해당 필드는 그 필드가 들어있는 class 내부에서만 사용할 수 있다. 

그렇기 때문에 다른 class에서도 사용하려면 setter/getter 메소드를 이용해서 값을 불러오고 내보낸다. 

 

# 사칙연산 setter/getter

사칙연산을 setter/ getter를 이용해 해본다.

아래의 코드에는 필드가 들어있는 클래스 하나, 메인 메소드가 들어있는 클래스 하나가 각각 들어 있다 

먼저 필드가 들어 있는 ComputeTest 클래스이다. 

class ComputeTest{
	private int x, y;
	private int sum; // 합
	private int sub; //차
	private int mul; //곱
	private double div; // 나누기

x와 y에 대해 합, 차 , 곱, 나누기를 수행할 것이다. 

먼저 setter 메소드이다. 

setter 메소드는 아래의 main 메소드에서 받은 값들을 가져와 필드 값에 데이터를 전달한다. 

public void setX(int x){
		this.x = x;
	}
public void setY(int y){
		this.y = y;
	}
	
public void calc (){
		sum = x + y;
		sub = x - y;
		mul = x * y;
		div = (double)x / y;

	}

setX를 통해서 x값, setY를 통해 y 값을 각각 가져온다. 

여기서 this.x = x; 코드를 보면 같은 x가 2개나 있다. 

필드의 x와 해당 메서드의 매개변수 x 둘다 같은 x이므로 구분하기 위해 this를 붙여준다. 

this.x는 필드의 x를 말하며 아무 표시가 없는 x는 자신의 매개변수 x이다. 

여하튼 이 코드로 자신이 main 메서드로부터 가져온 x값을 필드에게 보내주는 것이다. 

 

값을 가져왔으면 이젠 계산을 위해 보내줘야한다. 

이때 쓰는 메서드가 getter 메서드이다. 

	// get
	public int getX(){
		return x; 
	}

	public int getY(){
		return y;
	}

	public int getSum(){
		return sum;
	}
	
	public int getSub(){
		return sub;
	}

	public int getMul(){
		return mul;
	}
	
	public String getDiv(){
		return String.format("%.3f",div);
	}

}

x와 y를 각각 리턴해주고, 합 / 뺌 / 곱/ 나눔 모두 리턴해준다. 

getter의 경우엔 이미 setter에서 값을 가져왔기 때문에 매개변수가 필요없다. 

또한 계산의 경우에도 위의 calc 메서드를 통해 끝냈고 그 값들 역시 필드로 보냈기 때문에 

그 값을 다시 보내주기만 하면(return) getter 메서드의 임무 완료이다. 

 

 다음은 메인 메서드가 들어있는 클래스 ComputeMain이다. 

여기서 총 3번 값을 받을 것이기 객체 배열을 선언한다. 

class ComputeMain{
	public static void main(String[] args){
		ComputeTest[] ct = new ComputeTest[3];
		
		ct[0] = new ComputeTest();
		ct[1] = new ComputeTest();
		ct[2] = new ComputeTest();
		

각 배열에 객체를 생성해주었다. 

(클래스의 주소는 곧 객체이다. 각 배열에는 클래스의 주소들이 들어가는 것이다)

 

이제 각 객체들에게 값을 할당해준다. 

	ct[0].setX(320);
	ct[0].setY(126);

	ct[1].setX(126);
	ct[1].setY(89);
	
	ct[2].setX(257);
	ct[2].setY(126);

값을 할당해줄 때는 setter 메소드에게 값을 준다. 

main 메서드가 들어 있는 ComputeMain 클래스는 직접 ComputeTest에 있는 필드들에 접근할 수 없기 때문에 setter를 거치는 것이다. 

setter에서 값을 받으면 그 값들을 필드에게 전달해주고 값을 가지고 있는 필드는 getter 메서드를 통해서 return 된다. 

 

그럼 이 클래스에서 값을 출력할 때는 반대로 getter 메서드를 불러서 출력하면 된다. 

		// 출력 및 계산
		System.out.println("X\tY\tSUM\tSUB\tMUL\tDIV");
		for(ComputeTest a : ct){
			
			a.calc();

			
			System.out.println(a.getX()+"\t"+a.getY()+"\t"+a.getSum()+"\t"+a.getSub()+"\t"+a.getMul()+"\t"+a.getDiv());

		}

		
	}
}

 

 

# This 키워드 

this 키워드이다. 

this 키워드는 위에서도 확인했듯이 클래스의 필드값과 매개변수의 값이 같을 경우 

어떤 것이 클래스의 필드값인지 매개변수인지 표시해주기 위해서 사용한다. 

(또 다른 경우가 있는 듯하지만 오늘은 이것만)

아래의 코드는 역시 필드가 들어있는 클래스, 메인메서드가 들어있는 클래스 이다. 

먼저 필드가 들어있는 클래스이다.

class ThisTest{
	private int a; 
	
	// set
	public void setA(int a){
		this.a = a; // a 자신 
	}

	// get
	public static getA(){
		return a; // 필드의 a (this.a가 생략된 형태)
	}
}

필드에 a가 있다. 

이 a의 값을 main 메서드에서 setA메서드로 가져왔다.

그런데 setA 메서드의 매개변수 역시 a이다. 

이런 경우 어떤 것이 누구의 a 인지 모르기 때문에 

ThisTest 클래스의 a를 this.a 라고 표현해준다. 

아무런 표시가 없는 a는 setA 메서드가 가지고 있는 매개변수 a이다. 

 

getter 메소드의 return a; 의 a도 사실은 this.a이지만 this를 생략한 형태이다. 

나머지 메인 메서드가 있는 ThisMain 클래스이다. 

class ThisMain{
	public static void main(String[] args){
		
		ThisTest aa = new ThisTest();
		System.out.println("aa = " + aa);
		aa.setA(10);

	}
}

 

# 생성자 

생성자는 초기화를 위한 기능이다. 

초기화는 필드를 초기화하거나, 메소드를 호출해서 객체를 사용할 준비가 되게 만들어놓는 것이다. 

생성자를 이용해서 세사람의 이름과 나이를 입출력해보자. 

 

아래의 코드는 필드와 생성자가 들어 있는 ConstructorTest 클래스와 메인 메서드가 들어있는 ConstructorMain 클래스이다. 

먼저 ConstructorTest 클래스이다.

우리는 사람의 이름과 나이만 입출력할 것이기 때문에 필드는 아래와 같다. 

class ConstructorTest{
	private String name; 
	private int age;

 그런 후 생성자를 만들어준다. 

 

먼저 default 생성자이다. 

	public ConstructorTest(){}

default 생성자는 모든 클래스에 반드시 존재하며 하나 이상 가질 수 있다. 

만약 클래스 내부에 생성자 선언을 생략하면 컴파일러는 중괄호 {} 안에 아무 내용 없는 기본생성자(default 생성자)를 바이트 코드에 자동으로 추가 시킨다. 

생성자도 오버로딩을 시킬 수 있으므로 위의 기본 생상자를 오버로드해 이름과 나이를 초기화하는 생성자를 만들어준다. 

	public ConstructorTest(String name){
		this.name = name; 

	}

먼저 이름을 받는 생성자다. 

이 생성자는 setter와 같은 기능을 한다. main에서 가져온 name의 값을 필드로 보내준다. 

하지만 setter와는 다르게 단 한번만 가져온다. 

public ConstructorTest(int age){
		this.age = age; 

	}

위의 생성자는 똑같이 나이를 가져왔다. 

위의 세 생성자는 오버로딩한 것이다. 

 

생성자는 강제호출이 불가능하며 클래스를 new 선언해서 만들었을 때만 부를 수 있지만 

생성자끼리 call을 할 수 있다는 특징이 있다. 

예를 들어 age 값을 가져오는 메서드에서 기본생성자를 부를 수 있다는 것이다. 

하지만 다른 생성자를 부를 때는 해당 생성자를 가장 첫번째 줄에 위치시켜야한다. 

 

각 값들을 불러왔으니 이제 getter로 내보낸다 

	public String getName(){
		return name;
	}
	public int getAge(){
		return age;
	}
}
class ConstructorMain{
	public static void main(String[] args){
		
		// 생성자 부르기, 빈 매개변수를 보고 default 생성자로 갔다 온다  
		ConstructorTest aa = new ConstructorTest();
		System.out.println("이름 = " + aa.getName() + "  나이 = " + aa.getAge());

		ConstructorTest bb= new ConstructorTest("홍길동");
		System.out.println("이름 =" + bb.getName() + "   나이 = " + bb.getAge());
		
		ConstructorTest cc = new ConstructorTest(25);
		System.out.println("이름 =" + cc.getName() + "   나이 = " + cc.getAge());

	}
}

 

생성자가 호출되고 왔다갔다하는 흐름을 잘 파악해야한다..

아래의 코드를 보자 

class Constructor{
	private String name;
	private int age;
	
	// 기본생성자
	public Constructor() {}
	
	public Constructor(String name) {
		this();
		this.name = name;
	}
	
	public Constructor(int age) {
		this("김");
		this.age = age;
	}
}
public class ConstructorMain {

	public static void main(String[] args) {
		Constructor aa = new Constructor(25);

	}

}

 

1.main 메서드에서 객체에 25라는 값을 주었다. 

2. 25는 int형이기 때문에 매개변수 int형을 받고 있는 세번째 생성자로 간다. 

3. 생성자 내부에서 this("김"); 이라는 String 형 생성자호출로 인해 두번째 생성자로 간다. 

4. 두번째 생성자에서 this()를 통해 기본생성자를 호출했기 때문에 첫번째의 기본생성자로 간다. 

5. 기본생성자에서 다시 밑으로 내려와 두번째 생성자로 향해 name값을 필드에 준다. 

6. 다시 밑으로 내려와 세번째 생성자로 도달해 age값을 필드에 준다. 

7. 그런 후 다시 25로 돌아온다.

 

이런 흐름으로 생성자는 서로 호출할 수 있고 이동한다.