为什么要将类 2 的引用放入类 1 的对象中
本文关键字:对象 引用 为什么 | 更新日期: 2023-09-27 18:30:39
好的,所以我遇到了这个代码片段:
class1 a = new class1();
a.Test();
class1 b = new class2();
b.Test();
它与虚拟和覆盖有关,但现在的问题是:为什么键入
class1 b = new class2();
当你可以只输入
class2 b = new class2();
因为两个解决方案具有相同的输出
class1显然是class2的超类。这样,例如,您可以拥有一个 class1 对象的列表,所有对象都包含 class1 或 class2 对象。您可以简单地将 a 和 b 添加到该列表中而不会出现问题。
class Class1 {
public virtual void test(){
//do something
{
}
class Class2 : Class1 {
public override void test(){
// do something else
}
}
IList<Class1> list = new List<Class1>();
Class1 a = new Class1();
Class1 b = new Class2();
list.add(a);
list.add(b);
然后,尝试从该列表中获取项目,您只需执行以下操作:
list[0].test(); //calls test of Class1
list[1].test(); //calls test of Class2
这个概念被称为多态性(poly=many,morph=shape)。
在方法上使用"new"关键字而不是"override"的派生类的行为会有所不同,具体取决于它的转换方式。
例:
class Class1
{
public virtual void DoSomething
{
Console.WriteLine("Class1.DoSomething");
}
}
class Class2 : Class1
{
public new void DoSomething
{
Console.WriteLine("Class2.DoSomething");
}
}
class Class3 : Class1
{
public override void DoSomething
{
Console.WriteLine("Class3.DoSomething");
}
}
类 2 和类 3 派生自类 1,但类 2 使用"new"关键字"隐藏"类 1 的虚拟成员,而类 3 使用"override"关键字"覆盖"类 1 的虚拟成员。以下是以自己的类型为幌子使用这些类时发生的情况:
Class1 one = new Class1();
one.DoSomething(); // outputs "Class1.DoSomething"
Class2 two = new Class2();
two.DoSomething(); // outputs "Class2.DoSomething"
Class3 three = new Class3();
three.DoSomething(); // outputs "Class3.DoSomething"
它们都按预期输出正确的类名。但是,当您以类 1 为幌子使用这些类时,就会发生这种情况:
Class1 one = new Class1();
one.DoSomething(); // outputs "Class1.DoSomething"
Class1 two = new Class2();
two.DoSomething(); // outputs "Class1.DoSomething"
Class1 three = new Class3();
three.DoSomething(); // outputs "Class3.DoSomething"
由于类 2 "隐藏"了该方法,因此当用作自己的类型时,它将输出"Class2.DoSomething",但在用作其基类型时将输出"Class1.DoSomething"。但是因为类 3 "重写"了该方法,所以无论它是用作自己的类型还是基类型,它都会输出"Class3.DoSomething"——因为它"重写"了基类型的功能。
(这样做的另一个效果是,如果Class2
或Class3
有其他方法,例如DoSomethingElse
,您将无法调用Class1 two = new Class2(); two.DoSomethingElse()
,因为Class1
没有该方法。
我不知道有任何现实世界的用例,但它就在那里,这是我能想到的唯一方法,使用Class1 class2 = new Class2()
可以提供任何真正的用途。如果Class2
不"隐藏"Class1
的任何成员,那么就没有真正的好处。
请参阅:http://msdn.microsoft.com/en-us/library/ms173153.aspx
比方说,B1
和 B2
都源自 A
。然后,您可能直到运行时才知道您有B1
还是B2
。在这种情况下,您必须静态概化为可以容纳这两种子类型的A
。如果继承使用正确,则无需关心具体的运行时类型是什么。
例:
A a = GetA();
A GetA() {
if (Random()) return new B1();
else return new B2();
}
因为它可以是B1
和B2
,所以你必须对变量类型(A
)使用公共基类。
这是一个抽象和松散耦合的问题。如果代码仅取决于 'class1' 的类型,而不依赖于 'class2' 的细节(它是 class1 的特定子类),那么代码更通用,您可以轻松地切换到 class1 的不同子类型,而无需更改其他代码。
举个例子:假设你有一个抽象List
类。它有两个子类,ArrayList
和LinkedList
。它们的工作方式或多或少相同(作为项目列表),但实现方式不同,从而赋予它们不同的性能特征。编写代码时,不确定哪种实现最适合您的代码。因此,您希望以不依赖于任何特定子类的细节的方式编写代码。
如果你的代码只关心类是一个List
,那么你只需要命名一次具体的子类:
List x = new LinkedList();
在其他任何地方,您可以将其视为更通用的List
类。这确保了两件事:
- 如果您决定使用
ArrayList
而不是LinkedList
,则只需在一个位置更改代码。 - 您不会意外地依赖于其中一个具体子类的实现特定细节,例如,通过调用仅存在于其中一个子类上的方法。通过强制转换为基类,类型检查器可确保只能调用所有子类共享的方法。这再次意味着您可以更轻松地交换实现。
例如,List
将定义一些方法和属性,例如Count
和Item
,然后所有子类都将支持这些方法和属性。但是特定的子类也可能定义额外的方法,比如Resize
用于ArrayList
和IsCircular
用于LinkedList
,这只对特定的子类有意义。
通过将变量声明为更通用的类型 List
,可以确保您不会依赖于某些特定于子类的方法或属性,因为编译器根本不允许您使用它们。
称为多态性。简而言之,它允许您创建多个子类并将它们视为父类,这具有一些优点,例如防止代码重复。
我将添加另一个答案来解决为什么有人在他的正常头脑中会像那样输入它的问题。
唯一可能表现不同的情况是,如果class2
和class1
都具有同名的方法,但不使用虚拟继承。这可以使用 new
关键字(或根本没有关键字,它会编译但会触发当之无愧的警告)来完成。
这是糟糕的风格,几乎从来没用。这可能不是他的本意。
以这种方式编写它以记录仅使用class1
成员的事实可能仍然有意义。他可能会说,它确实是运行时的class2
这一事实并没有发挥作用。这很可能是因为虚拟继承。
因此,这可能纯粹是为了记录意图。
我可以解释Java中的情况,这同样适用于C#
从下面的代码中,我创建了一个引用 World class 的对象 (obj)。
由于 World 扩展了印度和比利时类,我们可以使用相同的对象 (obj) 来访问两个类的方法,这种符号是为了提高代码的效率。遵循相同的表示法也不是强制性的。
希望我已经回答了您的问题,如果有任何疑问,请告诉我:)
类世界 {
public void printName() {
System.out.println("Name is: World");
}
}
类 印度扩展世界 {
public void printName() {
System.out.println("Name is: India");
}
}类 比利时扩展世界 {
public void printName() {
System.out.println("Name is: Belgium");
}
}公共类 地理 {
public static void main(String[] args){
World obj; // Declaring an Object referencing World Super Class
obj = new India(); // Allocating M/m to India class (All V & M Ind & World Class)
obj.printName();
// Allocating Same Object M/m to Belgium class (All V & M BGM & World Class)
obj = new Belgium();
obj.printName();
}
}
您可以使用这个在"工厂"模式中安装的示例。这是我能想到的第一个用法。