Java
4/8 - 상속, 인터페이스, 중첩 선언과 익명 객체
Jiwon_Loopy
2025. 4. 12. 21:22
반응형
목차
상속
- 재사용
- 코드 줄임
- 유지보수성을 높임
- 상위 그룹으로 한 번에 묶을 수 있음(그룹핑) → 통일성, 일관성
- 자식 클래스에 extneds 키워드를 이용
package ch07.sec02;
public class Phone {
public String model;
public String color;
public void bell() {
System.out.println("벨이 울립니다.");
}
public void receiveVoice(String message) {
System.out.println("자기: " + message);
}
public void sendVoice(String message) {
System.out.println("상대방: " + message);
}
public void hangUp() {
System.out.println("전화를 끊습니다.");
}
}
package ch07.sec02;
public class SmartPhone extends Phone{
public boolean wifi;
public SmartPhone(String model, String color) {
this.model = model;
this.color = color;
}
public void setWifi(boolean wifi) {
this.wifi = wifi;
System.out.println("와이파이 상태를 변경했습니다.");
}
public void internet() {
System.out.println("인터넷에 연결합니다.");
}
}
package ch07.sec02;
public class SmartPhoneExample {
public static void main(String[] args) {
SmartPhone myPhone = new SmartPhone("갤럭시","은색");
System.out.println("모델: " + myPhone.model);
System.out.println("색상: " + myPhone.color);
System.out.println("와이파이 상태: " + myPhone.wifi);
myPhone.bell();
myPhone.sendVoice("여보세요.");
myPhone.receiveVoice("안녕하세요! 저는 홍길동인데요.");
myPhone.sendVoice("아~ 네, 반갑습니다.");
}
}
실행 결과
모델: 갤럭시
색상: 은색
와이파이 상태: false
벨이 울립니다.
상대방: 여보세요.
자기: 안녕하세요! 저는 홍길동인데요.
상대방: 아~ 네, 반갑습니다.
- 부모가 자식으로 자동 형 변환이 된다.
- // 자동 형 변환 Phone myPhone2 = new SmartPhone("아이폰","검정"); // myPhone2.wifi(); // 사용 불가 // SmartPhone myPhone3 = myPhone2; // 사용 불가
- 자식이 부모 타입으로 형 변환된 경우에만 강제 형 변환 가능
- // 강제 형 변환 (원래 자식 타입이 부모 타입으로 형 변환된 경우만 가능) Phone myPhone2 = new SmartPhone("아이폰","검정"); SmartPhone myPhone3 = (SmartPhone) myPhone2; myPhone3.internet(); // 사용 가능 Phone myPhone4 = new Phone(); // Phone은 SmartPhone의 부모 클래스 SmartPhone myPhone5 = (SmartPhone) myPhone4; // 강제 형 변환, 에러
- 부모 객체가 생성된 후 자식 객체가 생성됨
- 상속과 구현의 차이
- 상속
- class
- 한 개만 가능
- 구현
- interface
- 여러 개 가능
- 인터페이스끼리 상속
- 상속
메소드 오버라이딩 (재정의)
- 부모의 메서드를 상속받은 자식 클래스에서 각각의 기능, 특성에 맞추어 구현하는 것
- 자식 메서드 우선적으로 실행
- 부모 메소드 선언부 (리턴 타입, 메소드 이름, 매개 변수)와 동일해야 한다.
- 더 강한 접근 제한으로 오버라이딩 할 수 없다.
- 새로운 예외를 thorws할 수 없다.
- ≠ Overloading (오버로딩하고는 다름)
- 다형성과 관련 있음
- 실행 코드는 하나 인데 결과가 달라지는 것
- super는 부모의 필드 값을 가져올 수 있음
- final은 더 이상 상속 불가능
- 오버라이드 어노테이션
- @Override
package ch07.sec04.exam01; public class Calculator { public double areaCircle(double r) { System.out.println("Computer 객체의 areaCircle() 실행"); return 3.14159 * r * r; } } package ch07.sec04.exam01; public class Computer extends Calculator{ @Override public double areaCircle(double r) { System.out.println("Computer 객체의 areaCircle() 실행"); return Math.PI * r* r; } } package ch07.sec04.exam01; package ch07.sec04.exam01; public class ComputerExample { public static void main(String args[]) { Calculator calculator = new Calculator(); int r = 10; System.out.println("원 면적: " + calculator.areaCircle(r)); System.out.println(); Computer computer = new Computer(); System.out.println("원 면적: " + computer.areaCircle(r)); System.out.println(); Calculator car = computer; System.out.println("원 면적: " + car.areaCircle(r)); // 부모의 메서드가 실행 -> 실제 자식 메서드가 실행 System.out.println(); // car.game() // 사용 불가 } } 실행 결과 Calculator 객체의 areaCircle() 실행 원 면적: 314.159 Computer 객체의 areaCircle() 실행 원 면적: 314.1592653589793 Computer 객체의 areaCircle() 실행 원 면적: 314.1592653589793
- 형 변환 시 원래 객체(new로 생성된 객체)로 돌아갈 수는 있다. (강제 형 변환 조건)
- 있는 것만 쓸 수 있지만, 재정의 한 경우 예외 적으로 재정의 한 것으로 쓸 수 있다.
- 있는 것 ⇒ 왼쪽(선언 변수)
- 생성 가능한 것 ⇒ 오른쪽 범위가 더 좁으면 가능
- 필드의 다형성
- 부모 타입의 필드에 여러가지 상속을 받은 자식 객체가 대입 될 수 있음
package ch07.sec08.exam01; public class CarExample { public static void main(String args[]) { Car myCar = new Car(); myCar.tire = new Tire(); myCar.run(); myCar.tire = new HankookTire(); myCar.run(); myCar.tire = new KumhoTire(); myCar.run(); } } 실행 결과 회전합니다. 한국 타이어가 회전합니다. 금호 타이어가 회전합니다.
- 다형성을 이용한 구현
- package ch07.sec08.exam02; public class Vehicle { public void run() { System.out.println("차량이 달립니다."); } } package ch07.sec08.exam02; public class Driver { public void drive(Vehicle vehicle) { vehicle.run(); } } package ch07.sec08.exam02; public class Bus extends Vehicle { @Override public void run() { System.out.println("버스가 달립니다."); } } package ch07.sec08.exam02; public class Taxi extends Vehicle { @Override public void run() { System.out.println("택시가 달립니다."); } } package ch07.sec08.exam02; public class DriverExample { public static void main(String[] args) { Driver driver = new Driver(); Bus bus = new Bus(); driver.drive(bus); Taxi taxi = new Taxi(); driver.drive(taxi); } } 실행 결과 버스가 달립니다. 택시가 달립니다.
객체 타입 확인
- instanceOf
- 변수가 참조하는 객체의 타입을 확인할 때 쓰임
추상 클래스
- abstract 키워드를 앞에 붙여 사용
- 객체를 생성할 수 없음
- 새로운 클래스를 만들기 위한 부모 클래스로만 사용되므로 extends 뒤에 와야함
package ch07.sec10.exam01;
public abstract class Phone {
String owner;
Phone(String owner){
this.owner = owner;
}
void turnOn() {
System.out.println("폰 전원을 켭니다.");
}
void turnOff() {
System.out.println("폰 전원을 끕니다.");
}
}
package ch07.sec10.exam01;
public class SmartPhone extends Phone {
SmartPhone(String owner){
super(owner); // 기본 생성자 매개 변수 써서 없으므로 만들어 주기
}
void internetSearch() {
System.out.println("인터넷 검색을 합니다.");
}
}
package ch07.sec10.exam01;
public class SmartPhoneExample {
public static void main(String[] args) {
//Phone phone = new phone(); //
SmartPhone smartPhone = new SmartPhone("홍길동");
smartPhone.turnOn();
smartPhone.internetSearch(); // 에러, 자동 형 변환 필요
smartPhone.turnOff();
Phone phone = new SmartPhone("홍길동");
phone.turnOn();
// phone.internetSearch(); // 에러, 자동 형 변환 필요
phone.turnOff();
}
}
- 추상 메서드 재정의
- 자식 클래스들의 공통 메소드를 뽑아선언
- 반드시 자식 클래스에서 재정의 해야 함
package ch07.sec10.exam02; public abstract class Animal { public void breathe() { System.out.println("숨을 쉽니다."); } public abstract void sound(); } package ch07.sec10.exam02; public class Dog extends Animal{ @Override public void sound() { System.out.println("멍멍"); } } package ch07.sec10.exam02; public class Cat extends Animal{ @Override public void sound() { System.out.println("야옹"); } } package ch07.sec10.exam02; public class AbstractMethodExample{ public static void main(String args[]) { Dog dog = new Dog(); dog.sound(); Cat cat = new Cat(); cat.sound(); animalSound(new Dog()); animalSound(new Cat()); } private static void animalSound(Animal animal) { animal.sound(); } } 출력 결과 멍멍 야옹 멍멍 야옹
- abstract void receive();
봉인 클래스
- final 클래스를 제외한 모든 클래스는 부모 클래스가 될 수 있음
- Java 15부터 무분별한 자식 클래스 생성 방지를 위해 sealed 클래스가 도입
public sealed class Person permits Employee, Manager { ... }
- permits를 기준으로 상속 가능한 자식 클래스들을 뒤에 붙여 해당 클래스들에게만 권한을 준다.
인터페이스
- 여러 인터페이스를 상속할 수 있음
- 프로그램(시스템)간의 사이에 연결된 프로그램 (중간 역할)
- 구성 멤버
- 상수
- 추상 메서드
- 일반 메서드
- 정적 메서드
- private 메서드
- 다형성
- 부모타입으로 모든 자식을 저장 가능(자동 형 변환) + 실행코드는 동일하지만 실행 결과가 달라짐(메서드 재정의)
- 인터페이스 + 추상메서드 (재정의)
- interface 키워드를 앞에 붙여 선언
- 접근 제한자를 아무것도 쓰지 않으면 기본적으로 public이다. (static 취급)
- 디폴트 메서드는 default를 밝혀주어야 한다.
- implements 클래스명 으로 상속받을 수 있다.
package ch08.sec02;
public interface RemoteControl {
int VOLUME = 0; // static final -> 상수
void turnOn(); // public abstract
// 일반 메서드
default int add(int x, int y) {
return x + y;
}
}
- 인터페이스 구현해보기
package ch08.sec02;
public interface RemoteControl {
int VOLUME = 0; // static final -> 상수
void turnOn(); // public abstract
// 일반 메서드
default int add(int x, int y) {
return x + y;
}
}
package ch08.sec02;
public class RemoteControlExample {
public static void main(String[] args) {
RemoteControl rc = new Television(); // 자동 형 변환
rc.turnOn(); // 다형성
}
}
package ch08.sec02;
public class Television implements RemoteControl {
@Override
public void turnOn() {
System.out.println("TV를 켭니다.");
}
}
실행 결과
TV를 켭니다.
- 갈아끼우는 법
package ch08.sec02;
public class RemoteControlExample {
public static void main(String[] args) {
RemoteControl rc = new Television(); // 자동 형 변환
rc.turnOn(); // 다형성
rc = new Audio(); // 자동 형 변환
rc.turnOn(); // 다형성
}
}
출력 결과
TV를 켭니다.
오디오를 켭니다.
- 다중 인터페이스
- ,(쉼표)를 통해 여러 가지를 상속할 수 있다.
- 인터페이스끼리 상속이 가능함
- 여러 개도 가능
중첩 클래스
- 클래스 안 클래스
- 멤버 클래스
- 인스턴스 멤버 클래스
- 하나를 생성해야 그 안의 것을 생성 가능
- 정적 멤버 클래스
- static
- 상위 클래스를 생성하지 않아도 안쪽 클래스 생성 가능
- 인스턴스 멤버 클래스
- 로컬 클래스
- 메서드가 실행할 때만 객체 생성 가능
익명 객체 *(중요)
- 이름이 없는 객체
- 익명상속(자식)객체
- 익명구현객체
- 명시적으로 클래스를 선언하지 않아 쉽게 객체를 생성할 수 있음
- 일회성으로 사용
- 람다표현식 (Lanbda Expression)
package ch08.sec02;
import ch07.sec10.exam02.Animal;
public class RemoteControlExample {
public static void main(String[] args) {
**// 익명 구현 객체 (interface)**
// implements를 구현한 구현체는 이름이 없음
// 주로 1회용에 사용 (일회성)
RemoteControl rc = new RemoteControl() {
@Override
public void turnOn() {
System.out.println("에어컨을 켭니다.");
}
}; // 실행문 이므로, 세미콜론
rc.turnOn();
**// 익명 상속(자식) 객체 (class)**
Animal ani = new Animal() {
@Override
public void sound() {
System.out.println("어흥");
}
};
ani.sound();
}
}
실행 결과
에어컨을 켭니다.
어흥
- 다양한 사용법
// 1
cal(new LabdaEX(){
@Override
public int calc(int x, int y){
return x-y;
}
}
// 2
cal((x,y) -> {
return x+y;
}
// 3
cal(x,y) -> x-y;
- 함수를 매개변수로 넘길 수 없기 때문에, 람다를 이용하여 콜백으로 넘겨 비슷한 기능을 내기 위해 functional interface를 사용
- 무조건 추상 메서드가 1개만 있어야 사용 가능
메모
- super, this는 항상 맨 위에 있어야 함
- 어노테이션
- @어노테이션 명으로 표기
- 강제 형 변환은 원래가 중요 (자식 → 부모 → 자식) 강제 형 변환 가능
- 자식 → 부모 자동 형 변환
- 부모 → 자식 강제 형 변환 (조건 : 원래 자식)
- 추상 클래스
- 객체 생성 불가
- 상속 받은 후 객체 생성
- 추상메서드가 한 개 이상이 있으면 반드시 추상클래스
- 기본자료형 ↔ 참조자료형
int[] arr = {1,2,3,4,5};
// 기본 자료형 -> 참조 자료형
Integer[] arr2 = Arrays.stream(arr).boxed().toArray(new IntFunction<Integer[]>() {
@Override
public Integer[] apply(int value) {
return new Integer[value];
}
});
// 참조 자료형 -> 기본 자료형
int[] arr3 = Arrays.stream(arr2).mapToInt(i->i).toArray();
728x90
반응형