[Java]/Program source (java)

★★★ 112 - Java 상속(inheritance) : 부모 클래스의 생성자가 인자를 받는 생성자만 있을 경우 주의사항!

Jelly-fish 2023. 9. 12. 17:41
Ⅰ. [부모 클래스에서 매개변수를 받는 사용자 정의 생성자만을 생성했을 경우... ]


부모 클래스(상위 클래스)
에서 사용자 정의 생성자 매개변수를 받는 생성자를 생성했을 경우

 인자(매개변수 parameter)를 받지 않는 default 생성자() 자동으로 생성되지 않는다.



★ 이때, 자식 클래스 생성자 정의에서
부모 생성자 호출 형태를 어떻게 하느냐에 따라 오류가 발생할 수 있다. 


public class SuperTest112		// 부모 클래스! 
{	
	// 사용자 정의 생성자 생성. (매개변수 문자열 타입 str)   
    public SuperTest112(Sting str)
    {
    	// SuperTest112 생성자
    }
   
    // 사용자 정의 생성자를 생성했으므로 default 생성자는 생성되지 않음.
    // 즉, 부모 클래스 SuperTest112에는 매개변수를 받는 생성자만 존재하는 상황!
    /*
    SuperTest112()
    {
    	// default 부모 클래스의 생성자 생성되지 않음!
    }
    */
}

class Rect() extends SuperTest112	// SuperTest112의 자식 클래스!
{
	Rect()
    {
    	// 사용자 정의 Rect() 생성자.
        // 부모 클래스의 생성자 super(); 가 맨 윗줄에 자동 생성되지만...
        // 부모 클래스의 생성자는 매개변수 String을 받는 생성자밖에 존재하지 않기 때문에
        // 오류가 발생한다...!!!
    }
}​​

 

 

Ⅱ. 자식 클래스(하위 클래스)에서의 생성자 정의 형태에 따른 에러 발생, 에러를 피할 수 있도록 호출

 

1. [ 자식 클래스에서 생성자 정의를 하지 않은 경우  -  Error! ]

자식 클래스에서 생성자 정의를 하지 않으면, 자동으로 default 생성자가 생성되게 된다.

만약, 자식 클래스 class Rect112라고 한다면... 자식 클래스의 default 생성자부모 클래스의  생성자 호출 `super()`자동으로 생성하여 자식 생성자 내부에서 호출할 것이다...


public class SuperTest112
{
	public SuperTest112(String str)
    {
    	// 부모 클래스의 생성자 : String 매개변수를 받는다...
    }
}




class Rect() extends SuperTest112
{

	/* 자동으로 생성된 자식 클래스의 생성자
	public Rect()
    {
    	// super()	자동으로 부모 클래스(인자없는) 생성자를 호출한다!!
        			// 부모 클래스에 인자가 없는 생성자가 없기 때문에 오류!!!
    }
    */
}​

 

 

2. [ 자식 클래스에서 매개변수를 받지 않는(or 받는) 생성자 정의를 하지 않은 경우  -  Warning! ]

자식 클래스(Sub class)에서 매개변수 유, 무에 관계 없이 사용자 정의 생성자를 정의게 되면 그 안에 부모 클래스(Super Class)의  생성자 호출 키워드 `super()`를 작성할 수 있다.

단, 자식 클래스의 생성자 안에서  부모 클래스 생성자를 호출할 때 매개변수가 없는 형태로 호출해 버리면... `super()`
부모 클래스의 생성자는 매개변수가 있는 생성자만 존재하기 때문에 생성자가 호출되지 않아 오류가 발생한다!!!

따라서, 부모 클래스에서 인자가 있는 생성자만 존재할 경우  자식 클래스 생성자를 사용자 정의로 생성하여 반드시
매개변수가 있는 부모 생성자를  `super(parameter)` 호출할 수 있도록 한다!!!


public class SuperTest112
{
	public SuperTest112(String str)
    {
    	// 부모 클래스의 생성자 : String 매개변수를 받는다...
    }
}




class Rect() extends SuperTest112
{

	/* 자동으로 생성된 자식 클래스의 생성자
	public Rect()
    {
    	// super()	자동으로 부모 클래스(인자없는) 생성자를 호출한다!!
        			// 부모 클래스에 인자가 없는 생성자가 없기 때문에 오류!!!
    }
    */
}​

 

 

 

/*===========================
  ■■■ 클래스 고급 ■■■
  - 상속(Inheritance)
=============================*/

// ※ 『super』

//   static 으로 선언되지 않은 메소드에서 사용되며 (설계도 x 객체 o)
//   현재 클래스가 상속받은 상위 클래스의 객체를 가리킨다.
//   super 는 상위 클래스의 생성자를 호출하거나
//   상위 클래스의 멤버 변수 또는 메소드를 호출할 때 사용할 수 있다.

//   하위 클래스의 생성자에서 상위 클래스의 생성자를 호출할 때에는
//   하위 클래스의 생성자 정의 구문에서 맨 처음에만 위치할 수 있다.


// ※ 생성자와 클래스 상속간의 관계

//    하위 클래스는 상위 클래스의 멤버를 상속받지만,
//    생성자는 상속 대상에서 제외된다.
//    그리고, 하위 클래스의 생성자를 호출할 때
//    자동으로 상위 클래스의 생성자를 호출하게 된다.
//    이 때, 상위 클래스의 생성자는
//    인수가 없는 생성자(default 생성자 형태)가 호출된다.	(매개변수 x)

//    상위 클래스 및 하위 클래스(즉, 상속관계에 있는 클래스)를 설계하는 과정에서
//    상위 클래스의 생성자를 정의하지(작성하지) 않거나
//    인수가 없는 생성자만을 정의한(작성한) 경우
//    명시적으로 하위 클래스에서 상위 클래스의 생성자를 호출하지 않아도
//    아무런 문제가 발생하지 않지만
//    상위 클래스에 인자가 있는 생성자만 존재하는 경우
//    주의해야 한다.

/*
예를 들어... 다음에서...

class Aclass
{
	Aclass(int n)		-->> 사용자 정의 생성자를 생성했으므로, default 생성자
	{						 생성되지 않음!!! (Aclass() 형태의 생성자가 존재하지 않게 된다.)
	}
}


class Bclass extends Aclass
{
	Bclass()
	{
		super();		-->> 이렇게 호출하면, 부모 생성자에 매개변수가 없는 생성자가 없기 때문에 오류!!!!!
	}
}

*/

//    하위 클래스인 Bclass 의 생성자에서
//    명시적으로 Aclass 의 생성자를 호출하지 않으면
//    자동으로 인자 없는 생성자를 호출한다.
//    하지만,  Aclass 에는 인자가 있는 생성자만 존재하고
//    인자가 없는 생성자는 존재하지 않기 때문에 에러 발생한다.
//    따라서, Bclass 생성자의 선두에
//    다음처럼 명시적으로 상위 클래스의 생성자 호출 구문을 작성해야 한다.


/*
class Aclass
{
	Aclass(int n)
	{
	}
}


class Bclass extends Aclass
{
	Bclass()
	{
		super(10);
		...;
		...;
	}
}
*/



/*
		※ 상속 시 주의할 사항

		상위 클래스에서 선언된 멤버 변수의 이름과
		하위 클래스에서 선언된 멤버 변수의 이름이 같으면
		상위 클래스의 멤버 변수는 무시된다.
		이 때, 상위 클래스의 멤버 변수를 사용하기 위해서는
		『super』 키워드를 이용한다.

		동일한 이름의 멤버 변수나 동일한 이름의 메소드가
		한 클래스 안에 선언되거나 정의되는 경우 기본적으로 에러 발생한다.
		단, 메소드의 경우는 매개변수의 개수나 타입이 다른 경우
		에러 발생하지 않고 이들을 서로 다른 메소드로 취급하게 된다.	// 메소드 오버로딩

		// 메소드 명 중복되어도, 부모로부터 물려받은 것을 덮어 쓰는 개념이 된다...
		// 클래식 카 개조...
*/

// Rect112 클래스와 Circle112 클래스의 부모 클래스

class SuperTest112
{
	protected double area;
	private String title;

	public SuperTest112()
	{
		System.out.println("SuperTest112... 인자 없는 생성자");
	}


	public SuperTest112(String title)
	{
		this.title = title;
		System.out.println("SuperTest112... 문자열을 넘겨받는 생성자");
	}

	public void write()
	{
		System.out.println(title + " - " + area);
	}


}

// SuperTest112 클래스를 상속받는 자식 클래스(단일 상속)
class Rect112 extends SuperTest112
{
	/*
	protected double area;

	// ※ private 멤버는 접근 자체가 불가능~!!!
	//private String title;
	
	
	// ※ 생성자는 상속 대상에서 제외~!!!
	public SuperTest112()
	{
		System.out.println("SuperTest112... 인자 없는 생성자");
	}

	
	// ※ 생성자는 상속 대상에서 제외~!!!
	public SuperTest112(String title)
	{
		this.title = title;
		Sysetm.out.println("SuperTest112... 문자열을 넘겨받는 생성자");
	}
	


	public void write()
	{
		System.out.println(title + " - " + area);
	}

	*/

	// 자동으로 생성되는 default 생성자 → class의 접근제어 지시자 그대로 따라간다!!!

	private int w, h;

	public Rect112()
	{
		// super();
	}

	
	public void calc(int w, int h)
	{
		this.w = w;
		this.h = h;
		area = (double)this.w * this.h;
		write();

	}						
						
							
	// is a, has a 관계
	// is a 관계일 때만, 상속 클래스를 생성한다...
	// 군인 → 총 (상속 is a 관계) 
	// 총 → 군인 (불가능! 둘 간의 관계가 is a 관계가 아님! 총이 군인에 포함되는 개념x)
	// 상하위 상속 관계를 명확히 알고 부모 클래스, 자식 클래스를 생성해야 함!


	// 데이터를 수식하는 metadata!!
	// 이미지 데이터, 동영상 데이터에 해시태그라는 개념을 붙이는 것과 비슷하다...
	// 원본 영상, 이미지에 변화를 주진 않지만 추가 데이터가 붙게 되는 개념!

	@Override	//-- 어노테이션(annotation) - metadata → JDK 1.5		
						
							// default 로 선언했을 경우 → protected, public으로 접근제어지시자 변경 가능!!! (접근강도 ↓)
							// 하지만, 접근 강도를 높일 순 없다!! public → default (Ⅹ)
							// default는 상속 받을 수도 있고 아닐 수도... (동일 패키지이면 상속 ok!!)
	public void write()		
	{						
		System.out.println("w : " + w + ", h : " + h);
		System.out.println("사각형 - " + area);
	}
	// --> 메소드의 오버 로딩 (메소드의 중복 정의)
	//     매개변수의 타입, 수를 조절하여...
	
	// --> 메소드의 오버 라이딩 (메소드 재정의)
	//     부모에게 상속받은 메소드를 (물려받은 것) 튜닝한다! 재정의한다! → @Override 를 표시
	//     한번 덮어쓰면... 절대 원래 부모가 상속해 준 메소드로 돌아갈 수 없다!!!
}

	
	// ※ 메소드 오버라이딩(Method Overriding)

	//    상위 클래스를 상속받은 하위 클래스에서
	//    상위 클래스에 정의된 메소드를 다시 정의하는 것으로(재정의)
	//    객체 지향 프로그래밍의 특징인 다형성을 나타낸다.
	//    재정의(Overriding)는 반드시 상속 관계에 있어야 하며,
	//    메소드 이름, 리턴 타입, 매개변수의 개수나 타입이
	//    모두 완전히 일치해야 한다.




// SuperTest112 클래스를 상속받는 자식 클래스(단일 상속)
class Circle112 extends SuperTest112
{
	/*
	protected double area;

	// ※ private 멤버는 접근 자체가 불가능~!!!
	//private String title;
	
	
	// ※ 생성자는 상속 대상에서 제외~!!!
	public SuperTest112()
	{
		System.out.println("SuperTest112... 인자 없는 생성자");
	}

	
	// ※ 생성자는 상속 대상에서 제외~!!!
	public SuperTest112(String title)
	{
		this.title = title;
		Sysetm.out.println("SuperTest112... 문자열을 넘겨받는 생성자");
	}
	

	public void write()
	{
		System.out.println(title + " - " + area);
	}

	*/

	public Circle112(String title)
	{
		// super();
		super(title);
	}
	
	public void calc(int r)
	{
		area = r * r * 3.141592;
		write();					
	}
	// 메소드 오버라이딩을 안 했으므로, 부모가 물려준 메소드를 그대로 사용!

}

//-----------------------------------------------------------------------


// main() 메소드를 포함하는 외부의 다른 클래스 
public class Test112
{
	public static void main(String[] args)
	{
		// Rect112 클래스(자식 클래스) 기반 인스턴스 생성
		Rect112 ob1 = new Rect112();
		//--==>> SuperTest112... 인자 없는 생성자


		// Circle112 클래스(자식 클래스) 기반 인스턴스 생성
		//Circle112 ob2 = new Circle112();
		//--==>> 에러 발생(컴파일 에러)
		//-- 현재 Circle112 클래스에는
		//   매개변수를 필요로하는 사용자 정의 생성자가 만들어져 있으며
		//   이로 인해 default 생성자가 자동으로 삽입되지 않는 상황.


		// Circle112 클래스(자식 클래스) 기반 인스턴스 생성
		Circle112 ob3 = new Circle112("원");
		//--==>> SuperTest112... 인자 없는 생성자
		//            ↓
		//--==>> SuperTest112... 문자열을 넘겨받는 생성자

		ob1.calc(10, 5);
		//--==>> w : 10, h : 5
		//       사각형 - 50.0
	

		ob3.calc(10);
		//--==>> 원 - 314.1592

	}
}

/*
====================================================================================================================
상위 클래스   |   하위 클래스     |   결과
--------------------------------------------------------------------------------------------------------------------
생성자를      |생성자 정의 안함   | → 가능하다.
정의하지      |인수가 없는 생성자 | → 가능하다.
않음          |인수가 있는 생성자 | → 가능하다.
--------------------------------------------------------------------------------------------------------------------
인수가        |생성자 정의 안함   | → 가능하다.
없는          |인수가 없는 생성자 | → 가능하다.
생성자만 정의 |인수가 있는 생성자 | → 가능하다.
--------------------------------------------------------------------------------------------------------------------
인수가        |생성자 정의 안함   | → 에러 발생.
있는          |인수가 없는 생성자 | → 상위 클래스의 해당 생성자를 호출하지 않으면 에러 발생. (인수가 있는 생성자를 호출해야 에러 x)
생성자만 정의 |인수가 있는 생성자 | → 상위 클래스의 해당 생성자를 호출하지 않으면 에러 발생.
====================================================================================================================
*/