추상 클래스

사전적 의미로 추상(abstract)은 실체 간에 공통되는 특성을 추출한 것을 말한다.

예를 들어 새, 곤충, 물고기 등의 실체에서 공통되는 특성을 추출해보면 동물이라는 공통점이 있다.

여기서 동물은 구체적인 실체라기 보다는 실체들의 공통되는 특성을 가지고 있는 추상적인 것이라고 볼 수 있다.

 

객체를 직접 생성할 수 있는 클래스를 실체 클래스라고 한다면 이 클래스들의 공통적인 특성을 추출해서 

선언한 클래스를 추상 클래스라고 한다. 추상 클래스와 실체 클래스는 상속의 관계를 가지고 있다.

추상 클래스가 부모, 실체 클래스가 자식으로 구현되어 실체 클래스는 충상 클래스의 모든 특성을 물려받고,

추가적인 특성을 가질 수 있다. ( 특성은 필드와 메소드를 말함 )

 

 

추상 클래스의 용도

실체 클래스의 공통적인 특성(필드, 메소드)을 뽑아내어 추상 클래스를 만드는 이유는 2가지가 있다.

 

1. 공통된 필드와 메소드의 이름을 통일할 목적

실체 클래스를 설계하는 사람이 여러 사람일 경우, 실체 클래스마다 필드와 메소드가 제각기 다른 이름을 

가질 수 있다. 예) Phone이라는 추상 클래스에 소유자인 owner 필드와 turnOn() 메소드를 선언하고,

Telephone과 SmartPhone을 상속함으로써 필드와 메소드 이름을 통일할 수 있다.

 

2. 실체 클래스를 작성할 때 시간 절약

공통적인 필드와 메소드는 추상 클래스인 Phone에 모두 선언해두고, 다른 점만 실체 클래스에 선언하면

실체 클래스를 작성하는데 시간을 절약할 수 있다.

 

 

 

일반적으로 개발 프로젝트에서 설계자와 코더(코드를 작성하는 사람)는 다른 일을 수행한다.

설계자는 코더에게 클래스는 어떤 구조로 작성해야 한다는 것을 알려주어야 한다.

이를 단순히 문서로 전달한다면, 코더가 실수로 필드와 메소드 이름을 다르게 코딩할 수 도 있다.

코더가 작성해야 할 클래스가 다수이고 이 클래스들이 동일한 필드와 메소드를 가져야 할 경우, 설계자는

이 내용들을 추려내어 추상 클래스로 설계 규격을 만드는 것이 좋다. 그리고 코더에게 추상 클래스를 상속해서

구체적인 클래스를 만들도록 요청하면 된다.

 

 

 

추상 클래스 선언

추상 클래스를 선언할 때에는 클래스 선언에 abstract 키워드를 붙여야 한다.

abstract를 붙이면 new 연산자를 이용해서 객체를 만들지 못하고, 상속을 통해 자식 클래스만 만들 수 있다.

public abstract class 클래스 {
//필드
//생성자
//메소드
}
실체 클래스 생성

추상 클래스는 실체 클래스의 공통되는 필드와 메소드를 추출해서 만들었기 때문에 
객체를 직접 생성해서 사용할 수 없다.
Animal animal = new Animal(); <= X

추상 클래스는 새로운 실체 클래스를 만들기 위해 부모 클래스로만 사용된다.
코드로 설명하면 추상 클래스는 extends 뒤에만 올 수 있는 클래스이다.
Class Ant extends Animal {...} <= O

 

추상 클래스 실습 

package sec03.exam01;
// 추상클래스 basic
public abstract class Aaa {
	
	public static void main(String[] ar) {
//		Aaa a1 = new Aaa(); 추상클래스는 객체 생성 불가
		
		Baa a2 = new Baa();
		Aaa a3 = a2; // 필드 다형성
		
		
	}
}

class Baa extends Aaa {
	
}

 

 

 

추상 메소드와 재정의

추상 클래스는 실체 클래스가 공통적으로 가져야 할 필드와 메소드들을 정의해놓은 추상적인 클래스로

실체 클래스의 멤버(필드, 메소드)를 통일하는 데 목적이 있다. 모든 실체들이 가지고 있는 메소드의 실행

내용이 동일하다면 추상 클래스에 메소드를 작성하는 것이 좋을 것이다.

하지만 반대로 메소드의 선언만 통일하고, 실행 내용은 실체 클래스마다 달라야 하는 경우도 있는데 예를

들어서 모든 동물은 소리를 내기 때문에 sound(); 라는 메소드를 추상 클래스에 정의를 하고 각각 동물의

소리는 실체 클래스에서 직접 다르게 재정의하면 된다.

추상 메소드는 abstract 키워드와 함께 메소드의 선언부만 있고 메소드 실행 내용인 중괄호{}가 없는 메소드

[public | protected] abstract 리턴타입 메소드이름(매개변수, ...);

추상 클래스 설계 시 하위 클래스가 반드시 실행 내용을 채우도록 강제하고 싶은 메소드가 있을 경우 해당 

메소드를 추상 메소드로 선언한다. 자식 클래스는 반드시 추상 메소드를 재정의해서 실행 내용을 작성해야 하는데,

그렇지 않으면 컴파일 에러가 발생한다.

공통적인 특징을 규정하기 위해 sound() 메소드를 추상 메소드로 선언 방법

public abstract class Animal {
	public abstract void sound();
}

 

 

Animal 클래스를 상속하는 하위 클래스는 동물마다 고유한 소리를 내도록 sound()메소드를 재정의해야 한다

Dog와 Cat 클래스에서 sound() 메소드를 재정의해야 한다.

 

추상 메소드 재정의 실습 1

추상 메소드 선언


package sec03.exam01;
// 추상 메소드 선언 basic
public abstract class Aaa2 {
	void method() {
		
	}
	abstract void method2();// 추상 메소드
}


추상 메소드 재정의
package sec03.exam01;
// 추상 메소드 재정의 basic
public class Bbb extends Aaa2 {

	@Override
	void method2() {
		// TODO Auto-generated method stub
		
	}

}

 

 

추상 메소드 재정의 실습 2

추상 메소드 선언


package sec03.exam02;

// 추상클래스, 추상메소드 선언
public abstract class Animal { // 추상클래스
	public String kind;
	
	public void breathe() {
		System.out.println("숨을 쉽니다.");
	}
	
	public abstract void sound(); // 추상 메소드
}



추상 메소드 재정의 1

package sec03.exam02;
//추상 메소드 재정의
public class Cat extends Animal {
	public Cat() {
		this.kind = "포유류";
	}

	@Override
	public void sound() { 
		System.out.println("야옹");
		
	}
	
	
}

추상 메소드 재정의 2
package sec03.exam02;
//추상 메소드 재정의
public class Dog extends Animal {
	public Dog() {
		this.kind = "포유류";
	}

	@Override
	public void sound() { // 추상 메소드 재정의
		System.out.println("멍멍");
		
	}
	
	
}



실행
package sec03.exam02;
// 실행 
public class AnimalEx {

	public static void main(String[] args) {
		Dog dog = new Dog();
		Cat cat = new Cat();
		dog.sound();
		cat.sound();
		System.out.println("-----");
		
		//변수의 자동 타입 변환
		Animal animal = null;
		animal = new Dog();// 자동 타입 변환 및 재정의된 메소드 호출
		animal.sound();
		animal= new Cat();// 자동 타입 변환 및 재정의된 메소드 호출
		animal.sound();
		System.out.println("-----");
	
		//메소드의 다형성
		animalSound(new Dog());
		animalSound(new Cat());
		
	
	}
	public static void animalSound(Animal animal) {
		animal.sound();// 재정의된 메소드 호출
	}
	
}
<결과>
멍멍
야옹
-----
멍멍
야옹
-----
멍멍
야옹

 

추상 메소드 재정의 실습 3

추상 메소드 선언

package sec03.exam03;

public abstract class Http {// 추상클래스
	public abstract void service();
}


추상 메소드 재정의 1
package sec03.exam03;

public class HttpChild extends Http { 

	@Override
	public void service() {
		System.out.println("로그인 합니다.");
		
	}

	
	
}


추상 메소드 재정의 2
package sec03.exam03;

public class HttpChild2 extends Http {

	@Override
	public void service() {
		System.out.println("파일 다운로드합니다.");
		
	}
	
}


실행
package sec03.exam03;

public class HttpEx {

	public static void main(String[] args) {
		method(new HttpChild());
		method(new HttpChild2());

	}
	public static void method(Http http) {
		http.service();
	}
	

}
<결과>
로그인 합니다.
파일 다운로드합니다.

 

 

 

 

 

인터페이스

자바에서 인터페이스는 객체의 사용 방법을 정의한 타입이다.

인터페이스를 통해 다양한 객체를 동일한 사용 방법으로 이용할 수 있다.

인터페이스에 장점 중 하나는 개발 코드를 수정하지 않고 사용하는 객체를 변경할 수 있도록하는 장점이 있다.

인터페이스는 하나의 객체가 아니라 여러 객체들과 사용이 가능하므로 어떤 객체를 사용하느냐에 따라서 실행

내용과 리턴값이 다를 수 있다. 따라서 개발 코드 측면에서는 코드 변경없이 실행 내용과 리턴값을 다양화할 수

있다는 장점을 가지게 된다.

 

인터페이스 선언

인터페이스 선언은 class 키워드 대신에 interface 키워드를 사용한다.

인터페이스 이름은 클래스 이름을 작성하는 방법과 동일하다.

[public] interface 인터페이스이름 {...}

 

 

클래스는 필드, 생성자, 메소드를 구성 멤버로 가지는데 비해, 인터페이스는 상수 필드와 추상 메소드만을 구성 멤버로

가진다. 인터페이스는 객체로 생성할 수 없기 때문에 생성자를 가질 수 없다.

 

상수 필드 선언

인터페이스는 객체 사용 방법을 정의한 것이므로 실행 시 데이터를 저장할 수 있는 인스턴스 또는 정적 필드를 선언

할 수 없다. 그러나 상수필드는 선언이 가능하다. 단, 상수는 인터페이스에 고정된 값으로 실행 시에 데이터 변경 불가

따라서 인터페이스에 선언된 필드는 모두 public static final의 특성을 갖는다. public static final을 생략하더라도

컴파일 과정에서 자동으로 붙게 된다.

[public static final] 타입 상수이름 = 값;
상수 필드 선언

public interface RemoteControl {
	
	public int MAX_VOLUME = 10;
	public int MIN_VOLUME = 0;
    }

 

 

 

추상 메소드 선언

인터페이스를 통해 호출된 메소드는 최종적으로 객체에서 실행된다. 그렇기 때문에 인터페이스의 메소드는

실행 블록이 필요 없는 추상 메소드로 선언한다. 추상 메소드는 리턴 타입, 메소드이름, 매개 변수만 기술되고

중괄호{ }를 붙이지 않는 메소드를 말한다. 인터페이스에 선언된 추상 메소드는 모두 public abstract의 특성을

갖기 때문에 public abstract를 생략하더라도 컴파일 과정에서 자동으로 붙게 된다.

 

상수필드, 추상 메소드 선언

package sec01.exam01;
// 상수필드, 추상 메소드 선언
public interface RemoteControl {
	// 상수
	public int MAX_VOLUME = 10;
	public int MIN_VOLUME = 0;
	
	// 추상 메소드
	public void trunOn();
	public void trunOff();
	public void setVolume(int volme); // 메소드 선언부만 작성
}

 

 

 

인터페이스 구현

개발 코드가 인터페이스 메소드를 호출하면 인터페이스는 객체의 메소드를 호출한다. 객체는 인터페이스에서

정의된 추상 메소드와 동일한 메소드 이름, 매개 타입, 리턴 타입을 가진 실체 메소드를 가지고 있어야 한다.

이러한 객체를 인터페이스의 구현 객체라고 하고, 구현 객체를 생성하는 클래스를 구현 클래스라고 한다.

 

구현 클래스

구현 클래스는 보통의 클래스와 동일한데, 인터페이스 타입으로 사용할 수 있음을 알려주기 위해 클래스 선언부에

implements 키워드를 추가하고 인터페이스 이름을 명시해야 한다. 그리고 인터페이스에 선언된 추상 메소드의 

실체 메소드를 선언해야 한다.

public class 구현클래스이름 implements 인터페이스이름 {
	//인터페이스에 선언된 추상 메소드의 실체 메소드 선언
}
구현 클래스 1

package sec01.exam01;

public class Television implements RemoteControl {
	// 필드
	private int volume;
	
	
	@Override
	public void trunOn() {
		System.out.println("Tv를 켭니다.");
		
	}

	@Override
	public void trunOff() {
		System.out.println("Tv를 끕니다.");
		
	}

	@Override
	public void setVolume(int volme) {// 인터페이스 상수를 이용 volume필드의 값을 제한
		if(volme > RemoteControl.MAX_VOLUME) {
			this.volume = RemoteControl.MAX_VOLUME;
		}else if(volme < RemoteControl.MIN_VOLUME) {
			this.volume = RemoteControl.MIN_VOLUME;
		}else {
			this.volume = volme;
		}
		System.out.println("현재 TV 볼륨 : " + this.volume);
	}



}


구현 클래스 2

package sec01.exam01;
// 구현 클래스
public class Audio implements RemoteControl{
	// 필드
	private int volume;
	
	@Override
	public void trunOn() {
		System.out.println("Audio를 켭니다.");
		
	}

	@Override
	public void trunOff() {
		System.out.println("Audio를 끕니다.");
		
	}

	@Override
	public void setVolume(int volme) {// 인터페이스 상수를 이용 volume필드의 값을 제한
		if(volme > RemoteControl.MAX_VOLUME) {
			this.volume = RemoteControl.MAX_VOLUME;
		}else if(volme < RemoteControl.MIN_VOLUME) {
			this.volume = RemoteControl.MIN_VOLUME;
		}else {
			this.volume = volme;
		}
		System.out.println("현재 Audio 볼륨 : " + this.volume);
	}

}

 

구현 클래스가 작성되면 new 연산자로 객체를 생성할 수 있다. 하지만 다음 코드는 인터페이스를 사용한 것이 아님

Television tv = new Television();

인터페이스로 구현 객체를 사용하려면 다음과 같이 인터페이스 변수를 선언하고 구현 객체를 대입해야 한다.

인터페이스 변수는 참조 타입이기 때문에 구현 객체가 대입될 경우 구현 객체의 번지를 저장한다.

인터페이스 변수에 구현 객체 대입

package sec01.exam01;

public class RemoteConEx {
	
	

	public static void main(String[] args) {
		RemoteControl rc;
		rc = new Television();
		//rc.trunOn();
		//rc.setVolume(5);
//		excute(rc, 7);
		
		
//		rc = new Audio();
//		//rc.setVolume(6);
//		//rc.trunOff();
//		excute(rc, 5);
		
//		Searchable se = new Television();
//		se.search("www.naver.com");
		
//		Searchable se = (Searchable) rc;
//		se.search("www.naver.com");

	}
	
	public static void excute(RemoteControl rc, int vol) { // 해당 코드로 메서드 모두 호출 가능
		rc.trunOn();
		rc.trunOff();
		rc.setVolume(vol);
	}
}

 

 

 

다중 인터페이스 구현 클래스

객체는 다음 그림과 같이 다수의 인터페이스 타입으로 사용할 수 있다.

인터페이스 A와 인터페이스 B가 객체의 메소드를 호출할 수 있으려면 객체는 이 두 인터페이스를 모두 구현해야

한다. 따라서 구현 클래스는 위에 코드 처럼 작성되어야 한다.

다중 인터페이스를 구현할 경우, 구현 클래스는 모든 인터페이스의 추상 메소드에 대해 실체 메소드를 작성해야 한다.

 

다음은 인터넷을 검색할 수 있는 Searchable 인터페이스 이다. search() 추상 메소드는 매개값으로 인터넷 웹사이트

주소 ( URL )를 받습니다.

인터넷 검색할 수있는 search() 메소드

package sec01.exam01;

public interface Searchable {
	void search(String url);
}

만약 SmartTelevision이 인터넷 검색 기능도 제공한다면 다음과 같이 RemoteControl과 Searchable을 모두 구현한

SmartTelevision 클래스를 작성할 수 있다.

다중 인터페이스 구현 클래스

package sec01.exam01;
// 구현 클래스
public class SmartTelevision implements RemoteControl, Searchable {
	// 필드
	private int volume;
	 
	
	@Override
	public void trunOn() {
		System.out.println("Tv를 켭니다.");
		
	}

	@Override
	public void trunOff() {
		System.out.println("Tv를 끕니다.");
		
	}

	@Override
	public void setVolume(int volme) {
		if(volme > RemoteControl.MAX_VOLUME) {
			this.volume = RemoteControl.MAX_VOLUME;
		}else if(volme < RemoteControl.MIN_VOLUME) {
			this.volume = RemoteControl.MIN_VOLUME;
		}else {
			this.volume = volme;
		}
		System.out.println("현재 TV 볼륨 : " + this.volume);
	}
	
    // Searchable search()메소드 재정의
	@Override
	public void search(String url) {
		System.out.println(url + "을 검색합니다.");
		
	}

}

SmartTelevision 클래스는 RemoteControl과 Searchable 인터페이스를 모두 구현하고 있기 때문에 다음 예제와 같이

SmartTelevision 객체를 RemoteControl 타입 변수와 Searchable 타입 변수에 각각 대입할 수 있다.

인터페이스 변수에 구현 객체 대입

package sec01.exam01;

public class SmartTelevisionEx {

	public static void main(String[] args) {
		SmartTelevision tv = new SmartTelevision();
		
		RemoteControl rc = tv;
		Searchable searchable = tv;
		
	}

}

 

 

 

인터페이스 사용

구현 객체가 인터페이스 변수에 대입된다는 것을 알았았으니, 지금부터 인터페이스로 구현 객체를 사용하는 방법을

알아보겠습니다.

클래스를 선언할 때 인터페이스는 필드, 생성자 또는 메소드의 매개변수, 생성자, 또는 메소드의 로컬 변수로 선언될

수 있습니다.

 

인터페이스 사용_선언

package sec01.exam01;

public class MyClass {
	// 필드
	RemoteControl rc = new Television();

	// 생성자
	MyClass() {
	}

	MyClass(RemoteControl rc) {
		this.rc = rc;
		rc.trunOn();
		rc.setVolume(5);
	}

	// 메소드
	void methodA() {
		RemoteControl rc = new Audio();
		rc.trunOn();
		rc.setVolume(5);
	}

	void methodB(RemoteControl rc) {
		rc.trunOn();
		rc.setVolume(5);
	}
}


인터페이스 사용_실행

package sec01.exam01;

public class MyClassEx {

	public static void main(String[] args) {
		System.out.println("1)----------------");
		
		MyClass myClass1 = new MyClass();
		myClass1.rc.trunOn();
		myClass1.rc.setVolume(5);
		
		System.out.println("2)----------------");
		
		MyClass myClass2 = new MyClass(new Audio());
		
		System.out.println("3)----------------");
		
		MyClass myClass3 = new MyClass();
		myClass3.methodA();
		
		System.out.println("4)----------------");
		
		MyClass myClass4 = new MyClass();
		myClass4.methodB(new Television());
	}
}
<결과>
1)----------------
Tv를 켭니다.
현재 TV 볼륨 : 5
2)----------------
Audio를 켭니다.
현재 Audio 볼륨 : 5
3)----------------
Audio를 켭니다.
현재 Audio 볼륨 : 5
4)----------------
Tv를 켭니다.
현재 TV 볼륨 : 5

 

 

실습해보기

인터페이스 연습 1 

인터페이스 정의

package sec01.exam03;

public interface Figure {
	void draw();
}


인터페이스 구현 1

package sec01.exam03;

public class Circle implements Figure {

	@Override
	public void draw() {
		System.out.println("Circle의 draw 메소드");
		
	}
	
}


인터페이스 구현 2
package sec01.exam03;

public class Rectangle implements Figure {

	@Override
	public void draw() {
		System.out.println("Rectangle의 draw 메소드");
		
	}
	
}


인터페이스 구현 3

//인터페이스 구현3

package sec01.exam03;

public class Square implements Figure {

	@Override
	public void draw() {
		System.out.println("Square의 draw 메소드");
		
	}

}


구현한 인터페이스 정의

package sec01.exam03;

public class FigureFactory {
	public Figure getFigure(String figureType) {
		if(figureType == null) {
			return null;
		}
		// equalsIgnoreCase => 대소문자 상관없이 비교 
		if (figureType.equalsIgnoreCase("CIRCLE")) {
			return new Circle();
		}else if (figureType.equalsIgnoreCase("RECTANGLE")) {
			return new Rectangle();
		}else if (figureType.equalsIgnoreCase("SQUARE")) {
			return new Square();
		}
		
		return null;
	}
}


실행

package sec01.exam03;

public class FactoryPatternEx {

	public static void main(String[] args) {
		FigureFactory figureFactory = new FigureFactory();
		
		Figure fig1 = figureFactory.getFigure("CIRCLE");
		
		// Circle의 draw 메소드 호출
		fig1.draw();
		
		Figure fig2 = figureFactory.getFigure("RECTANGLE");
		
		// RECTANGLE의 draw 메소드 호출
		fig2.draw();
		
		Figure fig3 = figureFactory.getFigure("SQUARE");
		
		// SQUARE의 draw 메소드 호출
		fig3.draw();
			
	}

}
<결과>
Circle의 draw 메소드
Rectangle의 draw 메소드
Square의 draw 메소드

 

인터페이스 연습 2

인터페이스 선언

package sec01.exam03_1;

public interface Animal {
	void eat();
}


다중 인터페이스 선언

package sec01.exam03_1;

public interface Bird extends Animal {
	void fly();
}


인터페이스 재정의
package sec01.exam03_1;

public class Sparrow implements Bird {

	@Override
	public void eat() {
		System.out.println("먹는다.");
		
	}

	@Override
	public void fly() {
		System.out.println("날아오른다.");
		
	}

}


실행

package sec01.exam03_1;

public class SparrowEx {

	public static void main(String[] args) {
		Sparrow sparrow = new Sparrow();
		sparrow.eat();
		sparrow.fly();

	}

}
<결과>
먹는다.
날아오른다.

 

인터페이스 연습 3

인터페이스 선언

package sec01.exam03_3;

public interface Calculator {
	void add(int a, int b);
	void subtract(int a, int b);
}


다중 인터페이스 구현 1

package sec01.exam03_3;

public interface Adder extends Calculator {
	void add(int a, int b);
}


다중 인터페이스 구현 2

package sec01.exam03_3;

public interface Subtractor extends Calculator {
	void subtract(int a, int b);
}


인터페이스 재정의 1

package sec01.exam03_3;

public class AdderClass implements Adder {

	@Override
	public void subtract(int a, int b) {
		

	}

	@Override
	public void add(int a, int b) {
		int add = a+b;
		System.out.println("더하기 = " + add);
	}
	


}


인터페이스 재정의 2

package sec01.exam03_3;

public class SubtractorClass implements Subtractor {

	@Override
	public void add(int a, int b) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void subtract(int a, int b) {
		int subtract = a-b;
		System.out.println("빼기 = " + subtract);
		
	}

}


실행

package sec01.exam03_3;

public class Main {

	public static void main(String[] args) {
		AdderClass adderClass = new AdderClass();
		adderClass.add(10, 20);
		
		SubtractorClass subtractorClass = new SubtractorClass();
		subtractorClass.subtract(20, 10);
	}

}
<결과>
더하기 = 30
빼기 = 10

 

'프로젝트 기반 자바(JAVA) 응용 SW개발자 취업과정' 카테고리의 다른 글

2023-06-12 17일차  (1) 2023.06.12
2023-06-09 16일차  (0) 2023.06.09
2023-06-07 14일차  (0) 2023.06.07
2023-06-02 13일차  (0) 2023.06.02
2023-06-01 12일차  (0) 2023.06.01

 

Animal_java

메소드 클래스 

package jsp0607;

public class Dog extends Animal {

	@Override
	public String eat() {
		
		return "멍멍";
	}
	
}

package jsp0607;

public class Cat extends Animal {

	@Override
	public String eat() {
		
		return "야옹";
	}

}

package jsp0607;

public class Pig extends Animal {

	@Override
	public String eat() {
		
		return "꿀꿀";
	}
	
	
}
부모

package jsp0607;

public class Animal {
	public String eat() {
		return "먹는다";
	}
}
Animal을 이용하는 클래스

package jsp0607;

public class Feed {
	public String feed(Animal animal) {
		return animal.eat();
		
	}
}

 

form_JSP

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<form action="animalPerson.jsp">  
  <label for="animal">동물 선택</label>
  <select name="animal">
    <option selected>선택</option>
    <option value="dog" >개</option>
    <option value="cat">고양이</option>
    <option value="pig">돼지</option>
    <input type="submit">
  </select>
</form>
</body>
</html>

 

Person_JSP

<%@page import="jsp0607.Pig"%>
<%@page import="jsp0607.Dog"%>
<%@page import="jsp0607.Cat"%>
<%@page import="jsp0607.Animal"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ page import="jsp0607.Feed" %>
<%
//전송된 동물 값(parameter)을 가져옴
String animal = request.getParameter("animal");
Feed feed = new Feed();
Animal animals;
Cat cat = new Cat();
Dog dog = new Dog();
Pig pig = new Pig();

%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<% 
// 선택된 동물이 "dog"인지 확인
if(animal.equals("dog")){
	//feed.feed(dog)를 호출하여 Feed 클래스의 feed() 메서드를 실행
	//이 때, dog 객체를 인자로 전달
	
	%><%=feed.feed(dog) %><% 
}else if(animal.equals("cat")){
	%><%=feed.feed(cat) %><%
}else if(animal.equals("pig")){
	%><%=feed.feed(pig) %><%
}
%>
</body>
</html>

Person_java

package jsp0607;

public class Person {
	private String name;
	private String address;
	private String phone;
	private String email;
	private int birthday; // 예) 19880607
	
	
	
	
	@Override
	public String toString() {
		return "Person [name=" + name + ", address=" + address + ", phone=" + phone + ", email=" + email + ", birthday="
				+ birthday + "]";
	}

	public Person() {} // 기본 생성자 필요 
	// 생성자
	public Person(String name, String address, String phone, String email, int birthday) {
		super();
		this.name = name;
		this.address = address;
		this.phone = phone;
		this.email = email;
		this.birthday = birthday;
	}
	
	
	// Getter, Setter
	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getAddress() {
		return address;
	}

	public void setAddress(String address) {
		this.address = address;
	}

	public String getPhone() {
		return phone;
	}

	public void setPhone(String phone) {
		this.phone = phone;
	}

	public String getEmail() {
		return email;
	}

	public void setEmail(String email) {
		this.email = email;
	}

	public int getBirthday() {
		return birthday;
	}

	public void setBirthday(int birthday) {
		this.birthday = birthday;
	}
	
	
	
	
}

 

 

form_JSP

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<form action="person.jsp">
<a>이름 입력=></a><input type="text" name="name"></br>
<a>주소 입력=></a><input type="text" name="adress"></br>
<a>번호 입력=></a><input type="text" name="phone"></br>
<a>이메일 입력=></a><input type="text" name="email"></br>
<a>생년월일 입력=></a><input type="text" name="day"></br>
<input type="submit">
<input>
</form>
</body>
</html>

 

 

Person_JSP

<%@page import="java.util.jar.Attributes.Name"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ page import="jsp0607.Person" %>
<%
Person person = new Person();
//person.setName("홍길동");
//System.out.println(person);
String name = request.getParameter("name");
person.setName(name);
String adress = request.getParameter("adress");
person.setAddress(adress);
String phone = request.getParameter("phone");
person.setPhone(phone);
String email = request.getParameter("email");
person.setEmail(email);
String day = request.getParameter("day");
int days = Integer.parseInt(day);
person.setBirthday(days);


%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<%
out.println(person.getName());
out.println(person.getAddress());
out.println(person.getPhone());
out.println(person.getEmail());
out.println(person.getBirthday());
%>
</body>
</html>

 

매개 변수의 다형성

다형성 : 객체 사용 방법은 동일하지만 실행결과가 다양하게 나오는 성질을 말함
기능 수정 x, 기능 추가 
 
자동 타입 변환은 필드의 값을 대입할 때에도 발생하지만, 주로 메소드를 호출할 때 많이 발생
메소드를 호출할 때에는 매개 변수의 타입과 동일한 매개값을 지정하는 것이 정석이지만,
매개값을 다양화하기 위해 매개 변수에 자식 객체를 지정할 수도 있음
 

외우기

선언
public class Driver {
public void drive( Vehicle vehicle) {
vehicle.run();
	}
}

호출
public class DriverEx {

	public static void main(String[] args) {
		Driver driver = new Driver();
        Vehicle vehicle = new Vehicle();
        driver.drive(vehicle);

 

Vehicle의 자식 클래스인 Bus 객체를 drive() 메소드의 매개값으로 넘겨준 경우

drive() 메소드는 Vehicle 타입을 매개 변수로 선언했지만, Vechicle을 상속받는 Bus 객체가 
매개값으로 사용되면 자동 타입 변환이 발생
매개변수의 타입이 클래스일 경우, 해당 클래스의 객체뿐만 아니라 자식 객체까지도 매개값으로
사용할 수 있다.

즉, 매개값으로 어떤 자식 객체가 제공되느냐에 따라 메소드의 실행결과는 다양해질 수 있다.
자식 객체가 부모의 메소드를 재정의했다면 메소드 내부에서 재정의된 메소드를 호출함으로써 
메소드의 실행결과는 다양해진다.

 

          Vehicle => 자식 객체
void drive(Vehicle vehicle) {
 vehicle.run(); <= 자식 객체가 재정의한 run() 메소드 실행
}

 

매개 변수의 다형성 예제 1

부모

package sec02.exam09;
//매개 변수의 다형성

public class Vehicle {
	public void run() {
		System.out.println("차량이 달린다.");
	}
}
Vehicle을 이용하는 클래스

package sec02.exam09;
//매개 변수의 다형성

public class Driver {
	//drive()메소드에서 Vehicle 타입의 매개값을 받아서 run()메소드를 호출
	public void drive( Vehicle vehicle) {
		vehicle.run();
		
		//Pony pony = (Pony) vehicle;// 강제 타입 변환 
		
	}
}
자식 1

package sec02.exam09;
//매개 변수의 다형성

public class Bus extends Vehicle {

	@Override
	public void run() {
		System.out.println("버스가 달린다.");
	}

	
}
자식 2

package sec02.exam09;
//매개 변수의 다형성

public class Pony extends Vehicle {

	@Override
	public void run() {
		System.out.println("포니 달린다.");
	}
	
}
자식 3

package sec02.exam09;
//매개 변수의 다형성

public class Taxi extends Vehicle {

	@Override
	public void run() {
		System.out.println("택시가 달린다.");

	}

	
}
실행

package sec02.exam09;
// 매개 변수의 다형성

public class DriverEx {

	public static void main(String[] args) {
		Driver driver = new Driver();
		
		Vehicle vehicle = new Vehicle();
		driver.drive(vehicle);
		
		 Pony pony = new Pony();
		 driver.drive(pony);//자동 타입 변환:Vehicle vehicle = pony;
		
		 Bus bus = new Bus();
		 driver.drive(bus);//자동 타입 변환:Vehicle vehicle = bus;
		
		 Taxi taxi = new Taxi();
		 driver.drive(taxi);//자동 타입 변환:Vehicle vehicle = taxi;
		

	}

}
< 결과 >
차량이 달린다.
포니 달린다.
버스가 달린다.
택시가 달린다.

 

매개 변수의 다형성 예제 2

부모

package sec02.exam09_02;
// 매개 변수의 다형성


public class Animal {
	void eat() {
		System.out.println("먹는다");
	}
}
Animal을 이용하는 클래스

package sec02.exam09_02;
//매개 변수의 다형성

public class Feed {
	void feed(Animal animal) {
		animal.eat();
	}
}
자식
package sec02.exam09_02;
//매개 변수의 다형성

public class Dog extends Animal {

	@Override
	void eat() {
		System.out.println("개가 먹는다.");
	}
	
	
	
}
실행

package sec02.exam09_02;
//매개 변수의 다형성

public class FeedEx {

	public static void main(String[] args) {
		Feed feed = new Feed();
		
		Dog dog = new Dog();
		feed.feed(dog);
		// dog 객체를 feed 메서드의 매개변수로 전달
	}

}
< 결과 >
개가 먹는다.

 

 

 

강제 타입 변환

강제 타입 변환은 부모 타입을 자식 타입으로 변환하는 것을 말함

그렇다고 해서 모든 부모타입을 자식 타입으로 강제 변환할 수 있는 것은 아님자식 타입이 부모 타입으로 자동 타입 변환한 후 다시 자식 타입으로 변환할 때 강제 타입 변환을 사용할 수 있다.

 

자식 타입이 부모 타입으로 자동 타입 변환하면, 부모에 선언된 필드와 메소드만 사용 가능하다는
제약 사항이 따른다.
만약 자식에 선언된 필드와 메소드를 꼭 사용해야 한다면 강제 타입 변환을 해서 다시 자식 타입으로
변환한 다음 자식의 필드와 메소드를 사용하면 된다.

field2 필드와 method3() 메소드는 Child 타입에만 선언되어 있으므로 Parent 타입으로 자동 타입
변환하면 사용할 수 없다.
field2 필드와 method() 메소드를 사용하고 싶다면 다시 Child 타입으로 강제 타입 변환을 해야 한다.
 

강제 타입 변환 실습 예제

부모

package sec02.exam09_03;
// 강제 타입 변환

public class Parent {
	public String field1;
	
	public void method1() {
		System.out.println("parent-method1");
	}
	public void method2() {
		System.out.println("parent-method2");
	}
}
자식

package sec02.exam09_03;
//강제 타입 변환

public class Child extends Parent {
	public String field2;
	
	public void method3() {
		System.out.println("Child-method3");
	}
}
실행

package sec02.exam09_03;
//강제 타입 변환

public class ChildEx {

	public static void main(String[] args) {
//		Parent p1 = new Parent();
//		Child c1 = (Child) p1; // 컴파일 에러
		
		// 필드 다형성
		Parent parent = new Child();
		parent.field1 = "aaa";		
		//parent.field2 = "bbb";// 자식만 가지고 있어서 에러
		parent.method1();
		parent.method2();
//		parent.method3(); // 자식만 가지고 있어서 에러
		
		// 강제 형변환시 가능 
		Child child = (Child) parent;
		child.field2 = "bbb";
		child.method1();
		child.method2();
		child.method3();

	}

}
< 결과 >
parent-method1
parent-method2
parent-method1
parent-method2
Child-method3

 
 
 

객체 타입 확인

강제 타입 변환은 자식 타입이 부모 타입으로 변환되어 있는 상태에서만 가능하기 때문에 다음과 같이
처음부터 부모 타입으로 생성된 객체는 자식 타입으로 변환할 수 없다.

Parent parent = new Parent();
Child child = (Child) parent; // 강제 타입 변환을 할 수 없음

부모 변수가 참조하는 객체가 부모 객체인지 자식 객체인지 확인하는 방법은 instanceof 연산자 사용
어떤 객체가 어떤 클래스의 인스턴스인지 확인하기 위해 instanceof 연산자를 사용함

boolean result = 좌항(객체) instanceof 우항(대입)

instanceof 연산자의 좌항에는 객체가 오고 우항에는 타입이 오는데, 좌항의 객체가 우항의 인스턴스이면
즉 우항의 타입으로 객체가 생성되었다면 true를 리턴하고 그렇지 않으면 false를 리턴 한다.
instanceof 연산자는 주로 매개값의 타입을 조사할 때 사용됨
메소드 내에서 강제 타입변환이 필요할 경우 반드시 매개값이 어떤 객체인지 instanceof 연산자로 확인하
고 안전하게 강제 타입 변환을 해야 한다.
만약 타입을 확인하지 않고 강제 타입 변환을 시도한다면 ClassCastException이 발생할 수있음 
 

객체 타입 확인 실습 예제

부모

package sec02.exam09_04;
//객체 타입 확인

public class Parent {

}
자식

package sec02.exam09_04;
//객체 타입 확인

public class Child extends Parent {

}
실행

package sec02.exam09_04;
//객체 타입 확인

public class InstanceofEx {
	
	// instanceof 연산자로 변환 가능한지 확인한 후 변환
	public static void method1(Parent parent) {
		if(parent instanceof Child) {// Child 타입으로 변환이 가능한지 확인
			Child child = (Child) parent;
			System.out.println("method1 - Child로 변환 성공");
		}else {
			System.out.println("method1 - Child로 변환되지 않음");
		}

	}
	//Parent 객체를 Child 타입으로 강제로 변환
	public static void method2(Parent parent) {
		Child child = (Child) parent;// ClassCastException 발생할 가능성 있음
		System.out.println("method2 - Child로 변환 성공");
	}
	
	public static void main(String[] args) {
		Parent parentA = new Child();// Child 객체를 Parent 타입으로 참조
		method1(parentA);// Child 객체를 매개값으로 전달
		method2(parentA);
		
		Parent parentB = new Parent();// Parent 객체를 생성
//		parentB 객체는 Child 타입으로 변환할 수 없으므로 "method1 - Child로 변환되지 않음"이 출력
		method1(parentB); // Parent 객체를 매개값으로 전달
		
//		parentB 객체는 Child 타입으로 변환할 수 없음
		method2(parentB); // 예외 발생
	}

}

< 결과 >
method1 - Child로 변환 성공
method2 - Child로 변환 성공
method1 - Child로 변환되지 않음
Exception in thread "main" java.lang.ClassCastException:

 
 
 

그외 실습 

static 메서드 호출 방식

package sec02.exam09_04;
//static 메서드 호출 방식

public class TestExStatic {
	
	public void bbb() {
		System.out.println("bbb()");
	}
	public static void aaa() {
		System.out.println("aaa()");
	}
	public static void main(String[] args) {
		aaa();
		
		TestExStatic t1 = new TestExStatic();
		t1.bbb();

	}

}

 

확인 문제 2번

부모

package sec02.exam09_05;
//확인 문제 2번
//SnowTireEx 실행 시켰을 때 출력 결과는?

public class Tire {
	public void run() {
		System.out.println("일반 타이어가 굴러갑니다.");
	}
}
자식

package sec02.exam09_05;
// 확인 문제 2번
// SnowTireEx 실행 시켰을 때 출력 결과는?

public class SnowTire extends Tire {

	@Override
	public void run() {
		System.out.println("스노우 타이어가 굴럽갑니다.");
	}
	
}
실행

package sec02.exam09_05;
//확인 문제 2번
//SnowTireEx 실행 시켰을 때 출력 결과는?

public class SnowTireEx {

	public static void main(String[] args) {
		SnowTire snowTire = new SnowTire();
		Tire tire = snowTire;
		
		//재정의
		snowTire.run();
		tire.run();
		
		

	}

}
< 결과 >
스노우 타이어가 굴럽갑니다.
스노우 타이어가 굴럽갑니다.

 

확인 문제 3번

상속 관계

package sec02.exam09_05;

//확인 문제 3번


public class A {}
	
	class B extends A{}
	class D extends B{}
	class E extends B{}
	
	class C extends A{}
	class F extends C{}
실행

package sec02.exam09_05;

// 확인 문제 3번 
// A, B, C, D, E, F 클래스 상속 관계 빈 칸에 들어올 수 없는 코드

public class Ex1 {
	
	public static void method(B b) {}
	public static void main(String[] args) {
//	B b = new B();
//	method(new B()); 가능
	
//	B b = (B) new A();// 에러는 안나오지만 실행시키면
//	method((B) new A());// ClassCastException 발생
		
//	B b = new D();
//	method(new D()); 가능
	
//	B b = new E();
//	method(new E()); 가능 
	}

}

 

확인 문제 4번

상속 관계 정의

package sec02.exam09_05;
//확인 문제 4번
//Controller 클래스의 setService() 메소드를 호출하려고 한다.
// setService() 메소드의 매개값으로 올 수 있는 것은?

class Service{}
public class MemberService extends Service {}
class Aservice extends MemberService{}
class Bservice extends MemberService{}

class BoardService extends Service{}
class Dservice extends BoardService{}
메소드 정의

package sec02.exam09_05;

public class Controller {
	public MemberService service;
	public void setService(MemberService service) {
		this.service = service;
	}
}
실행

package sec02.exam09_05;
//확인 문제 4번
//Controller 클래스의 setService() 메소드를 호출하려고 한다.
//setService() 메소드의 매개값으로 올 수 있는 것은
public class ControllEx {

	public static void main(String[] args) {
		Controller controller = new Controller();
		
//		불가능
//		controller.setservice(new Service());
//		상속관계에 있지 않으므로 매개값으로 전달할 수 없음
		
//		가능
//		controller.setService(new MemberService());
//		Service 클래스를 상속받았으므로 매개값으로 전달할 수 있음
		
//		가능
//		controller.setService(new Aservice());
//		MemberService 클래스를 상속받았으므로 매개값으로 전달할 수 있음
//		가능
//		controller.setService(new Bservice());
//		MemberService 클래스를 상속받았으므로 매개값으로 전달할 수 있음
		
//		불가능
//		controller.setService(new BoardService());
//		Service 클래스와 상속관계가 없으므로 매개값으로 전달할 수 없음
		
//		불가능
//		controller.setService(new Dservice());
//		BoardService 클래스를 상속받았으나, Controller 클래스의 setService() 메서드에 전달할 수 있는 
//		매개값은 MemberService와 그 하위 클래스들뿐이므로 매개값으로 전달할 수 없음
	}

}

'프로젝트 기반 자바(JAVA) 응용 SW개발자 취업과정' 카테고리의 다른 글

2023-06-09 16일차  (0) 2023.06.09
2023-06-08 15일차  (0) 2023.06.08
2023-06-02 13일차  (0) 2023.06.02
2023-06-01 12일차  (0) 2023.06.01
2023-05-31 11일차  (0) 2023.05.31

소스코드

 

package superCode;

public class Sjh_test {

	public static void main(String[] args) {
//		[문제] 
//			1에서 200 사이의 숫자 중 다음 조건에 맞는 숫자를 출력하시오.
//			조건) 6의 배수 중에서 100에 가장 가까운 수를 출력하시오.
//		[정답]
//			102
		
		1. 방법
//		int i = 6;
//		int count = 0;
//		
//		boolean run = true;
//		
//		while(run) {
//			if(i % 6 == 0) {
//				
//				count = count + 1;
//			}
//			if(count == 17) {
//				System.out.println(i);
//				run = false;
//			}
//			i += 1;
//		}
		
		2. 방법
		int i = 1;
		
		int limit = 100;
		int answer = 0;
		
		while(i <= 200) {
			// 100 까지 6의 배수 구하기
			if(i % 6 == 0 && i <= limit) {
				answer = i;
			}
			i += 1;
		}
		System.out.println("answer = " + answer); // answer = 96
		
		// 96 100 102
		int nextanswer = answer + 6;
		System.out.println("nextanswer = " + nextanswer);
		
		if(limit - answer < limit - nextanswer) {
			System.out.println(answer);
		}else {
			System.out.println(nextanswer);
		}
		
	}

}

 

결과

+ Recent posts