Java面向对象-static关键字、静态方法与普通方法、静态成员变量
Java面向对象-static关键字、静态方法与普通方法
static关键字的基本作用:方便在没有创建对象的情况下来进行调用(方法/变量)。
很显然,被static关键字修饰的方法或者变量不需要依赖于对象来进行访问,只要类被加载了,就可以通过类名去进行访问。具体用途如下:
1.static可以用来修饰类的成员方法、类的成员变量;
2.可以编写static代码块来优化程序性能。
java里方法分为 static静态方法和普通方法:
所谓静态方法 是加了static修饰词的方法,我们使用的时候 一般用类名.方法 方式调用;
当然也可以用对象.方法 调用; 一般java里的工具类里的工具方法 用static修饰,作为静态方法;
上代码:
1 package com.java1234.chap03.sec03; 2 3 public class Demo02 { 4 5 void fun1(){ 6 System.out.println("这是一个普通方法"); 7 } 8 9 static void fun2(){ 10 System.out.println("这是一个静态方法"); 11 } 12 13 public static void main(String[] args) { 14 Demo02 demo=new Demo02(); 15 // 调用普通方法 对象.方法 16 demo.fun1(); 17 18 // 调用静态方法 类名.方法 19 Demo02.fun2(); 20 demo.fun2(); 21 } 22 }
static方法一般称作静态方法,由于静态方法不依赖于任何对象就可以进行访问,因此对于静态方法来说,是没有this的,因为它不依附于任何对象,既然都没有对象,就谈不上this了。并且由于这个特性,在静态方法中不能访问类的非静态成员变量和非静态成员方法(此处不能访问指:不能直接访问,但可以通过实例化对象访问类的非静态成员,),因为非静态成员方法/变量都是必须依赖具体的对象才能够被调用。
但是要注意的是,虽然在静态方法中不能访问非静态成员方法和非静态成员变量,但是在非静态成员方法中是可以访问静态成员方法/变量的,当然在静态方法中能访问类的静态成员变量和静态成员。
上下代码:
上面代码就是因为在静态方法中不能访问类的非静态成员变量和非静态成员方法,所以报错
上面代码就是因为:在静态方法中不能访问类的非静态成员变量和非静态成员方法(此处不能访问指:不能直接访问,但可以通过实例化对象访问类的非静态成员)
Java中静态成员变量:
static修饰的成员变量也叫类变量或全局变量,在类被加载时static修饰的成员变量被初始化,与类关联,只要类存在,static变量就存在。一个static变量单独划分一块存储空间,不与具体的对象绑定在一起,该存储空间被类的各个对象所共享。也就是说当声明一个对象时,并不产生static变量的拷贝,而是该类所有的实例对象共用同一个static变量。static修饰的成员变量能在创建任何实例对象之前被访问,而不必引用任何对象,也就是说不管创建多少对象,static修饰的变量只占有一块内存。
我们上下代码:
1 package com.baiye.test; 2 3 public class StaticTest { 4 static int a=9; 5 static String str="quan"; 6 public StaticTest(){ 7 System.out.println("static变量在类装载的时候就初始化(在实例化对象之前):a="+a); 8 System.out.println(a); 9 System.out.println(str); 10 11 } 12 static void staticMethod(){ 13 str="baiye"; 14 //return str; 15 System.out.println("在静态方法引用静态变量:str="+str); 16 } 17 void generalMethod(){ 18 a=6; 19 System.out.println("在非静态方法中调用静态变量:a="+a); 20 } 21 public static void main(String[] args){ 22 StaticTest st1=new StaticTest(); 23 StaticTest st2=new StaticTest(); 24 StaticTest st3=new StaticTest(); 25 st1.a=5; 26 System.out.println("st1.a="+st1.a+" st2.a="+st2.a+" st3.a="+st3.a); 27 staticMethod(); 28 System.out.println("st1.str="+st1.str+" st2.str="+st2.str+" st3.str="+st3.str); 29 StaticTest st4=new StaticTest(); 30 st1.generalMethod(); 31 System.out.println("st1.a="+st1.a+" st2.a="+st2.a+" st3.a="+st3.a); 32 } 33 34 }
运行结果:
static变量在类装载的时候就初始化(在实例化对象之前):a=9
9
quan
static变量在类装载的时候就初始化(在实例化对象之前):a=9
9
quan
static变量在类装载的时候就初始化(在实例化对象之前):a=9
9
quan
st1.a=5 st2.a=5 st3.a=5
在静态方法引用静态变量:str=baiye
st1.str=baiye st2.str=baiye st3.str=baiye
static变量在类装载的时候就初始化(在实例化对象之前):a=5
5
baiye
在非静态方法中调用静态变量:a=6
st1.a=6 st2.a=6 st3.a=6
在这个结果中我们可以看出不管实例多少个对象static修饰的成员变量只占有一块内存
java中static关键字不会改变类中成员的访问权限
在非静态方法中能够通过this访问静态成员变量
static是不允许用来修饰局部变量
常见的static笔试题:
1.下面这段代码的输出结果是什么?
1 public class Test extends Base{ 2 3 static{ 4 System.out.println("test static"); 5 } 6 7 public Test(){ 8 System.out.println("test constructor"); 9 } 10 11 public static void main(String[] args) { 12 new Test(); 13 } 14 } 15 16 class Base{ 17 18 static{ 19 System.out.println("base static"); 20 } 21 22 public Base(){ 23 System.out.println("base constructor"); 24 } 25 }
运行结果:
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()的时候会先调用父类的构造器,然后再调用自身的构造器。因此,便出现了上面的输出结果。
2.这段代码的输出结果是什么?
1 public class Test { 2 Person person = new Person("Test"); 3 static{ 4 System.out.println("test static"); 5 } 6 7 public Test() { 8 System.out.println("test constructor"); 9 } 10 11 public static void main(String[] args) { 12 new MyClass(); 13 } 14 } 15 16 class Person{ 17 static{ 18 System.out.println("person static"); 19 } 20 public Person(String str) { 21 System.out.println("person "+str); 22 } 23 } 24 25 26 class MyClass extends Test { 27 Person person = new Person("MyClass"); 28 static{ 29 System.out.println("myclass static"); 30 } 31 32 public MyClass() { 33 System.out.println("myclass constructor"); 34 } 35 }
运行结果:
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的构造器。
3.这段代码的输出结果是什么?
1 public class Test { 2 3 static{ 4 System.out.println("test static 1"); 5 } 6 public static void main(String[] args) { 7 8 } 9 10 static{ 11 System.out.println("test static 2"); 12 } 13 }
运行结果:
test static 1 test static 2
虽然在main方法中没有任何语句,但是还是会输出,原因上面已经讲述过了。另外,static块可以出现类中的任何地方(只要不是方法内部,记住,任何方法内部都不行),并且执行是按照static块的顺序执行的。