C#中Override关键字和New关键字的用法详解

C# 语言经过专门设计,以便不同库中的基类与派生类之间的版本控制可以不断向前发展,同时保持向后兼容。这具有多方面的意义。例如,这意味着在基类中引入与派生类中的某个成员具有相同名称的新成员在 C# 中是完全支持的,不会导致意外行为。它还意味着类必须显式声明某方法是要重写一个继承方法,还是一个隐藏具有类似名称的继承方法的新方法。
在 C# 中,派生类可以包含与基类方法同名的方法。
基类方法必须定义为 virtual。

  • 如果派生类中的方法前面没有 new 或 override 关键字,则编译器将发出警告,该方法将有如存在 new 关键字一样执行操作。
  • 如果派生类中的方法前面带有 new 关键字,则该方法被定义为独立于基类中的方法。
  • 如果派生类中的方法前面带有 override 关键字,则派生类的对象将调用该方法,而不是调用基类方法。

可以从派生类中使用 base 关键字调用基类方法。

override、virtual 和 new 关键字还可以用于属性、索引器和事件中。
默认情况下,C# 方法为非虚方法。如果某个方法被声明为虚方法,则继承该方法的任何类都可以实现它自己的版本。若要使方法成为虚方法,必须在基类的方法声明中使用 virtual 修饰符。然后,派生类可以使用 override 关键字重写基虚方法,或使用 new 关键字隐藏基类中的虚方法。如果 override 关键字和 new 关键字均未指定,编译器将发出警告,并且派生类中的方法将隐藏基类中的方法。
为了在实践中演示上述情况,我们暂时假定公司 A 创建了一个名为 GraphicsClass 的类,您的程序将使用此类。 GraphicsClass 如下所示:

class GraphicsClass
{
  public virtual void DrawLine() { }
  public virtual void DrawPoint() { }
}

您的公司使用此类,并且您在添加新方法时将其用来派生自己的类:

class YourDerivedGraphicsClass : GraphicsClass
{
  public void DrawRectangle() { }
}

您的应用程序运行正常,直到公司 A 发布了 GraphicsClass 的新版本,类似于下面的代码:

class GraphicsClass
{
  public virtual void DrawLine() { }
  public virtual void DrawPoint() { }
  public virtual void DrawRectangle() { }
}

现在,GraphicsClass 的新版本中包含一个名为 DrawRectangle 的方法。开始时,没有出现任何问题。新版本仍然与旧版本保持二进制兼容。已经部署的任何软件都将继续正常工作,即使新类已安装到这些软件所在的计算机系统上。在您的派生类中,对方法 DrawRectangle 的任何现有调用将继续引用您的版本。
但是,一旦您使用 GraphicsClass 的新版本重新编译应用程序,就会收到来自编译器的警告 CS0108。此警告提示您必须考虑希望 DrawRectangle 方法在应用程序中的工作方式。
如果您希望自己的方法重写新的基类方法,请使用 override 关键字:

class YourDerivedGraphicsClass : GraphicsClass
{
  public override void DrawRectangle() { }
}

override 关键字可确保派生自 YourDerivedGraphicsClass 的任何对象都将使用 DrawRectangle 的派生类版本。派生自 YourDerivedGraphicsClass 的对象仍可以使用基关键字访问 DrawRectangle 的基类版本:

base.DrawRectangle();

如果您不希望自己的方法重写新的基类方法,则需要注意以下事项。为了避免这两个方法之间发生混淆,可以重命名您的方法。这可能很耗费时间且容易出错,而且在某些情况下并不可行。但是,如果您的项目相对较小,则可以使用 Visual Studio 的重构选项来重命名方法。

或者,也可以通过在派生类定义中使用关键字 new 来防止出现该警告:

class YourDerivedGraphicsClass : GraphicsClass
{
  public new void DrawRectangle() { }
}

使用 new 关键字可告诉编译器您的定义将隐藏基类中包含的定义。这是默认行为。
重写和方法选择
当在类中指定方法时,如果有多个方法与调用兼容(例如,存在两种同名的方法,并且其参数与传递的参数兼容),则 C# 编译器将选择最佳方法进行调用。下面的方法将是兼容的:

public class Derived : Base
{
  public override void DoWork(int param) { }
  public void DoWork(double param) { }
}

在 Derived 的一个实例中调用 DoWork 时,C# 编译器将首先尝试使该调用与最初在 Derived 上声明的 DoWork 版本兼容。重写方法不被视为是在类上进行声明的,而是在基类上声明的方法的新实现。仅当 C# 编译器无法将方法调用与 Derived 上的原始方法匹配时,它才尝试将该调用与具有相同名称和兼容参数的重写方法匹配。例如:

int val = 5;
Derived d = new Derived();
d.DoWork(val); // Calls DoWork(double).

由于变量 val 可以隐式转换为 double 类型,因此 C# 编译器将调用 DoWork(double),而不是 DoWork(int)。有两种方法可以避免此情况。首先,避免将新方法声明为与虚方法同名。其次,可以通过将 Derived 的实例强制转换为 Base 来使 C# 编译器搜索基类方法列表,从而使其调用虚方法。由于是虚方法,因此将调用 Derived 上的 DoWork(int) 的实现。例如:

((Base)d).DoWork(val); // Calls DoWork(int) on Derived.

何时使用 Override 和 New 关键字
在 C# 中,派生类中方法的名称可与基类中方法的名称相同。可通过使用 new 和 override 关键字指定方法互动的方式。 override 修饰符 extends 基类方法,且 new 修饰符将其“隐藏”起来。这种区别在本主题中的示例显示出来。
在控制台应用程序中,声明下面的 BaseClass 和 DerivedClass 两个类. DerivedClass 继承自 BaseClass。

class BaseClass
{
  public void Method1()
  {
    Console.WriteLine("Base - Method1");
  }
}

class DerivedClass : BaseClass
{
  public void Method2()
  {
    Console.WriteLine("Derived - Method2");
  }
}

在 Main 方法中,声明变量 bc、dc 和 bcdc。

  • bc 的类型为 BaseClass,并且其值的类型为 BaseClass。
  • dc的类型为 DerivedClass,并且其值的类型为 DerivedClass。
  • bcdc的类型为 BaseClass,并且其值的类型为 DerivedClass。这是要密切注意的变量。

由于 bc 和 bcdc 具有类型 BaseClass,因此,除非您使用强制转换,否则它们只会直接访问 Method1。变量 dc 可以访问 Method1 和 Method2。下面的代码演示这些关系。

class Program
{
  static void Main(string[] args)
  {
    BaseClass bc = new BaseClass();
    DerivedClass dc = new DerivedClass();
    BaseClass bcdc = new DerivedClass();

    bc.Method1();
    dc.Method1();
    dc.Method2();
    bcdc.Method1();
  }
  // Output:
  // Base - Method1
  // Base - Method1
  // Derived - Method2
  // Base - Method1
}

接下来,将以下 Method2 方法添加到 BaseClass。此方法的签名与 DerivedClass 中 Method2 方法的签名相匹配。

public void Method2()
{
  Console.WriteLine("Base - Method2");
}

由于 BaseClass 现在有 Method2 方法,因此可以为 BaseClass 变量 bc 和 bcdc 添加第二个调用语句,如下面的代码所示。

bc.Method1();
bc.Method2();
dc.Method1();
dc.Method2();
bcdc.Method1();
bcdc.Method2();

当生成项目时,您将看到在 BaseClass 中添加 Method2 方法将引发警告。警告提示,DerivedClass 中的 Method2 方法将 Method2 方法隐藏在 BaseClass 中。如果要获得该结果,则建议您使用 Method2 定义中的 new 关键字。或者,可以重命名 Method2 方法之一来解决警告,但这始终不实用。
在添加 new 之前,运行该程序以查看其他调用语句生成的输出。显示以下结果。

输出:

Base - Method1
Base - Method2
Base - Method1
Derived - Method2
Base - Method1
Base - Method2

new 关键字可以保留生成输出的关系,但它将取消警告。具有 BaseClass 类型的变量继续访问 BaseClass 成员,具有 DerivedClass 类型的变量首先继续访问 DerivedClass 中的成员,然后再考虑从 BaseClass 继承的成员.
要禁止显示警告,请向 DerivedClass 中的 Method2 定义添加 new 修饰符,如下面的示例所示:可在 public 前后添加修饰符。

public new void Method2()
{
  Console.WriteLine("Derived - Method2");
}

再次运行该程序以确认没有更改输出。还确认警告不再出现。通过使用 new,您断言您了解它修改的成员将隐藏从基类继承的成员。关于通过继承隐藏名称的更多信息,请参见 new 修饰符(C# 参考)。
要将此行为与使用 override 的效果进行对比,请将以下方法添加到 DerivedClass。可在 public 的前面或后面添加 override 修饰符。

public override void Method1()
{
  Console.WriteLine("Derived - Method1");
}

将 virtual 修饰符添加到 BaseClass 中的 Method1 的定义。可在 public 的前面或后面添加 virtual 修饰符。

public virtual void Method1()
{
  Console.WriteLine("Base - Method1");
}

再次运行项目。尤其请注意下面输出的最后两行。

输出:

Base - Method1
Base - Method2
Derived - Method1
Derived - Method2
Derived - Method1
Base - Method2

使用 override 修饰符使 bcdc 能够访问 DerivedClass 中定义的 Method1 方法。通常,这是继承层次结构中所需的行为。让具有从派生类创建的值的对象使用派生类中定义的方法。通过使用 override 扩展基类方法可实现该行为。
下面的代码包括完整的示例。

using System;
using System.Text;

namespace OverrideAndNew
{
  class Program
  {
    static void Main(string[] args)
    {
      BaseClass bc = new BaseClass();
      DerivedClass dc = new DerivedClass();
      BaseClass bcdc = new DerivedClass();

      // The following two calls do what you would expect. They call
      // the methods that are defined in BaseClass.
      bc.Method1();
      bc.Method2();
      // Output:
      // Base - Method1
      // Base - Method2

      // The following two calls do what you would expect. They call
      // the methods that are defined in DerivedClass.
      dc.Method1();
      dc.Method2();
      // Output:
      // Derived - Method1
      // Derived - Method2

      // The following two calls produce different results, depending
      // on whether override (Method1) or new (Method2) is used.
      bcdc.Method1();
      bcdc.Method2();
      // Output:
      // Derived - Method1
      // Base - Method2
    }
  }

  class BaseClass
  {
    public virtual void Method1()
    {
      Console.WriteLine("Base - Method1");
    }

    public virtual void Method2()
    {
      Console.WriteLine("Base - Method2");
    }
  }

  class DerivedClass : BaseClass
  {
    public override void Method1()
    {
      Console.WriteLine("Derived - Method1");
    }

    public new void Method2()
    {
      Console.WriteLine("Derived - Method2");
    }
  }
}

以下示例显示了不同上下文中的类似行为。该示例定义了三个类:一个名为 Car 的基类,和两个由其派生的 ConvertibleCar 和 Minivan。基类中包含 DescribeCar 方法。该方法给出了对一辆车的基本描述,然后调用 ShowDetails 来提供其他的信息。这三个类中的每一个类都定义了 ShowDetails 方法。 new 修饰符用于定义 ConvertibleCar 类中的 ShowDetails。 override 修饰符用于定义 Minivan 类中的 ShowDetails。

// Define the base class, Car. The class defines two methods,
// DescribeCar and ShowDetails. DescribeCar calls ShowDetails, and each derived
// class also defines a ShowDetails method. The example tests which version of
// ShowDetails is selected, the base class method or the derived class method.
class Car
{
  public void DescribeCar()
  {
    System.Console.WriteLine("Four wheels and an engine.");
    ShowDetails();
  }

  public virtual void ShowDetails()
  {
    System.Console.WriteLine("Standard transportation.");
  }
}

// Define the derived classes.

// Class ConvertibleCar uses the new modifier to acknowledge that ShowDetails
// hides the base class method.
class ConvertibleCar : Car
{
  public new void ShowDetails()
  {
    System.Console.WriteLine("A roof that opens up.");
  }
}

// Class Minivan uses the override modifier to specify that ShowDetails
// extends the base class method.
class Minivan : Car
{
  public override void ShowDetails()
  {
    System.Console.WriteLine("Carries seven people.");
  }
}

该示例测试被调用的 ShowDetails 版本。以下方法,TestCars1 为每个类提供了一个实例,并在每个实例上调用 DescribeCar。

public static void TestCars1()
{
  System.Console.WriteLine("\nTestCars1");
  System.Console.WriteLine("----------");

  Car car1 = new Car();
  car1.DescribeCar();
  System.Console.WriteLine("----------");

  // Notice the output from this test case. The new modifier is
  // used in the definition of ShowDetails in the ConvertibleCar
  // class. 

  ConvertibleCar car2 = new ConvertibleCar();
  car2.DescribeCar();
  System.Console.WriteLine("----------");

  Minivan car3 = new Minivan();
  car3.DescribeCar();
  System.Console.WriteLine("----------");
}

TestCars1 生成以下输出:尤其请注意 car2 的结果,该结果可能不是您所需的内容。对象的类型是 ConvertibleCar,但 DescribeCar 不会访问 ConvertibleCar 中定义的 ShowDetails 版本,因为方法已声明包含 new 修饰符,而不是 override 修饰符。因此,ConvertibleCar 对象显示与 Car 对象相同的说明。比较 car3 的结果,它是一个 Minivan 对象。在这种情况下,在 Minivan 类中声明的 ShowDetails 方法重写 Car 类中声明的 ShowDetails 方法,显示的说明描述微型面包车。

// TestCars1
// ----------
// Four wheels and an engine.
// Standard transportation.
// ----------
// Four wheels and an engine.
// Standard transportation.
// ----------
// Four wheels and an engine.
// Carries seven people.
// ----------

TestCars2 创建 Car 类型的对象列表。对象的值由 Car、ConvertibleCar 和 Minivan 类实例化而来。 DescribeCar 是调用列表中的每个元素。以下代码显示了 TestCars2 的定义。

public static void TestCars2()
{
  System.Console.WriteLine("\nTestCars2");
  System.Console.WriteLine("----------");

  var cars = new List<Car> { new Car(), new ConvertibleCar(),
    new Minivan() };

  foreach (var car in cars)
  {
    car.DescribeCar();
    System.Console.WriteLine("----------");
  }
}

显示以下输出。请注意,此输出与由 TestCars1 显示的输出相同。 ConvertibleCar 类的 ShowDetails 方法不被调用,无论对象的类型是 ConvertibleCar,如在 TestCars1 中,还是 Car,如在 TestCars2 中。相反,car3 在两种情况下都从 Minivan 类调用 ShowDetails 方法,无论它具有类型 Minivan 还是类型 Car。

// TestCars2
// ----------
// Four wheels and an engine.
// Standard transportation.
// ----------
// Four wheels and an engine.
// Standard transportation.
// ----------
// Four wheels and an engine.
// Carries seven people.
// ----------

完成示例的方法 TestCars3 和 TestCars4。这些方法直接调用 ShowDetails,首先从宣布具有类型 ConvertibleCar 和 Minivan (TestCars3) 的对象调用,然后从具有类型 Car (TestCars4) 的对象调用。以下代码定义了这两种方法。

public static void TestCars3()
{
  System.Console.WriteLine("\nTestCars3");
  System.Console.WriteLine("----------");
  ConvertibleCar car2 = new ConvertibleCar();
  Minivan car3 = new Minivan();
  car2.ShowDetails();
  car3.ShowDetails();
}

public static void TestCars4()
{
  System.Console.WriteLine("\nTestCars4");
  System.Console.WriteLine("----------");
  Car car2 = new ConvertibleCar();
  Car car3 = new Minivan();
  car2.ShowDetails();
  car3.ShowDetails();
}

该方法产生下面的输出,它对应本主题中第一个示例的结果。

// TestCars3
// ----------
// A roof that opens up.
// Carries seven people.

// TestCars4
// ----------
// Standard transportation.
// Carries seven people.

以下代码显示了整个项目及其输出。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace OverrideAndNew2
{
  class Program
  {
    static void Main(string[] args)
    {
      // Declare objects of the derived classes and test which version
      // of ShowDetails is run, base or derived.
      TestCars1();

      // Declare objects of the base class, instantiated with the
      // derived classes, and repeat the tests.
      TestCars2();

      // Declare objects of the derived classes and call ShowDetails
      // directly.
      TestCars3();

      // Declare objects of the base class, instantiated with the
      // derived classes, and repeat the tests.
      TestCars4();
    }

    public static void TestCars1()
    {
      System.Console.WriteLine("\nTestCars1");
      System.Console.WriteLine("----------");

      Car car1 = new Car();
      car1.DescribeCar();
      System.Console.WriteLine("----------");

      // Notice the output from this test case. The new modifier is
      // used in the definition of ShowDetails in the ConvertibleCar
      // class.
      ConvertibleCar car2 = new ConvertibleCar();
      car2.DescribeCar();
      System.Console.WriteLine("----------");

      Minivan car3 = new Minivan();
      car3.DescribeCar();
      System.Console.WriteLine("----------");
    }

输出:

TestCars1
----------
Four wheels and an engine.
Standard transportation.
----------
Four wheels and an engine.
Standard transportation.
----------
Four wheels and an engine.
Carries seven people.
----------
    public static void TestCars2()
    {
      System.Console.WriteLine("\nTestCars2");
      System.Console.WriteLine("----------");

      var cars = new List<Car> { new Car(), new ConvertibleCar(),
        new Minivan() };

      foreach (var car in cars)
      {
        car.DescribeCar();
        System.Console.WriteLine("----------");
      }
    }

输出:

TestCars2
----------
Four wheels and an engine.
Standard transportation.
----------
Four wheels and an engine.
Standard transportation.
----------
Four wheels and an engine.
Carries seven people.
----------
    public static void TestCars3()
    {
      System.Console.WriteLine("\nTestCars3");
      System.Console.WriteLine("----------");
      ConvertibleCar car2 = new ConvertibleCar();
      Minivan car3 = new Minivan();
      car2.ShowDetails();
      car3.ShowDetails();
    }

输出:

TestCars3
----------
A roof that opens up.
Carries seven people.
    public static void TestCars4()
    {
      System.Console.WriteLine("\nTestCars4");
      System.Console.WriteLine("----------");
      Car car2 = new ConvertibleCar();
      Car car3 = new Minivan();
      car2.ShowDetails();
      car3.ShowDetails();
    }
    // Output:
    // TestCars4
    // ----------
    // Standard transportation.
    // Carries seven people.
  }

  // Define the base class, Car. The class defines two virtual methods,
  // DescribeCar and ShowDetails. DescribeCar calls ShowDetails, and each derived
  // class also defines a ShowDetails method. The example tests which version of
  // ShowDetails is used, the base class method or the derived class method.
  class Car
  {
    public virtual void DescribeCar()
    {
      System.Console.WriteLine("Four wheels and an engine.");
      ShowDetails();
    }

    public virtual void ShowDetails()
    {
      System.Console.WriteLine("Standard transportation.");
    }
  }

  // Define the derived classes.

  // Class ConvertibleCar uses the new modifier to acknowledge that ShowDetails
  // hides the base class method.
  class ConvertibleCar : Car
  {
    public new void ShowDetails()
    {
      System.Console.WriteLine("A roof that opens up.");
    }
  }

  // Class Minivan uses the override modifier to specify that ShowDetails
  // extends the base class method.
  class Minivan : Car
  {
    public override void ShowDetails()
    {
      System.Console.WriteLine("Carries seven people.");
    }
  }

}
(0)

相关推荐

  • 深入理解C#中new、override、virtual关键字的区别

    OO思想现在已经在软件开发项目中广泛应用,其中最重要的一个特性就是继承,最近偶简单的复习了下在C#中涉及到继承这个特性时,所需要用到的关键字,其中有一些关键点,特地整理出来,方便大家查阅. 一.在C#中,new这个关键字使用频率非常高,主要有3个功能: a) 作为运算符用来创建一个对象和调用构造函数. b) 作为修饰符. c) 用于在泛型声明中约束可能用作类型参数的参数的类型. 在本文中,只具体介绍new作为修饰符的作用,在用作修饰符时,new关键字可以在派生类中隐藏基类的方法,也就说在使用派生

  • C#中new的用法及与override的区别分析

    C#中new的用法有三种: (1)new是运算符,用于创建对象和调用构造函数.如Class1=new Class1();也可以为值类型调用默认的构造函数如int a=new int();此时a=0. (2)new是修饰符,用于隐藏基类成员的继承成员.override不能隐藏积累成员的继承成员.如: using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace A {

  • 详解C#用new和override来实现抽象类的重写区别

    一,抽象的实现 using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Virtualdemo { class Program { static void Main(string[] args) {//BClass A = new BClass(); 抽象类无法被实例 Class1 c = new Class1(); BClass c2 = c; c2.Meth

  • C#中new的几种用法详解

    在 C# 中,new 关键字可用作运算符.修饰符或约束. new 运算符 用于创建对象和调用构造函数. new 修饰符 用于向基类成员隐藏继承成员. new 约束 用于在泛型声明中约束可能用作类型参数的参数的类型. new 修饰符(C# 参考) 在用作修饰符时,new 关键字可以显式隐藏从基类继承的成员.隐藏继承的成员意味着该成员的派生版本将替换基类版本.在不使用 new 修饰符的情况下隐藏成员是允许的,但会生成警告.使用 new 显式隐藏成员会取消此警告,并记录代之以派生版本这一事实. 若要隐

  • 基于C# 中可以new一个接口?的问题分析

    如果有人问你,C# 中可以new 一个接口吗?,你会怎么回答? 假设ITestInterface 是一个接口,那么这样的代码是否有问题? ITestInterface testInterface = new ITestInterface(); 很多书上都会说,当然有问题,接口不能用new ,然后你就认为上面这句语句肯定通不过编译器的编译了. 可是凡事无绝对,C# 竟然允许你这么写,当然你需要加点"料"才行. 在VS2005 中新建控制台程序CA2005.添加 Microsoft.Off

  • C# new和override的区别分析

    昨天面试问到了new的几种用法以及与Override的区别,有点模糊 回来google下,new的用法有以下3中 1.运算符:初始化对象和调用构造函数 2.修饰符:隐藏基类方法 3.于在泛型声明中约束可能用作类型参数的参数的类型 至于作为修饰符和override的区别,看了下文章不太明白,写了个例子,运行结果,发现了差异,下面分享下代码: using System; using System.Collections.Generic; using System.Linq; using System

  • C#基础知识之new关键字介绍

    一.运算符 用于创建对象和调用构造函数.这种大家都比较熟悉,没什么好说的了. 二.修饰符 在用作修饰符时,new 关键字可以显式隐藏从基类继承的成员. 无new关键字代码: 有new关键字代码: 结果: 注意: 在子类中用 new 关键字修饰定义的与父类中同名的方法,叫覆盖.覆盖不会改变父类方法的功能. 当子类创建父类时,代码中A c = new B(),覆盖不会改变父类的功能.依然还是调用父类的功能. 三.new 约束 用于在泛型声明中约束可能用作类型参数的参数的类型. public clas

  • .net(c#)中的new关键字详细介绍

    1)new 运算符:用于创建对象和调用构造函数.这种大家都比较熟悉,没什么好说的了.2)new 修饰符:在用作修饰符时,new 关键字可以显式隐藏从基类继承的成员.3)new 约束:用于在泛型声明中约束可能用作类型参数的参数的类型. new关键字在我们的程序中可谓是无时不刻在用到,那么new关键字都可以用在哪些地方呢?考虑以下几个问题: 1.new一个class对象和new一个struct或者new一个enum有什么不同? 答:new一个class时,new完成2个内容:一是调用newobj命令

  • C#中new和override的区别个人总结

    问题: A类 有方法 public virtual void test() B类继承自A类,有方法 public new void test()  如下实例化: A a = new B(); a.test(); 会调用哪个类中的TEST方法,最好能详细给我解释一下好吗?先谢谢了! 回答: 如果你用override,则无论调用的是A类还是B类中的TEST(),系统都会找到它实质类的TEST(): 如果是用的New,则可以通过类型转换调用到基类的TEST(): 下面是override的情况: A a

  • 浅谈MySQL中授权(grant)和撤销授权(revoke)用法详解

    MySQL 赋予用户权限命令的简单格式可概括为: grant 权限 on 数据库对象 to 用户 一.grant 普通数据用户,查询.插入.更新.删除 数据库中所有表数据的权利 grant select on testdb.* to common_user@'%' grant insert on testdb.* to common_user@'%' grant update on testdb.* to common_user@'%' grant delete on testdb.* to c

  • 对Python中class和instance以及self的用法详解

    一. Python 的类和实例 在面向对象中,最重要的概念就是类(class)和实例(instance),类是抽象的模板,而实例是根据类创建出来的一个个具体的 "对象". 就好比,学生是个较为抽象的概念,同时拥有很多属性,可以用一个 Student 类来描述,类中可定义学生的分数.身高等属性,但是没有具体的数值.而实例是类创建的一个个具体的对象, 每一个对象都从类中继承有相同的方法,但是属性值可能不同,如创建一个实例叫 hansry 的学生,其分数为 93,身高为 176,则这个实例拥

  • java中的抽象类和接口定义与用法详解

    目录 一.抽象类 1.什么叫抽象类? 2.抽象类的特点: 3.成员特点: 二.接口 1.接口是什么? 2.接口的特点 3.接口的组成成员 4.类与抽象的关系: 5.抽象类与接口的区别: 一.抽象类 1.什么叫抽象类? 例如在生活中我们都把狗和猫归为动物着一类中,但当只说动物时,我们是不知道是猫还是狗还是其他的.所以动物就是所谓的抽象类,猫和狗则是具体的类了.因此在Java中,一个没有方法体的方法应该定义为抽象类,而类中有抽象方法,则必须为抽象类. 2.抽象类的特点: 抽象类与抽象方法必须用abs

  • Android Studio 3.6中新的视图绑定工具ViewBinding 用法详解

    前言 我们在Android开发的过程中总是需要获取XML布局中的ViewId,以便给其赋值进行显示,早期我们只能使用 findViewById 这个API,会导致很多的模版代码出现.2013年左右Android界大神 Jake Wharton开源了Butter Knife框架,通过Bind("viewid")方式方便开发者获取ViewId.近两年由于谷歌对Kotlin的支持,我们开始使用 Android Kotlin extensions. 在文件中导入布局文件直接引用viewId.无

  • JS中的Replace()传入函数时的用法详解

    replace方法的语法是:stringObj.replace(rgExp, replaceText) 其中stringObj是字符串(string),reExp可以是正则表达式对象(RegExp)也可以是字符串(string),replaceText是替代查找到的字符串.. 废话不多说了,直接给大家贴代码了,具体代码如下所示: <script> var str = "a1ba2b"; var reg = /a.b/g; str = str.replace(reg,func

  • Python在信息学竞赛中的运用及Python的基本用法(详解)

    前言 众所周知,Python是一种非常实用的语言.但是由于其运算时的低效和解释型编译,在信息学竞赛中并不用于完成算法程序.但正如LRJ在<算法竞赛入门经典-训练指南>中所说的一样,如果会用Python,在进行一些小程序的编写,如数据生成器时将会非常方便,它的语法决定了其简约性.本文主要介绍一下简单的Python用法,不会深入. Python的安装和实用 Linux(以Ubuntu系统为例) 一般的Linux都自带了Python,在命令行中输入Python即可进入 如果没有出现上图的文字,可以使

  • C#中const 和 readonly 修饰符的用法详解

    1. 只有C#内置类型(int,double,long等)可以声明为const;结果.类和数组不能声明为const. 2. readonly 是在字段上使用的修饰符,直接以类名.字段访问. 3. const 必须在申明中初始化.之后不能再修改. 4. readonly可以在申明中初始化,也可以在构造函数中初始化,其它情况不能修改. namespace const_and_readonly { class Program { static void Main(string[] args) { Co

  • MySql中的IFNULL、NULLIF和ISNULL用法详解

    今天用到了MySql里的isnull才发现他和MSSQL里的还是有点区别,现在简单总结一下: mysql中isnull,ifnull,nullif的用法如下: isnull(expr) 的用法: 如expr 为null,那么isnull() 的返回值为 1,否则返回值为 0. mysql> select isnull(1+1); -> 0 mysql> select isnull(1/0); -> 1 使用= 的null 值对比通常是错误的. isnull() 函数同 is nul

  • ES6中Array.find()和findIndex()函数的用法详解

    ES6为Array增加了find(),findIndex函数. find()函数用来查找目标元素,找到就返回该元素,找不到返回undefined. findIndex()函数也是查找目标元素,找到就返回元素的位置,找不到就返回-1. 他们的都是一个查找回调函数. [1, 2, 3, 4].find((value, index, arr) => { }) 查找函数有三个参数. value:每一次迭代查找的数组元素. index:每一次迭代查找的数组元素索引. arr:被查找的数组. 例: 1.查找

  • C++中stack、queue、vector的用法详解

    一.栈(stack) 引入头文件 #include<stack> 常用的方法 empty() 堆栈为空则返回真 pop() 移除栈顶元素 push() 在栈顶增加元素 size() 返回栈中元素数目 top() 返回栈顶元素 3.实例代码 #include<iostream> #include<stack> using namespace std; int main(){ //创建栈 s stack<int> s; //将元素压入栈 for(int i=0;

随机推荐