初面网初面网

类的组成、声明和使用

类,是对象的抽象,由方法和变量构成。类的所有组成都可以称为“成员”。所以当提及类的变量的时候,常用"成员变量"来称呼,而提及类的方法的时候,用"成员函数"来称呼。

所以也可以说,类由其成员变量和成员方法组成。

对象,是具体的类(实例化的类)。因为本质上还是某种类,所以可能拥有那个类的方法和变量。

类与对象是一对概念,他们的关系是抽象与具体。形象的说,可以看做是石头和鹅卵石,又可以看做是气体和氧气。

之所以说"可能拥有那个类的方法和变量",是因为有些东西可能是类所独占的。现实里可能很难举例出恰当的例子,因为特征实际上是对象独占的。

现在不理解类与对象的关系并不是大问题,在往后的学习中能够有更好地感受和体会

// 摘抄自https://www.runoob.com/csharp/csharp-class.html
using System;
namespace BoxApplication
{
  class Box
  {
    public double length;   // 长度
    public double breadth;  // 宽度
    public double height;   // 高度
  }
  class Boxtester
  {
    static void Main(string[] args)
    {
      Box Box1 = new Box();        // 声明 Box1,类型为 Box
      Box Box2 = new Box();        // 声明 Box2,类型为 Box
      double volume = 0.0;         // 体积

      // Box1 详述
      Box1.height = 5.0;
      Box1.length = 6.0;
      Box1.breadth = 7.0;

      // Box2 详述
      Box2.height = 10.0;
      Box2.length = 12.0;
      Box2.breadth = 13.0;
      
      // Box1 的体积
      volume = Box1.height * Box1.length * Box1.breadth;
      Console.WriteLine("Box1 的体积: {0}",  volume);

      // Box2 的体积
      volume = Box2.height * Box2.length * Box2.breadth;
      Console.WriteLine("Box2 的体积: {0}", volume);
      Console.ReadKey();
    }
  }
}

构造函数与析构函数

既然二者都被称为"函数",那么它们本质上其实也是方法。由于它们存在于类中,所以它们自然而然的是"成员函数"。

此外,既然需要单独来说明,它们自然各有自己的"绝技"。

构造函数:类在实例化时必定调用一次,名称与类名一致

析构函数:类被销毁前必定调用一次

由于类在实例化时必定调用构造函数,所以在构造函数里非常适合做一些初始化的操作。例如我们需要一个正方体,默认长宽高都是1,那么就可以在构造函数里将它的长宽高设置为1

析构函数在类被销毁的时候调用一次,那么当我们需要类销毁前做些操作的时候,就非常适合把操作放到析构函数里。例如有一个3立方米的正方体,希望在它销毁的时候能够缩小到0.01立方米,那么我们就可以在析构函数里进行这一步操作

// 摘抄自 https://www.runoob.com/csharp/csharp-class.html
using System;
namespace LineApplication
{
  class Line
  {
    private double length;   // 线条的长度
    public Line(double len)  // 参数化构造函数, 但其实也可以没有参数
    {
        Console.WriteLine("对象已创建,length = {0}", len);
        length = len;
    }
    ~Line() //析构函数
    {
        Console.WriteLine("对象已删除");
    }

    public void setLength( double len )
    {
        length = len;
    }
    public double getLength()
    {
        return length;
    }

    static void Main(string[] args)
    {
        Line line = new Line(10.0);
        Console.WriteLine("线条的长度: {0}", line.getLength());
        // 设置线条长度
        line.setLength(6.0);
        Console.WriteLine("线条的长度: {0}", line.getLength());
        Console.ReadKey();
    }
  }
}

属性的set和get

属性也有内置的方法,set和get就是其中的方法

一般来讲,属性不暴露给外部,暴露出去的应该只有方法

如果不确定应该暴露哪些,那么现将所有的访问修饰符设为private比较稳妥,使用时需要哪些暴露再酌情设为public或者protected。

当然,随着编程经验的丰富,应该把哪些暴露也会更快判断出来

public class Vector3
{
  private int _value;
  public int a
  {
    set
    {
      _value = value; // 设置的时候,右值会由系统识别,所以我们只管赋值就好
      Console.WriteLine("设置值");
    }

    get
    {
      return _value;
    }
  }
  public string name{set;get;}  // 像这样,可以直接由系统接管属性的设置和获取
}

public class App
{
  static void Main(string[] args)
  {
    Vector3 v3 = new Vector3();
    Console.WriteLine(v3.a);
    v3.a = 100;   // 这里的100会代替上面的右值value
    Console.WriteLine(v3.a);
    v3.name = "Tom";
    Console.WriteLine(v3.name);

    Console.ReadKey();
  }
}

静态成员

静态成员使用static来标明。这意味着无论实例化多少对象,只会有一个该静态成员的副本

当我们说"静态成员"时,应该立刻拆成两部分来看,一部分是"静态",一部分是"成员"。静态,就意味着它具有唯一性,所有实例化出来的对象都只能对唯一的静态成员进行操作;成员,意味着变量和方法都可以有静态的形式,即静态变量、静态方法。

一定要记住:静态方法只能访问静态成员!!!,也就是静态方法只能使用静态变量和静态方法。

还需要记住:静态方法只能通过类名访问,即 类名.静态方法名();

using System;
namespace TestApp
{
  class Book
  {
    public static string _name;
    private static int price;
    
    public void plsSayName()
    {
      Console.WriteLine(_name);
    }
    
    public static void sayName()
    {
      plsSayName();
    }
    
    public void setName(string name)
    {
      _name = name;
    }
    
    //public static void sayPrice()
    //{
    // Console.WriteLine(price);
    //}
  }
 
  class Infect
  {
    public static int Main(string[] args)
    {
      Book book = new Book();
      book.setName("逗号");
      Book.sayName();         // 调用静态方法必须用类名

      return 0;
    }
  }
}

更新于 2025/2/26