大家好,最近写一个涉及泛型的测试,真是死的心都有:
遇到如下问题,请高手指正:

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);  }

解决方案 »

  1.   

    对于泛型,我觉得你好像还不是很理解的样子。
    泛型的定义是为了解决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()));
      

  2.   

    首先,谢谢您!
    有点疑问,这里是说我不能进行递归的定义,如
    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);  }
      

  3.   

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

  4.   

    你对泛型的定义似乎还是不够清楚的样子。首先不用递归定义,因为泛型没有所谓的递归的概念。
    如果你希望所谓的递归定义,你完全可以拆开来定义。
    ILogicalProcess<Aclass,Bclass> a............
    ILogicalProcess <ILogicalProcess,......> b..........然后回到第二个问题,依旧是那句话,泛型的S类型是需要外部定义的,在内部不能用实际类型,因为泛型定义类不知道S类型是什么类型。S是一个动态的类型,它把定义权利移交给了类的使用者。既然不知道S类型是什么类型,所以从某种程度上来说,定义类型不好直接用S类型中的方法,除非extends某类来告诉定义类它一定是某类的子类,无论你多么确定传入的是什么参数,但是泛型定义类不会知道,它只知道有S这么一个类型,至于它是什么不知道。
    你用通配符参数类型只能说明泛型参数可以是某类型的子类型,如果单纯是个?,默认的是extends Object而已(当然你在类里面定义了是AbstractState,但是他跟通配符传参也不是一个概念)。
    再者,我不知道你的IEvent 接口是哪个接口,有没有被ILogicalProcess 继承,因为两个类或者接口之间的泛型是不能混用的,即使他们都是定义的S类型而且同时继承AbstractState,但是那不是一个东西了,不要把它们主观的认为是同一个东西。
      

  5.   

    泛型实际上是为了保证类型安全的,避免了使用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这个泛型变量。
      

  6.   

    最后,跟楼主说一下关于?东西的问题,这也是我看了楼主的方法后研究了一下的成功,楼主的方法如下
    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类型不是同一个东西,不要误以为他们是同一个东西,他们之间不能互相传递。
      

  7.   

     Iterator<ILogicalProcess<ILogicalProcess,State>> it =pingpong.getSubModelIterator();//just a list将得到如下的警告:
    ILogicalProcess is a raw type. References to generic type
    ILogicalProcess<LP> should be parameterized
      

  8.   

    获益匪浅啊!我感觉我们国人的钻研精神和求真务实态度不比德国人差!
    对了
    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 class3  public class Ping <T,E>extends LogicalProcess<T,E>
     T E and letter for Generic
    4   public class Ping <T,E>extends LogicalProcess<?,?>这四种情况声明类的继承关系的句子都是合法的吧?
      

  9.   

    我试过了,这个函数是可以用的。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).);
         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 =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;
    }}
      

  10.   

    setInnerstate(((SimpleEvent<S>)event).changestate(this.getInnerstate()));这一句仍旧会出错吧?
      

  11.   

    不会出错,我用eclipse3.3 编译通过并运行了,但是我还是不太了解所以然
      

  12.   

    我还是觉得你并没有理解泛型的作用,不过就目前而言,泛型并不重要,因为很多地方并不支持1.5的jdk,而且很多大框架也没有用到泛型。
      

  13.   


    第一个问题interface ILogicalProcess <LP extends ILogicalProcess,S extends AbstractState>这样可以就可以吗?