문제

같은 클래스의 대상 개체에 객체를 복사하기위한 인터페이스를 만들고 싶었습니다. 간단한 방법은 캐스팅을 사용하는 것입니다.

import org.junit.Test;
import org.junit.internal.runners.JUnit4ClassRunner;
import org.junit.runner.RunWith;

@RunWith(JUnit4ClassRunner.class)
public class TestGenerics {
public static interface Copyable {
    public void copy(Copyable c);
}

public static class A implements Copyable {
    private String aField = "--A--";
    protected void innerCopy(Copyable c) {
        A a = (A)c;
        System.out.println(a.aField);
    }
    public void copy(Copyable c) {
        innerCopy(c);
    }
}

public static class B extends A {
    private String bField = "--B--";
    protected void innerCopy(Copyable c) {
        B b = (B)c;
        super.innerCopy(b);
        System.out.println(b.bField);
    }
}

@Test
public void testCopy() {
    Copyable b1 = new B();
    Copyable b2 = new B();
    b1.copy(b2);
}
}

또한 제네릭을 사용하여 수행 할 수있는 방법을 찾았습니다.

import org.junit.Test;
import org.junit.internal.runners.JUnit4ClassRunner;
import org.junit.runner.RunWith;

@RunWith(JUnit4ClassRunner.class)
public class TestGenerics {
    public static interface Copyable<T> {
        public void copy(T t);
    }

    public static class A<T extends A<?>> implements Copyable<T> {
        private String a = "--A--";
        public void copy(T t) {
            System.out.println(t.a);
        }
    }

    public static class B<T extends B<?>> extends A<T> {
        private String b = "--B--";
        public void copy(T t) {
            super.copy(t);
            System.out.println(t.b);
        }
    }

    @Test
    @SuppressWarnings("unchecked")
    public void testCopy() {
        Copyable b1 = new B();
        Copyable b2 = new B();
        b1.copy(b2);
    }
}

내가 경고를 제거하는 유일한 방법은 주석입니다. 그리고 뭔가 잘못된 것 같은 느낌이 듭니다. 그래서 무슨 일이야? 나는 문제의 근원에서 무언가 잘못되었다는 것을 받아 들일 수 있습니다. 따라서 모든 종류의 설명을 환영합니다.

도움이 되었습니까?

해결책 6

나는 스칼라를 배웠고 이제 2 년 전에 내가 원했던 것은 비밀화 유형 매개 변수 그리고 Scala의 유형 시스템 :

trait CopyableTo[-T] {
  def copyTo(t: T)
}

class A(private var a: Int) extends CopyableTo[A] {
  override def copyTo(t: A) {
    println("A:copy")
    t.a = this.a
  }
}

class B(private var a: Int, private var b: Int) extends A(a) with CopyableTo[B] {
  def copyTo(t: B) {
    println("B:copy")
    super.copyTo(t)
    t.b = this.b
  }
}

@Test
def zzz {
  val b1 = new B(1, 2)
  val a1 = new A(3)
  val b2 = new B(4, 5)
  b1.copyTo(a1)
  a1.copyTo(b1)
  b1.copyTo(b2)
}

Java 유형 시스템은 너무 약합니다.

다른 팁

인터페이스 정의 :

public interface Copyable<T extends Copyable<T>> {
    void copy(T copyFrom);
}

구현 :

public class Example implements Copyable<Example> {
    private Object data;
    void copy(Example copyFrom) {
        data = copyFrom.data;
    }
    //nontrivial stuff
}

그것은 당신의 경고를 처리해야합니다.

서브 클래스를 더 이상 클래식하고 싶지 않다고 가정하면 필요합니다.

public static /*final*/ class AClass implements Copyable<AClass> {

초록 수업의 경우 "열거적 인"일을합니다.

public static abstract class AClass<T extends AClass<T>> implements Copyable<T> {

TestCopy에서 경고 중 하나는 콘크리트 복사 가능한 일부 대신 복사 가능한 "원시 유형"을 인스턴스화하기 때문입니다.u003CT> . 복사 가능한 것을 인스턴스화하면 ts (t의 아형 포함)에만 적용 할 수 있습니다. 공식적인 유형으로 인스턴스화하려면 클래스 정의를 약간 변경해야합니다.

public static class A<T extends A> implements Copyable<T>
public static class B<T extends B> extends A<T>

다음 문제는 복사 u003CB>가능이 컴파일 타임 유형의 B (복사 가능의 정의에 따라) 만 통과 할 수 있다는 것입니다. 위의 TestCopy ()는 컴파일 타임 유형의 복사 가능한 유형을 전달합니다. 다음은 간단한 설명과 함께 작동하는 내용의 몇 가지 예입니다.u003C/b>

public void testExamples()
{
    // implementation of A that applies to A and subtypes
    Copyable<A> aCopier = new A<A>();

    // implementation of B that applies to B and subtypes
    Copyable<B> bCopier = new B<B>();

    // implementation of A that applies to B and subtypes
    Copyable<B> bCopier2 = new A<B>();
}

나는 당신의 첫 번째 접근 방식에서 경고를 없애는 방법을 계속 찾으려고 노력하고 있으며 효과가있는 것을 생각해 낼 수 없습니다. 그럼에도 불구하고, 나는 첫 번째 접근법이 두 가지 악의 적은 것이라고 생각합니다. 안전하지 않은 캐스트는 수업에 복잡한 API를 제공 해야하는 것보다 낫습니다.

완전히 별도의 접근 방식은 Object.Clone ()을 무시하고 복제 가능한 구현하는 것입니다.

이것은 두 번째 접근법의 최상의 코드입니다. 경고없이 컴파일됩니다.

import static org.junit.Assert.fail;

import org.junit.Test;
import org.junit.internal.runners.JUnit4ClassRunner;
import org.junit.runner.RunWith;

@RunWith(JUnit4ClassRunner.class)
public class TestGenerics {
    public static interface Copyable<T> {
        public void copy(T t);
    }

    public static class A<T extends A<T>> implements Copyable<T> {
        private String a = "--A--";
        public void copy(T t) {
            System.out.println(t.a);
        }
        @SuppressWarnings("unchecked")
        public static Copyable<Object> getInstance() {
            return new A();
        }

    }

    public static class B<T extends B<T>> extends A<T> {
        private String b = "--B--";
        public void copy(T t) {
            super.copy(t);
            System.out.println(t.b);
        }
        @SuppressWarnings("unchecked")
        public static Copyable<Object> getInstance() {
            return new B();
        }
    }


    @Test
    public void testCopy() {
        Copyable<Object> b1 = B.getInstance();
        Copyable<Object> b2 = B.getInstance();
        Copyable<Object> a = A.getInstance();
        b1.copy(b2); // this works as intended
        try {
            b1.copy(a); // this throws ClassCastException
            fail();
        } catch (ClassCastException cce) {
        }
    }
}

또한 나는이 프로그램에서 일어나는 모든 일을 반성하는 데 도움을 주었다.

       for (Method method : A.class.getMethods()) {
               if (method.getName().equals("copy")) {
                       System.out.println(method.toString());
               }

       }
       for (Method method : B.class.getMethods()) {
               if (method.getName().equals("copy")) {
                       System.out.println(method.toString());
               }

       }

출력은 다음과 같습니다.

public void com.sbp.core.TestGenerics$A.copy(com.sbp.core.TestGenerics$A)
public void com.sbp.core.TestGenerics$A.copy(java.lang.Object)

public void com.sbp.core.TestGenerics$B.copy(com.sbp.core.TestGenerics$B)
public void com.sbp.core.TestGenerics$B.copy(com.sbp.core.TestGenerics$A)
public void com.sbp.core.TestGenerics$A.copy(java.lang.Object)

그것은 그것을 의미합니다 :

  1. a와 b의 사본 (...) 메소드는 컴파일러가 "브리지"를 생성합니다 - 각각에 대해 2 개의 다른 방법, 하나는 조상에서 refed 인수 유형을 갖는다 (복사 가능한 객체에서 Reified t, Reified "t artends a" 그리고 그것이 과부하가되지 않고 과부하가되지 않는 이유이며, 다른 하나는 클래스를 정의하기위한 반복 인수 유형입니다. 첫 번째 방법 (자가 생성 신체 포함) 다운 캐스트 두 번째라고 부르는 주장 (그들은 그것을 다리라고 부릅니다). 이 다운 캐스팅으로 인해 B1.copy (a)를 호출하면 런타임에서 ClassCastException을 얻습니다.

  2. 직접 유형 캐스팅이 깨끗하고 내 문제에 대한 더 나은 도구 인 것처럼 보이며 제네릭은 직접 목적으로 더 잘 사용됩니다 - 컴파일 시간 유형 검사를 시행합니다.

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