如何进行泛型的递归定义

denverbenjamin2000 2008-05-22 10:31:04
大家好,最近写一个涉及泛型的测试,真是死的心都有:
遇到如下问题,请高手指正:
1
public interface ILogicalProcess<LP,S extends AbstractState> extends IModel {
声明了这样一个接口,
但是在使用时,我希望把LP替换为一个ILogicalProcess类型,但似乎进入了一个递归的定义。。。。,这样做是否合法,如果不合法,那么如何定义呢
这样写
ILogicalProcess<ILogicalProcess<ILogicalProcess<LP。。。。,S extends AbstractState>
晕了,
2 父类型参数不能用子类替换的问题:
我声明了如下的类,
public class simpleLogicalProcess<LP,S extends AbstractState> extends
LogicalProcess<LP,S>{

其中,一个函数changestate可以返回AbstractState类型的数据,
而另一个函数setInnerstate可以接受S类型的数据,但我在进行如下调用时
setInnerstate(((SimpleEvent)event).changestate(this.getInnerstate()));
居然报错:
The method setInnerstate(S) in the type simpleLogicalProcess<LP,S> is
not applicable for the arguments (AbstractState)

不会吧。。。

public class simpleLogicalProcess<LP,S extends AbstractState> extends
LogicalProcess<LP,S>{
//WB do i really need the flexibility?
private S innerstate;
public simpleLogicalProcess() {
super();


// TODO Auto-generated constructor stub
}

public simpleLogicalProcess(String name) {
super(name);
// TODO Auto-generated constructor stub
}

@Override
public ArrayList<LP> influenced() {
// TODO Auto-generated method stub
return super.influenced();
}

@Override
public ArrayList<IEvent<LP, ?, ?>> out() {
// TODO Auto-generated method stub
return super.out();

}

@Override
protected void sendEvent(IEvent<LP, ?, ?> event) {
// TODO Auto-generated method stub
super.sendEvent(event);
}

@Override
public void run(IEvent<?, ?, ?> event) {
// TODO Auto-generated method stub
if (event instanceof SimpleEvent)
{
setInnerstate(((SimpleEvent)event).changestate(this.getInnerstate()));
}

}

public S getInnerstate() {
return innerstate;
}

public void setInnerstate(S innerstate) {
this.innerstate = innerstate;
}

}

interface SimpleEvent extends IEvent{

public AbstractState changestate(AbstractState raw);

}
...全文
324 21 打赏 收藏 转发到动态 举报
写回复
用AI写文章
21 条回复
切换为时间正序
请发表友善的回复…
发表回复
刘彬彬 2008-05-27
  • 打赏
  • 举报
回复
学习了
树成 2008-05-24
  • 打赏
  • 举报
回复
setInnerstate(((SimpleEvent<S>)event).changestate(this.getInnerstate()));

这一句仍旧会出错吧?
树成 2008-05-24
  • 打赏
  • 举报
回复
为什么这些方法你不自己式一下?
denverbenjamin2000 2008-05-24
  • 打赏
  • 举报
回复
[Quote=引用 11 楼 spiniper 的回复:]
最后,跟楼主说一下关于?东西的问题,这也是我看了楼主的方法后研究了一下的成功,楼主的方法如下
public void run(IEvent <?, ?, ?> event) {
// TODO Auto-generated method stub
if (event instanceof SimpleEvent)
{
setInnerstate(((SimpleEvent <S>)event).changestate(this.getInnerstate()));
}

}
这是一个非常非常不好的使用方式,因为你传入的三个泛型变量为无限定通配符参数,如果了解这个东西你会明白的。
无线定通配符参数是不能传入任何参数,返回参数只能是Object。
就像setInnerstate(S innerstate) 方法,如果你定义的是SimpleEvent <?>,那么很遗憾,编译器会拒绝传入任何参数,因为编译器无法确认?的参数类型。而且你返回的也是一个?,基于对java机制的理解,这个地方编译器也无法确认你要返回一个什么值,那么这个?只能被所有类的超类Object类接收。

[/Quote]
我试过了,这个函数是可以用的。setInnerstate(S innerstate)能够找到原来的对象

////////////
simpleLogicalProcess
////////////

package generic;
import java.util.ArrayList;
public class simpleLogicalProcess<LP,S extends AbstractState> extends LogicalProcess<LP>{
//WB do i really need the flexibility?
private Integer name;
private S innerstate;
public simpleLogicalProcess() {
super();


// TODO Auto-generated constructor stub
}
public simpleLogicalProcess(Integer id) {
name=id;


// TODO Auto-generated constructor stub
}


@Override
public ArrayList<LP> influenced() {
// TODO Auto-generated method stub
return super.influenced();
}

@Override
public ArrayList<IEvent<LP, ?, ?>> out() {
// TODO Auto-generated method stub
return super.out();

}

@Override
protected void sendEvent(IEvent<LP, ?, ?> event) {
// TODO Auto-generated method stub
//super.sendEvent(event);
}


public void run(IEvent<?, ?, ?> event) {
// TODO Auto-generated method stub

if (event instanceof SimpleEvent)
{
System.out.print("we are running"+((SimpleEvent<SonofState>)event).mark);
setInnerstate(((SimpleEvent<S>)event).changestate(this.getInnerstate()));
}

}
public static void main(String args[])
{
Event fly,land,refly;

simpleLogicalProcess<Integer,SonofState> runner1
=new simpleLogicalProcess<Integer,SonofState>((Integer)1);
simpleLogicalProcess<Integer,SonofState> runner2
=new simpleLogicalProcess<Integer,SonofState>((Integer)2);
fly=new SimpleEvent<SonofState>(2,1,123,1.0);
runner1.run(fly);
}
public S getInnerstate() {
System.out.print("we are getInnerstate");
return innerstate;
}

public void setInnerstate(S Sinnerstate) {

this.innerstate = Sinnerstate;
System.out.print("we are setInnerstate"+Sinnerstate.state1);
}
}
class SimpleEvent<S extends AbstractState> extends Event
{
public int mark=1234;
public SimpleEvent(Integer to,Integer from,Integer news,Double newTime)
{

super( to, from, news, newTime);
}
public S changestate(S raw){
return raw;
}

}



///////////////////////////

package generic;

public class AbstractState {

public static int state1=123;
}


/////////////////////

package generic;

public class SonofState extends AbstractState {
public static int sons=111;
public void printson(){
System.out.print(sons);
}
}

/////////////
package generic;

public class Event implements IEvent<Integer,Integer,Integer> {

private Integer sender,reciever,message;
private Double Time;
public Event(Integer to,Integer from,Integer news,Double newTime)
{
sender=from;
reciever=to;
message=news;
Time=newTime;

}
@Override
public Double getTime() {
// TODO Auto-generated method stub
return Time;
}

}
greathawker 2008-05-24
  • 打赏
  • 举报
回复

第一个问题

interface ILogicalProcess <LP extends ILogicalProcess,S extends AbstractState>

这样可以就可以吗?
denverbenjamin2000 2008-05-24
  • 打赏
  • 举报
回复
不会出错,我用eclipse3.3 编译通过并运行了,但是我还是不太了解所以然
树成 2008-05-24
  • 打赏
  • 举报
回复
我还是觉得你并没有理解泛型的作用,不过就目前而言,泛型并不重要,因为很多地方并不支持1.5的jdk,而且很多大框架也没有用到泛型。
树成 2008-05-23
  • 打赏
  • 举报
回复
对于泛型,我觉得你好像还不是很理解的样子。
泛型的定义是为了解决Object需强制转换的问题以及通过这样的不安全操作。
例如public interface ILogicalProcess <LP,S extends AbstractState> extends IModel
这里的是泛型的定义,其中定义两个泛型变量,LP与S,而在当前定义类中不确定LP与S是什么类型的数据(当然你声明的是一个接口)
而后面定义的extends AbstractState并不是继承,他和后面定义的extends IModel不是一个概念了,这个定义的意思是LP与S必须是AbstractState的子类才是有效定义,这个定义过程由调用者来定义。
当你用到这个接口的时候,泛型可以这样来定义。
ILogicalProcess<Aclass,Bclass> ilp=ILogicalProcessFactory.getILogicalProcess();//假定你是这样获得这个接口的对象的。
那么Aclass,Bclass是一个实际存在的类(你自己要实现这些类),而且他们必须继承AbstractState这个类。

那么我回答你的第二个问题
setInnerstate(((SimpleEvent)event).changestate(this.getInnerstate()));
这一句,我知道getInnerstate你获取了一个S类型,这个类型是当前类定义的一个泛型变量,而你setInnerstate是接收一个S类型。如果你直接这样set或者get是不会错的,但是你的changestate方法返回的是一个AbstractState类型,这个地方就会出错,虽然S类型一定是AbstractState的一个子类,但是当前类还不知道它是什么类型,只知道它是一个S类型,这个S类型要被调用者定义。而且此方法从逻辑上来推理,S类型一定是一个AbstractState的子类,但是你返回的是父类,父类的类型是不能被子类的类型所接受的,所以你需要强转一下,也就是改成
setInnerstate((S)((SimpleEvent)event).changestate(this.getInnerstate()));
goodmrning 2008-05-23
  • 打赏
  • 举报
回复
帮顶下
burningice44 2008-05-23
  • 打赏
  • 举报
回复
有必要一定要这样用吗
lisl2003 2008-05-23
  • 打赏
  • 举报
回复
你的标题已经吓到我了……
denverbenjamin2000 2008-05-23
  • 打赏
  • 举报
回复
获益匪浅啊!我感觉我们国人的钻研精神和求真务实态度不比德国人差!
对了
in which circunstance shall I use
1 public class Ping extends LogicalProcess<Ping,PingPongState>{
2 public class Ping <Ping,PingPongState>extends
LogicalProcess<Ping,PingPongState>{
Ping and PingPong state r concrete class

3 public class Ping <T,E>extends LogicalProcess<T,E>
T E and letter for Generic
4 public class Ping <T,E>extends LogicalProcess<?,?>

这四种情况声明类的继承关系的句子都是合法的吧?
denverbenjamin2000 2008-05-23
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 spiniper 的回复:]
你对泛型的定义似乎还是不够清楚的样子。

首先不用递归定义,因为泛型没有所谓的递归的概念。
如果你希望所谓的递归定义,你完全可以拆开来定义。
ILogicalProcess <Aclass,Bclass> a............
ILogicalProcess <ILogicalProcess,......> b..........
[/Quote]
Iterator<ILogicalProcess<ILogicalProcess,State>> it =pingpong.getSubModelIterator();//just a list

将得到如下的警告:
ILogicalProcess is a raw type. References to generic type
ILogicalProcess<LP> should be parameterized
树成 2008-05-23
  • 打赏
  • 举报
回复
最后,跟楼主说一下关于?东西的问题,这也是我看了楼主的方法后研究了一下的成功,楼主的方法如下
public void run(IEvent <?, ?, ?> event) {
// TODO Auto-generated method stub
if (event instanceof SimpleEvent)
{
setInnerstate(((SimpleEvent <S>)event).changestate(this.getInnerstate()));
}

}
这是一个非常非常不好的使用方式,因为你传入的三个泛型变量为无限定通配符参数,如果了解这个东西你会明白的。
无线定通配符参数是不能传入任何参数,返回参数只能是Object。
就像setInnerstate(S innerstate) 方法,如果你定义的是SimpleEvent <?>,那么很遗憾,编译器会拒绝传入任何参数,因为编译器无法确认?的参数类型。而且你返回的也是一个?,基于对java机制的理解,这个地方编译器也无法确认你要返回一个什么值,那么这个?只能被所有类的超类Object类接收。
说句实话,通配符类型确实是一个让人头疼的类型。而且我也觉得你还没理解泛型的真正作用。
还有最后要声明的是,你在ILogicalProcess <LP,S extends AbstractState> extends IModel 定义的S泛型类型和在interface SimpleEvent <S extends AbstractState>extends IEvent定义的S类型不是同一个东西,不要误以为他们是同一个东西,他们之间不能互相传递。
北京-李大鹏 2008-05-23
  • 打赏
  • 举报
回复
泛型实际上是为了保证类型安全的,避免了使用Object进行强转。
extends要保证所有父类型出现的地方都可以用子类进行替换。
implements要保证所有接口出现的地方都可以用任意实现进行替换。

现在看楼主的递归的问题,主要是这个接口的定义:
public interface ILogicalProcess <LP,S extends AbstractState> extends IModel
其中的LP实际上是ILogicalProcess本身。

由于ILogicalProcess接口出现的地方都可以用任意实现类进行替换,那么

public ArrayList<LP> influenced()
protected void sendEvent(IEvent<LP, ?, ?> event)

这两个方法中的泛型变量LP完全可以直接使用ILogicalProcess进行定义。

所以ILogicalProcess接口可以这样定义:

public interface ILogicalProcess <S extends AbstractState> extends IModel
{
....
public ArrayList<ILogicalProcess> influenced()
protected void sendEvent(IEvent<ILogicalProcess, ?, ?> event)
....
}

这样在ILogicalProcess的定义中就不会出现楼主所说的递归的问题了,因为根本不需要定义LP这个泛型变量。
树成 2008-05-23
  • 打赏
  • 举报
回复
对了,你的递归泛型定义是可以定义的,你为什么不自己试一试呢?
树成 2008-05-23
  • 打赏
  • 举报
回复
你对泛型的定义似乎还是不够清楚的样子。

首先不用递归定义,因为泛型没有所谓的递归的概念。
如果你希望所谓的递归定义,你完全可以拆开来定义。
ILogicalProcess<Aclass,Bclass> a............
ILogicalProcess <ILogicalProcess,......> b..........

然后回到第二个问题,依旧是那句话,泛型的S类型是需要外部定义的,在内部不能用实际类型,因为泛型定义类不知道S类型是什么类型。S是一个动态的类型,它把定义权利移交给了类的使用者。既然不知道S类型是什么类型,所以从某种程度上来说,定义类型不好直接用S类型中的方法,除非extends某类来告诉定义类它一定是某类的子类,无论你多么确定传入的是什么参数,但是泛型定义类不会知道,它只知道有S这么一个类型,至于它是什么不知道。
你用通配符参数类型只能说明泛型参数可以是某类型的子类型,如果单纯是个?,默认的是extends Object而已(当然你在类里面定义了是AbstractState,但是他跟通配符传参也不是一个概念)。
再者,我不知道你的IEvent 接口是哪个接口,有没有被ILogicalProcess 继承,因为两个类或者接口之间的泛型是不能混用的,即使他们都是定义的S类型而且同时继承AbstractState,但是那不是一个东西了,不要把它们主观的认为是同一个东西。
denverbenjamin2000 2008-05-23
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 spiniper 的回复:]
那么我回答你的第二个问题
setInnerstate(((SimpleEvent)event).changestate(this.getInnerstate()));
这一句,我知道getInnerstate你获取了一个S类型,这个类型是当前类定义的一个泛型变量,而你setInnerstate是接收一个S类型。如果你直接这样set或者get是不会错的,但是你的changestate方法返回的是一个AbstractState类型,这个地方就会出错,虽然S类型一定是AbstractState的一个子类,但是当前类还不知道它是什么类型,只知道它是一个S类型,这个S类型要被调用者定义。而且此方法从逻辑上来推理,S类型一定是一个AbstractState的子类,但是你返回的是父类,父类的类型是不能被子类的类型所接受的,所以你需要强转一下,也就是改成
setInnerstate((S)((SimpleEvent)event).changestate(this.getInnerstate())); [/Quote]


这种改写也是不行的。
因为泛型类可以继承或者实现其它泛型类或接口,例如ArrayList<T>实现了List<T>接口。因此ArrayList<Base>可以被转换成List<Base>,( 装苹果的袋子仍然是袋子)此外向List<Base>中添加base和derived也是合法的。
但是将list2赋值给list3会导致编译错误,就像关于继承的那个经典问题一样:苹果可以是水果的子类,但是能够装苹果的袋子不是能够装水果的袋子的子类。

////////////
class Test<Test<....
这种定义到底行不行啊?
/////////
denverbenjamin2000 2008-05-23
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 spiniper 的回复:]
ILogicalProcess <Aclass,Bclass> ilp=ILogicalProcessFactory.getILogicalProcess();//
那么Aclass,Bclass是一个实际存在的类(你自己要实现这些类),而且他们必须继承AbstractState这个类。
[/Quote]
首先,谢谢您!
有点疑问,这里是说我不能进行递归的定义,如
ILogicalProcess<ILogicalProcess <Aclass,Bclass>.......?

第二个问题,我采用了如下方法
public void run(IEvent<?, ?, ?> event) {
// TODO Auto-generated method stub
if (event instanceof SimpleEvent)
{
setInnerstate(((SimpleEvent<S>)event).changestate(this.getInnerstate()));
}

}


interface SimpleEvent<S extends AbstractState>extends IEvent{

public S changestate(S raw);

}
jdlsfl 2008-05-23
  • 打赏
  • 举报
回复
强大

62,614

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧