[java] Java에서 객체와 같은 구조

객체와 같은 구조체를 만드는 Java 방식과 완전히 반대입니까?

class SomeData1 {
    public int x;
    public int y;
}

접근 자와 뮤 테이터가 더 많은 클래스가 Java와 비슷하다는 것을 알 수 있습니다.

class SomeData2 {
    int getX();
    void setX(int x);

    int getY();
    void setY(int y);

    private int x;
    private int y;
}

첫 번째 예제의 클래스는 표기법이 편리합니다.

// a function in a class
public int f(SomeData1 d) {
    return (3 * d.x) / d.y;
}

이것은 편리하지 않습니다.

// a function in a class
public int f(SomeData2 d) {
    return (3 * d.getX()) / d.getY();
}



답변

이것은 일반적으로 논의되는 주제입니다. 개체에서 공용 필드를 만드는 단점은 설정된 값을 제어 할 수 없다는 것입니다. 같은 코드를 사용하는 프로그래머가 많은 그룹 프로젝트에서는 부작용을 피하는 것이 중요합니다. 또한 때로는 필드의 객체 사본을 반환하거나 어떻게 든 변환하는 것이 좋습니다. 테스트에서 이러한 메소드를 조롱 할 수 있습니다. 새 클래스를 만들면 가능한 모든 동작이 표시되지 않을 수 있습니다. 방어적인 프로그래밍과 같습니다. 언젠가 getter와 setter가 도움이 될 수 있으며이를 작성 / 사용하는 데 많은 비용이 들지 않습니다. 그래서 그들은 때때로 유용합니다.

실제로 대부분의 필드에는 간단한 getter 및 setter가 있습니다. 가능한 해결책은 다음과 같습니다.

public property String foo;   
a->Foo = b->Foo;

업데이트 : 속성 지원이 Java 7 또는 그 이후에 추가 될 가능성은 거의 없습니다. Groovy, Scala 등과 같은 다른 JVM 언어는 현재이 기능을 지원합니다. -알렉스 밀러


답변

Java가 “struct”를 지원하는 경우 (동작이 없을 때) 클래스가 기본적으로 “구조”인 경우 공용 인스턴스 변수를 사용하는 것이 적절하다고 말하는 많은 Java 사용자가 Sun Java 코딩 지침에 익숙하지 않은 것 같습니다.

사람들은 게터와 세터가 마치 마치 자바의 중심에있는 것처럼 자바 방식이라고 생각하는 경향이 있습니다. 그렇지 않습니다. 적절한 상황에서 퍼블릭 인스턴스 변수를 사용하여 Sun Java 코딩 지침을 따르면 실제로 불필요한 게터와 세터로 코드를 어지럽히는 것보다 더 나은 코드를 작성하는 것입니다.

1999 년 Java 코드 규칙은 변경되지 않았습니다.

10.1 인스턴스 및 클래스 변수에 대한 액세스 제공

정당한 이유없이 인스턴스 나 클래스 변수를 공개하지 마십시오. 종종, 메소드 변수의 부작용으로 발생하는 인스턴스 변수를 명시 적으로 설정하거나 가져올 필요가 없습니다.

적절한 퍼블릭 인스턴스 변수의 한 예는 클래스가 기본적으로 데이터 구조이며 동작이없는 경우입니다. 즉, 클래스 대신 구조체를 사용했을 경우 (Java가 구조체를 지원하는 경우) 클래스의 인스턴스 변수를 public으로 만드는 것이 적절합니다 .

http://www.oracle.com/technetwork/java/javase/documentation/codeconventions-137265.html#177

http://en.wikipedia.org/wiki/Plain_old_data_structure

http://docs.oracle.com/javase/1.3/docs/guide/collections/designfaq.html#28


답변

상식을 실제로 사용하십시오. 다음과 같은 것이 있다면 :

public class ScreenCoord2D{
    public int x;
    public int y;
}

그런 다음 게터와 세터로 감싸는 데 약간의 포인트가 있습니다. 다른 방법으로 x, y 좌표를 전체 픽셀로 저장하지 않습니다. 게터와 세터는 속도를 늦출뿐입니다.

반면에,

public class BankAccount{
    public int balance;
}

나중에 어느 시점에서 잔액이 계산되는 방식을 변경하고 싶을 수도 있습니다. 이것은 실제로 게터와 세터를 사용해야합니다.

규칙을 구부릴 수있는시기를 알 수 있도록 유용한 방법을 적용하는 이유 를 아는 것이 항상 바람직합니다 .


답변

변경 가능성 문제를 해결하기 위해 x와 y를 final로 선언 할 수 있습니다. 예를 들면 다음과 같습니다.

class Data {
  public final int x;
  public final int y;
  public Data( int x, int y){
    this.x = x;
    this.y = y;
  }
}

이러한 필드에 쓰려고 시도하는 호출 코드는 “필드 x가 최종 선언되어 할당 할 수 없습니다”라는 컴파일 시간 오류를 발생시킵니다.

그런 다음 클라이언트 코드는 게시물에 설명 된 ‘짧은’편의를 가질 수 있습니다.

public class DataTest {
    public DataTest() {
        Data data1 = new Data(1, 5);
        Data data2 = new Data(2, 4);
        System.out.println(f(data1));
        System.out.println(f(data2));
    }

    public int f(Data d) {
        return (3 * d.x) / d.y;
    }

    public static void main(String[] args) {
        DataTest dataTest = new DataTest();
    }
}


답변

public필드를 사용하지 마십시오

public클래스의 내부 동작을 실제로 래핑하려는 경우 필드를 사용하지 마십시오 . 가지고 java.io.BufferedReader예를 들어. 다음과 같은 필드가 있습니다.

private boolean skipLF = false; // If the next character is a line feed, skip it

skipLF모든 읽기 방법으로 읽고 씁니다. 별도의 스레드에서 실행되는 외부 클래스 skipLF가 읽기 도중에 상태를 악의적으로 수정 한 경우 어떻게됩니까? BufferedReader확실히 haywire 갈 것입니다.

public필드를 사용하십시오

Point수업을 예로 들어 보겠습니다.

class Point {
    private double x;
    private double y;

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

    public double getX() {
        return this.x;
    }

    public double getY() {
        return this.y;
    }

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

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

이로 인해 두 점 사이의 거리를 계산하는 것이 매우 고통 스럽습니다.

Point a = new Point(5.0, 4.0);
Point b = new Point(4.0, 9.0);
double distance = Math.sqrt(Math.pow(b.getX() - a.getX(), 2) + Math.pow(b.getY() - a.getY(), 2));

이 클래스에는 일반 게터 및 세터 이외의 동작이 없습니다. 클래스는 단지 데이터 구조를 나타내며,이없는, 때 공공 필드를 사용하는 것이 허용 하고 행동을 (얇은 getter와 setter가되어주지 않습니다 적이 없습니다 여기에 행동으로 간주). 이 방법으로 더 잘 작성할 수 있습니다.

class Point {
    public double x;
    public double y;

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

Point a = new Point(5.0, 4.0);
Point b = new Point(4.0, 9.0);
double distance = Math.sqrt(Math.pow(b.x - a.x, 2) + Math.pow(b.y - a.y, 2));

깨끗한!

그러나 수업에 행동이 없어야 할뿐만 아니라 미래에도 행동을 취할 이유 가 없어야 합니다.


(이 답변 이 정확히 설명하는 내용입니다. “Java 프로그래밍 언어에 대한 코드 규칙 : 10. 프로그래밍 실습” 을 인용 하십시오 .

적절한 퍼블릭 인스턴스 변수의 한 예는 클래스가 기본적으로 데이터 구조이며 동작이없는 경우입니다. 즉, struct클래스 대신 (Java가 지원되는 경우 struct)을 사용했다면 클래스의 인스턴스 변수를 public으로 만드는 것이 적절합니다.

따라서 공식 문서 도이 관행을 받아들입니다.)


또한 위 Point클래스의 멤버를 변경할 수 없다고 확신하는 경우 final키워드를 추가 하여 적용 할 수 있습니다 .

public final double x;
public final double y;


답변

그런데 예제로 제공하는 구조는 이미 Java 기본 클래스 라이브러리에 있습니다 java.awt.Point. 공개 필드로 x와 y가 있으므로 직접 확인하십시오 .

당신이하고있는 일을 알고 있고 팀의 다른 사람들이 그것에 대해 알고 있다면, 공공 장소를 갖는 것은 괜찮습니다. 그러나 스택 할당 구조체 인 것처럼 객체를 사용하는 개발자와 관련된 버그처럼 두통을 일으킬 수 있기 때문에 의존해서는 안됩니다 (자바 객체는 항상 사본이 아닌 참조로 메서드에 전송 됨).


답변

Re : aku, izb, John Topley …

가변성 문제를 조심하십시오 …

게터 / 세터를 생략하는 것이 합리적으로 보일 수 있습니다. 어떤 경우에는 실제로 괜찮을 수도 있습니다. 여기에 제시된 제안 된 패턴의 실제 문제는 변경 가능성입니다.

문제는 최종이 아닌 공개 필드를 포함하는 객체 참조를 전달하는 것입니다. 해당 참조가있는 다른 항목은 해당 필드를 자유롭게 수정할 수 있습니다. 더 이상 해당 객체의 상태를 제어 할 수 없습니다. (문자열이 변경 가능하면 어떻게 될지 생각하십시오.)

해당 객체가 다른 객체의 내부 상태에서 중요한 부분이되면 나빠집니다. 내부 구현을 방금 노출했습니다. 이를 방지하려면 대신 오브젝트 사본을 리턴해야합니다. 이 방법은 효과가 있지만 수많은 일회용 복사본으로 인해 엄청난 GC 압력이 발생할 수 있습니다.

공개 필드가있는 경우 클래스를 읽기 전용으로 설정하십시오. 필드를 생성자에 매개 변수로 추가하고 필드를 final로 표시하십시오. 그렇지 않으면 내부 상태가 노출되지 않도록하고 반환 값에 대해 새 인스턴스를 생성해야하는 경우 지나치게 호출되지 않도록하십시오.

Joshua Bloch의 ” 유효한 Java “-항목 # 13 : 선호 불변성 참조.

추신 : 요즘 모든 JVM은 가능한 경우 getMethod를 최적화하여 단일 필드 읽기 명령을 생성합니다.