[JAVA] 객체지향이론2

Posted by 신희준 on August 23, 2017


2017 - 08 - 23 (수)

  • 상속/오버라이딩
  • 제어자/다형성

  • 참고 도서 : 자바의 정석(남궁성 저, 도우출판)


    1 . 상속/오버라이딩


    상속

    - 기존의 클래스를 재사용해서 새로운 클래스를 작성하는 것.

    - 두 클래스를 조상과 자손으로 관계를 맺어주는 것.

    - 자손은 조상의 모든 멤버를 상속받는다. ( 생성자와 초기화 블럭은 제외 )

    - 자손은 조상의 멤버를 모드 포함하기 때문에 조상보다 멤버가 더 많거나 같다.

    class child extends parents{
      // child 클래스가 parents 클래스의 상속을 받음. extends(확장) parents보다 확장된다는 의미.
    }
    

    - 자바는 단일 상속만을 허용한다. - 비중이 높은 클래스 하나만 상속관계로 사용하며, 나머지는 포함관계(인스턴스를 생성)로 사용한다.

    class Human{
      int height;
      int weight;
      void run(){}
      void eat(){}
    }
    class Student extends Human{    // Human class 는 Student class 의 조상이다. 상속관계이다.
      void learn(){}              //Student class 는 Human class 의 인스턴스를 가지며 이에 확장된 인스턴스를 가진다.
      Book b = new Book();   //포함관계이다 . Book 클래스는 Student의 포함관계에 있다.
    }
    class Book{
      String title;
      int price;
    }  
    

    - 모든 클래스의 최고 조상은 Object 클래스이다. 조상이 없는 클래스도 자동적으로 Object클래스를 상속받는다.


    오버라이딩

    - 조상 클래스로부터 상속받은 메서드의 내용을 상속받는 클래스에 맞게 변경하는 것.(덮어씌우는 것)

    - 오버라이딩을 하기위해서는 선언부가 같아야한다.

    - 접근제어자의 범위를 좁힐 수 없다. (public 에서 protected 로 변경불가)

    class Human{
      void run() //run() 메서드 정의
    }
    class Student extends Human{
      void run(System.out.println("빨리뛰다.")) // 오버라이딩.
    }
    

    - super : this 와 비슷하다. 조상의 멤버와 자신의 멤버를 구별하는데 사용한다. super.변수명으로 조상의 멤버변수에 접근.

    - super() : this() 와 비슷하다. 조상의 생성자를 호출한다.

    public class Human {
    	int height;
    	int weight;
    	void run() {System.out.println("걷는다");}
    	void eat() {System.out.println("먹는다");}
    	public Human(int height, int weight) {
    		this.height = height;
    		this.weight = weight;
    	}
    }
    
    public class Student extends Human {
    	public Student(int height, int weight) {
    		super(height, weight); //조상클래스의 생성자를 호출한다.
    	}
    	void learn() {System.out.println("배운다.");}
    	void run() {System.out.println("키가 "+super.height+"이고  몸무게가"+ super.weight+"인 사람이 뛴다.");}
    } //오버라이딩. super.height 로 조상 클래스의 인스턴스 접근( this. 으로 자신의 인스턴스 접근하는 방법과 같다. )
    


    2 . 제어자/다형성



    제어자

    - 클래스, 변수, 메서드의 선언부에 사용되어 부가적인 의미 부여한다.

    접근제어자 : public, protected, defualt, private

    그 외의 제어자들 : static, final, abstract, native, synchronized, etc,..

    static : 멤버변수, 메서드, 초기화 블럭 앞에 붙을 수 있다. 클래스변수는 인스턴스를 따로 생성하지 않아도 되며 클래스 로드시 자동 생성된다.

    final : 클래스, 메서드, 멤버변수, 지역변수에 붙을 수 있다. final을 붙이면 변경될 수 없으며 변수에 붙으면 상수가 되고 메서드에 붙으면 오버라이딩을 통한 재정의를 할 수 없다.

    abstract : 클래스, 메서드 앞에 붙을 수 있으며 추상화만 시켜놓고 완성하지 않은 클래스 또는 메서드앞에 붙는다.

    class Card{
      final int NUM;
      final String KIND;
      Card(int n, String k){
          NUM=n;
          KIND=k;      
      } //생성자를 통한 final변수 초기화
    }
    public static void main(String args[]){
      Card c = new Card(1, "Spade"); // 생성자로 FINAL 변수 초기화.
      c.NUM = 3; // 불가능하다. 생성자로 FINAL 변수를 초기화 해주었기 때문에 변경 불가능.
    }  
    

    접근제어자

    private : 같은 클래스 내에서만 접근이 가능하다.

    default : 같은 패키지 내에서만 접근이 가능하다.

    protected : 같은 패키지 내에서, 다른패키지의 자손클래스에서 접근가능

    public : 접근제한이 없다.

    package a;
    
    public class Client {
    	private String id;  //private는 다른 패키지에서 접근이 불가능하다. 그러므로 getter, setter로 접근한다.
    	public String getId() {
    		return id;
    	}
    	public void setId(String id) {
    		this.id = id;
    	}
    	public client(String id) {
    		this.id = id;
    	} //보통 id 나 password 같은 개인정보는 유출의 우려가 있기에 외부로부터 보호하기위해 접근제어자를 private를 사용한다.
    }
    
    package b;   //다른패키지
    import a.Client; // 다른 패키지에있는 Client 클래스 임포트
    public class UserManage {
    	public static void main(String[] args) {
    		Client c1 = new Client("shj"); //Client 클래스는 public 으로 정의되어 접근가능.
      	System.out.println(c1.getId()); //getId 메소드또한 public으로 정의되어 다른패키지임에도 불구하고 사용가능.
    	}
    }
    


    다형성 (polymorphism)

    - 하나의 참조변수로 여러 타입의 객체를 참조할 수 있는 것. - 같은 메서드를 사용하더라도 결과가 다를 수 있음.

    참조변수의 형변환

    - 서로 상속관계에 있는 타입간의 형변환만 가능.

    - 자손 타입에서 조상타입으로 형변환 하는 경우, 형변환 생략가능

    - instanceof 연산자로 참조하는 인스턴스의 실제 타입을 체크

    class Human{
      int height;
      void run();
    }
    class Student extends Human{
      void run(System.out.println("빨리뛰다."));
    }
    
    class Test{
      public static void main(String args[]){
        Human h = new Human();
        Student s = new Student();
        //h = s;   >> 생략가능  
        //s = (Student)h;   >> 형변환 해주어야함.
        if(h instanceof Human){ System.out.print("true")}
        if(h instanceof Object){System.out.print("true")} //오브젝트 클래스는 모든 클래스의 조상
        if(h instanceof Student){System.out.prinln("true")} // 보통 instanceof를 통해 확인 한 후 형변환 진행.
    
      }
    }
    


    참조변수와 인스턴스 변수의 연결

    - 상속을 받으면서 멤버변수가 중복정의 될 시 참조변수의 타입(형태)에 따라 연결되는 멤버변수의 값이 달라진다.

    - 메서드가 오버라이딩 될 경우에는 참조변수의 타입에 상관없이 실제 인스턴스 타입에 정의된 메서드가 호출된다.

    class Human{
      int height = 100;
      void method(){System.out.println("사람");}
    }
    class Student extends Human{
      int height = 130;
      void method(){System.out.println("학생");}
    }
    class Test{
      public static void main(String args[]){
        Human s1 = new Student();
        Student s2 = new Student();
        s1.height; // 100이 저장된다.
        s2.height; // 130이 저장된다.  >> 멤버변수의 경우 참조하는 타입에 영향을 받는다.
        s1.method(); // 학생이 출력된다.
        s2.method();// 학생이 출력된다. >> 메서드는(오버라이딩) 참조변수 타입에 영향을 받지 않는다.
      }
    }