타입 변환과 다형성 ( 인터페이스 )
상속은 같은 종류의 하위 클래스를 만드는 기술이고, 인터페이스는 사용 방법이 동일한
클래스를 만드는 기술이라는 개념상 차이가 있지만 둘 다 다형성을 구현하는 방법은 비슷
프로그램을 개발할 때 인터페이스를 사용해서 메소드를 호출하도록 코딩했다면, 구현 객체를
매우 손쉽고 빠르게 교체할 수 있다. 프로그램 소스 코드는 변함이 없는데, 구현 객체를 교체함
으로써 프로그램의 실행 결과가 다양해진다. 이것이 인터페이스의 다형성 이다.
위에 이미지처럼 I 인터페이스를 이용해서 프로그램을 개발했다. I 인터페이스를 구현한 클래스로
처음에는 A 클래스를 선택했는데, 테스트를 해보니 A 클래스에 문제가 있다는 것을 알았다. 그래서
B 클래스와 교체한 후 단 한 줄만 수정해서 프로그램을 재실행할 수 있다.
자동 타입 변환
구현 객체가 인터페이스 타입으로 변환되는 것은 자동 타입 변환에 해당한다. 자동 타입 변환은 프로그램
실행 도중에 자동적으로 타입 변환이 일어나는 것을 말한다.
인터페이스 구현 클래스를 상속해서 자식 클래스를 만들었다면 자식 객체 역시 인터페이스 타입으로
자동 타입 변환할 수 있다.
자동 타입 변환을 이용하면 필드의 다형성과 매개 변수의 다형성을 구현할 수 있다. 필드와 매개변수의 타입을
인터페이스로 선언하면 다양한 구현 객체를 대입해서 실행결과를 다양하게 만들 수 있다.
필드의 다형성
한국 타이어와 금호 타이어는 공톡적으로 타이어 인터페이스를 구현했기 때문에 모두 타이어 인터페이스에
있는 메소드를 가지고 있다. 따라서 타이어 인터페이스로 동일하게 사용할 수 있는 교체 가능한 객체에 해당한다.
인터페이스
package sec01.exam04_0;
public interface Tire {
public void roll();
}
구현클래스 1
package sec01.exam04_0;
public class HankookTire implements Tire {
@Override
public void roll() {
System.out.println("한국타이어가 굴러갑니다.");
}
}
구현클래스 2
package sec01.exam04_0;
public class KumhoTire implements Tire {
@Override
public void roll() {
System.out.println("금호타이어가 굴러갑니다.");
}
}
필드 다형성
package sec01.exam04_0;
public class Car {
// 인터페이스 타입 필드 선언과 초기 구현 객체 대입
Tire frontLeftTire = new HankookTire();
Tire frontRightTire = new HankookTire();
Tire backLeftTire = new HankookTire();
Tire backRightTire = new HankookTire();
//인터페이스에서 설명된 roll() 메소드 호출
void run() {
frontLeftTire.roll();
frontRightTire.roll();
backLeftTire.roll();
backRightTire.roll();
}
}
실행
package sec01.exam04_0;
public class CarEx {
public static void main(String[] args) {
Car myCar = new Car();
// 한국타이어x4
myCar.run();
//frontTire 2개 kumhoTire로 교체
myCar.frontLeftTire = new KumhoTire();
myCar.frontRightTire = new KumhoTire();
// 앞 바퀴 금호 2개, 뒷 바퀴 한국타이어 유지
myCar.run();
}
}
<실행>
한국타이어가 굴러갑니다.
한국타이어가 굴러갑니다.
한국타이어가 굴러갑니다.
한국타이어가 굴러갑니다.
금호타이어가 굴러갑니다.
금호타이어가 굴러갑니다.
한국타이어가 굴러갑니다.
한국타이어가 굴러갑니다.
매개 변수의 다형성
자동 타입 변환은 필드의 값을 대입할 때에도 발생하지만, 주로 메소드를 호출할 때 많이 발생한다.
매개값을 다양화하기 위해서 상속에서는 매개 변수를 부모 타입으로 선언하고 호출할 때에는 자식 객체를
대입했습니다.
위에 이미지 처럼 만약 Bus가 구현 클래스라면 다음과 같이 Driver의 drive() 메소드를 호출할 때 Bus 객체를
생성해서 매개값으로 줄 수 있다. drive() 메소드는 Vehicle 타입을 매개 변수로 선언했지만, Vehicle을 구현한
Bus 객체가 매개값으로 사용되면 자동 타입 변환이 발생한다.
<= 자동 타입 변환
Vehicle vehicle = bus;
매개 변수의 타입이 인터페이스일 경우 어떠한 구현 객체도 매개값으로 사용할 수 있고, 어떤 구현객체가 제공
되느냐에 따라 메소드의 실행결과는 다양해질 수 있다. 이것이 인터페이스 매개변수의 다형성 이다.
인터페이스
package sec01.exam04_1;
//인터페이스
public interface Vehicle {
public void run();
}
매개 변수의 인터페이스화
package sec01.exam04_1;
public class Driver {
public void drive(Vehicle vehicle) {
vehicle.run();
}
}
구현 클래스 1
package sec01.exam04_1;
public class Bus implements Vehicle {
@Override
public void run() {
System.out.println("버스가 달립니다.");
}
}
구현 클래스 2
package sec01.exam04_1;
public class Taxi implements Vehicle {
@Override
public void run() {
System.out.println("택시가 달립니다.");
}
}
실행
package sec01.exam04_1;
public class DriverEX {
public static void main(String[] args) {
Driver driver = enw Driver();
Bus bus = new Bus();
Taxi taxi = new Taxi();
driver.drive(bus); // 자동 타입 변환
driver.drive(taxi);// 자동 타입 변환
}
}
<결과>
버스가 달립니다.
택시가 달립니다.
강제 타입 변환
구현 객체가 인터페이스 타입으로 자동 타입 변환하면, 인터페이스에 선언된 메소드만 사용 가능하다는 제약사항이
따른다. 예를 들어 인터페이스에는 3개의 메소드가 선언되어 있고 클래스에는 5개의 메소드가 선언되어 있다면,
인터페이스로 호출 가능한 메소드는 3개뿐 이다.
하지만 경우에 따라서는 구현 클래스에 선언된 필드와 메소드를 사용해야 할 경우도 발생하는데 이때 강제 타입
변환을 해서 다시 구현 클래스 타입으로 변환한 다음, 구현 클래스의 필드와 메소드를 사용할 수 있다.
인터페이스
package sec01.exam04_1;
//인터페이스
public interface Vehicle {
public void run();
}
매개 변수의 인터페이스화
package sec01.exam04_1;
public class Driver {
public void drive(Vehicle vehicle) {
vehicle.run();
}
}
구현 클래스 1
package sec01.exam04_1;
public class Bus implements Vehicle {
@Override
public void run() {
System.out.println("버스가 달립니다.");
}
public void checkFare() {
System.out.println("승차요금 체크 합니다.");
}
}
구현 클래스 2
package sec01.exam04_1;
public class Taxi implements Vehicle {
@Override
public void run() {
System.out.println("택시가 달립니다.");
}
}
실행
package sec01.exam04_1;
public class DriverEX {
public static void main(String[] args) {
// 익명의 객체생성
Vehicle vehicle1 = new Vehicle() {
@Override
public void run() {
System.out.println("새로운 차 달린다.");
}
};
Vehicle vehicle = new Bus(); // 필드 다형성
vehicle.run();
// Bus bus = vehicle;
// vehicle.chechFare(); //에러 밑에 처럼 강제 형변환 필요
// Bus bus = (Bus) vehicle;
// bus.checkFare();
// ((Bus) vehicle).checkFare(); // 위에 두줄과 동일
if(vehicle instanceof Bus) { // 강제 형변환 확인 유무
System.out.println("객체 변한 가능");
Bus bus = (Bus) vehicle;
bus.checkFare();
}
}
}
<결과>
버스가 달립니다.
객체 변한 가능
승차요금 체크 합니다.
객체 타입 확인
강제 타입 변환은 구현 객체가 인터페이스 타입으로 변환되어 있는 상태에서 가능하다. 그러나 어떤 구현 객체가
변환되어 있는지 알 수 없는 상태에서 무작정 강제 타입 변환할 경우 ClassCastException이 발생할 수도 있다.
예를 들어 다음과 같이 Taxi 객체가 인터페이스로 변환되어 있을 경우, Bus 타입으로 강제 타입 변환하면 구현
클래스 타입이 다르므로 ClassCastException이 발생한다.
Vehicle vehicle = new Taxi();
Bus bus = (Bus) vehicle;
메소드의 매개 변수가 인터페이스로 선언된 경우, 메소드를 호출할 때 다양한 구현 객체들을 매개값으로 지정할 수
있다.( 매개 변수의 다형성 ) 어떤 구현 객체가 지정될지 모르는 상황에서 다음과 같이 매개값을 Bus로 강제 타입 변환
하면 ClassCastException이 발생할 수 있다.
public void drive(Vehicle vehicle) {
Bus bus = (Bus) vehicle;
bus.checkFare();
}
예를 들어 Vehicle 인터페이스 타입으로 변환된 객체가 Bus 인지 확인하려면 다음과 같이 instanceof 연산자 사용
if(vehicle instanceof Bus) {
Bus bus = (Bus) vehicle;
}
인터페이스 타입으로 자동 타입 변환된 매개값을 메소드 내에서 다시 구현 클래스 타입으로 강제 타입 변환해야
한다면 반드시 매개값이 어떤 객체인지 instaceof 연산자로 확인하고 안전하게 강제 타입 변환을 해야 한다.
인터페이스 상속
인터페이스도 다른 인터페이스를 상속할 수 있다. 인터페이스는 클래스와는 달리 다중 상속을 허용 한다.
밑에와 같이 extends 키워드 뒤에 상속할 인터페이스들을 나열할 수 있다.
하위 인터페이스를 구현하는 클래스는 하위 인터페이스의 메소드뿐만 아니라 상위 인터페이스의 모든 추상
메소드에 대한 실체 메소드를 가지고 있어야 한다. 그렇기 때문에 구현 클래스로부터 객체를 생성한 후에
밑에와 같이 하위 및 상위 인터페이스 타입으로 변환이 가능하다.
하위 인터페이스로 타입 변환이 되면 상위 및 하위 인터페이스에 선언된 모든 메소드를 사용할 수 있으나,
상위 인터페이스로 타입 변환되면 상위 인터페이스에 선언된 메소드만 사용 가능하고 하위 인터페이스에
선언된 메소드는 사용할 수 없다. 예를 들어 아래와 같이 인터페이스가 상속 관계에 있다고 가정하면
InterfaceC 인터페이스 변수는 methodA(),mehodB(),methodC()를 모두 호출할 수 있지만,
InterfaceA와 InterfaceB 변수는 각각 methodA()와 mehodB()만 호출할 수 있다.
상위 인터페이스 1
package sec01.exam04_2;
// 상위 인터페이스
public interface InterA {
public void methodA();
}
상위 인터페이스 2
package sec01.exam04_2;
//상위 인터페이스
public interface InterB {
public void methodB();
}
하위 인터페이스
package sec01.exam04_2;
//하위 인터페이스
public interface InterC extends InterA, InterB {
public void methodC();
}
하위 인터페이스 구현
package sec01.exam04_2;
public class C implements InterC {
@Override
public void methodA() {
System.out.println("C-method_A 실행");
}
@Override
public void methodB() {
System.out.println("C-method_B 실행");
}
@Override
public void methodC() {
System.out.println("C-method_C 실행");
}
}
실행
package sec01.exam04_2;
public class Ex1 {
public static void main(String[] args) {
C c1 = new C();
InterA a1 = c1;
a1.methodA();
InterB a2 = c1;
a2.methodB();
InterC a3 = c1;
a3.methodA();
a3.methodB();
a3.methodC();
}
}
<결과>
C-method_A 실행
C-method_B 실행
C-method_A 실행
C-method_B 실행
C-method_C 실행
실습
인터페이스_구현 클래스 2개
인터페이스
package sec01.exam04_3;
public interface DataAccessObject {
public void select();
public void insert();
public void updata();
public void delete();
}
구현 클래스 1
package sec01.exam04_3;
public class OracleDao implements DataAccessObject {
@Override
public void select() {
System.out.println("Oracle DB에서 검색");
}
@Override
public void insert() {
System.out.println("Oracle DB에서 삽입");
}
@Override
public void updata() {
System.out.println("Oracle DB에서 수정");
}
@Override
public void delete() {
System.out.println("Oracle DB에서 삭제");
}
}
구현 클래스 2
package sec01.exam04_3;
public class Mysql implements DataAccessObject {
@Override
public void select() {
System.out.println("Mysql에서 검색");
}
@Override
public void insert() {
System.out.println("Mysql에서 삽입");
}
@Override
public void updata() {
System.out.println("Mysql에서 수정");
}
@Override
public void delete() {
System.out.println("Mysql에서 삭제");
}
}
실행
package sec01.exam04_3;
public class Ex1 {
// static이 붙은건 "." 호출, 안붙으면 생성자 생성 후 "." 호출
public static void dbWork(DataAccessObject dao) {
dao.select();
dao.insert();
dao.updata();
dao.delete();
}
public static void main(String[] args) {
dbWork(new OracleDao());
dbWork(new Mysql());
}
}
<결과>
Oracle DB에서 검색
Oracle DB에서 삽입
Oracle DB에서 수정
Oracle DB에서 삭제
Mysql에서 검색
Mysql에서 삽입
Mysql에서 수정
Mysql에서 삭제
Maria DB_JAVA파일 연동 후 (JDBC) 입력 값 DB에 저장
package jdbc0609;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Scanner;
public class TestForJDBC {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
Scanner sc = new Scanner(System.in);
Connection con = null;
String url = "jdbc:mariadb://localhost:3307/jspdb";// DB 연결 주소
String user = "root"; // DB 계정
String pass = "maria"; // DB PW
Class.forName("org.mariadb.jdbc.Driver");
System.out.println("드라이버 로딩!");
con =
DriverManager.getConnection(url, user, pass);
System.out.println("접속 성공!");
System.out.print("사번 입력: ");
int empno = sc.nextInt(); // 사용자로부터 사번 입력 받음
System.out.print("이름 입력: ");
String ename = sc.nextLine(); // 사용자로부터 이름 입력 받음
ename = sc.nextLine();
System.out.print("급여 입력: ");
int sal = sc.nextInt(); // 사용자로부터 가격 입력 받음
System.out.print("전화번호 입력: ");
String phone = sc.nextLine(); // 사용자로부터 전화번호 입력 받음
phone = sc.nextLine();
String sql = "insert into emp (empno,ename,sal,phone)"
+ "VALUES ("+ empno +", '"+ename+"', " + sal +", '"+phone+"' )";
Statement stmt = con.createStatement();
stmt.executeUpdate(sql);
System.out.println("query 성공");
}
}
Maria DB_JSP파일 연동 후 (JDBC) 입력 값 DB에 저장
사용자에게 입력 받기
<%@ 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>
<h1>사용자 입력</h1>
<form action="connection.jsp">
<a>사번 입력=></a><input type="text" name="empno"></br>
<a>이름 입력=></a><input type="text" name="ename"></br>
<a>급여 입력=></a><input type="text" name="sal"></br>
<a>전화번호 입력=></a><input type="text" name="phone"></br>
<button type="submit">입력</button>
</form>
<form>
</form>
</body>
</html>
DB 연결 및 정의
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ page import="java.sql.*" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<%
String aa = request.getParameter("empno");
int empno = Integer.parseInt(aa);
String ename = request.getParameter("ename");
int sal = Integer.parseInt(request.getParameter("sal"));
String phone = request.getParameter("phone");
%>
<%
Connection con = null;
String url = "jdbc:mariadb://localhost:3307/jspdb";// DB 연결 주소
String user = "root"; // DB 계정
String pass = "maria"; // DB PW
Class.forName("org.mariadb.jdbc.Driver");
System.out.println("드라이버 로딩!");
con =
DriverManager.getConnection(url, user, pass);
System.out.println("접속 성공!");
String sql = "insert into emp (empno,ename,sal,phone)"
+ "VALUES ("+ empno +", '"+ename+"', " + sal +", '"+phone+"' )";
Statement stmt = con.createStatement();
stmt.executeUpdate(sql);
System.out.println("query 성공");
%>
<hr>
<h1>사용자 등록 완료</h1>
<div><a><strong>사번=</strong><%out.println(empno);%></a></div>
<div><a><strong>이름=</strong><%out.print(ename); %></a><button type="submit" onclick="location.href= 'reset.jsp'">수정</button></div>
<div><a><strong>급여=</strong><%out.println(sal); %></a></div>
<div><a><strong>전화번호=</strong><%out.println(phone); %></a></div>
<hr>
</body>
</html>
'프로젝트 기반 자바(JAVA) 응용 SW개발자 취업과정' 카테고리의 다른 글
2023-06-13 18일차 (0) | 2023.06.13 |
---|---|
2023-06-12 17일차 (1) | 2023.06.12 |
2023-06-08 15일차 (0) | 2023.06.08 |
2023-06-07 14일차 (0) | 2023.06.07 |
2023-06-02 13일차 (0) | 2023.06.02 |