【问题标题】:whose instance is created in below line of code其实例是在下面的代码行中创建的
【发布时间】:2014-09-12 07:33:01
【问题描述】:

this question 的回答说“你没有创建接口的实例..”我想知道这是不是真的。

谁能告诉我谁的实例是在下面的代码行中创建的?为什么?

BaseClass b= new Child();

 BaseInterface bi= new Child();

编辑:我问的是 C#.net 语言。如果实例是由 child() 创建的。为什么visual studio的intellisense在按下时会显示Base成员?

【问题讨论】:

  • 它的 c# 代码。 Child 派生自 BaseClass(Class) 以及 BaseInterface(Interface)。
  • new Child() 实际创建;然后它被访问为BaseInterface
  • @Akie 我相信你需要更多地学习 OOP。学习 OOP 可以很容易地回答这个问题。请不要误解我的意思:这是一个过于基本的问题。

标签: c# oop inheritance interface


【解决方案1】:

创建的实际对象是子类的实例

“向上转换”只是相同子对象实例的不同视图

静态类型语言根据表达式的类型限制操作,而不是表达式计算的实际对象的类型。因此,IntelliSense 将只显示适用于 b 的 BaseClass 和 bi 的 BaseInterface 的方法。

这也是为什么像Object o = new Child() 这样的东西是有效的,尽管只有在Object 上定义的方法可以在o 上调用,这是一个类型为Object 的表达式

实际的对象一个孩子的事实可以这样证明:

Child c = new Child();
BaseClass b = c;
BaseInterface bi = c;
c.GetType() == typeof(Child)     // => true
object.ReferenceEquals(c, b)     // => true
object.ReferenceEquals(c, bi)    // => true

【讨论】:

  • 你的意思是说子类对象被创建然后向上转换到Base?如果是这样,我们可以说最终对象是Base吗?
  • @Akie 不。该对象是一个孩子,并且永远是一个孩子。 视图(“可以执行的操作”)是基本类型(或实现的接口)。
  • 哦好吧..有道理。还有一件事,如果是孩子的实例,为什么不允许我使用 b 或 bi 访问 Child 的成员?
  • @Akie 因为 view 是 BaseClass/BaseInterface 的。想象一下,如果有两种子类型,ChildA 和 ChildB。 ChildA 定义了一个方法methodA,ChildB 定义了一个方法methodB(这个方法的作用无关紧要)。由于它们都是 BaseClass 的子级,因此可以将它们分配给 b。但是,由于 表达式类型 用于静态类型系统,因此只允许为 BaseClass 定义的方法。这可以防止出现这样的情况:BaseClass x = new ChildA(); x.methodB();(其中 methodB 仅在 ChildB 中定义,但在 ChildA 中没有定义,它是实际创建的对象)。
  • 因为您自己说过您只想将 b 或 bi 的视图放在孩子身上。只要它是一个孩子,你总是可以再次向下转换为 Child,但变量类型是你定义的类型,只有那些方法是可调用的。
【解决方案2】:

这是一个非常基本的问题,也是一个非常非常重要的问题。但我不确定这个网站是获得答案的最佳媒介(更重要的是,理解它)。尝试在某处学习 OOP 课程,或查找详细介绍它的在线演示文稿。

简答

运行时类型和静态类型是两个非常不同的东西。

更长的答案:

在静态类型语言如 C#(或 java、F# 或其他一堆)中,变量始终具有静态类型。静态类型是编译器证明变量的类型,因为你告诉它它是,或者因为它推断它(例如在 var 或 lambda 参数的情况下)。

一些例子:

int i; //i is of type int
BaseClass b; //b is of class BaseClass
IEnumerable<int> list; //list implements interface IEnumerable<int>
var s = "foo"; //s is inferred to be of type string

这是静态类型。这意味着变量是给定的类型。这并不意味着变量中的对象是这种类型(这对接口来说甚至没有意义!),它只是意味着编译器有证据证明里面的对象可以分配给这种类型(这意味着它可以是放入该类型的变量/字段中)。

对比运行时类型。运行时类型是实例的实际类型。它只是一个运行时的东西,编译器无法访问它。它是有效的。

当你静态地进行方法和属性调用时,你只能从静态类型中调用属性和方法。仅仅因为它是编译器可以知道的唯一类型。当你写作时

BaseInterface bi= new Child();

您实际上是在告诉编译器“我要求您忘记这个对象是Child,将其视为BaseInterface”。这正是编译器所做的:您无法访问特定于 Child 类的 bi 成员。

事实上,这个赋值只是进行两个非常不同的操作的一种捷径。是一样的

BaseInterface bi; // I create a "bi" variable. Its static type is BaseInterface
bi = new Child() // Instanciate an object of runtime type Child and assign it to the bi variable

给变量赋值不会改变它的静态类型。

【讨论】:

    【解决方案3】:

    BaseClass b= new Child(); - new Child() 调用 Child 类的构造函数初始化对象(创建一个新实例),引用类型将是基类。 所以如果 BaseClass a 有 baseClassMet() 并且 class Child() 有一个额外的方法 childMet(),你可以调用只在 BaseClass 中定义的方法。

    BaseInterface bi=new Child();首先使用接口,您不能直接实例化接口。您可以为接口分配实现该接口的类。

    所以在这种情况下,假设 Base 接口有一个方法定义 void interfMet(); 如您所知,在实现此接口的类中,您有义务实现此方法。 作为 BaseInterface 类型的对象引用 bi 只能访问接口声明的方法。您不能使用 Child 类的 bi(接口引用类型)方法。 如果您真的想访问 Child 的方法,则必须进行强制转换。 希望对您有所帮助。

    interface BaseInterface{ void interMet(); } class BaseClass{ void baseClassMet(){ System.out.println("baseClassMet method in superclass"); } } public class Child extends BaseClass implements BaseInterface{ //overrided method void baseClassMet(){ System.out.println("baseClass method in extended class"); } //method of child void childMet(){ System.out.println("Child met"); } public void interMet() { System.out.println("Implemented method"); } public static void main(String[] args) { Child c = new Child(); c.baseClassMet();// prints "baseClass method in extended class" BaseClass b = new Child(); b.baseClassMet();// prints "baseClass method in extended class" b.childMet//can't access object method childMet() like this // Does not compile ((Child)b).childMet();//you can do it like this telling the compiler that //you are sure that b point to a Child object BaseClass b1 = new BaseClass(); b1.baseClassMet();//prints "baseClassMet method in superclass" BaseInterface bi = new Child();//assigning bi of type BaseInterface(interface) the object Child bi.interMet(); // this prints "Child met" }}

    【讨论】:

      【解决方案4】:

      引用的声明类型是您选择与 Child 实例交互的透视图,透视图 oopingly 是 Child 的超类或接口。

      【讨论】:

        猜你喜欢
        • 2019-05-05
        • 1970-01-01
        • 2018-07-05
        • 2016-07-03
        • 1970-01-01
        • 1970-01-01
        • 2016-06-01
        • 1970-01-01
        • 2014-07-08
        相关资源
        最近更新 更多