JavaSE

18일차_상속

알 수 없는 사용자 2015. 6. 21. 07:15

---------------------------------------
상속 (Inheritance)

1. 클래스를 재사용할 수 있도록 파생시키는 방법.
파생의 사전적 의미 : 사물이 어떤 근원으로부터 갈려 나와 생김.

2. 상속의 기본 형식

public class 하위클래스명 extends 상위클래스명 {
 //상위클래스의 멤버들을 하위클래스가 공유하게 된다.
 //자기 만의 고유한 멤버들을 추가할 수 있다.
}

3. Java에서 모든 클래스는 Object 클래스로부터 파생된 상태이므로 Object 클래스는 모든 클래스의 최상위 클래스이다.

4.
 Object 클래스는 명시적인 상속 표기를 하지 않아도 자동 상속된 상태이다. 따라서 모든 클래스는 Object 클래스의 멤버들을 공유할 수 있다.

//Sample87.java
package com.test;

//Object 클래스의 상속은 자동으로 이루어진다.
public class Sample87 {
 //멤버가 전혀 없는 상태의 클래스 작성
 //자동 생성되는 멤버->기본 생성자->객체 생성 과정에서 필수적으로 사용된다.
 //->내부적으로 Object 클래스의 멤버(toString() 등) 공유 가능
}

 

//Main87.java
package com.test;

public class Main87 {

 public static void main(String[] args) {
  
  Sample87 sample = new Sample87();
  
  //Sample87 클래스의 멤버는 전혀 없지만
  //Object 클래스의 멤버를 공유할 수 있기 때문에
  //toString() 메소드를 사용할 수 있다.
  //toString() 메소드 -> 인스턴스의 정보 반환
  System.out.println(sample.toString());
  
  //String 클래스도 Object 클래스의 하위 클래스이지만
  //toString() 메소드의 역할은 내부적으로 재정의(오버라이딩)되어 있다.
  String str = new String("TEST");
  System.out.println(str.toString());
  
  //같은 클래스 다른 객체 생성
  //->해쉬코드 확인
  Sample87 sample2 = new Sample87();
  System.out.println(sample2.toString());
  
  //특정 객체의 참조주소를 저장
  //->같은 객체를 접근할 수 있게 된다.
  //->해쉬코드 확인
  Sample87 sample3 = sample2;
  System.out.println(sample3.toString());
  
  //equals() 메소드는 두 개의 객체가 같은지, 다른지를 확인해준다.
  System.out.println(sample.equals(sample2));
  System.out.println(sample2.equals(sample3));
  
  
  //String 클래스에서의 equals() 메소드는
  //문자열 비교시 사용 -> 오버라이딩
  String a = new String("TEST");
  String b = new String("HELLO");
  String c = new String("TEST");
  String d = new String("test");
  System.out.println(a.equals(b));
  System.out.println(a.equals(c));
  System.out.println(a.equals(d));
  System.out.println(a.equalsIgnoreCase(d));
  

 }

}

 

 

--------------------------------
Object 클래스

java.lang Package

lang 패키지에는 모든 클래스의 상위 클래스인 Object, 기본형을 포함하는 wrapper클래스, String 클래스, 수학적 계산을 위한 Math, Thread, Class, Package 등의 클래스를 포함한다.

1. Object class

자바 클래스 계층에서 최상위 클래스이다.
아무런 클래스도 상속 받지 않은 클래스라도 실제로는 Object 클래스를 상속 받게 된다. 즉, 모든 클래스는 Object를 상속 받게 된다. Object 형의 참조 변수는 어떠한 클래스의 참조 값도 저장 할 수 있다. 클래스의 계층에서 상위 클래스의 참조 변수는 하위 클래스의 참조형을 저장 할 수 있다. primitive 형을 Object 에 직접 대입 할 수는 없다. wrapper 클래스 형태나 배열로 만들면 대입이 가능하다.

 

 


1.1 Object 의 메소드

1) boolean equals(Object obj)

두 개의 객체가 같은지를 비교한다. 이 메소드는 두 개의 객체가 동일한 객체일 때 (즉 메모리 공간의 동일한 공간에 저장된 같은 메모리 일 때)만 true를 리턴한다.

Button a = new Button("foo");
Button b = new Button("foo");
if(a.equals(b)){
System.out.print("equals");
}


두 개의 버튼은 같은 내용을 포함하고 있지만 두 개의 버튼이 저장된 실제의 위치는 다르다. 즉, a가 가리키는 메모리 번지와 b가 가리키는 메모리 번지가 다르다. 그러므로 "equals"는 출력이 되지 않는다.

Integer a = new Integer(3);
Integer b = new Integer(3);
if(a.equals(b)){
System.out.print("equals");
}

두 번째의 코드에서는 "equals"라는 메세지가 출력이 된다. 두 개의 Interger 객체가 3이라는 정수 값을 가지고 있지만 두 개의 객체는 서로 다른 메모리 번지를 가지고 있다. 그래서 Object에서 정의된 equals()에 의하면 flase가 되어야 한다. 하지만 Integer에서는 equals() 함수를 오버라이딩 했다. Object의 equals()는 두 개
의 객체 참조값(메모리 번지)를 비교하지만 이것을 오버라이딩 한 Interger() 함수에서는 그 포함한 값을 비교해서 같은 true를 리턴하도록 오버라이딩한 것이다. 객체의 equals() 메소드를 사용할 때는 equals()가 오버라이딩됐는지를 확인하고 사용해야 한다. 객체.equals(null)은 항상 false 가 리턴된다.

 

 

2) protected void finalize()

가비지 컬렉터가 이 객체를 가비지 컬렉션 할 후보라고 생각할 때( 이 객체를 참조하는 값이 하나도 없을 때)호출된다. 즉, 가비지 컬렉션 되기 전에 호출되는 메소드이다. 객체에 관한 마지막 정리 작업(비메모리 자원의 반환등)을 하는 용도로 주로 쓰인다.

3) Class getClass()

해당 객체의 런타임 클래스를 리턴한다.

[참고]
런타임 클래스

자바는 하위 클래스의 객체가 상위 클래스의 참조 변수에 대입 될 수 있다. 그러므로 객체 참조 변수의 실제적인 형은 실행시간이 되어 봐야 알 수 있다. 아래의 예를 보자.

Object obj = new Object(); //1
System.out.println(obj.getClass()); //2
Integer i = new Integer(7);
obj = i; //3
System.out.println(obj.getClass()); //4
System.out.print(obj.equals(new Integer(7))); //5

결과는 다음과 같다.
class java.lang.Object
class java.lang.Integer

//1 에서 obj 객체가 Object 형으로 선언된다. 그러므로 //2의 getClass() 메소드에 의해 "class java.lang.Object"라는 값이 출력이 된다. //3에서는 Object로 선언된 동일한 변수에 Integer 객체가 대입된다. obj가 실제 참조하고 있는(가리키고 있는) 변수는 Integer형의 객체를 가리키게 된다. 즉 런타임 클래스는 Integer
클래스가 된다. //5에서 obj.equals()를 하면 Object의 equals()메소드가 호출되지 않고 Integer의 equals() 메소드가 호출된다. 즉, 메소드는 런타임 클래스의 메소드가 호출되고 변수는 선언형의 멤버 변수가 참조 된다.

4) String toString()

객체가 표현하는 내용을 String으로 리턴한다. Object의 toString()은 단순히 클래스 이름과 해쉬 코드값을 출력하도록 아래와 같이 정의되어 있다. getClass().getName() + '@' + Integer.toHexString(hashCode()) 이 메소드도 equals()메소드 처럼 그 클래스가 포함하는 내용을 출력하도록 오버라이딩 되어 있는 곳이 있다.

Integer i = new Integer(9);
System.out.print(i.toString()); //Integer i의 정수값이 String으로 변형되어 출력된다.

5) 기타 메소드

* protected Object clone()
이 객체의 값을 가지고 있는 동일한 타입의 객체를 만들어 리턴한다.
* int hashCode()
객체의 hash code 값을 리턴한다.
* void notify()
이 객체가 가지고 있는 락을 기다리는 쓰레드 중 하나를 깨운다.
* void notifyAll()
이 객체가 가지고 있는 락을 기다리는 모둔 쓰레드를 깨운다.
* void wait()
다른 쓰레드가 이 객체에 해당하는 notify()나 notifyAll()을 호출할 때 까지 현재의 쓰레드를 멈춘다.
* void wait(long timeout)
다른 쓰레드가 이 객체에 해당하는 notify()나 notifyAll()을 호출하거나 timeout 만큼의 시간이 지날때 까지 현재의 쓰레드를 멈춘다.
* void wait(long timeout, int nanos)
다른 쓰레드가 이 객체에 해당하는 notify()나 notifyAll()을 호출하거나 timeout 만큼의 시간이 지날때 까지 현재의 쓰레드를 멈춘다. 이 메소드는 void wait(long timeout) 와 비슷하지만 더 세밀한 부분까지 시간을 조절 할 수 있다. 타임 아웃 시간은 1000000*millis+nanos 로 된다.

 

--------------------------------


//Main.java
package com.test;

public class Main {

 public static void main(String[] args) {
  
  //두 객체 간의 비교
  Sample31 s31 = new Sample31();
  Sample31 s32 = new Sample31();
  Sample31 s33 = s32;
  
  //Object 클래스의 멤버인 toString() 메소드는
  //모든 클래스가 사용 가능한 멤버이다.
  //toString() 메소드는 객체의 클래스명@해쉬코드를 반환한다.
  //(단, 오버라이딩된 경우는 예외)
  //toString() 메소드는 표현을 생략할 수 있다.
  System.out.println(s31.toString());
  System.out.println(s32.toString());
  System.out.println(s33.toString());
  System.out.println(s31);
  System.out.println(s32);
  System.out.println(s33);
  
  //Object 클래스의 멤버인 equals() 메소드는
  //모든 클래스가 사용 가능한 멤버이다.
  //equals() 메소드는 객체의 참조주소를 비교해서
  //일치하는지를 반환한다.
  //(단, 오버라이딩된 경우는 예외)
  System.out.println(s31.equals(s32));
  System.out.println(s32.equals(s33));
  
  
  //Wrapper 클래스는 내부적으로
  //toString()과 equals() 메소드를 오버라이딩해서 사용하고 있다.
  Integer i1 = new Integer(10);
  int i1 = 10;

  Integer i2 = new Integer(10);
  Integer i3 = i2;
  
  System.out.println(i1.toString());
  System.out.println(i2.toString());
  System.out.println(i3.toString());
  System.out.println(i1);
  System.out.println(i2);
  System.out.println(i3);
  
  System.out.println(i1.equals(i2));
  System.out.println(i2.equals(i3));
  
 }

}

 

 

 

 

5. 하위 클래스가 상속을 받은 경우 상위 클래스의 멤버들 중에서 public, protected 접근지정자를 가진 멤버들만 접근할 수 있다. private 멤버와 생성자는 제외된다.


접근지정자 종류
- private : 같은 클래스 내부에서만 접근 가능
- (default) : 접근지정자 표기하지 않은 경우. 같은 패키지 내부에서만 접근 가능
- protected : 상위 클래스에서 protected 접근 지정자를 지정한 멤버는 하위 클래스에서만 접근 가능. 단, 같은 패키지에서도 접근 가능.
- public : 모든 경우에서 접근 가능

//SuperSample32.java
package com.test;

//상위 클래스
public class SuperSample32 {
 
 //private 멤버
 private void method1() {
 }
 
 //(default) 멤버
 void method2() {
  this.method1();
 }
 
 //protected 멤버
 protected void method3() {
 }
 
 //public 멤버
 public void method4() {
 }
 

}

 

 

//SubSample32.java
package com.test;

//(같은 패키지)하위 클래스
public class SubSample32 extends SuperSample32 {
 
 //SuperSample32 클래스의 멤버를 공유할 수 있다.
 
 public void method() {
  
  //this.method1(); //private 멤버
  this.method2(); //(default) 멤버
  this.method3(); //protected 멤버
  this.method4(); //public 멤버
  
 }

}

 


//Main.java
package com.test;

public class Main {

 public static void main(String[] args) {
  
  //같은 패키지의 클래스
  SubSample32 s32 = new SubSample32();
  //s32.method1(); //private 멤버
  s32.method2(); //(default) 멤버
  s32.method3(); //protected 멤버
  s32.method4(); //public 멤버
  
  SuperSample32 s33 = new SuperSample32();
  //s33.method1(); //private 멤버
  s33.method2(); //(default) 멤버
  s33.method3(); //protected 멤버
  s33.method4(); //public 멤버
  
 }

}

 


//SubSample32.java
package com.sist;

import com.test.SuperSample32;

//(다른 패키지)하위 클래스
public class SubSample32 extends SuperSample32 {

 //SuperSample32 클래스의 멤버를 공유할 수 있다.
 
 public void method() {
  
  //this.method1(); //private 멤버
  //this.method2(); //(default) 멤버
  this.method3(); //protected 멤버
  this.method4(); //public 멤버
  
 }

}

 


//Main.java
package com.sist;

public class Main {

 public static void main(String[] args) {
  
  //다른 패키지의 클래스
  SubSample32 s32 = new SubSample32();
  //s32.method1(); //private 멤버
  //s32.method2(); //(default) 멤버
  //s32.method3(); //protected 멤버
  s32.method4(); //public 멤버

 }

}

 

 


6. 상속관계를 그림으로 표현한 것을 상속계층도라고 하다.

최상위클래스(Object) <- 상위클래스 <- 하위클래스 <- 최하위클래스(final 키워드 사용)


//FinalSample32.java
package com.test;

//파이널 클래스 : 더 이상 상속이 되지 않는 클래스 (오버라이딩 금지)
public final class FinalSample32 extends SuperSample32 {
 
 //오버라이딩 금지된 메소드
 //자기 자신을 위한 고유 멤버 추가는 가능하다.
  public void method() {
  
  }

}

 


//AnotherSubSample32.java
package com.test;

//상속 관계에 있어서
//상위 클래스를 SuperSample32 클래스로 지정할 수 있다.
//상위 클래스를 SubSample32 클래스로 지정할 수 있다.
//파이널 클래스인 FinalSample32 클래스는 지정할 수 없다.
public class AnotherSubSample32
  extends FinalSample32 {
 
}

 

 

----------------------------------------
요약

1. 상속의 개념
- 상위 클래스에 대한 서브(파생) 클래스를 만드는 행위.

2. 상속의 특징
- 상위 클래스의 멤버를 하위 클래스에서 공유할 수 있다.
- public class 하위클래스명 extends 상위클래스명 { }
- 최상위 클래스는 Object 클래스이다. Object 클래스가 가진 멤버는 모든 클래스의 멤버가 된다. toString(), equals()
- protected 접근제어자(접근지정자)는 상속 관계일 때만 작동.
- 상속 금지(오버라이딩 금지)는 final 키워드 사용.


---------------------------------------------