你能在Java / C#中返回super吗? (如果可以,它会有用吗?)

时间:2017-06-26 20:11:52

标签: javascript oop method-chaining

继续之前:
这是一个绝对抽象的问题。不要问你想做什么。

这就是事情:
用两种不同的语法看这两段代码。 (语法?)
我几乎完全使用第二个,并且在第二个中使用另一个在另一个中不可能的能力。
我不知道Java / C#中的OO 我想知道Java / C#在这个能力上的立场。
我的问题是关于这种能力,以及:
    如果在C#/ Java中可以实现这种能力? (我知道在第一种语法中它是不可能的)
    就C#/ Java中的OO原则而言,这是完全有缺陷的吗? (因为我认为可能存在第一种语法中不可能的原因)     这是不受欢迎的事吗?

虽然我对这个术语不太确定,但我所说的这种能力正在使超级人物退缩。

第一种语法:(这是es6的东西)

var log = console.log;

class Gender {
    constructor(type) {
        this.gender = type;
    }
    sayGender() {
        log(this.gender);
        return this;
    }
}
class Person extends Gender {
    constructor(gender, name, age) {
        super(gender);
        this.name = name;
        this.age = age;
    }
    sayName() {
        log(this.name);
        return this;
    }
    sayAge() {
        log(this.age);
        return this;
    }
    saySomething() {
    // only limited access to super methods.
    // access limited to calling super methods/getters/setters and not public properties.
    // (also not possible to return them since they're just imaginary refrences and not values)
    // this === invoked instance
    // super === reference to implicit derived instance (not returnable since not value)
    // no access to super/base instance (instance of Person)
    log("you can't break the chain here, even if u wanted to");
    return this;
}
class Employee extends Person {
    constructor(gender, name, age, jobTitle) {
        super(gender, name, age);
        this.jobTitle = jobTitle;
    }
    sayJob() {
        log(this.jobTitle);
        return this;
    }
}

这是第二种语法

var log = console.log;
function newGender(type) {
    let inst = {};
    inst.gender = type;

    inst.sayGender = function () {
        log(gender); // or this.gender if u want (but context-less calls will no longer be available)
        return this;
    };

    return inst;
}
function newPerson(gender, name, age) {
    let _super_ = newGender(gender);
    let inst = Object.create( _super_ );

    let privateVariable;
    function privateFunction() {} // not possible with the other syntax

    inst.name = name;
    inst.age = age;

    inst.sayName = function () {
        log(name);
        return this;
    };
    inst.sayAge = function () {
        log(age);
        return this;
    };
    inst.saySomething = function () {
    // full access to super/base, derived, and invoked instances. (even returning them since they're values now).
    // differentiation between super/base, derived, and invoked instances in the context of current class.
    // _super_ === base instance
    // inst === derived instance
    // this === invoked instance
    log("you can break the chain here if u want");
    return inst;
    };

    return inst;
}
function newEmployee(gender, name, age, jobTitle) {
    let _super_ = newPerson(gender, name, age);
    let inst = Object.create( _super_ );

    inst.jobTitle = jobTitle;

    inst.sayJob = function () {
        log(jobTitle);
        return this;
    };

    return inst;
}

的diff:

方法链:

var t = new Employee("male", "mohammad", 28, "web developer")
t.sayGender()        //  "male"
    .sayName()       //  "mohammad"
    .sayAge()        //  28
    .saySomething()  //  "you can't break the chain here, even if u wanted to"
    .sayJob()        //  "web developer"

var t = newEmployee("male", "mohammad", 28, "web developer")
t.sayGender()        //  "male"
    .sayName()       //  "mohammad"
    .sayAge()        //  28
    .saySomething()  //  "you can break the chain here if u want"
    // I can't chain after this point since I returned the super and sayJob() is not defined on it.
    .sayJob()        //  "web developer"

无环境调用:

var t = new Employee("male", "mohammad", 28, "web developer")
var sayJob = t.sayJob;
sayJob() // TypeError: Cannot read property 'jobTitle' of undefined

var t = newEmployee("male", "mohammad", 28, "web developer")
var sayJob = t.sayJob;
sayJob() // web developer

修改:

问题不在于Java或C#或JavaScript。

在JavaScript中使用new)调用派生类的构造函数时 有一个隐式超级实例可用于派生实例(因为所有派生类构造函数都必须包含super()调用)。但是你只能使用这个隐式实例的方法(和getter / setter)而不是属性 因此,在sayName()类的Person方法中,我可以说super.someMethod()super["name of a setter"] = "a value";super["name of a getter"]; // and u can read it

所以我可以访问超级实例,但我的访问权限有限。 因此,为什么你不能返回它,是的我知道super不是一个值=))))。
现在假设您可以完全访问super指向的实例。对不对?
我完全访问的意思是想象你在那里得到那个实例作为一个值,所以现在你可以返回它或者其他什么。

我要问你的是,如果你是一名Java / C#开发人员并且你经常使用等级继承并且有这方面的经验,明天我会出现在你工作的地方,或者发送电子邮件你或者我会告诉你我有一个重大消息:
从今天开始,Java / C#lang将会有两个变化:
1 super现在指向基类实例 2 super现在是一个值,是派生类上下文中的实际实例,您可以随意执行任何操作。你甚至可以用一种方法返回它!
你说什么?你的想法是什么?

(一种情况是现在一个方法可以返回超级实例,如果有人从外部链接某些方法并调用此方法,则将返回的下一个实例将不再具有派生实例方法)

最终编辑:我在评论讨论后写这个问题的方式(虽然我不确定这种方式是否更好,因为它更长):

在JavaScript中,一个类的行为如下:(当我说一个类时我的意思是伪经典继承,我们假装它与底层原型系统一起)
它必须有一个构造函数,当你使用new kewrod(var t = new Person())实例化它时,你必须得到该类的实例(或对象)。 所以当你定义你的班级时,例如:

class Person() { // from this curly

} // to this curly  

如果有人调用new,您可以引用将创建的实例 到目前为止并不复杂。让我们继续吧。 所以一个类可以从另一个类派生。而这件事增加了复杂性。为什么?好吧,让我们看看:
现在我们必须完成派生类的行为 派生类与基类共享相同的行为,除了少数几个:
派生类有一个构造函数,在这些curlies中你将引用实例(将在调用new之后创建),以及所有这些,就像基类一样。
但是派生类有一些它不与基类共享的行为。所以让我们通过它们,这里是派生类的定义:

class Employee extends Person {
    constructor() {
        super()
    }
}

派生类虽然有一个类似基类的构造函数,但它还有一个附加规则:它的构造函数必须包含一个super()调用,它的作用是它将调用基类构造函数。所以现在,在this关键字(即要创建的实例)的派生类的curlies中,我们还有一个super关键字。
super关键字允许您执行的操作是引用一个与this类似的对象,除非您调用new没有它&# 39;不是那个对象,它是你实例化基类(new Person())时会得到的对象,但它不同于你手动实例化那个基类,它是如何区别的?它有所不同,因为如果您通过new调用手动同步该基类,您将获得该类的所有公共方法,属性,getter和setter。但这并不是super关键字发生的事情。 所以使用super关键字虽然你实际上是引用了基类的那个实例,但是你的派生实例(在curlies里面)有一个(隐式的)基类实例,你不会得到要访问该实例的属性(甚至是公共属性),您只能使用公共方法。 (虽然在es6 js中没有公共私人,但让我们假装它是。就像打字稿一样)。
所以现在我们看到,在一个划分类的curlies中,我们可以访问该实例,虽然仅限于方法,但仍然可以访问并且重要的是要记住super关键字就像一个想象的东西而不是一个值。

所以到目前为止一切正常没什么特别的。这就是我的困境:
由于JavaScript内部系统,我有能力为我提供了一个选项,当我构建对象时,让我们看看这个能力是什么,更重要的是我最后关于这个能力的问题:
我一直提到的这个能力是:
记得我说:super就像你手动实例化但有限制的基类实例?好吧,我现在可以将super视为真的是我手动实例化的基类实例。所以现在我不仅可以访问它的所有成员(属性和方法)而不受super的限制,但由于它现在是一个值,我可以在派生方法中返回它同样,并导致连锁断裂(我觉得它更好,没有,不需要等等)。

以下是迄今为止我能提出的两项能力:

#1 一方面是当您使用类语法链接方法时,我总是会有一个实例,一个对象。并在链中的一步之后。我可以访问该实例的所有方法,并且其中一些方法被拥有而其中一些方法被继承的事实并不重要。但是价值种类super我可以在该链中设置止损。那有什么用呢呢?嗯,我不确定,但我现在想到的可能是我可以有一个提示来区分自有和继承的方法。所以现在如果一个方法打破了链条,我知道该方法是在层次结构的某个地方继承的。

#2 另一个方面是无上下文的调用,但是让我们感到厌烦,因为我不确定Java / C#中是否有这样的东西。 (但很快就要明确了:无上下文调用意味着你在没有上下文的情况下调用方法,换句话说,没有提供this关键字指向哪个对象)。

这两种能力让我感到困惑,因为我不知道OO的推理方式我想知道(比如我的手背),所以虽然我喜欢这些能力,但我还是#39 ;我不确定他们将在哪里领导系统。而且我不知道如何衡量它或如何预测它的未来,所以我想要求Java / C#程序员的意见。

P.S。两个更新的答案都是可接受的答案。

2 个答案:

答案 0 :(得分:2)

这个答案适用于Java,但我相信C#也是一样。

thissuper都是同一个对象。作为对象参考,没有区别。

所以,不需要return super,因此这不是有效的语法,但是你可以return this,这是也是super的参考。

<强>更新

更新的问题是关于方法链,以及是否可以从方法返回基类,因此链中的下一个方法调用不能使用子类中的方法。

答案是肯定的,不是。

是的,您可以将声明的方法返回类型更改为基类。由于Java是静态类型的,因此只有在基类中声明的方法才可用于下一个方法调用。

不,你不能完全限制对基类方法的方法调用,因为返回的对象仍然是子类,即使编译器不知道,以及重写的基类的任何方法子类仍然会调用子类方法,即使声明的类型是基类。

这种差异是类与原型继承模型的一个方面,以及两种语言的静态与动态类型(分别是Java与JavaScript)。

答案 1 :(得分:0)

Java不允许您将super用作值。你不能退货。并且您不需要返回它,因为您可以使用this引用该对象。

在Java中,类的实例由一个对象表示。超类不由单独的对象表示。

类支持从超类继承实现。这允许我们编写子类使用或覆盖的公共代码。

超类和接口支持 polymorphism 。例如,超类类型的引用可用于从子类对象调用方法。这允许我们利用Liskov Substitution Principle编写一次可以处理多种类型的代码。这有助于我们not repeat ourselves。来自Java语言规范,section 1.1: 1.1 Organization of the Specification

  

类支持单实现继承,其中每个类的实现都是从单个超类的实现派生的...类类型的变量可以引用该类的实例或该类的任何子类的实例,从而允许新类型与现有方法一起使用,多态。

Java允许您使用关键字super引用超类 - 但仅限于:

  • 使用参数
  • 调用超类构造函数
  • 从子类中访问超类的成员。

详细

来自Java语言规范,第8.8.7.1节,Explicit constructor invocations

  

超类构造函数调用以关键字super(可能以显式类型参数开头)或Primary表达式或ExpressionName开头。它们用于调用直接超类的构造函数。

来自Java语言规范,第15.11.2节,Accessing Superclass Members using super

  

表单super.Identifier是指当前对象的名为Identifier的字段,但当前对象被视为当前类的超类的实例。

所以super是一个关键字。但该语言不支持将super用作值。