Inheritance(상속)은 부모가 자식에게 물려주는 것 입니다.
클래스가 A클래스가 있고 B클래스가 있으면 B가 A의 기능을 물려받으면서 사용하고 싶으면 상속이라는 개념을 사용해서 가능합니다.
상속을 할 경우에는 extends와 implement가 있습니다.
크게 보았을때 둘의 차이점은 extends는 단일상속, 부모클래스의 기능을 그대로 사용할 수 있으며, 굳이 부모클래스의 기능을 구현하지 않아도 될 경우에는 안해도됩니다.
하지만 implement 구현은 override로 자식클래스(인터페이스)가 부모인터페이스의 기능을 재정의를 무조건해야하며, 다중상속이 가능하다고 일단 이렇게만 차이점을 알고 있으면 됩니다.
class A{
int a;
void A_calssMethod(){
}
}
class B extends A{
String b;
void B_classMethod(){
}
}
public static void main(String[] args) {
B b = new B();
b.A_classMethod();//부모클래스의 메서드
b.a=10;//부모클래스의 변수
b.b = "자식클래스변수";//자식클래스의 변수
b.B_classMethod();//자식클래스의 메서드
}
위에 코드와 같이 이런식으로 가능합니다.
하지만 부모클래스에서 private 접근제한자로 되어있으면 그 해당 멤버필드는 (변수나 메서드) 상속이 안됩니다.
그러고 부모클래스와 자식클래스가 서로 다른 패키지에 있는 경우에는 default접근제한자 있어도 상속대상에서 제외가 되어서 상속이 되지않습니다. 이럴 경우에는 public 접근제한자로 상속을 하던지 .. 해야합니다.
추가로 Class가 final로 접근제한자로 되어있는경우네는 상속을 할 수 없습니다.
//부모클래스
public class Cellphone{
String model;
String color;
void powerOn(){
System.out.println("전원을 킵니다.");
}
void powerOff(){
System.out.println("전원을 끕니다.");
}
}
//자식클래스
public DmbCellphone extends Cellphone{
int channel;
DmbCellphone(Stirng model, Stirng color, int channel){
this.model = model;//부모클래스에게 상속을 받아서 사용가능.
this.color = color;//부모클래스에게 상속을 받아서 사용가능.
this.channel = channel;
}
void turnOnDmb(){
System.out.println("채널 " + channel+"번을 "+ "수신합니다.")
}
void turnOffDmb(){
System.out.println("Dmb방송 수신을 종료합니다");
}
}
public static void main(String[] args) {
DmbCellphone dmbcellphone = new DmbCellphone("아이폰", "검은색", 10);
System.out.println(dmbcellphone.model);//부모클래스부터 상속받은 필드
System.out.println(dmbcellphone.color);//부모클래스부터 상속받은 필드
System.out.println(dmbcellphone.channel);//자식클래스 필드
dmbcellphone.turnOn();//부모클래스의 메서드
dmbcellphone.turnOnDmb();//자식클래스의 메서드
}
위에 코드와 같이 이런식으로 상속을 받으면 응용을 하거나 유지보수나 코드수를 줄이면서 사용할 수 있다.
그리고 추가적으로 이렇게 상속받은 자식클래스를 객체를 생성할 때 즉. new 연산자를 이용할때, 부모클래스를 상속받고 있기 때문에 개발자의 눈에는 자식클래스만 객체를 생성되는 것 처럼 보이지만, 사실 부모클래스부터 객체가 생성되고 그 다음에 자식클래스의 객체가 생성된다.
그럼 부모클래스의 생성자는 어떻게 호출이 되어서 부모클래스이 객체부터 생성이 될까?
위에는 자식클래스가 명시적으로 생성자를 작성을 하였기 때문에 부모클래스의 생성자를 불러와서 객체를 생성을 하였다.
하지만 명시적으로 작성을 하지 않았을 경우에는 자식클래스의 생성자에서 super();을 알아서 컴파일러가 만들어서 불러온다. 원래 클래스 작성 후에 생성자를 안 만들어도 컴파일러가 기본 생성자를 만들어주는 것 처럼 말이다.
public Car{
String name;
String color;
public Car(String name, String color){
this.name = name;
this.color = color;
}
}
public class KiaCar extends Car{
int carNumber;
public KiaCar(String name, Stirng color, int carNumber){
super(name, color);
this.carNumber = carNumber;
}
}
위에 코드처럼 super()를 이용할 수가 있다.
근데? 이렇게 상속을 하는이유가 뭘까?
간단하게 위에 코드들을 작성을 하였지만 상속을 받을 경우에는 이미 마련되어 있던 클래스를 재사용해서 만들 수 있기 때문에 효율적이고, 개발 시간을 줄여주게 됩니다.
Override(재정의)
오버라이딩은 자바코드를 보다가 보면 @override라고 본 적이 있다.
이것은 재정의를 하였다고 어노테이션을 붙여서 사용을 합니다.
재정의를 하는경우는
1. interface를 상속 및 구현을 할 경우에 재정의는 강제적으로 해서 사용을 해야 합니다.
2. 자식클래스가 부모클래스를 상속 받은 경우에 자식클래스에 맞지않은 메소드인 경우에 재정의를 해서 사용해야하는 경우.
저의 짧은 지식으로는 이렇게 위에 경우에는 재정의를 필요로 합니다.
class Mother{
void Mvoid(){}
void Mvodi1(){}
}
class Son extends Mother{
@override
void Mvoid(){}//재정의를 한 메서드
void Mvoid2(){}
}
public static void main(String[] args) {
Son s = new Son();
s.Mvoid();//재정의된 메서드이기 때문에 Son에서 재정의한 메서드가 호출. Mother클래스에서 호출X.
s.Mvoid1();//부모클래스의 메서드
s.Mvoid2();//자식클래스의 메서드
}
public interface Mother {
void speak(){
System.out.println("공부해라");
}
}
class son implements Mother{
@override
void speak(){
System.out.println("공부하기 싫다.")
}
}
위에 처럼 사용을 할 수 있다.
그리고 또 오버라이딩을 할 경우는 지켜야할 조건이 있다.
1. 오버라이딩하려하는 메소드의 이름, 매개변수, 리턴 값이 모두 동일해야 한다.
2. @Override라는 어노테이션을 표기해주어야 한다.(필수는 아님 하지만 누구나 보기 편하게 필수라고 생각하며 적자.)
3. 부모의 접근 제어자보다 축소된 범위를 가질 수 없다.
그런데 여기서 재정의된 메서드를 사용을 하지만 원래의 오버라이딩 되지 않은 메서드를 사용을 해야할 경우가 있다면 어떻게 해야할까?
밑에 코드를 봐보자.
class Mother{
void Mvoid(){}
void Mvodi1(){}
}
class Son extends Mother{
@override
void Mvoid(){}//재정의를 한 메서드
void Mvoid2(){}
super.Mvoid();//재정의를 하지않은 부모클래스의 메서드
}
이렇게 super()를 사용하여서 메서드를 사용할 수 있다.
추가로 위에 상속을 할때도 class가 final 접근제한자일 경우에는 상속이 안되었던 것처럼 재정의도 메서드가 final로 되어있으면 재정의가 안된다... 이점을 파악하자.
다형성(Polymorphism)
다형성이란 하나의 메소드나 클래스가 있을 때 이것들이 다양한 방법으로 동작하는 것을 의미한다. 라고 나오는데...
- 여러가지 형태를 가질 수 있는 능력.
- 하나의 참조변수로 여러 타입의 객체를 참조할 수 있는 것.
- 조상클래스 타입의 참조변수로 자손클래스의 인스턴스를 참조할 수 있도록 하는 것.
일단 코드를 봐보자.
public class Car{
void printInfo(){
System.out.println("나는 자동차입니다.");
}
}
public KiaCar extends Car{}
public HyundaiCar extends Car{}
public static void main(String[] args) {
KiaCar kia = new kia();
HyundaiCar hyundai = new hyundai();
kia.printInfo();
hyundai.printInfo();
}
위에 코드처럼 할 경우에는 모두 다 상속을 받아서 "나는 자동차입니다"라고 찍힐 것 입니다.
상속받은 자식클래스들을 오버라이딩을 해보면,
public KiaCar extends Car{
@override
void printInfo(){
super.printInfo();
System.out.println("나는 기아자동차입니다.")
}
}
public HyundaiCar extends Car{
@override
super.printInfo();
void printInfo(){
System.out.println("나는 현대자동차입니다.")
}
}
이렇게 할 경우에는 위에서 배웠다시피 오버라이딩한것은 오버라이딩한 메소드가 호출되고 super만 부모클래스의 오버라이딩되지않은 메소드가 호출이 됩니다.
public KiaCar extends Car{
@override
void printInfo(){
super.printInfo();
System.out.println("나는 기아자동차입니다.")
}
void KiaPrint(){
System.out.print("나는 k5입니다.")
}
}
public HyundaiCar extends Car{
@override
void printInfo(){
super.printInfo();
System.out.println("나는 현대자동차입니다.")
}
void HyundaiPrint(){
System.out.println("나는 제네시스입니다.")
}
}
이렇게 부모클래스에 없고 자식클래스에 단독적으로 메소드를 만들었을 경우에는 어떻게 적용이 될까?
결론적으로는 호출이 안됩니다.
왜냐하면 부모클래스에서는 자식클래스에서 단독적으로 만들어지는 메소드를 알 방법이 없습니다..
이럴경우에는 어떻게 해결을 해야할까요
public static void main(String[] args) {
Car car = new KiaCar();//참조변수의 다형성.
car.printInfo();
((KiaCar)Car).KiaPrint();// 캐스팅을 해서 사용해야 할 수 있음.
Car car1 = new HyundaiCar();
car1.printInfo();
((HyundaiCar)Car).HyundaiPrint();
}
이렇게 위와 같이 캐스팅을 통해 자식클래스에서 만든 메소드를 사용할 수 있습니다.
근데 이런식으로 하면 다형성을 어디에다가 사용을 할 수 있을까요..
예를들어보면
public void function(Car car){
car.printInfo();
}
public static void main(String[] args){
KiaCar kiacar = new KiaCar();
function(kiacar);//매개변수의 다형성
}
위에와 같이 function함수의 매개변수는 People형인데 하지만 상속하는 모든 클래스를 받을 수 있습니다.
이렇게 다형성을 이용할 수 있습니다..
또 다형성하면 instance of라는 연산자가 있는데
참조변수가 참조하는 인스턴스의 실제 타입을 알아보기 위해 사용합니다.
왼쪽에는 참조변수, 오른쪽에는 참조형 변수의타입, 연산결과는 true, false 하나를 반환한다.
null값일 경우에는 false를 반환합니다.
instanceof 결과가 true 이면, 해당 타입으로 형변환이 가능합니다. 작은타입이 큰타입으로 안되고 큰타입이 작은타입으로는 형변환이 가능합니다.
class Car {
}
class KiaCar extends Car {
}
public class Test {
public static void main(String[] args) {
KiaCar kia = new KiaCar();
if(kia instanceof KiaCar) {
System.out.println("KiaCar의 인스턴스이다");
}
if(kia instanceof Car) {
System.out.println("Car의 인스턴스이다");
}
if(Car instanceof Object) {
System.out.println("Object의 인스턴스이다");
}
}
}
이상.. 나중에 또 알아봐보자...
Reference
https://velog.io/@ahnick/Java-Overloading%EA%B3%BC-Overriding
[Java] Overloading과 Overriding
자바의 Method Overloading vs Overriding
velog.io
이것이 자바다 -한빛미디어- 신용권저자.
Java 다형성(polymorphism), instanceof 연산자
1. 다형성(polymorphism) - 여러가지 형태를 가질 수 있는 능력. - 하나의 참조변수로 여러 타입의 객체를 참조할 수 있는 것. - 조상클래스 타입의 참조변수로 자손클래스의 인스턴스를 참조할 수 있
gangzzang.tistory.com
'JAVA' 카테고리의 다른 글
Java Throw, Throws 예외처리 (0) | 2022.03.26 |
---|---|
JAVA 추상클래스 (0) | 2021.07.30 |
JAVA 데이터 타입, 메모리 사용 영역 (0) | 2021.07.27 |
JAVA<GENERIC> (0) | 2021.03.31 |
JSTL (0) | 2021.03.30 |