생성자는 객체의 초기화를 위해 실행하는 메소드이다.
사람의 개인정보를 출력하는 클래스를 생성해보자.
-Person.java
public class Person {
String name;
String job;
int age;
char gender;
String bloodType;
}
-PersonApp.java
public class PersonApp {
public static void main(String[] args) {
Person p1=new Person(); //인스턴스화
p1.name="최승희";
p1.job="의사";
p1.gender='여';
p1.bloodType="AB";
p1.age=45;
Person p2=new Person();
p2.name="이미녀";
p2.job="골프선수";
p2.gender='여';
p2.bloodType="O";
p2.age=28;
Person p3=new Person();
p3.name="김미남";
p3.job="교수";
p3.gender='남';
p3.bloodType="AB";
p3.age=47;
System.out.println(p3.name);
System.out.println(p3.job);
System.out.println(p3.gender);
System.out.println(p3.bloodType);
System.out.println(p3.age);
이렇게 객체를 따로따로 불러내는 것은 번거로운 일이다.
따라서 변수를 초기화하여 인스턴스화 하기 위해 사용하는 것이 생성자이다.
기존에 class를 호출할 때, 굳이 객체를 초기화하지 않아도 호출이 가능하다.
왜냐하면 java언어는 컴파일 시에 컴파일러가 객체를 스스로 초기화 하는데, 이를 디폴트 생성자라고 한다.
만약에 임의적으로 개발자가 생성자를 생성할 시에는 컴파일러는 디폴트 생성자를 만들지 않는다.
또한 임의로 생성하는 생성자는 또 다른 특징이 있는데,
public Person() {
}
public Person(String name, String job, int age, char gender, String bloodType) {
this.name = name;
this.job = job;
this.age = age;
this.gender = gender;
this.bloodType = bloodType;
}
보다시피 같은 이름으로 여러가지 생성을 할 수 있는데, 이것을 생성자 오버로딩이라고 한다.
이렇게 만들어진 생성자는 어떻게 쓸까?
Person p4=new Person(
"김자바",
"학생",
22,
'남',
"A"
);
System.out.println(p4.name);
System.out.println(p4.job);
System.out.println(p4.age);
System.out.println(p4.gender);
System.out.println(p4.bloodType);
다음과 같이 매서드를 호출할 때, 앞서 Person에서 호출한 생성자를 바탕으로 내부의 매개변수가 생성자 코드 내부로 들어가게 된다. 따라서 클래스와 변수를 일일히 지정하지 않아도 값을 호출할 수 있다.
여기서 class 생성자 내부에 보면 this가 붙어있는 것을 볼 수 있다.
래퍼런스 this의 역할은 뭘까?
class AirPlane{
String name;
String color;
public AirPlane(String name, String color) {
this.name = name;
this.color = color;
}
}
public class ThisTestEx01 {
public static void main(String[] args) {
AirPlane a1=new AirPlane("제트기", "흰색");
AirPlane a2=new AirPlane("항공기", "노란색");
}
}
다음과 같은 코드가 있다.
매서드 호출이 두 군데서 일어났다. 각자 매서드는 다른 heap 공간에 떠있다. 이 때 this의 역할은 매서드가 호출되었을 때, 매서드가 호출되어있던 공간(객체)에 접근함으로써 heap 내부에 지정된 생성자의 값을 넣는다. 즉, a1 매서드가 호출될 때는 a1 heap 공간에 제트기, 흰색의 데이터가 들어가고 a2 heap 공간에 항공기, 노란색의 데이터가 들어간다.
따라서 바인딩 된 공간이 호출될 때마다 달라지기 때문에 this 레퍼런스는 동적이다.
토끼 프로그램을 하나 만들어보자.
class Rabbit {
String name;
int power;
public Rabbit(String name, int power) {
this.name = name;
this.power = power;
}
void drink() {
//100이 넘어가면 동작하지 않도록
power++;
public class RabbitApp {
public static void main(String[] args) {
Rabbit r1=new Rabbit("토끼", 20); //100이 맥스
while(true) {
r1.drink();
System.out.println(r1.power());
if(r1.getpower()>=100) {
break;
}
}
다음과 같은 프로그램은 무엇이 문제가 있을까?
아무리 while문으로 제어한다고 해도, while문 이후에 power=250; 따위로 지정해버리면 프로그램을 설계한 의미가 사라진다.
그렇기 때문에, main에서 제어할 수 없도록, 변수를 지정한 클래스에서 조치를 취해 다른 클래스에서 변수를 제어할 수 없도록 한다.
따라서 접근 지정을 걸어야한다.
- public : 모든 패키지 내에서 접근 가능
- private : 클래스 내부에서만 접근 가능
- (설정하지 않음) : 같은 패키지 내에서만 접근 가능
따라서, RabbitApp class 에서 Rabbit class 내부의 변수에 접근하지 못하도록, 변수에게 접근 지정자를 건다.
class Rabbit {
private String name;
private int power;
다음과 같이 변수에 지정자를 걸면 외부 클래스에서 접근이 불가하게 되는데, 이를 변수의 은닉화라고 한다.
이 때, 문제가 생기는데,
public class RabbitApp {
public static void main(String[] args) {
Rabbit r1=new Rabbit("토끼", 20); //100이 맥스
while(true) {
r1.drink();
System.out.println(r1.power());
마지막줄 출력문에서 power을 인식하지 못하게 된다. Rabbit 클래스 외부에 있어 power이라는 변수에 접근할 수 없기 때문이다. 이 때는 Rabbit 클래스 내부에 return등 변수를 보여줄 수 있는 매서드를 따로 만드는데, 이것을 간접접근이라고 한다.
따라서, 변수를 간접접근하게 한 토끼 프로그램의 최종 완성본은
class Rabbit {
private String name;
private int power;
public Rabbit(String name, int power) {
this.name = name;
this.power = power;
}
boolean drink() {
//100이 넘어가면 동작하지 않도록
if(power==100) {
return false;
}
power++;
return true;
}
public int getpower() {
return power;
}
void setName(String name) {
this.name=name;
}
public String getName() {
return name;
}
}
public class RabbitApp {
public static void main(String[] args) {
Rabbit r1=new Rabbit("토끼", 20); //100이 맥스
while(r1.drink()) {}
System.out.println(r1.getpower());
r1.setName("산토끼");
System.out.println(r1.getName());
}
다음과 같다.
이처럼 main에서 직접 제어하는 것이 아닌, 인스턴스화 된 "토끼"가 drink 라는 매서드를 통해 "행동"을 하고 그로 인해 변화가 일어나는 일련의 프로그램을 객체지향 프로그램이라고 한다.
while문도 변화가 일어난 것이 보인다. 기존 main에서 제어하던 drink의 한계점을 drink 매서드가 들고간 것이 보인다. 이렇게 drink가 스스로 행위를 제어하는 것을 행위를 '책임' 진다고 한다. 이렇게 매서드가 행위를 책임지게 되면 이후 프로그램의 유지보수가 용이하게 된다.
'JAVA' 카테고리의 다른 글
8. 상속 (0) | 2020.03.30 |
---|---|
7. 오버로딩 (0) | 2020.03.27 |
클래스, 객체, 인스턴스 (0) | 2020.03.27 |
JAVA 실습 6. while, break, continue를 이용한 난수맞추기 게임 만들기 (0) | 2020.03.24 |
JAVA 실습 4. for문을 이용해 배열을 뒤집어서 출력하기 (0) | 2020.03.24 |