分享几个javastatic关键字的常见误区(代码片段)

xhmj12 xhmj12     2022-12-01     601

关键词:

上一篇:真实土木工程专业现状。。

这两天有一个网友,在微信群里讨论面试情况。提到了一个 static 关键字的问题,不少网友回答错误了,我这里整理一篇文章分享给大家。不喜轻喷!

static 关键字是很多朋友在编写代码和阅读代码时碰到的比较难以理解的一个关键字,也是各大公司的面试官喜欢在面试时问到的知识点之一。下面就先讲述一下 static 关键字的用法和平常容易误解的地方,最后列举了一些面试笔试中常见的关于 static 的考题。以下是本文的目录大纲:

  1. static关键字的用途

  2. static关键字的误区

  3. 常见的笔试面试题

static 关键字的用途

在《Java编程思想》P86 页有这样一段话:

static 方法就是没有 this 的方法。在 static 方法内部不能调用非静态方法,反过来是可以的。而且可以在没有创建任何对象的前提下,仅仅通过类本身来调用 static 方法。这实际上正是 static 方法的主要用途。

这段话虽然只是说明了 static 方法的特殊之处,但是可以看出 static 关键字的基本作用,简而言之,一句话来描述就是:

方便在没有创建对象的情况下来进行调用(方法/变量)。

很显然,被 static 关键字修饰的方法或者变量不需要依赖于对象来进行访问,只要类被加载了,就可以通过类名去进行访问。

static 可以用来修饰类的成员方法、类的成员变量,另外可以编写 static 代码块来优化程序性能。

static 方法

static 方法一般称作静态方法,由于静态方法不依赖于任何对象就可以进行访问,因此对于静态方法来说,是没有 this 的,因为它不依附于任何对象,既然都没有对象,就谈不上 this 了。并且由于这个特性,在静态方法中不能访问类的非静态成员变量和非静态成员方法,因为非静态成员方法/变量都是必须依赖具体的对象才能够被调用。

但是要注意的是,虽然在静态方法中不能访问非静态成员方法和非静态成员变量,但是在非静态成员方法中是可以访问静态成员方法/变量的。举个简单的例子:

static 方法

在上面的代码中,由于 print2 方法是独立于对象存在的,可以直接用过类名调用。假如说可以在静态方法中访问非静态方法/变量的话,那么如果在 main 方法中有下面一条语句:

MyObject.print2();

此时对象都没有,str2 根本就不存在,所以就会产生矛盾了。同样对于方法也是一样,由于你无法预知在 print1 方法中是否访问了非静态成员变量,所以也禁止在静态成员方法中访问非静态成员方法。

而对于非静态成员方法,它访问静态成员方法/变量显然是毫无限制的。

因此,如果说想在不创建对象的情况下调用某个方法,就可以将这个方法设置为 static。我们最常见的 static 方法就是 main 方法,至于为什么 main 方法必须是 static 的,现在就很清楚了。因为程序在执行 main 方法的时候没有创建任何对象,因此只有通过类名来访问。

static 变量

static 变量也称作静态变量,静态变量和非静态变量的区别是:静态变量被所有的对象所共享,在内存中只有一个副本,它当且仅当在类初次加载时会被初始化。而非静态变量是对象所拥有的,在创建对象的时候被初始化,存在多个副本,各个对象拥有的副本互不影响。

static 成员变量的初始化顺序按照定义的顺序进行初始化。

static 代码块

static 关键字还有一个比较关键的作用就是 用来形成静态代码块以优化程序性能。static 块可以置于类中的任何地方,类中可以有多个 static 块。在类初次被加载的时候,会按照 static 块的顺序来执行每个 static 块,并且只会执行一次。

为什么说 static 块可以用来优化程序性能,是因为它的特性:只会在类加载的时候执行一次。下面看个例子:

class Person
    private Date birthDate;
     
    public Person(Date birthDate) 
        this.birthDate = birthDate;
    
     
    boolean isBornBoomer() 
        Date startDate = Date.valueOf("1946");
        Date endDate = Date.valueOf("1964");
        return birthDate.compareTo(startDate)>=0 && birthDate.compareTo(endDate) < 0;
    

isBornBoomer 是用来这个人是否是 1946-1964 年出生的,而每次 isBornBoomer 被调用的时候,都会生成 startDate 和 birthDate 两个对象,造成了空间浪费,如果改成这样效率会更好:

class Person
    private Date birthDate;
    private static Date startDate,endDate;
    static
        startDate = Date.valueOf("1946");
        endDate = Date.valueOf("1964");
    
     
    public Person(Date birthDate) 
        this.birthDate = birthDate;
    
     
    boolean isBornBoomer() 
        return birthDate.compareTo(startDate)>=0 && birthDate.compareTo(endDate) < 0;
    

因此,很多时候会将一些只需要进行一次的初始化操作都放在 static 代码块中进行。

static关键字的误区

static关键字会改变类中成员的访问权限吗?

有些初学的朋友会将 java 中的 static 与 C/C++ 中的 static 关键字的功能混淆了。在这里只需要记住一点:与 C/C++ 中的 static 不同,Java 中的 static 关键字不会影响到变量或者方法的作用域。在 Java 中能够影响到访问权限的只有 private、public、protected(包括包访问权限)这几个关键字。看下面的例子就明白了:

提示错误Person.age 不可视,这说明 static 关键字并不会改变变量和方法的访问权限。

能通过 this 访问静态成员变量吗?

虽然对于静态方法来说没有 this,那么在非静态方法中能够通过 this 访问静态成员变量吗?先看下面的一个例子,这段代码输出的结果是什么?

public class Main   
    static int value = 33;
 
    public static void main(String[] args) throws Exception
        new Main().printValue();
    
 
    private void printValue()
        int value = 3;
        System.out.println(this.value);
    
33

这里面主要考察队 this 和 static 的理解。this 代表什么?this 代表当前对象,那么通过new Main()来调用printValue的话,当前对象就是通过new Main()生成的对象。而 static 变量是被对象所享有的,因此在 printValue 中的 this.value 的值毫无疑问是 33。在 printValue 方法内部的 value 是局部变量,根本不可能与 this 关联,所以输出结果是 33。在这里永远要记住一点:静态成员变量虽然独立于对象,但是不代表不可以通过对象去访问,所有的静态方法和静态变量都可以通过对象访问(只要访问权限足够)。

static能作用于局部变量么?

在 C/C++ 中 static 是可以作用域局部变量的,但是在 Java 中切记:static 是不允许用来修饰局部变量。不要问为什么,这是 Java 语法的规定。

常见的笔试面试题

下面列举一些面试笔试中经常遇到的关于 static 关键字的题目,仅供参考,如有补充欢迎下方留言。

下面这段代码的输出结果是什么?

public class Test extends Base
    static
        System.out.println("test static");
    
     
    public Test()
        System.out.println("test constructor");
    
     
    public static void main(String[] args) 
        new Test();
    

 
class Base
    static
        System.out.println("base static");
    
     
    public Base()
        System.out.println("base constructor");
    
base static
test static
base constructor
test constructor

至于为什么是这个结果,我们先不讨论,先来想一下这段代码具体的执行过程,在执行开始,先要寻找到 main 方法,因为 main 方法是程序的入口,但是在执行 main 方法之前,必须先加载 Test 类,而在加载 Test 类的时候发现 Test 类继承自 Base 类,因此会转去先加载 Base 类,在加载 Base 类的时候,发现有 static 块,便执行了 static 块。在 Base 类加载完成之后,便继续加载 Test 类,然后发现 Test 类中也有 static 块,便执行 static 块。在加载完所需的类之后,便开始执行 main 方法。在 main 方法中执行new Test()的时候会先调用父类的构造器,然后再调用自身的构造器。因此,便出现了上面的输出结果。

这段代码的输出结果是什么?

public class Test 
    Person person = new Person("Test");
    static
        System.out.println("test static");
    
     
    public Test() 
        System.out.println("test constructor");
    
     
    public static void main(String[] args) 
        new MyClass();
    

 
class Person
    static
        System.out.println("person static");
    
    public Person(String str) 
        System.out.println("person "+str);
    

 
class MyClass extends Test 
    Person person = new Person("MyClass");
    static
        System.out.println("myclass static");
    
     
    public MyClass() 
        System.out.println("myclass constructor");
    
test static
myclass static
person static
person Test
test constructor
person MyClass
myclass constructor

类似地,我们还是来想一下这段代码的具体执行过程。首先加载 Test 类,因此会执行 Test 类中的 static 块。接着执行new MyClass(),而 MyClass 类还没有被加载,因此需要加载 MyClass 类。在加载 MyClass 类的时候,发现 MyClass 类继承自 Test 类,但是由于 Test 类已经被加载了,所以只需要加载 MyClass 类,那么就会执行 MyClass 类的中的 static 块。在加载完之后,就通过构造器来生成对象。而在生成对象的时候,必须先初始化父类的成员变量,因此会执行 Test 中的Person person = new Person(),而 Person 类还没有被加载过,因此会先加载 Person 类并执行 Person 类中的 static 块,接着执行父类的构造器,完成了父类的初始化,然后就来初始化自身了,因此会接着执行 MyClass 中的Person person = new Person(),最后执行 MyClass 的构造器。

这段代码的输出结果是什么?

public class Test 
    static
        System.out.println("test static 1");
    
    public static void main(String[] args) 
         
    
     
    static
        System.out.println("test static 2");
    
test static 1
test static 2

虽然在 main 方法中没有任何语句,但是还是会输出,原因上面已经讲述过了。另外,static 块可以出现类中的任何地方(只要不是方法内部,记住,任何方法内部都不行),并且执行是按照 static 块的顺序执行的。

来源:cnblogs.com/dolphin0520

java常见的30个误区与细节!(代码片段)

...员自行使用goto所带来的混乱,Java语言仍将goto定义为一个关键字,但是没有定义任何语法,故称为“保留字”。2??true、false和null在IDE中虽然以不同 查看详情

今天给大家带来新手学java常见的误区

 给大家分享一下常见的误区 以前自己写代码的时候全靠自摸自学没人教踩过的坑也有百八十个下面是一些常见误区误区1:没有一个良好的面向对象思想把所有代码或者是业务逻辑代码都写在一个方法里   缺点:代码... 查看详情

常见的性能测试误区

...沉淀,对于误区阐述的观点在当下并不是太难理解,就挑几个记下来。误区1:性能测试独立于功能测试  性能测试和功能测试时紧密联系在一起的,原因之一是很多性能问题是由软件自身功能缺陷引起的。如果应用系统功能... 查看详情

经验分享:自学编程常见的8种误区,初学者快来避坑

小伙伴们大家好,又是全新的一天。关于“自学编程的一些常见误区”这个话题其实很早之前就在视频里聊过了。时间过去了很久了,也还是有很多小伙伴会提及各种自学过程中的常见疑惑,所以还是用文字总结一下... 查看详情

java常见的30个误区与细节!

...员自行使用goto所带来的混乱,Java语言仍将goto定义为一个关键字,但是没有定义任何语法,故称为“保留字”。2  true、false和null在IDE中虽然以不同的颜色显示,但是并不是关键字,而是“字面常量”,就和String 查看详情

javastatic关键字

static可以修饰的内容如下:●变量●方法●代码块●内部类那就有一个问题,为什么static不能修饰外部类?我们首先看一下static的作用是什么?先看看其他人怎么解释的:Astaticmethodcanbeaccessedwithoutcreatinganobjecto... 查看详情

javastatic关键字

static可以修饰的内容如下:●变量●方法●代码块●内部类那就有一个问题,为什么static不能修饰外部类?我们首先看一下static的作用是什么?先看看其他人怎么解释的:Astaticmethodcanbeaccessedwithoutcreatinganobjecto... 查看详情

预训练模型代码深度剖析之开宗明义:新学常见误区和正确的学习姿势

...近在给新徒弟讲授预训练模型的过程中,发现了初学者的几个误区,分别是:在整个学习过程中,重理论轻代码,忽略了将论文和代码进行对齐,而由于代码中往往包括了一些论文中不曾讲到的细节,所以也未曾达到全面细致的... 查看详情

javastatic关键字

static修饰变量:  作用:用static修饰符修饰的域变量不属于任何一个类的具体对象,而专属于类。  特点:它被保存在类的内存区中(堆中)的公共存储单元中,而不是保存在某个对象的内存区中,因此,一个类的任何对象... 查看详情

javastatic关键字

可以修饰变量和方法。修饰变量加载类的时候分配内存空间。相对于整个类来说,变量有固定,单独的内存空间,是属于整个类的,也就是“类变量”。非static修饰的变量是,相对于对象存在,是属于对象(成员)的,也就是“... 查看详情

javastatic关键字

当成员被静态修饰后,就多了一种调用方式,除了可以被对象调用外,还可以直接被类名调用。类名.静态成员static特点:  1.随着类的加载而加载    静态会随着类的消失而消失,说明它的生命周期最长。  2.优先于类... 查看详情

内部类(代码片段)

Java中的static关键字解析  static关键字是很多朋友在编写代码和阅读代码时碰到的比较难以理解的一个关键字,也是各大公司的面试官喜欢在面试时问到的知识点之一。下面就先讲述一下static关键字的用法和平常容易误解的地... 查看详情

javastatic关键字

static:静态属性/类属性调用方式:类名.静态成员作用:将变量/方法的使用权归类,而非类实例化的对象。 1.static修饰的变量要用静态方法调用,或者类名.调用。      2.静态方法/类方法,使用同静态变量&... 查看详情

常见的低/零代码误区

随着时代和技术的快速发展,企业信息化步伐越来越快,而且更讲究轻型作战,更看重效率,但传统定制开源方式因为周期长、费用高一直为人诟病。低/零代码开发平台就是在这样的背景下应运而生。低/零代码开发平台,让开... 查看详情

几个常见的网站seo误区,你注意过没?

今天,沈老师就和大家谈谈常见的网站seo优化误区有哪些?网站seo优化一:各种标签滥用做网站seo优化的站长都知道,每个网页有且只有一对h1标签,这里就有很多优化人员,就把图片放在h1标签中,认为这样做能加强图片的ALT... 查看详情

javastatic详解(代码片段)

1、static目的 java中的static关键字主要用于内存管理。2、static范围使用范围:javastatic关键字可以用在变量、方法、代码块和嵌套类伤。作用范围:static关键字属于类,而不是类的实例。静态(static)修饰如下:变量&#... 查看详情

javastatic

1.static关键字修饰变量  被static修饰的成员变量叫做静态变量,也叫做类变量,说明这个变量是属于这个类的,而不是属于是对象,  没有被static修饰的成员变量叫做实例变量,说明这个变量是属于某个具体的对象... 查看详情

那些常见的web前端学习误区分享

近几年来,学习前端技术的人越来越多。有的人选择自学也有很大部分人会选择系统学习。但是对于零基础的人入门Web前端,自学还是具备一定的难度,没有经验,没有基础,是很容易踏入到Web前端的学习误... 查看详情