JAVA.상속, 추상클래스, 오버라이딩, 포함관계, 업캐스팅/다운캐스팅

brave_chicken·2024년 3월 23일

잇(IT)생 챌린지

목록 보기
10/90

상속 중복제거

  • Student, Teache, Staff에서 이름 나이의 설정과 출력 형식이 겹침
  • Person이라는 부모클래스에서 설정


    Person 상속한 자식클래스
    부모클래스와 자식클래스에 동일한 이름의 display()가 겹치니, super.diplay()로 부모클래스 상속 표시

상속 기타기록

  • 상속은 이중으로 받을 수 없음. 한번에 두개 이상의 클래스는 상속할 수 없음.
  • stackOverFlowError : stack(메모리), overflow(넘치다), 메모리에 올라갈 공간이 없다
  • 상위클래스 상속 표시(?)도 source-generate using field-insert point에서 설정해서 만들수있음.
  • 상속받기 (extends___) 클래스 생성시 super class 옆 Browse...-상속받고 싶은 클래스 검색 및 선택하면 생성됨
  • 상속은 is a 관계 성립시만(Alcohol is a drink)

BeverageTest 예제

부모클래스 beverage

package oop.inheritance;

public class Beverage {
	private String type;
	private int price;
	
	public Beverage(String type, int price) {
		super();
		this.type = type;
		this.price = price;
	}
	public String getType() {
		return type;
	}
	public void setType(String type) {
		this.type = type;
	}
	public int getPrice() {
		return price;
	}
	public void setPrice(int price) {
		this.price = price;
	}
}

자식클래스 coffee

package oop.inheritance;

public class Coffee extends Beverage {
	private String name;

	public Coffee(String type, int price, String name) {
		super(type, price);
		this.name = name;
	}
	
	public void print() {
		System.out.println("타입:"+getType()+", "+"가격: "+getPrice()+", "+"이름: "+name);
	}
	
	public String getName() {
		return name;
	}

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

TestAccount 예제




부모클래스 Account

package oop.inheritance;

public class Account {
	private String accId;
	private long balance;
	private String ownerName;
	
	public Account() {
		
	}
	public Account(String accId, long balance, String ownerName) {
		super();
		this.accId = accId;
		this.balance = balance;
		this.ownerName = ownerName;
	}
	
	//입금하기
	public void deposit(long amount) {
		balance = balance + amount;
	}

	//출금하기
	public void withdraw(long amount) {
		balance = balance - amount;
	}

	public String getAccId() {
		return accId;
	}
	public void setAccId(String accId) {
		this.accId = accId;
	}
	public long getBalance() {
		return balance;
	}
	public void setBalance(long balance) {
		this.balance = balance;
	}
	public String getOwnerName() {
		return ownerName;
	}
	public void setOwnerName(String ownerName) {
		this.ownerName = ownerName;
	}
}

자식클래스 checkingAccount

package oop.inheritance;

public class CheckingAccount extends Account {
	private String cardNo;
	
	public CheckingAccount() {
		
	}

	public CheckingAccount(String accId, long balance, String ownerName,String cardNo) {
		super(accId,balance,ownerName);
		this.cardNo = cardNo;
	}
	
	public void pay(long amount,String cardNo) {
		//String은 참조형이니까 ==은 주소 비교하는것
		//문자열을 비교하는 경우 무조건 equals=>대소문자까지 비교
		if(amount<=getBalance() & this.cardNo.equals(cardNo)) {
			withdraw(amount);
		}
		else{
			System.out.println("지불이 불가능합니다.");
		}
	}

	public String getCardNo() {
		return cardNo;
	}
	public void setCardNo(String cardNo) {
		this.cardNo = cardNo;
	}
}

Prob1, Drink/Alcohol..상속

Drink 클래스의 제약조건
1. 상품명(name), 단가(price), 수량(count) 정보를 저장하는 멤버변수가 있어야 한다.
3. 멤버변수를 초기화하는 생성자 메서드가 있어야 한다.
4. 금액(단가*수량)을 계산하는 getTotalPrice() 메서드가 있어야 한다.
5. 타이틀을 출력하는 printTitle() 메서드가 있어야 한다.
5. 상품의 정보를 출력하는 printData() 메서드가 있어야 한다.

Alcohol 클래스의 제약조건
1. Drink 클래스를 상속받아야 한다.
2. 알코올 도수를 나타내는 멤버변수(alcper)가 있어야 한다.
3. 멤버변수를 초기화하는 생성자 메서드가 있어야 한다.
4. 부모 클래스인 Drink 의 printTitle() 메서드의 기능을 재정의(오버라이딩) 한다.
5. 부모 클래스인 Drink 의 printData() 메서드의 기능을 재정의(오버라이딩) 한다.

상위클래스 Drink

package oop.inheritance;

public class Drink {
	private String name;
	private int price;
	private int count;
	
	public Drink() {
		
	}
	public Drink(String name, int price, int count) {
		super();
		this.name = name;
		this.price = price;
		this.count = count;
	}
	
	public int getTotalPrice() {
		int totalPrice = 0;
		totalPrice = price * count;
		return totalPrice;
		//return count*price;//이렇게해도됨!
	}
	
	public static void printTitle() {
		System.out.println("상품명\t단가\t수량\t금액");
	}
	public void printData() {
		System.out.println(name+"\t"+price+"\t"+count+"\t"+getTotalPrice());
	}
	
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getPrice() {
		return price;
	}
	public void setPrice(int price) {
		this.price = price;
	}
	public int getCount() {
		return count;
	}
	public void setCount(int count) {
		this.count = count;
	}
}

하위클래스 Alcohol

package oop.inheritance;

public class Alcohol extends Drink{
	private double alcper;
	
	public Alcohol() {
		
	}
	//상위클래스 상속 표시(?)도 generate using field-insert point에서 설정해서 만들수있음.
	public Alcohol(String name, int price, int count,double alcper) {
		super(name,price,count);
		this.alcper = alcper;
	}
	
	public static void printTitle() {
		System.out.println("상품명(도수[%])\t단가\t수량\t금액");
	}
	public void printData() {
		System.out.println(getName()+"("+alcper+")"+"\t"+getPrice()+"\t"+getCount()+"\t"+getTotalPrice());
	}

	public double getAlcper() {
		return alcper;
	}

	public void setAlcper(double alcper) {
		this.alcper = alcper;
	}
}

다형성

VehicleTest/Tire 오버라이딩, 포함관계(has a 관계)

포함관계/상속관계 설명잘된 링크

VehicleTest

package oop.polymorphism;

class Vehicle {
	//has a 관계
	Tire tire;//null상태
	//Tire tire2 = new Tire();//Tire객체를 참조하고 있는 상태, has a 관계라서 이렇게 정의하지않음
	public Vehicle() {}
	public Vehicle(Tire tire) {
		super();
		this.tire = tire;
	}

	public void run() {
		System.out.println("차량이 달립니다.");
	}
}

class Bus extends Vehicle{

	//Source - Override/Implement method하면 생성됨
	@Override
	public void run() {
		System.out.println("버스가 달립니다.");
	}
}

class Taxi extends Vehicle{

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

public class VehicleTest{
	public static void main(String[] args) {
		Bus obj = new Bus();
		obj.tire = new HankookTire();
		Taxi obj2 = new Taxi();
		obj2.tire = new KumhoTire();
		obj.run();
		obj2.run();
	}
}

Tire

package oop.polymorphism;

class HankookTire extends Tire{
	@Override
	public void roll() {
		System.out.println("한국타이어가 회전합니다.");
	}
}

class KumhoTire extends Tire{
	@Override
	public void roll() {
		System.out.println("금호타이어가 회전합니다.");
	}
}

public class Tire {
	//메소드
	public void roll() {
		System.out.println("차량이 달립니다.");
	}
}

FinalTest

final을 붙이면 어떻게 되는지(교재 345p)

  • 변수 -> 상수로 정의
  • 메소드 -> 오버라이딩을 할 수 없는 메소드가 됨
  • 클래스 -> 상속할 수 없는 클래스가 됨
package oop.inheritance;

final class A{
	public void test() {
		//일반기능의 메소드 - 하위클래스에서 상속해서 변경해야하는 메소드
	}
	public final void login(String pass) {
		System.out.println("부모클래스의 중요한 메소드 - 인증하고 엑세스하기");
	}
}

class B extends A{//상속불가. A가 final class라서
	public void login(String pass) {//오버라이딩 불가. login이 final method라서
		System.out.println("인증하지 않고 엑세스하는 코드로 수정");
	}
}

public class FinalTest {
	public static final int CODE=100;//상수는 대문자로, final이붙는 상수 앞엔 static이 붙음.
	public void test() {
		//CODE = 1000; 상수는 값을 재할당할 수 없다.
	}
	public static void main(String[] args) {
		// TODO Auto-generated method stub

	}

}

AbstractTest 추상클래스

추상(Abstract)클래스 -->다형성으로 연결됨.

: 객체를 생성할 수 없는 클래스, 미완성된 클래스
: 내용이 구현되어있지 않은 메소드(추상메소드 : body가 없는 메소드)를 포함하고 있는 클래스를 추상클래스라 한다.

1) 추상메소드를 선언하는 방법
접근제어자 abstract 리턴타입 메소드명(매개변수1,매개변수2...);

2) 추상클래스의 특징

  • 추상메소드가 하나라도 정의되어있으면 추상클래스가 된다.
    따라서 추상클래스는 선언부에 abstract 추가한다.
  • 추상클래스에는 추상메소드와 일반메소드를 모두 정의할 수 있다.
  • 추상클래스는 객체생성을 할 수 없다.
  • 추상클래스를 상속받는 클래스는 extends 하면 에러가 발생
    =>child 클래스가 Parent클래스를 상속받는다
    Parent클래스의 모든 멤버가 child의 소유가 된다
    child는 Parent의 일반메소드인 test()와 추상메소드인 display()를 모두 소유하므로 차일드도 추상클래스가된다


    [에러처리]
  • 차일드클래스의 선언부에 abstract
  • 차일드가 상속받은 추상메소드를 구현(오버라이딩)

  • abstract 메소드는 하위클래스에서 반드시 오버라이딩되어야한다는 것을 문법적으로 제시
package oop.polymorphism;

abstract class Parent{//추상클래스
	public void test() {
		System.out.println("일반메소드");
	}
	public abstract void display(String data);//추상메소드
}

class Child extends Parent{
	//컴파일러에 정보를 알려주는 작업
	//@Override는 컴파일러에게 오버라이딩된 메소드라는 것을 알려주는 기호

	@Override
	public void display(String data) {
		System.out.println("부모에게 상속받은 추상메소드를 구현");
	}
	
}

public class AbstractTest {
	public static void main(String[] args) {
		Child obj = new Child();
		obj.display("");
	}
}

출력 :
부모에게 상속받은 추상메소드를 구현

RefTypeCastingTest1

캐스팅, 업캐스팅, 다운캐스팅 설명링크

  • 상속관계에 있는 클래스는 자동캐스팅
  • 서브클래스(자식클래스)의 인스턴스를 슈퍼클래스타입(부모클래스)으로 변환하는 작업 - 업캐스팅(안전)
  • 상위클래스타입 변수 = new 하위클래스()
package oop.polymorphism;

import java.util.AbstractCollection;
import java.util.AbstractList;
import java.util.ArrayList;
import java.util.List;

public class RefTypeCastingTest {
	public static void main(String[] args) {
		ArrayList<String> list = new ArrayList<>();
		AbstractList<String> ablist = new ArrayList<String>();
		AbstractCollection<String> aclist = new ArrayList<>();
		List<String> list2 = new ArrayList<>();
		
		String str = new String("java");
		StringBuffer sb = new StringBuffer();
		
		//String = StringBuffer
		//참조형에서 상속관계가 아닌 경우에는 캐스팅을 할 수 없다.
		//참조형에서 캐스팅을 하려면 무조건 상속관계에 있는 클래스여야 함
		//str = sb;//컴파일 오류
	}
}

RefTypeCastingTest2

package oop.polymorphism;
//객체의 형변환
//사용자정의클래스
class Super{
	String data = "상위클래스";
	public void display() {
		System.out.println("super의 display");
	}
}

class Sub extends Super{
	String data = "하위클래스";
	public void display() {
		System.out.println("sub의 display");
	}
	public void test() {
		System.out.println("sub의 test");
	}
}

//sub가 자식객체지만 부모객체 super보다 확장된 영역임을 기억하며 보기..

public class RefTypeCastingTest2 {
	public static void main(String[] args) {
		System.out.println("1.Super타입의 참조변수로 Super객체를 사용");
		Super obj1 = new Super();
		obj1.display();
		System.out.println(obj1.data);
		System.out.println("***************************************");
		
		System.out.println("2.Sub타입의 참조변수로 Sub객체를 사용");
		Sub obj2 = new Sub();
		obj2.display();
		System.out.println(obj2.data);
		System.out.println("***************************************");
		
		
		//상속관계에 있는 클래스는 자동캐스팅
		//서브클래스의 인스턴스를 슈퍼클래스타입으로 변환하는 작업 - 업캐스팅(안전) : 할당되는 자식타입이 부모타입화되는게 업캐스팅
		//컴파일 시점과 런타임 시점의 차이때문에 테스트 실행안됨
		//컴파일시점에는 참조변수의 타입에 따라서 사용 가능한 멤버가 결정된다.
		//자바는 동적바인딩을 해서 객체 관리
		//동적바인딩 : 런타임시에 실제 생성되는 객체를 확인하고 메소드의 실행도 실제 생성되는 객체의 메소드가 실행
		//필드(멤버변수)는 참조변수의 선언된 타입으로 호출되고 
        //메소드는 런타임시에 실제 할당된 객체의 메소드가 호출 
		//즉 참조변수가 참조하는 실제 힙에 할당된 객체 타입을 보고 실행
		
		System.out.println("3.Super타입의 참조변수로 Sub객체를 사용");
		Super obj3 = new Sub();
		obj3.display(); //얘는 왜 오버라이딩 된 결과가 나오냐? 
		//obj3.test();
		//obj3이 Super타입의 참조변수이지만 실제 참조하고있는 생성된 객체는 Sub 객체이므로 캐스팅이 가능
        
		//부모타입인 obj3의 객체참조를 서브객체참조로 변환 => 다운캐스팅
		((Sub)obj3).test();//obj3이 실제로 참고하는 객체가 서브기때문에 넘어감
		System.out.println(obj3.data);
		System.out.println(((Sub)obj3).data);//멤버변수는 얘 클래스가 타입이 어떻게되냐에 따라 결정..? 
		System.out.println("***************************************");
		
		
		//캐스팅이 안된다고 하기 보다는 인식을 할 수 없는 거죠 이미 부모타입으로 캐스팅이 된 상태라 안 보이는 상태인거죠
		
		System.out.println("4.Sub타입의 참조변수로 Super객체를 사용");
		//Sub obj4 = new Super(); 불가능함~!
		
		System.out.println("***************************************");
		//명시적으로 캐스팅하면 컴파일러를 속일 수 있다.
		//but 실행시엔ㄴ obj1이 참조하는 객체가 Super이므로 실행할 때 캐스팅을 할 수 없어 오류가 발생한다.
		System.out.println("5. Sub변수 = Super객체를 참조하는 변수");
		//Sub obj5 = (Sub)obj1;//얘는 실제로 수퍼이기 때문에 오류, 불가능함~!
		
		
		System.out.println("***************************************");
		System.out.println("6.Sub변수 = Sub객체를 참조하는 Super변수가 오는경우");
		Sub obj6 = (Sub)obj3;
		obj6.display();
		System.out.println(obj6.data);
		
	}

}

출력:
1.Super타입의 참조변수로 Super객체를 사용
super의 display
상위클래스


2.Sub타입의 참조변수로 Sub객체를 사용
sub의 display
하위클래스


3.Super타입의 참조변수로 Sub객체를 사용
sub의 display
sub의 test
상위클래스
하위클래스


4.Sub타입의 참조변수로 Super객체를 사용


  1. Sub변수 = Super객체를 참조하는 변수

6.Sub변수 = Sub객체를 참조하는 Super변수가 오는경우
sub의 display
하위클래스

PolyTest

package oop.polymorphism;
abstract class ParentA{
	public abstract void print();
}
//상위클래스로 쓰기위한 목적으로 만듦. 바디는 필요없음. 실행시점에 오버라이딩하기위해,,?
//추상클래스를 정의하는 목적 자체가 컴파일러가 프린트메소드를 인식하게 만들고, 어차피 실행시점엔 하위클래스에서 오버라이딩된게 실행됨

class ChildB extends ParentA{
	public void print() {
		System.out.println("ChildB");
	}
}
class ChildC extends ParentA{
	public void print() {
		System.out.println("ChildC");
	}
}
class ChildD extends ParentA{
	public void print() {
		System.out.println("ChildD");
	}
}
class NewChild extends ParentA{
	public void print() {
		System.out.println("NewChild");
	}
}
public class PolyTest {
	public static void main(String[] args) {
	//	ChildB obj = new ChildC(); //캐스팅은 부모자식간의 관계(상속관계)만 가능
		ParentA obj = new ChildB();
		ParentA obj2 = new ChildC();
		ParentA obj3 = new ChildD();
		ParentA obj4 = new NewChild();
		test(obj4);
	}
	
	public static void test(ParentA obj) {//super타입의 변수로는 모든 하위객체를 다 받을 수 있음
		obj.print();
	}
}

본 포스팅은 멀티캠퍼스의 멀티잇 백엔드 개발(Java)의 교육을 수강하고 작성되었습니다.

0개의 댓글