通用接口上的类型参数是什么意思?

时间:2017-12-14 13:50:34

标签: java generics interface

我正在研究泛型,我很难理解一些概念: 我创建了一个通用接口,如下所示:

   public interface ICOperations<A,B> {
      A findById(B b);
      A saveOrUpdate(A a);
      <G> G deleteById(A a);  }

我在想代码行的Type参数:

    <G> G deleteById(A a);

只能在我在代码行中定义它的情况下使用:

   public interface ICOperations<A,B> {

我的问题是:参数类型是什么意思?

如果有人可以用类中的方法示例解释它,可以实现方法 deleteById

G 是方法的返回类型, A 是方法的参数类型,使用的是什么以及使用了什么?

4 个答案:

答案 0 :(得分:1)

如果方法还接受一些参数作为生成该类型实例的方法,则声明返回该泛型类型实例的特定方法的泛型类型参数更有意义。

例如,考虑Stream<T>接口。

它有一个map方法,带有泛型类型参数R。它收到Function作为参数,将类型为Stream的{​​{1}}元素转换为T类型的Stream元素。这允许该方法将R转换为Stream<T>

Stream<R>

示例:

<R> Stream<R> map(Function<? super T, ? extends R> mapper);

在此示例中,Stream<String> stream = Stream.of("aaa","bb","c"); Stream<Integer> lengths = stream.map(String::length); TStringR

另一方面,我看不到您的Integer示例的实际使用情况,因为任何实现<G> G methodName(A a);的类都无法返回methodName(A a)的实例。

答案 1 :(得分:1)

<G> G metodName(A a)正在使用接口中定义的A类型的参数,而返回类型G则来自赋值运算符的左侧,因此它可以是基于赋值构造的任何内容。请考虑以下几行:Person p = methodName(someInstanceA);Vector v = methodName(someInstanceA);。在第一种情况下,G变为Person,在第二种情况下,G变为Vector。由于您无法事先知道将使用哪个赋值,因此方法实现必须返回强制转换为G类型的“内容”:

@Override
public <G> G methodName(A a) {
    return (G) a; // if A does not extends G, an exception will be thrown
}

更合理的是以这种方式定义方法签名:

@Override
public <G super A> G methodName(A a) {
    return (G) a; // always legal
}

在上面的示例中,将A的实例强制转换为G始终是安全的,因为G应该是A的超类型(即投射到父级)类型)。由于G被约束为A的父类,因此当且仅当赋值的左侧与指定的约束匹配时,赋值才会编译。

但是,您会经常看到一个方法签名,它从提供的参数中推断出参数化类型:

public <G> G methodName(G g, A a) {
    // G is defined as "any" object, thus only object methods can be accessed:
    // g.toString(); g.hashCode(); ... but g.someMethod(); would not compile...
    // do-something with g and a...
    return g;
}

由于你可以传递任何代替G的内容,G有效地属于Object类型,因此,只有少数情况下这样的内容会对此有用或足够您的需求。因此,如果您想要做一些更有意义的事情,您应该使用上面提到的某种类型约束(G super AG extends SomeOtherType)。有关泛型约束的更多详细信息,请参阅Wildcards

答案 2 :(得分:0)

您可以在类级别(在您的情况A和B中)和方法级别(G)上定义类型参数。如果你创建了实现ICOperations的新课程K,你应该说:public class K<String, Integer> ...<Long> Long methodName(String s)。这意味着您将从类K中将String作为参数传递给您,并且您将收到Long作为答案。

答案 3 :(得分:0)

感谢所有回复的人。 我认为我总体上对java中的不同概念感到困惑。

1概念      如果我实现了一个类的接口,我应该覆盖我班级界面的所有方法。所以在我的课上我会覆盖方法。

2概念 如果我希望在通用方法中使用参数化类型作为方法参数,我应该将其定义为接口的参数类型,否则我将收到编译错误。

//i passed B as Parameter to my interface and i use it at my method as parameter

public interface ICOperations<B> {
  <A> A findById(B b);

//i don't passed the B as parameter type at my interface so when i passed it as method parameter the compiler say to me that i dont know the symbol B.

public interface ICOperations {
  <A> A findById(B b);

如果我没有在我的界面定义中定义一个字母(在我的情况下,我只有A和B:

public interface ICOperations<A,B>

但是我需要创建一个新的字母,我需要使用钻石注释(在这里我们到达我说的关于字母G的点。

<G> G deleteById(A a);

在这种情况下,我们完全松开了Type Safety,因为它与接口本身没有任何联系。

当我们创建一个通用接口时(在我的情况下:public interface ICOperations<A,B>我定义这个接口将由两个类型(A和B)组成,每个将实现我的接口的类定义要替换的类型A和B.  我创建了一个名为Operations的类:public class Operations implements<Integer,String>, 现在我有了接口的定义:

public interface ICOperations<A,B>{
    A findById(B b)
}

和我的班级定义为:  public class Operations implements<Integer,String>

当我覆盖我的方法时,我应该定义:

public class Operations implements ICOperations<Integer,String>

   @Overrided
   Integer deleteById(String id){
  //some code here
}