상속
: 부모클래스가 자식클래스에 필드, 메소드 물려주는 것
부모클래스 내 private 필드, 메소드는 상속되지 않음 (접근할 수 없어서)
(자바) 다중 상속 불가 => 단 하나의 부모 클래스만 상속 가능
public class Account {
static final String BANKNAME = "신한은행";
String accountNo;
String ownerName;
int balance;
public Account(String accountNo, String ownerName, int balance) {
this.accountNo=accountNo;
this.ownerName=ownerName;
this.balance=balance;
}
public Account() {
}
void deposit (int amount) {
balance+=amount;
}
int withdraw(int amount) throws Exception {
if (balance<amount) {
throw new Exception("잔액 부족");
}
balance-=amount;
return amount;
}
}
//Account 클래스 상속
public class CheckingAccount extends Account {
//필드 추가
String cardNo;
//생성자
public CheckingAccount(String accountNo, String ownerName, int balance, String cardNo) {
super(accountNo, ownerName, balance); //부모 생성자 호출
// this.accountNo=accountNo;
// this.ownerName=ownerName;
// this.balance=balance;
this.cardNo=cardNo;
}
//체크카드 지불 메소드
int pay(String cardNo, int amount) throws Exception {
if (!this.cardNo.equals(cardNo)) {
throw new Exception("카드번호가 일치하지 않습니다.");
}else {
return withdraw(amount);
}
}
}
public class CheckingAccountEx1 {
public static void main(String[] args) {
CheckingAccount chulsu = new CheckingAccount("22-333", "김철수", 1000, "1111-2222-3333");
chulsu.deposit(30000); //Account 메소드 상속했으므로 객체 생성 시 사용 가능
try {
int paidAmount = chulsu.pay("1111-2222-3333", 11000);
System.out.println("지불액 : "+paidAmount);
System.out.println("잔액 : "+chulsu.balance);
}catch(Exception e) {
System.out.println(e.getMessage());
}
}
}
//
지불액 : 11000
잔액 : 20000
- 부모 생성자 호출 (super)
객체는 클래스 생성자 호출해야만 생성됨 & 부모 객체 생성해야 자식 객체 생성 가능
=> 자식 클래스 객체 생성하려면 부모 생성자 호출해야 함
부모생성자는 자식생성자의 맨 첫 줄에서 호출됨
부모의 기본생성자 있을 때 => super();
부모의 기본생성자 없을 때(=매개변수 있는 생성자만 있을 때) => super(매개값,..);
메소드 오버라이딩 (메소드 재정의)
: 자식클래스에서 상속받은 메소드를 수정해 재정의하는 것
=> 자식객체 메소드 호출 시 오버라이딩된 메소드 호출됨
주의
1. 접근제한을 더 강하게 오버라이딩할 수 없음 (ex. 부모: public => 자식: default X)
2. 새로운 예외 throws 할 수 없음
cf. 메소드 오버로딩 : 같은 이름으로 여러 메소드 생성 (매개변수 개수, 타입, 순서 다를 때)
public class CreditLineAccount extends Account{ //Account 상속
//필드
int creditLine; //마이너스 한도
//생성자
public CreditLineAccount(String accountNo, String ownerName, int balance, int creditLine) {
super(accountNo, ownerName, balance);
this.creditLine=creditLine;
}
//메소드
int withdraw(int amount) throws Exception { //withdraw 재정의 => 메소드 오버라이딩 (deposit()은 그대로)
if (balance+creditLine<amount) {
throw new Exception("인출이 불가능합니다.");
}
balance-=amount;
return amount;
}
}
- 부모 메소드 호출(super)
메소드 오버라이딩한 자식클래스에서 기존 부모클래스 메소드 호출해야 하는 경우
super.메소드명();
final 클래스, 메소드
final : 수정 불가능한 최종값
1. final 클래스 => 최종 클래스이므로 자식클래스 생성(상속) 불가
2. final 메소드 => 최종 메소드이므로 재정의(오버라이딩) 불가
다형성
: 같은 타입의 다양한 객체를 이용할 수 있는 성질
부모타입에 모든 자식객체 대입 가능
ex. 같은 규격(타입)이면 금호타이어, 한국타이어(객체) 모두 교체 가능
- 클래스의 다형성
1. 자동 형변환 : 자식클래스 타입 객체를 부모클래스 타입으로 형변환
ex. 부모클래스 A = new 자식클래스();
부모클래스로 선언, 자식클래스로 생성 => 결과적으로 부모클래스 타입 산출됨
부모클래스에 존재하는 필드, 메소드에만 접근 가능
부모, 자식클래스에 동시에 존재하는 메소드(오버라이딩한 메소드)는 자식클래스의 메소드 사용
2. 강제 형변환 : 부모 객체가 자식 타입으로 강제 타입 변환 <= (자동 변환 후 자식객체 필드/메소드 필요할 때 강제변환)
ex. 자식클래스 B =(자식) 부모클래스 A;
자식 -> 부모 -> 자식 클래스로 재변환하는 경우에만 가능
부모클래스에 기본 생성자 없으면 자식클래스 기본생성자 생성 불가
public class PolymorphismEx1 {
public static void main(String[] args) {
Account chulsu1 = new Account();
CheckingAccount gildong1=new CheckingAccount(); //(CheckingAccount에 디폴트 생성자 추가함)
CreditLineAccount chanho1 = new CreditLineAccount();
Account chulsu = new CheckingAccount(); //자동 형변환
//선언은 Account, 생성은 CheckingAccount => 결과: Account 타입
//선언된 클래스의 메소드만 사용 가능 ex. Account (withdraw, deposit)
Account gildong = new CreditLineAccount();
//오버라이드한 메소드 이용 가능 (Credit의 withdraw)
Account chanho = new DokdoAccount(null, null, 0, 0);
//오버라이드 메소드 이용 가능 (Dokdo의 deposit)
CheckingAccount younghee = (CheckingAccount)chulsu; //강제형변환
}
}
- 객체 타입 확인 (instanceof)
강제 형변환 가능한지 검사 (자식->부모 변환 여부 확인)
부모타입 변수가 부모객체 참조하면 불가
public class InstanceOfEx{
public void test(Parent parent){ //Parent, Child 타입 모두 파라미터로 들어올 수 있음
if (parent instanceof Child){ //Child 타입으로 변환 가능한지 검사
//매개변수가 참조하는 객체가 Child 타입인지 검사
Child child = (Child) parent;
System.out.println("Child로 변환 성공");
} else {
System.out.println("Child로 변환 실패");
}
}
public static void main(String[] args){
Parent parentA = new Child(); //자동형변환
test(parentA); //"Child로 변환 성공" //강제형변환
Parent parentB = new Parent();
test(parentB); //"Child로 변환 실패"
}
}
- 필드의 다형성
public class Tire {
//필드
public int maxRotation; //타이어 수명
public int accumulatedRotation; //누적 회전수
public String location; //타이어 위치 (4곳)
//생성자
public Tire(String location, int maxRotation) {
this.location=location;
this.maxRotation=maxRotation;
}
//메서드
public boolean roll() {
accumulatedRotation++;
if (accumulatedRotation<maxRotation) {
System.out.println(location+" 타이어의 수명 : "+(maxRotation-accumulatedRotation)+"회");
return true;
}else {
System.out.println("*** "+location+" 타이어 펑크 ***");
return false;
}
}
}
public class Car {
//필드
Tire frontLeftTire = new Tire("앞 왼쪽", 7);
Tire frontRightTire = new Tire("앞 오른쪽", 3);
Tire backLeftTire = new Tire("뒤 왼쪽", 5);
Tire backRightTire = new Tire("뒤 오른쪽", 4);
//default 생성자
//메서드
int run() {
System.out.println("자동차가 달립니다. 씽씽");
if(frontLeftTire.roll()==false) {
stop();
return 1;
}
if(frontRightTire.roll()==false) {
stop();
return 2;
}
if(backLeftTire.roll()==false) {
stop();
return 3;
}
if(backRightTire.roll()==false) {
stop();
return 4;
}
return 0; //펑크 안 날 때
}
void stop() {
System.out.println("자동차가 멈춥니다.");
}
}
public class HankookTire extends Tire {
//필드 상속
//생성자
public HankookTire(String location, int maxRotation) {
super(location, maxRotation);
}
//메소드 오버라이드
@Override
public boolean roll() {
accumulatedRotation++;
if (accumulatedRotation<maxRotation) {
System.out.println(location+" 한국타이어의 수명 : "+(maxRotation-accumulatedRotation)+"회");
return true;
}else {
System.out.println("*** "+location+" 한국타이어 펑크 ***");
return false;
}
}
}
public class KumhoTire extends Tire {
//필드 상속
//생성자
public KumhoTire(String location, int maxRotation) {
super(location, maxRotation);
}
//메소드 오버라이드
@Override
public boolean roll() {
accumulatedRotation++;
if (accumulatedRotation<maxRotation) {
System.out.println(location+" 금호타이어의 수명 : "+(maxRotation-accumulatedRotation)+"회");
return true;
}else {
System.out.println("*** "+location+" 금호타이어 펑크 ***");
return false;
}
}
}
public class CarEx1 {
public static void main(String[] args) {
Car csMyCar = new Car(); //인스턴스 객체 생성
for (int i=1;i<=5;i++) { //5번 반복
int problemLocation = csMyCar.run();
switch (problemLocation) { // 펑크 안 나면 0
case 1:
System.out.println("앞 왼쪽 금호타이어로 교체");
csMyCar.frontLeftTire=new KumhoTire("앞 왼쪽", 15); //필드의 다형성
//KumhoTire 객체를 Car의 Tire 타입 frontLeftTire 필드에 대입
break;
case 2:
System.out.println("앞 오른쪽 한국타이어로 교체");
csMyCar.frontRightTire=new HankookTire("앞 오른쪽", 10); //필드의 다형성
break;
case 3:
System.out.println("뒤 왼쪽 한국타이어로 교체");
csMyCar.backLeftTire=new HankookTire("뒤 왼쪽", 13); //필드의 다형성
break;
case 4:
System.out.println("뒤 오른쪽 금호타이어로 교체");
csMyCar.backRightTire=new KumhoTire("뒤 오른쪽", 12); //필드의 다형성
break;
}//switch
System.out.println("-----------------");
}//for
}
}
cf. Car 클래스 배열로 축약하기
public class Car {
//Tire frontLeftTire = new Tire("앞 왼쪽", 7);
//Tire frontRightTire = new Tire("앞 오른쪽", 3);
//Tire backLeftTire = new Tire("뒤 왼쪽", 5);
//Tire backRightTire = new Tire("뒤 오른쪽", 4);
Tire[] tires = {
new Tire("앞 왼쪽", 7),
new Tire("앞 오른쪽", 3),
new Tire("뒤 왼쪽", 5),
new Tire("뒤 오른쪽", 4)
}
int run() {
System.out.println("자동차가 달립니다. 씽씽");
/*if(frontLeftTire.roll()==false) {
stop();
return 1;
}
if(frontRightTire.roll()==false) {
stop();
return 2;
}
if(backLeftTire.roll()==false) {
stop();
return 3;
}
if(backRightTire.roll()==false) {
stop();
return 4;
}
return 0; */
for (int i=0;i<tires.length;i++){
if (tires[i].roll()==false){
stop();
return (i+1);
}
}
return 0;
}
void stop() {
System.out.println("자동차가 멈춥니다.");
}
}
- 매개변수의 다형성
public class Driver {
//메소드
void Drive(Vehicle vehicle) { //Vehicle 타입의 클래스 받음
vehicle.run();
}
}
public class Vehicle {
//메서드
public void run() {
System.out.println("차량이 달립니다.");
}
}
public class Bus extends Vehicle {
@Override
public void run() {
System.out.println("버스가 달립니다.");
}
}
public class Taxi extends Vehicle {
@Override
public void run() {
System.out.println("택시가 달립니다.");
}
}
public class DriverEx1 {
public static void main(String[] args) {
Driver chulsu = new Driver();
Taxi taxi = new Taxi();
Bus bus = new Bus();
chulsu.Drive(taxi); //오버라이딩한 메소드 실행
chulsu.Drive(bus); //
}
}
//
택시가 달립니다.
버스가 달립니다.
추상 클래스
: 실체 클래스 간 공통 특성 추출해 선언한 클래스
=> 인터페이스와 유사, 인터페이스가 더 자주 쓰임
실체 클래스들의 필드, 메소드 이름 통일시킴
실체 클래스 작성 시 시간 절약
=>
메소드 이름만 추상 클래스에서 미리 정의해두고, 통일된 이름 다른 클래스들에서 사용하도록
추상클래스 내에는 반드시 추상 메서드(메소드 본체 없음)가 있음 & 자식 클래스는 추상 메서드 내부에 코드 작성해야 함
new 로 객체 생성 불가 => 상속 통해서만 자식 클래스 생성 가능
틀만 만들고 구현은 자식클래스에 넘김
public abstract class Animal { //추상 클래스
String name;
abstract void move(); //추상 메소드=> 메서드 본체(중괄호 열고 기능 적는 것)가 없음
}
public class Tiger extends Animal{ //자식 클래스
int age;
@Override
void move() { //추상메소드 오버라이딩
System.out.println("네 발로 이동");
}
}
public class Eagle extends Animal{ //자식 클래스
String home;
@Override
void move() { //
System.out.println("날개로 이동");
}
}
public class AnimalEx1 {
public static void main(String[] args) {
Tiger tiger1 = new Tiger();
Eagle eagle1 = new Eagle();
tiger1.name = "대한이";
tiger1.age = 2;
System.out.println(tiger1.name+"는 "+tiger1.age+"살 입니다.");
tiger1.move();
eagle1.name = "대머리";
eagle1.home = "소나무 둥지";
System.out.println(eagle1.name+"는 "+eagle1.home+"에 삽니다.");
eagle1.move();
}
}
//
대한이는 2살 입니다.
네 발로 이동
대머리는 소나무 둥지에 삽니다.
날개로 이동
'Programming > 자바' 카테고리의 다른 글
자바 재정리 - 중첩 클래스, 중첩 인터페이스 (0) | 2022.08.26 |
---|---|
자바 재정리 - 인터페이스 (0) | 2022.08.25 |
자바 재정리 - 클래스 (0) | 2022.08.11 |
자바 재정리 - 참조 (0) | 2022.08.05 |
생활코딩 자바 - Collections framework (0) | 2022.04.24 |