본문 바로가기

수업내용

[Day12][Java] 다형성 / 추상 메소드 / 추상 클래스

Ⅰ. 다형성

 

-- 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()이라고 똑같이 써 주어야 한다.

 

 

Animal 클래스의 printAnimal method

 

 

Dog 클래스의 printanimal method

 

 

 

 

 

 

 

-- printAnimal method를 만들려고 했으나 실수로 printanimal 이라고 작성하였을 때, main method에서 printAnimal method를 호출하였을 경우 Animal 클래스의 printAnimal을 호출하게 된다.

 

 

Dog 클래스의 printanimal method

 

 

-- 잘못 타이핑 한 것을 알려 주고 방지하기 위해 위에 @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.zip
0.01MB

-- 코드는 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;

 

 

day13.zip
0.01MB

-- 완성 코드 첨부