은행일 할때도 상속 온다하면 머리가 아팠는데, 단어부터 어려운 이걸 대체 왜 써야할까.
클래스를 만들다보면 겹치는 기능이 있기 마련이다. 스마트한 집단인 개발자들은 중복되는 값을 무지 싫어한다. 중복을 보면 묶어버리고 싶다는 본능이 되살아난다. 자, 공통된 기능을 묶었는데 그럼 이걸 뭐라 칭해야하지? 그리고 묶은 값을 받아서 쓰는 애들을 뭐라하지?
공통된 값을 묶은 것을 부모클래스라고 한다. 이 클래스의 기능을 받아서 쓰는 클래스를 자식클래스라고 한다. 그리고 자식클래스에 기능을 넘겨주는 것을 상속이라고 정의한다. 짠. 간단하다.
public class 자식클래스 extends 부모클래스 { . . . }
// 덧셈과 뺄셈 기능이 있는 부모 클래스 생성
/* 생성자를 특별히 정의하지 않는 경우 자바 컴파일러가 기본 생성자가 있다고 간주하기
* 때문에 클래스 다이어그램에서는 기본생성자를 명시한다. */
public class CalcParent {
public int plus(int x, int y) {
return x + y;
}
public int minus(int x, int y) {
return x - y;
}
}
// 자식클래스의 작성 (클래스 다이어그램 구현)
// 부모의 모든 기능을 상속받고 있으며, 곱셈과 나눗셈을 추가하여 기능을 확장시켰다.
public class CalcChild extends CalcParent {
public int times(int x, int y) {
return x * y;
}
public int divide(int x, int y) {
int result = 0;
if (y != 0) { // 0으로 나누면 에러니까
result = x / y;
}
return result;
}
}
// 열심히 만든 클래스를 이제 Main에서 써보자!
// 부모클래스 기능 확인
public class Main01 {
public static void main(String[] args) {
CalcParent parent = new CalcParent();
System.out.println(parent.plus(100, 50));
System.out.println(parent.minus(100, 50));
System.out.println("-----------");
// 자식클래스 기능 확인
// 부모클래스 기능을 다 받아오고 곱하기 나누기도 더해 사칙연산으로 기능이 확장되었다
CalcChild child = new CalcChild();
System.out.println(child.plus(200, 100));
System.out.println(child.minus(200, 100));
System.out.println(child.times(200, 100));
System.out.println(child.divide(200, 100));
}
}
<실습 02>
// 공통기능을 구현하는 클래스
// 게시판의 일반적인 기능을 구현한다. 두 자식들의 공통점을 추출한 것이다.
public class Article {
// 글 번호
private int num;
// 제목
private String title;
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
}
// 질의응답 게시판 클래스
// 공통기능인 글번호와 제목을 받아오기에 답변에 대한 개념만 추가한다.
public class QNAArticle extends Article {
// 부모 클래스의 title을 질문으로 보고, 답변을 추가한다.
private String answer;
public String getAnswer() { return answer; }
public void setAnswer(String answer) { this.answer = answer; }
public String toString() {
return "질문/답변 [글번호=" + getNum() + ", 제목="
+ getTitle() + ", 답변=" + answer + "]";
}
}
// 자료실 게시판 클래스
// 첨부파일이라는 개념만 추가한다.
public class FileArticle extends Article {
// 자료의 확장 --> 파일이름
private String fileName;
public String getFileName() {
return fileName;
}
public void setFileName(String fileName) {
this.fileName = fileName;
}
public String toString() {
return "자료실 [번호=" + getNum() + ", 제목="
+ getTitle() + ", 첨부파일=" + fileName + "]";
}
}
// 잘 만든 클래스를 이제 써보자
public class Main {
public static void main(String[] args) {
FileArticle fileArticle = new FileArticle();
fileArticle.setNum(1);
fileArticle.setTitle("첫 번째 자료 입니다.");
fileArticle.setFileName("java.ppt");
System.out.println(fileArticle.toString());
System.out.println("----------------");
QNAArticle qna = new QNAArticle();
qna.setNum(1);
qna.setTitle("첫 번째 질문입니다.");
qna.setAnswer("첫 번째 답변입니다.");
System.out.println(qna.toString());
}
}
다형성이란 무엇일까? 소프트웨어가 하드웨어랑 구별되는 특징은 쉽게 모양을 바꿀수도 있고, 확장할 수도 있다는 점이다. 확장이 용이하게 하기 위해선 유지보수가 쉬워야할거고, 좋은 코드를 짜야하는 이유를 여기서도 찾을 수 있겠다.
public class Unit {
private String name;
// 생성자 정의
public Unit(String name) {
super();
this.name = name;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
// 재정의할 메서드
public void attack() {
System.out.println(this.name + " >> 공격준비");
}
}
public class Army extends Unit {
public Army(String name) { // 부모클래스의 생성자를 강제호출
super(name);
}
@Override
public void attack() {
super.attack();
System.out.println(super.getName() + " >> 지상공격 실행함");
}
public void tank() {
System.out.println(super.getName() + " >> 탱크공격");
}
}
public class Navy extends Unit {
public Navy(String name) {
super(name);
}
@Override
public void attack() {
super.attack();
System.out.println(this.getName() + " >> 어뢰 발사!!");
System.out.println(this.getName() + " >> 지상 상륙");
}
public void nucleus() {
System.out.println(this.getName() + " >> 핵미사일");
}
}
public class AirForce extends Unit {
public AirForce(String name) {
super(name);
}
@Override
public void attack() {
super.attack();
System.out.println(this.getName() + " >> 이륙");
System.out.println(this.getName() + " >> 공중공격 실행함");
}
public void bombing() {
System.out.println(this.getName() + " >> 폭격");
}
}
public class Main01 {
public static void main(String[] args) {
Army am = new Army("육군");
Navy nv = new Navy("해군");
AirForce af = new AirForce("공군");
am.attack();
am.tank();
nv.attack();
nv.nucleus();
af.attack();
af.bombing();
}
}
@Override : 메서드 재정의 하는 과정에서 오타가 발생하면 어떻게 될까? 아! 새로운 메서드 정의구나! 하고 그냥 오류없이 진행된다. (잘못되었는데 잘 진행되는것만큼 무서운 것도 없다... 나중에 어떻게 돌아올지 모르기 때문이다.) 그래서 이건 재정의 하는거니까 오타 있으면 알려달라는 의미에서 쓰는게 @Override 이다. 재정의되는 모든 메서드 위에 붙여서 오타를 예방하자.
public class Charactor {
private String job;
private int age;
public void setProperty(String job) {
this.job = job;
}
public void setProperty(int age) {
this.age = age;
}
public void setProperty(String job, int age) {
this.job = job;
this.age = age;
}
public void setProperty(int age, String job) {
this.job = job;
this.age = age;
}
@Override
public String toString() {
return "Charactor [job=" + job + ", age=" + age + "]";
}
}
public class Main01 {
public static void main(String[] args) {
Charactor c = new Charactor();
System.out.println(c.toString()); // null값과 0이 출력된다.
c.setProperty(19);
System.out.println(c.toString());
c.setProperty("회사원");
System.out.println(c.toString());
c.setProperty("자영업", 20);
System.out.println(c.toString());
c.setProperty(30, "교수");
System.out.println(c.toString());
}
}
<객체 생성 방법의 다양화>
public class Member {
private String job;
private int age;
public Member() { }
public Member(int age) { this.age = age; }
public Member(String job) { this.job = job; }
public Member(String job, int age) {
this.job = job;
this.age = age;
}
@Override // why? toString은 최상위 객체인 Object에서 가져온 메서드기 때문
public String toString() {
return "Charactor [job=" + job + ", age=" + age + "]";
}
}
public class Main02 {
public static void main(String[] args) {
Member m1 = new Member();
System.out.println(m1.toString());
Member m2 = new Member(19);
System.out.println(m2.toString());
Member m3 = new Member("학생");
System.out.println(m3.toString());
Member m4 = new Member("강사", 20);
System.out.println(m4.toString());
}
}
<실습 06> - 정의된 멤버변수들을 모두 초기화 하는 완전한 형태의 생성자를 정의한다.
public class Article {
private int seq;
private String subject;
private String writer;
public Article(int seq, String subject, String writer) {
super();
this.seq = seq;
this.subject = subject;
this.writer = writer;
}
// 파라미터가 서로 다른 생성자들이 하나의 완전한 생성자를 호출하도록 하며,
// 데이터의 초기화를 한 곳에서 일괄적으로 처리하도록 구현할 수 있다.
public Article(int seq) {
this(seq, "제목없음", "익명");
}
public Article(int seq, String subject) {
this(seq, subject, "익명");
}
@Override
public String toString() {
return "Article [seq=" + seq + ", subject=" + subject + ", writer=" + writer + "]";
}
}
public class Main03 {
public static void main(String[] args) {
// Article 클래스의 기능 확인
Article a1 = new Article(1);
System.out.println(a1.toString());
Article a2 = new Article(2, "테스트 게시물");
System.out.println(a2.toString());
Article a3 = new Article(3, "두 번째 게시물", "자바학생");
System.out.println(a3.toString());
}
}
이 포스트는 itpaper.co.kr에서 제공되는 강의자료를 바탕으로 작성되었습니다.