9.静态成员

9.面向对象-封装-静态成员


9.1 知识点

知识回顾

class 类名
{
    #region 特征——成员变量
    #endregion
    #region 行为——成员方法
    #endregion
    #region 初始化调用——构造函数
    #endregion
    #region 释放时调用——析构函数
    #endregion
    #region 包裹成员变量——成员属性
    #endregion
    #region 通过中括号使用对象——索引器
    #endregion
}

静态成员基本概念

  • static 关键字用于修饰成员变量、方法、属性等,称为静态成员。
  • 静态成员的特点是:直接用类名点出使用。

早已出现的静态成员

  • 静态成员早在 Console 类中就已经出现,例如属性和方法。

自定义静态成员

class Test
{
    // 静态成员变量
    static public float PI = 3.1415926f;
    // public 和 static 的顺序可以随意摆放
    public static float π = 3.1415926f;

    // 成员变量
    public int testInt = 100;

    // 静态成员方法
    public static float CalcCircle(float r)
    {
        // πr²
        return PI * r * r;
    }

    // 成员方法
    public void TestFun()
    {
        Console.WriteLine("123");
    }
}

静态成员的使用

主函数内

  • 使用静态成员
    // 输出静态成员变量 π
    Console.WriteLine(Test.PI); // 3.1415925
    Console.WriteLine(Test.π); // 3.1415925
    // 半径为2的圆的面积
    Console.WriteLine(Test.CalcCircle(2)); // 12.56637
    
  • 实例化对象后使用非静态成员
    Test t = new Test();
    Console.WriteLine(t.testInt); // 100
    t.TestFun(); // 123
    
  • 实例化对象不能使用静态成员
    // Console.WriteLine(t.PI); // 报错
    // Console.WriteLine(t.CalcCircle(2)); // 报错
    // 无法使用实例引用访问静态成员“member”;用类型名称限定它。
    // 只能使用类名来限定静态变量;实例名称不能是限定词。
    

为什么可以直接点出来使用

  • 实例化对象的特点:对象、变量、函数都需要在内存中分配内存空间。
  • 静态成员的特点:程序开始运行时就会分配内存空间,因此可以直接使用。

静态函数中不能使用非静态成员

public static float CalcCircle(float r)
{
    // 静态函数中不能使用非静态成员
    // Console.WriteLine(testInt); // 报错,非静态字段、方法或属性“成员”需要对象引用。
    
    // 非静态成员不能无中生有,必须通过对象实例化后才能访问
    Test t = new Test();
    t.testInt = 54250;
    Console.WriteLine("CalcCircle实例化对象后,输出testInt的值是:{0}", t.testInt);
    
    // πr²
    return PI * r * r;
}

非静态函数可以使用静态成员

public void TestFun()
{
    Console.WriteLine("123");
    
    // 非静态函数可以使用静态成员
    // 静态成员的生命周期比非静态更长,因此在非静态函数中使用静态成员没有问题
    Console.WriteLine("非静态函数可以使用静态成员" + "PI:" + PI);
    
    // 使用静态成员方法也没有问题
    Console.WriteLine("非静态函数可以使用静态成员" + "CalcCircle(2):" + CalcCircle(2));
}

静态成员对于我们的作用

  • 静态变量的作用

    • 常用唯一变量的声明,如 π。
    • 方便别人获取的对象声明,静态变量具有全局性。
  • 静态方法的作用

    • 常用的唯一的方法声明,例如相同规则的数学计算相关函数,如圆的周长和面积。
  • 过多的静态成员的后果

    • 过多的静态成员可能导致频繁触发 GC。

常量和静态变量

  • const(常量)可以理解为特殊的 static(静态)。
  • 常量和静态变量的相同点:它们都可以通过类名点出使用。
  • 常量和静态变量的不同点:
    • const 必须初始化,不能修改;static 没有这个规则。
    • const 只能修饰变量,static 可以修饰很多。
    • const 一定是写在访问修饰符后面的,static 没有这个规则。

测试类内

// 常量
// 重力加速度
public const float G = 9.8f;
// 一定要初始化,否则报错

// 自然对数
// const public float e = 2.72f;
// 报错,const 一定是写在访问修饰符后面的

主函数内

// Test.G = 10; // 报错,常量不可修改
Console.WriteLine(Test.G); // 9.8

总结

  • 概念:用 static 修饰的成员变量、成员方法、成员属性等就称为静态成员。
  • 特点:直接用类名点出来使用(全局性)。
  • 生命周期:和程序同生共死,程序运行后就会一直存在内存中,直到程序结束后才会释放,因此静态成员具有唯一性。
  • 注意:
    • 静态函数中不能直接使用非静态成员。
    • 非静态函数中可以直接使用静态成员。
  • 常量和静态变量:
    • 常量是特殊的静态变量。
    • 常量和静态变量相同点:它们都可以通过类名点出来使用。
    • 常量和静态变量不同点:
      • const 必须初始化,不能被修改;static 没有这个规则。
      • const 只能修饰变量,static 可以修饰很多。
      • const 不能写在访问修饰符前面,一定是写在变量声明前面;static 没有这个规则。

9.2 知识点代码

using System;

namespace Lesson7_封装_静态成员
{
    #region 知识回顾
    class 类名
    {
        #region 特征——成员变量

        #endregion

        #region 行为——成员方法

        #endregion

        #region 初始化调用——构造函数

        #endregion

        #region 释放时调用——析构函数

        #endregion

        #region 包裹成员变量——成员属性

        #endregion

        #region 通过中括号使用对象——索引器
        #endregion
    }
    #endregion

    #region 知识点一 静态成员基本概念
    //静态关键字 static
    //用static修饰的 成员变量、方法、属性等 称为静态成员
    //静态成员的特点是:直接用类名点出使用
    #endregion

    #region 知识点二 早已出现的静态成员
    //如 Console类里出现的属性和方法
    #endregion

    #region 知识点三 自定义静态成员

    //class语句块外 语句块内

    // 测试 类
    class Test
    {
        //静态成员变量
        static public float PI = 3.1415926f;
        //public 和 static 的顺序可以随意摆放
        public static float π = 3.1415926f;

        //成员变量
        public int testInt = 100;

        //静态成员方法
        public static float CalcCircle(float r)
        {
            #region 知识点六 静态函数中不能使用非静态成员

            //成员变量只能将对象实例化出来后 才能点出来使用 不能无中生有
            //不能直接使用 非静态成员 否则会报错

            //Console.WriteLine(testInt);
            //报错 非静态字段、方法或属性“成员”需要对象引用

            //非静态成员不能无中生有
            //一定要打印testInt的话可以实例化一个对象出来
            Test t = new Test();
            t.testInt = 54250;
            Console.WriteLine("CalcCircle实例化对象后,输出testInt的值是:{0}",t.testInt);
            //CalcCircle实例化对象后,输出testInt的值是:54250

            #endregion


            //πr²
            return PI * r * r;
        }

        //成员方法
        public void TestFun()
        {
            Console.WriteLine("123");

            #region 知识点七 非静态函数可以使用静态成员

            //静态成员生命周期比非静态更长一点
            //所以非静态里使用静态成员没有问题
            Console.WriteLine("非静态函数可以使用静态成员" + "PI:" + PI);
            //非静态函数可以使用静态成员PI:3.1415925

            //使用静态成员方法也没有问题
            Console.WriteLine("非静态函数可以使用静态成员" + "CalcCircle(2):" + CalcCircle(2));
            //非静态函数可以使用静态成员CalcCircle(2):12.56637

            #endregion
        }

        #region 知识点九 常量和静态变量

        // 测试类 内

        //常量

        //重力加速度
        public const float G = 9.8f;
        //一定要初始化 否则报错

        //自然对数
        //const public float e = 2.72f;
        //报错 const一定是写在访问修饰符后面的

        #endregion

    }
    #endregion

    #region 知识点五 为什么可以直接点出来使用

    //实例化对象的特点
    //程序中是不能无中生有的
    //我们要使用的对象,变量,函数都是要在内存中分配内存空间的
    //之所以要实例化对象,目的就是分配内存空间,在程序中产生一个抽象的对象

    //静态成员的特点
    //程序开始运行时 就会分配内存空间。所以我们就能直接使用。
    //静态成员和程序同生共死
    //只要使用了它,直到程序结束时内存空间才会被释放
    //所以一个静态成员就会有自己唯一的一个“内存小房间”
    //这让静态成员就有了唯一性
    //在任何地方使用都是用的小房间里的内容,改变了它也是改变小房间里的内容
    //所以同时具有全局性

    #endregion

    #region 知识点八 静态成员对于我们的作用
    //静态变量的作用:
    //1.常用唯一变量的申明 如π
    //2.方便别人获取的对象申明 静态变量具有全局性

    //静态方法的作用:
    //常用的唯一的方法申明
    //比如 相同规则的数学计算相关函数 
    //例:圆的周长和面积

    //过多的静态成员 可能导致频繁触发GC
    #endregion

    #region 知识点九 常量和静态变量
    //const(常量)可以理解为特殊的static(静态)
    //常量和静态变量的相同点
    //他们都可以通过类名点出使用
    //常量和静态变量的不同点
    //1.const必须初始化,不能修改 static没有这个规则
    //2.const只能修饰变量、static可以修饰很多
    //3.const一定是写在访问修饰符后面的 ,static没有这个要求
    #endregion
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("静态成员");

            //主函数内

            #region 知识点四 静态成员的使用

            //使用静态成员
            //输出静态成员变量 π
            Console.WriteLine(Test.PI);//3.1415925
            Console.WriteLine(Test.π);//3.1415925
            //半径为2的圆的面积
            Console.WriteLine(Test.CalcCircle(2));//12.56637


            //实例化对象后使用非静态成员
            Test t = new Test();
            Console.WriteLine(t.testInt);//100
            t.TestFun();//123

            //实例化对象不能使用静态成员
            //Console.WriteLine(t.PI);//报错
            //Console.WriteLine(t.CalcCircle(2));//报错
            //无法使用实例引用访问静态成员“member”;用类型名称限定它
            //只能使用类名来限定静态变量;实例名称不能是限定词。



            #endregion

            #region 知识点九 常量和静态变量

            //Test.G = 10;//报错 常量不可修改
            Console.WriteLine(Test.G);//9.8

            #endregion
        }
    }

    //总结

    //概念:用static修饰的成员变量、成员方法、成员属性等 就称为静态成员
    //特点:直接用类名点出来使用(全局性)
    //生命周期:和程序同生共死,程序运行后就会一直存在内存中,知道程序结束后才会释放,因此静态成员具有唯一性

    //注意:
    //1.静态函数中不能直接使用非静态成员
    //2.非静态函数中可以直接使用静态成员

    //常量和静态变量
    //常量是特殊的静态变量
    //常量和静态变量相同点
    //他们都可以通过类名点出来使用
    //常量和静态变量不同点
    //1.const必须初始化不能被修改 static没有这个规则
    //2.const只能修饰变量,static可以修饰很多
    //3.const不能写在访问修饰符前面 一定是写在变量申明前面 static没有这个规则
}

9.3 练习题

const和static的区别

  • 相同点:

    • 两者都可以通过类名点出来使用。
  • 不同点:

    1. const必须初始化不能被修改,static没有这个要求:

      • const用于定义常量,其值在编译时就需要确定,并且不能在运行时修改。
      • static可以是变量、方法、属性等,而且其值或状态可以在运行时进行修改。
    2. const是只能修饰变量,static可以修饰很多:

      • const主要用于定义常量,修饰的是常量值。
      • static可以修饰变量、方法、属性等,表示这些成员是属于类而不是实例的。
    3. 访问修饰符要写在const前面,static随意:

      • const必须加上访问修饰符,例如public const int MyConstant = 42;
      • static可以根据需要加上访问修饰符,也可以不加,例如private static int myStaticVariable;

用静态成员实现单例模式

一个类对象,在整个应用程序的生命周期中,有且仅会有一个该对象的存在,不能在外部实例化,直接通过该类类名就能够得到唯一的对象

class语句块外 namespace语句块内

// class语句块外 namespace语句块内
// 单例类
class Singleton
{
    // 设置一个私有静态的对象 new出一个自己 即是唯一对象
    private static Singleton instance = new Singleton();

    public int singletonInt = 123;

    // 使用静态属性 通过属性让外部只能得不能改
    public static Singleton Instance
    {
        get
        {
            return instance;
        }
    }

    // 写一个私有的构造函数 在外面就不能new了
    private Singleton()
    {

    }
}

主函数内

// 主函数内
//Singleton instance =  new Singleton();
//报错 构造函数私有 不能new

//要把Singleton.instance设置为private 不然有可能外部置空
//Singleton.instance = null;
//Singleton.instance设置为private后 报错

Console.WriteLine(Singleton.Instance.singletonInt);//123

9.4 练习题代码

using System;

namespace Lesson7_练习题
{
    #region 练习题一
    //请说出const和static的区别

    //const和static的相同点
    //他们都可以通过类名点出来使用
    //const和static的不同点
    //1.const必须初始化不能被修改,static没有这个要求
    //2.const是只能修饰变量,static可以修饰很多
    //3.访问修饰符要写在const前面,static随意
    #endregion

    #region 练习题二

    //请用静态成员相关知识实现
    //一个类对象,在整个应用程序的生命周期中,有且仅会有一个该对象的存在,
    //不能在外部实例化,直接通过该类类名就能够得到唯一的对象

    //class语句块外 namespace语句块内

    //其实是单例模式的实现

    // 单例 类
    class Singleton
    {
        //设置一个私有静态的对象 new出一个自己 即是唯一对象
        private static Singleton instance = new Singleton();

        public int singletonInt = 123;

        //使用静态属性 通过属性让外部只能得不能改
        public static Singleton Instance
        {
            get
            {
                return instance;
            }
        }

        //写一个私有的构造函数 在外面就不能new了
        private Singleton()
        {

        }
    }

    #endregion

    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("静态成员练习题");

            //主函数内

            #region 练习题二

            //Singleton instance =  new Singleton();
            //报错 构造函数私有 不能new

            //要把Singleton.instance设置为private 不然有可能外部置空
            //Singleton.instance = null;
            //Singleton.instance设置为private后 报错

            Console.WriteLine(Singleton.Instance.singletonInt);//123

            #endregion
        }
    }
}


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com

×

喜欢就点赞,疼爱就打赏