简体   繁体   English

关于继承和泛型的Java泛型的有用性扩展了自我

[英]what the usefulness about Java generics involving inheritance and generics extends self

I find the generics whose generics params extends itself( here ). 我找到了泛型params扩展自己的泛型( 这里 )。 I don't understand that well.I suspect that it is wrong at the beginning, but no one put forward. 我不太了解。我怀疑一开始是错的,但没有人提出来。 I have some questions about this: 我对此有一些疑问:

  1. How to use the Variant generics, can you give me a example? 如何使用Variant泛型,你能举个例子吗?
  2. What the benefit or effect of this generics style. 这种仿制药的好处或效果是什么。

here is the generics style code which is picked from ( here ). 这是从( 这里 )挑选的泛型样式代码。

abstract class Base<T extends Base<T>> {

}

class Variant<T extends Variant<T>> extends Base<T> {

}

Thanks! 谢谢!

I think you're talking about F-bounded types . 我想你在谈论F-bounded类型 I've found them very useful in situations where two hierarchies are directly correlated. 我发现它们在两个层次结构直接相关的情况下非常有用。 The most clear case that comes to mind is the builder pattern, targeted to a hierarchy of classes. 想到的最明显的案例是构建器模式,它针对类的层次结构。 In this case, it could be of use to have a hierarchy of builders as well. 在这种情况下,也可以使用构建器的层次结构。

An example might shed some light. 一个例子可能会有所启发。 Consider the following (very stereotyped) hierarchy: 考虑以下(非常刻板的)层次结构:

public abstract class Human {

    protected String name;

    protected int age;
}

public class Woman extends Human {

    protected String loveMovie;
}

public class Man extends Human {

    protected String soccerTeam;
}

Now, we want to create builders for Man and Woman . 现在,我们想为ManWoman创建建设者。 We could implement a builder for each one, duplicating the methods to set name and age attributes. 我们可以为每个构建器实现构建器,复制方法以设置nameage属性。 However, as Man and Woman inherit from Human , we could have an abstract HumanBuilder , and make our WomanBuilder and ManBuilder inherit from it. 然而,当ManWoman继承Human ,我们可以拥有一个抽象的HumanBuilder ,并使我们的WomanBuilderManBuilder继承它。 This is where F-bounded types come in handy. 这就是F-bound类型派上用场的地方。

The Human class, along with its HumanBuilder , would be as follows: Human类及其HumanBuilder如下:

public abstract class Human {

    protected String name;

    protected int age;

    public static abstract class HumanBuilder<H extends Human, 
                                              T extends HumanBuilder<H, T>> {
        protected String name;

        protected int age;

        @SuppressWarnings("unchecked")
        public T name(String name) {
            this.name = name;
            return (T) this;
        }

        @SuppressWarnings("unchecked")
        public T age(int age) {
            this.age = age;
            return (T) this;
        }

        protected void fill(H human) {
            human.name = this.name;
            human.age = this.age;
        }

        protected abstract H create();

        public final H build() {
            H human = this.create();
            this.fill(human);
            return human;
        }
    }
}

This would be the Woman class, along with its WomanBuilder : 这将是Woman类及其WomanBuilder

public class Woman extends Human {

    protected String loveMovie;

    public static class WomanBuilder extends HumanBuilder<Woman, WomanBuilder> {

        protected String loveMovie;

        public WomanBuilder loveMovie(String loveMovie) {
            this.loveMovie = loveMovie;
            return this;
        }

        @Override
        protected void fill(Woman woman) {
            super.fill(woman);
            woman.loveMovie = this.loveMovie;
        }

        @Override
        protected Woman create() {
            return new Woman();
        }
    }
}

And finally, here's the Man class, along with its ManBuilder : 最后,这里是Man类,以及它的ManBuilder

public class Man extends Human {

    protected String soccerTeam;

    public static class ManBuilder extends HumanBuilder<Man, ManBuilder> {

        protected String soccerTeam;

        public ManBuilder soccerTeam(String soccerTeam) {
            this.soccerTeam = soccerTeam;
            return this;
        }

        @Override
        protected void fill(Man man) {
            super.fill(man);
            man.soccerTeam = this.soccerTeam;
        }

        @Override
        protected Man create() {
            return new Man();
        }
    }
}

This approach saves quite a lot of lines of code, especially in a real-world use case. 这种方法可以节省大量代码,特别是在实际用例中。

As expected, using the builders does not require any casting: 正如预期的那样,使用构建器不需要任何铸造:

Man man = new Man.ManBuilder()
    .name("Joe")
    .age(29)
    .soccerTeam("Los Angeles Galaxy")
    .build();

Woman woman = new Woman.WomanBuilder()
    .name("Jane")
    .age(25)
    .loveMovie("Meet Joe Black")
    .build();

From the code you linked, it looks like the Base and Variant classes hold methods that return references to an object of their own class, I'm guessing similar to a Singleton. 从你链接的代码看,Base和Variant类看起来像是返回对它们自己的类的对象的引用的方法,我猜测它类似于Singleton。

abstract class Base {
    protected abstract Base getNewInstance();
}

Now if you wanted to return an instance of a subclass of Base, you'd be out of luck. 现在,如果你想返回Base的子类的实例,那你就不走运了。 That's where generics come in. 这就是仿制药的用武之地。

class Variant<T extends Variant<T>> extends Base<T> {
    protected Base<T> getNewInstance() { 
        return new Variant(); 
    }
}

In regards to usefulness, I personally don't really see any. 关于实用性,我个人并没有真正看到任何有用的东西。 It's unnecessarily complicated and could probably be refactored to something much more readable. 这是不必要的复杂,可能会被重构为更具可读性的东西。

Consider following example. 考虑以下示例。 You need to write an algorithm which takes an Iterable of any type T and returns minimum of those objects. 您需要编写一个算法,该算法采用任何类型TIterable并返回这些对象的最小值。 To define relative order over type T you need either pass Comparator over T or, as alternative, require type T extends Comparable<T> . 要定义类型T相对顺序,您需要通过T传递Comparator ,或者作为替代方法,要求类型T extends Comparable<T> This is convenient alternative, because many built-in types like String , Integer , etc. already does. 这是方便的替代方法,因为许多内置类型(如StringInteger等)已经可以。

public static <T extends Comparable<T>> T min(Iterable<T> args) {
    T m = null;
    for (T arg : args)
        m = (m == null || arg.compareTo(m) < 0) ? arg : m;
    return m;
}

This is not exactly form of extending your are talking about, but closely related. 这并不是扩展你所谈论的形式,而是密切相关的。 Generic extending itself might be useful in tree structures, for example. 例如,通用扩展本身在树结构中可能是有用的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM