Joslynn의 하루

대용량 웹서비스를 위한 MSA Full-Stack 개발자 양성 과정 -10일차 노트 필기_ 상속, 다형성_220729 본문

MSA Full-Stack 개발자 양성과정/Java

대용량 웹서비스를 위한 MSA Full-Stack 개발자 양성 과정 -10일차 노트 필기_ 상속, 다형성_220729

Joslynn 2022. 7. 29. 18:37

Inheritance(상속)

 

1) 부모 class의 속성과 method를 상속받는 것

2) 부모 class의 생성자(constructor)와 private 요소를 제외한 모든 것을 상속 받음

    : 생성자는 객체 생성시 딱 한 번만 실행되기 때문;

3) 부모 class의 method와 속성을 별도의 선언 없이 내안에 있는 것처럼 접근하여 사용

4) extends 키워드

    class A extends B {    }: A가 B를 상속 받는다.// B: 부모 class

5) 단일 상속, 그러나 부모의 부모 class는 내려 받을 수 있음(대물림)

6) java의 모든 class는 Object(class)를 상속받는다

7) java의 최고 조상: Object (java의 모든 class는 Object를 상속 받음;)

  : 굳이 상속이라는 단어 사용 필요 없음;

8) 자식 class는 부모class의 속성과 method를 사용하지만, 부모class는 자식 class의 속성과 method 사용 불가 

 

class Car{
		public String carname;
		public int cost;
		
		protected void printAttributes(){
			System.out.println("carname="+carname+"\tcost="+cost);
		}
}

//Car를 상속받는 EfSonata
	
class EfSonata extends Car {
	EfSonata(){
		super.carname = "Sonata"; // super는 부모를 의미;
		this.cost = 20000000 ; // super, this, 생략 3가지 다 가능
	}
    
 // Car 내부의 메소드 활용
  public class InheritanceExam{
	public static void main (String [] args) {
		new Car().printAttributes();
		new EfSonata().printAttributes();
    }

결과값:


예시 2)

class Car{
		public String carname;
		public int cost;
		
		protected void printAttributes(){
			System.out.println("carname="+carname+"\tcost="+cost);
		}
}

//Car를 상속받는 EfSonata, Excel, Carnival 3개 클래스 작성	
	
class EfSonata extends Car {
	EfSonata(){
    // 중요 포인트!! efSonata의 객체 안에는 Car 객체 영역과 EfSonata 영역이 같이 생성;
		this.carname = "Sonata"; 
		this.cost = 20000000 ;
	}

}

class Excel extends Car {
	Excel(){
		this.carname = "페라리";
		this.cost = 20000000;
	}
}

class Carnival extends Car {
	Carnival(){
		this.carname = "카니발";
		this.cost = 30000000;
	}
}

// Car calss에있는 printAttributes()메소드를 호출
public class InheritanceExam{
	public static void main (String [] args) {
		new Car().printAttributes();
  // 중요 포인트!! Car 객체의 접근자가 허용하는 범위내에서 ef.으로 Car 객체의 필드, 메소드 호출 가능
		new EfSonata().printAttributes();
		new Excel().printAttributes();
		new Carnival().printAttributes();
	}

}

중요 Point

: EfSonata, Carnival, Excel 이 세 class는 각각 Car 객체로부터 상속 받음;

   상속 시, Car 객체는 공유 되지 않으며, EfSonata, Carnival, Excel  객체 생성 시, 각각 생성된다. 

: 위의 예제에서 Car 객체의 접근자가 허용하는 범위내에서 ef.으로 Car 객체의 필드, 메소드 호출 가능


상속의 효용

: 공통의 속성 또는 기능을 가지는 class들 → 공통 속성, 기능을 하나의 부모 클래스에 정의해두고 extends로 내 것처럼 사용 가능;

: 반복 코드 감소, 속성 및 기능 변경, 유지보수에 유리

 

 


 

 

Polymorphisom (다형성)

1) 반드시 상속 관계에서 성립

2) class A extends B {   }일 때, A를 A라 부를 수 있고, A를 B라 부를 수 있다.  // A를 부르는 호칭 변경;

    : 호칭에 따라 접근할 수 있는 영역에 제한이 생김; B라고 부르면, B의 영역만 접근 가능; 

3) : 부모클래스의 참조 변수는 자식 객체를 참조할 수 있다. // Promotion 일어나기 때문; 부모 class는 자식 class의 상위 class // Upcasting(업캐스팅)

4) 여러 타입의 객체를 하나의 타입으로 관리할 수 있음; 

class A extends B {   
    A a = new A(); // 가능
    B b = new A(); // 가능
    B c = new B(); // 가능
    A d = new B(); //컴파일 에러
 }

 

Polymorphisom (다형성)의 효용

: 다형성이 없으면, 함수 OverLoading을 계속해야 할 수 있음; (아래 예제 참고)

: 아래 예제에서 만약 새로운 차(Car) 타입이 등장해도 engineer 메소드를 수정할 필요 없이, Car class를 상속 받는 class를 만들기만 하면 됨; // Code 유지 보수에 유리

 

 

 

다형성 예제)

class CarCenter{
	public void engineer(Car cd){ 
		System.out.print(cd.carname+" 수리완료!\t");
		System.out.println("청구비용"+cd.cost+" 원");
		
	}
}

public class PolymorphismExam{
	public static void main(String[] args) {
		
		CarCenter cc=new CarCenter();
		EfSonata ef=new EfSonata();
		Carnival ca=new Carnival();
		Excel ex=new Excel();		
		Car car= new Car();
		
		cc.engineer(car);// Car 객체의 주소값을 cd의 engineer 메소드의 인수로; Car cd = car(주소값)
		cc.engineer(ef);// engineer 메소드는 EfSonata 객체가 상속 받은 Car 객체를 가르킴;  
		cc.engineer(ca);//
		cc.engineer(ex);//
		
	}
}

 

 

만약 다형성이 없다면)

class CarCenter{
	public void engineer(Car cd){ 
		System.out.print(cd.carname+" 수리완료!\t");
		System.out.println("청구비용"+cd.cost+" 원");
   		}
        
        public void engineer(EfSonata ef){ // 인수는 같은 타입만 받을 수 있음; 따라서 앞선 메소드와 다른 인수 타입으로 함수 오버로딩
		System.out.print(cd.carname+" 수리완료!\t");
		System.out.println("청구비용"+cd.cost+" 원");
 	    }
        public void engineer(Carnival ca){ 
		System.out.print(cd.carname+" 수리완료!\t");
		System.out.println("청구비용"+cd.cost+" 원");
   		}
        public void engineer(Excel ex){ 
		System.out.print(cd.carname+" 수리완료!\t");
		System.out.println("청구비용"+cd.cost+" 원");	
		}
}

public class PolymorphismExam{
	public static void main(String[] args) {
		
		CarCenter cc=new CarCenter();
		EfSonata ef=new EfSonata();
		Carnival ca=new Carnival();
		Excel ex=new Excel();		
		Car car= new Car();
		
		cc.engineer(car);
        cc.engineer(ef); 
		cc.engineer(ca);
		cc.engineer(ex);
		
	}
}

 


 

 

업캐스팅 (UpCasting)

: 위의 예시에서  s2변수는 부모 객체를 참조(UpCasting), 하위에 있는 자식 멤버는 접근할 수 없음;  // 단, 재정의된 메소드만 자식부분 접근가능 (Overriding)

→ 하나의 타입으로 여러 객체(부모, 자식 class에서 생성된 객체)들을 관리할 수 있으며, 같은 타입일지라도 재정의된 메소드로 인해 실행 결과가 다를 수 있다. // 재정의된 자식 메소드가 호출되기 때문; (동적 바인딩)

 

다운캐스팅 (DownCasting)

: Upcasting된 대상 객체를 다시 해당 type으로 참조시키는 것; 

   Ex> Sub s3 = (Sub) s2 ; => ObjectDownCasting

: 형 변환 - 객체가 변하는 것이 아니라 참조변수의 타입에 따라 참조하는 객체의 볼 수 있는 멤버 범위가 달라짐;

 

 *참조사항*

Object(객체) 타입의 명시적 형 변환: 객체 타입은 크기를 비교할 수 없으나, 상속관계에서 명식적인 형 변환(Casting)이 가능;

 

* instanceof(연산자)

: 상황에 맞춰서 해당 객체를 확인하고, DownCasting을 하는 방법도 존재; 

: (Object변수) instanceof (ObjectType) ⇨ 왼쪽의 참조변수가 오른쪽의 Type이 될 수 있는지?

Ex> s3 instanceof Sub

instance: 메모리에 생성된 객체;

즉, 참조 변수 s3가 Sub class를 이용해 만들어진 객체인지 확인

== 참조변수 객체가 어떤 타입으로 형 변환이 가능한지 확인하는 것;

 

: 반드시 상속관계일 때 사용한다. (아니면 컴파일 오류)

: 왼쪽의 변수형이 오른쪽의 Type과 같거나 서브 class일 때 true이다.

 

class CarCenter{
	public void engineer(Car cd){ 
		System.out.println("cd = "+cd);
		System.out.println("cd.carname = "+cd.carname);

		//System.out.println(cd.color); // 부모 타입 변수로는 자식 부분접근 불가
		/*아래 ex와 cd를 가르키는 주소값은 동일하지만 Car 타입 변수에 담은 cd는 자식 타입의 필드에 접근 불가 */

		// 위 문자 에러: 부모 타입을 자식 타입으로 형변환 해서 접근 가능하도록 한다.
		Excel ex2 = (Excel) cd; // 부모 타입을 자식 타입으로 변경하려 함; 더 작은 type으로 형 변환은 Casting 연산자 필요 === 객체를 DownCasting (ObjectDownCasting)

		System.out.println("ex2= "+ex2);
		System.out.println("ex2.color= "+ex2.color);
		
	}
}

public class PolymorphismExam{
	public static void main(String[] args) {
		
		CarCenter cc=new CarCenter();
		Car car= new Car();
		Excel ex=new Excel();		

		System.out.println("ex= "+ex);
		System.out.println("ex.carname= "+ex.carname);
		System.out.println("ex.color= "+ex.color);

		System.out.println("-------------------engineer메소드 호출---------------");
		cc.engineer(ex);//
		
	
	}
}

: 객체는 변경되지 않았으나, 객체를 가르키는 참조 변수가 누구인지에 따라 부모, 자식 객체의 멤버 접근 가능 범위가 달라짐;

 

다형성의 한계점: 부모 class에서 자식 class로 접근하기 위해 빈번한 ObjectDownCasting 일어나야 함

// 유연한 사용을 위해 Overriding(재정의) 개념을 사용


 

: Overriding: 상속 관계에서 modifier(abstract)만 다를 수 있음; 

   ↔ OverLoading: 하나의 class 내에서 인수 타입, 개수, 순서가 다르나 이름이 같은 method;

        (제한자, retrun type달라도 상관없음;)

 

**Java의 중요한 문법**

동적 바인딩: 재정의된 메소드는 부모 타입의 변수에 받았을 지라도 자식부분이 호출된다.

정의된 자식 메소드가 호출;

 


 


super 기능 3가지

1) super.변수이름  → 자식class에서 부모 class의 전역변수 호출

    // 자식class의 변수이름과 부모class의 변수이름 같을 때 구분

2) super.method이름( [값, 값, ...] );  자식class에서 부모class의 method호출

3) super( [값, 값, ... ] );  자식 class의 생성자구현부 첫 번째 줄에서 부모 class의 생성자 호출

 

 

생성자 예제 1)

class Parent{
    1. Parent(){
    }
    2. Parent(int i){
    }
    3. Parent(String str){
    }
}

//------------------------
class Child extends Parent{
    4. Child(){}
    5. Child(int i){
    }
    6. Child(boolean b){
    }
}

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

new Child (); // 4 → 1 → 4
new Child (5); // 5 → 1 → 5
new Child (true); // 6 → 1 → 6
// new Child ("o") // 컴파일 에러

//만약 1,2,3이 없다면,
new Child (); // Super ();자동으로 호출
new Child (5);

//만약 1 없고, 2,4 있다면,
//new Child(); // 컴파일 에러, 자식 class는 생성 시 부모의 기본생성자 자동 호출함;
//new Child(5); // 컴파일 에러

//해결 방법------------------------

class Child extends Parent{
	Child(){
    	this(3);
    }
    Child(int i){
        super(5);
    }
    Child(boolean b){ 
         super("O");
    }
}

중요 포인트

: 자식 class가 인수가 있는 생성자를 호출하더라도 부모 class의 기본 생성자가 필요;

 


package VS import

1) package

 

2) import

: package는 문서에 첫번째 줄에 한개 선언 ↔ import는 여러 개 선언 가능

: 다른 폴더에 있는 class를 사용할 때는 반드시 "import"를 붙여줘야 함; 


최종 정리 예시>

class Animal{
// 공통의 속성
	int leg;
	String name;
// 공통의 기능
	public void sound(){ }
	public void eat(){ }
	public void run(){ }

}

class Pig extends Animal{
	/* int leg;
	String name;*/
//Animail이 가진 속성, 기능 다 사용할 수 있음;
    
    public void sound(){ // Overriding
   		 "꿀꿀";
    }
}

class Dog extends Animal{

    public void sound(){ // Overriding
   		 "멍멍";
    }
}

class Cat extends Animal{
	public void sound(){ // Overriding
   		 "야옹";
    }
}

/*--------------------------------------------------------------------*/

// 필드를 이용한 다형성 == 타입 하나만 두고 갈아끼우는 것;
    Animal an = new Cat();
       		new Pig();
       	 	new Dog(); 

// 매개변수를 이용한 다형성
    public void test(Animal an){ // 인수로 Cat, Pig, Dog 가능
        an.eat( );
        an.run( );
        an.sound( );
    }

필드의 다형성:  한 가지의 타입에 어떤 객체를 필드로 저장하느냐에 따라 실행결과가 달라질 수 있다

매개변수의 다형성 : 메소드의 매개변수에 자식타입의 객채를 대입할 수 있다

 

Overriding의 효용

: 사용자의 이용을 편리하게 함; → 같은 기능을 하는 메소드의 이름이 모두 다를 경우, 사용자가 알아야 할 메소드의 이름이 너무 많아짐; 

: 같은 타입으로 여러 객체를 관리할 수 있지만, 각 객체별 실행결과는 달라질 수 있도록 하는 다형성의 중요 개념

 


super 기능 3가지

1) super.변수이름  → 자식class에서 부모 class의 전역변수 호출

    // 자식class의 변수이름과 부모class의 변수이름 같을 때 구분

2) super.method이름( [값, 값, ...] ); 자식class에서 부모class의 method호출

3) super( [값, 값, ... ] ); 자식 class의 생성자구현부 첫 번째 줄에서 부모 class의 생성자 호출

 


Object class

: Java class의 최고 조상인 Object는 속성과 method를 가지고 있음;

: 모든 class들은 Object class의 속성과 method를 상속 받는다. 

 

Comments