이번 시간에는 저번 시간에 했던 객체지향의 기본개념에 이어서 상속과 다형성에 대하여 공부하겠습니다.
1. 상속
- 상위 클래스의 모든 멤버를 하위 클래스가 물려 받는 것.
- 재사용성과 코드의 간결성 향상
- 자신이 만들어서 상속 시킬수도 있고 JDK가 지원하는 클래스로 부터 상속 받아 사용가능
- 최상위 클래스는 java.lang.Object
- 상속 키워드 : extends
- 상속의 종류 : 단일 상속(하나 클래스로 부터...), 다중 상속(2개 이상 클래스로 부터...)
- 상속의 용어
- 상속하는 클래스 : Base, Super, Parent Class
- 상속받는 클래스 : Derivation, Sub, Child Class
- 상속의 형식
[public/final/abstract] class 클래스이름 extends 상위클래스이름
{
멤버 변수;
멤버 메소드;
}
- private 멤버를 제외한 상위 클래스의 모든 멤버는 상속됩니다.
- 만약 동일한 이름의 변수가 상위 클래스와 하위 클래스에 존재한다면 상위 클래스의 변수는 가려진다.
- static 변수도 상속 가능
- 하위 클래스에서 객체 생성시 메모리 할당
<예제 소스코드1 - Employee.class>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | public class Employee { private String empNo; // 사원번호 private String name; // 이름 private String part; // 부서 // 매개변수가 없는 생성자 public Employee() { } // 매개변수 3개를갖는 생성자 public Employee(String empNo, String name, String part) { this.empNo = empNo; this.name = name; this.part = part; } // getter와 setter를 이용한 값을 정해주고 반환해주기 public String getEmpNo() { return empNo; } public void setEmpNo(String empNo) { this.empNo = empNo; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPart() { return part; } public void setPart(String part) { this.part = part; } // 멤버 필드의 결과값 문자열로 public String resultStr() { String result = ""; result += "사번 : " + empNo + "\n"; result += "이름 : " + name + "\n"; result += "부서 : " + part + "\n"; return result; } } | cs |
<예제 소스코드2 - Manager.class>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | public class Manager extends Employee { private String position; // 직책 // 매개변수 4개를 갖는 생성자 public Manager(String empNo, String name, String part, String position) { setEmpNo(empNo); setName(name); setPart(part); this.position = position; } // 관리자에서 추가되는 정보를 결과 문자열로 결합 public String addStr() { String result = ""; result += "직책 : " + position + "\n"; return result; } } | cs |
<예제 소스코드3 - Company.class>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | import java.io.BufferedReader; import java.io.InputStreamReader; public class Company { public static void main(String[] args) { String result = ""; // 결과 문자열 Employee emp = null;// Employee 객체의 레퍼런스 변수 Manager mng = null; // Manger 객체의 레퍼런스 변수 String empNo = null;// 사원 번호 String name = null;// 이름 String part = null; // 부서 String position = null; // 직책 // BufferedReader은 String 타입의 데이터 입력받을때 쓰임 // Scanner은 여러 타입 입력 가능 BufferedReader in =new BufferedReader(new InputStreamReader(System.in)); try // 예외처리를 위한 try ~ catch문 (나중이 자세히 배움) { // 정보 입력 단계 System.out.print("사번 입력(예)A1010 : "); empNo = in.readLine(); System.out.print("이름 입력(예)너구리 :"); name = in.readLine(); System.out.print("부서 입력(예)기획 :"); part = in.readLine(); System.out.print("직책 입력(예)사원-1, 대리-2, 과장-3 :"); position = in.readLine(); }catch(Exception e) // 잘못입력 했을시... { System.out.println("입력 오류"); } if (position.equals("1")) // 직책이 사원 일경우는 사원 생략 { emp = new Employee(empNo, name, part); result += emp.resultStr(); // 결과값 }else // 직책이 매니져급인 대리 과장일 경우 { // 2일경우 대리 나머지일경우 과장 position = (position.equals("2")) ? "대리" : "과장"; // 생성자 mng = new Manager(empNo, name, part, position); // 결과값 넣어서 잇기 result += mng.resultStr() + mng.addStr(); } System.out.println(result); // 결과 출력 } } |
<결과>
- super
- 앞에서는 super()에 대하여 배웠습니다. 하지만 여기서 super는 쫌 다릅니다.
- 하위 클래스에서 상위 클래스 객체를 가리키는 포인터
- 상위 클래스와 하위 클래스 모두 동일안 메소드 또는 변수가 있을때 상위 클래스 멤버 지지
- 생성자에서만 호출가능
- 사용방법
- 멤버 필드 접근 : super.멤버필드
- 멤버 메소드 접근 : super.멤버메소드(매개변수)
- 생성자 접근 : super(매개변수) - 생성자 메소드에서만 사용이 가능
<수정된 super 예제 소스코드1 - Employee.class>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | public class Employee { private String empNo; // 사원번호 private String name; // 이름 private String part; // 부서 // 매개변수가 없는 생성자 public Employee() { } // 매개변수 3개를갖는 생성자 public Employee(String empNo, String name, String part) { this.empNo = empNo; this.name = name; this.part = part; } // getter와 setter를 이용한 값을 정해주고 반환해주기 public String getEmpNo() { return empNo; } public void setEmpNo(String empNo) { this.empNo = empNo; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPart() { return part; } public void setPart(String part) { this.part = part; } // 멤버 필드의 결과값 문자열로 public String resultStr() { String result = ""; result += "사번 : " + empNo + "\n"; result += "이름 : " + name + "\n"; result += "부서 : " + part + "\n"; return result; } } | cs |
<수정된 super 예제 소스코드2 - Manager.class>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | public class Manager extends Employee { private String position; // 직책 // 매개변수 4개를 갖는 생성자 public Manager(String empNo, String name, String part, String position) { // set대신 상위클래스 멤버 필드 가져오기 super(empNo, name, part); this.position = position; } // 관리자에서 추가되는 정보를 결과 문자열로 결합 public String addStr() { // super를 이용한 상위클래스 메소드 가져오기 String result = super.resultStr(); result += "직책 : " + position + "\n"; return result; } } | cs |
<수정된 super 예제 소스코드3 - Company.class>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | import java.io.BufferedReader; import java.io.InputStreamReader; public class Company { public static void main(String[] args) { String result = ""; // 결과 문자열 Employee emp = null;// Employee 객체의 레퍼런스 변수 Manager mng = null; // Manger 객체의 레퍼런스 변수 String empNo = null;// 사원 번호 String name = null;// 이름 String part = null; // 부서 String position = null; // 직책 // BufferedReader은 String 타입의 데이터 입력받을때 쓰임 // Scanner은 여러 타입 입력 가능 BufferedReader in =new BufferedReader(new InputStreamReader(System.in)); try // 예외처리를 위한 try ~ catch문 (나중이 자세히 배움) { // 정보 입력 단계 System.out.print("사번 입력(예)A1010 : "); empNo = in.readLine(); System.out.print("이름 입력(예)너구리 :"); name = in.readLine(); System.out.print("부서 입력(예)기획 :"); part = in.readLine(); System.out.print("직책 입력(예)사원-1, 대리-2, 과장-3 :"); position = in.readLine(); }catch(Exception e) // 잘못입력 했을시... { System.out.println("입력 오류"); } if (position.equals("1")) // 직책이 사원 일경우는 사원 생략 { emp = new Employee(empNo, name, part); // 생성자 result += emp.resultStr(); // 결과값 }else // 직책이 매니져급인 대리 과장일 경우 { // 2일경우 대리 나머지일경우 과장 position = (position.equals("2")) ? "대리" : "과장"; // 생성자 mng = new Manager(empNo, name, part, position); // 결과값 넣어서 잇기 result += mng.addStr(); } System.out.println(result); // 결과 출력 } } | cs |
<결과>
- 결과는 마찬가지로 같은 결과가 나온다.
2. 다형성
- 다형성은 여러 가지 형태를 가질 수 있는 능력을 의미하며 한 타입의 참조변수로 여러 타입의 객체를 참조할 수 있도록하고 상속관계에서 일어난다.
- 위 예제 소스코드중 Company.class에서 38라인과 45라인이 다형성에 예라고 할 수 있다.
3. 추상 클래스
- 클래스 이름 앞에 abstract라는 예약어가 사용된 클래스
- 하위 클래스에서 구현될 기능을 추상 메소드로 선언한 클래스
- 추상 메소드는 선언만 되어 있고 구현 부분이 없는 메소드로 메서드의 결과형 앞에 abstract를 기재해서 생성
- 추상 메소드는 반드시 하위 클래스에서 오버라이딩 되어서 구현되어야 한다.
- 추상 메소드는 일반적인 멤버 변수와 메소드를 가질 수 있습니다.
- 하지만 객체를 생성하지 못하여 상속을 통해서만 사용되어 집니다.
<추상 클래스 예제 소스코드1 - Starcraft.class>
1 2 3 4 5 | // 추상 클래스 abstract class Starcraft { abstract void attack(); } | cs |
1 2 3 4 5 6 7 8 9 10 | public class Protoss extends Starcraft { // 추상 클래스는 오버라이딩 해서 사용 @Override public void attack() { System.out.println("프로토스의 공격"); } } | cs |
<추상 클래스 예제 소스코드3 - Terran.class>
1 2 3 4 5 6 7 8 9 | public class Terran extends Starcraft { // 추상 클래스는 오버라이딩 해서 사용 @Override public void attack() { System.out.println("테란의 공격"); } } | cs |
<추상 클래스 예제 소스코드4 - Zerg.class>
1 2 3 4 5 6 7 8 9 | public class Zerg extends Starcraft { // 추상 클래스는 오버라이딩 해서 사용 @Override public void attack() { System.out.println("저그의 공격"); } } | cs |
<추상 클래스 예제 소스코드5 - Main.class>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | public class Main { public static void main(String[] args) { Terran marine = new Terran(); marine.attack(); Protoss dragoon = new Protoss(); dragoon.attack(); Zerg hydralisk = new Zerg(); hydralisk.attack(); System.out.println("====객체 형변환과 오버라이딩을 이용===="); Starcraft obj = new Terran(); // 상위 클래스의 참조형 변수에 하위 클래스의 객체를 대입 obj.attack(); // shot() 메소드 호출 obj = new Protoss(); obj.attack(); // shot() 메소드 호출 obj = new Zerg(); obj.attack(); // shot() 메소드 호출 /* error 추상 클래스는 자신의 생성자를 이용해서 객체를 생성할 수 없음 obj = new Starcraft(); obj.shot(); */ } } | cs |
<결과>
4. final 관련 키워드 정리
- final 클래스 : 상속할수 없는 클래스
- final 메소드 : 재정의 할 수 없는 메소드
- final 필드 : 값을 변경할 수 없는 필드
5. 인터페이스
- 다중 상속을 위해서 나온 개념
- static final 변수와 추상 메소드 만을 소유
- 인터페이스에 정의된 모든 메소드는 상속받는 클래스에서 전부 오버라이딩해야 한다.
- 인터페이스로부터 상속 받을 때 implements키워드 사용
<Interface 예제 소스코드1 - Inter.class>
1 2 3 4 5 6 7 8 9 10 | public interface Inter { // 인터페이스에서는 final을 사용하지 않아도 변수는 final public int a=100; public final int b = 200; public abstract void method1(); // 인터페이스에서는 abstract을 사용하지 않아도 메소드는 abstract public void method2(); } | cs |
<Interface 예제 소스코드2 - InterTest.class>
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 InterTest implements Inter { @Override public void method1() { System.out.println("추상메소드"); } @Override public void method2() { System.out.println("추상메소드"); } public static void main(String args[]) { InterTest obj = new InterTest(); //obj.a = 200; // final 이므로 변경할 수 없다. obj.method1(); System.out.println("Inter의 a : " + obj.a); System.out.println("Inter의 b : " + obj.b); } } | cs |
<결과>
여기까지 객체지향 클래스의 대하여 알아보았습니다. 다음 시간에는 참조형 자료형인 배열에 대해서 공부하겠습니다.
'조재연의 Java 개꿀떡 > 조재연의 Java 기초 개꿀떡' 카테고리의 다른 글
자바(Java)의 기초 박살내기 - 예외처리(Exception) & java.lang 패키지 (0) | 2017.07.06 |
---|---|
자바(Java)의 기초 박살내기 - 배열(array) (0) | 2017.07.05 |
자바(Java)의 기초 박살내기 - 객체지향(클래스)의 기본 개념 (0) | 2017.07.02 |
자바(Java)의 기초 박살내기 - 제어문(Control Statement) (0) | 2017.06.30 |
자바(Java)의 기초 박살내기 - 연산자(Operator) (1) | 2017.06.30 |