Java|static关键字【实例变量与类变量、实例方法与类方法】_请简述static关键字-程序员宅基地

技术标签: Java  static  # Java基础  

在这里插入图片描述

Hello 大家好,开始更新有关Java的文章,第一篇就是关于static关键字的,个人认为这个this关键字是Java中蛮重要的,一定要清楚地掌握才可以

一、static关键字是什么?

static是静态的意思,是一个修饰符,就像是一个形容词,是用来形容类,变量,方法的。在声明static关键字时,可以在前面加上static修饰,用static修饰的成员变量称做类变量(static变量、静态变量)

二、加了static关键字有什么用?

  • 被static关键字修饰的方法或者变量不需要依赖于对象来进行访问,只要类被加载了,就可以通过类名去进行访问
  • static还有一个很关键的作用就是可以通过static来构建一个静态代码块,在这个静态代码块中,你可以将一些变量初始化,在程序加载的时候static代码块是优先加载的,因此可以说成是用来形成静态代码块以优化程序性能,【这一块我会在下一篇文章中具体讲到】

三、static静态变量和实例变量

说了一些static关键字的基本理念和它的作用,空谈不行,要将其应用到实例化代码中,接下来讲讲静态变量和实例变量的声明

1、两种变量的声明

  • 比方说我们下面定义一个System类
class System{
    
	int name;		//姓名
	int num;		//编号
	static int onlineNumber;	//在线人数
}
  • 可以看出,这里的姓名和编号都是属于普通的实例成员变量,但是对于在线人数onlineNumber,前面却加了static关键字,表明其是一个静态变量

注意:只要成员变量可以用static关键字修饰,普通的局部变量不可以,是非法的

2、两种变量的区别

  • 对于实例变量,改变其中一个对象的实例变量不会影响其他对象的实例变量,因为它们在堆内存中是一块块独立的区域,各自有各自的内存,是互不相干的;但是你通过任何对象去修改一个static修饰的成员变量,都可以将其修改,改变其中一个对象的类变量会影响其他对象的这个类变量,通俗一点来讲就是对象共享类变量
  • 在Java中,当程序执行的时候,类的【字节码文件】会被加载到内存中,如果类没有创建对象,则类的成员变量不会被分配内存,但对于类变量,也就是静态变量,它有在堆中有一个专属的静态变量区,,当JVM虚拟机将字节码加载到内存时,就会为这个onlineNumber在线人数在堆区中分配出一段空间用于放置
  • 当你去通过类定义对象的时候,这个时候才会在堆内存中为不同的对象分配不同的内存空间,上面我们说过,所有对象的类变量都是相同的一块内存空间,光这么说太抽象了,我们来看个

【堆栈内存原理分布图】

在这里插入图片描述

  • 然后在配合一个示例,大家可以先对照着我前面讲的把这个逻辑理一遍

具体案例

public class User {
    
    //static修饰的成员变量,内存中只有一份,可以被共享
    public static int onlineNumber = 16;
    //静态成员变量,直接用类名访问

    //实例成员变量 - 用对象访问
    private String name;
    private int age;

    public static void main(String[] args) {
    
        //直接用类名访问,不用对象
        //1.类名.静态成员变量
        System.out.println(User.onlineNumber);

        //2.对象名.实例成员变量
        User u = new User();
        //System.out.println(User.name); 不能用类名去访问实例成员变量
        u.name = "张三";
        u.age = 21;
        System.out.println(u.name);
        System.out.println(u.age);
        System.out.println("-----------");
        u.onlineNumber++;       //新来了一个人

        User u2 = new User();
        u2.name = "李四";
        u2.age = 22;
        System.out.println(u2.name);
        System.out.println(u2.age);
        System.out.println("-----------");
        u2.onlineNumber++;       //体现了共享的特点


        System.out.println(u.onlineNumber);
        System.out.println(User.onlineNumber);
        System.out.println(onlineNumber);
        //同一个类中静态成员变量的访问可以省略类型
    }
}

这个是运行结果
在这里插入图片描述

  • 好,我们继续回来,通过这个案例我们可以很清楚的看到,类的实例变量和静态变量在调用和分步时是如何实现的。每个对象都指向堆区中的一块内存地址,每一块内存地址都是独立的,互不干扰,但是后面可以看出,两块不同的堆区内存均指向同一块静态变量区的地址,这就很好地印证了我上面说的那一点,所有对象的类变量都是相同的一块内存空间
  • 从运行结果可以看出,通过下面两条语句,看运行结果,都可以实现在线人数的递增,这就印证了对象共享类变量这句话
u.onlineNumber++;
u2.onlineNumber++;
  • 有一点要注意的是这句代码是不可行的,上面讲到过,当还没有通过类去构建对象的时候,是不会在堆内存中为其分配空间的,也就是说,这个时候堆内存中完全没有name这个变量,那你去直接用类名访问的话,是在访问哪个对象的姓名呢?
//System.out.println(User.name); 不能用类名去访问实例成员变量
  • 好,我们讲本小块的最后一个知识点,就是如何去访问这个静态成员变量,一共是有下述三种方法,这三种方法就对应最后的这三句代码
    ①类名.静态成员变量(推荐)
    ②对象名.静态成员变量(不推荐)
    ③同一个类中,访问静态成员可以省略类名不写
 System.out.println(u.onlineNumber);
 System.out.println(User.onlineNumber);
 System.out.println(onlineNumber);
 //同一个类中静态成员变量的访问可以省略类型

四、static静态方法和实例方法

1、两种方法的声明

//静态方法 - 实现通用功能
public static int getMax(int x,int y){
    
	return x > y ? x : y;
}

//实例方法 - 直接访问对象的实例成员
public void speak(){
    
	name = "张三";
	System.out.println(name + "在说话");
}
  • 通过以上代码,相信大家对静态方法和实例方法有了一个基本的认识,在声明方法时候
  • 如果你想要实现一个通用功能,那就用静态方法;
  • 但如果你想要直接访问对象的实例成员,则用实例方法

注意: static关键字需要放在方法的类型之前,而不可以乱放置;而且不可以用static修饰构造方法

2、两种方法的区别

接下来说一说两种方法之间的差异性

  • 上面在说到类加载时的字节码文件会被加载到内存中,而方法中存在一个入口地址,类的实例方法不会被分配入口地址,只有当该类创建了对象后,类中的实例方法才会被分配入口地址。而且当你创建了一个对象之后再继续创建对象时,不会再为实例方法分配入口地址,通俗地说就是,方法的入口地址所有对象共享

那如何将变量和方法联系起来呢,接下来我们就来说说

  • 在实例方法中你不仅可以操作实例变量,而且可以操作类变量,也就是static变量
  • 对于实例方法,它还可以调用类中其他的实例方法和类方法(不包括构造方法)
public static void main(String[] args) {
    
    //1.类名.静态成员方法
    System.out.println(Student.GetMax(10, 30));
    System.out.println(GetMax(50, 99));     //可不用类名

    //study();     需要对象名去访问
    //2.对象名.实例方法
    Student st = new Student();
    st.name = "孙悟空";
    st.study();

    //3.对象名.静态成员方法(语法可行,但是不推荐)
    System.out.println(st.GetMax(1,9));
}
  • 从上述代码我们可以看出静态成员方法和实例成员方法的调用格式,对于静态成员方法,它的格式有两种,我们也是推荐第一种,因为系统也是支持第一种调用方法,
  • ①类名.静态成员方法
    ②对象名.静态成员方法(语法可行,但是不推荐)
    对于这个,大家可以记住一句话

对于静态的东西,直接用类名调用即可,不会出错

  • 而对于这个实例成员方法,则只能用对象名去调用,因为其是属于对象的一部分,和实例成员变量一样,不可以用类名去调用,更不能直接调用,因为具体的对象其所对应的具体方法,内部的成员变量 也是相互对应的

【内存原理剖析】

下面是一句代码的内存结构图,可以很形象地展示出用类名调用类方法的过程

在这里插入图片描述

  • 从下面这张图可以看出,对于同一类中直接访问静态方法,它会找到方法区中的getMax()方法,然后访问输出,但是对于实例方法,只可以用定义好的,实际存在的对象去访问,已经加载完之后会归属到对象中,因此会通过对象的引用去访问方法区中对应的study()实例方法,打印出来的就是孙悟空在做什么,就体现了实例化这个特性
    在这里插入图片描述

五、static关键字注意事项

1、静态方法只能访问静态的成员,不可以’直接’访问实例成员
2、实例方法可以访问静态的成员,也可以访问实例成员
3、静态方法中是不可以出现this关键字的

我们到具体的代码中来看

package com.itheima.d1_static_field;
//static 访问注意事项:

public class Test3 {
    
    public static int OnlineNum = 100;
    String name;

    //1.静态方法只能访问静态的成员,不可以'直接'访问实例成员
    public static void gg()
    {
    
        System.out.println(OnlineNum);
        System.out.println(Test3.OnlineNum);
       // System.out.println(name);       //不可以直接访问实例成员

        Test3 t3 = new Test3();
        System.out.println(t3.name);        //但是可以创建临时变量来间接访问
    }
}
  • 从中可以看出,对于静态方法,可以去访问静态变量,但是不可以访问实例成员变量,如果一定要访问的话,可以去构建一个当前类的对象,因为实例成员变量只能通过对象去访问

public static void hold()
{
    
    System.out.println("====ff====");
}
//2.实例方法可以访问静态的成员,也可以访问实例成员
public void run()
{
    
    OnlineNum = 200;
    hold();             //体现了静态变量和静态方法共享的特性
    name = "张三";
    System.out.println(this);       //可以出现在实例方法中
}
  • 上述代码可以看出,对于实例方法,不仅可以访问实例成员变量,还可以访问静态成员变量,因为静态成员变量是共享的。不仅如此,静态方法也可以访问,也就是hold()这个方法,很好地体现了静态变量和静态方法共享的特性
//3.静态方法中是不可以出现this关键字的
public static void ff()
{
    
    //System.out.println(this);   //this代表当前对象
}
  • 最后一点,就是对于静态方法中不可以出现this关键字,因为this代表的是当前对象,静态方法中是可以不用声明实例对象的,但是this可以出现在实例方法中,就如上一个注意事项中的最后一句代码,this代表正好是这个对象所对应的地址,就可以访问其所对应的成员变量

六、总结与回顾

好的,我们本文的内容就讲到这里,关于static在Java中的基础知识,通过这篇文章,相信大家已经有所收获,如果还觉有些模糊,可以自己去编译器中运行一下(我用的IDEA),感受一下这个关键字的魅力

有关static关键字的应用知识会在下篇文章讲到,如果想知道记得关注我哦,本文如果有任何疑问,可以于评论区或私信留言,感谢您的观看

在这里插入图片描述

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/Fire_Cloud_1/article/details/126788449

智能推荐

iMeta | 南农沈其荣团队发布微生物网络分析和可视化R包ggClusterNet-程序员宅基地

文章浏览阅读1k次。点击蓝字 关注我们ggClusterNet:包含多种基于模块可视化布局算法的微生物网络挖掘R包https://doi.org/10.1002/imt2.32SHORT COMMUNICATIONVolume1, Issue3●2022年6月13日,南农沈其荣团队在iMeta在线发表了题为“ggClusterNet: An R package for microbiome ..._微生物网络分析需要把所有数据都输入吗

exec用法_-exec-程序员宅基地

文章浏览阅读1.1w次,点赞6次,收藏18次。 博客 学院 下载 GitChat TinyMind 论坛 APP 问答 商城 VIP 活动 招聘 ITeye 写博客 发Chat 登录注册 我的博客 消息(3) 帐号设置 反馈 帮助 退出 转一个强大的linux命令——find之exec2017年01月09日 11:23:20阅读数:7..._-exec

在单片机上利用一个定时器和二行代码轻轻松松实现多任务的运行(基于时间片)_一个定时器执行多个程序-程序员宅基地

文章浏览阅读3.2k次,点赞4次,收藏14次。因为我常用的是stm32F4系列单片机,所以采用其滴答定时器作为时基定时器(如果你使用的单片机是别款,只要单片机上有个定时器都可以,另外也得有中断处理函数)(另外如果用的是stm32等单片机,片上具有滴答定时器,可以省掉1、2步骤,在HAL库下直接用HAL_GetTick()代替GetCount()即可,其他类似)1.首先初始化定时器,本人一般设置定时时间为1ms,这个可以是具体情况而定。..._一个定时器执行多个程序

python 使用matplotlib绘图时 出现Exceeded cell block limit (set ‘agg.path.chunksize‘ rcparam)_exceeded cell block limit (set 'agg.path.chunksize-程序员宅基地

文章浏览阅读5.2k次。首先,如果你的数据长度在百万级左右的,正常是不会出现这句话的。所以用不到下面两句话:matplotlib.rcParams['agg.path.chunksize'] = 10000matplotlib.rcParams.update(matplotlib.rc_params())大概率是本身数据里面存在问题,比如我经常碰到的,整个数据中有个别字符串类型的,与其他的double类型数据不一样。..._exceeded cell block limit (set 'agg.path.chunksize' rcparam)

iPhone开发之UITableView的小试牛刀 利用MVC模式从plist文件读取数据并字典转模型的格式实现_[self settingframe];-程序员宅基地

文章浏览阅读1k次。新建一个具有simple VIew的工程,并把相关图片拉进资源文件夹在Supporting files文件夹下新建work.plist文件,编辑内容如下图:在工程下新建model文件夹,并在文件夹内新建model类Hero根据文件的字典属性编辑Hero.h如下://// Hero.h// 作业整理//// Created by apple on 15/9/_[self settingframe];

数据质量最佳实践案例:如何利用数据质量来实现业务文化_数据质量工程实践-程序员宅基地

文章浏览阅读3.9k次。作者:禅与计算机程序设计艺术 《57. 数据质量最佳实践案例:如何利用数据质量来实现业务文化》引言随着数字化时代的到来,数据已经成为企业成功的基础。数据质量的保证和数据文化的建设,对于企业的业务发展和良好的数据_数据质量工程实践

随便推点

【并查集】银河英雄传说 (luogu 1196/ssl 1225)_银河英雄传说 描述 公元五八○一年,地球居民迁移至金牛座α第二行星,在那里发表银-程序员宅基地

文章浏览阅读268次。银河英雄传说luogu 1196ssl 1225题目大意:有n列船,每列一开始有一艘船,可以将某一艘船所在的列所有船接到另外一列,然后会问某两艘船是否在一列,如果在那中间有多少艘船_银河英雄传说 描述 公元五八○一年,地球居民迁移至金牛座α第二行星,在那里发表银

Windows下 MySql通过拷贝data目录迁移数据库的方法_mysql文件夹里面的date能直接复制到新数据库吗-程序员宅基地

文章浏览阅读2.8k次,点赞3次,收藏8次。现举例说明通过COPY文件夹data下数据库文件,进行数据拷贝的步骤;源数据库运行在A服务器上,拷贝到B服务器,假定B服务器上MySQL数据库已经安装完成,为空数据库。选中要拷贝的数据库及ibdata1文件到B服务器的MySQL数据库的data文件夹下,启动目标数据库服务net start mysql,即可查看到导过来的所有数据库了。MySQL数据库的文件目录下图所示,_mysql文件夹里面的date能直接复制到新数据库吗

Android自定义View获取background的颜色和图片_android view 获取背景颜色-程序员宅基地

文章浏览阅读1.4w次,点赞2次,收藏4次。我们自定义View的时候有时会用到background,为了调用者更好的使用,我们可以复用Android自带的background属性,而不是自定义属性.获取并修改background的内容如下(以自定义TextView为例): paint = new Paint(); paint.setAntiAlias(true); Drawable backgro_android view 获取背景颜色

org/jaxen/JaxenException-程序员宅基地

文章浏览阅读1.2k次。dom4j用到xpath的时候要用到相应的jar包jaxen.jar,没这个包就报上边的错了._ora/jaxen/jaxenexception

阿里飞冰 设置 vscode 编辑器 启动脚本_vscode插件飞冰-程序员宅基地

文章浏览阅读1.4k次,点赞3次,收藏6次。文章目录检查vscode安装设置阿里飞冰 编辑器检查vscode安装win+Rcmdcode --version设置阿里飞冰 编辑器设置自定义编辑器启动脚本code ${cwd}_vscode插件飞冰

chatgpt赋能python:Python构造函数的作用_python中构造函数有什么用-程序员宅基地

文章浏览阅读68次。在Python中,构造函数是一种特殊的函数,用于创建和初始化对象。当我们创建一个新的对象时,Python将会自动调用该对象的构造函数。构造函数可用于指定对象的属性和初始状态。在Python中,构造函数的名称是__init__,它是一个方法(函数),通常是在类定义中定义的。当我们创建一个新的对象时,Python将会自动调用对象的__init__方法。本文由chatgpt生成,文章没有在chatgpt生成的基础上进行任何的修改。以上只是chatgpt能力的冰山一角。作为通用的Aigc。_python中构造函数有什么用