source

매개 변수의 실제 유형을 기반으로 한 메서드 선택 오버로드

factcode 2022. 9. 6. 22:15
반응형

매개 변수의 실제 유형을 기반으로 한 메서드 선택 오버로드

이 코드를 실험하고 있습니다.

interface Callee {
    public void foo(Object o);
    public void foo(String s);
    public void foo(Integer i);
}

class CalleeImpl implements Callee
    public void foo(Object o) {
        logger.debug("foo(Object o)");
    }

    public void foo(String s) {
        logger.debug("foo(\"" + s + "\")");
    }

    public void foo(Integer i) {
        logger.debug("foo(" + i + ")");
    }
}

Callee callee = new CalleeImpl();

Object i = new Integer(12);
Object s = "foobar";
Object o = new Object();

callee.foo(i);
callee.foo(s);
callee.foo(o);

foo(Object o) 。 방식 선택은 파라미터 유형을고려하기를 합니다.메서드 선택은 (선언된 것이 아닌) 실제 파라미터 유형을 고려하기를 기대합니다.가가뭘 ?놓 ???★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★foo(12),foo("foobar") ★★★★★★★★★★★★★★★★★」foo(Object o)

메서드 선택은 (선언된 것이 아닌) 실제 파라미터 유형을 고려하기를 기대합니다.내가 뭘 빼놓았나요?

네. 예상이 빗나갔어요.Java에서 동적 메서드디스패치는 메서드가 호출된 오브젝트에 대해서만 실행됩니다.오버로드된 메서드의 파라미터 타입에 대해서는 발생하지 않습니다.

Java 언어 사양 인용:

메서드가 호출되면('15.12'), 실제 인수(및 임의의 명시적 형식 인수) 및 인수 컴파일 시간 유형을 컴파일 시 사용하여 호출되는 메서드의 시그니처를 결정합니다('15.12.2).호출되는 방식이 인스턴스 방식일 경우 실제 호출되는 방식은 동적 메서드 룩업('15.12.4)을 사용하여 런타임에 결정됩니다.

앞서 설명한 바와 같이 컴파일 시 오버로드 해결이 수행됩니다.

Java Puzzler의 좋은 예가 있습니다.

퍼즐 46: 혼란스러운 건설자의 경우

이 퍼즐은 두 개의 혼란스러운 생성자를 보여줍니다.메인 메서드는 컨스트럭터를 호출하지만 어떤 메서드를 호출합니까?이 프로그램의 출력 그 대답에 달려 있다.무엇, 아니면 합법적인 프로그램은 인쇄나요?

public class Confusing {

    private Confusing(Object o) {
        System.out.println("Object");
    }

    private Confusing(double[] dArray) {
        System.out.println("double array");
    }

    public static void main(String[] args) {
        new Confusing(null);
    }
}

붕괴 46:Confusing의 사례.

...자바의 과부하 해결 과정을 2단계에서 운영되고 있다.첫 단계는 선언하고 접근할 수 있는 모든 메서드나 생성자를 선정한다.두번째 단계는 가장 방법 또는 생성자가 첫번째 단계에 선택한 특정 선택합니다.그것이 매개 변수를 다른[JLS 15.12.2.5]에 전달을 받아들일 수 있는 메서드나 생성자 덜 또 다른 것보다 한정된다.

우리 프로그램에서는 두가지 생성자와 해당 액세스 할 수 있습니다.생성자 Confusing(Object), 그래서 Confusing(Object)덜 구체적인 것이다.(모든 이중 배열은 개체지만, 모든 개체가 두 배열입니다.) 모든 매개 변수 Confusing(double[])에 전달을 받는다.가장 구체적인 생성자가 그러므로 Confusing(double[])는 프로그램의 출력을 설명하고 있다.

이 동작은 type double[]의 값을 전달하면 의미가 있습니다.null을 전달하면 직관에 반합니다.이 퍼즐을 이해하는 열쇠는 어떤 방법 또는 생성자가 가장 구체적인지 테스트에서 실제 매개 변수, 즉 호출에 나타나는 매개 변수를 사용하지 않는다는 것입니다.이 명령어는 어떤 과부하가 적용되는지 판단하기 위해서만 사용됩니다.컴파일러는 어떤 오버로드가 적용 가능하고 접근 가능한지 판단하면 선언에 나타나는 파라미터인 형식 파라미터만을 사용하여 가장 구체적인 오버로드를 선택합니다.

Null 매개 변수를 사용하여 Conflicing(Object) 생성자를 호출하려면 새 Conflicing((Object) null)입력합니다.이렇게 하면 혼동(개체)만 적용됩니다.보다 일반적으로 컴파일러가 특정 오버로드를 선택하도록 하려면 실제 파라미터를 선언된 형식 파라미터 유형에 캐스팅합니다.

인수 유형에 따라 메서드에 콜을 디스패치하는 기능은 멀티 디스패치라고 불립니다.자바에서는 Visitor 패턴으로 이루어집니다.

지금하고 있기 에, 상대하고 있는 것은, 상대하고 있다.Integer §String이 수 없습니다(할 수 없습니다).,switch오브젝트 런타임에 따라 선택할 수 있습니다.

Java 에서는 호출하는 메서드(어떤 메서드시그니처를 사용하는지)가 컴파일시에 결정되기 때문에 컴파일 시간 타입에 따릅니다.

이 문제를 해결하기 위한 일반적인 패턴은 오브젝트 시그니처를 사용하여 메서드의 오브젝트유형을 체크하고 캐스트를 사용하여 메서드에 위임하는 것입니다.

    public void foo(Object o) {
        if (o instanceof String) foo((String) o);
        if (o instanceof Integer) foo((Integer) o);
        logger.debug("foo(Object o)");
    }

유형이 많고 이것이 관리 불가능한 경우 메서드 오버로드는 올바른 접근법이 아닐 수 있습니다.대신 퍼블릭 메서드는 오브젝트를 사용하여 오브젝트 유형별로 적절한 처리를 위임하는 일종의 전략 패턴을 구현해야 합니다.

String, Integer, Boolean, Long 등과 같은 몇 가지 기본 Java 유형을 취할 수 있는 "Parameter"라는 클래스의 오른쪽 생성자를 호출하는 것과 비슷한 문제가 있었습니다.오브젝트 배열이 지정되면 입력 배열 내의 각 오브젝트에 대해 가장 고유한 생성자를 호출하여 그것들을 파라미터 오브젝트 배열로 변환합니다.또한 IlligalArgument를 슬로우하는 생성자 파라미터(Object o)를 정의하려고 합니다.예외.물론 이 메서드는 어레이 내의 모든 오브젝트에 대해 호출됩니다.

제가 사용한 해결책은 반사를 통해 생성자를 찾아보는 거였어요

public Parameter[] convertObjectsToParameters(Object[] objArray) {
    Parameter[] paramArray = new Parameter[objArray.length];
    int i = 0;
    for (Object obj : objArray) {
        try {
            Constructor<Parameter> cons = Parameter.class.getConstructor(obj.getClass());
            paramArray[i++] = cons.newInstance(obj);
        } catch (Exception e) {
            throw new IllegalArgumentException("This method can't handle objects of type: " + obj.getClass(), e);
        }
    }
    return paramArray;
}

보기 흉한 인스턴스, 스위치문 또는 방문자 패턴은 필요 없습니다. : )

Java는 호출할 메서드를 결정할 때 참조 유형을 확인합니다.코드를 강제로 '올바른' 방법을 선택하려면 필드를 특정 유형의 인스턴스로 선언할 수 있습니다.

Integeri = new Integer(12);
String s = "foobar";
Object o = new Object();

매개 변수 유형으로 매개 변수를 캐스팅할 수도 있습니다.

callee.foo(i);
callee.foo((String)s);
callee.foo(((Integer)o);

메서드 호출로 지정된 인수 수와 타입과 오버로드된 메서드의 메서드시그니처 사이에 정확하게 일치하는 것이 있으면 그것이 호출되는 메서드입니다.오브젝트 참조를 사용하고 있기 때문에 Java는 컴파일 시에 오브젝트 파라미터에 오브젝트를 직접 받아들이는 메서드가 있다고 판단합니다.그래서 그 방법을 세 번 불렀어요.

언급URL : https://stackoverflow.com/questions/1572322/overloaded-method-selection-based-on-the-parameters-real-type

반응형