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
반응형