[java] Java에서 보호 된 정적을 사용해서는 안되는 이유

이 질문을 진행 했습니다 Java에서 클래스 변수를 재정의하는 방법이 있습니까?
36 개의 찬성 투표를 한 첫 번째 댓글은 다음과 같습니다.

를 본 적이 있으면 protected static실행하십시오.

누구든지 왜 protected static눈살을 찌푸리는 지 설명 할 수 있습니까 ?



답변

직접적인 문제 라기보다는 문체에 가깝습니다. 수업에서 무슨 일이 일어나고 있는지 제대로 생각하지 못했음을 시사합니다.

static의미 에 대해 생각해보십시오 .

이 변수는 클래스 수준에 존재하며 각 인스턴스에 대해 별도로 존재 하지 않으며 나를 확장하는 클래스에 독립적으로 존재하지 않습니다 .

protected의미 에 대해 생각해보십시오 .

이 변수는이 클래스, 동일한 패키지의 클래스 및 나를 확장하는 클래스에서 볼 수 있습니다 .

두 가지 의미는 정확히 상호 배타적이지는 않지만 매우 가깝습니다.

두 가지를 함께 사용할 수있는 유일한 경우는 확장되도록 설계된 추상 클래스가 있고 확장 클래스가 원본에 정의 된 상수를 사용하여 동작을 수정할 수있는 경우입니다. 그런 종류의 배열은 대부분 매우 지저분해질 것이며 클래스 디자인의 약점을 나타냅니다.

대부분의 경우 상수를 공용으로 사용하는 것이 더 낫습니다. 그 이유는 모든 것을 더 깨끗하게 만들고 사람들이 하위 클래스를 더 유연하게 만들 수 있기 때문입니다. 대부분의 경우 구성이 상속보다 선호되는 반면 추상 클래스는 상속을 강제합니다.

이것이 어떻게 깨질 수 있는지에 대한 한 가지 예를보고 독립적 인 존재가없는 변수가 의미하는 바를 설명하려면 다음 예제 코드를 시도하십시오.

public class Program {
    public static void main (String[] args) throws java.lang.Exception {
        System.out.println(new Test2().getTest());
        Test.test = "changed";
        System.out.println(new Test2().getTest());
    }
}

abstract class Test {
    protected static String test = "test";
}

class Test2 extends Test {
    public String getTest() {
        return test;
    }
}

결과가 표시됩니다.

test
changed

https://ideone.com/KM8u8O 에서 직접 시도해보십시오.

이 클래스는 Test2정적 멤버에 액세스 할 수 있습니다 test에서 Test이름을 규정 할 필요없이 – 그러나 상속하지 않습니다 또는 자신의 사본을 얻을. 그것은 메모리에서 똑같은 물체를보고 있습니다.


답변

모순적이기 때문에 눈살을 찌푸립니다.

변수를 만드는 것은 패키지 내에서protected 사용 되거나 하위 클래스 내에서 상속 된다는 것을 의미합니다 .

변수를 static만들면 클래스의 구성원이되어 상속 의도가 제거됩니다 . 이것은 패키지 내에서 사용하려는 의도만을 남겨두고 우리는 그것을 package-private위해 가지고 있습니다 (수정 자 없음).

당신은 자바 FX의 같은 응용 프로그램을 (실행하는 데 사용되어야하는 클래스를 선언한다면 나는이 유용하게 찾을 수있는 유일한 상황은 Application#launch, 단지 서브 클래스에서 발사 할 수있을 싶었다. 그렇게하면, 방법은 또한 보장 final에 허용 안 숨어 . 그러나 이것은 “규범”아니다, 아마도 응용 프로그램을 실행할 수있는 새로운 방법을 추가하여 더 복잡성을 추가하는 것을 방지하기 위해 구현되었다.

각 수정 자의 액세스 수준을 보려면 다음을 참조하십시오. The Java Tutorials-Controlling Access to Members of a Class


답변

나는 이것이 왜 눈살을 찌푸려 야하는 특별한 이유를 보지 못한다. 항상 동일한 동작을 달성하기위한 대안이있을 수 있으며, 이러한 대안이 보호 된 정적 방법보다 “더 나은”지 여부는 실제 구조에 따라 달라집니다. 그러나 보호 된 정적 메서드가 합리적 일 수있는 한 가지 예는 다음과 같습니다.

( protected더 명확하게 사용하기 위해 별도의 패키지로 분할하도록 편집 )

package a;
import java.util.List;

public abstract class BaseClass
{
    public Integer compute(List<Integer> list)
    {
        return computeDefaultA(list)+computeDefaultB(list);
    }

    protected static Integer computeDefaultA(List<Integer> list)
    {
        return 12;
    }
    protected static Integer computeDefaultB(List<Integer> list)
    {
        return 34;
    }
}

그로부터 파생 :

package a.b;

import java.util.List;

import a.BaseClass;

abstract class ExtendingClassA extends BaseClass
{
    @Override
    public Integer compute(List<Integer> list)
    {
        return computeDefaultA(list)+computeOwnB(list);
    }

    private static Integer computeOwnB(List<Integer> list)
    {
        return 56;
    }
}

또 다른 파생 클래스 :

package a.b;

import java.util.List;

import a.BaseClass;

abstract class ExtendingClassB extends BaseClass
{
    @Override
    public Integer compute(List<Integer> list)
    {
        return computeOwnA(list)+computeDefaultB(list);
    }

    private static Integer computeOwnA(List<Integer> list)
    {
        return 78;
    }
}

protected static수정 확실히 여기 정당화 될 수 :

  • 메서드는 static인스턴스 변수에 의존하지 않기 때문에 일 수 있습니다 . 다형성 방법으로 직접 사용하기위한 것이 아니라 더 복잡한 계산의 일부인 기본 구현 을 제공 하고 실제 구현의 “구성 요소”역할을하는 “유틸리티”방법입니다 .
  • 메소드는 public구현 세부 사항이므로이 아니어야합니다 . 그리고 그들은 private확장 클래스에 의해 호출되어야하기 때문에 그럴 수 없습니다 . 또한 다른 패키지의 확장 클래스에 액세스 할 수 없기 때문에 “기본”가시성을 가질 수 없습니다.

(편집 : 원래 주석 이 메서드가 아닌 필드 만 언급했다고 가정 할 수 있지만 너무 일반적이었습니다)


답변

정적 멤버는 상속되지 않으며 보호 된 멤버는 하위 클래스 (물론 포함하는 클래스)에만 표시되므로 a protected static는와 동일한 가시성 static을 가지므로 코더의 오해를 암시합니다.


답변

사실 근본적으로 protected static. 패키지 및 선언 클래스의 모든 하위 클래스에 대해 표시되는 정적 변수 또는 메서드를 정말로 원하면 계속 진행하십시오 protected static.

어떤 사람들은 일반적으로 사용하지 않도록 protected여러 가지 이유로 어떤 사람들이 아닌 최종 생각 static나는의 조합을 생각 때문에 변수는, (나는 개인적으로 어느 정도 후자의 동정) 반드시 피해야 protected하고 static봐야한다 ^ 2을 나쁜 사람들이에 두 그룹에 속합니다.


답변

Protected는 서브 클래스에서 사용할 수 있도록 사용됩니다. 동일한 변수에 접근 할 수있는 것은 정적 방식이므로 구체적인 클래스의 컨텍스트에서 사용할 때 보호 된 정적을 정의하는 논리는 없지만 컴파일러는 정적 방식으로 슈퍼 클래스 정적 변수에 액세스 할 때 경고를 표시합니다.


답변

글쎄요, 대부분의 사람들이 대답했듯이 :

  • protected의미- ‘ package-private + 하위 클래스에 대한 가시성-속성 / 동작이 상 속됨
  • static의미- ‘ 인스턴스의 반대-CLASS 속성 / 동작, 즉, 상속되지 않음

따라서 그들은 약간 모순적이고 호환되지 않습니다.

그러나 최근에이 두 가지를 함께 사용하는 것이 합리적 일 수있는 사용 사례를 찾았습니다. 불변 유형 abstract의 부모 클래스 를 만들고 하위 유형에 공통적 인 속성을 가지고 있다고 상상해보십시오 . 불변성을 적절하게 구현 하고 가독성을 유지 하기 위해 Builder 패턴 을 사용할 수 있습니다 .

package X;
public abstract class AbstractType {
    protected Object field1;
    protected Object field2;
    ...
    protected Object fieldN;

    protected static abstract class BaseBuilder<T extends BaseBuilder<T>> {
        private Object field1; // = some default value here
        private Object field2; // = some default value here
        ...
        private Object fieldN; // = some default value here

        public T field1(Object value) { this.field1 = value; return self();}
        public T field2(Object value) { this.field2 = value; return self();}
        ...
        public T fieldN(Object value) { this.fieldN = value; return self();}
        protected abstract T self(); // should always return this;
        public abstract AbstractType build();
    }

    private AbstractType(BaseBuilder<?> b) {
        this.field1 = b.field1;
        this.field2 = b.field2;
        ...
        this.fieldN = b.fieldN;
    }
}

그리고 왜 protected static? AbstactType자체 비추 상 빌더를 구현하고 외부 package X에 위치 하여 .NET Framework에 액세스하고 재사용 할 수 있는 비추 상 하위 유형을 원 하기 때문 BaseBuilder입니다.

package Y;
public MyType1 extends AbstractType {
    private Object filedN1;

    public static class Builder extends AbstractType.BaseBuilder<Builder> {
        private Object fieldN1; // = some default value here

        public Builder fieldN1(Object value) { this.fieldN1 = value; return self();}
        @Override protected Builder self() { return this; }
        @Override public MyType build() { return new MyType(this); }
    }

    private MyType(Builder b) {
        super(b);
        this.fieldN1 = b.fieldN1;
    }
}

물론 우리는 BaseBuilder대중에게 공개 할 수 있지만 또 다른 모순 된 진술을합니다.

  • 비 인스턴트 할 수없는 클래스 (추상)가 있습니다.
  • 우리는 그것을위한 공공 건축업자를 제공합니다

그래서 모두의 경우에서 protected staticpublic의 빌더abstract class 우리는 모순 된 진술을 결합한다. 그것은 개인적인 취향의 문제입니다.

그러나, 나는 여전히 선호 public의 빌더를abstract class 때문에 protected static내게는 짐 우드와 OOP 세계에서 자연스러운 느낌!