抽象类和静态类有什么区别?

37

这两者都不可实例化。它们的区别是什么,以及在什么情况下可以使用其中之一?


2
在使用静态类时,请记得考虑线程安全性。请参见此处 - kenchilada
9个回答

37

static 表示类只能拥有静态成员,不能创建其实例。它用于无状态功能(例如只定义扩展方法或实用程序方法的类型)。您也可以在非静态类上声明static成员。这允许您将功能附加到类型而无需实例化它。

更多关于使用静态成员和类的详细信息

abstract 定义了所有派生类型共享的基本结构和功能,但本身不能使用。可以将其视为蓝图和契约。这是面向对象编程的核心概念。

更多关于使用抽象类的详细信息


6
C#中的静态类是一个封闭的抽象类。 - Matthew Whited

37

以下是简要概述:

  • 静态类只能包含 static 成员(只是一个容器,用于存放不属于任何标准类实例的方法)
  • 抽象类可以包含所有通常类型的成员(静态、抽象和实例成员)

关键区别在于你可以从一个 abstract 类继承,但不能从一个 static 类继承。严格来说,.NET 运行时没有任何关于 static 类的概念,所以 C# 编译器将它们编译为既是 abstract 也是 sealed 的类(这意味着你不能从它们派生子类)。

因此,static 类是既是 abstract 又是 sealed 的类(尽管这不是 C# 程序员通常看待问题的方式),并且仅包含 static 成员(这由 C# 编译器强制执行)。


11

抽象类旨在作为类继承层次结构的基础使用。静态类不能作为类继承层次结构的基础使用。

静态类旨在用于单例状态或无状态功能。抽象类不适合单例功能,因为即使它可能像静态类一样包含静态方法和字段,它也不能禁止继承,因此可以通过子类来反对单例使用。或者至少会让其他程序员感到困惑,因为其定义会传达与实际预期用途不同的意图。

抽象类和静态类之间的表面相似性仅在于两者都无法实例化。除此之外,它们是完全不同的对象,具有完全不同的用例。


8

CLR没有静态类的概念,这是特定于C#的。编译器通过使用CLR属性为类实现它:它将其声明为抽象和密封。这可以防止任何语言实例化此类。 当您运行Ildasm时,它看起来像这样:

.class public abstract auto ansi sealed beforefieldinit ConsoleApplication1.Test
       extends [mscorlib]System.Object
{
}

使其封闭性是静态类的重点,它被用作静态方法和字段的容器。这使它们像在C或Pascal等语言中拥有的全局变量和函数一样运行。

抽象类则完全相反,它被设计为派生自。如果一个抽象类具有所有成员都是抽象的,则它就像一个接口。C#有一个关键字来表示这一点,使得静态类和接口成为了完全相反的概念。


指出静态类在内部是密封的和抽象的,加1分。 - Firestrand

6

抽象类通过派生类间接实例化。它们提供了公共行为和实例状态,但表明需要更多的内容,并且必须由派生具体类提供。例如,Transform 可能是一个抽象类:它声明了一个通用的 Apply(Shape) 方法,但没有该方法的实现。具体的派生类如 RotationTranslation 将实现该方法,这些类可以被实例化。

静态类不能被实例化,任何状态都在类级别而不是实例级别。它们通常用于定义实用程序方法,其中与方法相关联的状态不存在。Transform 不能是静态类,因为具体的派生类需要每个实例状态(例如,Rotation 需要每个实例的 Angle,因为不同的 Rotation 转换可能是不同的角度)。


3

抽象类旨在用作基类;它们不能直接实例化。相反,您必须派生子类,提供通常在抽象基类中(通常是有意地)省略的内容。

例如:考虑您有一个复杂的应用程序,用户可以登录到该应用程序。各种身份验证机制都应可用,比如LDAP、NTLM等。在这种情况下,对于“用户”或“主体”,一种建模方式是将所有这些机制中共同的部分收集到一个抽象基类中,并留下“空白”(抽象方法),以便实际实现发挥作用:

abstract class Authenticator {

   protected Dictionary<string,User> userCache;

   ...

   public User LoadUser(string name) {
        User user;
        if( userCache.TryGet(name, out user) ) return user;
        else {
            user = LoadFromStore(name);
            userCache.Add(name, user);
            return user;
        }
   }

   protected abstract User LoadFromStore(string name);
}

在这里,用户缓存是一个常见的问题,在基本案例中进行建模,而实际检索留给子类提供。

静态类则是完全不同的一回事。它们本质上是存放实用函数的地方:

static class StrUtil {

    public static string TrimWhitespace(string str) {
        ...
    }
}

把它们看作一种特殊的命名空间,只能包含静态成员。基本上是一个放置函数的地方。


2

抽象类(基类): 允许其他类继承这个类(一个类获得另一个类的属性(方法和字段)),但是禁止实例化,也就是说我们不能创建这个类的对象。 http://csharp.net-tutorials.com/classes/abstract-classes

静态类: 这个类不能被实例化。同时,这个类不能被继承。要访问这个类的方法,可以直接使用类名.方法。 https://social.technet.microsoft.com/wiki/contents/articles/21028.difference-between-static-class-sealed-class-and-abstract-class-in-c.aspx


1

抽象类的主要目的是定义一个或多个抽象方法。 任何扩展抽象类的类都将实现抽象方法,否则也需要声明为“抽象”。

但是,也可以在不实现任何抽象方法的情况下将类声明为“抽象”。请参见下面的示例。

public abstract class AbstractTest {
    public void abcd(){}

    public static void main(String[] args) {
        System.out.print("hi...");
    }
}

只有内部类可以声明为"Static",请参见下面的代码。 上层/封装类不能声明为"Static"。 可以通过使用上层/封装类变量来访问它。静态内部类名称与使用类名调用任何静态方法相同。
public class StaticTest {
    public static void main(String ag[]){
        System.out.println("hello...1");
        StaticTest.StaticTest2.meth2();
    }
    
    public static class StaticTest2 {
        public static void meth2(){
            System.out.print("hello...2");
        }
    }
}

-1

两者之间的主要区别在于可扩展性。

CLR 在幕后将所有“静态”类标记为“抽象和密封”的(即它们不能被继承,因此不能被扩展),当包含程序或命名空间被加载时,.NET Framework CLR 会自动加载它们。这在运行时提供了性能增益。

“抽象”类背后的哲学是将所有扩展类的共同特征集中在一个地方。

希望这有所帮助。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接