继续之前:
这是一个绝对抽象的问题。不要问你想做什么。
这就是事情:
用两种不同的语法看这两段代码。 (语法?)
我几乎完全使用第二个,并且在第二个中使用另一个在另一个中不可能的能力。
我不知道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;
}
方法链:
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
修改:
在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。两个更新的答案都是可接受的答案。
答案 0 :(得分:2)
这个答案适用于Java,但我相信C#也是一样。
this
和super
都是同一个对象。作为对象参考,没有区别。
所以否,不需要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
用作值。