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();
}
Java가 "Struct"(동작이 없는 경우)를 지원하는 경우 클래스가 본질적으로 "Struct"일 때 퍼블릭 인스턴스 변수를 사용하는 것이 매우 적절하다는 Sun Java Coding Guidelines에 대해 많은 Java 사용자가 잘 모르는 것으로 보입니다.
사람들은 게터나 세터가 자바 방식이라고 생각하는 경향이 있다. 마치 그들이 자바 중심인 것처럼 말이다.그렇지 않아요.Sun Java Coding Guidelines에 따라 적절한 상황에서 퍼블릭인스턴스 변수를 사용하면 불필요한 getter와 setter를 사용하여 코드를 쉽게 작성할 수 있습니다.
1999년 이후 Java Code Conventions는 변경되지 않았습니다.
10.1 인스턴스 및 클래스 변수에 대한 접근 제공
인스턴스 또는 클래스 변수를 정당한 이유 없이 공개하지 마십시오.인스턴스 변수를 명시적으로 설정하거나 가져올 필요가 없는 경우가 많습니다. 메서드 호출의 부작용으로 발생하는 경우가 많습니다.
적절한 퍼블릭인스턴스 변수의 예로서 클래스가 본질적으로 동작하지 않는 데이터 구조인 경우를 들 수 있습니다.즉, 클래스 대신 구조체를 사용하는 경우(Java가 구조체를 지원하는 경우) 클래스의 인스턴스 변수를 공개하는 것이 적절합니다..
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;
}
나중에 잔액이 계산되는 방법을 변경할 수 있습니다.이것은 정말 getter와 setter를 사용해야 한다.
규칙을 어겨도 괜찮은지 알 수 있도록 항상 모범 사례를 적용하는 이유를 아는 것이 좋습니다.
이것은 흔히 논의되는 주제입니다.오브젝트에 퍼블릭필드를 작성할 때의 단점은 설정된 값을 제어할 수 없다는 것입니다.같은 코드를 사용하는 프로그래머가 많은 그룹 프로젝트에서는 부작용을 피하는 것이 중요합니다.또한 필드의 오브젝트 복사본을 반환하거나 어떻게든 변환하는 것이 좋을 수 있습니다.시험에서는 그런 방법을 조롱할 수 있다.새 클래스를 만들면 가능한 작업 중 일부가 표시되지 않을 수 있습니다.이것은 방어적인 프로그래밍과 같습니다. 언젠가 게터나 세터가 도움이 될 수 있고, 그것들을 만들고 사용하는 데 많은 비용이 들지 않습니다.그래서 그것들은 때때로 유용하다.
실제로 대부분의 필드에는 단순한 게터와 세터가 있습니다.생각할 수 있는 솔루션은 다음과 같습니다.
public property String foo;
a->Foo = b->Foo;
업데이트: Java 7에서 자산 지원이 추가될 가능성은 매우 낮습니다.Groovy, Scala 등 다른 JVM 언어도 현재 이 기능을 지원하고 있습니다.- Alex Miller
가변성에 관한 문제를 해결하려면 x와 y를 최종으로 선언할 수 있습니다.예를 들어 다음과 같습니다.
class Data {
public final int x;
public final int y;
public Data( int x, int y){
this.x = x;
this.y = y;
}
}
이러한 필드에 쓰려고 하는 호출 코드는 "field x is declared final; cannot be assigned"라는 컴파일 시간 오류를 받습니다.
그 후, 클라이언트 코드는, 투고시에 기재되어 있던 「단기」의 편리성을 얻을 수 있습니다.
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클래스 내부 동작을 랩하는 경우 필드를 선택합니다.예를 들어보자.이 필드에는 다음 필드가 있습니다.
private boolean skipLF = false; // If the next character is a line feed, skip it
skipLF모든 읽기 방법으로 읽고 씁니다. 클래스가 가 악의적으로 skipLF책는읽 안안? BufferedReader분명히 문제가 생길 거야
사용하세요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));
클래스에는 플레인게터 및 세터 이외의 동작은 없습니다.클래스가 데이터 구조만 나타내며 동작은 존재하지 않으며 동작은 발생하지 않을 경우 퍼블릭필드를 사용할 수 있습니다(신게터 및 세터는 여기서 동작으로 간주되지 않습니다).이렇게 하면 더 잘 표현할 수 있습니다.
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(가 ""를 하는 경우)struct클래스 인스턴스 변수를 공개하는 것이 적절합니다.
따라서 공식 문서에서도 이 관행을 인정하고 있습니다.)
알고 ,Point class를 할 수 .그러면 추가가 가능합니다.final키워드를 지정합니다.
public final double x;
public final double y;
덧붙여서, 당신이 예로 들고 있는 구조는 자바 기본 클래스 라이브러리에 이미 존재합니다.java.awt.Pointx와 y가 공개필드로 되어 있으니 직접 확인해 보세요.
자신이 무엇을 하고 있는지 알고 있고, 팀의 다른 사람들도 알고 있다면, 공공장소를 가지고 있어도 괜찮습니다.그러나 개발자가 개체를 스택 할당 구조처럼 사용하는 것과 관련된 버그에서와 같은 문제를 일으킬 수 있으므로 이 문제에 의존해서는 안 됩니다(Java 개체는 항상 복사본이 아닌 참조로 메서드에 전송됩니다).
아쿠, 이즈브, 존 토플리...
가변성 문제에 주의하세요...
getter/setter를 생략하는 것이 현명해 보일 수 있습니다.사실 어떤 경우에는 괜찮을 수도 있어요.여기에 제시된 패턴의 진짜 문제는 가변성입니다.
문제는 최종적이지 않은 공개 필드가 포함된 개체 참조를 전달한 경우입니다.이 참조가 있는 다른 필드는 자유롭게 변경할 수 있습니다.더 이상 해당 개체의 상태를 제어할 수 없습니다.(Strings가 변이 가능한 경우 어떤 일이 일어날지 생각해 보십시오.
그 오브젝트가 다른 오브젝트의 내부 상태의 중요한 일부일 경우, 내부 구현이 노출되었을 뿐입니다.이를 방지하려면 개체의 복사본을 대신 반환해야 합니다.이 방법은 작동하지만, 1회용 복사본이 대량으로 생성되어 엄청난 GC 압력이 발생할 수 있습니다.
공용 필드가 있는 경우 클래스를 읽기 전용으로 설정하는 것이 좋습니다.필드를 생성자에 매개 변수로 추가하고 필드를 최종으로 표시합니다.그렇지 않으면 내부 상태를 노출하지 않도록 하고 반환 값에 대해 새 인스턴스를 구성해야 할 경우 과도하게 호출되지 않도록 하십시오.
Joshua Bloch의 "유효한 자바"를 참조하십시오.-- 항목 #13: 불변성을 선호합니다.
PS: 또한 최근의 모든 JVM은 가능하면 getMethod를 최적화하여 하나의 필드 읽기 명령만 얻을 수 있습니다.
getters와 setters는 의미상 의미없는 교묘함으로 코드를 엉망으로 만들고, 다른 언어들은 관례에 기초한 데이터 숨기기나 책임 분할(예: python)으로 잘 되는 것처럼 보인다는 이론으로 몇 가지 프로젝트에서 이것을 시도했다.
위에서 설명한 바와 같이 2가지 문제가 발생하지만 실제로 해결할 수 있는 문제는 아닙니다.
- Java 월드에 있는 거의 모든 자동화 툴은 getter/setter 규칙에 의존합니다.jsp 태그, 스프링 구성, 이클립스 툴 등에 대해서도 마찬가지입니다.툴이 기대하는 것과 싸우는 것은 스프링빈을 시작하는 비표준적인 방법을 찾기 위해 구글을 통해 긴 세션의 레시피입니다.정말 그럴 가치도 없어요
- 수백 개의 공용 변수를 사용하여 우아하게 코드화된 응용 프로그램을 사용하면 적어도 한 가지 불충분한 상황을 발견할 수 있습니다. 즉, 변수가 설정되었을 때 반드시 불변성이 필요하거나, 변수가 설정되었을 때 이벤트가 발생하거나, 개체 상태가 다음과 같이 설정되기 때문에 변수 변경에 대해 예외를 발생시키고 싶은 경우입니다.경첩이 불쾌하다.그 후 변수가 직접 참조되는 모든 곳에서 특별한 방법을 사용하여 코드를 혼란스럽게 하거나 어플리케이션의 1000개 변수 중 3개에 대한 특별한 액세스 형식을 사용하는 것 중 만족할 수 없는 선택을 해야 합니다.
이는 완전히 자급자족한 개인 프로젝트에서 작업하는 최상의 시나리오입니다.이 모든 것을 공개 접근 가능한 라이브러리로 내보내면 이러한 문제는 더욱 커질 것입니다.
Java는 매우 장황하고, 이것은 유혹적인 것입니다.하지 마세요.
Java 방식이 OO 방식이라면, 네, 공개 필드가 있는 클래스를 만드는 것은 개체가 자신의 내부 상태를 관리해야 한다는 정보 은닉에 관한 원칙을 위반합니다.(따라서 단순히 전문용어를 말하는 것이 아니라, 정보 숨김의 장점은 클래스의 내부 작업이 인터페이스 뒤에 숨겨져 있다는 것입니다.예를 들어 구조 클래스가 필드 중 하나를 저장하는 메커니즘을 변경하고 싶다고 가정하면 클래스를 사용하는 모든 클래스를 다시 변경해야 할 수도 있습니다.
또한 JavaBean 명명 준수 클래스를 지원할 수 없습니다. 식 언어를 사용하여 작성된 JavaServer 페이지에서 클래스를 사용하기로 결정하면 문제가 발생합니다.
Java World 기사 "Why Getter and Setter Methods is Evil" (게터 및 셋터 메서드가 사악한 이유) 또한 접근자 및 뮤테이터 메서드를 구현하지 않는 시기에 대해 생각해 보는 데 관심이 있을 수 있습니다.
만약 당신이 작은 솔루션을 쓰고 있고, 관련된 코드의 양을 최소화하고 싶다면, 자바 방식은 올바른 방법이 아닐 수 있습니다. 항상 당신과 당신이 해결하려는 문제에 달려 있다고 생각합니다.
작성자가 오브젝트가 아닌 구조체(또는 데이터 셔틀)임을 알고 있다면 이러한 유형의 코드에 아무런 문제가 없습니다.많은 자바 개발자들은 (java.lang의 하위 클래스가 아닌) 잘 형성된 오브젝트의 차이를 구별하지 못한다.오브젝트, 그러나 특정 도메인의 실제 오브젝트) 및 파인애플.에르고, 그들은 물건이 필요할 때 구조를 쓰게 되고 그 반대도 하게 돼.
아주 아주 오래된 질문이지만, 한 가지 더 짧게 기고하겠습니다.Java 8은 람다 표현식과 메서드 참조를 도입했습니다.람다 식은 단순한 메서드 참조일 수 있으며 "참" 본문을 선언할 수 없습니다.그러나 필드를 메서드 참조로 "변환"할 수는 없습니다.따라서
stream.mapToInt(SomeData1::x)
합법은 아니지만
stream.mapToInt(SomeData2::getX)
이에요.
퍼블릭 필드 액세스를 사용할 때의 문제는 공장 출하시 방식이 아닌 신규 방식을 사용하는 것과 같습니다.나중에 생각이 바뀌면 기존의 발신자가 모두 고장납니다.따라서 API의 진화적 관점에서 보면, 일반적으로는 참고 getters/setters를 사용하는 것이 좋습니다.
다른 방법으로는 내부 데이터 구조로 사용되는 내부 정적 클래스 등 클래스에 대한 액세스를 강력하게 제어하는 방법이 있습니다.이 경우 필드 액세스를 사용하는 것이 훨씬 명확할 수 있습니다.
덧붙여서, e-bartek의 주장대로라면, IMO가 Java 7에 추가될 가능성은 매우 낮습니다.
코드를 단순화하기 위해 프라이빗 내부 클래스를 만들 때 이 패턴을 자주 사용하지만 퍼블릭 API에서 이러한 개체를 노출하는 것은 권장하지 않습니다.일반적으로 퍼블릭 API에서 객체를 불변하게 하는 빈도가 높을수록 더 좋고, '구조와 같은' 객체를 불변하게 구성하는 것은 불가능합니다.
한편, 이 오브젝트를 프라이빗 내부 클래스로 쓰고 있어도 오브젝트를 초기화하기 위한 코드를 단순화하는 컨스트럭터를 제공할 수 있습니다.사용할 수 있는 오브젝트를 얻기 위해 3줄의 코드를 가지고 있어야 하는 것은 매우 번거로운 일입니다.
만약 당신이 그것이 항상 단순한 구조일 것이고 그것에 행동을 붙이고 싶어하지 않을 것이라는 것을 안다면, 나는 해가 되지 않을 것이다.
이것은 객체 지향 설계에 관한 질문이지 자바 언어가 아닙니다.일반적으로 클래스 내에서 데이터 유형을 숨기고 클래스 API의 일부인 메서드만 노출하는 것이 좋습니다.내부 데이터 유형을 노출하면 나중에 변경할 수 없습니다.숨길 경우 메서드의 반환 및 인수 유형만 사용자에게 필요합니다.
여기서 5명의 이름과 나이를 입력하고 선택 정렬(나이와이즈)을 하는 프로그램을 만듭니다.구조(C 프로그래밍 언어 등)와 메인 클래스를 사용하여 전체 작업을 수행했습니다.여기 아래에 코드를...
import java.io.*;
class NameList {
String name;
int age;
}
class StructNameAge {
public static void main(String [] args) throws IOException {
NameList nl[]=new NameList[5]; // Create new radix of the structure NameList into 'nl' object
NameList temp=new NameList(); // Create a temporary object of the structure
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
/* Enter data into each radix of 'nl' object */
for(int i=0; i<5; i++) {
nl[i]=new NameList(); // Assign the structure into each radix
System.out.print("Name: ");
nl[i].name=br.readLine();
System.out.print("Age: ");
nl[i].age=Integer.parseInt(br.readLine());
System.out.println();
}
/* Perform the sort (Selection Sort Method) */
for(int i=0; i<4; i++) {
for(int j=i+1; j<5; j++) {
if(nl[i].age>nl[j].age) {
temp=nl[i];
nl[i]=nl[j];
nl[j]=temp;
}
}
}
/* Print each radix stored in 'nl' object */
for(int i=0; i<5; i++)
System.out.println(nl[i].name+" ("+nl[i].age+")");
}
}
위의 코드는 에러 프리 및 테스트 완료입니다.복사하여 IDE에 붙여넣기만 하면 됩니다.그거 알아요?:)
Java에서 메서드 없이 공용 필드를 사용하여 간단한 클래스를 만들 수 있지만 여전히 클래스이며 클래스처럼 구문적으로 메모리 할당 측면에서 처리됩니다.자바에서 구조를 진정으로 재현할 수 있는 방법은 없습니다.
메서드에서 여러 값을 반환해야 할 때 이러한 클래스를 사용할 수 있습니다.물론 이러한 물체는 수명이 짧고 시야가 매우 제한적이기 때문에 괜찮습니다.
대부분의 것과 마찬가지로, 일반적인 규칙과 특정한 상황이 있습니다.특정 객체의 사용 방법을 알기 위해 캡처된 폐쇄형 애플리케이션을 실행하는 경우 가시성 및/또는 효율성을 높이기 위해 더 많은 자유를 행사할 수 있습니다.만약 당신이 통제할 수 없는 다른 사람들에 의해 공개적으로 사용될 클래스를 개발하고 있다면, getter/setter 모델에 기대세요.모든 것이 그렇듯이, 단지 상식을 사용하세요.공개와 초기 라운드를 한 후 나중에 getter/setter로 변경하는 것이 좋습니다.
애스펙트 지향 프로그래밍을 사용하면 할당이나 페치를 트랩하여 가로채기 논리를 붙일 수 있습니다.이것이 문제를 해결하는 올바른 방법입니다.(공용인지 보호인지 패키지 보호인지에 대한 문제는 직교입니다).
따라서 먼저 적절한 접근 수식자를 가진 인터셉트되지 않은 필드로 시작합니다.프로그램 요건이 증가함에 따라 검증, 반환되는 오브젝트 복사 등을 위한 논리를 첨부합니다.
getter/setter의 철학은 필요하지 않은 다수의 단순한 사례에 비용을 부과합니다.
애스펙트 스타일이 더 깨끗한지 아닌지는 어느 정도 질적이다.클래스의 변수만 보고 논리를 따로 보는 것은 쉬울 것입니다.실제로 Aspect 지향 프로그래밍의 존재 이유는 많은 우려 사항이 크로스 컷되어 클래스 본문에 그것들을 구분하는 것 자체가 이상적이지 않다는 것입니다(로그는 예를 들어 로그하고 싶은 경우 Java는 getters를 모두 작성하여 동기화시키기를 원하지만 Aspect J는 한 줄의 라이너를 허용합니다).
IDE의 문제는 레드헤어링.타이핑이 아니라 get/set에서 발생하는 읽기 및 시각적 오염입니다.
주석은 얼핏 보기엔 애스펙트 지향 프로그래밍과 비슷하지만 애스펙트J의 간결한 와일드 카드와 같은 포인트 컷 사양과 달리 주석을 연결하여 포인트 컷을 완전히 열거해야 합니다.
Aspect J에 대한 인식이 너무 빨리 역동적인 언어에 안주하는 것을 막았으면 좋겠다.
언급URL : https://stackoverflow.com/questions/36701/struct-like-objects-in-java
'programing' 카테고리의 다른 글
| _t(언더스코어-t) 뒤에 이어지는 유형은 무엇을 나타냅니까? (0) | 2022.07.29 |
|---|---|
| Java Map의 각 엔트리에 대해 효율적으로 반복하려면 어떻게 해야 합니까? (0) | 2022.07.29 |
| Vuex 알 수 없는 작업 유형...동작이 로딩되지 않음 (0) | 2022.07.29 |
| 페이지를 갱신할 때 Vuex 및 VueRouter에서 글로벌 상태가 손실되지 않도록 합니다. (0) | 2022.07.28 |
| Java enum - 이름 대신 toString을 사용하는 이유 (0) | 2022.07.28 |