写出相应的输出,同时完成所要求的程序的书写。

写出相应的输出,同时完成所要求的程序的书写。

class Example3

{

public int x;          //非静态变量

public static int y;     //静态变量

void method()       //非静态方法

{

    x = 1;   //正确,非静态方法可以访问非静态成员

    y = 1;   //正确,非静态方法可以访问静态成员

   System.out.println("实例方法访问:x="+x+" y="+y);

}

static void smethod()     //静态方法

{

    //x = 3;  错误,静态方法不能非静态成员

    y = 3;   //正确,静态方法可以访问静态成员

   System.out.println("静态方法访问:y="+y);

}

public static void main(String[] args)

{

Example3 prog3 = new Example3();//生成类的实例

    prog3.method();    //非静态方法通过实例来调用



    Example3.smethod();  //静态方法通过类名来调用

}

}

创建一个名称为StaticDemo的类 并声明一个静态变量和一个普通变量。对变量分别赋予10和5的初始值。在main()方法中输出变量值。

创建类,然后定义变量,再输出即可,只不过访问静态成员变量和普通成员变量的方式有点不同。

代码如下:



public class StaticDemo {

    static int staticVar ;
     int  normalVar ;
    
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        
         
        Example3 prog3 = new Example3();//生成类的实例     
        prog3.method();    //非静态方法通过实例来调用
        Example3.smethod();  //静态方法通过类名来调用
        
        StaticDemo sd = new StaticDemo();
        StaticDemo.staticVar = 10; // 类的静态变量,可以直接通过 类名.静态成员名 来访问
        sd.normalVar = 5;  // 类的普通变量,需要先创建对象,然后再通过 对象名.非静态成员名 来访问
        
        System.out.println("静态变量的值为:"+sd.staticVar); // 类的静态变量,也可以通过 对象名.静态成员名 来访问
        System.out.println("非静态变量的值为:"+sd.normalVar);
    
    }

}

class Example3

{

    public int x;          //非静态变量
     
    public static int y;     //静态变量
     
    void method()       //非静态方法
     
    {
     
        x = 1;   //正确,非静态方法可以访问非静态成员
     
        y = 1;   //正确,非静态方法可以访问静态成员
     
       System.out.println("实例方法访问:x="+x+" y="+y);
     
    }
     
    static void smethod()     //静态方法
     
    {
     
        //x = 3;  错误,静态方法不能非静态成员
     
        y = 3;   //正确,静态方法可以访问静态成员
     
       System.out.println("静态方法访问:y="+y);
     
    }
     

}

img

  • 这篇博客: 静态局部变量和静态全程变量static。中的 2.3 静态局部变量有以下特点: 部分也许能够解决你的问题, 你可以仔细阅读以下内容或跳转源博客中阅读:
    • (1)该变量在全局数据区分配内存;
    • (2)静态局部变量在程序执行到该对象的声明处时被首次初始化,即以后的函数调用不再进行初始化;
    • (3)静态局部变量一般在声明处初始化,如果没有显式初始化,会被程序自动初始化为 0;
    • (4)它始终驻留在全局数据区,直到程序运行结束。但其作用域为局部作用域,当定义它的函数或语句块结束时,其作用域随之结束。

    一般程序把新产生的动态数据存放在堆区,函数内部的自动变量存放在栈区。自动变量一般会随着函数的退出而释放空间,静态数据(即使是函数内部的静态局部变量)也存放在全局数据区。全局数据区的数据并不会因为函数的退出而释放空间。

    看下面的例子:

    //example: #include <stdio.h> #include <stdlib.h> int k1 = 1; int k2; static int k3 = 2; static int k4; int main() { static int m1 = 2, m2; int i = 1; char*p; char str[10] = "hello"; char*q = "hello"; p = (char *)malloc(100); free(p); printf("栈区-变量地址 i:%p\n", &i); printf("栈区-变量地址 p:%p\n", &p); printf("栈区-变量地址 str:%p\n", str); printf("栈区-变量地址 q:%p\n", &q); printf("堆区地址-动态申请:%p\n", p); printf("全局外部有初值 k1:%p\n", &k1); printf(" 外部无初值 k2:%p\n", &k2); printf("静态外部有初值 k3:%p\n", &k3); printf(" 外静无初值 k4:%p\n", &k4); printf(" 内静态有初值 m1:%p\n", &m1); printf(" 内静态无初值 m2:%p\n", &m2); printf(" 文字常量地址:%p, %s\n", q, q); printf(" 程序区地址:%p\n", &main); return 0; }

    输出结果如下:


    static 关键字最基本的用法是:

    • 1、被 static 修饰的变量属于类变量,可以通过类名.变量名直接引用,而不需要 new 出一个类来
    • 2、被 static 修饰的方法属于类方法,可以通过类名.方法名直接引用,而不需要 new 出一个类来

    被 static 修饰的变量、被 static 修饰的方法统一属于类的静态资源,是类实例之间共享的,换言之,一处变、处处变。

    在 C++ 中,静态成员是属于整个类的而不是某个对象,静态成员变量只存储一份供所有对象共用。所以在所有对象中都可以共享它。使用静态成员变量实现多个对象之间的数据共享不会破坏隐藏的原则,保证了安全性还可以节省内存。

    静态成员的定义或声明要加个关键 static。静态成员可以通过双冒号来使用即 <类名>::<静态成员名>。

    通过类名调用静态成员函数和非静态成员函数:

    class Point { public: void init() { } static void output() { } }; void main() { Point::init(); Point::output(); }

    报错:

    'Point::init' : illegal call of non-static member function

    结论 1:不能通过类名来调用类的非静态成员函数。

    通过类的对象调用静态成员函数和非静态成员函数。

    class Point { public: void init() { } static void output() { } }; void main() { Point pt; pt.init(); pt.output(); }

    编译通过。

    结论 2:类的对象可以使用静态成员函数和非静态成员函数。

    在类的静态成员函数中使用类的非静态成员。

    #include <stdio.h> class Point { public: void init() { } static void output() { printf("%d\n", m_x); } private: int m_x; }; void main() { Point pt; pt.output(); }

    编译出错:

    error C2597: illegal reference to data member 'Point::m_x' in a static member function

    因为静态成员函数属于整个类,在类实例化对象之前就已经分配空间了,而类的非静态成员必须在类实例化对象后才有内存空间,所以这个调用就出错了,就好比没有声明一个变量却提前使用它一样。

    结论3:静态成员函数中不能引用非静态成员。

    在类的非静态成员函数中使用类的静态成员。

    class Point { public: void init() { output(); } static void output() { } }; void main() { Point pt; Pt.init(); pt.output(); }

    编译通过。

    结论 4:类的非静态成员函数可以调用用静态成员函数,但反之不能。

    使用类的静态成员变量。

    #include <stdio.h> class Point { public: Point() { m_nPointCount++; } ~Point() { m_nPointCount--; } static void output() { printf("%d\n", m_nPointCount); } private: static int m_nPointCount; }; void main() { Point pt; pt.output(); }

    按 Ctrl+F7 编译无错误,按 F7 生成 EXE 程序时报链接错误。

    error LNK2001: unresolved external symbol "private: static int Point::m_nPointCount" (?m_nPointCount@Point@@0HA)

    这是因为类的静态成员变量在使用前必须先初始化。

    在 main() 函数前加上 int Point::m_nPointCount = 0; 再编译链接无错误,运行程序将输出 1。

    结论 5:类的静态成员变量必须先初始化再使用。

    思考总结:静态资源属于类,但是是独立于类存在的。从 J 类的加载机制的角度讲,静态资源是类初始化的时候加载的,而非静态资源是类实例化对象的时候加载的。 类的初始化早于类实例化对象,比如 Class.forName("xxx") 方法,就是初始化了一个类,但是并没有实例化对象,只是加载这个类的静态资源罢 了。所以对于静态资源来说,它是不可能知道一个类中有哪些非静态资源的;但是对于非静态资源来说就不一样了,由于它是实例化对象出来之后产生的,因此属于类的这些东西它都能认识。所以上面的几个问题答案就很明确了:

    • 1)静态方法能不能引用非静态资源?不能,实例化对象的时候才会产生的东西,对于初始化后就存在的静态资源来说,根本不认识它。
    • 2)静态方法里面能不能引用静态资源?可以,因为都是类初始化的时候加载的,大家相互都认识。
    • 3)非静态方法里面能不能引用静态资源?可以,非静态方法就是实例方法,那是实例化对象之后才产生的,那么属于类的内容它都认识。

    static 修饰类:这个用得相对比前面的用法少多了,static 一般情况下来说是不可以修饰类的, 如果 static 要修饰一个类,说明这个类是一个静态内部类(注意 static 只能修饰一个内部类),也就是匿名内部类。像线程池 ThreadPoolExecutor 中的四种拒绝机制 CallerRunsPolicy、AbortPolicy、DiscardPolicy、 DiscardOldestPolicy 就是静态内部类。静态内部类相关内容会在写内部类的时候专门讲到。)

    • (1)静态成员函数中不能调用非静态成员。
    • (2)非静态成员函数中可以调用静态成员。因为静态成员属于类本身,在类的对象产生之前就已经存在了,所以在非静态成员函数中是可以调用静态成员的。
    • (3)静态成员变量使用前必须先初始化(如 int MyClass::m_nNumber = 0;),否则会在 linker 时出错。

    一般总结:在类中,static 可以用来修饰静态数据成员和静态成员方法。

    静态数据成员

    • (1)静态数据成员可以实现多个对象之间的数据共享,它是类的所有对象的共享成员,它在内存中只占一份空间,如果改变它的值,则各对象中这个数据成员的值都被改变。
    • (2)静态数据成员是在程序开始运行时被分配空间,到程序结束之后才释放,只要类中指定了静态数据成员,即使不定义对象,也会为静态数据成员分配空间。
    • (3)静态数据成员可以被初始化,但是只能在类体外进行初始化,若未对静态数据成员赋初值,则编译器会自动为其初始化为 0。
    • (4)静态数据成员既可以通过对象名引用,也可以通过类名引用。

    静态成员函数

    • (1)静态成员函数和静态数据成员一样,他们都属于类的静态成员,而不是对象成员。
    • (2)非静态成员函数有 this 指针,而静态成员函数没有 this 指针。
    • (3)静态成员函数主要用来方位静态数据成员而不能访问非静态成员。

    再给一个利用类的静态成员变量和函数的例子以加深理解,这个例子建立一个学生类,每个学生类的对象将组成一个双向链表,用一个静态成员变量记录这个双向链表的表头,一个静态成员函数输出这个双向链表。