Ⅰ. 다형성
-- Day11의 소스 코드를 재활용하였다.
-- console 가독성을 위해 기본 생성자 삭제
public class MainApp {
public static void main(String[] args) {
Animal dg1 = new Dog();
dg1.setName("뽀삐");
dg1.setBirthYear(2010);
dg1.printAnimal();
Animal ct1 = new Cat();
ct1.setName("톰");
ct1.setBirthYear(2017);
ct1.printAnimal();
Animal dk1 = new Duck();
dk1.setName("도널드");
dk1.setBirthYear(2018);
dk1.printAnimal();
}
}
▷결과
1.동물명 : 뽀삐
2.나이 : 10 살
1.동물명 : 톰
2.나이 : 3 살
1.동물명 : 도널드
2.나이 : 2 살
public class Dog extends Animal{
public void printAnimal() {
StringBuffer sb = new StringBuffer();
sb.append("1.Dog Name : " + super.getName() + "\n");
sb.append("2.Age : " + getAge()+" 살\n");
sb.append("귀여운 강아지 입니다.\n");
System.out.println(sb.toString());
}
}
-- Dog클래스에 printAnimal()을 생성하고 실행하면 자기 자신(Dog 클래스)에 있는 printAnimal()을 실행한다.
-- 마우스를 갖다 대서 확인해 보면 printAnimal 메소드는 Animal 클래스의 메소드로 나오지만 결과는 dog클래스의 메소드로 출력된다.
▷▷ 메소드의 오버라이딩(Overriding) == 메소드의 재정의
-- 부모 클래스에서 정의되어진 메소드의 형태만 그대로 자식클래스에 가져와서 그 내용 즉, { } 부분을 새롭게 바꾸어 주는 것을 말한다.
-- 형태를 그대로 해야 오버라이딩 가능하다.
예> Animal 부모 클래스에 printAnimal() 이 있다면 Dog 자식 클래스에 printAnimal()이라고 똑같이 써 주어야 한다.
-- printAnimal method를 만들려고 했으나 실수로 printanimal 이라고 작성하였을 때, main method에서 printAnimal method를 호출하였을 경우 Animal 클래스의 printAnimal을 호출하게 된다.
-- 잘못 타이핑 한 것을 알려 주고 방지하기 위해 위에 @Override를 사용한다.
-- 부모 클래스에 같은 이름의 클래스가 정의되어 있지 않으면 빨간 밑줄로 오류를 나타내 준다.
-- @ : 어노테이션(애노테이션)이라고 부른다.
package my.day13.b.polymorphism;
public class MainApp {
public static void main(String[] args) {
Animal an1 = new Dog();
an1.setName("뽀삐");
an1.setBirthYear(2010);
an1.printAnimal();
Animal an2 = new Cat();
an2.setName("톰");
an2.setBirthYear(2017);
an2.printAnimal();
Animal an3 = new Duck();
an3.setName("도널드");
an3.setBirthYear(2018);
an3.printAnimal();
Animal an4 = new Animal();
an4.setName("동물");
an4.setBirthYear(2019);
Dog dg1 = new Dog();
dg1.setName("멍멍이");
dg1.setBirthYear(2002);
dg1.setWeight(30);
Cat ct1 = new Cat();
ct1.setName("야옹이");
ct1.setBirthYear(2003);
ct1.setColor("white");
Duck dk1 = new Duck();
dk1.setName("꽥꽥이");
dk1.setBirthYear(2004);
dk1.setPrice(5000);
Animal[] animArr = new Animal[7];
animArr[0] = an1; // new Dog();
animArr[1] = an2; // new Cat();
animArr[2] = an3; // new Duck();
animArr[3] = an4; // new Animal();
animArr[4] = dg1;
animArr[5] = ct1;
animArr[6] = dk1;
}
}
-- 배열을 만들어서 값을 저장해 준다.
for(Animal anm : animArr) {
anm.printAnimal(); // 다형성
if(anm instanceof Dog)
((Dog)anm).printDog();
else if(anm instanceof Cat)
((Cat)anm).printCat();
else if(anm instanceof Duck)
((Duck)anm).printDuck();
System.out.println("");
}
if(anm instanceof Dog)
-- anm이 Dog 클래스로 만들어진 instance인지 아닌지 판단한다.
-- 맞다라면 true, 틀리면 false (리턴 값 boolean)
((Dog)anm).printDog();
-- 형변환을 해서 printDog, printCat, printDuck method를 사용해 본다.
-- ((Dog)anm)에서 괄호를 해 주지 않으면 형변환을 나중에 하기 때문에 printAnimal()만 보여 준다.
▷결과
1.Dog Name : 뽀삐
2.Age : 10 살
귀여운 강아지 입니다.
1.강아지명 : 뽀삐
2.나이 : 10 살
3.몸무게 : 0 kg
1.Cat Name : 톰
2.Age : 3 살
예쁜 고양이 입니다.
1.고양이명 : 톰
2.나이 : 3 살
3.피부색 : null 색
1.Duck Name : 도널드
2.Age : 2 살
멋진 오리입니다.
1.오리명 : 도널드
2.나이 : 2 살
3.가격 : 0 원
1.동물명 : 동물
2.나이 : 1 살
1.Dog Name : 멍멍이
2.Age : 18 살
귀여운 강아지 입니다.
1.강아지명 : 멍멍이
2.나이 : 18 살
3.몸무게 : 30 kg
1.Cat Name : 야옹이
2.Age : 17 살
예쁜 고양이 입니다.
1.고양이명 : 야옹이
2.나이 : 17 살
3.피부색 : white 색
1.Duck Name : 꽥꽥이
2.Age : 16 살
멋진 오리입니다.
1.오리명 : 꽥꽥이
2.나이 : 16 살
3.가격 : 5000 원
Ⅱ. 추상(미완성) 클래스, 추상(미완성) 메소드
-- Package(my.day13.c.polymorphism)에 Class 5개(MainApp, Figure, Rectangle, Triangle, Circle)을 생성한다.
-- MainApp클래스에는 main method가 포함되어 있다.
-- 사각형, 삼각형, 원의 넓이를 구하는 함수를 생성하고자 한다.
-- A, B, C, D가 프로젝트를 나눠서 진행한다고 할 때 넓이를 구하는 함수 이름이 다 다르면 찾기 힘들기 때문에
Figure에서 함수 이름을 지정해서 지정한 함수 이름만 사용하도록 막아준다.
// A(P.M)
// 추상(==미완성) 클래스
public abstract class Figure {
// 추상(==미완성) 메소드
public abstract double area(double a, double b);
}
-- 추상(미완성) 메소드가 클래스에 존재하면 추상 메소드가 있는 클래스도 추상(미완성) 클래스가 된다.
-- 클래스와 메소드 앞에 abstract를 추가해 주어야 한다.
-- 추상(미완성) 클래스는 인스턴스화(객체 생성) 할 수 없다.
// B
public class Rectangle extends Figure{
@Override
public double area(double a, double b) {
return Math.round(a*b*10)/10.0;
}
}
// C
public class Triangle extends Figure{
@Override
public double area(double a, double b) {
return Math.round(a*b*0.5*10)/10.0;
}
}
// D
public class Circle extends Figure{
@Override
public double area(double a, double b) {
a=3.14159;
return a*b*b;
}
}
package my.day13.c.polymorphism;
public class MainApp {
public static void main(String[] args) {
Rectangle rt = new Rectangle();
double area = rt.area(5, 4.5);
System.out.println("가로5, 세로4.5인 사각형 면적 : " + area);
Triangle tr = new Triangle();
area = rt.area(6, 4.5);
System.out.println("가로6, 세로4.5인 삼각형 면적 : " + area);
Circle cr = new Circle();
area = rt.area(3.14159, 7);
System.out.println("반지름이 7인 원 면적 : " + area);
}
}
▷결과
가로5, 세로4.5인 사각형 면적 : 22.5
가로6, 세로4.5인 삼각형 면적 : 27.0
반지름이 7인 원 면적 : 22.0
▷▷ method Override를 하는 이유
-- 프로그램은 혼자 개발하는 것이 아니라 여러 사람들이 모여서 하는 것이므로 같은 함수 이름과 변수를 사용해 주어야 main method에서 호출할 때 헷갈리지 않고 찾기 수월하다.
-- 개발 전 약속한 규칙을 강제화 시키는 것이 추상 메소드와 추상 클래스이다.
-- viewInfo() method를 생성한다.
▶▶ Figure 클래스
public abstract class Figure {
public abstract double area(double a, double b);
public void infoTest() {
System.out.println("추상 클래스인 Figure의 infoTest() 메소드 호출함\n");
}
}
▶▶ Rectangle 클래스
public class Rectangle extends Figure{
private int garo;
private int sero;
public int getGaro() {
return garo;
}
public void setGaro(int garo) {
this.garo = garo;
}
public int getSero() {
return sero;
}
public void setSero(int sero) {
this.sero = sero;
}
public void viewRectInfo() {
System.out.println("1.가로 : " + garo + ", 2.세로 : " + sero);
}
}
▶▶ Triangle 클래스
public class Triangle extends Figure{
private int bottom;
private int height;
public int getBottom() {
return bottom;
}
public void setBottom(int bottom) {
this.bottom = bottom;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
public void viewTriInfo() {
System.out.println("1.밑변 : " + bottom + ", 2.높이 : " + height);
}
}
▶▶Circle 클래스
public class Circle extends Figure{
private int radious;
public int getRadious() {
return radious;
}
public void setRadious(int radious) {
this.radious = radious;
}
public void viewCircleInfo() {
System.out.println("반지름 : " + radious);
}
}
문제 ▷▷ 1. Figure 배열 크기가 6인 figArr을 생성하세요.
Figure[] figArr = new Figure[6];
문제 ▷▷ 2. 생성되어진 배열 figArr에 rt, tr, cr 및 new Rectangle();, new Triangle();, new Circle();을 넣으세요.
이 때, new Rectangle(); 은 가로3, 세로4 / new Triangle(); 는 밑변3, 높이4 / new Circle(); 은 반지름 2
figArr[0] = rt;
figArr[1] = tr;
figArr[2] = cr;
figArr[3] = new Rectangle();
((Rectangle)figArr[3]).setGaro(3);
((Rectangle)figArr[3]).setSero(4);
figArr[4] = new Triangle();
((Triangle)figArr[4]).setBottom(3);
((Triangle)figArr[4]).setHeight(4);
figArr[5] = new Circle();
((Circle)figArr[5]).setRadious(2);
문제 ▷▷ 3. 생성되어진 배열 figArr을 사용하여 각 도형마다 면적을 나타내고 viewXXXInfo()를 출력하세요.
for(Figure fig : figArr) {
if(fig instanceof Rectangle) {
int garo = ((Rectangle)fig).getGaro();
int sero = ((Rectangle)fig).getSero();
System.out.println("사각형의 넓이 : "+ fig.area(garo,sero));
((Rectangle)fig).viewRectInfo();
System.out.println("");
}
else if(fig instanceof Triangle) {
int bottom = ((Triangle)fig).getBottom();
int height = ((Triangle)fig).getHeight();
System.out.println("삼각형의 넓이 : "+ fig.area(bottom, height));
((Triangle)fig).viewTriInfo();
System.out.println("");
}
else if(fig instanceof Circle) {
int radious = ((Circle)fig).getRadious();
System.out.println("원의 넓이 : "+ fig.area(3.14159, radious));
((Circle)fig).viewCircleInfo();
System.out.println("");
}
}
-- 모든 클래스의 원뿌리는 Object 이므로 생략하더라도 자동적으로 상속되어 있다.
-- MainApp에서 부모 클래스를 따로 지정하지 않았지만 Object 메소드를 사용할 수 있는 걸 볼 수 있다.
public class MainApp {
public static void main(String[] args) {
(생략)
for(Figure fig : figArr) {
if(fig instanceof Rectangle) {
System.out.println(fig);
System.out.println(fig.toString());
}
}
}
▷ 결과
my.day13.c.polymorphism.Rectangle@4e25154f
my.day13.c.polymorphism.Rectangle@4e25154f
-- System.out.println(fig);과 System.out.println(fig.toString());는 똑같은 결과를 나타낸다.
public class Rectangle extends Figure{
(생략)
@Override
public String toString() {
String result = "호호호하하하 나는 사각형";
return result;
}
▷ 결과
-- 결과 값이 바뀐다.
@Override
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append("== Rectangle 객체 정보 ===\n");
sb.append("1. garo : " + garo + "\n");
sb.append("2. sero : " + sero + "\n");
return sb.toString();
}
▷ 결과
다형성(Polymorphism)을 이용하여 구직자 관련 프로그램을 작성해 보자.
-- 코드는 day12.d를 참조하였다.
public static void main(String[] args) {
// 구직자 및 구인회사로 가입된 Gujikja 객체와 Company 객체를 저장시키는 공간
Member[] memArr = new Member[9];
memArr[0] = new Gujikja("hongkd", "Qwer1234$", "홍길동", "19930311", 1, 1, 4000);
memArr[1] = new Gujikja("eomjh", "Qwer1234$", "엄정화", "19830311", 2, 2, 5000);
memArr[2] = new Gujikja("leess", "Qwer1234$", "이순신", "20010919", 1, 2, 3000);
memArr[3] = new Company("samsung","Qwer1234$","삼성",300000000000L,"제조업");
memArr[4] = new Company("lgelectronic","Qwer1234$","엘지전자",250000000000L,"서비스업");
}
-- Gujikja, Company 따로 저장되어 있던 것을 Member로 한 번에 저장한다.
Gujikja loginMember = null;
-- loginUser와 loginCompany를 loginMember로 합쳐 준다.
-- 오류가 난 gujaArr, compArr 변수와 함수 이름을 memArr, Member로 바꿔 준다.
-- loginMember는 똑같이 쓰지만 출력 메시지는 "이미 구직자로 로그인 되어진 상태입니다."와 "이미 구인회사로 로그인 되어진 상태입니다."와 같이 두 가지로 나뉘어서 출력되어져야 한다.
▶▶ case 2: 로그인
case "2":
if(loginMember != null &&
loginMember instanceof Gujikja)
System.out.println(">> 이미 구직자로 로그인 되어진 상태입니다.\n");
else if(loginMember != null &&
loginMember instanceof Company)
System.out.println(">> 이미 구인회사로 로그인 되어진 상태입니다.\n");
else
loginMember = loginGujikja(sc, memArr);
break;
-- 로그인 메소드에서 gujaArr, compArr가 아니라 memArr에 저장된 값을 받아와서 비교해야 한다.
▶▶ 구직자로 로그인 함수
static Gujikja loginGujikja(Scanner sc, Member[] memArr) {
Gujikja loginUser = null;
System.out.print("◆ 아이디 : ");
String userid = sc.nextLine();
System.out.print("◆ 암호 : ");
String passwd = sc.nextLine();
boolean flag = false;
for(int i=0; i<memArr.length; i++) {
if( memArr[i] != null &&
memArr[i].isExists(userid, passwd) &&
memArr[i] instanceof Gujikja) {
flag = true;
loginUser = (Gujikja)memArr[i];
break;
}
}
if(flag==true)
System.out.println(">> 구직자로 로그인 성공!! <<\n");
else
System.out.println(">> 구직자로 로그인 실패!! <<\n");
return loginUser;
}
▶▶ 구인회사로 로그인 함수
static Company loginCompany(Scanner sc, Member[] memArr) {
Company loginComp = null;
System.out.print("▶아이디 : ");
String id = sc.nextLine();
System.out.print("▶암 호 : ");
String passwd = sc.nextLine();
boolean flag = false;
for(int i=0; i<memArr.length; i++) {
if(memArr[i] != null &&
memArr[i].isExists(id, passwd) ) {
loginComp = (Company)memArr[i];
flag = true;
break;
}
}
if(flag)
System.out.println(">> 구인회사로 로그인 성공!!\n");
else
System.out.println(">> 구인회사로 로그인 실패!!\n");
return loginComp;
}
▶▶case 3 : 로그아웃
case "3":
if(loginMember != null &&
loginMember instanceof Gujikja) { // 구직자로 로그인 되어진 상태
loginMember = null;
System.out.println(">> 구직자로 로그아웃 되었습니다.\n");
}
else if(loginMember != null &&
loginMember instanceof Company) { // 구인회사로 로그인 되어진 상태
loginMember = null;
System.out.println(">> 구인회사로 로그아웃 되었습니다.\n");
}
else
System.out.println(">> 로그인을 한 후에 로그아웃을 할 수 있습니다.\n");
break;
▶▶ case 4 : 나의 정보 조회
-- showGujikjaInfo()와 showCompanyInfo()를 삭제하고, Member 클래스에 viewInfo()를 만들어 Gujikja클래스와 Company 클래스에 오버라이딩 후 구직자 정보와 구인회사 정보를 나타내는 함수를 만든다.
case "4":
if(loginMember == null) {
System.out.println(">> 먼저 로그인 하세요!!\n");
}
else {
loginMember.viewInfo();
}
break;
▶ Member 클래스를 추상 클래스로 만들고, viewInfo 추상 메소드를 만든다.
public abstract class Member {
public abstract void viewInfo();
}
public class Gujikja extends Member {
@Override
public void viewInfo() {
String result = "";
result += "1.아이디 : " + super.getId() + "\n";
result += "2.암 호 : " + super.getPasswd() + "\n";
result += "3.성 명 : " + super.getName() + "\n";
result += "4.생년월일 : " + birthday.substring(0, 4)+"-"+birthday.substring(4, 6)+"-"+birthday.substring(6)+"\n";
String strGender = "";
if(gender == 1)
strGender = "남";
else
strGender = "여";
result += "5.성 별 : "+strGender+"\n";
String strSchool = "";
if(school == 1)
strSchool = "대졸이상";
else if(school == 2)
strSchool = "초대졸";
else if(school == 3)
strSchool = "고졸";
else
strSchool = "고졸미만";
result += "6.학 력 : "+strSchool+"\n";
result += "7.희망연봉 : "+hopeMoney+"만원\n";
System.out.println(result+"\n");
}
}
@Override
public void viewInfo() {
String result = "";
// 부모클래스의 객체(지금은 Member클래의 객체)를 나타내어주는 대명사가 super 이다.
result += "1.아이디 : " + super.getId() + "\n";
result += "2.암 호 : " + super.getPasswd() + "\n";
result += "3.회사명 : " + super.getName() + "\n";
result += "4.자본금 : " + seedMoney + "\n";
result += "5.업 종 : " + jobType + "\n";
System.out.println(result+"\n");
}
▶▶ case 5 : 모든 구직자 정보 조회
case "5":
if (loginMember != null && loginMember instanceof Company) {
for (int i = 0; i < memArr.length; i++) {
if (memArr[i] != null && memArr[i] instanceof Gujikja)
memArr[i].viewInfo();
}
} else {
System.out.println(">> 먼저 구인회사로 로그인 하세요.");
}
break;
-- 완성 코드 첨부
'수업내용' 카테고리의 다른 글
[Day14][Java] Exception(예외) / 제품 주문 관리 프로그램 (0) | 2019.09.06 |
---|---|
[Day13][Java] Overloading(오버로딩) / final(예약어) / interface(인터페이스) (0) | 2019.09.05 |
[Day11][Java] 캡슐화 / 다형성 (0) | 2019.09.03 |
[Day10][Java] 상속 / 구인구직 관리 프로그램 (0) | 2019.09.02 |
[Day9][Java] 이차원 배열 / String 클래스 메소드 / 로또 당첨 프로그램 / Calendar / OOP(Object Oriented Programming) (0) | 2019.09.01 |