위로 아래

상속

상속

  1. 클래스가 가지고 있는 멤버를 다른 클래스에게 계승시키는 것
  2. C++은 다중 상속 (여러 클래스를 동시에 상속)을 쓰고, 자바는 단계별 상속을 이용한다.
  3. 상위 객체 클래스 : 부모 클래스(parent class), 슈퍼 클래스(super class), 기본 클래스(base class)
  4. 하위 객체 클래스 : 자식 클래스(child class), 서브 클래스(sub class), 파생 클래스(derived class), 확장 클래스(extended class)

 

상속의 장점

  1. 중복 코드를 줄일 수 있다
  2. 클래스 간의 전체 계층 구조를 파악하기 쉽다
  3. 새로운 클래스, 데이터, 메소드를 추가하기가 쉽다
  4. 데이터와 메서드를 변경할 때 상위의 있는 것만 수정해도 일괄 수정되어 유지보수가 용이하다

 


is-a와 has-a

is - a관계

  1. 상속관계
  2. 하얀 삼각형 화살표 사용
  3. 예시 : 원 - 도형, 사과 - 과일, 호랑이 - 동물

has - a관계

  1. 소유관계 (클래스 안의 클래스)
  2. 검정 삼각형 화살표 사용
  3. 예시 : 엔진 - 자동차, 카메라 - 스마트폰, 마우스 - 컴퓨터

 

예시

더보기
----------------------One.java 파일-------------------------
public class One {
	private int secret = 1;   // 전부 접근 불가
	int roommate = 2;   // default. 동일 패키지까지만 접근 가능
	protected int child = 3;   // 동일 패키지 접근 가능, 다른 패키지의 자식 패키지까지 접근 가능
	public int anybody = 4;   // 전부 접근 가능
}
---------------------One2.java 파일 (is - a 관계) -----------------------
public class One2 extends One{   // is - a 관계 (상속 관계)
	void print() {
		//System.out.println(secret);   //private는 접근 불가
		//System.out.println(roommate);   // 자식 클래스라도 부모와 다른 패키지에 있으면 default에 접근 불가
		System.out.println(child);
		System.out.println(anybody);
	}
}
---------------------Two.java 파일 (has - a 관계) -----------------------
public class Two {
	void print() {
		One o = new One();    // has - a 관계 (클래스 안의 클래스)
		//System.out.println(o.secret)   // 같은 패키지에 잇어도 다른 객체의 private 멤버 접근 불가
		System.out.println(o.roommate);
		System.out.println(o.child);
		System.out.println(o.anybody);
	}
}

extends

기본형

//부모 클래스 

class SuperClass{ 내용 }

//상속 받는 자식 클래스
class SubClass extends SuperClass { 내용 }

 

예시

더보기
-----------------------부모 클래스 Ex01Circle.java 파일-------------------------
public class Ex01Circle {
	private void secret() {   // private : 상속관계에서 호출 불가능.
		System.out.println("비밀이다.");
	}
	protected void findRadius() {   // protected : 상속관계에서 호출 가능.
		System.out.println("반지름은 10.0센티이다.");
	}
	public void findArea() {   // public : 상속관계에서 호출 가능.
		System.out.println("넓이는 ~이다.");
	}
}

---------------------자식 클래스 Ex01Ball.java 파일-----------------------
public class Ex01Ball extends Ex01Circle {
	private String color;
	
	public Ex01Ball(String color) {
		this.color = color;
	}
	
	public void findColor (){
		System.out.println(color + "색 공");
	}
	
    @Override
    public void findArea() {
		System.out.println("넓이는 4*(~)이다.");
	}
    
	public void findVolume() {
		System.out.println("부피는 ~이다.");
	}
}

---------------------메인 클래스 Ex01Main.java 파일-----------------------
public class Ex01Main {
	public static void main(String[] args) {
		Ex01Circle c1 = new Ex01Circle();
		Ex01Ball c2 = new Ex01Ball("빨강");
		
		System.out.println("원 :");
        //c1.secret();   // private라 직접 접근 불가
		c1.findRadius();
		c1.findArea();
		
		System.out.println("공 : ");
        //c2.secret();   // private라 상속 불가
		c2.findRadius();   // Circle에게서 상속 받은 메소드
		c2.findColor();   // Ball이 새로 생성한 메소드
		c2.findArea();   //  Circle에게서 상속 받은 메소드
		c2.findVolume();   // Ball이 새로 생성한 메소드
	}
}

 

 


오버라이딩 (Overriding)

특징

  1. 상속된 메소드와 동일한 이름, 동일한 매개변수를 가지는 메소드를 정의하여 메소드를 덮어씌우는 것
  2. 부모 클래스로부터 상속 받은 메소드를 자식 클래스에서 재정의하는 것.
  3. 오버라이딩 할 경우엔, public, default 이런 접근지시자의 범위를 좁혀서는 안 된다.
  4. 어노테이션 : 오버라이딩 한 코드에는 표시하기 위해서 @Override를 붙이기도 한다. 오버라이딩 문법에 어긋나면 오류를 띄워 알려준다.
  5. 오버라이딩 불가능한 경우
    1. private 메소드 : 부모 클래스 전용이라 자식 클래스가 접근할 수 없다.
    2. static 메소드 : 클래스는 힙 영역에, static은 class method영역에 저장되어, 메모리가 저장되는 위치가 다르다
    3. final 메소드 : 오버라이드 불가
  6. 상속 받은 클래스를 자식 클래스의 상황에 맞게 변경해야 할 경우 사용
    1. 상속받은 부모 클래스 메소드의 기능 변경
    2. 상속받은 부모 클래스 메서드데 기능 추가

 

접근지시자 예시

더보기
-----------------------sec 패키지 One.java 파일-------------------------
public class One {
	private int secret = 1;   // 전부 접근 불가
	int roommate = 2;   // default. 동일 패키지까지만 접근 가능
	protected int child = 3;   // 동일 패키지 접근 가능, 다른 패키지의 자식 패키지까지 접근 가능
	public int anybody = 4;   // 전부 접근 가능
	
	public void show() {}   // 추상 클래스
}
---------------------sec 패키지 One1.java 파일-----------------------
public class One1 extends One{
	void print() {
		//System.out.println(srcret);
		System.out.println(roommate);
		System.out.println(child);
		System.out.println(anybody);
	}
	
	//void show() {}   // 오버라이딩할 때 접근 범위가 좁아지면 오류 발생.
  	  //오류 발생 안 하려면 부모랑 똑같이 public 붙여줘야 함.
}

 

어노테이션 @Override 예시

더보기
public class Ex01Ball extends Ex01Circle {
	private String color;
	
	public Ex01Ball(String color) {   // 생성자
		this.color = color;
	}
	
	public void findColor (){   // 새로 추가한 메소드
		System.out.println(color + "색 공");
	}
	
	@Override
	public void findArea() {   // 상속 받은 메소드 재정의(오버라이드)
		System.out.println("넓이는 4*(~)이다.");
	}

}

 

 

 


상속 제한

private

  1. 같은 클래스 내에서만 사용할 수 있도록 규제되기에, 상속 받은 클래스라 하더라도 사용할 수 없다. 

 

final

  1. 필드, 메소드, 클래스에 붙이면 상속이 제한된다.
  2. final 변수 : 상수
  3. final 메소드 : 하위 클래스에서 오버라이딩할 수 없는 메소드.
  4. final 클래스 : 상속이 불가능한 클래스.

 

Static

  1. 인스턴스 메소드나 인스턴스 변수는 heap 영역에 저장되어 런타임 중 상속이 가능하나, 메소드 영역 안에 있는 static 영역은 프로그램 첫 실행 때 먼저 실행되므로 컴파일 때 저장된다.
  2. static이 붙으면 같은 이름의 메소드를 오버라이드하더라도, 상속이 되지 않고 각자의 메소드로 사용하게 된다.

 


생성자와 super

특징

  1. 자식 생성자를 호출하면 부모 생성자를 더 우선으로 호출한다. (자식 클래스로 인스턴스를 만들면 부모 생성자부터 확인한다)
  2. 부모 클래스에게 매개변수가 있는 생성자만 있을 경우, 자식 클래스의 생성자에 super를 꼭 써줘야 한다.
  3. 오류 해결법
    1. 부모 클래스에 디폴트 생성자 넣어주기
    2. 자식 클래스 생성자에 super 메소드 넣어주기

 

super

  1. 부모 클래스의 생성자를 호출하는 메소드.
  2. 자식 클래스의 생성자 첫 줄에 써야 한다. 

 

예시

더보기
-----------------------부모 클래스 Animal.java 파일-------------------------
class Animal {
	public Animal() {
		System.out.println("종 : 이름");
	}
	public Animal(String s) {
		System.out.println("동물 : "+s);
	}
}

---------------------자식 클래스 Mammal.java 파일-----------------------
class Mammal extends Animal {
	public Mammal() {
		System.out.println("포유류 : 원숭이");
	}
	public Mammal(String s) {
		super(s);
		System.out.println("포유류 : "+s);
	}
}
---------------------메인 클래스 Main.java 파일-----------------------
public class Main {
	public static void main(String[] args) {
		Mammal ape = new Mammal();
		Mammal lion = new Mammal("사자");
	}
}

 

 

타입 변환

타입변환 (casting)

  1. 자동 타입변환 (auto casting or Promotion)
    1. 부모 클래스 변수에 자식 객체 타입을 대입하면, 자동으로 타입변환이 일어난다.
    2. 상속 관계가 아니면 타입 변환이 불가능하다! (어떠한 객체든지 최상위 클래스 Object와는 상속 관계를 맺고 있으니 Object 자료형을 써주면 해결할 수 있다)
    3. 자동 타입변환 후, 변수는 자식 객체를 참조하고 있지만, 변수로 접근 가능한 클래스 멤버는 부모 클래스 멤버로만 한정된다.
    4. 단, 메소드가 자식클래스에서 오버라이딩 되었다면, 부모 클래스의 메소드 대신 오버라이딩된 메소드가 호출된다.
  2. 강제 타입변환 (Casting)
    1. 부모 타입을 자식 타입으로 변환하는 것
    2. 가능한 경우는 하나 : 자식 타입이 부모 타입으로 자동 변환 되어 있을 때, 다시 자식 타입으로 변환할 때 사용.

 

 

예시

더보기
-----------------------부모 클래스 Person.java 파일-------------------------
public class Person {
	String name = "사람";
	
	void whoami() {
		System.out.println("나는 사람이다.");
	}
-----------------------자식 클래스 Student.java 파일-------------------------
public class Student extends Ex06Person {
	int number = 7;
	void work() {
		System.out.println("나는 공부한다.");
	}
}
-----------------------메인 클래스 Main.java 파일-------------------------
public class Main {
	public static void main(String[] args) {
		Person p;
		// p 가 가지고 있는 멤버들은  whoami(), name
		Student s = new Student();
		// s가 가지고 있는 멤버들은 whoami(), name - 상속 받은 것, work(), number - 본인 것
		
		// 하위 클래스 변수가 상위 클래스 변수로 저장 가능
		p = s;   // 자동 형변환 (auto casting). p가 부모 클래스라, p에 s를 담으면 자동으로 s의 정보를 담은 Person의 인스턴스가 된다.
		
		//p.number = 1;   // p는 Person의 인스턴스이므로, Student의 멤버는 사용하지 못한다.
		//p.work();   // p는 Person의 인스턴스이므로, Student의 멤버는 사용하지 못한다.
		p.whoami();   // Person의 멤버(메소드)이므로 호출 가능.
		
		Student s1 = (Student) p; //강제 형변환 (casting). Person인 p를 강제로 Student로 형변환해서, p의 정보를 담은 Student인 s1 선언.
		s1.number=6;   // s1은 Student의 인스턴스라 Student 멤버 사용 가능.
		s1.work();   // s1은 Student의 인스턴스라 Student 멤버 사용 가능.
	}
}

 

 

instanceof

어떤 클래스로 만들어졌는지 확인

고객의 등급 (vip, 일반) 등을 확인할 때 쓰인다.

 

기본형

변수 instanceof 타입
// 변수 : 객체를 참조하는 변수
// instanceof : boolean 값 반환
// 타입 : 클래스 이름 혹은 인터페이스 이름

 

예시

더보기
-----------------------부모 클래스 Person.java 파일-------------------------
public class Person {
	String name = "사람";
	
	void whoami() {
		System.out.println("나는 사람이다.");
	}
-----------------------자식 클래스 Student.java 파일-------------------------
public class Student extends Ex06Person {
	int number = 7;
	void work() {
		System.out.println("나는 공부한다.");
	}
}
-----------------------메인 클래스 Main.java 파일-------------------------
public class Main {
	public static void main(String[] args) {
		Ex06Student s = new Student();
		Ex06Person p = new Person();
		
		System.out.println(s instanceof Person);   // 결과 true.
		// Student의 인스턴스도 Person을 상속받았기 때문에, 결국 Person으로 만들어졌다
		System.out.println(s instanceof Student);   // 결과 true
		System.out.println(p instanceof Student);   // 결과 false
		//System.out.println(s instanceof String);   // 불가능.
		
		downcast(s);   // Student를 전송
		downcast(p);   // Person을 전송
	}
	
	static void downcast (Person p) {   // Person이 부모이기 때문에, Person도 Student도 받을 수 있다. (다형성)
		if(p instanceof Student) {   // p가 Student로 만들어졌는지?
			Student s = (Student) p;
			System.out.println("ok. 하향 타입 변환"+s.number);
			s.work();
		} else {
			p.whoami();
		}
	}
}

 

 

 


언제 쓰느냐

같은 내용을 지닌 채로 전송 시에는 부모 클래스로 형변환해 쉽게 오가다가, 도착 후에는 본인 클래스로 돌아와 정보를 풀어놓는다.

코드가 짧아진다.

-----------------------메인 클래스 MsgSendExam2.java 파일-------------------------
public class MsgSendExam2 {
	public static void main(String[] args) {
		MsgSend msg[] = {
				new EmailSend(),
				new SmsSend(),
				new FaxSend()};
		
		for(MsgSend m : msg) {   // 다형성
			m.send();   // 각자 자기 메소드 실행
			if(m instanceof EmailSend) {
				EmailSend e = (EmailSend) m;
				e.createEmail();   // 결과 이건 이메일 거
			}
			if(m instanceof SmsSend) {
				SmsSend s= (SmsSend) m;
				s.createSMS();   // 결과 이건 SMS 거
			}
		}
	}
}
-----------------------부모 클래스(추상 클래스) MsgSend.java 파일-------------------------
public class MsgSend {
	public void send() {}
}
-----------------------자식 클래스 MsgSend.java 파일-------------------------
public class EmailSend extends MsgSend {
	@Override
	public void send() {
		System.out.println("여기는 Email 전송");
	}
	
	public void createEmail() {
		System.out.println("이건 이메일 거");
	}
}
-----------------------자식 클래스 SmsSend.java 파일-------------------------
public class SmsSend extends MsgSend {
	@Override
	public void send() {
		System.out.println("여기는 SMS 전송");
	}
	public void createSMS() {
		System.out.println("이건 SMS거");
	}
}
-----------------------자식 클래스 FaxSend.java 파일-------------------------
public class FaxSend extends MsgSend {
	@Override
	public void send() {
		System.out.println("여기는 Fax 전송");
	}
}