zoukankan      html  css  js  c++  java
  • 温故而知新类、结构

     类和结构是.NET Framework中的常规类型系统的两种基本构造。两者在本质上都属于数据结构,封装着一组整体作为一个逻辑单位的数据和行为。数据和行为是该类或结构的“成员”,他们包含各自的method,property和event等。
     
    类是一种“引用类型”(堆,内存分配地址)。创建类的对象时,对象赋值到的变量只保存对该内存的引用。将对象引用赋值给新变量时,新变量引用的是原始对象。通过一个变量做出的更改将反映在另一个变量中,因为两者引用同一数据。
     
    结构是一种值类型(栈上分配空间,这个空间对应着值类型的变量)。创建结构时,结构赋值到的变量保存该结构的实际数据。将结构赋值给新变量时,将复制该结构。因此,新变量和原始变量包含同一数据的两个不同的副本。对一个副本的更改不影像另一个副本。
     
    类通常用于对于较为复杂的行为建模,或对要在创建类对象后进行修改的数据建模。结构最适合一些小型数据结构,这些数据结构包含的数据以创建结构后不修改的数据为主。
     
    “封装” 有时被称为面向对象的编程的第一支柱或原则。根据封装的原则,类或结构可以指定其每个成员对于该类或结构外部的代码的可访问性,可将无意在类或程序集外部使用的方法和变量隐藏起来,以减小编码错误或遭恶意利用的可能性。
     
    “类”是一种构造,通过使用该构造,可以将其他类型的变量、方法和事件组合在一起,从而创建自己的自定义类型。类就像一个蓝图,它定义类型的数据和行为。如果类没有声明为静态类,客户端代码就可以创建赋给变量的“对象”或“实例”,从而使用该类。在对变量的所有引用都超出范围之前,该变量始终保持在内存中。所有引用都超出范围时,CLR将标记该变量以供GC。如果声明为静态类,则内存中只存在一个副本,并且客户端代码只能通过该类自身而不是“实例变量”访问该类。
    与结构不同,类支持“继承”,而继承是面向对象编程的基础特性。
    尽管有时类和对象可互换,但它们是不同的概念,类定义对象的类型,但它不是对象的本身。对象是基于类的具体实体,有时称为类的实例。
     
    对象
    类或结构定义的作用类似于蓝图,置顶该类型可以进行哪些操作。从本质上说,对象是按照此蓝图分配和配置的内存块。程序可以创建同一个类的多个对象。对象(实例)可以存储在命名变量中,也可以存储在数组或集合中。使用这些变量来调用对象方法及访问对象公共属性的代码称为客户端代码。(静态类型的行为将在后序介绍)
    对象的内存在现成堆栈上进行分配。该内存随声明他的类型或方法一起回收。这就是在赋值时复制结构的一个原因。相比之下,当对类实例对象的所有引用都超出范围时,为该类实例分配的内存将由公共语言运行时自动回收。不像在C++中那样明确销毁类对象。
    结构实例与类实例
    由于类是引用类型,因此类对象的变量引用该对象在托管堆上的地址
    类的实例使用 new 运算符创建。
    由于结构是值类型,因此结构对象的变量具有整个对象的副本。
    结构的实例也可以使用new 运算符来创建,但不是必须的、
    对象标识与值相等
    在比较两个对象是否相等时,首先必须明确是想知道两个变量是否表示内存中的同一对象,还是想知道两个对象的一个或多个字段的值是否相等。如果对值进行比较,必须考虑这两个对象是值类型(结构)的实例,还是引用类型(类,委托、数组)的实例。
    判断两个类实例是否引用内存中的同一位置(意味着他们具有相同的标识),可以使用静态Equals方法。
    判断两个结构实例中的实例字段是否具有相同的值,可使用ValueType.Euqals方法。(由于所有结构都隐式继承自System.ValueType,因此可以直接在对象上调用该方法)。
    public struct Person
    {
        public string Name;
        public string Age;
    }
    Person p1=new Person("zhangsan",18);
    Person p2;
    p2.Name="zhangsan";
    p2.Age=18;
    if(p2.Equals(p1))
    {Console.WriteLine("OK");}
    Equals的System.ValueType实现使用反射,因此它必须能够确定任何结构中有哪些字段。在创建自己的结构时,重写Equals方法可以提供针对自己的类型的高效求等算法。

    结构(Struct)

    结构与类共享大多数相同语法,但结构比类受到的限制更多:

    1.在结构声明中,除非哦字段被声明为const或static,否则无法初始化。

    2.结构不能声明默认构造函数(无参构造函数)或析构函数。

    3.结构在赋值时进行复制。将结构赋值给变量时,将复制所有的数据,并且对新副本所做的任何修改不会更改原始副本的数据。

    4.结构是值类型,类是引用类型。

    5.结构实例化可以不使用new 运算符。

    6.结构可以声明带参数的构造函数。

    7.一个结构不能从另一个结构或类继承,而且不能作为一个类的基类。所有结构都直接继承自System.ValueType,后者继承自System.Object。

    8.结构可以实现接口。

    9.结构可用作可以为null的类型,可以向其赋null值。

    Struct类型适于表示PointRectangleColor等轻量对象,尽管使用自动实现的属性继承将一个点表示为类同样方便,但在某些情况下使用结构更加有效。例如:声明1000哥Point对象组成的数组,为了引用每个对象,则需要分配更多内存;这中情况下,使用结构可以节约资源。

    继承

    继承(封装、多态)是面向对象编程的三个主要特性(支柱)。继承用于创建可重用、扩展和修改在其他类中定义的行为的新类。其成员被继承的类称为“基类”,继承这些成员的类称为“派生类”。派生类只能有一个直接基类、但是,继承是可传递的。(结构不支持继承,但可以实现借口)。派生类是基类的专用化。

    定义一个类从其他类派生时,炮声泪隐式获得基类除构造函数和析构函数以外的所有成员。因此,派生类可以重用基类中的代码而无需重新实现这些代码。可以在派生类中添加更多的成员(扩展基类的功能)。

     

    图片抽象方法和虚方法

    当基类将方法声明为virtual时,派生类可以重写该方法。如果基类将成员声明为abstract,则直接继承自该类的任何非抽象类中中都必须重写该方法。如果派生类是抽象的,则它继承抽象成员而不实现他们。抽象成员和虚成员是多态性的基础。。。

    抽象基类

    如果希望禁止通过new关键字直接进行实例化,可以将类声明为abstract ,如果这样,则仅当从该类派生心累时才能使用该类。抽象类可以包含一个或多个自身声明为抽象的方法签名。这个签名指定参数和返回值,但没有实现(方法体)。抽象类不必包含抽象成员;但是如果某个类确实包含抽象成员,则该类自身必须声明为抽象类。自身不是抽象类的派生类必须为抽象基类中的任何抽象方法提供实现。

    接口

    “接口”,像仅包含抽象成员的抽象基类。类在从接口实现时必须为该接口的所有成员提供实现。类只能从一个直接街垒派生,可以实现多个接口。

    派生类对基类成员的访问

    派生类可以访问基类的公共成员、受保护成员、内部成员和受保护内部成员。即使派生类继承基类的私有成员,仍不能访问这些成员。但这些是有成员在派生类中仍然存在,且执行与基类自身中相同的工作。

    禁止进一步派生

    类可以将自身或其成员声明为sealed,从而禁止其他类从该类自身或其任何成员继承。

    派生类隐藏基类成员

    派生类可以通过相同的名称和签名声明基类成员来隐藏这些成员。可以使用new修饰符显示指示成员不作为基类成员的重写。(可以不使用new,会警告!!!)

     

  • 相关阅读:
    腾讯加入QQ群,代码生成地址
    jsTree 是一个基于Javascript,支持多浏览器的Tree view jQuery插件。
    PHP Ajax 跨域问题最佳解决方案
    【转载】目前主流过滤XSS的三种技术
    nginx中location、rewrite用法总结
    Tomcat请求头过大
    ssh秘钥分发错误“/usr/bin/ssh-copy-id: ERROR: No identities found”
    ssh分发秘钥时出现错误“Permission denied (publickey,gssapi-keyex,gssapi-with-mic)”
    修改Jenkins用户的密码
    注销/etc/passwd带来的系统登陆不上
  • 原文地址:https://www.cnblogs.com/zhangxiaohui/p/2534502.html
Copyright © 2011-2022 走看看