5

static关键字你真的懂了吗?

 2 years ago
source link: https://blog.csdn.net/m0_61163395/article/details/123557429
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

static关键字

1、Java中的static

1.1 static关键字的定义和性质

1)static翻译为"静态的";

2)static修饰的方法是静态方法,static修饰的变量是静态变量;

3)使用static修饰的元素都称为静态的,都可以用"类名."的方式访问,当然也可以用"引用."的方式访问【但不建议】

4)采用"引用."的方式访问的时候,即使引用是null,也不会出现空指针异常,因为访问静态数据不需要对象的存在;

1.2 实例变量与静态变量

1.2.1 实例变量

什么时候成员变量声明为实例变量呢?

–所有对象都有这个属性,但是这个属性的值会随着对象的变化而变化【不同对象的这个属性具体值不同】

–实例变量在构造方法进行的时候初始化,存在堆内存中

以下列例子说明:

public class helloworld {
	public static void main(String[] args) {
        Chinese zhangsan = new Chinese("1","zhangsan","Chinese");
        System.out.println(zhangsan.country);
	}
}
class Chinese{
	String id;
	String name;
	String country;
	public Chinese(String id, String name, String country) {
		this.id = id;
		this.name = name;
		this.country = country;
	}
}

1.2.2 静态变量

什么时候成员变量声明为静态变量呢?

–所有对象都有这个属性,并且所有对象的这个属性的值是一样的,建议定义为静态变量,节省内存的开销

**静态变量在类加载的时候初始化,内存在方法区中开辟。**访问的时候不需要创建对象,直接使用"类名.静态变量名"的方式访问;

  • 局部变量存储在栈内存当中;
  • 实例变量在构造方法进行的时候初始化,存在堆内存中(成员变量的一种)
  • 静态变量在类加载的时候初始化,存在方法区内存中(成员变量的一种)

以下列例子说明:

public class helloworld {
	public static void main(String[] args) {
        Chinese zhangsan = new Chinese("1","zhangsan");
        System.out.println(zhangsan.country);
        System.out.println(Chinese.country);
        zhangsan = null;
        System.out.println(zhangsan.country);
	}
}
class Chinese{
	String id;
	String name;
	static String country = "chinese";
	public Chinese(String id, String name) {
		this.id = id;
		this.name = name;
	}
}

输出结果为三个Chinese;

1)所有静态的数据都是可以采用"类名.",也可以采用"引用.",但是建议采用类名.的方式访问;

2)采用"引用."的方式访问时,即使是null,也不会出现空指针异常,因为访问静态变量的时候不需要对象的存在;

1.3 静态代码块

1)语法格式:

static{
	//java语句
}

2)静态代码块在类加载时执行,并且执行一次

3)静态代码块在一个类中可以编写多个,并且遵循自上而下的顺序依次执行;

4)静态代码块可以用在项目中要求在类加载的时刻/时机执行代码完成日志的记录,那么这段记录日志的代码就可以编写在静态代码块当中,完成日志记录;

5)静态代码块是java为程序员准备一个特殊的时刻,这个时刻被称为类加载时刻,若希望在此刻执行一段特殊的程序,这段代码可以放到静态代码块当中;

public class StaticTest{
	static{
		System.out.println("类加载--->1");
    }
    static{
		System.out.println("类加载--->2");
    }
}

1.4 *实例语句块 / 代码块

1)实例代码块可以编写多个,也是遵循自上而下的顺序依次执行;

2)实例代码块在构造方法执行之前执行,构造方法执行一次,实例代码块对应执行一次;

3)实例代码块也是java语言为程序员准备一个特殊的时机,这个时机被称为:对象初始化时机

public class helloworld{
    public class Test{
    //构造函数
    	public Test(){
    		System.out.println("Test类的缺省构造器执行");
    	}
    }    
    //实例代码块
    {
		System.out.println(1);
    }
    //实例代码块
    {
		System.out.println(2);
    }
    public static void main(String[] args){
    	System.out.println("main begin");
    	new helloworld();
	}
}

1.5 static总结

public static void main(String[] args)

1.5.1 对java语句的解读

1)public代表公开的,在任何位置都可以访问;

2)static表示静态的,使用"类名."的方式访问,不需要创建对象

3)void表示main方法执行结束之后不返回任何值;

4)(String[] args)是参数列表;

1.5.2 什么时候定义为静态的?

1)方法描述的是动作,当所有的对象执行这个动作的时候,最终产生影响是一样的,那么这个动作已经不再属于某一个对象动作了,可以将这个动作提升为类级别的动作,模板级别的对象;

2)静态方法中无法直接访问实例变量和实例方法;

3)大多数方法都定义为实例方法,一般一个行为或一个动作在发生的时候都需要对象的参与而大多数“工具类”当中的方法都是静态的,因为工具类就是方便编程的,为了方便方法的调用,自然不需要new对象是最好的;

2、C/C++中的static

2.1 局部变量

2.1.1 普通局部变量

  • 在任何一个函数内部定义的变量(不加static修饰符)都属于这个范畴。编译器一般不对普通局部变量进行初始化,也就是说它的值在初始时是不确定的,除非对其显式赋值。
  • 普通局部变量存储于进程栈空间,使用完毕会立即释放

2.1.2 静态局部变量

  • 静态局部变量使用static修饰符定义,即使在声明时未赋初值,编译器也会把它初始化为0
  • 静态局部变量**存储于进程的全局数据区,即使函数返回,它的值也会保持不变。**编译器自动对其初始化,其作用域为局部作用域,当定义它的函数结束时,其作用域随之结束
#include <stdio.h>

void fn(void)
{
    int n = 10;
    
    printf("n=%d\n", n);
    n++;
    printf("n++=%d\n", n);

}

void fn_static(void)
{
    static int n = 10;

    printf("static n=%d\n", n);
    n++;
    printf("n++=%d\n", n);

}

int main(void)
{
    fn();
    printf("--------------------\n");
    fn_static();
    printf("--------------------\n");
    fn();
    printf("--------------------\n");
    fn_static();
    return 0;
}

运行结果如下:

n=10
n++=11
static n=10
n++=11
n=10
n++=11
static n=11
n++=12

可见,静态局部变量的效果跟全局变量有异曲同工之妙,但是位于函数体内部,有利于程序的模块化了。

2.2 全局变量

全局变量定义在函数体外部,在全局数据区分配存储空间,且编译器会自动对其初始化

2.2.1 普通全局变量

普通全局变量对整个工程可见,其他文件可以使用extern外部声明后直接使用。也就是说其他文件不能再定义一个与其相同名字的变量了(否则编译器会认为它们是同一个变量)。

2.2.2 静态全局变量

  • 静态全局变量仅对当前文件可见,其他文件不可访问,其他文件可以定义与其同名的变量,两者互不影响。
  • 在定义不需要与其他文件共享的全局变量时,加上static关键字能够有效地降低程序模块之间的耦合,避免不同文件同名变量的冲突,且不会误使用。

2.3 函数

函数的使用方式与全局变量类似,在函数的返回类型前加上static,就是静态函数。其特性如下:

  • 静态函数只能在声明它的文件中可见,其他文件不能引用该函数
  • 不同的文件可以使用相同名字的静态函数,互不影响
  • 非静态函数可以在另一个文件中直接引用,甚至不必使用extern声明

2.4 面向对象使用static

2.4.1 静态数据成员

在类内数据成员的声明前加上static关键字,该数据成员就是类内的静态数据成员。其特点如下:

  • 静态数据成员存储在全局数据区,静态数据成员在定义时分配存储空间,所以不能在类声明中定义
  • 静态数据成员是类的成员,无论定义了多少个类的对象,静态数据成员的拷贝只有一个,且对该类的所有对象可见。也就是说任一对象都可以对静态数据成员进行操作。而对于非静态数据成员,每个对象都有自己的一份拷贝。

由于上面的原因,静态数据成员不属于任何对象,在没有类的实例时其作用域就可见,在没有任何对象时,就可以进行操作

  • 和普通数据成员一样,静态数据成员也遵从public, protected, private访问规则
  • 静态数据成员的初始化格式:<数据类型><类名>::<静态数据成员名>=<值>
  • 类的静态数据成员有两种访问方式:<类对象名>.<静态数据成员名> 或 <类类型名>::<静态数据成员名>
    同全局变量相比,使用静态数据成员有两个优势:
  • 静态数据成员没有进入程序的全局名字空间,因此不存在与程序中其它全局名字冲突的可能性
    可以实现信息隐藏。静态数据成员可以是private成员,而全局变量不能

2.4.2 静态成员函数

与静态数据成员类似,静态成员函数属于整个类,而不是某一个对象,其特性如下:

  • 静态成员函数没有this指针,它无法访问属于类对象的非静态数据成员,也无法访问非静态成员函数,它只能调用其余的静态成员函数
  • 出现在类体外的函数定义不能指定关键字static
    成员名> 或 <类类型名>::<静态数据成员名>
    同全局变量相比,使用静态数据成员有两个优势:
  • 静态数据成员没有进入程序的全局名字空间,因此不存在与程序中其它全局名字冲突的可能性
    可以实现信息隐藏。静态数据成员可以是private成员,而全局变量不能

2.4.2 静态成员函数

与静态数据成员类似,静态成员函数属于整个类,而不是某一个对象,其特性如下:

  • 静态成员函数没有this指针,它无法访问属于类对象的非静态数据成员,也无法访问非静态成员函数,它只能调用其余的静态成员函数
  • 出现在类体外的函数定义不能指定关键字static
  • 非静态成员函数可以任意地访问静态成员函数和静态数据成员

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK