-
상속, instanceof, 추상, interfaceJAVA 2021. 7. 22. 22:56
상속 inheritance
타입변환과 다형성
다형성이란 같은 타입이지만 실행결과가 다향한 형태, 객체를 이용할 수 있는 성질을 말한다.
프로그램측면에서 보면 다형성은 하나의 타입에 여러객체를 대입함으로서 다양한 기능을 수행
할 수 있도록 한다.
다형성을 위해서 자바는 자식클래스가 부모클래스로 타입변환을 허용한다. 즉, 부모타입에 모든
자식객체들은 대입이 될 수가 있다. 이 기능을 이용하면 객체는 부품화가 가능하다.
타입변환이란 데이터타입을 다른 데이터 타입으로 변환하는 행위를 말한다. 기본 데이터 타입의
변환처럼 참조타입(class등)도 타입변환이 가능하다. 클래스타입변환은 직접적인 상속관계가
있는 클래스 사이에 발생한다.
자동타입변환(promotion)은 프로그램 실행도중에 자동적으로 타입변환이 일어나는 것을 말한다.
자동타입변환 개념은 자식은 부모의 특징과 기능을 상속받기 때문에 부모와 동일하게 취급될 수
있다는 것이다.
주의할 점은 자동타입변환이 된 후에는 부모타입에 선언된 필드와 메서드만 접근 가능하다.
비록 변수는 자식객체를 참조하지만 변수로 접근 가능한 멤버(필드,메서드)는 부모클래스의
멤버로만 제한된다. 그러나 예외가 있는데 메서드가 자식클래스에서 오버라이딩되었다면 부모
클래스의 메서드가 호출되는 것이 아니라 자식객체의 메서드가 호출된다.
추상 abstract
추상: 실체들 간에 공통되는 특성을 추출한 것.
추상메서드를 하나라도 가지고 있다면 클래스를 abstract클래스로 선언해주어야 한다.
또한 추상클래스는 new연산자로 객체 생성하지 못하고, 상속 통해 자식 클래스만 생성 가능.
추상메서드란? 선언부만 있고 구현부{}가 없는 메서드
ex) void method();
interface
인터페이스(interface)
자바에서 인터페이스는 객체의 사용방법을 정의한 참조타입이다. 인터페이스는
객체의 교환성을 높여주기 때문에 다형성을 구현하는 매우 중요한 역할을 한다.
특히, java8버전에서부터 인터페이스의 중요성은 더욱 커졌다. java8의 람다식
(Lambda)은 함수적 인터페이스의 구현객체를 생성하기 때문이다.
인터페이스는 개발코드와 객체가 서로 통신하는 접점역할을 한다. 개발코드가
인터페이스의 메서드를 호출하면 인터페이스는 객체의 매서드를 호출한다.
그렇기 때문에 개발코드는 내부구조를 알 필요가 없고 인터페이스의 메서드만
알고 있으면 된다.
개발코드가 직접 메서드를 호출하면 간단한데 중간에 인터페이스를 두는 이유는
개발코드를 직접 수정하지 않고 사용하는 객체를 변경할 수 있도록 하기 위해서 이다.
인터페이스는 하나의 객체가 아니라 여러 객체들과 사용이 가능하기 때문에 어떤 객체
를 사용하느냐에 따라 실행내용과 결과값이 다를 수 있어서 개발코드 측면에서 보면
코드의 변경없이 실행내용과 리턴값을 다양화할 수 있다는 장점이 있다.
// 1.상수필드(final static, constant field)
인터페이스는 객체의 사용설명서이므로 런타임시에 데이터를 저장할 수 있는 필드를
선언할 수 없다. 하지만 상수필드는 선언할 수 있다. 상수는 인터페이스에 고정된
값으로 런타임시에 값을 변경할 수 없다. 따라서 상수를 선언할 때는 반드시 초깃값을
대입해야 한다. 인터페이스에서 상수는 별도로 명시하지 않아도 자동으로 컴파일 과정에서
public static final이 추가된다.
// 2.추상메서드(Abstract Method)
추상메서드는 객체가 가지고 있는 메서드를 설명한 것으로 호출할 때 어떤 매개값이 필요하고,
리턴타입이 무엇인지를 알려준다.
실제 실행부는 구현객체(실제객체, 하위객체)가 가지고 있다. 인터페이스의 메서드는 무조건
추상메서드이기 때문에 public abstract을 생략해도 컴파일과정에서 자동으로 추가된다.
// 3.default메서드
default메서드는 인터페이스에 선언되지만, 사실은 구현객체가 가지고 있는
인터페이스 메서드라고 생각하면 된다. java8에서 default 메서드를 허용한
이유는 기존 인터페이스를 확장해서 새로운 기능을 추가하기 위해서이다.
default메서드는 실행블록을 가지고 있는 메서드로서 default키워드를 반드시
붙여야 하며 기본적으로 public 접근권한자를 생략해도 자동으로 컴파일 과정
에서 추가된다.
// 4.static메서드
정적메서드로 java8부터 작성할 수 있는데 default 메서드와는 달리 객체가 생성되지
않아도 인터페이스만으로 호출이 가능하다
// 5.익명객체
클래스에서 구현하여 따로 생성자를 만들지 않고
실행보드에서 이름없는(그래서 인터페이스 이름으로 넣음)
인터페이스형 익명객체를 만들어 바로 구현가능하다.
구현은 추상메서드를 당연히 해야하며, 추가로 메서드를 넣어도 상관없다.
//6. 다형성
1. 타입변환과 다형성
상속에서 타입변환과 다형성에 대해 보았듯이 인터페이스도 다형성을 구현하는 기법이 사용된다.
요즘에는 상속보다는 인터페이스를 통해서 다형성을 구현하는 경우가 많다.
다만 차이점은 상속은 같은 타입의 하위클래스를 만드느 기법이고 인터페이스는 동일한 클래스를
만드는 기법이다. 둘다 다형성을 구현하는 방법에서는 동일한 개념이다.
2. 매개변수의 다형성
자동타입변환은 필드의 값을 대입할 때에도 발생하지만 주로 메서드를 호출할 때
더 많이 발생한다.
매개값을 다양화하기 위해서는 상속에서는 매개변수를 부모타입으로 선언하고 호출
할 때에는 자식객체를 대입했지만 인터페이스에서는 매개변수를 인터페이스 타입으로
선언하고 메서드를 호출할 때 구현객체를 대입한다.
상속1
123456789public class A {}public class B extends A{}public class C extends A{}public class D extends B{}public class E extends C{}cs 1234567891011121314151617181920212223242526public class PromotionMain {public static void main(String[] args) {A a = new A();B b = new B();C c = new C();D d = new D();E e = new E();//자동형변환(promotion)a = b;a = c;a = d;a = e;// 타입변환불가// 직접적인 상속관계가 없기 때문에 타입변환 불가/*b = e;c = d;*/}}cs
상속2
자동형변환
부모
12345678910public class Parent {void method1() {System.out.println("Parent.method1 호출,,,");}void method2() {System.out.println("Parent.method2 호출,,,");}}cs 자식
123456789101112public class Child extends Parent{@Overridevoid method2() {System.out.println("Child.method2 호출,,,");}void method3() {System.out.println("Child.method3 호출,,,");}}cs 123456789101112131415161718192021222324252627282930313233343536public class ChildMain {public static void main(String[] args) {Child child = new Child();child.method1();child.method2();child.method3();System.out.println();Parent parent1 = child; //자동형변환(promotion)parent1.method1();parent1.method2();System.out.println(parent1 == child);System.out.println();Parent parent2 = new Parent();parent2.method1();parent2.method2();System.out.println();}}/* 출력 결과Parent.method1 호출,,,Child.method2 호출,,,Child.method3 호출,,,Parent.method1 호출,,,Child.method2 호출,,,trueParent.method1 호출,,,Parent.method2 호출,,,*/cs 상속3
다형성
부모
123456public class Vehicle {public void run() {System.out.println("승용차를 운전합니다!");}}cs 자식3개
123456public class Bus extends Vehicle {@Overridepublic void run() {System.out.println("버스를 운전합니다.");}}cs 123456public class Taxi extends Vehicle {@Overridepublic void run() {System.out.println("택시를 운전합니다.");}}cs 123456public class AutoBi extends Vehicle {@Overridepublic void run() {System.out.println("오토바이를 운전합니다.");}}cs 123456public class Driver {public void drive(Vehicle vehicle) {vehicle.run();}}cs 1234567891011public class DriverMain {public static void main(String[]args) {Driver driver = new Driver();driver.drive(new Vehicle());driver.drive(new Bus());driver.drive(new Taxi());}}cs 1번 : 승용차를 운전합니다. 2번 : 버스를 운전합니다. 3번 : 택시를 운전합니다.강제타입변환(Casting)
강제타입변환은 부모타입을 자식타입으로 변환하는 것을 말한다.
그렇다고 해서 모든 부모타입을 자식타입으로 강제형변환할 수 있는 것은 아니다.
자식타입이 부모타입으로 자동형변환 후에 자식타입으로 변환할 때만 강제 타입변환을 할 수 있다.
자식타입이 부모타입으로 자동형변환하면 부모타입에 선언된 필드와 메서드만 사용 할 수 있다.
만약 자식타입에 선언된 필드와 메서드를 꼭 사용해야 한다면 강제형 변환을 해서 다시 자식타입으로 변환한 후에 자식타입의 필드와 메서드를 사용하면 된다.
1234567891011121314151617181920212223242526272829public class ChildMain {public static void main(String[] args) {// 1. 자동형변환Parent parent = new Child();parent.field1 = "사용가능";// parent.field2 = "사용불가능";parent.method1();parent.method2(); // Child에서 재정의한 method2()// parent.method3(); 사용불가능// 2. 강제형변환Child child = (Child) parent;child.field1 = "사용가능";child.field2 = "사용가능";child.method1();child.method2();child.method3();// 3. 직접 강제형변환// ClassCastingException 에러 발생Parent parent1 = new Parent();Child child2 = (Child) parent1;// 빨간색은 오류표시는 없지만 실행시 예외가 걸린다.}}cs
추상클래스(상속)
1. 추상클래스의 개념
사전적 의미로 추상은 실체간에 공통된 특성을 추출한 것을 말한다.
예를 들어 새, 곤충, 물고기등의 실체에서 공통된 특성을 추출해 보면 움직인다 라는 동물의 공통점을 가지고 있다.
이와 같이 구체적인 실체라기 보다는 실체들의 공통된 특성을 가지고 있는 것을 추상적인 것이라 볼 수 있다.
클래스에서도 추상클래스를 정의할 수 있다. 객체를 직접 생성할 수 있는 클래스를 실체 클래스라고 하고, 이 클래스들의 공통적은 특성을 추출해서 선언한 클래스를 추상 클래스라고 한다.
추상클래스와 실체클래스는 상속적인 관계를 가지고 있다.
추상클래스가 부모클래스이고 실체클래스가 자식으로 구현되어 실체클래스는 추상클래스의 모든 속성을 상속받고 추가 적인 특성을 가질 수 있다.
여기서 속성이란 필드와 메서드를 말한다.
추상클래스는 실체클래스의 공통된 필드와 메서드를 추출해서 만들었기 떄문에 객체를 직접 생성할 수 없다.
다시 말해서 추상클래스는 new 연산자를 사용해서 인스턴스(객체) 를 생성할 수가 없다.
2. 추상클래스의 용도
1) 실체클래스들의 공통된 필드와 메서드들의 이름을 통일해서 사용할 목적
2) 실체클래스를 작성할 때 개발시간등을 감소시킬 수 있다.
3. 추상클래스의 선언 추상클래스를 선언할 때는 클래스 내부에 abstract 라는 키워드로 정의해야 한다.
abstract를 붙이게 되면 new 연산자로 객체를 생성하지 못하고 상속을 통해서 하위 클래스만 생성할 수 있다.
123456789101112131415161718192021public abstract class Phone {// 필드public String owner;// 생성자public Phone(String owner) {this.owner = owner;}// 메서드public void turnOn() {System.out.println("파워온!!!");}public void turnOff() {System.out.println("파워오프!!!");}}cs 123456789101112public class SmartPhone extends Phone{//default 생성자 없고 아래위 생성자를 오버로드 해야한다.public SmartPhone(String owner) {super(owner);}public void internetSearch() {System.out.println("인터넷 검색!!!");}}cs 12345678910111213141516public class SmartPhoneMain {public static void main(String[] args) {// 추상클래스는 new연산자로 객체를 생성할 수 없다.//Phone phone = new Phone("홍길동"); 추상클래스는 객체를 생성할 수 없다.SmartPhone smartphone = new SmartPhone("홍길동");System.out.println("phone.owner");smartphone.turnOn();smartphone.turnOff();smartphone.internetSearch();}}cs
interface구현
123456789101112131415161718192021public interface Remote {int MIN_VOLUMN = 0;int MAX_VOLUMN = 10;void turnOn();void turnOff();void SetVolumn(int volumn);default void setMute(boolean mute) {if(mute) {System.out.println("무음처리");}else {System.out.println("무음해제");}}static void changBattery() {System.out.println("건전지를 교체합니다.");}}cs 1234567891011121314151617181920212223242526public class Audio implements Remote {private int volumn;@Overridepublic void turnOn() {System.out.println("오디오 파워온!!");}@Overridepublic void turnOff() {System.out.println("오디오 파워오프!!");}@Overridepublic void SetVolumn(int volumn) {if (volumn > Remote.MAX_VOLUMN) {this.volumn = Remote.MAX_VOLUMN;} else if (volumn < Remote.MIN_VOLUMN) {this.volumn = Remote.MIN_VOLUMN;} else {this.volumn = volumn;}System.out.println("현재 오디오의 볼륨은 " + this.volumn + "입니다.");}}cs 123456789101112131415161718192021222324252627public class Television implements Remote{private int volumn;@Overridepublic void turnOn() {System.out.println("TV 파워온!!");}@Overridepublic void turnOff() {System.out.println("TV 파워온!!");}@Overridepublic void SetVolumn(int volumn) {if (volumn > Remote.MAX_VOLUMN) {this.volumn = Remote.MAX_VOLUMN;} else if (volumn < Remote.MIN_VOLUMN) {this.volumn = Remote.MIN_VOLUMN;} else {this.volumn = volumn;}System.out.println("현재 오디오의 볼륨은 " + this.volumn + "입니다.");}}cs 12345678910111213141516171819202122public class RemoteControlMain {public static void main(String[] args) {// 인터페이스형의 Audio객체와 Television객체 생성Remote audio = new Audio();Remote tv = new Television();audio.turnOn();audio.SetVolumn(5);audio.setMute(true);audio.turnOff();System.out.println();tv.turnOn();tv.SetVolumn(20);tv.setMute(true);tv.turnOff();}}cs 'JAVA' 카테고리의 다른 글
java.lang.Object 클래스 (0) 2021.07.23 인터페이스, 내부클래스, 예외 (0) 2021.07.23 set,get,상속,overriding & overloading (0) 2021.07.22 메서드,싱글톤,static,상수 (0) 2021.07.22 static main, 접근제한자, 싱글톤정의 (0) 2021.07.22