JAVA

[JAVA] 상속 / 오버라이딩 / this,super / 검색하기

sian han 2022. 2. 26. 14:56

 

 

객체지향언어의 3대특징 - 은닉성(캡슐화), 상속성, 다형성

 

 

 

※ 상속 (Inheritance)

       - 부모 클래스구성요소, 행위를 그대로 물려받아 사용하고, 자신만의 구성요소와 행위는 추가해서 사용

       - 클래스를 상속받게 되면 부모 클래스의 멤버들을 가져다가 사용할 수 있다

       - 자식 클래스들의 공통적인 부분은 부모 클래스에서 관리하고, 자식클래스는 자신에 정의된 멤버들만 관리

 

▶ 상속의 장점

  - 적은양의 코드로 새로운 클래스 작성 가능

  - 코드를 공통적으로 관리할 수 있기 때문에 코드의 추가 및 변경이 용이

 

  부모클래스 ) 상위 (Super) 클래스, 기본(Base) 클래스, 조상클래스

  자식클래스 ) 하위(sub) 클래스, 파생 (derived) 클래스, 자손클래스

    - 클래스간의 상속관계를 맺어주면 자식 클래스들의 공통적인 부분은 부모클래스에서 관리하고 자식클래스는 자신에 정의된 멤버들만 관리하면되므로 각 클래스의 코드가 적어져서 관리가 쉬워짐

 

▷ 자식 클래스의 멤버개수는 부모클래스와 같거나 많다

자식클래스 멤버 >= 부모클래스

 

class 자식클래스명 extends 부모클래스명
class Son extends Parent

 

protected = 같은 패키지는 물론 다른 패키지일지라도 상속관계가 있으면 접근 가능

                    (상속받은 자식 클래스에서 접근 가능) 

   - 외부에 자신의 멤버를 감추고 자식클래스에게만 멤버를 노출함

   - 실행타임에는 default 클래스 (=클래스 외부에서 보면 default 로 보임)

     디자인타임에 자식에게는 public 

  

 

▶ 상속의 특징

  - 생성자는 상속되지않음. 멤버만 상속됨

  - 생성자는 상위클래스로부터 '상속' 되지 않고 '호출' 됨 ( 메모리는 최상위 클래스부터 차례대로 생성됨 )

  - 클래스는 중복상속이 불가하며 단일 상속만 가능함

  - 단계별상속 : 상위 레벨의 생성자가 차례대로 호출되어지고, 제일 마지막에 자신의 것이 호출됨

 

 

 

※ Object 클래스 ( 모든 클래스의 조상 ) 

      - 모든 클래스 상속 계층도의 제일 위에 위치하는 조상 클래스

      - 다른 클래스로부터 상속받지 않는 모든 클래스들은

           자동적으로 Object 클래스로부터 상속받음

     ( = 자바의 모든 클래스들은 Object 클래스의 멤버들을 상속받음.

           따라서 Object 클래스에 정의된 멤버들을 사용할 수 있다 ex) toString(), equals(Object o)) 

 

 

※ 자료형별 디폴트값

자료형  default 값
int 0
long 0
double 0.0
boolean false
String (or Object) null

 

 

 

※ 기본형 매개변수와 참조형 매개변수

 

기본형 매개변수 (call by value)
 - 변수의 값을 읽기만 할 수 있다 (read only)
 - 매개변수가 기본자료형, 값이 전달됨
 => 메서드에서 매개변수의 값을 변경해도 호출한 곳 (main) 에서는 변경의 영향을 받지 않음

 

 

참조형 매개변수 (call by reference)
 - 변수의 값을 읽고 변경할 수 있다 (read & write)
 - 매개변수가 참조형, 주소가 전달됨
 => 메서드에서 매개변수의 값을 변경하면 호출한곳(main) 에서도 변경의 영향을 받음

 

public class ValueTest {
	public static void main(String[] args) {
		Data d = new Data();
		//기본
		d.x=10;
		System.out.println("main() : x="+d.x); //10
		
		change(d.x);
		System.out.println("메서드 호출 후 main(): x="+ d.x); //10
		
		//class 가 매개변수인 경우
		d.x=20;
		System.out.println("\n----main() : x="+d.x); //20
		
		change2(d);
		System.out.println("change2() 호출 후 main():x="+d.x); //2000
		
		//배열이 매개변수인경우
		int[] arr = new int[2];
		arr[0]=30;
		arr[1]=40;
		
		System.out.println("\n======main(): arr[0]="+arr[0]); //30
		
		change3(arr);
		System.out.println("change3() 호출 후 main() : arr[0]="+arr[0]); //3000
	}

	public static void change(int x) { //call by value
		x=1000;
		System.out.println("change() : x="+x); //1000
	}
	
	public static void change2(Data d) { //call by reference
		d.x=2000;
		System.out.println("change2() : x="+d.x); //2000
	}
	
	public static void change3(int[] arr) { //call by reference
		arr[0]=3000;
		System.out.println("change3() : arr[0]="+arr[0]); //3000
	}
}

==> 기본형을 매개변수로 가진 경우 change 메서드를 호출해도 main() x의 값이 이전과 동일하지만

       참조형 (클래스가 매개변수, 배열이 매개변수) 의 경우 change 메서드 호출 후 main() 값이 변경된것을 확인할 수           있다.

 

 

※ 오버라이딩 (Overriding)

  - 부모 클래스로부터 상속받은 메서드의 내용을 변경하는 것 (= 메서드 재정의 )

 

▶ 오버라이딩 조건

  1. 메서드의 선언부는 부모의 것과 완전히 일치해야 함

       선언부 : 메서드명, 매개변수, 반환타입이 같아야 함

 

  2. 접근 제한자는 부모 메서드보다 좁은 범위로 변경할 수 없다.

      ex ) 부모 메서드가 protected 라면, 오버라이딩 메서드는 protected 나 public 이어야 함

             접근제한자 : private < default < protected < public

 

  3. 부모클래스의 메서드보다 많은 수의 예외를 선언할 수 없다

 

class Point{
	protected int x;
	protected int y;
	
	public String findLocation() {
		String result="x="+x+", y="+y;
		return result;
	}
} // 부모클래스

            class Point3D extends Point{
            private int z;

            //오버라이딩 메서드
            public String findLocation() {

                String result=super.findLocation() + ", z="+z; 
                return result;
            } // 자식클래스 
              //   => 부모(super) 에서 findLocation메서드를 가져와 변수 z 를 추가한다

 

※ this / super

 

▶ this

   - 다음 두 조건을 만족시킨다면 생성자간에도 서로 호출이가능함

        1 ) 생성자의 이름으로 클래스 이름 대신 this 를 사용한다

        2 ) 한 생성자에서 다른 생성자를 호출할때는 반드시 첫 줄에서만 호출이 가능하다

 

    ▷ this.멤버 : 자신의 멤버를 참조하는 this

    this () - 생성자를 호출하는 this()

                   - 같은 클래스 내의 Overloading 된 다른 생성자 메서드를 호출할 때 사용

 

                 - 다양한 변수들을 선택적으로 초기화하기위해 생성자를 다양하게 Overloading 하는건 알지 서현아

                    Overloading : 같은 클래스에서 메서드명은 같은데 매개변수의 개수 자료형 다른 것

 

lass Car{
	private String color;
	private String gearType;
	private int door;
    
    //기본형 생성자
    Car(String color, String gearType, int door){
		this.color=color;
		this.gearType=gearType;
		this.door=door;
	}
    
    Car(){
		this("white","auto",4); //this 로 매개변수가 3개인 위의 생성자를 호출하여 
                              매개변수 값에 차레로 값을 넣어줌
	}
    
    Car(String color){
		this(color, "auto",4);
	}  // this 로 맨 위의 생성자를 호출하여 color 매개변수를 넣으면
            color, auto,4로 나오게 함
            
    
    public void showInfo() {
		System.out.println("색상:"+ color);
		System.out.println("gearType:"+ gearType);
		System.out.println("문의 개수:"+ door+"\n");
	}
}

public class ThisTest {

	public static void main(String[] args) {
		Car c1 = new Car();
		c1.showInfo();
		
		Car c2 = new Car("Black");
		c2.showInfo();
		
		Car c3 = new Car("Red","manual",2);
		c3.showInfo();
				
	}

}

색상:white
gearType:auto
문의 개수:4

색상:Black
gearType:auto
문의 개수:4

색상:Red
gearType:manual
문의 개수:2

 

 

 

▶ super / super()

  ▷  super 

  - 부모클래스의 메서드를 자식클래스에서 오버라이딩한 경우에 super 을 사용함

  - 부모클래스의 메서드 내용에 추가적으로 작업을 덧붙이는 경우라면

       super 을 사용해서 부모클래스의 메서드를 포함시키는 것이 좋다

  - 자식클래스 내부에서 부모클래스의 메서드를 사용하고싶다면 super 키워드 사용

//부모클래스 메서드
public void showInfo() {
		System.out.println("이름:"+name);
		System.out.println("나이:"+age);
	}
//자식클래스 메서드
    public void showInfo() {
		super.showInfo(); //
		System.out.println("전공:"+major);
	}

//  : super이용하여 중복제거 (showInfo 메서드 오버라이딩한거임)

  = > 이름,나이,전공 출력 확인 가능 

 

	public String findLocation() {
			return super.findLocation()+", z="+z; // 부모 메서드 호출
		}

=> 이렇게 편리하게 사용가능 ! 

 

 

 

 

 

 ▷ super() - 부모 생성자를 호출하는 super()

 

class Parent{
	int x=10;
}

class Child extends Parent{
	int x=20;
	
	public void method() {
		System.out.println("x="+x);  //20
		System.out.println("this.x="+this.x); //20
		System.out.println("super.x="+super.x); //10
	}
}

public class SuperTest {
	public static void main(String[] args) {
		Child ch= new Child();
		ch.method();
	}

}

 

 

※ this와 super, this()/super() 를 비교하여 설명

 자신의 멤버를 참조하는 this => this.멤버
 생성자를 호출하는 this() => 같은 클래스의 다른 생성자를 호출할 때 사용한다.

 부모의 멤버를 참조하는 super => super.멤버, 부모의 멤버와 자신의 멤버를 구별하는 데 사용된다
 부모 생성자를 호출하는 super() 

 

 

 

 

 

◈ 전화번호부 만들기 속 '검색하기' 기능

 

    - 그냥 . . 통째로 외우자 . . !!!!

private int search(String name) {
		int index = -1;
		
		for (int i=0;i<count;i++) {
			PhoneInfo info = p[i];
		
		if(name.equals(info.getName()))
			index = i;
		}
		return index;
	}

search 기능은 delete 할때도 사용해야할 수 있으니까 따로 만들어둔다

  = > int index 를 -1 로 초기화 한다

        PhoneInfo 의 i 번째 배열을 info 변수에 저장한다

        

        만약 ( info 배열에서 가져온 name 이 == 매개변수 name)  과 같다면

        int index 의 값을 i 로 변경.

        그렇지않으면 -1 로 유지.

 

 

나는 지금 내가 '검색' 했던 name 이 i 번째 배열에 존재한다는 것을 search를 통해 알게되었다

그럼 이제 검색한 이름을 포함하고있는 i 번째 배열의 값 ( name, num, birth ) 을 뽑아보자 ! 

public void searchData() {
		System.out.println("데이터 검색을 시작합니다");
		
		System.out.println("이름:");
		String name = sc.nextLine();
		
		int dataIndex = search(name);
		if(dataIndex<0) {
			System.out.println("해당하는 데이터가 존재하지 않습니다");
		}else {
			p[dataIndex].showPhoneInfo();
			System.out.println("데이터 검색이 완료되었습니다");
		}
	}

 

 

 

위 search 에서 조회되지않아 처음 초기화 시켜놓았던  -1 값으로 유지되었다면

"해당하는 데이터가 존재하지 않습니다" 알림이 뜬다

 

 

i 번째 배열 순서를 int dataIndex 에 넣고

dataIndex 번째 ( =i번째 ) 배열의 전체 info 를 보여줘 라고 명령했다 ( p[dataIndex].showPhoneInfo(); )

 

내가 검색했던 'name' 이 포함된 배열의 전체값 (name , num, birth) 확인가능 !