IT story

일반 Java 메소드의 일반 유형을 사용하여 인수 유형을 적용 할 수 있습니까?

hot-time 2021. 1. 7. 19:59
반응형

일반 Java 메소드의 일반 유형을 사용하여 인수 유형을 적용 할 수 있습니까?


메서드의 인수가 다음과 같이 동일한 유형인지 확인하기 위해 제네릭 유형을 사용하고 싶습니다.

public static <T> void x(T a, T b)

이 메서드에 전달되는 두 인수 (a 및 b)는 항상 동일한 유형이어야한다고 가정합니다. 그러나 놀랍게도 어떤 인수가 전달 되더라도 T가 Object에 지워지는 것처럼 모든 유형의 인수 (기본 요소 포함)를 메서드 x에 전달할 수있었습니다.

지금까지 찾은 유일한 해결 방법은 다음과 같이 '확장'을 사용하는 것입니다.

public static <T, U extends T> void x(T a, U b)

하지만 그것으로 살 수는 있지만 내가 원했던 것은 아니다.

제네릭 형식을 사용하여 메서드의 모든 인수 형식을 강제하는 방법이 있습니까?


귀하의 질문을 올바르게 이해하면 다음을 원합니다.

x(10, "x");

컴파일 타임에 실패합니다. 이제 이것을 고려하십시오.

Integer i = 10;
String s = "x";
Object o1 = i;
Object o2 = s;
x(o1, o2);

이 경우 둘 다 동일한 유형의 객체입니다. 원하는 것을 실제로 시행 할 수있는 방법은 없다고 생각합니다. 인수를 Object로 캐스트 할 때 경고 / 오류없이 두 가지 유형으로 호출 할 수 있습니다.

다음과 같이 사용하여 사용할 유형을 지정할 수 있습니다.

ClassName.<Type>x(obj1, obj2);

그리고 그것은 아마도 그것을 할 수있는 유일한 방법 일 것입니다.


내가 올바르게 이해한다면,이를 수행하는 한 가지 방법 은 컴파일러가 다른 유형의 두 개체가 인수로 전달되는 경우 해당 유형이 가장 직접적인 수퍼 클래스라고 추론하도록하는 대신 명시 적으로 T 유형을 지정하는 것입니다. 예를 들면 다음과 같습니다.

public class Test {
    public static void main(String[] args) {
        Test.x(5.0, 5);          // This works since type is inferred to be Number
        Test.<Integer>x(5, 5);   // This works since type is stated to be Integer
        Test.<Integer>x(5.0, 5); // This doesn't; type is stated to be Integer and Double is passed in
    }

    public static <T> void x(T a, T b) {
    }
}

애초에 이것이 문제가되어야하는 이유는 나에게 다소 모호하다. 대신 타입 시스템이 유용한 방식에 대해 오해 한 것 같습니다.

우리는 무엇을 할 수 <T> void x(T a, T b)있습니까? 글쎄, 많이는 아니야. 본체 내부 x, T과 동일 Object우리는 단지 전화 같은 것을 할 수 있도록, toString에을 a하고 b이를 인쇄 할 수 있습니다.

거기에 정말 실용적 이유 ab같은 유형이 있어야합니다. 공통된 유형이 있고 그 유형은 Object또는 그 하위 유형입니다. 사실, <T> void x(T a, T b)실제로 일반화해야하는 명확한 이유가 없습니다 .

  • 이 방법의 몸은 무엇의 실제 유형에 상관하지 않는다 ab어쨌든 사용하지 수 있기 때문이다.
  • 호출 사이트는 무엇의 실제 유형에 상관하지 않는다 a하고 b있기 때문이다 xA는 void이 블랙홀 그래서 방법.

메서드가 <T> List<T> Arrays.asList(T...)다음 과 같은 결과를 얻는 것이 더 일반적입니다 .

// This will cause a compile error because
// the type inferred must be compatible
// with the return assignment.
List<Integer> r = Arrays.asList(1, 1.0);

또는 경계 :

// We don't care what the actual types of
// a and b are, just that we can call bar()
// on them.
// Note: this method does not need to be generic.
<T extends Foo> void x(T a, T b) {
    a.bar();
    a.bar();
}

또는 어떤 종류의 관계를 주장하는 경계 :

// We don't care what the actual types of
// a and b are, just that we can compare
// them to each other.
<T extends Comparable<T>> T max(T a, T b) {
    return (a.compareTo(b) < 0) ? b : a;
}

메서드를 호출 할 때 형식 매개 변수를 명시 적으로 지정할 수 있습니다. 예를 들면 :

 <String>x("hello", "world");

그러나 유형 매개 변수를 명시 적으로 지정 하지 않고 Java의 유형 추론 기능에만 의존한다면 Generics뿐만 아니라 일반적으로 할 수 있다고 생각하지 않습니다.

메소드 매개 변수의 유형은 구체적인 유형이 아니라 적용 가능한 유형 집합 을 나타내는 것입니다 ( 예를 들어 클래스 경우이 집합하나의 유형으로 만 구성 될 수 있음 final).

예를 들어이 방법은 다음과 같습니다.

public void x(Something a) { }

denotes a method, which parameter should be of a type from the set of types, which are compatible with Something (i.e. Something and all its subtypes).

The same applies for Generics.


Presumably, you are not calling your generic method in a generic fashion, so it's treated like a call to x(Object a, Object b). In this example:

public class Test {

  static <T> void x(T a, T b) {
  }

  public static void main(String[] args) {
    x(1, 2); // compiles
    Test.<String>x(1, 2); // does not compile
    Test.<String>x("a", "b"); // compiles
  }
}

The first call to x is not made generically so it compiles. The second call equates T to String, so it fails because 1 and 2 are not Strings. The third call compiles because it properly passes in Strings.


This worked for me

public static <T> void x(T a, T b, Class<T> cls) {
}

now this compiles

public static void main(String[] args) throws Exception {
    x(1, 2, Integer.class);
}

and this does not

public static void main(String[] args) throws Exception {
    x(1, "", Integer.class);
}

ReferenceURL : https://stackoverflow.com/questions/30217236/can-the-generic-type-of-a-generic-java-method-be-used-to-enforce-the-type-of-arg

반응형