class A {
void print() {
System.out.println("A");
}
}
class B extends A {
void print() {
System.out.println("B");
}
}
public class Main {
public static void main(String[] args) {
A obj = new B();
obj.print();
}
}
🖍️ B
obj.print();
→ B의 print()
class Calc {
int add(int a, int b) {
return a + b;
}
double add(double a, double b) {
return a + b;
}
}
public class Main {
public static void main(String[] args) {
Calc c = new Calc();
System.out.println(c.add(2, 3));
System.out.println(c.add(2.5, 1.5));
}
}
🖍️
5
4.0
c.add(2, 3)
→int add(int a, int b){}
→ 5c.add(2.5, 1.5)
→double add(double a, double b){}
→ 4.0
public class Main {
public static void main(String[] args) {
String s1 = new String("hello");
String s2 = new String("hello");
System.out.println(s1 == s2);
System.out.println(s1.equals(s2));
}
}
🖍️
false
true
s1 == s2
→ false (다른 객체)s1.equals(s2)
→ true (내용 비교)
class Animal {
void sound() {
System.out.println("Some sound");
}
}
class Dog extends Animal {
void sound() {
System.out.println("Bark");
}
}
public class Main {
public static void main(String[] args) {
Animal a = new Dog();
a.sound();
}
}
🖍️ Bark
Animal a = new Dog();
a.sound();
→ Dog의 오버라이딩된 메서드 호출됨 → "Bark"
class Parent {
static void greet() {
System.out.println("Hello from Parent");
}
}
class Child extends Parent {
static void greet() {
System.out.println("Hello from Child");
}
}
public class Main {
public static void main(String[] args) {
Parent p = new Child();
p.greet();
}
}
🖍️ Hello from Parent
Parent p = new Child();
p.greet();
→static
은 클래스 타입 기준 → "Hello from Parent"
abstract class Shape {
abstract void draw();
}
class Circle extends Shape {
void draw() {
System.out.println("Draw Circle");
}
}
public class Main {
public static void main(String[] args) {
Shape s = new Circle();
s.draw();
}
}
🖍️ Draw Circle
Shape s = new Circle();
s.draw();
→ "Draw Circle"
class Super {
Super() {
System.out.println("Super constructor");
}
}
class Sub extends Super {
Sub() {
System.out.println("Sub constructor");
}
}
public class Main {
public static void main(String[] args) {
Sub obj = new Sub();
}
}
🖍️
Super constructor
Sub constructor
- Sub 객체 생성 시 → Super → Sub 순으로 호출됨
class Animal {}
class Cat extends Animal {}
public class Main {
public static void main(String[] args) {
Animal a = new Cat();
System.out.println(a instanceof Animal);
System.out.println(a instanceof Cat);
}
}
🖍️
true
true
Animal a = new Cat();
a instanceof Animal
→ truea instanceof Cat
→ true
class Parent {
int x = 10;
}
class Child extends Parent {
int x = 20;
}
public class Main {
public static void main(String[] args) {
Parent p = new Child();
System.out.println(p.x);
}
}
🖍️ 10
Parent p = new Child();
p.x
→ 10 (Parent 기준으로 접근됨)
interface Drawable {
void draw();
}
class Rectangle implements Drawable {
public void draw() {
System.out.println("Drawing Rectangle");
}
}
public class Main {
public static void main(String[] args) {
Drawable d = new Rectangle();
d.draw();
}
}
🖍️ Drawing Rectangle
instanceof
는 실제 객체 기준으로 판별한다(타입 일치 여부)instanceof null
→ 항상 falseinstanceof
가능class Animal {}
class Dog extends Animal {}
class Cat extends Animal {}
public class Main {
public static void main(String[] args) {
Animal a = new Dog();
System.out.println(a instanceof Dog);
System.out.println(a instanceof Cat);
System.out.println(a instanceof Animal);
}
}
🖍️
true
false
true
a
는 실제로Dog
객체 →instanceof Dog
→ truea
는Cat
은 아님 →instanceof Cat
→ falseDog
는Animal
을 상속 →instanceof Animal
→ true
interface Eater {}
class Human implements Eater {}
class Robot {} // Robot은 Object를 상속하고 있음
public class Main {
public static void main(String[] args) {
Object obj = new Human();
System.out.println(obj instanceof Eater);
System.out.println(obj instanceof Human);
System.out.println(obj instanceof Robot);
}
}
🖍️
true
true
false
Human
은Eater
구현 →instanceof Eater
→ trueobj
는Human
이므로instanceof Human
→ trueHuman
은Robot
아님 → false
new Robot() instanceof Object // true
Object obj = new Human();
→obj
는 실제로Human
객체
→Human
과Robot
은 아무 관계 없음
class A {}
public class Main {
public static void main(String[] args) {
A a = null;
System.out.println(a instanceof A);
}
}
🖍️ false
instanceof
는null
이면 무조건 false- 타입과 상관없음
class Animal {
void speak() {
System.out.println("Animal speaks");
}
}
class Cat extends Animal {
void speak() {
System.out.println("Meow");
}
void jump() {
System.out.println("Cat jumps");
}
}
public class Main {
public static void main(String[] args) {
Animal a = new Cat();
a.speak();
// a.jump(); // 컴파일 에러 발생 여부?
}
}
🖍️ Meow
Animal a = new Cat();
a.speak();
: Cat의 오버라이딩된 메서드 호출a.jump();
: a.jump() 는 업캐스팅된 참조로는 불가 → 컴파일 에러
class Parent {
void show() {
System.out.println("Parent");
}
}
class Child extends Parent {
void show() {
System.out.println("Child");
}
void onlyChild() {
System.out.println("Child specific method");
}
}
public class Main {
public static void main(String[] args) {
Parent p = new Child(); // 업캐스팅
p.show(); // 오버라이딩된 Child.show()
Child c = (Child) p; // 다운캐스팅 (정상)
c.onlyChild(); // Child의 전용 메서드
}
}
🖍️
Child
Child specific method
class A {}
class B extends A {}
class C extends A {}
public class Main {
public static void main(String[] args) {
A obj = new C(); // 실제로는 C 타입
B b = (B) obj; // C는 B의 하위 클래스 아님 → ClassCastException 발생
System.out.println("Cast success");
}
}
🖍️ ❗ 런타임 에러 (ClassCastException) 발생
Exception in thread "main" java.lang.ClassCastException: C cannot be cast to B
class Vehicle {
void run() {
System.out.println("Vehicle runs");
}
}
class Bike extends Vehicle {
void run() {
System.out.println("Bike runs fast");
}
}
public class Main {
public static void main(String[] args) {
Vehicle[] list = { new Vehicle(), new Bike() };
for (Vehicle v : list) {
v.run();
}
}
}
🖍️
Vehicle runs
Bike runs fast배열 선언:
Vehicle[] list = { new Vehicle(), new Bike() };
- list는 Vehicle 타입의 배열이지만,
그 안에는 Vehicle 객체와 업캐스팅된 Bike 객체가 있음.- 즉, 내부적으로는 이렇게 저장돼 있음:
list[0] → new Vehicle() list[1] → new Bike() ← Bike가 Vehicle로 업캐스팅됨
반복문 실행:
for (Vehicle v : list) { v.run(); }
- 첫 번째 반복:
v = new Vehicle()
→v.run()
→ Vehicle runs- 두 번째 반복:
v = new Bike()
v는 Vehicle 타입으로 보이지만, 실제 객체는 Bike이므로
→ 오버라이딩된Bike.run()
이 호출됨
→ Bike runs fast
class Animal {}
class Dog extends Animal {
void bark() {
System.out.println("Woof");
}
}
class Cat extends Animal {}
public class Main {
public static void main(String[] args) {
Animal a = new Cat();
if (a instanceof Dog) {
Dog d = (Dog) a;
d.bark();
} else {
System.out.println("Not a Dog");
}
}
}
🖍️ Not a Dog
a
는Cat
이므로instanceof Dog
→ false
→ else 블록 실행됨
class Base {
static void greet() {
System.out.println("Hello from Base");
}
void say() {
System.out.println("Base says hi");
}
}
class Derived extends Base {
static void greet() {
System.out.println("Hello from Derived");
}
void say() {
System.out.println("Derived says hi");
}
}
public class Main {
public static void main(String[] args) {
Base b = new Derived();
b.greet();
b.say();
}
}
🖍️
Hello from Base
Derived says hiBase b = new Derived(); b.greet(); // 정적 메서드 → 참조 변수 타입 기준 → Base.greet() b.say(); // 인스턴스 메서드 → 실제 객체 기준 → Derived.say()
greet()
은 static → 오버라이딩 아님 → Base 기준say()
는 오버라이딩 → Derived 기준