▶생성자
-. 생성자는 클래스가 생성이 될 때 자동으로 실행되어지는 특수한 형태의 메서드
-. 클래스의 이름과 동일한 이름을 가진다.
-. 생성자는 클래스안에서의 그 어떤 메서드보다 먼저 실행이 된다는 특징을 가지고 있다.
-. new키워드를 사용한다.
-. 리턴형을 명시하지 않으며, 메서드의 이름은 클래스와 동일하다.
▶생성자 예시
Main이라는 함수에 Book book = new Book()을 입력한다.
이는 Book()이라는 생성자를 생성한다는 의미이고
new 이용하여 Book이라는 구체적인 기능을 사용하는 book이라는 인스턴스를 생성한다는 의미이다.
이와 같은 과정이 있었기에 book은 book.read(); 를 통해 Book의 read라는 메서드(기능)을 불러올 수 있게 되고 거기엔 syso 기능이 포함되어 있어서 밑과 같은 결과가 콘솔에 출력되게된다.
이 생성자는 파라미터,멤버변수가 없는 기본생성자로서( https://miyakita.tistory.com/202 )
클래스에 특별히 생성자가 정의되지 않은 경우에도 java컴파일러가 기본 생성자가 존재한다고 인식한다.
즉, Main에서 따로 넘길 파라미터가 없고 가져올 기능도 없다면 Book클래스 안의 book()을 우리가 따로 입력을 하지 않아도 자바에서 자동으로 기본생성자가 존재한다고 인식을 한다는 것이다.
물론, 우리가 입력을 따로 하지 않았으니 우리 눈에는 보이지 않는다.
▶생성자의 사용 이유
생성자를 만드는것이 멤버변수의 값을 초기화 시키는 과정이라고도 할 수 있는데
book 클래스안의 book 생성자에서 멤버변수에 대한 기본값을 설정하기 때문에, 객체를 생성하는 것 만으로 멤버변수가 초기화되는 것이다.
자동으로 실행된다는 특성때문에, 객체가 생성되면서 멤버변수의 값을 초기화 하기 위해 사용한다.
**초기화의 중요성
값을 초기화(=값을 최초로 세팅하는 것)하는 것은 생각보다 중요한데, 초기화되지않은 필드는 프로그램이 오류를 일으키는 가장 중요한 원인 중 하나이다. 또한 그 오류는 테스트를 통해 검출되지 않는 오류로 유명하다. 그래서 객체지행프로그레밍에서는 생성자라고 하는 특별한 방법을 이용하여 객체를 만들고 나서 값을 반드시 초기화하도록 언어를 설계했다.
▶생성자 주의사항
생성자가 너무 많은 일을 하는 것은 바람직하지않다. 이것은 프로그램마다 약간씩 달라질 수 있지만 일반적인 규칙에 의해선 생성자는 가볍게 필드의 값을 적절한 초기값으로 지정하는 정도가 적합하다고 할 수 있다. 아주 큰 자료구조를 가지고 있는 객체라면 그것을 생성자에게 몽땅 만들기보다는 필요할 때 생성하여 만드는 것이 메모리도 절약되고 불필요한 일을 미리 하지 않는다는 점에서 효율적일 수 있다.(필요할 때 까지 미룬다는 원칙이라 할 수 있다.)
▶파라미터를 갖는 생성자
생성자도 메서드의 한 종류이므로 파라미터를 함께 정의하는 것이 가능하다.
왜 굳이 생성자에 파라미터를 넣어 값을 보내는걸까?
1
2
3
4
5
6
7
8
|
Calculator c1 = new Calculator();
c1.setOprands(10,20);
c1.sum();
c1.avg();
Calculator c1 = new Calculator(10,20);
c1.sum();
c1.avg();
|
cs |
위에는 Main 함수에 있는 파라미터가 있는 생성자, 파라미터가 없는 생성자 2개의 예시가 있다.
우리가 외주를 받아 계산기기능을 가진 코드를 만들어야한다고 했을 때 우린 위와 같이 만들것이다.
그런데 우리가 사용자 입장이 되어 생각을 해보았을 때 사용자는 메서드 sum 을 호출하기전에 setOprands를 호출해야한다는 것을 기억하고 있어야한다는 것을 의미하고 이러한 절차를 기억하는 것은 사용자 입장에서 불편함으로 인식이 되고 잘못된 사용으로 인한 오류가 발생활 확률을 높힌다.
그럼 setOprands의 역할은 어디서 하느냐
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
class Calculator{
int left, right;
public Calculator(int left, int right){
this.left = left;
this.right = right;
}
public void sum(){
System.out.println(this.left + this.right );
}
public void avg(){
System.out.println((this.left + this.right ) / 2);
}
}
|
cs |
이처럼 Calculator라는 클래스안에 동일한 이름을 가진 Calculator이 Main 함수에서 넘어온 파라미터랑 똑같은 데이터유형, 똑같은 데이터숫자를 받아 데이터를 저장하고 넘기는 것이다.
위의 들고왔던 기본생성자(Book)의 예시와 다른 점을 살펴보자면
파라미터가 없는 생성자(Book)는 클래스 안의 메서드(Book())에서 값을 입력하고(this.subject = "JAVA입문") 전역변수에 넣어주지만, 파라미터가 있는 생성자(Calculator)는 Main함수에서부터 값을 넘겨주고(10,20) 클래스 안에서는 생성자의 파라미터를 멤버변수에 복사하는 역할(this.left = left)만 한다는 것이 형식의 다른점이라 할 수 있다.
즉, 파라미터가 있는 생성자는 객체의 초기화를 외부적인 요인에 의해 처리할 수 있다는 것이다 .
▶Super
super키워드: 클래스의 상속 관계에서 자식 클래스가 부모 클래스를 가르키는 예약어
사용방법
-> 멤버변수 이름 앞에 명시되는 경우:
부모 클래스의 멤버변수를 의미한다. 이 때, 자식클래스가 부모클래스의 메서드를
가지고 오고 싶다면 super.부모메서드명 이렇게 출력을 해도 되지만 그 멤버변수는 이미
모두 자식 클래스에 상속되어 있기 때문에 이 경우는 this키워드를 사용하는 것과
동일한 결과이기에 잘 사용하지 않는다.
-> 메서드 이름 앞에 명시:
재정의(Override) 되지 않은 메서드
->이미 상속되어 있기 때문에 this 키워드를 사용하는 것과 동일한 결과를 가진다.
재정의(Override) 된 메서드
->Override된 메서드 이름 앞에 사용하게 되면 재정의 이전의 원본 메서드를 의미
->ex)
Hellop는 본래의 부모값, KoreanC의 say()는 필요에 의해 재구현한 값이다. 근데 만약 KoreanC가 say()를 재구현했지만 hellop의 say() "Hello" 값이 필요하다면? KoreanC 는 Hellop의 값을 오버라이딩 즉, 재할당하여 그 값을 덮어버렸기때문에 this로는 정상출력이 되지 않는다.
이 때 KoreanC의 코드안에 가져오고싶은 say()메소드를 넣고 앞에 super를 붙혀 부모 클래스의 기능을 호출한다. 그럼 재 할당된 "안녕하세요"값이 아닌 원본의 값 "Hello"가 출력됨을 볼 수 있다.
▶상속관계에서의 생성자처리
생성자가 정의된 클래스의 상속 제한되어있다.
생성자가 정의되어 파라미터를 받는 부모 클래스는 객체 생성을 위해서 생성자 파라미터를 반드시 전달받아야하기 때문에 단순히 자식으로 메서드를 상속만 시킨다면 에러가 발생된다.
이떄 자식 클래스에 super를 사용하여 강제적으로 부모의 생성자와 자식 생성자를 연결해준다.
이는 생성자를 부모생성자를 자식에게 "상속"한 것이 아니라 super를 통해 자식에게 "호출"한 것임을 기억해야한다.
생성자는 기본적으로 상속이 되지 않는 특징을 가지고 있다.
이건 오버라이드을 전혀 하지 않은 일반 상속만 받은 코드이다.
오버라이드를 하지 않아도 상속은 받았기에 부모의 생성자 호출이 필요하고 파란색 라인에 super();를 입력하여 부모 생성자를 강제로 호출한다.
근데 위 파란줄의 super();를 굳이 명시하지않아도 java컴파일러는 자동적으로 super();를 만드는 기능을 가지고 있다. 즉, super()가 생략되어있음으로 우리가 따로 super()를 입력해주지않아도 출력하면 "부모생성자호출""자식생성자호출"순으로 출력되게된다는 것이다.
super();로 ()안에 아무런 인자값을 넣지 않고! 자바에서 자동적으로 만들어 주는 경우는 부모가 파라미터가 없는 경우이다.
그럼 부모가 파라미터를 받는경우엔 어떻게 될까?
부모 생성자가 인자값을 가지고 있다면 자식 클래스를 객체화(CClass2 CClass2 = new CClass2) 할 때 자바는 super()를 자동으로 만들지 않는다.
따라서 개발자 스스로 자식 생성자에 명시적으로 super()를 입력하여 부모 생성자를 호출해야한다는 것이다.
단, super()를 사용할 때 자식 생성자의 첫 줄에 위치해야만한다.
Main05에서 "부모생성자"값을 넣으면 이 값은 자식 클래스 안의 CClass Str로 받고 그 밑의 super(str)로 받아서 부모생성자 위의 PClass str로 넘어가게된다. 그렇게 부모생성자에 데이터 값을 넣어줄 수 있게 되고 출력값으론 "부모생성자 호출: 부모생성자, 자식생성자" 가 출력이 되게 된다.
파라미터를 가지는 부모클래스에 데이터 값을 넣을 땐 자식 클래스가 아닌 메인클래스에서 데이터를 넣는 것이 좋다. 자식클래스에 바로 데이터 값을 넣는 것은 하드코딩이라고 부르는데 값을 자식클래스 안에 고정시켜버리는 것이기 때문에 차후에 유지보수하기에 힘이 들기 때문이다.
▶상속관계의 예시
예시를 한번 더 보자
[Unit 클래스 : 부모]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
public class Unit{
protected String name;
//생성자를 정의
public Unit(String name){
this.name = name;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
// 재정의 대상
public void attack(){
System.out.println(this.name + " >>>공격준비");
}
}
|
cs |
부모클래스에는 자식 1,2,3에게 필요한 공통적인 기술을 넣어준다. name이라는 파라미터를 받으니 파라미터를 받는 생성자 형식으로 생성자를 생성해준다.
[Army 클래스: 자식1]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
public class Army extends Unit{
//부모 클래스의 생성자를 강제 호출하기 위한 생성자
public Army(String name) {
super(name);
}
/*공격의 형태를 육군에 맞게 변경하지만,
부모클래스가 가지고있는 공격 준비 기능을 super키워드를 통해 보전 */ public void attack(){
super.attack();
System.out.println(super.getName() + " >>지상공격실행");
}
public void tank(){
System.out.println(super.getName() + ">>>탱크공격");
} //상속이 아닌 자체적인 기능
}
|
cs |
자식 생성자로서, 부모 클래스를 상속을 받았지만, 부모 생성자는 파라미터를 가지는 생성자임으로 super()를 통해 개발자가 명시적으로 부모 생성자를 호출하는 것을 코딩해줘야한다.
근데 여기서 Army클래스는 부모클래스의 attck에 "공격준비" 에 지상공격실행까지 추가할 수 있다. 육군만의 "지상공격실행"이라는 개인의 속성을 추가하여 attck()이라는 메서드를 자식클래스가 오버라이드 한 것이다.
[AirForce 클래스: 자식2]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
public class AirForce extends Unit {
public AirForce(String name){
super(name);
}
public void attack(){
super.attack();
System.out.println(this.getName() + " >>공중공격실행");
System.out.println(super.getName() + " >>이륙");
}
public void Airplane(){
System.out.println(super.getName() + ">>>비행기공격");
} //상속이 아닌 자체적인 기능
}
|
cs |
attck()안에서 공중공격실행과 이륙은 this와 super로 각각 다르게 설정이 되어있는데 AirForce는 이미 Unit이라는 부모의 기능이 상속이 되어있는 상황이기에 this나 super나 같은 효과를 가지게된다.
또한 Airplane()(비행기)은 공군(AirForce)만의 고유한 기능이다. 부모의 메서드를 그대로 가져와 attck()에 오버라이드 할 수 있지만 AirForce만의 본인 고유의 기능(메서드)를 추가할 수 있다.
[Navy 클래스: 자식 3]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
public class Navy extends Unit{
public Navy(String name) {
super(name);
}
@Override
public void att(){
super.attack();
System.out.println(this.getName() + " >>어뢰발사");
System.out.println(this.getName() + " >>지상상륙");
}
public void nucleus(){
System.out.println(this.getName() + " >>핵미사일");
}
}
|
cs |
Unit의 세번째 자식 클래스로 역시나 부모의 attck()기능을 받는데 Navy 클래스에는 개발자의 실수로 attck이 att으로 이름 오류가 났다. 그렇게 되면, 자바는 att를 부모에게 가져온 attck()이 아닌 오로지 Navy 클래스만의 개별기능이라고 인지하기에 특별히 에러를 표시하지 않는다. 그럼 차후에 attck()의 내용을 변경하기 위해 부모클래스의 attck() 내용을 변경할 때 Navy만 변경이 되지 않아 혼란을 줄 수 있다.
이 때 @override옵션을 사용한다.
****@override 옵션
- "@override"는 이 키워드가 명시된 위치 아래에 정의되는 메서드가 부모 클래스에 존재하지 않을 경우 구문에러로처리한다.
-. 부모 클래스의 메서드를 재 정의하고자 할 경우 의도치 않은 실수를 예방하기 위해서 '오타 방지 옵션'이다.
-. 여러 개의 메서드를 재 정의한다면 재정의 되는 모든 메서드를 위에 각기 명시한다.
[Main 클래스]
1
2
3
4
5
6
7
8
9
10
11
12
13
|
public class Main01 {
public static void main(String[] args) {
Army am = new Army("육군");
Navy nv = new Navy("해군");
AirForce ar = new AirForce("공군");
am.attack();
am.tank();
nv.attack();
ar.attack();
}
}
|
cs |
서로의 클래스 파일은 다르게 설정해주었지만 Main은 하나로 공유한다.
main에서는 주로 생성자의 객체를 생성해주고 데이터 값을 각각의 클래스로 보내주고 출력하는 기능을 꺼내는 역할을 한다. Main은 자바에서 제일 먼저 접근하는 클래스로 Main을 기준으로 자바는 모든 클래스의 기능을 찾으러 출발한다.
그래서 Main은 반드시 패키지 안에 존재하여 각각의 클래스와 연결이 되어있어야한다.
▶클래스,메서드,상수의 이름 규칙
1) 공통이름규칙
-. 영어, 숫자, 언더바(_)의 조합, 첫 글자는 반드시 영어로 표기한다.
2) 클래스 이름 규칙
-. 첫 글자는 대문자로 시작, 나머지 글자는 소문자로 표시한다.
-. 2개 이상의 단어를 조합해야할 경우 새로운 단어는 대문자로 시작한다.
-. ex) class Student/ class MyClass
3) 메서드, 변수 이름 규칙
-. 대부분 소문자로 구성되지만, 두 개 이상의 단어를 조합할 경우 새로운 단어는 대문자로 표시한다.
-. ex) int age / String user_name/ String userName/ String memberCount
4) 상수 이름 규칙
-. 모두 대문자로 표시한다.
-. ex) final double PI/ final int COLOR
'국비필기노트 > Java' 카테고리의 다른 글
객체지향 프로그래밍(인스턴스, 자바빈즈, 클래스의 분리, 상속) (0) | 2022.03.17 |
---|---|
java_메서드,클래스,생성자 선언 방법 정리 (0) | 2022.03.15 |
자바(java)_클래스,객체,메서드,전역변수,지역변수 (0) | 2022.03.14 |
자바(java)_메서드 (0) | 2022.03.11 |
java - 2차 배열 (0) | 2022.03.11 |