Java 抽象类 : Returning “this” pointer for derived classes "follow up"

标签 java inheritance casting

我在下面的帖子中需要一些帮助,因为我无法使用泛型从基础对象中获取派生对象,而且我不希望使用向下转型。

Java Abstract Classes: Returning "this" pointer for derived classes

我非常有兴趣看到帖子中@Adam Arold 设置的代码示例。

public <T extends KeyException> T withId(final String Id) {
    this.Id = Id;
    return (T)this;
}

我无法对该帖子发表评论,因为我需要代表点数才能做到这一点,所以我要发布新的。

我基本上试过了,但收到了一些警告,

   public class KeyException <T extends KeyException<T>> {

    private static final long serialVersionUID = 1L;
    protected String Id;

    public String getId() {
        return Id;
    }

    // The type parameter T is hiding the type T
    public <T extends KeyException<T>> T withId(final String Id) { 
        this.Id = Id;
        return (T)this; //Type safety: Unchecked cast from KeyException<T> to T
    }
}

使用泛型避免向下转型的正确方法是什么?

下面是我的代码,

class Foo<TSelf extends Foo<?>> {
    Class<TSelf> selfClass;

    Foo(Class<TSelf> selfClass) {
        if (!this.getClass().equals(selfClass)) 
            throw new IllegalArgumentException();
        this.selfClass = selfClass;
    }

    TSelf returnThis() {
        return selfClass.cast(this);
    }
}

class Bar extends Foo<Bar> {
    Bar() {
        super(Bar.class);
    }

    public int id = 10;

    public static void main(String str[]) {
        Bar b = new Bar();
        b.id = 10;
        Foo F = new Bar();
        F.returnThis().id = 20; // Error, id cannot be resolved or is not a field
    }
}

使用“Fluent”界面实现构建器模式,

// Base Class here

public abstract class Foo {
    protected final String className;

    protected Foo(Builder<?> builder)  {
        this.className = builder.className; 
    }

    /* Builder class */
    public static abstract class Builder<T extends Builder<?>> {
        Class<T> selfClass;

        protected String className;

        public Builder(Class<T> selfClass) {
            if (!this.getClass().equals(selfClass)) 
                throw new IllegalArgumentException();
            this.selfClass = selfClass;
        }                         

        public Builder<?> withClassName(String className) {
            this.className = className;
            return self();
        }

        public T self() { 
            return selfClass.cast(this);
        }

        /* build the Option */
        public abstract Foo build();

        private void validate() {
            if(className != null)
                throw new IllegalArgumentException();
        }
    }     
}

// Derived Class here

public class Bar extends Foo {
    private final String barProp;   

    private Bar(Builder builder) {
        super(builder);
        this.barProp = builder.barProp;
    }

    /* Builder class */
    public static class Builder extends Foo.Builder<Bar.Builder> {
        private String barProp = null;  

        public Builder() {
            super(Bar.Builder.class);
        }

        public Bar.Builder withBarProp(String barProp) {
            this.barProp = barProp;
            return self();
        }

        public Bar build() {
            if(barProp != null)
                throw new IllegalArgumentException();

            return new Bar(this);
        }            
    }

    public static void main(String[] args) {         

        Foo f1 = new Bar.Builder()
                    .withBarProp("Prop 1")
                    .withClassName("Bar") // works fine
                    .build();

        Foo f2 = new Bar.Builder()
                    .withClassName("Bar")
                    .withBarProp("Prop 1") // does not work
                    .build();

    }
}

最佳答案

您正在隐藏 withId() 中的 T 参数。这意味着方法中使用的 T 与类作用域中使用的 T 不同。只需使用:

public T withId(String id) {
    ...
}

也就是说,您尝试执行的操作可能无法实现类型安全。 KeyException 根本无法保证this 的类型是T。类型系统无法表达这种约束,我有一种预感,它甚至不能这样做,因为它会造成比它解决的更多的麻烦。

您能得到的最接近的是仅适用于一个继承级别的仍然样板化的解决方法:

class Foo<TSelf extends Foo> {
    Class<TSelf> selfClass;

    Foo(Class<TSelf> selfClass) {
        if (!this.getClass().equals(selfClass)) 
            throw new IllegalArgumentException();
        this.selfClass = selfClass;
    }

    TSelf returnThis() {
        return selfClass.cast(this);
    }
}

class Bar extends Foo<Baz> {
    Bar() {
        super(Baz.class);
    }
}

这仍然需要您详细说明您希望 withId() 等方法返回什么类型,但至少您不必重写它们中的每一个。

关于Java 抽象类 : Returning “this” pointer for derived classes "follow up",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19024831/

相关文章:

java - Guice log4j 自定义注入(inject)不支持在构造函数内进行日志记录

c++ - C 结构继承与 C++ POD 结构继承

c++ - 调用基础运算符而不是派生运算符 - 正常行为?

C++:此代码编译,但抛出运行时检查失败 #2 - 变量 'num' 周围的堆栈已损坏。发生

java - 在java中使用另一个ArrayList更新ArrayList

java - 获取java中以 "9.1.0.0-10"形式给出的Ip地址范围

c# - 避免继承树中的大量强制转换

java - 将 Int 转换为 Java 中的枚举

Java 流 : Replacing groupingBy and reducing by toMap

c++ - 使用运算符重载调用虚函数