2021. 1. 23. 14:55ㆍDev.Program/Java & Spring
< 생성자(Constructor) >
- 생성자 메서드 라고도 함
- 객체가 생성될 때 호출되어 멤버변수 초기화나 객체 생성 시 특정 작업을 수행
- 메서드 구조와 유사하나, 리턴타입이 없고, 이름을 클래스명과 동일하게 정의
- 메서드와 마찬가지로 파라미터가 없을 수도 있고, 파라미터가 있을 수도 있다.
- 생성자를 정의하지 않으면, 컴파일러에 의해 기본 생성자가 자동으로 생성됨
- ⇒ 하나라도 정의할 경우, 기본 생성자가 자동으로 생성되지 않는다!
- (기본 생성자 : 파라미터가 없고, 구현부의 코드가 아무것도 없음)
- ⇒ 생성자는 반드시 최소한 한 개 이상이 존재해야함(자동 생성 기본 생성자 포함)
< 생성자 정의 기본 문법 >
[제한자] 클래스명([파라미터...]) {
// 객체 생성 시 수행할 작업들...
}
- 생성자 만들 때 class 명이랑 한 글자라도 다르면 바로 오류남! (일반 메서드로 취급 됨)
- ctrl + space : 기본으로 생성해줌
- 밑에 부분(생성자)을 주석처리해도 오류 안남. (자동으로 생성 - p203)
- (콘솔창을 보면) 생성자 호출을 먼저 한 뒤, 호출을 실행함
- 생성자를 호출하여 "홍길동" 문자열을 전달한 후 종료되면 다음 문장이 실행됨
- 이제 자동으로 만들어 주지 않음! (비어있는 놈은 없기 때문)
- 생성자 내에서 멤버변수에 저장될 기본값을 설정할 수 있다!
- 객체를 만들자마자 이름이 홍길동으로 기본설정됨!
- DefaultPerson()은 아무값을 주지 않았기 때문에 참조형의 기본값인 null 이 나옴
- DefaultPerson() 과 DefaultPerson2() 둘 의 차이 잘 보기!
> 파라미터로 String, int, boolean 타입 데이터를 전달받아
멤버변수 name, age, isHungry 초기화하는 생성자 정의
- String, int, boolean 순서대로 적기
> 생성자도 메서드와 똑같기 때문에 생성자도 생성자오버로딩이 똑같이 적용!
> 멤버 변수에 저장할 데이터 3개를 파라미터로 전달받아 초기화하는 생성자 정의
- 보통 getter / setter 위에 만듭니다!
- getter / setter 는 Alt + Shift + S → R 로 자동생성하기
======== Ex3.java 만들기 (생성자 오버로딩)
< 생성자 오버로딩 >
- 생성자 호출 시 다양한 형태의 파라미터 전달을 위함
- 메서드 오버로딩과 방법 동일
> 기본 생성자 정의 - 멤버변수 name 을 "홍길동" 으로 초기화
> 파라미터 생성자 정의 - 문자열을 전달받아 멤버변수 name 을 초기화
class Person3 {
String name;
public Person3() {
name = "홍길동";
}
public Person3(String s) {
name = s;
}
}
- 호출
- Person3 p = new Person3();
System.out.println(p.name);
- Person3 p2 = new Person3("홍길동2");
System.out.println(p2.name);
- 이름이 같은데 오류 안남 ⇒ 오버로딩이 잘 되었다!
======== Test3.java 만들기
문제 )
Account3() 생성자 정의
Account3(String) 생성자 정의 - 계좌번호(accountNo) 초기화
Account3(String, String) 생성자 정의 - 계좌번호, 예금주명 초기화
Account3(String, String, int) 생성자 정의 - 계좌번호, 예금주명, 현재잔고 초기화
Getter/Setter 정의
public class Test3 {
public static void main(String[] args) {
Account3 a = new Account3();
a.showAccountInfo();
Account3 a2 = new Account3("111-1111-111");
a2.showAccountInfo();
Account3 a3 = new Account3("111-1111-111", "유라");
a3.showAccountInfo();
Account3 a4 = new Account3("111-1111-111", "유라", 500000);
a4.showAccountInfo();
}
}
class Account3 {
private String accountNo;
private String ownerName;
private int balance;
// Account3() 생성자 정의
public Account3() {
System.out.println("Account3() 생성자 호출됨!");
}
// Account3(String) 생성자 정의 - 계좌번호(accountNo) 초기화
public Account3(String s) {
System.out.println("Account3(String) 생성자 호출됨!");
accountNo = s;
}
// Account3(String, String) 생성자 정의 - 계좌번호, 예금주명 초기화
public Account3(String s, String s2) {
System.out.println("Account3(String, String) 생성자 호출됨!");
accountNo = s;
ownerName = s2;
}
// Account3(String, String, int) 생성자 정의 - 계좌번호, 예금주명, 현재잔고 초기화
public Account3(String s, String s2, int i) {
System.out.println("Account3(String, String, int) 생성자 호출됨!");
accountNo = s;
ownerName = s2;
balance = i;
}
// Getter/Setter 정의
public String getAccountNo() {
return accountNo;
}
public void setAccountNo(String accountNo) {
this.accountNo = accountNo;
}
public String getOwnerName() {
return ownerName;
}
public void setOwnerName(String ownerName) {
this.ownerName = ownerName;
}
public int getBalance() {
return balance;
}
public void setBalance(int balance) {
this.balance = balance;
}
public void showAccountInfo() {
System.out.println("계좌번호 : " + accountNo);
System.out.println("예금주명 : " + ownerName);
System.out.println("현재잔고 : " + balance + "원");
}
}
- 출력창 (기본값 들어가는거 잘 보기)
- 기본 생성자 public Account4() {} 를 주석처리하면 오류 : 자동생성X
- Ex3.java 에서 이 부분 주석처리하고 생성자 자동 생성 해보기
- 단축키 : Alt + Shift + S → O
- 자동생성! (지금은 모르는 super()지우기)
======== Ex4.java 만들기
p.205
< 레퍼런스 this >
- 자신의 인스턴스 주소를 저장하는 레퍼런스 변수(참조 변수)
- 자동으로 생성되는 레퍼런스
- 생성자 또는 메서드 내에서 로컬변수와 멤버변수의 이름이 같을 때 멤버변수를 지정하기 위한 키워드로 사용됨
< 기본 문법 >
this.멤버변수명
- public 속 파라미터 변수(로컬변수, 지역변수) name 과 인스턴스 변수(멤버변수) name 이름이 같아도 오류는 안남.
- 근데 색을 확인해보면 로컬변수 name 에 로컬변수 name 이 저장됨.
- (자기한테 자기 값 넣는 거!)
- 아무 효과 없다고 경고창 뜸!
- 로컬변수 name 값을 다시 로컬변수 name 에 저장하는 코드 = 효과X
> 메서드(생성자) 내의 로컬변수명과 클래스 내의 멤버변수명이 같을 경우 메서드 내에서 두 변수의 이름을 지정하면 로컬변수를 지정하게 됨.
- 로컬변수 name 값을 다시 로컬변수 name 에 저장하는 코드 = 효과X
- 멤버변수 name(this.name) 에 로컬변수 name(name) 값을 전달
- 차이점 구분 잘 하기!
======== Test4.java 만들기
- 오류 고치기! this. 추가
- p.207
- 같은 기능인데 코드가 계속 중복된다.
- 생성자 this() 사용하면 코드를 줄일수있다 (코드낭비제거)
------------------------------ 오후
======== Ex5.java 만들기 (생성자 this() 오버로딩)
p.207
< 생성자 this() >
- 생성자 내에서 자신의 또 다른 생성자를 호출하는 키워드
- 레퍼런스 this 와 동일하게 자신의 인스턴스에 접근하여 다른 생성자를 호출할 때 사용
- 생성자 오버로딩 시 멤버변수 초기화 코드의 중복을 제거하기 위해 사용
- ⇒ 여러 생성자에서 멤버변수를 중복으로 초기화하지 않고, 하나의 생성자에서만 초기화하고, 나머지 생성자에서는 해당 생성자를 호출하여 초기화 할 값만 전달 후 대신 초기화 수행
- 생성자 내의 첫 번째 라인에서 생성자 this() 를 호출해야함
- ⇒ 생성자 호출 코드보다 다른 코드가 먼저 실행될 수 없다!
< 생성자 this() 호출 기본 문법 >
--------생성자 내의 첫번째 라인에서--------
this(파라미터...);
문제 )
MyDate d1 = new MyDate();
// 기본 생성자를 통해 아무것도 전달하지 않으면 1900/1/1 출력
System.out.println(d1.year + "/" + d1.month + "/" + d1.day);
MyDate d2 = new MyDate(2020);
// 생성자 정수 1개를 전달하면 연도를 초기화하여 2020/1/1 출력
System.out.println(d2.year + "/" + d2.month + "/" + d2.day);
MyDate d3 = new MyDate(2020, 2);
// 생성자 정수 2개를 전달하면 연도를 초기화하여 2020/1/1 출력
System.out.println(d3.year + "/" + d3.month + "/" + d3.day);
MyDate d4 = new MyDate(2020, 2, 11);
// 생성자 정수 3개를 전달하면 연도를 초기화하여 2020/1/1 출력
System.out.println(d4.year + "/" + d4.month + "/" + d4.day);
- 일단은 자동완성 하지 말고, this() 쓰지 말고 만들어보기(원래 하던 대로)
class MyDate {
int year;
int month;
int day;
public MyDate() {
this.year = 1900;
this.month = 1;
this.day = 1;
}
public MyDate(int year) {
this.year = year;
this.month = 1;
this.day = 1;
}
public MyDate(int year, int month) {
this.year = year;
this.month = month;
this.day = 1;
}
public MyDate(int year, int month, int day) {
this.year = year;
this.month = month;
this.day = day;
}
}
// this. 생략가능
답 )
- 생성자 내에서 다른 코드보다 아래쪽(뒤)에 생성자 this() 가 올 수 없다!
- ⇒ 반드시 생성자 내의 첫 번째 라인에서 생성자 this() 를 사용해야함!
- 위로 옮기면 오류창 없어지는 거 확인할 수 있다 (가장 먼저 사용해야함!)
- 실행해보면 이렇게 호출되는데, (1900,1,1)을 찾아가서 제일 위에 문장이 가장 먼저 실행됨. (어떻게 실행되는지 잘 알아두기)
> this() 오버로딩 해보기 )
class MyDate {
int year;
int month;
int day;
public MyDate() {
this(1900, 1, 1);
System.out.println("MyDate() 생성자 호출됨!");
}
public MyDate(int year) {
this(year, 1, 1);
System.out.println("MyDate(int) 생성자 호출됨!");
}
public MyDate(int year, int month) {
this(year, month, 1);
System.out.println("MyDate(int, int) 생성자 호출됨!");
}
// 전체를 초기화하는 생성자는 그대로 두고,
// 나머지 생성자만 this() 를 사용
public MyDate(int year, int month, int day) {
// this(year, month, day); // 많이 하는 실수!!
System.out.println("MyDate(int, int, int) 생성자 호출됨!");
this.year = year;
this.month = month;
this.day = day;
}
}
- // this(year, month, day); // 많이 하는 실수!!
- 여기서 ctrl c + ctrl v 하면 이렇게 자동 복사
======== Test4.java 복사해서 Test5.java 만들기
문제 ) Account5로 바꾸고 전부 this() 로 만들어보기
p.207
public class Test5 {
public static void main(String[] args) {
Account5 a = new Account5();
a.showAccountInfo();
Account5 a2 = new Account5("111-1111-111");
a2.showAccountInfo();
Account5 a3 = new Account5("111-1111-111", "홍길동");
a3.showAccountInfo();
Account5 a4 = new Account5("111-1111-111", "홍길동", 0);
a4.showAccountInfo();
}
}
class Account5 {
private String accountNo; // 기본값 : "111-1111-111"
private String ownerName; // 기본값 : "홍길동"
private int balance; // 기본값 : 0
public Account5() {
this("111-1111-111", "홍길동", 0);
System.out.println("Account5() 생성자 호출됨!");
}
public Account5(String accountNo) {
this(accountNo, "홍길동", 0);
System.out.println("Account5(String) 생성자 호출됨!");
}
public Account5(String accountNo, String ownerName) {
this(accountNo, ownerName, 0);
System.out.println("Account5(String, String) 생성자 호출됨!");
}
public Account5(String accountNo, String ownerName, int balance) {
System.out.println("Account5(String, String, int) 생성자 호출됨!");
this.accountNo = accountNo;
this.ownerName = ownerName;
this.balance = balance;
}
public String getAccountNo() {
return accountNo;
}
public void setAccountNo(String accountNo) {
this.accountNo = accountNo;
}
public String getOwnerName() {
return ownerName;
}
public void setOwnerName(String ownerName) {
this.ownerName = ownerName;
}
public int getBalance() {
return balance;
}
public void setBalance(int balance) {
this.balance = balance;
}
public void showAccountInfo() {
System.out.println("계좌번호 : " + accountNo);
System.out.println("예금주명 : " + ownerName);
System.out.println("현재잔고 : " + balance + "원");
}
}
======== Ex6.java 책 p.200-202 코드 따라쳐서 만들기
public class Ex6 {
public static void main(String[] args) {
WalkTestBad wtb = new WalkTestBad();
wtb.walk();
wtb.walk(100);
wtb.walk(100, "cm");
WalkTestGood wtg = new WalkTestGood();
wtg.walk();
wtg.walk(100);
wtg.walk(100, "cm");
}
}
class WalkTestBad {
void walk() {
System.out.println("100cm 이동");
}
void walk(int distance) {
System.out.println(distance + "cm 이동");
}
void walk(int distance, String unit) {
switch(unit) {
case "cm":
break;
case "inch":
distance *= 2.54;
break;
default:
System.out.println("unknown");
distance = 0;
}
System.out.println(distance + "cm 이동");
}
}
class WalkTestGood {
void walk() {
walk(100, "cm");
}
void walk(int distance) {
walk(distance, "cm");
}
void walk(int distance, String unit) {
switch(unit) {
case "cm":
break;
case "inch":
distance *= 2.54;
break;
default:
System.out.println("unknown");
distance = 0;
}
System.out.println(distance + "cm 이동");
}
}
- wtb 는 각자 하나하나가 코드를 출력한다면
- wtg 은 맨 마지막 switch ~ case 문 혼자 일 다함
- “이동” 이라는 글자를 “이동했습니다!” 라고 수정하려면 wtb 는 3번이나 고쳐야하지만, wtg 는 마지막 문장 하나만 수정하면 된다.
- 유지보수성이 좋다. 유지보수성이 향상된다. - 라고 할 수 있다.
'Dev.Program > Java & Spring' 카테고리의 다른 글
[Java] 상속(Inheritance) (1) | 2022.10.05 |
---|---|
[Java] 패키지(package) / import (0) | 2021.01.23 |
[Java] 오버로딩 / 가변인자 (0) | 2021.01.23 |
[Java] 변수 선언 위치에 따른 분류 / 접근제한자 (0) | 2021.01.23 |
[Java] 클래스의 객체 / 인스턴스화 (0) | 2021.01.19 |