我正在研究泛型,我很难理解一些概念: 我创建了一个通用接口,如下所示:
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 是方法的参数类型,使用的是什么以及使用了什么?
答案 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);
为T
,String
为R
。
另一方面,我看不到您的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 A
,G 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
}