Skip to content

Item 16. public 클래스에서는 public 필드가 아닌 접근자 메서드를 사용하라 #16

@lain1nya

Description

@lain1nya

Chapter : 4. 클래스와 인터페이스

Item : 16. public 클래스에서는 public 필드가 아닌 접근자 메서드를 사용하라

Assignee : Lainlnya


🍑 서론

🍑 본론

캡슐화의 이점을 제공하지 못하는 예시

  1. API를 수정하지 않고는 내부 표현을 변경할 수 없다.
  2. 불변식을 보장할 수 없으며, 외부에서 필드에 접근할 때 부수 작업을 수행할 수도 없다.
    class Point {
        public double x;
        public double y;
    }

캡슐화된 예시

✅ 패키지 바깥에서 접근할 수 있는 클래스라면 접근자를 제공하면, 유연성을 높일 수 있다.

    class Point {
        private double x;
        private double y;

        public Point(double x, double y) {
            this.x = x;
            this.y = y;
        }

        public double getX() { return x; }
        public double getY() { return y; }

        public void setX(double x) { this.x = x; }
        public void setY(double y) { this.y = y; }

    }

package-private 클래스 혹은 private 중첩 클래스라면 데이터 필드를 노출하는 것이 문제가 되지 않는다.

✅ package-private 클래스
com.example.myapp 패키지 외부에서는 접근할 수 없으므로 데이터 필드를 노출해도 큰 문제가 없다.

package com.example.myapp;

// 패키지 내부에서만 접근 가능한 클래스
class PackagePrivateClass {
    int data; // 데이터 필드를 노출
}

✅ private 중첩 클래스
내부에서만 사용할 수 있고, private 클래스는 외부에서 접근할 수 없다. 따라서 데이터 필드를 노출하는 것이 문제가 되지 않는다.

public class OuterClass {
    // 외부에서 접근할 수 있는 public 메서드
    public void doSomething() {
        NestedPrivateClass nested = new NestedPrivateClass();
        nested.setData(42); // 중첩 클래스의 데이터 필드에 접근
        System.out.println(nested.getData()); // 중첩 클래스의 데이터 필드 출력
    }

    // private 중첩 클래스
    private static class NestedPrivateClass {
        private int data; // 데이터 필드를 노출

        public int getData() {
            return data;
        }

        public void setData(int data) {
            this.data = data;
        }
    }
}

java에서 public 클래스 필드를 직접 노출하지 말라는 규칙을 어긴 사례

Dimension의 경우 내부를 노출해서 아직까지 성능 문제를 해결하지 못했다.

public class Dimension extends Dimension2D implements java.io.Serializable {

    /**
     * The width dimension; negative values can be used.
     *
     * @serial
     * @see #getSize
     * @see #setSize
     * @since 1.0
     */
    public int width;

    /**
     * The height dimension; negative values can be used.
     *
     * @serial
     * @see #getSize
     * @see #setSize
     * @since 1.0
     */
    public int height;
        public double getWidth() {
        return width;
    }

    /**
     * {@inheritDoc}
     * @since 1.2
     */
    public double getHeight() {
        return height;
    }

    /**
     * Sets the size of this {@code Dimension} object to
     * the specified width and height in double precision.
     * Note that if {@code width} or {@code height}
     * are larger than {@code Integer.MAX_VALUE}, they will
     * be reset to {@code Integer.MAX_VALUE}.
     *
     * @param width  the new width for the {@code Dimension} object
     * @param height the new height for the {@code Dimension} object
     * @since 1.2
     */
    public void setSize(double width, double height) {
        this.width = (int) Math.ceil(width);
        this.height = (int) Math.ceil(height);
    }
}

public 클래스의 필드가 불변이라면

  1. 불변식을 보장하기 때문에 직접 노출할 때의 단점이 줄어든다.
  2. API를 변경하지 않고는 표현 방식을 바꿀 수 없고, 필드를 읽을 때 부수 작업을 수행할 수 없는 것은 여전히 단점이다.
    public final class Time {
        private static final int HOURS_PER_DAY = 24;
        private static final int MINUTES_PER_HOUR = 60;

        public final int hour;
        public final int minute;
    }

🍑 결론

✅ public 클래스는 절대 가변 필드를 직접 노출해서는 안된다. => 불변 필드면 노출해도 덜 위험하지만 권장X
✅ package-private 클래스나 private 중첩 클래스에서는 종종 필드를 노출하는 것이 나을 때도 있다.


Referenced by

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions