对接口还是不理解:看下面这段程序,希望回答问题的时候能按照我的问题一个一个的解答,万分感谢。如果有好的建议也请提出来,比如哪里能看到类似的书籍和举例。public class LPex
{
  Cplex cplex=new Cplex();  internal static void methodA (IInterf1 face1, IInterf2[][] face2, IInterArray[][] ary)
  {
    double[] lb={1,2,3};
    double[] ub={4,5,6};
    IInterf2[] x= face1.GenerateArray(3, lb, ub): 
    ary[0] = new IInterArray[2]
    ary[0][1]=face1.AddLe( something inside  )
  }
}这是CPLEX里一段典型的定义 优化方程  变量上下限的语句。让我看不明白的是:
1)方法的参数里有接口的引用还是实现了接口的类的引用。 
2)引用这个接口能做什么
3)方法内部第三行程序,接口的引用face1,突然冒出个方法,GenerateArray,竟然又生成了个接口,这是在做什么?
4)第五行 也是, 一个接口的方法能生成另一个接口。这是什么意思?不是说接口的方法只能在类定义的时候才能实现么, 这里还没写就直接用它生成新的接口了, 而且通篇程序任何描述ary[0][1]内方法的语句。请前辈帮帮新人!!谢谢!!

解决方案 »

  1.   

    hero的举例犀利而直观接口就是一种声明而已。楼主多想想。
      

  2.   


    还是不明白,声明的是一个实现了该接口的类? 那个 face1 究竟是个类的引用还是 接口的引用,就口能有引用么?
      

  3.   

    再举个例子,打比方上面方法好比一个动作或者说行为——狗狗吃饭(食物 food) 你是调用者,你调用“狗狗吃饭”并给予食物。首先“食物”约定了你给狗狗的是能吃的东西,你给它板砖,条凳,它都不吃,并且编译错误还咬你。你只好把“狗粮”拿出来给它吃。狗粮 是 食物 的实例食物 是 狗粮 的接口。
      

  4.   


    在本程序里:face1 是 引用, 是个类的引用对么但是它实现了IInterf1, 如果 人 是object, 春哥就是个接口,相当于IInterf1,而face1是一个实现了春哥接口的某人的引用, 对么? 
      

  5.   

    internal static void methodA (IInterf1 face1, IInterf2[][] face2, IInterArray[][] ary)加粗的是声明部分,声明的是接口,即“食物”
    红色的是实例,即“狗粮”
      

  6.   

    你说调用方法必须传给你这个接口的实例,所以“face1.AddLe( something inside  )”实际上是因为face1是实现了IInterf1接口的实例,那这个方法产生的返回值为什么又是一个接口IInterarry, 是不是说返回值是实现了IInterarry 的实例 Ary? 
      

  7.   


    谢谢您的耐心解释,您说得接口的实例, 是不是指一个实现了该接口的类的实例,因为接口不能实例化, 那这里是不是少写了sometype:IInterf1, 这类的声明呢?
      

  8.   

    god...你的脑筋就不会转转嘛...女人能生女人,那你去给找个“女人”来给我们看看?抽象的概念仅仅用来分类,实例就是实例,实例具有的抽象类型都只是事先约定的...张三是男人,也可以是公物猿还可以是贪污犯,但张三只是张三而已...所有类型都只是约定,实例只是被约定的...春哥其实不想被人叫哥...先把抽象和实现分清楚...
      

  9.   

    有人会在建男厕所的时候去想jj不能被实例化,而替上帝担心是不是少写了 张三:Ijj 这类的声明呢?我感觉你的问题是对面向对象完全没概念,在拿面向过程的思维方法在思考面向对象的概念...先去学学OOP,转转脑筋吧...
      

  10.   


    我只想搞清楚传参数传进来的“internal static void methodA (IInterf1 face1, IInterf2[][] face2, IInterArray[][] ary)”IInterf1 face1,究竟是什么实例? 按你的说话,方法传进来的都是实例,而接口又不能实例化,那参数里接口类型的实例是什么概念呢?不要和我说厕所,我实在不知道face1究竟是男人还是厕所,这样会让我更糊涂,我本来就是自学的,来这里诚心求教。
      

  11.   

    概念问题就是概念的描述...你应该先去学OOP入门...否则怎么说你都看不懂...再说一次...实例是实例,类型是类型...类型仅仅是约定,实例如何实例化在哪里实例化与方法参数无关...教育部规定了只有通过大学考试的才能叫大学毕业生,我公司规定了只招大学毕业生...你不用管这些规定是不是狗P,但这里就这么约定的...教育部才不管你清华、北大还是野鸡学校,通过考试就发毕业证,这个考试方法传递的就是大学生这么个接口,它才不管你在哪儿实例化,类型是什么...同样的,我公司HR只关心你有没有大学毕业证,这个招聘方法传递的就是大学毕业证这么个接口,它才不管你在哪儿实例化,类型是什么...没有人会在建厕所时关心未来的顾客如何出生...公司招人的时候同样不关心...
      

  12.   


    您现在说的就是我对此类写法感到困惑的关键,
    按您的说法,实例是实例,类形式类型,internal static void methodA (IInterf1 face1, IInterf2[][] face2, IInterArray[][] ary), 实例是 face1, face2, 类形式接口类型,而接口类型不能实例化,那这个face1, face2 是什么实例? 是不是某个实现了接口IInterfx的实例? 我只希望得到明确的是或者不是。我已经卡在这类问题上很久了,过不了这关我以前的努力就白费了,谢谢您的耐心帮助
      

  13.   


    我真有点执迷不悟了,是不是说face1, face2已经实现了接口,是实现了接口的类的一个实例。而且face1 全部实现了接口里的方法?
      

  14.   

    而face1 是实现了接口的某个类的一个实例 呢?
      

  15.   

    是的...否则它就不可能是实例了...还有,假如这些实例没有实现约定的接口,自然会引发异常...对.NET这种强类型语言来说,编译期间就会出参数类型不匹配错误,跟本就不可能通过编译...所以方法也就根本不用去关心参数未来的实例究竟有没有实现接口,有没有实例化...因为没有是不可能的...
      

  16.   


    假设I男人是个接口类型,里面有个方法叫ML(),返回的类型是另外一个接口IBaby
    张三和李四两个类都实现了它
    那么就可以这样 I男人 man = 张三()或者李四();
    而此时在另外一个类里面有个方法:
    IBaby MakeBaby(I男人 man, I女人 woman) //I女人也一样是个接口
    {
        //这里你可以直接调用接口方法,而不用去管具体是张三还是李四,只要man是实现了I男人这个接口的实例就行了
         return man.ML();
    }类比一下,LZ例子里的face1.GenerateArray(3, lb, ub)方法,其实就是IInterf1这个接口定义的方法,最后那一行也是,只是这个方法返回的是另一个接口 IInterf2[] 的数组类型而已
    和平常我们返回的string[]没啥两样,都只是一个Type的形式,所以不能说是生成接口
      

  17.   

    I男人 man = new 张三() 或者 李四();
      

  18.   


    其实很容易理解。你一直把"实例化"和"实例"拧在一起了。说接口不能实例化是因为接口不能使用普通实例化的语法。例如
    public interface IPerson ;
    IPerson person = new IPerson();
    上面的语法会直接报错,这就叫做"接口不能实例化"但是如果使用某个类继承了接口,例如
    public class Man : IPerson
    那就可以这样写:
    IPerson person = new Man();
    person就是IPerson的一个"实例"。
      

  19.   

    谢谢大家的回复,我基本上明白了,下面是我模仿的一段“IBM CPLEX” 优化简单程序。里面充满了这种接口的用法。 大家只要看"Populate by ROW" 就可以了。他们的API在这个地址里:http://publib.boulder.ibm.com/infocenter/cosinfoc/v12r2/index.jsp?topic=/ilog.odms.cplex.help/html/refcallablelibrary/html/overview.html这个例子的目的是把下面的模型写入程序并求出X1, X2, X3 的最优解:Maximize x1 + 2x2 + 3x3
    subject to 
    –x1 + x2 + x3 ≤ 20
    x1 – 3x2 + x3 ≤ 30
    with these bounds 
    0 ≤ x1 ≤ 40
    0 ≤ x2 ≤ infinity
    0 ≤ x3 ≤ infinity

    我的问题是:
    1)既然都是用实现了接口的类,干吗不直接用类来写API呢,
    2)同样:既然方法参数传入的是实现了接口的类, 比如 method1(Iinter1 interf,...)
    那必然有class xxx : interf
    {
    methods in Iinter1()
    }
    可通篇程序没有任何冠以这个传入的类如何实现这些接口的代码, 实现接口的代码跑哪里去了呢?这是我目前最后一个问题了,从昨天到今天,我还是明白了很多的,谢谢大家:
    下面就是例子:PopulateByRow 最好理解, 是逐行写这个这个优化方程:using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using ILOG.Concert;
    using ILOG.CPLEX;namespace CPLEX1
    {
        public class LPex
        {
            //Step 7
             internal static void Usage()
            {
                System.Console.WriteLine("usage: LPex1 <option>");
                System.Console.WriteLine("Options: -r build model row by row");
                System.Console.WriteLine("Options: -c build model colomn by column");
                System.Console.WriteLine("Options: -n build model nonzero by nonzero");
            }
             public static void Main(string[] args)
             {
                 if (args.Length != 1 || args[0].ToCharArray()[0] != '-')
                 {
                     Usage();
                     return;
                 }
                 try
                 {
                     // Step 3
                     //step 3
                     Cplex cplex = new Cplex();
                     INumVar[][] var = new INumVar[1][];
                     IRange[][] rng = new IRange[1][];                 //step 8
                     switch (args[0].ToCharArray()[1])
                     {
                         case 'r': PopulateByRow(cplex, var, rng);
                             break;
                         case 'c': PopulateByColumn(cplex, var, rng);
                             break;
                         case 'n': PopulateByNonzero(cplex, var, rng);
                             break;
                         default: Usage();
                             return;
                     }
                     // Step 11
                     cplex.ExportModel("lpex.lp");
                     //Step 9
                     if (cplex.Solve())
                     {
                         //Step 10
                         double[] x = cplex.GetValues(var[0]);
                         double[] dj = cplex.GetReducedCosts(var[0]);
                         double[] pi = cplex.GetDuals(rng[0]);
                         double[] slack = cplex.GetSlacks(rng[0]);                     cplex.Output().WriteLine("Solution status = " + cplex.GetStatus());
                         cplex.Output().WriteLine("Solution value = " + cplex.ObjValue);                     int nvars = x.Length;                     for (int j = 0; j < nvars; ++j)
                         {
                             cplex.Output().WriteLine("Variable :" + j + " Value= " + x[j] + " Reduced cost = " + dj[j]);
                         }
                         int ncons = slack.Length;                     for (int i = 0; i < ncons; ++i)
                         {
                             cplex.Output().WriteLine("Constraint: " + i + " Slack = " + slack[i] + " pi = " + pi[i]);
                         }
                        Console.ReadKey();                 }
                    
                     cplex.End();                 
                 }
                 catch (ILOG.Concert.Exception e)
                 {
                     System.Console.WriteLine("Concert exception '" + e + " '  caught");
                 }
             }
          
            
                 
            // Step 8
            
            //Step 4
            internal static void PopulateByRow(IMPModeler model, INumVar[][] var, IRange[][] rng)
            {
                double[] lb = { 0.0, 0.0, 0.0 };
                double[] ub = { 40.0, System.Double.MaxValue, System.Double.MaxValue };
                INumVar[] x = model.NumVarArray(3, lb, ub);
                var[0] = x;
                double[] objvals = { 1.0, 2.0, 3.0 };
                model.AddMaximize(model.ScalProd(var[0], objvals));            rng[0] = new IRange[2];
                rng[0][0]=model.AddLe(model.Sum(model.Prod(-1.0,x[0]),model.Prod(1.0,x[1]),model.Prod(1.0,x[2])),20.0);
                rng[0][1] = model.AddLe(model.Sum(model.Prod(1.0, x[0]), model.Prod(-3.0, x[1]), model.Prod(1.0, x[2])), 30.0);
            }
            //Step 5
            internal static void PopulateByColumn(IMPModeler model, INumVar[][] var, IRange[][] rng)
            {
                IObjective obj = model.AddMaximize();
                rng[0] = new IRange[2];
                rng[0][0] = model.AddRange(-System.Double.MaxValue, 20.0);
                rng[0][1] = model.AddRange(-System.Double.MaxValue, 30.0);            IRange r0 = rng[0][0];
                IRange r1 = rng[0][1];            var[0] = new INumVar[3];
                var[0][0] = model.NumVar(model.Column(obj, 1.0).And(model.Column(r0, -1.0).And(model.Column(r1, 1.0))), 0.0, 40.0);            var[0][1] = model.NumVar(model.Column(obj, 2.0).And(model.Column(r0, 1.0).And(model.Column(r1, -3.0))), 0.0, System.Double.MaxValue);
                
                var[0][2] = model.NumVar(model.Column(obj, 3.0).And(model.Column(r0, 1.0).And(model.Column(r1, 1.0))), 0.0, System.Double.MaxValue);        }
            // Step 6
            internal static void PopulateByNonzero(IMPModeler model, INumVar[][] var, IRange[][] rng)
            {
                double[] lb = { 0.0, 0.0, 0.0};
                double[] ub = { 40.0, System.Double.MaxValue, System.Double.MaxValue};
                INumVar[] x = model.NumVarArray(3, lb, ub);
                var[0] = x;
                double[] objvals = { 1.0, 2.0, 3.0 };
                model.Add(model.Maximize(model.ScalProd(x, objvals)));
                rng[0] = new IRange[2];
                rng[0][0] = model.AddRange(-System.Double.MaxValue, 20.0);
                rng[0][1] = model.AddRange(-System.Double.MaxValue, 30.0);
                rng[0][0].Expr = model.Sum(model.Prod(-1.0, x[0]), model.Prod(1.0, x[1]), model.Prod(1.0, x[2]));            rng[0][1].Expr=model.Sum(model.Prod(1.0,x[0]),model.Prod(-3.0,x[1]), model.Prod(1.0, x[2]));            x[0].Name="x1";
                x[1].Name = "x2";
                x[2].Name = "x3";            rng[0][0].Name = "c1";
                rng[0][1].Name="c2";
            }    }   
    }
    再次感谢大家的回复
      

  20.   

    internal static void methodA (IInterf1 face1, IInterf2[][] face2, IInterArray[][] ary)
      {
        double[] lb={1,2,3};
        double[] ub={4,5,6};
        IInterf2[] x= face1.GenerateArray(3, lb, ub): 
        ary[0] = new IInterArray[2]
        ary[0][1]=face1.AddLe( something inside  )
      }
    这里传进来的face1就表示是实现了接口IInterf1的的类。所以face1的方法就是实现类实现的方法。假如借口是模型,则实现类就是用模型做出来的实在的东西了。
      

  21.   

    对于vrhero
     
    的接口解析真的很有道理
      

  22.   


    谢谢回复, 可是我看CPLEX API,每一个接口都有很多成员和方法 比如INumVar和IMPMOdeler, 可没有一句是讲如何实现这些方法的呀。我看他们的API,好多都是只写了overloaded, 这是为什么?IBM CPLex的.net 和Java的API在这个链接:http://publib.boulder.ibm.com/infocenter/cosinfoc/v12r2/index.jsp?topic=/ilog.odms.cplex.help/html/refcallablelibrary/html/overview.html.能帮我彻底搞清楚实在是感激不尽
      

  23.   


    晕。既然是官方的API,那当然是只有接口方法签名,怎么可能公布具体的实现代码?给出一份接口文档来,满足你的调用就可以了。这有什么可糊涂的……
      

  24.   


    抱歉我才学了两星期,一般接口在教材上写的都是只有方法名称没有方法体,当某个类实现了接口要自己写实现接口里方法的代码。 你的意思是说 官方的接口实际上都有实现接口内方法的代码, 而我们只要写签名就能在实现这个接口的类中实现接口的方法。比如interface ISpeeding
    {
    void SpeedAt();}
    而实现这个接口的类是需要打印出超速的速度值来。 如果这个接口像IBM Cplex中的那样是个官方接口,那某个类实现了这接口,打印输出语句就自动生成了? 不明白。难道只要我们签名 写上速度值就能调用输出方法speedAt(speedValue)?
      

  25.   

    举个例子
    比如先有一个方法
    bool Greater(object obj1,object obj2);
    如果obj1大于obj2则返回true。
    但担心使用这个方法的人传入的参数压根就不能比较,所以制定个接口
    interface IComparable{
    int CompareTo(object obj);
    }
    上面的方法就变为
    bool Greater(IComparable obj1,IComparable obj2);
    这里参数类型IComparable的意思是,任何实现了IComparable这个接口的类型。不是所有的object都能行了,要用这个方法先要给自己的类型实现IComparable。IComparable里有CompareTo方法。Greater就变成
    bool Greater(IComparable obj1,IComparable obj2){
    if(obj1.CompareTo(obj2)>0) return true;
    return false;
    然后会发个说明:
    意思是说,如果你想使用Greater方法,并且返回你想要的结果,得按照这个来。不按这个在自己的类型里实现CompareTo方法,使用Greater虽然不给报错,但也不会是正确的结果。怎么实现自己看着办。自己的类型:
    class MyClass{
    string ID;
    public MyClass(string id){ID=id;}
    }
    这个类型目前显然和IComparable一点关系没有,不能传给Greater,要先实现接口
    class MyClass:IComparable{
    string ID;
    public MyClass(string id){ID=id;}
    public void Abc(){do something;}
    public int CompareTo(object obj){return 1;}
    }
    然后
    MyClass c1=new MyClass("lambertapple1");
    MyClass c2=new MyClass("lambertapple2")
    Greater(c1,c2);
    就能运行了,虽然可能不会是想要的结果。如果要获得想要结果,CompareTo具体实现就要参考说明写。
    Greater方法不是只给MyClass用的,很可能有Greater的时候MyClass根本就不存在。如果之后又有了MyClass2,只要给MyClass2也实现了IComparable,就也能当Greater的参数。由于在使用的时候只关心CompareTo方法,不关心Abc里do了什么,所以也可以这么写
    IComparable c1=new MyClass("lambertapple1");
    IComparable c2=new MyClass("lambertapple2")
    Greater(c1,c2);
    这时候c1和c2只能用CompareTo方法,Abc用不了,要用Abc得先转类型
      

  26.   

    悲剧啊,不能编辑自己的类型:
    class MyClass{
    string ID;
    public MyClass(string id){ID=id;}
    }
    应为自己的类型:
    class MyClass{
    string ID;
    public void Abc(){do something;}
    public MyClass(string id){ID=id;}
    }
      

  27.   

    传递接口作为参数的目的在于在调用时决定使用哪个具体对象,但方法本身只关系要执行的动作简单实现如下:
    定义运行的接口
    inferface IRun
    {
       void Run();
    }class dog:IRun
    {
        void Run()
        {
            Console.WriteLine("狗在跑");
        }
    }class cat:IRun
    {
        void Run()
        {
            Console.WriteLine("猫在跑");
        }
    } class Program
     {
        static void Main(string[] args)
        {
            //我只关系要什么去跑,
            IRun dog=new dog();
            Run(dog);
            IRun cat=new cat();
            Run(cat);
        }    static void Run(IRun object)
        {
            //我只管跑
            object.Run();
        }
    }
      

  28.   

    不能编辑interface写错手动写代码有这样的问题,无语
      

  29.   


    您这个例子里至少在继承接口的类中自己定义了run()方法, 然后调用接口生成新的实现了接口的对象。可是IBM CPLEX里根本就没有对继承了接口的类的方法的实现代码,而直接就用接口生成实现了接口的类的对象, 究竟怎么实现的完全没有交代。
      

  30.   


    你要关注的是在调用LPex.methodA(...)是否传递的对象实现了IInterf1接口我那个例子中的
    static void Run(IRun object)
      {
      //我只管跑
      object.Run();
      }
    就相当于你的methodA
      

  31.   

    vrhero  比喻太强了 ,膜拜