前言
static关键字是摆在刚入行编程语言的小白们面前的一道难题,为什么要用static?使用它有什么好处?修饰方法和修饰变量有什么区别?本文将就java中static关键字的使用方法及注意事项进行深入探讨,一是为了方便自己以后查阅,二也为了与大家交流分享学习的经验。
一、什么是static关键字
static表示静态,常用来修饰成员变量、成员方法、代码块和内部类,存放在方法区,作用在于创建独立于对象存在的域变量或方法,当类被加载时,被static修饰的变量或方法就可以通过类名进行访问,当创建多个对象时,被static修饰的变量/方法不会因此建立多个数据。
我们通过下面一段代码来解释一下它的功能:
public class Demo1 {
public static void main(String[] args) {
Test.p="静态变量赋值了";
Test.say();
new Test();
}
}
class Test{
Test(){
System.out.println("构造方法执行了");
}
static String p ;
static{
System.out.println("静态代码块执行了");
}
public static void say(){
System.out.println("静态方法执行了");
System.out.println(p);
}
public void say2(){
System.out.println("方法执行了");
System.out.println(p);
}
}
代码中我们分别使用关键字static定义了静态变量、静态代码块和静态方法,执行结果如下
我们发现,最先执行的语句是static修饰的代码块,在我们通过类名直接调用方法say之前就执行了,随后是我们通过类名访问的静态方法say,最后才是构造方法。到这里小白可能会问,为什么我们还没有创建对象就可以访问类中的内容呢?这就涉及到了关键字static的使用方法。
二、static关键字的使用方法
1.修饰变量和方法**
被static修饰的变量和方法我们统称为静态变量和静态方法,属于类的静态资源,是类实例之间共享的,简单地说,即不随着创建对象的改变而发生改变。以普通变量和方法为例:我们写一段简单的代码
public class Demo1 {
public static void main(String[] args) {
Test t1 = new Test();
Test t2 = new Test();
t1.p = "变量赋值了";
t1.x =1;
t2.x =2;
t1.say();
}
}
class Test{
String p;
static int x;
void say(){
System.out.println("方法执行了");
System.out.println(p);
System.out.println(x);
}
}
这段代码很简单,即我们通过创建的对象t来访问Test类中的内容,与上一段代码不同的是我们不能通过类名的方式来直接调用这些变量方法,如Test.p和Test.say,而是要通过创建的新对象t。但是我们却可以用对象t来访问静态变量x,但是变量x的内容属于类,对象t1,t2是共享一个变量x的,通过两个对象赋值后,结果取最后赋的值,所以输出的结果如下。
2.静态代码块
静态静态块也是static的重要应用之一。通常使用于类的初始化,和静态变量、静态方法一样,静态块里面的代码只执行一次,且只在初始化类的时候执行。
为了更清楚地描述静态代码块的功能,我们编写如下代码。
public class Demo1 {
public static void main(String[] args) {
new Test2();
new Test1();
}
}
class Test2 extends Test1{
static{
System.out.println("静态代码块1执行了");
}
static{
System.out.println("静态代码块2执行了");
}
}
class Test1{
static {
System.out.println("静态代码块3执行了");
}
}
不难看出,静态代码块随着对象的创建,或者说类的实例化而进行,且只进行一次,我们创建了两个对象,但是每个语句只打印了一次。我们根据他们打印的顺序可以推断出静态代码块的执行规则。
1.按照父类到子类的顺序执行。
2.在同一个类中按照代码的顺序执行
3.每个静态代码块只执行一次
静态代码块可以优化程序性能,正是因为它的特性:只会在类被初次加载的时候执行一次。
3.静态内部类
static正常情况下是不能用来修饰类的,它只能修饰内部类,也就是我们说的静态内部类,它的应用场景相对于以上两个功能少得多,通常我们使用内部类时会保存一个引用,引用是指向创建它的外围内,但是静态内部类却没有。没有这个引用就意味着:
1、它的创建是不需要依赖外围类的创建。
2、它不能使用任何外围类的非static成员变量和方法。
我们通过代码示例来简单地介绍一下静态内部类使用方法
package com.java.demo1;
public class Demo1 {
public static void main(String[] args) {
Test.Test2 t = new Test.Test2();
t.say();
}
}
class Test {
static class Test2 {
void say(){
System.out.println("静态内部类");
}
}
}
三、为什么要使用static
好了,说到这里,可能一些初学者会问,为什么要使用静态呢?首先我们总结一下被静态static修饰的变量/方法/方法块/类的特点
静态修饰的特点
1.被static修饰的变量/方法是独立与类所创建的对象而存在的,简而言之,当我们创建多个对象实例时,static修饰的变量/方法是被它们所共享的,即不随着不同对象的创建而发生改变。
2.static在类加载时就创建好了内存空间,但是它的内容是可以改变的,我们可以通过不同的对象给它赋值,但是它的值取决于你最终给它的赋值。
3.即便不创建对象,static修饰的变量或方法也是可以存在的,当一个类加载完毕后,类中static修饰的变量和方法就可以进行访问。
静态修饰的优点
1.方便在我们没有创建对象时,调用类中的方法/变量
2.static可以用来修饰类的成员方法、成员变量或编写static代码块,能够有效地优化程序性能
我们可以通过下面一段代码来直观地感受一下
package com.java.demo1;
public class Demo1 {
public static void main(String[] args) {
Test t1 = new Test();
Test t2 = new Test();
Test t3 = new Test();
t1.name = "张三";
t2.name = "李四";
t3.name = "王麻子";
t1.age = 18;
t2.age = 18;
t3.age = 19;
Test.school = "清华大学";
t1.say();
t2.say();
t3.say();
}
}
class Test {
String name;
int age;
static String school;
void say(){
System.out.println("我是"+name+",今年"+age+"岁,就读于"+school);
}
}
运行结果如下
对于三个对象,他们的school属性是完全相同的,因此为了不占用过多内存,我们用static把变量school修饰成静态变量,如果我们发现变量school的内容写错了,也可以通过一次修改就达成修改所有对象的目的。
四、注意事项
介绍完了static的优点,接下来说一些使用static关键字时经常出现的错误和需要大家注意的一些细节。
1.static不会改变类中成员的访问权限
很多初学者容易把java中的static和C/C++中的static搞混了,在C/C++中,static能够改变成员的访问权限,而这在java中时不行的,在java中只能通过四个权限修饰符来改变成员的访问权限
如图所示,我们直接给private封装的变量school赋值时,会提示错误。
2.静态方法不能引用非静态资源
这一点是初学者经常犯的错误,当我们定义了一个非静态的变量/方法后,如果我们通过静态的变量或方法来访问非静态的资源时程序是会报错的。这其实不难理解,我们之前说过,静态修饰的变量/方法在类初始化时加载,它们的创建顺序是在非静态资源之前的,我们用已经创建的资源去访问没有被创建的资源,这显然是不合理的。但反过来,非静态资源/静态资源则是可以访问静态资源的。我们通过代码来直观地感受一下。
3.可以通过this来访问静态的资源
虽然我们之前提到过,静态的资源本身是独立于实例化的对象而存在的,但是我们却可以通过对象来访问静态的资源,所有的静态方法和静态变量都可以通过对象访问(只要访问权限足够)。我们再通过一个案例来感受:
public class Demo1 {
public static void main(String[] args) {
Test t = new Test();
t.say();
}
}
class Test {
static int num = 1;
void say(){
int num = 2;
System.out.println(this.num);
}
}
结果输出为1,代码中的this.num并没有指向方法say中定义的num,这里的this还是指向了Test类,显然我们是可以通过对象本身来访问静态资源的。
最后
感谢你看到这里,看完有什么的不懂的可以在评论区问我,觉得文章对你有帮助的话记得给我点个赞,每天都会分享java相关技术文章或行业资讯,欢迎大家关注和转发文章!