1) 업캐스팅을 하면 자식의 메소드를 덮어쓴다. 하지만 부모 클래스에서 존재하지 않는 메소드는 이용할 수 없다.
2) (Circle) circle과 같은 일반적인 형변환을 시킬 필요가 없다.
static class Cake{
public void yummy(){
System.out.println("Yummy Cake");
}
}
static class CheeseCake extends Cake{
@Override
public void yummy(){
System.out.println("Yummy Cheese Cake");
}
}
public static void main(String[] args) {
Cake c1 = new CheeseCake();
CheeseCake c2 = new CheeseCake();
c1.yummy();
c2.yummy();
}
// 둘다 Yummy Cheese Cake가 출력됨
3) 업캐스팅 시 메모리의 변화
class A{
private int a;
public getA(){
...
}
}
class B extends A{
private int b;
public getB(){
...
}
}
A a = new B(); // 1번
B b = new A(); // 2번, 에러
(1) A a = new B()
: a가 B를 참조하였으므로 부모 클래스인 A와 B 모두 존재함 → 따라서 주소값 2000을 통해서 들어가면 b를 확인할 수 있으므로 컴파일 에러가 발생하지 않음
(2) B b = new A()
: b를 A를 참조하였으므로 B 부분은 제거됨 → 주소값 2000을 통해서 들어가면 b를 확인할 수 없으므로 컴파일 에러가 발생함
cf) 현업에서는 업캐스팅이라는 용어를 잘 쓰지 않는다.
cf) 수업에서 주로 다형성이라고 부른다.
💡 업캐스팅: **부모 = 자식** static class Cake{
public void yummy(){
System.out.println("Yummy Cake");
}
}
static class CheeseCake extends Cake{
@Override
public void yummy(){
System.out.println("Yummy Cheese Cake");
}
}
public static void main(String[] args) {
Cake c1 = new CheeseCake();
CheeseCake c2 = new CheeseCake();
c1.yummy();
c2.yummy();
}
// 둘다 Yummy Cheese Cake가 출력됨
→ 위의 코드에서 c1은 CheeseCake라는 객체를 가리키지만 클래스 타입은 Cake이다. 만약 CheeseCake의 클래스 타입을 원래대로인 CheeseCake로 돌려주고 싶으면 다운 캐스팅을 사용할 수 있다.
CheeseCake c2 = (CheeseCake) c1;
class Shape{
...
public double getArea(){
...
}
}
class Rectangle extends Shape{
...
@Override
public double getArea(){
...
}
}
class Triangle extends Shape{
...
@Override
public double getArea(){
...
}
}
public class ShapeTest{
public static void print(Shape s){
System.out.println("넓이는 "+s.getArea());
}
public static void main (String arg[]){
Rectangle s1 = new Rectangle(10,10);
Triangle s2 = new Triangle(10,10);
print(s1);
print(s2);
}
→ Rectangle s1 = new Rectangle(10,10); 이므로 print(s1)에서 print(Shape s = new Rectangle(10,10)의 형태가 되므로 이 부분에서 업캐스팅이 발생했다고 볼 수 있다.
public class Poly{
//instance of 연산자
public static void print(Shape shape){
// instance of 연산자는 기본적으로 true와 false를 return 함 --> if 문 사용
// 객체명(변수명) instanceof 클래스 타입: 해당하면 true, 아니면 false
// 객체를 찾아서 타입을 확인해라
if(shape instanceof Rectangle){
System.out.println("실제 타입은 Rectangle 입니다.");
}else if (shape instanceof Circle){
System.out.println("실제 타입은 Circle 입니다.");
} else{
System.out.println("알 수 없는 타입입니다.");
}
}
public static void main(String[] args) {
Shape[] shape = {new Triangle(10,10), new Rectangle(10,10), new Circle(10)};
print(shape[0]);
print(shape[1]);
print(shape[2]);
}
}
1) 추상 클래스는 한 개 이상의 미완성 메소드를 가진다 → 미완성 메소드는 반드시 자손이 구현해주어야 한다.
2) 인터페이스와는 달리 상속관계에서 사용된다.
3) 객체 생성이 안된다.
abstract class Animal{
public abstract void move();
}
class Lion extends Animal{
@Override
public void move() {
System.out.println("사자의 move 메소드입니다.");
}
}
public class HelloWorld{
public static void main(String[] args) {
// Animal animal = new Animal(); abstract 클래스는 객체 생성이 안 됨
Lion lion = new Lion();
lion.move();
}
}
4) 활용
// interface는 상수와 추상함수만 올 수 있음
interface Printable{
public abstract void print(String doc);
}
class SPrinterDriver implements Printable{
@Override
public void print(String doc) {
System.out.println("삼성 프린터입니다.");
System.out.println(doc);
}
}
class LPrinterDriver implements Printable{
@Override
public void print(String doc) {
System.out.println("LG 프린터입니다.");
System.out.println(doc);
}
}
public class DriveTest {
public static void main(String[] args) {
// 인터페이스도 class와 유사하게 다형성 적용 가능
// 추상 함수가 있으므로 객체 생성 불가, 참조 변수 선언 가능
// Printable print = new Printable();
Printable print = new SPrinterDriver();
print.print("출력해주세요.");
print = new LPrinterDriver();
print.print("출력해주세요.");
}
}
interface MyInterface {
default void printHello() {
System.out.println("Hello World");
}
}
class MyClass implements MyInterface { /* empty */ }
public class DefaultMethod {
public static void main(String[] args) {
MyClass myClass = new MyClass();
myClass.printHello();//실행결과 Hello World 출력
}
}
자바에서는 다중 상속이 지원되지 않는다
인터페이스를 이용하면 다중상속의 효과를 낼 수 있다.
interface Drivable{
void drive();
}
interface Flyable{
void fly();
}
class FlyingCar implements Drivable, Flyable{
@Override
public void drive() {
System.out.println("드라이브가 가능합니다.");
}
@Override
public void fly() {
System.out.println("날 수 있습니다.");
}
}
public class Drive {
public static void main(String[] args) {
FlyingCar flyingCar = new FlyingCar();
flyingCar.drive();
flyingCar.fly();
}
}