JAVA_09_상속,재정의(overriding),인터페이스(interface)

김민영·2024년 2월 26일

JAVA

목록 보기
10/10
post-thumbnail

상속(inheritance)

  • 객체지향 프로그램 4대 특징 중 하나

  • 실세계에서의 상속은 상위 객체의 속성이 하위 객체에 몰려져서 하위 객체가 상위 객체의 속성을 모두 가지는 개념

  • 자바에서의 상속은 자식클래스가 부모클래스의속성을 물려 받고 기능을 추가하여 확장(extends)하는 개념

  • 상속은 슈퍼클래스의 필드와 메서드를 물려 받아서 코드를 재사용 함으로써 코드 작성에 드는 시간과 비용을 줄일 수 있음

  • 기존에 이미 잘 만들어진 클래스를 재사용하여 새로운 클래스를 생성하는 자바 문법 <- 중요!
    즉, 특정 클래스를 만들 때 기존의 클래스의 데이터(속성)와 기능(메서드)을 그대로 물려 받아서 중복적인 코드를 없애줌 (클래스의 재사용, 코드의 중복을 없애줌)

  • 자식과 부모의 관계로 형성이 되어 있음
    ==> 부모클래스 : Supper, Parent 클래스 라고 하기도 함
    ==> 자식클래스 : Sub, Child 클래스 라고 하기도 함
    ==> 자식은 부모의 멤버보다 같거나 많다

  • 상속의 대상은 멤버(멤버변수, 멤버메서드)
    ==> 단, 생성자나 private 접근 제한을 갖는 멤버변수와 멤버메서드는 상속에서 제외

  • 상속 시 사용되는 키워드 : extends

  • 상속은 단일 상속만 가능 ==> 즉, 상속을 받을 수 있는 클래스는 하나다

  • 상속의 장점은 클래스의 수정을 최소화시킬 수 있다는 점, 유지보수의 시간을 최소화시켜 준다는 점이다

형식)
		[접근제한]Class 자식클래스명 extends 부모클래스명 {
				......;
 		}
	
  • 상속관계 : " ~ 은 ~ 이다" ==> is ~ a 관계

  • 포함관게 : " ~ 은 ~ 를 가지고 있다" ==> has ~ a 관계 ==> 사람은 (name, age, id)를 가지고 있다

  • 주의사항) 부모클래스는 반드시 기존에 미리 정의되어 있어야 함


  • Car
// 부모 클래스
public class Car {		// 자동차 클래스
	
	// 멤버변수
	int cc;
	int door;
	

}
public class Sonata extends Car{
	
	String model;		// 차량 모델명
	
	// int cc;
	// int door;
	
	void gerCarInfo() {
		System.out.println("모델명 >>> "+model);
		System.out.println("배기량 >>> "+cc);
		System.out.println("차량 문 수 >>> "+door);
	}
}

Sonata 클래스 객체 생성 과정

  • Sonata 클래스의 객체 생성 시에 JVM은 우선적으로 Car라는 부모 클래스의 객체를 먼저 생성한 후에 Sonata 클래스의 객체를 생성
public class Car_01 {

	public static void main(String[] args) {
		
		Sonata sonata = new Sonata();
		
		sonata.model = "소나타";
		sonata.cc = 2000;
		sonata.door = 4;
		
		sonata.gerCarInfo();

	}

}

출력결과


1. super 키워드

  • 부모의 멤버를 호출하는 명령어
    형식 ) super.부모클래스멤버(멤버변수, 멤버메서드)

2. this 키워드

  • 현재 클래스에 소속된 멤버를 호출하는 명령어
  • this 키워드는 현재 객체 자기 자신을 의미함
    형식 ) this.현재(자식)클래스멤버(멤버변수, 멤버메서드)
public class Car2 {

	int cc;
	int door;
	String color = "검정색";
	
}
public class Avante extends Car2{
	
	String color = "흰색";
	// 부모의 멤버보다 자식의 멤버가 우선순위가 높다
	
	void getCarInfo() {
		
		System.out.println("엔진 : " + cc + ", 차량 문 수 : " + door + ", 색상 : " + color);
		
		System.out.println("엔진 : " + cc + ", 차량 문 수 : " + door + ", 색상 : " + super.color);
																			// super 를 통해 부모를 불러옴
		System.out.println("엔진 : " + cc + ", 차량 문 수 : " + door + ", 색상 : " + this.color);
																			// this 를 통해 객체 자기 자신을 불러옴
		
	}

}

public class Car_02 {

	public static void main(String[] args) {
		
		Avante avante = new Avante();
		
		avante.cc=1600;
		avante.door=4;
		avante.getCarInfo();

	}

}

출력결과



public class Person {
	
	// 멤버변수
	String juminNo;		// 주민번호
	String name;		// 이름
	int age;			// 나이
	String job; 		// 직업

}
  • 급여
public class Employee extends Person {
	
	int salary;		// 급여
	
	void getEmployeeInfo() {
		System.out.println("주 민 번 호 >>> "+ juminNo);
		System.out.println("이	름 >>> "+ name);
		System.out.println("나	이 >>> "+ age);
		System.out.println("직	업 >>> "+ job);
		System.out.println("급	여 >>> "+ salary + "만원");
	}

}
  • 학생
public class Student extends Person {
	
	String major;	// 학과
	
	public Student() {
		super(); // 부모클래스를 기본 생성자에 호출해줘야 오류가 안남
	} // 기본 생성자
	
	public Student(String juminNo, String name, int age, String job,String major) {
		
		super();	// 부모클래스를 호출
		this.juminNo=juminNo;
		this.name=name;
		this.age=age;
		this.job=job;
		this.major=major;
	} // 인자생성자
	
	void getStudentInfo() {
		System.out.println("주 민 번 호 >>> "+ juminNo);
		System.out.println("이	름 >>> "+ name);
		System.out.println("나	이 >>> "+ age);
		System.out.println("직	업 >>> "+ job);
		System.out.println("학	과 >>> "+ major);
	}
}
  • person main
public class Person_03 {

	public static void main(String[] args) {
		
//		Student student = new Student();
		Student student = new Student("001101-2234567", "홍길자", 25, "대학생", "영문학과");
		
		student.getStudentInfo();
		
		System.out.println();
		
		Employee employee = new Employee();
		employee.juminNo = "740517 - 1234567";
		employee.name = "홍길동";
		employee.age=51;
		employee.job="회사원";
		employee.salary=1000;
		employee.getEmployeeInfo();

	}

}

출력결과


  • x와 y만 설정한 부모클래스
public class Point {
	
	int x;
	int y;
	
	public Point() { }	// 기본 생성자
	
	public Point(int x, int y) { 
		this.x=x;
		this.y=y;
	}	// 인자 생성자
	
	

}
  • 부모클래스를 호출하고 자식클래스에서 새로운 변수 생성

1. super() 키워드

  • 자식클래스에서 부모클래스의 생성자를 호출하는 명령어
    형식) supper(인자); --> 인자는 생략 가능

2. this() 키워드

  • 현재(자식) 클래스에서 현재 클래스 안에 있는 다른 생성자를 호출하는 명령어
    형식) this(인자);

    - 주의 ) this() 키워드를 사용 시애는 반드시 생성자 첫 문장에 와야 함

public class Point3D extends Point{
	
	int z;
	public Point3D() {
		super(); // 부모 클래스의 기본 생성자 호출
	} // 기본생성자
	
	public Point3D(int x,int y) {
		
//		super(); // 부모 클래스의 기본 생성자 호출 - 먼저 호출해줘야 오류 X
//		this.x=x;
//		this.y=y;
		super(x,y); // 부모클래스의 인자 생성자 호출
	} // 인자 생성자
	public Point3D(int x,int y,int z) {
//		this.x=x;
//		this.y=y;
		this(x,y); // 변수 2개짜리 인자생성자가 호출
		this.z=z;
	} // 인자 생성자
	
	void output() {
		System.out.println("x 좌표 >>> " + x);
		System.out.println("y 좌표 >>> " + y);
		System.out.println("z 좌표 >>> " + z);
	}
}
  • point main
public class Point_04 {

	public static void main(String[] args) {

		Point3D point = new Point3D(5,3,2);
		
		point.output();

	}

}

출력결과


  • Volume(부모클래스)
public class Volume {
	int volume = 1;
	public void setVolume(int volume) {
		this.volume=volume;
	}
	
	public int getVolume() {
		return volume;
	}
	
	// 볼륨 올리는 메서드
	void volumeUp() { 
		volume++;
		
		if(volume > 15) {
			volume = 15;
		}
	}
	// 볼륨 내리는 메서드
	void volumeDown() { 
		volume--;
		
		if(volume < 1) {
			volume = 1;
		}
	}
}
  • TV(자식클래스)
public class TV extends Volume{

}
  • Audio(자식클래스)
public class Audio extends Volume {

}
  • Computer(자식클래스)
public class Computer extends Volume {

}
  • Volume main
import java.util.Scanner;

public class Volume_05 {
	
	public static void main(String[] args) {
		
		TV tv = new TV();
		Audio audio = new Audio();
		Computer computer = new Computer();
		
		Scanner sc = new Scanner(System.in);
		
		while(true) {
			System.out.println("1. TV / 2. Audio / 3. Computer / 4. 종료");
			
			System.out.print("위 메뉴 중 하나를 선택하세요 : ");
			
			int menu = sc.nextInt();
			
			if(menu == 4) {
				break;
			}
			
			System.out.println("1. 볼륨 Up / 2. 볼륨 Down");
			int volume = sc.nextInt();
			
			switch (menu) {
			case 1:  // TV 메뉴 선택
				if(volume == 1) {
					tv.volumeUp();
				}else {
					tv.volumeDown();
				}
				break;
			case 2:  // Audio 메뉴 선택
				if(volume == 1) {
					audio.volumeUp();
				}else {
					audio.volumeDown();
				}
				break;
			case 3:  // Computer 메뉴 선택
				if(volume == 1) {
					computer.volumeUp();
				}else {
					computer.volumeDown();
				}
				break;
			}
			System.out.println();
			
			System.out.println(":::::::::::::::::::::::::::::::::::::::::::::");
			System.out.println("TV Volume : " + tv.getVolume()+" / "+"Audio Volume : " + audio.getVolume()+" / "+"Computer Volume : " + computer.getVolume());
		}
		
		System.out.println();
		System.out.println("수고하셨습니다.");
		sc.close();

	
	}
}

출력 결과


overriding

메서드 재정의(Method Overriding)

  • 부모 클래스에서 정의한 메서드를 자식 클래스에서 자식 클래스에 맞게 다시 작성(재정의)하는 것을 말함.

[메서드 재정의 특징]
1. 반드시 상속 관계에서만 발생함 (메서드 다중 정의 : 동일한 클래스 내에서 발생)
2. 부모 클래스의 원형 메서드를 자식 클래스에서 재정의(다시 작성)

[메서드 재정의 조건]
1. 반드시 접근지정자, 리턴타입(반환형), 매개변수 갯수와 자료형 모두 일치해야 함
(메서드 다중정의 : 매개변수의 갯수가 다르거나, 갯수가 같다면 자료형이 달라야 함)
2. 접근 지정자는 확대 가능(축소는 불가능)


  • Animal (부모 클래스)
public class Animal {

	void sound() {
		
		System.out.println("소리를 냅니다.~~~");
	
	}  // sound() 메서드 end
	
}
  • Dog (자식 클래스)
public class Dog extends Animal {

	// 메서드 재정의
	// void sound() {
		
	// 	System.out.println("멍멍멍~~~");
	
	// }
	
	@Override
	void sound() {

		System.out.println("멍멍멍~~~");
	}
	
}
  • Cat (자식 클래스)
public class Cat extends Animal {

	@Override
	void sound() {
	
		System.out.println("야옹야옹~~~");
	
	}
	
}
  • Tiger (자식 클래스)
public class Tiger extends Animal {

	@Override
	void sound() {
	
		System.out.println("어흥어흥~~~");
		
	}
	
}
  • Animal main
public class Animal_01 {

	public static void main(String[] args) {
	
		Dog dog = new Dog();
		Cat cat = new Cat();
		Tiger tiger = new Tiger();
		
		dog.sound();
		cat.sound();
		tiger.sound();
		

	}

}

결과 출력

부모 클래스를 자식 클래스에서 재정의하여 자식클래스의 각각의 출력문을 만들고 메인에서 모든 클래스를 불러온다


  • shape 부모 클래스
public class Shape {

	void draw() {
		
		System.out.println("그리다~~~");
		
	}
	
}
  • Rextangle 자식 클래스
public class Rectangle extends Shape {

	@Override
	void draw() {
		
		System.out.println("사각형을 그리다~~~");
	}
}
  • Line 자식 클래스
public class Line extends Shape {

	@Override
	void draw() {
		
		System.out.println("선을 그리다~~~");
	}
}
  • Circle 자식 클래스
public class Circle extends Shape {

	@Override
	void draw() {
		
		System.out.println("원을 그리다~~~");
	
	}
}
  • Shape main
public class Shape_02 {

	public static void main(String[] args) {
		
		Line line = new Line();
		Circle circle = new Circle();
		Rectangle rectangle = new Rectangle();
		
		line.draw(); circle.draw(); rectangle.draw();

	}

}

출력 결과


인터페이스(interface)

1. 완벽한 추상화를 제공한다

  • 일종의 추상 클래스 하지만 추상 클래스보다 추상화 정도가 더 높다
  • 실제 구현된 것이 전혀 없는 기본 설계도(알맹이 없는 껍데기)
  • 추상 메서드(알멩이 없는 껍데기)와 상수만을 멤버로 갖는다
  • 인스턴스를 생성할 수 없고, 클래스 작성에 도움을 줄 목적으로 사용
  • 미리 정해진 규칙에 맞게 구현하도록 표준을 제시하는데 사용 ==> 명세서

2. 모든 메서드가 추상화(추상 메서드)
3. 프로젝트 진행 시 표준 규약에 따른다 ==> 추상 클래스보다 더 많이 사용
4. 인터페이스는 상수와 추상메서드로만 구성이 되어 있음
5. 모든 변수는 상수가 된다

  • 예) public static final 로 인식

6. 모든 메서드는 추상메서드가 된다

  • 예) public abstract 로 인식

7. 인터페이스는 객체 생성이 불가능
8. 자식 클래스로 상속을 하여 자식 클래스에서 객체 생성
==> 인터페이스의 추상 메서드는 반드시 재정의(강제성이 부여)
9. 인터페이스는 다중 상속을 제공

10. class -> interface 키워드 사용
extends -> implements 키워드 사용

※ 인터페이스 사용 목적

  • 스펙을 주어 클래스들이 그 기능을 서로 다르게 구현할 수 있도록 하는 클래스의 규격 선언, 클래스의 다향성을 실현하는 도구

[인터페이스 장점]
1. 개발 시간을 단축할 수 있음
2. 표준화가 가능

public interface Inter {
	
	int num = 50;		// 인스턴스 멤버변수 - 상수
	
	void output1();		// 추상 메서드
	
	void output2();		// 추상 메서드
	
}
public class Sub implements Inter {

	@Override
	public void output1() {
		System.out.println("인터페이스 output1 메서드 정의");
		
	}

	@Override
	public void output2() {
		System.out.println("인터페이스 output2 메서드 정의");
		
	}

}
public class Inter_01 {

	public static void main(String[] args) {

		// 인터페이스는 객체 생성 불가능
		// Inter inter = new Inter();
		
		Sub sub = new Sub();
		
		// static final 상수로 인식
		// 상수 값을 변경하는 것은 불가능
		// sub.num = 237;
		
		sub.output1();
		sub.output2();

	}

}

결과 출력


- 인터페이스 다중 상속

- 인터페이스끼리 상속받을 경우 extends
- 클래스가 인터페이스를 상속받을 경우 implements

interface Inter1 {
	void aa();
}

interface Inter2{
	void bb();
}
// 인터페이스끼리 상속받을 경우 extends 
interface Inter3 extends Inter1, Inter2{
	
	// void aa(); 상속이 된 추상 메서드
	// void bb(); 상속이 된 추상 메서드
	
	void cc();
	
}

// 클래스가 인터페이스를 상속받을 경우 implements
class Total implements Inter3{

	@Override
	public void aa() {
		System.out.println("aa() 추상 메서드 재정의");
		
	}

	@Override
	public void bb() {
		System.out.println("bb() 추상 메서드 재정의");
		
	}

	@Override
	public void cc() {
		System.out.println("cc() 추상 메서드 재정의");
		
	}
	
}

// 인터페이스는 다중상속 가능

public class Main_02 {
	
	public static void main(String[] args) {
		Total total = new Total();
		total.aa(); total.bb(); total.cc();
		
	}

}

결과 출력


  • 한 클래스에서 선언 가능
interface Camera{
	// 사진 찍는 기능
	void photo();
}
interface Search{
	// TV보는 기능
	void search();
}
interface Mp3{
	// 음악 듣는 기능
	void playMusic();
}

class MyPhone implements Camera, Search, Mp3{

	@Override
	public void playMusic() {
		System.out.println("핸드폰으로 음악");
		
	}

	@Override
	public void search() {
		System.out.println("핸드폰으로 검색");
		
	}

	@Override
	public void photo() {
		System.out.println("핸드폰으로 사진");
		
	}
	
}

public class Main_03 {

	public static void main(String[] args) {
		MyPhone myphone = new MyPhone();
		
		myphone.playMusic();
		myphone.photo();
		myphone.search();

	}

}

결과 출력


profile
나다

0개의 댓글