문제

내 코드,나를 만드는 개체의 컬렉션에서 액세스할 수 있는 다양한 스레드에서는 패션을 만 안전 경우 객체를 변경할 수 없습니다.하려고 할 때에 삽입하는 새로운 개체로 수집,저는 테스트를 참조하는 경우는 변경할 수 없(하지 않을 경우,I'll throw 예외).

하나는 일은 내가 할 수 있는가를 확인하는 몇 가지 잘 알려진 변경할 수 없는 형태:

private static final Set<Class> knownImmutables = new HashSet<Class>(Arrays.asList(
        String.class, Byte.class, Short.class, Integer.class, Long.class,
        Float.class, Double.class, Boolean.class, BigInteger.class, BigDecimal.class
));

...

public static boolean isImmutable(Object o) {
    return knownImmutables.contains(o.getClass());
}

이는 실제로 저의 90%를 방법이지만,때로는 내용을 만들려고 변경 불가능한 단순한 형태의 자체:

public class ImmutableRectangle {
    private final int width;
    private final int height;
    public ImmutableRectangle(int width, int height) {
        this.width = width;
        this.height = height;
    }
    public int getWidth() { return width; }
    public int getHeight() { return height; }
}

는 몇 가지 방법이 있는(아마도 사용을 반영)할 수 있는 안정적으로 검출하는지 여부를 클래스를 변경할 수 없는?틀린 확실성(생각하고 그것의 불변이지 않은 경우)은 허용되지 않지만 틀린 네거티브(생각하고 그것은 변경할 수없는 경우)니다.

편집을 추가합니다: 감사에 대한 통찰력과 도움되는 답변이 있습니다.로부분의 답변이 지적,내가 소홀히 정의하는 나의 보안을 목표입니다.위협 여기에는 우둔 개발-이것은 한 조각의 프레임워크는 코드에 의해 사용됩니다 많은 사람들은 알고 다음에 대해 아무것도 스레딩되지 않습을 읽는 설명서를 참조하십시오.저는 필요하지 않습에 대한 방어 악의적인 개발자--을 정도로 똑똑하다면 문자열 변경 또는 다른 것이 헛소리 또한 똑똑히 알고 안전하지 않습니다.정적 분석의 코드 옵션,그래서 그것은 자동,하지만 코드를 검토할 수 없습 계산지 않을 수도 있기 때문에 모든 검토는 스레딩 정통한 검토합니다.

도움이 되었습니까?

해결책

클래스가 불변인지 여부를 감지 할 수있는 신뢰할 수있는 방법은 없습니다. 클래스의 속성이 변경 될 수있는 방법이 너무 많아서 반사를 통해 모든 것을 감지 할 수 없기 때문입니다.

이것에 가까워지는 유일한 방법은 다음과 같습니다.

  • 불변의 유형의 최종 속성 만 허용합니다 (원시 유형 및 클래스는 불변 할 수 없습니다),
  • 클래스가 최종 자체가되어야합니다
  • 그들이 당신이 제공하는 기본 클래스에서 상속해야합니다 (불변이 될 수 있음)

그런 다음 가지고있는 객체가 불변 인 경우 다음 코드로 확인할 수 있습니다.

static boolean isImmutable(Object obj) {
    Class<?> objClass = obj.getClass();

    // Class of the object must be a direct child class of the required class
    Class<?> superClass = objClass.getSuperclass();
    if (!Immutable.class.equals(superClass)) {
        return false;
    }

    // Class must be final
    if (!Modifier.isFinal(objClass.getModifiers())) {
        return false;
    }

    // Check all fields defined in the class for type and if they are final
    Field[] objFields = objClass.getDeclaredFields();
    for (int i = 0; i < objFields.length; i++) {
        if (!Modifier.isFinal(objFields[i].getModifiers())
                || !isValidFieldType(objFields[i].getType())) {
            return false;
        }
    }

    // Lets hope we didn't forget something
    return true;
}

static boolean isValidFieldType(Class<?> type) {
    // Check for all allowed property types...
    return type.isPrimitive() || String.class.equals(type);
}

업데이트: 주석에서 제안한 바와 같이, 특정 클래스를 확인하는 대신 슈퍼 클래스에서 재발하도록 확장 될 수 있습니다. 또한 isvalidfieldtype 방법에서 isimmutable을 재귀 적으로 사용하는 것이 제안되었습니다. 이것은 아마도 효과가있을 수 있으며 약간의 테스트를 수행했습니다. 그러나 이것은 사소한 것이 아닙니다. 문자열이 이미이 테스트에 실패하기 때문에 isimmutable에 대한 호출로 모든 필드 유형을 확인할 수는 없습니다 (필드 필드 hash 최종적이지 않습니다!). 또한 당신은 쉽게 끝없는 재귀를 겪고 있습니다. stackoverflowerrors ;) 다른 문제는 제네릭으로 인해 발생할 수 있으며, 여기서 불변성을 확인해야합니다.

나는 어떤 일을하면서, 이러한 잠재적 문제는 어떻게 든 해결 될 수 있다고 생각합니다. 그러나, 당신은 그것이 실제로 그만한 가치가 있는지 먼저 스스로에게 물어봐야합니다 (또한 성능 현명한).

다른 팁

사용 불변 주석 실제로 Java 동시성. 도구 FindBugs 그런 다음 변이 가능하지만 그렇지 않은 클래스를 감지하는 데 도움이 될 수 있습니다.

나의 회사에 우리는 정의된 라는 특성 @Immutable.선택하면 첨부는 클래스에,그것은 의미를 약속하신 변경할 수 없습니다.

그것은 작품에 대한 문서와에서 당신의 경우 그것은 대로 작동하는 필터입니다.

물론 당신은 여전히 작성자에 따라 유지 그의 말씀에 대해 변경할 수 없지만,때문에 저자는 명시적으로 추가 주석의 합리적인 가정이다.

기본적으로 아니오.

당신은 허용 된 수업의 거대한 흰색 목록을 만들 수 있지만 덜 미친 방법은이 컬렉션이라는 컬렉션에 대한 문서에 글을 쓰는 것입니다. ~ 해야 하다 불변이 되십시오.

편집하다: 다른 사람들은 불변의 주석이 있다고 제안했습니다. 이것은 괜찮지 만 문서도 필요합니다. 그렇지 않으면 사람들은 "내가이 주석을 내 수업에 넣으면 컬렉션에 보관할 수있다"고 생각하고 불변적이고 돌연변이가 많은 수업 모두에 걸릴 것입니다. 사실, 나는 사람들이 그 주석을 생각하는 경우를 대비하여 불변의 주석을 갖는 것에주의를 기울일 것입니다. 만든다 그들의 수업은 불변입니다.

이것은 또 다른 힌트가 될 수 있습니다.

클래스에 세터가 없으면 돌연변이를 할 수 없으며, "원시"유형이거나 자체적으로 변하지 않는 매개 변수를 부여 할 수 있습니다.

또한 방법을 재정의 할 수 없으며 모든 필드는 최종적이고 개인이며

나는 당신을 위해 내일 무언가를 코딩하려고 노력할 것입니다. 그러나 반사를 사용한 Simon의 코드는 꽤 좋아 보입니다.

그 동안 Josh Block의 "Effective Java"책의 사본을 가져 오려면이 주제와 관련된 항목이 있습니다. IS는 확실하지는 않지만, 무의미한 클래스를 감지하는 방법을 말하지는 않지만 좋은 클래스를 만드는 방법을 보여줍니다.

항목은 "호의적 인 불변성"이라고 불립니다.

링크:http://java.sun.com/docs/books/effective/

내 코드에서, 나는 객체가 불변이 아닌 경우에만 안전한 방식으로 다양한 스레드로 액세스 할 객체 모음을 만들고 있습니다.

귀하의 질문에 대한 직접적인 답변은 아니지만 불변의 물체는 자동으로 스레드 안전을 보장하지 않습니다 (슬프게도). 스레드 안전을 위해서는 코드가 부작용이 없어야하며, 이는 훨씬 더 어렵습니다.

이 수업이 있다고 가정합니다.

class Foo {
  final String x;
  final Integer y;
  ...

  public bar() {
    Singleton.getInstance().foolAround();
  }
}

그럼 foolAround() 이 방법에는 일부 비 스레드 안전 작업이 포함되어있어 앱이 날려 버릴 수 있습니다. 실제 참조는 필드 나 노출 된 인터페이스가 아닌 방법 본문에서만 찾을 수 있으므로 반사를 사용하여 테스트 할 수 없습니다.

그 외에는 다른 것들이 정확합니다. 클래스의 모든 선언 된 필드를 스캔 할 수 있습니다. 각각의 모든 분야가 최종적이고 불변의 수업인지 확인할 수 있습니다. 나는 최종 방법이 요구 사항이라고 생각하지 않습니다.

또한 불변성에 대한 종속 필드를 재귀 적으로 점검하는 데주의를 기울이면 다음과 같은 원으로 끝날 수 있습니다.

class A {
  final B b; // might be immutable...
}

class B {
  final A a; // same so here.
}

클래스 A와 B는 완벽하게 불변 (일부 반사 해킹을 통해 사용할 수 있음)이지만 순진한 재귀 코드는 끝없는 루프를 점검 한 다음 B, A, B로 다시 B, ... ... ...

사이클을 분해하는 '보인'맵 또는 모든 부양비가 자신에 따라 불변 할 수 없다면 클래스를 결정하는 정말 영리한 코드를 사용하면이를 해결할 수 있지만 실제로 복잡 할 것입니다 ... 정말 복잡 할 것입니다 ...

고객에게 메타 데이터 (주석)를 추가하고 반사 시간에 반사 시간에 확인하도록 요청할 수 있습니다.

메타 데이터 :

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.CLASS)
public @interface Immutable{ }

클라이언트 코드 :

@Immutable
public class ImmutableRectangle {
    private final int width;
    private final int height;
    public ImmutableRectangle(int width, int height) {
        this.width = width;
        this.height = height;
    }
    public int getWidth() { return width; }
    public int getHeight() { return height; }
}

그런 다음 클래스에 반사를 사용하여 주석이 있는지 확인하십시오 (코드를 붙여 넣지 만 보일러 플레이트를 붙여서 온라인으로 쉽게 찾을 수 있습니다).

모든 권장 사항이 클래스가 최종적이어야하는 이유는 무엇입니까? 리플렉션을 사용하여 각 객체의 클래스를 확인하고 해당 클래스가 불변 (불변의 최종 필드)을 프로그래밍 방식으로 결정할 수 있다면 클래스 자체가 최종적이어야 할 필요가 없습니다.

AOP를 사용할 수 있습니다 @Immutable 주석 jcabi-ASPECTS:

@Immutable
public class Foo {
  private String data;
}
// this line will throw a runtime exception since class Foo
// is actually mutable, despite the annotation
Object object = new Foo();

다른 답변가가 이미 말했듯이, IMHO 객체가 실제로 불변인지 알 수있는 신뢰할 수있는 방법이 없습니다.

추가 할 때 확인하기 위해 "불변"인터페이스를 소개합니다. 이것은 불변의 물체만이 어떤 이유로 든 삽입되어야한다는 힌트로 작동합니다.

interface Immutable {}

class MyImmutable implements Immutable{...}

public void add(Object o) {
  if (!(o instanceof Immutable) && !checkIsImmutableBasePrimitive(o))
    throw new IllegalArgumentException("o is not immutable!");
  ...
}

이 시도:

public static boolean isImmutable(Object object){
    if (object instanceof Number) { // Numbers are immutable
        if (object instanceof AtomicInteger) {
            // AtomicIntegers are mutable
        } else if (object instanceof AtomicLong) {
            // AtomLongs are mutable
        } else {
            return true;
        }
    } else if (object instanceof String) {  // Strings are immutable
        return true;
    } else if (object instanceof Character) {   // Characters are immutable
        return true;
    } else if (object instanceof Class) { // Classes are immutable
        return true;
    }

    Class<?> objClass = object.getClass();

    // Class must be final
    if (!Modifier.isFinal(objClass.getModifiers())) {
            return false;
    }

    // Check all fields defined in the class for type and if they are final
    Field[] objFields = objClass.getDeclaredFields();
    for (int i = 0; i < objFields.length; i++) {
            if (!Modifier.isFinal(objFields[i].getModifiers())
                            || !isImmutable(objFields[i].getType())) {
                    return false;
            }
    }

    // Lets hope we didn't forget something
    return true;
}

내가 아는 한, 100% 정확한 불변의 물체를 식별 할 방법이 없습니다. 그러나 나는 당신을 더 가까이 데려 가기 위해 도서관을 작성했습니다. 클래스의 바이트 코드 분석을 수행하여 불변이 아닌지 여부를 결정하고 런타임에 실행할 수 있습니다. 그것은 엄격한면에 있으므로 화이트리스트를 알려진 불변의 클래스를 허용합니다.

다음에서 확인할 수 있습니다. www.mutabilitydetector.org

응용 프로그램에서 이와 같은 코드를 쓸 수 있습니다.

/*
* Request an analysis of the runtime class, to discover if this
* instance will be immutable or not.
*/
AnalysisResult result = analysisSession.resultFor(dottedClassName);

if (result.isImmutable.equals(IMMUTABLE)) {
    /*
    * rest safe in the knowledge the class is
    * immutable, share across threads with joyful abandon
    */
} else if (result.isImmutable.equals(NOT_IMMUTABLE)) {
    /*
    * be careful here: make defensive copies,
    * don't publish the reference,
    * read Java Concurrency In Practice right away!
    */
}

Apache 2.0 라이센스에 따라 무료 및 오픈 소스입니다.

체크 아웃 Joe-e, Java의 기능 구현.

내장 클래스의 높은 비율에 맞는 것은 예를 들어 비슷한 테스트입니다. 날짜처럼 불변이 아닌 수업의 경우 대부분의 경우 종종 불변으로 취급됩니다.

감사와 존경의 양을 작업 Grundlefleck 있으로 둔 그의 가변성 탐지기,그러나 그것은 생각의 비트입니다.를 작성할 수 있습니다 간단하지만 실질적으로 매우 적절한(즉, 실용적인)감지기는 다음과 같다:

(주의:이것은 사본 의견기: https://stackoverflow.com/a/28111150/773113)

첫째,당신이 될 수 없이 쓰는 방법이 있는지 여부를 결정 등은 변경할 수 없;대신,당신이 쓰는 필요는 불변성 검출기준,기 때문에 그것을 유지하는 어떤 상태에 있습니다.상태 검출기의 것 검출한 불변의 모든 클래스는 그것을 조사하고 있습니다 그래서 지금까지.이뿐만 아니라 성능을 개선하는 데 유용하지만 실제로 필요하기 때문에 클래스가 포함될 수 있습 순환을 참조는 단순한 불변성 검출기로 무한한 재귀.

불변의 클래스에는 네 가능한 값: Unknown, Mutable, Immutable, 고 Calculating.당신은 아마이 있고 싶지도 연결하는 각 클래스는 지금까지 발생하는 불변성 값입니다.물론, Unknown 하지 않는 실제로 구현해야하기 때문에 그것이 수 있는 묵시적의 상태를 모든 클래스에는 아직도.

그래서,당신이 시작할 때 검사하는 클래스와 연결할 Calculating 값을 지도에서,그리고 당신이 완료되면,당신은 대체 CalculatingImmutableMutable.

에 대한 각 클래스에,당신은 단지를 확인하는 필드 구성원,지 않습니다.의 아이디어를 확인 바이트 코드는 오히려 잘못.

첫째,당신 체크인지 여부를 클래스 최종;종국의 클래스에 영향을 미치지 않는 그것의 불변성.대신하는 방법이 기대하는 불변 매개 변수는 먼저의 모든 호출하는 불변성 검출기를 주장하는의 불변성 등의 실제 물체의 것이 전달되었습니다.이 테스트를 생략할 수 있는 경우 매개변수의 유형은 최종 클래스 종국은 좋은 성능을 위해,그러나 엄밀히 말하면 필요하지 않습니다.또한,당신이 더 아래 참조,필드를 입력이 아닌 최종 등이 발생을 선언하는 클래스의하는 것으로 간주되 변경 가능 하지만,여전히,그것의 문제가의 선언이 아닌 클래스의 문제가 아닌 최종 변경할 수 없는 멤버 클래스입니다.그것은 완벽하게 괜찮을 높이의 계층 구조를 변경할 수 없는 클래스에서는 모든 비 잎 노드에 해야 합니다 물론 비 최종입니다.

는지 여부를 확인에는 필드에는 개인;그것은 완벽한 클래스를 공공 분야,그리고 가시의 분야에 영향을 미치지 않는의 불변성 선언 클래스에서 어떤 방법으로,모양,형태입니다.당신은 여부를 확인하여야 합드 최종과 유형을 변경할 수 없습니다.

을 검사할 때 클래스,당신이 무엇을 하고 싶음을 재귀적으로 사용을 결정하는 불변성의 super 클래스입니다.는 경우 슈퍼 mutable,그 후손은 정의에 의해 변경할 수도.

그 후,당신은 확인 선언 드이 아닌 클래스 모든 필드가 있습니다.

면 필드가 아닌 최종 후,당신의 클래스를 변경할 수 있습니다.

면 필드에 최종하지만,형식의 필드는 가변,다음 등은 변경할 수 있습니다.(배열은 정의에 의해 변경할 수 있습니다.)

는 경우드 등 최종 유형의 분야가 Calculating, 다음 그것을 무시하고 다음으로 진행하는 분야이다.는 경우 모든 분야 중 하나 또는 변경할 수 없 Calculating, 다음 당신의 클래스는 변경할 수 없습니다.

는 경우 형식의 필드의 인터페이스,또는 추상 클래스,또는 비 최종 클래스에,그것은 것으로 간주되 변경 가능 가지고 있기 때문에 당신이 절대적으로 제어하지 않습니다 실제 구현할 수 있습니다.이처럼 보일 수도 있는 극복할 수 없는 문제이기 때문에,그것이 의미하는 포장은 수정 가능한 컬렉션 내부에는 UnmodifiableCollection 는 여전히 실패 불변성 테스트,하지만 실제로 잘 이고,그것은 처리할 수 있습으로 다음과 같은 해결 방법입니다.

일부는 클래스가 포함될 수 있습 non-최종 필드를 아직도 변경할 수 없도록 효과적으로.의 예이 String 클래스입니다.다른 클래스는 이 범주에 속하는 클래스를 포함하는 비 최종 회원은 순수한 성능 모니터링을 위한 목적으로(호출이 카운터,etc.), 클래스를 구현하는 아이스는 불변성 (보면 그것까지),그리고 클래스 구성원을 포함하는 인터페이스 알려져있다하여 발생하지 않습니다.또한,는 경우 등이 포함 bona fide 변경 가능한 분야이지만 약속을하지 않으로 그들을 계산할 때 차이()및 equals(),다음 등은 물론 안전하지 않은 때 멀티-스레딩지만,여전히 수 있으로 변경 불가능을 사용하는 목적으로 키습니다.그래서,이 모든 경우에서 처리할 수 있는 두 가지 방법 중 하나:

  1. 수동으로 추가하는 클래스(및 인터페이스)를 귀하의 불변성 검출기입니다.당신이 알고 있는 경우는 특정 클래스를 변경할 수 없도록 효과적으로는 사실에도 불구하고 불변성에 대한 테스트 실패하면,당신 수동으로 추가한 항목을 감지기 연결 Immutable.이 방법,발견자려고 시도하지 않는지 여부를 확인 그것은 불변,그것은 항상 그냥 말하는'그렇다,그것입니다.'

  2. 소개 @ImmutabilityOverride 주석이 있습니다.당신의 면역성을 탐지기를 확인할 수 있습의 존재에 대한 이 주석에서 필드를 존재하는 경우,그것은 처리할 수도 있습장으로 변경할 수 없다는 사실에도 불구하고 현장할 수 있는 비 최종 또는 그것의 종류 수 변경 가능합니다.기도 확인에 대한의 존재 이 주석에서 클래스고,따라서 치료 등을 변경할 수 없는 것으로 간주하지 않고 심지어 귀찮게 확인하는 해당 필드가 있습니다.

도움이 되기를 바랍니다 미래 세대입니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top