문제

이 코드에서 다음을 이해합니다.

class Foo {
    public static void method() {
        System.out.println("in Foo");
    }
} 

class Bar extends Foo {
    public static void method() {
        System.out.println("in Bar");
    }
}

.. 정적 방법 Bar 정적 방법을 '숨기기' Foo, 다형성 의미에서 그것을 무시하는 것과는 반대로.

class Test {
    public static void main(String[] args) {
        Foo.method();
        Bar.method();
    }
}

... 출력 :

Foo에서
바에서

다시 정의 method() ~처럼 final 안에 Foo 능력을 비활성화합니다 Bar 그것을 숨기고 다시 실행합니다 main() 출력 :

Foo에서
Foo에서

(편집하다: 메소드를 표시하면 컴파일이 실패합니다 final, 내가 제거 할 때만 다시 실행됩니다 Bar.method())

정적 방법을 다음과 같이 선언하는 것이 나쁜 관행으로 간주됩니까? final, 서브 클래스가 의도적으로 또는 부주의하게 메소드를 다시 정의하지 못하면?

(이것 사용의 행동에 대한 좋은 설명입니다. final 이다..)

도움이 되었습니까?

해결책

나는 그것을 표시하는 것이 나쁜 관행이라고 생각하지 않습니다. static 방법 final.

당신이 알았 듯이 final 이 방법이 서브 클래스에 의해 숨겨지지 않도록합니다 아주 좋은 소식 IMHO입니다.

나는 당신의 진술에 매우 놀랐습니다.

FOO의 최종으로 다시 정의 된 메소드 ()는 막대가 숨길 수있는 기능을 비활성화하고 Main ()을 다시 실행합니다.

Foo에서
Foo에서

아니요, 메소드를 표시합니다 final 안에 Foo 방지 할 것입니다 Bar 컴파일에서. 적어도 일식에서 나는 얻는다 :

스레드의 예외 "main"java.lang.error : 해결되지 않은 컴파일 문제 : foo에서 최종 방법을 무시할 수 없습니다.

또한 사람들은 항상 호출해야한다고 생각합니다 static 클래스 자체 내에서도 클래스 이름으로 자격을 갖춘 방법 :

class Foo
{
  private static final void foo()
  {
    System.out.println("hollywood!");
  }

  public Foo()
  {
    foo();      // both compile
    Foo.foo();  // but I prefer this one
  }
}

다른 팁

정적 방법은 Java의 가장 혼란스러운 기능 중 하나입니다. 이 문제를 해결하기위한 모범 사례가 있으며 모든 정적 방법을 만들 수 있습니다. final 이러한 모범 사례 중 하나입니다!

정적 방법의 문제는 그 것입니다

  • 그들은 클래스 방법이 아니지만 글로벌 기능은 클래스 이름으로 접두사입니다.
  • 그들이 서브 클래스에 "상속 된"것이 이상합니다.
  • 그들이 무시할 수는 없지만 숨겨져 있다는 것은 놀라운 일입니다.
  • 수신기로 인스턴스로 호출 될 수 있다는 것은 완전히 깨졌습니다.

그러므로 당신은해야합니다

  • 항상 수신자로 수신자로 전화하십시오
  • 항상 선언 클래스와 함께 수신기로만 전화하십시오.
  • 항상 그들을 만들어 (또는 선언 클래스) final

그리고 당신은해야합니다

  • 절대 인스턴스로 수신기로 호출하십시오
  • 절대 선언 클래스의 서브 클래스로 수신기로 전화하십시오.
  • 절대 서브 클래스로 재정의하십시오

 

NB : 두 번째 버전의 You 프로그램은 컴파일 오류에 실패해야합니다. 나는 당신의 IDE가 당신 에게이 사실을 숨기고 있다고 가정합니다!

내가있는 경우 public static 방법, 그리고 그것은 종종 이미 소위에 위치하고 있습니다. 유틸리티 클래스static 행동 양식. 자체 설명 된 예는 다음과 같습니다 StringUtil, SqlUtil, IOUtil, etcetera. 이러한 유틸리티 클래스는 이미 선언 된 ITSELVES에 의해입니다 final 그리고 a private 건설자. 예를 들어

public final class SomeUtil {

    private SomeUtil() {
        // Hide c'tor.
    }

    public static SomeObject doSomething(SomeObject argument1) {
        // ...
    }

    public static SomeObject doSomethingElse(SomeObject argument1) {
        // ...
    }

}

이런 식으로 당신은 그들을 무시할 수 없습니다.

당신이 유틸리티 클래스의 종류에 있지 않다면, 나는 public 수정 자. 그렇지 않아야합니다 private? 그렇지 않으면 일부 유틸리티 클래스로 옮기십시오. "정상적인"클래스를 혼란스럽게하지 마십시오 public static 행동 양식. 이런 식으로 당신은 또한 그것들을 표시 할 필요가 없습니다 final.

또 다른 사례는 일종의 추상 공장 수업으로, public static 방법. 그러한 경우 방법을 표시하는 것이 완벽하게 의미가 있습니다. final, 당신은 콘크리트 구현이 방법을 무시할 수 있기를 원하지 않습니다.

일반적으로 유틸리티 클래스의 정적 메소드 만있는 클래스는 내유를 사용하는 것이 바람직하지 않습니다. 이러한 이유로 다른 클래스가 연장되는 것을 방지하기 위해 클래스를 최종으로 정의 할 수 있습니다. 이렇게하면 유틸리티 클래스 방법에 최종 수정자가 적용됩니다.

코드는 컴파일하지 않습니다.

test.java:8 : bar의 method ()는 foo에서 method ()를 무시할 수 없습니다. 재정의 메소드는 정적 최종 최종 공개 정적 무효 메소드입니다 () {

정의에 따라 정적 방법은 결코 무시할 수 없기 때문에 메시지는 오해의 소지가 있습니다.

코딩 할 때 다음을 수행합니다 (항상 100%는 아니지만 여기서는 "잘못된"것은 없습니다.

( "규칙"의 첫 번째 세트는 대부분의 일에 대해 수행됩니다. 일부 특별한 경우는 이후에 다루어집니다)

  1. 인터페이스를 만듭니다
  2. 인터페이스를 구현하는 추상 클래스를 만듭니다
  3. 추상 클래스를 확장하는 구체적인 클래스를 만듭니다
  4. 인터페이스를 구현하지만 추상 클래스를 확장하지 않는 콘크리트 클래스를 만듭니다.
  5. 가능하면 항상 인터페이스의 모든 변수/상수/매개 변수를 만드십시오.

인터페이스에는 정적 메소드가 없으므로 문제를 해결하지 못합니다. 추상 클래스 또는 콘크리트 클래스에서 정적 메소드를 만들려면 비공개 여야합니다. 그렇다면이를 무시하려고 할 방법이 없습니다.

특수한 상황들:

유틸리티 클래스 (모든 정적 방법이 포함 된 클래스) :

  1. 수업을 최종으로 선언하십시오
  2. 우발적 인 생성을 방지하기 위해 개인 생성자를 제공하십시오

비공개가 아닌 콘크리트 또는 추상 클래스에서 정적 방법을 원한다면 대신 유틸리티 클래스를 대신 만들고 싶을 것입니다.

값 클래스 (Java.awt.point와 같이 X 및 Y 값을 거의 보유하는 것과 같이 본질적으로 데이터를 보유 할 수있는 클래스) : :

  1. 인터페이스를 만들 필요가 없습니다
  2. 추상 클래스를 만들 필요가 없습니다
  3. 수업은 최종이어야합니다
  4. 비 개인적인 정적 방법은 괜찮습니다. 특히 캐싱을 수행하려고 할 수 있으므로 구조적으로는 괜찮습니다.

위의 조언을 따르면 책임을 상당히 깨끗하게 분리하는 꽤 유연한 코드가 있습니다.

예제 값 클래스는이 위치 클래스입니다.

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


public final class Location
    implements Comparable<Location>
{
    // should really use weak references here to help out with garbage collection
    private static final Map<Integer, Map<Integer, Location>> locations;

    private final int row;    
    private final int col;

    static
    {
        locations = new HashMap<Integer, Map<Integer, Location>>();
    }

    private Location(final int r,
                     final int c)
    {
        if(r < 0)
        {
            throw new IllegalArgumentException("r must be >= 0, was: " + r);
        }

        if(c < 0)
        {
            throw new IllegalArgumentException("c must be >= 0, was: " + c);
        }

        row = r;
        col = c;
    }

    public int getRow()
    {
        return (row);
    }

    public int getCol()
    {
        return (col);
    }

    // this ensures that only one location is created for each row/col pair... could not
    // do that if the constructor was not private.
    public static Location fromRowCol(final int row,
                                      final int col)
    {
        Location               location;
        Map<Integer, Location> forRow;

        if(row < 0)
        {
            throw new IllegalArgumentException("row must be >= 0, was: " + row);
        }

        if(col < 0)
        {
            throw new IllegalArgumentException("col must be >= 0, was: " + col);
        }

        forRow = locations.get(row);

        if(forRow == null)
        {
            forRow = new HashMap<Integer, Location>(col);
            locations.put(row, forRow);
        }

        location = forRow.get(col);

        if(location == null)
        {
            location = new Location(row, col);
            forRow.put(col, location);
        }

        return (location);
    }

    private static void ensureCapacity(final List<?> list,
                                       final int     size)
    {
        while(list.size() <= size)
        {
            list.add(null);
        }
    }

    @Override
    public int hashCode()
    {
        // should think up a better way to do this...
        return (row * col);
    }

    @Override
    public boolean equals(final Object obj)
    {
        final Location other;

        if(obj == null)
        {
            return false;
        }

        if(getClass() != obj.getClass())
        {
            return false;
        }

        other = (Location)obj;

        if(row != other.row)
        {
            return false;
        }

        if(col != other.col)
        {
            return false;
        }

        return true;
    }

    @Override
    public String toString()
    {
        return ("[" + row + ", " + col + "]");
    }

    public int compareTo(final Location other)
    {
        final int val;

        if(row == other.row)
        {
            val = col - other.col;
        }
        else
        {
            val = row - other.row;
        }

        return (val);
    }
}

특히 다른 사람들이 확장 할 것으로 예상되는 프레임 워크를 개발하는 경우 정적 방법을 최종으로 표시하는 것이 좋습니다. 그렇게하면 사용자가 실수로 수업에서 정적 방법을 숨기지 않을 것입니다. 그러나 프레임 워크를 개발하는 경우 정적 메소드를 사용하여 처음부터 시작하지 않을 수 있습니다.

이 대부분 final 발행 날짜는 VM-S가 상당히 멍청하고 보수적 인 시간으로 거슬러 올라갑니다. 그 당시에는 방법을 표시했다면 final VM이 메소드 호출을 피하고 VM을 인화 할 수 있음을 의미했습니다. 긴 (또는 긴 이중 : P) 시간 이후로는 그렇지 않습니다. http://java.sun.com/developer/technicalarticles/networking/hotspot/inlining.html .

추측 그 아이디어/netbeans 검사는 당신이 사용하고 싶다고 생각하기 때문에 경고합니다. final 최적화를위한 키워드와 그들은 당신이 현대 VM에 불분명하다는 사실을 알지 못한다고 생각합니다.

내 두 센트 ...

Spring 's AOP 및 MVC를 사용하여 최종 방법을 사용하는 데 한 가지 해를 끼쳤습니다. 나는 Spring의 AOP Put을 최종 선언 된 AbstractFormController의 방법 중 하나 주위에 보안 고리를 사용하려고 노력했습니다. 봄은 수업에서 주입을 위해 BCEL 라이브러리를 사용하고 있다고 생각했고 거기에는 약간의 제한이있었습니다.

순수한 유틸리티 클래스를 만들 때 개인 생성자로 선언하여 확장 할 수 없습니다. 일반 클래스를 만들 때 클래스 인스턴스 변수를 사용하지 않는 경우 내 메소드를 정적으로 선언합니다 (또는 경우에도 어떤 경우에도 메소드의 인수를 전달하고 정적으로 만들 수 있습니다. 방법이 수행하는 일). 이러한 방법은 정적으로 선언되었지만 비공개도 있습니다. 코드 복제를 피하거나 코드를 쉽게 이해할 수 있도록하기 위해 있습니다.

즉, 공개 정적 방법이 있고 확장 될 수있는 수업이있는 경우를 기억하지 못합니다. 그러나 여기에보고 된 내용을 바탕으로 정적 방법을 최종적으로 선언 할 것입니다.

정적 방법은 클래스의 속성이며 객체가 아닌 클래스의 이름으로 호출되기 때문입니다. 부모 클래스 메소드를 최종 최종으로 만들면 최종 메소드가 메모리 위치를 변경할 수 없지만 동일한 메모리 위치에서 최종 데이터 멤버를 업데이트 할 수 있으므로 과부하되지 않습니다.

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