ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 6주차 과제: 상속
    Programming/Java live study 2020. 12. 24. 20:48
     

    6주차 과제: 상속 · Issue #6 · whiteship/live-study

    목표 자바의 상속에 대해 학습하세요. 학습할 것 (필수) 자바 상속의 특징 super 키워드 메소드 오버라이딩 다이나믹 메소드 디스패치 (Dynamic Method Dispatch) 추상 클래스 final 키워드 Object 클래스 마

    github.com

    목표

    자바의 상속에 대해 학습하세요.

    학습할 것

     - 자바 상속의 특징

     - super 키워드

     - 메소드 오버라이딩

     - 다이나믹 메소드 디스패치 (Dynamic Method Dispatch)

     - 추상 클래스

     - final 키워드

     - Object 클래스


    상속

     현실 세계에서 상속은 부모의 재산을 자손이 물려받는 것을 의미한다. 객체 지향에서의 상속은 재산을 상속받는 것이 아니라 부모의 생물학적인 특징을 물려받는 것이 더 가깝다. 객체 지향에서 상속은 부모 클래스에 정의된 필드와 메소드를 자식 클래스가 물려받는 것을 의미한다. 자식 클래스는 부모 클래스가 정의한 필드와 메소드를 따로 정의하지 않아도 정의한 것 처럼 사용할 수 있다.

     

    자동차의 기능을 상속하고 기능이 추가되어 구체화된다.

     

     상속은 클래스 사이의 필드, 메소드의 중복 선언을 줄여준다. 또한 필드와 메소드를 재사용해서 클래스를 간결화한다. 마지막으로 클래스 간의 계층적 분류를 활용하여 관리에 용이하다.


    1. 자바 상속의 특징

    자바에서는 다중 상속을 지원하지 않는다.

     - 클래스를 여러 개 상속 받는 다중 상속 (multiple inheritance)를 지원하지 않는다. 상속을 선언하는 extends 뒤에는 하나의 클래스만 올 수 있다. 후에 다룰 interface에서는 다중 상속(multiple inheritance)를 지원하다.

     - 자바에서는 상속의 횟수에 제한을 두지 않는다.

     

    자바에서 계층 구조의 최상위 클래스는 java.lang.Object 클래스이다.

     - 자바에서는 따로 명시하지 않아도 Object 클래스가 컴파일러에 의해서 자동으로 상속된다. Object 클래스는 상위 클래스가 없고, 모든 클래스의 최상위에 위치한다.

     - 상속은 클래스 사이의 상속이다. 객체 사이의 상속이 아니다. 자식 객체가 생성될 때 작식 클래스와 부모 클래스의 상속 관계에 따라 부모 클래스에 정의된 필드 및 메소드를 가지고 생성된다.

     

    최상위 클래스 Object

    1.1 상속 선언

    public class Figure { // 도형 클래스
    
        private int x;
        private int y;
    
        public int getX() {
            return this.x;
        }
    
        public void setX(int x) {
            this.x = x;
        }
    
        public int getY() {
            return this.y;
        }
    
        public void setY(int y) {
            this.y = y;
        }
    }

     

    public class Cycle extends Figure { // 도형 클래스를 상속 받는 원 클래스
    
        private int radius;
    
        public int getRadius() {
            return this.radius;
        }
    
        public void setRadius(int radius) {
            this.radius = radius;
        }
    
    }

     

     Cycle 클래스는 Figure 클래스의 필드와 메소드를 물려받았기 때문에 다시 선언할 필요가 없다. 새롭게 추가된 특성을 표현하기 위한 필드와 메소드만 선언하면 된다.

     

    Figure 클래스의 메소드인 getX, getY가 사용가능하다.

    1.2 접근 지정자

     상속에는 접근 지정자에 따라서 클래스의 허용 범위가 달라진다. 특히 부모 클래스의 private한 필드들은 자식 클래스조차 접근이 불가능하지만 protected 필드는 자식 클래스의 접근이 허용된다.

     

     밑의 표는 상황과 접근 지정자에 따른 접근 가능 여부이다.

     

    부모 클래스 멤버에 접근하는 클래스
    부모 클래스 멤버의 접근 지정자
    defualt private protected public
    같은 패키지의 클래스 O X O O
    다른 패키지의 클래스 X X X O
    같은 패키지의 자식 클래스 O X O O
    다른 패키지의 자식 클래스 X X O O

     

    private 

     - 부모 클래스의 멤버에 private이 지정되면 자식클래스조차 접근이 불가능하다.

    protected

     - 같은 패키지에 속한 다른 클래스의 접근을 허용한다.

     - 같은 패키지, 다른 패키지든 상관없이 상속받는 자식 클래스는 접근을 허용한다.

    public 

     - 어떤 클래스에서도 접근 가능하다.

    default 

     -같은 패키지 안에만 있으면 모두 접근 가능하다.

    1.3 생성자

    상속 관계의 부모 클래스와 자식 클래스는 각각 생성자를 가지고 있다.  자식클래스의 객체 생성 시에 부모, 자식 클래스 모두 생성자를 호출한다. 생성자는 멤버의 초기화의 목적을 가지고 있기 때문에 부모 클래스의 멤버또한 생성자가 시행되어야 한다.

     

    public class Figure { // 도형 클래스
    
        private int x;
        private int y;
    
        public Figure() {
            System.out.println("Figure 생성자");
        }
    
        public int getX() {
            return this.x;
        }
    
        public void setX(int x) {
            this.x = x;
        }
    
        public int getY() {
            return this.y;
        }
    
        public void setY(int y) {
            this.y = y;
        }
    }
    
    public class Cycle extends Figure { // 도형 클래스를 상속 받는 원 클래스
    
        private int radius;
    
        public Cycle() {
            System.out.println("cycle 생성자");
        }
    
        public int getRadius() {
            return this.radius;
        }
    
        public void setRadius(int radius) {
            this.radius = radius;
        }
    
    }
    
    public class Main {
    
        public static void main(String[] args) {
            Cycle cycle = new Cycle();
        }
    }
    

     

     main 함수를 실행하게 되면 

     

    Figure 생성자
    cycle 생성자

     

     두 개의 클래스 생성자가 실행된 것을 확인 할 수 있다. 여기서 순서를 살펴보면 부모 클래스의 생성자가 먼저 실행된 것을 알 수 있다.

     

     

     이것이 의미하는 바는 객체를 저장하는 Heap영역에는 자식 클래스 뿐만 아니라 부모 클래스 또한 생성된다는 것을 알 수 있다. 

     

    1.4 생성자 짝 맞추기

    각 클래스는 하나의 생성자만 가지고 있지 않다. 컴파일러는 자식 클래스의 생성자를 기준으로 적합한 부모 클래스의 생성자를 선택한다.

     

    자식 클래스의 기본 생성자는 자동으로 부모 클래스의 기본 생성자와 짝을 맺는다. 짝을 이룰 기본 생성자가 없다면 컴파일러에 의해서 오류가 발생하게 된다.

     

    public class Figure { // 도형 클래스
    
        private int x;
        private int y;
    
        public Figure(int x, int y) {
            System.out.println("Figure 매개변수 생성자");
        }
    
        public int getX() {
            return this.x;
        }
    
        public void setX(int x) {
            this.x = x;
        }
    
        public int getY() {
            return this.y;
        }
    
        public void setY(int y) {
            this.y = y;
        }
    }
    
    public class Cycle extends Figure { // 도형 클래스를 상속 받는 원 클래스
    
        private int radius;
    
        public Cycle() { // 짝이 맞는 생성자가 존재하지 않는다. 오류 발생
            System.out.println("cycle 생성자"); 
        }
    
        public int getRadius() {
            return this.radius;
        }
    
        public void setRadius(int radius) {
            this.radius = radius;
        }
    
    }
    
    public class Main {
    
        public static void main(String[] args) {
            Cycle cycle = new Cycle();
        }
    }
    

     

     해결 하기 위해서는 부모 클래스에 짝이 맞는 생성자를 만들어 주거나, super()를 이용하여 명시적으로 슈퍼 클래스의 생성자를 호출해야 한다.


    2. super 키워드

    2.1 super

    this 키워드와 유사하게 사용이 가능하다. 자기 자신을 가리키는 것이 아닌 부모 클래스에 접근 가능한 멤버를 사용할 때 사용된다. this와 super는 모두 랜퍼런스이다. this는 현재 객체의 주소를 가리키고, super는 현재 객체의 부모 클래스 영역의 주소를 가진다.

     

    public class Cycle extends Figure { // 도형 클래스를 상속 받는 원 클래스
    
        private int radius;
    
        public Cycle() {
            System.out.println("cycle 생성자");
        }
    
        public int getRadius() {
            return this.radius;
        }
    
        public void setRadius(int radius) {
            this.radius = radius;
        }
    
        public void printXY() {
            System.out.println(super.getX()); // 부모 클래스의 getX를 호출
            System.out.println(super.getY()); // 부모 클래스의 getY를 호출
        }
    
    }

    2.2 super()

    명시적으로 부모 클래스의 생성자를 호출하기 위해서는 super()가 필요하다. 사용방법은 this()와 유사하다.

     

    public class Figure { // 도형 클래스
    
        private int x;
        private int y;
    
        public Figure(int x, int y) {
            System.out.println("Figure 매개변수 생성자");
        }
    
        public int getX() {
            return this.x;
        }
    
        public void setX(int x) {
            this.x = x;
        }
    
        public int getY() {
            return this.y;
        }
    
        public void setY(int y) {
            this.y = y;
        }
    }
    
    public class Cycle extends Figure { // 도형 클래스를 상속 받는 원 클래스
    
        private int radius;
    
        public Cycle() { 
        	super(0, 0); // 명시적으로 호출한다. 
            System.out.println("cycle 생성자"); 
        }
    
        public int getRadius() {
            return this.radius;
        }
    
        public void setRadius(int radius) {
            this.radius = radius;
        }
    
    }
    
    public class Main {
    
        public static void main(String[] args) {
            Cycle cycle = new Cycle();
        }
    }
    

     

     여기서 중요한 점은 반드시 생성자 코드 첫 라인에 와야한다. 추가로 this()와는 함께 사용할 수 없다.

     

    public Cycle() { 
        System.out.println("cycle 생성자"); 
        super(0, 0); // 에러 발생!
    }

    3. 메소드 오버라이딩

    3.1 오버라이딩

    메소드 오버라이딩은 부모 클래스와 자식 클래스 사이에서 발생한다. 부모 클래스의 메소드를 동일한 이름으로 자식 클래스에서 작성할 때 발생한다. 자식 클래스에 메소드를 오버라이딩 한 후 실행하게 되면 동적 바인딩이 일어나고, 부모 클래스의 메소드는 무시된다.

     

    메소드 오버라이딩을 위해서는 몇 가지 조건을 충족 시켜야 한다.

     

    메소드 오버라이딩은 부모 클래스의 메소드와 완전히 동일한 메소드를 재정의해야 한다. 

     - 같은 이름, 같은 반환 타입, 같은 매개 변수를 갖는 메소드를 작성해야 한다.

     

    메소드 오버라이딩 시에 부모 클래스 메소드의 접근 지정자보다 접근의 범위가 좁아질 수 없다.

      - public, protected, defualt, private 순으로 범위가 좁아진다. 

      - public 메소드의 경우 private, protected가 아닌 반드시 public으로 해야한다.

     

    static, private, final로 선언된 메소드는 오버라이딩 될 수 없다.

     

     메소드 오버라이딩에 간단한 예시이다. 

     

    public class Figure { // 도형 클래스
    
        private int x;
        private int y;
    
        public Figure() {
            System.out.println("Figure 생성자");
        }
    
        public Figure(int x, int y) {
            this.x = x;
            this.y = y;
        }
    
        public int getX() {
            return this.x;
        }
    
        public void setX(int x) {
            this.x = x;
        }
    
        public int getY() {
            return this.y;
        }
    
        public void setY(int y) {
            this.y = y;
        }
    
        public void print() {
            System.out.println("Figure의 print");
        }
    
    }

     

    public class Cycle extends Figure { // 도형 클래스를 상속 받는 원 클래스
    
        private int radius;
    
        public Cycle() {
            super();
            System.out.println("cycle 생성자");
        }
    
        public Cycle(int x, int y, int radius) {
            super(x, y);
            this.radius = radius;
        }
    
        public int getRadius() {
            return this.radius;
        }
    
        public void setRadius(int radius) {
            this.radius = radius;
        }
    
        @Override 
        public void print() { // Figure 클래스의 print 메소드 오버라이딩
           System.out.println("Cycle의 print");
        }
    
    }

     

    public class Main {
    
        public static void main(String[] args) {
            Cycle cycle = new Cycle(1, 1, 3);
            cycle.print();
        }
    
    }
    

     

    Cycle의 print

     

    부모 클래스의 print는 무시되고 Cycle 클래스의 print 메소드가 실행되는 것을 알 수 있다. 만약 부모 클래스의 print를 사용하고 싶다면 super.print()로 사용할 수 있다.

     

    @Override
    public void print() {
        super.print();
        System.out.println("Cycle의 print");
    }

     

    Figure의 print
    Cycle의 print

    3.2 @Override

    JDK 1.5부터 추가된 애노테이션이다. 자식 클래스에 오버라이딩을 위한 메소드를 작성하던 중 원형과 다를 경우 컴파일러는 새로운 메소드로 인식하고 아무런 오류를 보여주지 않는다. Java에서 이러한 오류를 컴파일 시에 쉽게 발견하기 위해서 추가하였다. @Override의 기능은 컴파일러에게 다음 라인에 오는 메소드가 오버라이딩하는 메소드임을 알려주고 원형 메소드를 체크하도록 지시한다.

    3.3 오버라이딩은 왜 필요한가?

    메소드 오버라이딩은 자식 클래스를 작성하는 개발자가 상속받은 슈퍼 클래스의 어떤 메소드를 자신의 특성에 맞게 새로 만들어 사용하고 싶은 경우에 활용된다. 

     

    public class Figure { // 도형 클래스
    
        private int x;
        private int y;
    
        public Figure() {
            System.out.println("Figure 생성자");
        }
    
        public Figure(int x, int y) {
            this.x = x;
            this.y = y;
        }
    
        public int getX() {
            return this.x;
        }
    
        public void setX(int x) {
            this.x = x;
        }
    
        public int getY() {
            return this.y;
        }
    
        public void setY(int y) {
            this.y = y;
        }
    
        public void print() {
            System.out.println("Figure의 print");
        }
    
        @Override
        public String toString() {
            return "Figure{" +
                    "x=" + x +
                    ", y=" + y +
                    '}';
        }
        
    }
    

     

    최상위 클래스인 Object 클래스의 toString 메소드를 오버라이딩 하였다. 각각의 클래스는 필드, 메소드 등 구성 요소가 다르기 때문에 toString 메소드를 사용하기 위해선 그 클래스에 맞추어 toString 메소드를 오버라이딩 해줘야 한다. 이처럼 각 클래스의 특성에 맞추어 필요한 equals 등 자신에게 맞게 오버라이딩 해줘야 안전하게 믿고 사용할 수 있다.


    4. 다이나믹 메소드 디스패치 (Dynamic Method Dispatch)

    메소드 디스패치란? 프로그램이 메소드를 어떻게 실행할지 정하는 것이다. Dynamic이 붙었기 때문에 컴파일 시점에서 정하는 것이 아니라 런타임 시점에 메소드가 동적으로 바인딩된다. 즉 코드가 실행되고 있는 와중에 어떤 메소드를 사용할지 정해지는 것이다.  Figure 클래스는 추상 클래스라고 가정하고, Cycle은 Figure 추상 클래스를 상속하여 구현한 구현체이다.

     

    public class Main {
    
        public static void main(String[] args) {
            Figure figure = new Cycle(1, 1, 3); // 부모 타입 래퍼런스 변수
            figure.print(); 
        }
    
    }
    

     

     위 코드를 보면 부모 타입의 래퍼런스 변수인 것을 알 수 있다. 컴파일 시점에서 호출된 객체의 정보를 알 수 없기 때문에 어떤 메소드를 사용할지 예측할 수 없다.

     

    public abstract class Figure { // 도형 클래스
    
        private int x;
        private int y;
    
        public Figure() {
            System.out.println("Figure 생성자");
        }
    
        public Figure(int x, int y) {
            this.x = x;
            this.y = y;
        }
    
        public int getX() {
            return this.x;
        }
    
        public void setX(int x) {
            this.x = x;
        }
    
        public int getY() {
            return this.y;
        }
    
        public void setY(int y) {
            this.y = y;
        }
    
        public abstract void print();
    
    }

     

    public class Cycle extends Figure { // 도형 클래스를 상속 받는 원 클래스
    
        private int radius;
    
        public Cycle() {
            super();
            System.out.println("cycle 생성자");
        }
    
        public Cycle(int x, int y, int radius) {
            super(x, y);
            this.radius = radius;
        }
    
        public int getRadius() {
            return this.radius;
        }
    
        public void setRadius(int radius) {
            this.radius = radius;
        }
    
        @Override 
        public void print() { // Figure 클래스의 print 메소드 오버라이딩
           System.out.println("Cycle의 print");
        }
    
    }

     

    public class Square extends Figure { // 도형 클래스를 상속 받는 사각형 클래스
    
        private int width;
        private int height;
    
        public Square() {
            super();
            System.out.println("square 생성자");
        }
    
        public Square(int x, int y, int width, int height) {
            super(x, y);
            this.width = width;
            this.height = height;
        }
    
        public int getWidth() {
            return this.width;
        }
    
        public void setWidth(int width) {
            this.width = width;
        }
        
        public int getHeight() {
        	return this.height;
        }
        
        public void setHeight(int height) {
        	this.height = height;
        }
    
        @Override 
        public void print() { // Figure 클래스의 print 메소드 오버라이딩
           System.out.println("Square의 print");
        }
    
    }

     

    public class Main {
    
        public static void main(String[] args) {
            Figure figure = new Cycle(1, 1, 3); // 부모 타입 래퍼런스 변수
            figure.print(); 
        }
    
    }
    

     

    Cycle의 print

     

     위의 예시는 부모 타입의 객체에 자식 타입이 대입되어 있는 형태이다. 런타임 시에 Cycle 클래스의 print를 가리켜 Cycle 클래스의 print가 실행되는 것을 알 수 잇다.


    5. 추상 클래스

    5.1 추상 메소드

    추상 메소드는 코드가 구현되지 않은, 메소드의 형식만 정해진 메소드이다. 추상 메소드를 작성하기 위해서는 추상이라는 의미를 가진 abstract 키워드가 필요하다. abstract와 함께 메소드의 반환 타입, 이름, 매개 변수를 선언해야 한다.

     

    public abstract void print();
    public abstract String getName();
    public abstract void setName(String name);

     

    추상 메소드는 메소드의 코드가 존재하면 안된다. 컴파일 오류를 발생시킨다.

     

    public abstract String getName() { // 컴파일 오류
    	return this.name;
    }
    
    public abstract void setName(String name) { // 컴파일 오류
    	this.name = name;
    }

     

    5.2 추상 클래스

    추상 클래스는 추상 메소드와 마찬가지로 abstract 키워드가 필요하다. 추상 클래스에는 몇 가지 조건이 필요하다.

     - 클래스를 반드시 abstract로 선언되어야 한다.

     - 추상 메소드가 하나도 포함되어 있지 않아도 된다.

     

    위의 Figure 클래스를 abstract로 바꾸었다.

     

    public abstract class Figure { // 도형 추상 클래스
    
        private int x;
        private int y;
    
        public Figure() {
            System.out.println("Figure 생성자");
        }
    
        public Figure(int x, int y) {
            this.x = x;
            this.y = y;
        }
    
        public int getX() {
            return this.x;
        }
    
        public void setX(int x) {
            this.x = x;
        }
    
        public int getY() {
            return this.y;
        }
    
        public void setY(int y) {
            this.y = y;
        }
    
        public abstract void print(); // 추상 메소드
    
    }

     

    Figure figure = new Figure(); // 오류

     

    추상 메소드는 생략이 가능 하다. 중요한 사실은 인스턴스 생성이 불가능하다. 추상 클래스에 실행 코드가 없는 추상 메소드가 있는 경우가 있기 때문에 객체 생성을 제한한다.

     

    Figure figure = new Cycle(); 

     

    하지만 래퍼런스 변수로는 사용이 가능하다. Figure 추상 클래스를 상속 받는 모든 클래스는 Figure 래퍼런스 변수에 대입될 수 있다. 다형성에 큰 이점을 가져온다.

     

    5.3 추상 클래스의 상속

    추상 클래스의 그대로 상속만 받으면 상속 받은 자식 클래스 또한 추상 클래스가 된다. 그렇기 때문에 abstract를 명시적으로 붙여줘야 컴파일 오류가 나지 않는다. 

     

    public abstract class ThreeDimensionalFigure extends Figure {
        
    }
    

     

    5.4 추상 클래스의 구현

    자식 클래스가 추상 클래스가 되지 않기 위해서는 추상 메소드를 전부 오버라이딩 해야 한다.

     

    public class ThreeDimensionalFigure extends Figure {
    
        @Override
        public void print() {
            System.out.println("ThreeDimensionalFigure");
        }
        
    }
    

     

    이렇게 되면 추상 클래스가 아니기 때문에 객체로 생성이 가능하다.

    5.5 추상 클래스의 용도

    추상 클래스를 상속받는 자식 클래스들은 개발자에 따라서 다양하게 구현된다. 단지 주의할 점으로는 추상 메소드만 전부 오버라이딩 하면 된다. 추상 클래스의 용도로는 설계와 구현체를 나누는 것이다. 해당 클래스의 용도를 설계하고 그 의도에 맞게 변형하여 구현체를 생성하는 것이다. 또한 추상 클래스는 상속 관계를 가지는 클래스를 설계할 때 적합하게 사용된다.


    6. final 키워드

     final 키워드는 세 군데에서 사용된다.

    6.1 final 클래스

    final이 클래스 이름 앞에 사용되면 클래스를 상속받을 수 없음을 의미한다.

     

    final class FinalFigure {
    	...
    }
    
    class Figure extends FinalFigure { // 컴파일 오류가 발생한다.
    	...
    }

    6.2 final 메소드

    final이 메소드 앞에 사용되면 이 메소드는 더 이상 오버라이딩 할 수 없음을 의미한다. 자식 클래스가 부모 클래스의 특정 메소드를 오버라이딩 하지 못하고 상속 받아 사용하도록 한다면 final로 지정하면 된다.

     

    class ParentFigure {
    	public final int finalMethod() {...}
    }
    
    class ChildFigure extends ParentFigure { 
    	public int finalMethod() {...} // 컴파일 오류가 발생한다.
    }

    6.3 final 필드

    자바에서 상수를 정의하기 위해서는 필드에 final 키워드를 붙여서 정의한다.

     

    final double PI = 3.141592;
    PI = 3.14; // 컴파일 오류가 발생한다.

     

    상수이기 때문에 값을 변경하려고 시도하면 컴파일 오류가 발생한다. final로 상수 필드를 정의하기 위해서는 선언 시에 초기값을 지정해야 한다. 상수 필드는 한 번 정의되면 값을 변경할 수 없다.

     

    일반적으로 final만 붙이게 되면 선언한 클래스 내에서만 사용가능하다. final 키워드에 static과 함께 사용하게 되면 프로그램 전체에서 공유할 수 있는 상수가 선언된다.

     

    public class PiClass {
    	public static final double PI = 3.141592;
    }

     

    선언한 클래스에서 사용 할 때는 그냥 사용이 가능하다.

     

    public double area = PI * radius * radius;

     

    외부의 클래스에서 사용 할 때는 선언된 클래스 명을 명시해 주어야 한다.

     

    public class PIClassTest {
    
        public static void main(String[] args) {
    
            int radius = 10;
            double area = PIClass.PI * radius * radius;
    
            System.out.println(area);
        }
    }

    7. Object 클래스

    7.1 Object

    Object는 클래스는 java.lang 패키지에 속한 클래스로, 자바의 모든 클래스들의 최상위에 위치한다. 이것이 의미하는 바는 모든 클래스는 Object의 자식 클래스 라는 의미이다. 클래스 이기 때문에 래퍼런스 변수 선언과 생성이 가능하다.

     

    Object object = new Object();

     

    Object

     

    7.2 주요 메소드

    메소드 설명
    protected Object clone() 현재 객체와 똑같은 객체를 만들어서 반환한다.
    boolean equals(Object obj) obj가 가리키는 객체와 현재 객체를 비교한다. 두 객체의 내용을 비교한다. 즉 동등성을 비교한다.
    Class getClass() 현재 객체의 런타임 클래스를 반환한다.
    int hashCode() 현재 객체에 대한 hash 코드 값을 리턴한다. native call을 하여 메모리가 가진 hash 주소 값을 출력한다. 두 객체가 같은 객체인지 비교한다. 즉 동일성을 비교한다.
    String toString() 현재 객체에 대한 문자열 표현을 반환한다.
    void notify() 현재 객체에 대해 대기하고 있는 스레드를 깨운다.
    void notifyAll() 현재 객체에 대해 대기하고 있는 모든 스레드를 깨운다.
    void wait() 다른 스레드가 깨울 때까지 현재 스레드를 대기하게 한다.

    7.3 getClass()

    Class 객체는 실행 중인 자바 프로그램에 포함된 클래스와 인터페이스를 나타내는 객체이다. getClass 메소드는 해당 클래스를 반환한다. getName()과 함께 사용하면 실제로 생성된 객체의 클래스 이름을 알 수 있다.

     

    Figure figure1 = new Figure();
    System.out.println(figure1.getClass().getName());
    
    Figure figure2 = new Cycle();
    System.out.println(figure2.getClass().getName());

     

    Figure
    Cycle

    7.4 toString()

    객체를 문자열로 변환하는 메소드이다. toString은 기본적으로 다음과 같이 정의된다.

     

    public String toString() {
    	return getClass().getName() + "@" + Integer.toHexString(hashCode());
    }

     

    Object 클래스의 toString은 현재 객체의 클래스 이름과 hash code를 16진수로 변환하여 문자열로 반환한다.

     

    System.out.println(figure.toString());

     

    Figure@36d64342

     

    그렇기 때문에 자신의 객체를 문자열로 바꾸고 싶으면 toString 메소드를 적절하게 오버라이딩 해야 한다.

     

    public String toString() {
    	return "Figure : { " + x + ", " + y + " }";

    7.5 equals(), hashCode()

    두 메소드 모두 객체를 비교하는 메소드이다. 하지만 둘은 큰 차이를 가지고 있다. equals의 경우 객체가 가진 내용을 비교한다. 즉 동등한지 비교하는 메소드이다. hashCode 메소드는 두 객체가 같은 객체인지, 같은 메모리에 있는 객체인지를 비교하는 메소드이다. 즉 동일성을 비교하는 연산자이다. equals의 경우 동등성에 대해서만 비교하기 때문에 온전하게 같은 객체라고 확신할 수 없다. 그렇기 때문에 hashCode도 함께 사용해야 한다.

     

    참고 : 황기태, 김효수 지음 명품 JAVA Programing

    'Programming > Java live study' 카테고리의 다른 글

    8주차 과제: 인터페이스  (0) 2021.01.05
    7주차 과제: 패키지  (0) 2020.12.30
    5주차 과제: 클래스  (0) 2020.12.24
    4주차 과제: 제어문  (0) 2020.12.24
    3주차 과제: 연산자  (0) 2020.12.24

    댓글

Designed by Tistory.