"그래서 오버로딩이랑 오버라이딩이 뭐가 다른데?"
단순 암기로 적용해 코딩을 하고는 있지만, 막상 질문을 받으면 머리속이 멍해진다. 심지어 단어도 비슷해 더 헷갈린다. 그래서 아예 정리해 두기로 했다.
가장 눈에 띄는 차이라 하면, 오버라이딩은 상속 관계에서 사용하지만 오버로딩은 그렇지 않다는 점이겠다. 때문에 둘의 차이를 설명하기 위해서는 자바의 상속 개념에 대해 알고 있어야 한다.
자바에서는 한 클래스가 다른 클래스의 필드와 메소드를 가져와 자기 것처럼 쓸 수 있다. 이것을 상속이라고 하며, 메소드를 빌려준 클래스를 부모 클래스(상위 객체), 메소드를 가져온 클래스를 자식 클래스(하위 객체)라고 한다.
상속 시, 하위 객체는 상위 객체의 특징(메소드, 변수 등)을 물려받게 된다. 이 때, 상위 객체의 특징을 '새롭게 구현'하는가, '그대로 사용'하는가에 따라서 상속의 형태가 갈리게 된다.
implements
부모 객체는 선언만 하며, 정의는 반드시 자식이 오버라이딩해서 사용한다.
부모 객체가 정의한 메소드/변수를 사용하는 extends와 달리, implements는 인터페이스 객체를 상속받아 자식이 그 내용을 정의한다.
abstract
extends와 interface의 기능을 합쳤다.
기본적으로는 extends로 동작하지만 추상 메소드도 사용가능하다.
public interface NoticeService {
//CRUD Create, Read, Update, Delete
void notice_insert(NoticeVO vo); //공지글 저장
List<NoticeVO> notice_list(); //공지글 목록 조회
NoticeVO notice_detail(int id); //공지글 상세 조회
void notice_update(NoticeVO vo); //공지글 변경 저장
void notice_delete(int id); //공지글 삭제
void notice_read(int id); //조회수 증가 처리
NoticePage notice_list(NoticePage page); //페이지 처리 된 공지글 목록 조회
void notice_reply_insert(NoticeVO vo); //답글 저장
}
// NoticeService.java
@Service
public class NoticeServiceImpl implements NoticeService {
@Autowired private NoticeDAO dao;
@Override
public void notice_insert(NoticeVO vo) {
dao.notice_insert(vo);
}
@Override
public List<NoticeVO> notice_list() {
// TODO Auto-generated method stub
return dao.notice_list();
}
@Override
public NoticeVO notice_detail(int id) {
return dao.notice_detail(id);
}
@Override
public void notice_update(NoticeVO vo) {
dao.notice_update(vo);
}
@Override
public void notice_delete(int id) {
dao.notice_delete(id);
}
@Override
public void notice_read(int id) {
dao.notice_read(id);
}
@Override
public NoticePage notice_list(NoticePage page) {
return dao.notice_list(page);
}
@Override
public void notice_reply_insert(NoticeVO vo) {
dao.notice_reply_insert(vo);
}
}
//NoticeServiceImpl.java
일반적으로 동일한 이름의 메소드는 실행 시 오류가 발생하기 때문에 함께 존재할 수 없다. 코드를 작성하면서 종종 저지르는 실수이기도 하다. 하지만 오버로딩은 동일한 이름의 메소드를 작성할 수 있게 한다.
만약 회원 정보 등록을 위한 클래스를 작성하는 중에, 매개변수로 주어진 정보의 개수와 종류가 각자 다르다면 어떻게 해야 할까? 각 경우에 맞춰 메소드를 새로 이름지어 따로 호출하는것은 아무래도 비효율적이다. 오버로딩을 사용하면 이름만 있는 회원도, 전화번호만 있는 회원도, 기타등등도 모두 메소드명 하나로 해결할 수 있다.
@Service
public class NoticeServiceImpl implements NoticeService {
@Autowired private NoticeDAO dao;
@Override
public List<NoticeVO> notice_list() {
// TODO Auto-generated method stub
return dao.notice_list();
}
@Override
public NoticePage notice_list(NoticePage page) {
return dao.notice_list(page);
}
}
// NoticePage를 매개변수로 한 호출도, 매개변수가 없는 호출도
// 모두 notice_list로 처리가능하다.
// 리턴 타입이 다른 것은 오버로딩의 조건이 아니다!
지금껏 예시로 붙여 두었던 코드를 보자. @Override라는 태그가 붙어 있다. 이 메소드들이 전부 오버라이딩 된 상태라는 의미이다. 예시 코드는 인터페이스에서 메소드 이름과 매개변수, 반환 타입만을 설정하고, 그것을 상속받은 클래스에서 비로소 내용을 정의하고 있다.
즉, 오버라이딩이란 부모 클래스가 가지고 있는 메서드를 자식 클래스가 재정의해서 사용하는 것이라 할 수 있다. 대부분의 IDE에서는 클래스를 상속하면 친절하게 오버라이딩 메소드가 자동으로 생성된다. 여기서 해당 클래스의 목적에 맞게 입맛대로 내용을 작성하면 된다.
만약 부모 클래스의 메소드에 이미 정의된 내용이 있을 때 오버라이딩을 한다면 어떻게 될까? 부모 클래스의 메소드 내용은 무시하고, 자식 클래스의 오버라이딩된 메소드만이 실행된다. 부모 클래스의 메소드 내용을 실행하고 싶다면 super 예약어를 사용한다.
public interface NoticeService {
void notice_insert(NoticeVO vo); //공지글 저장
}
// NoticeService.java
@Service
public class NoticeServiceImpl implements NoticeService {
@Autowired private NoticeDAO dao;
@Override
public void notice_insert(NoticeVO vo) {
dao.notice_insert(vo);
}
}
//NoticeServiceImpl.java