Java基础(二)-static关键字分析

java

static关键字是我们在编程中经常会使用到的,但有些可能只知其然而不知其所以然。下面介绍static关键字的作用再通过例子结合说明。

static关键字共有五种作用(先说明static所修饰的不会改变其(private、protected、default和public)作用域的范围):

  •  修饰成员变量(非局部变量)

  •  修饰成员方法
  •  修饰代码块
  •  修饰内部类
  •  静态导包

怎么会有五种呢,大部分初学者对前面两种或者加上第三种还是很熟悉的,第四种情况可能一开始的人就比较少知道了,第五种就更少人知道了。下面一一介绍:

二、修饰成员变量

  • 说明及特点:static所修饰的变量也叫做静态变量,该变量在类初次加载时会被初始化,所以它在内存中只有一个副本,被所有对象所共享(前提也是public所修饰的),其实也叫做类变量,直接通过类可以调用。而非静态变量是在创建对象的时候被初始化,存在多个副本但各个副本互不影响,它也叫做实例化对象的变量。其中要注意的是static不能修饰局部变量(定义在函数内,语句内等,只在所属的区域有效)

  • 好处:优先加载、内存利用率高(类初始化时加载且仅分配一次内存);  调用简单

  • 案例解析:

 1 package com.yuanfy.test.statics;

2

3 class Student {

4 //非静态变量

5 private String name;

6 int age;

7 //静态变量、全局变量

8 public static String schoolName = "清华大学";

9

10 public Student(String name, int age) {

11 this.name = name;

12 this.age = age;

13 }

14

15 public void say(){

16 static int count = 0;//编译报错,不能定义局部变量

17 }

18

19 public String getName() {

20 return name;

21 }

22

23 }

24 public class StaticTest {

25 public static void main(String[] args) {

26 Student s1 = new Student("张三", 18);

27 //1、只能通过实例对象调用

28 System.out.println("name: " + s1.getName() + ", age: " + s1.age);

29 //2、可以通过类直接调用,如果schoolName是public在其他包下也是可以直接通过类调用的,这样的变量也叫做全局变量

30 System.out.println("school:" + Student.schoolName);

31

32 //3、非静态变量只属于实例对象,所以对应成员变量的值互不影响。

33 Student s2 = new Student("李四", 19);

34 System.out.println("测试非静态变量是否会影响其他实例对象下的使用:");

35 System.out.println("name: " + s1.getName() + ", age: " + s1.age);//name: 张三, age: 18

36 System.out.println("name: " + s2.getName() + ", age: " + s2.age);//name: 李四, age: 19

37

38 //静态变量会影响使用。

39 System.out.println("静态变量会影响使用:");

40 s2.schoolName = "北京大学";

41 System.out.println("s2 school:" + s1.schoolName);//s1的学校名称肯定会改变成s2的学校名

42 }

43 }

output:

name: 张三, age: 18

school:清华大学

测试非静态变量是否会影响其他实例对象下的使用:

name: 张三, age: 18

name: 李四, age: 19

静态变量会影响使用:

s2 school:北京大学

三、修饰成员方法

  • 说明:static所修饰的方法叫做静态方法,也称类方法。
  • 特点:

  1、跟静态变量一样,静态方法属于类而不属于对象,所以静态方法可以通过类直接调用,而不需要创建对象实例来调用。
  2、由于静态方法是通过类直接调用的,所以静态方法中没有this对象。
  3、静态方法可以调用静态变量或方法,但是不能调用非静态变量或方法
  4、静态方法不能被覆盖。因为静态方法是编译时静态绑定的,而覆盖是基于运行时动态绑定的。

  注意:构造方法不是静态方法,可以参考这里。

  • 案例解析:

 1 class Student {

2 //非静态变量

3 private String name;

4 int age;

5 //静态变量、全局变量

6 public static String schoolName = "清华大学";

7

8 public Student(){}

9 public Student(String name, int age) {

10 this.name = name;

11 this.age = age;

12 }

13

14 public static void say(){

15 //2、由于静态方法是通过类直接调用的,所以静态方法中没有this对象。

16 System.out.println("调用者:" + this);//编译失败

17 //3、静态方法可以调用静态变量或方法,但是不能调用非静态变量或方法

18 //Cannot make a static reference to the non-static

19 System.out.println("调用非静态变量name:" + name);//编译失败

20 //但是可以调用静态方法

21 System.out.println("调用静态变量schoolName:" + schoolName);

22 }

23 public void setName(){

24 //非静态方法可以使用this,知道是哪个实例对象在调用。

25 System.out.println("调用者:" + this);

26 }

27 }

28 class StudentDTO extends Student{

29

30 //编译报错; 4、静态方法不能被覆盖覆盖。因为静态方法是编译时静态绑定的,而覆盖是基于运行时动态绑定的。

31 @Override

32 public static void say(){

33

34 }

35

36 }

四、修饰代码块

  • 说明:static修饰在代码块前用来形成静态代码块以优化程序性能。

  • 特点:

  1、在类初次被加载的时候在加载,只加载一次;

  2、一个类可以有多个代码块,按代码块的顺序执行。

  • 案例分析:

 1 public class StaticTest {

2 static {

3 System.out.println("第一次加载静态代码块内容");

4 }

5

6 public static void main(String[] args) {

7 //不需要实例化对象,只要类加载就会执行static块内容。

8 // 与执行顺序与代码块的顺序一致。

9 }

10

11 static {

12 System.out.println("第二次加载静态代码块内容");

13 }

14 }

output:

第一次加载静态代码块内容

第二次加载静态代码块内容

五、修饰内部类

  • 说明:static修饰的内部类成为静态内部类。

  • 特点:

  1、普通类不可以用static修饰,只有内部类才可以。(语法)

  2、非静态内部类无法声明静态方法和静态变量,只有静态内部类才可以。原因很简单:当加载该类时,会自动解析类中static所修饰的所有变量、方法、代码块和内部类,而静态变量定义在非静态内部类,所以不会加载。而jvm虚拟机是要求静态变量必须是在类加载时初始化的。所以会编译报错,无法声明。

  3、非静态内部类可以随意访问外部类的成员或方法,而静态内部类只能访问静态变量或方法。

  4、调用静态内部类不需要持有外部内的引用可以直接调用,而非静态内部类就必须持有外部内的引用才能调用

  • 案例分析:

 1 public class StaticTest {

2 private static int startPrice = 10;//起步价

3

4 private static int kmPrice = 2;//每一公里2块钱

5

6 private int kmCount;//里程计时器

7

8 static class Car1{

9 //编译成功, 2、非静态内部类无法声明静态方法和静态变量,只有静态内部类才可以。

10 public static void start(){

11 //编译失败,3、非静态内部类可以随意访问外部类的成员或方法,而静态内部类只能访问静态变量或方法。

12 // kmCount = 0;

13 System.out.println("car1汽车启动,起步价是:" + startPrice);

14 }

15 }

16 class Car2{

17 //编译报错。 2、非静态内部类无法声明静态方法和静态变量,只有静态内部类才可以。

18 // public static void start(){

19 // System.out.println("开始启动");

20 // }

21

22 public void start2(){

23 //编译成功,3、非静态内部类可以随意访问外部类的成员或方法,而静态内部类只能访问静态变量或方法。

24 kmCount = 0;

25 System.out.println("car2汽车启动,起步价是:" + startPrice);

26 }

27 }

28 public static void main(String[] args) {

29 StaticTest.Car1.start();

30 //编译报错 4、调用静态内部类不需要持有外部内的引用可以直接调用,而非静态内部类就必须持有外部内的引用才能调用

31 // StaticTest.Car2.start();

32

33 //编译成功

34 StaticTest.Car2 car2 = new StaticTest().new Car2();

35 car2.start2();

36 }

37 }

output:

car1汽车启动,起步价是:10

car2汽车启动,起步价是:10

六、静态导包

  • 说明:其实很简单,跟平常导包差不多,只是在import后面加上static,然后再在类后面引入所有成员(变量、方法、内部类等)用.*代替。格式如下:import static classPath.*;这个不是很常用,也不建议使用,请看下面特点及不足之处。

  • 特点:

  对于导入静态包可以直接使用其静态方法。

  • 不足之处:

  1、代码不直观:如果导入了多个静态包,不仔细看是不知道这个方法来源于哪个类 。

  2、会存在方法冲突。

  • 案列分析1:

package com.yuanfy.test;

/**

* @description 字符串工具类案例

* @author YuanFY

* @date 2017年12月10日 上午11:35:25

* @version 1.0

*/

public class StringUtil {

public static boolean isEmpty(String str){

return true;

}

}

package com.yuanfy.test.statics;

//导入静态包

import static com.yuanfy.test.StringUtil.*;

//import static com.yuanfy.test.scope2.StringUtil.*;

public class StaticTest2 {

public static void main(String[] args) {

String str1 = "123";

String str2 = new String("123");

//方便之处直接使用静态方法,不直观

if (isEmpty(str1)){

}

}

}

  • 案列分析2(导入多个静态包):

package com.yuanfy.test.scope2;

//注意这是不同包下的工具类

public class StringUtil {

public static boolean isEmpty(String str){

return true;

}

}

package com.yuanfy.test.statics;

//导入多个静态包

import static com.yuanfy.test.StringUtil.*;

import static com.yuanfy.test.scope2.StringUtil.*;
public class StaticTest2 {

public static void main(String[] args) {

String str1 = "123";

String str2 = new String("123");

//编译报错,The method isEmpty(String) is ambiguous for the type StaticTest2

if (isEmpty(str1)){

}

}

}

拓展(static所修饰加载的先后顺序):静态代码块和静态变量无优先顺序,只跟其定义的前后顺序有关;静态代码块和变量优先静态方法。

 1 class Test{

2 public Test(){

3 System.out.println("test()");

4 }

5 }

6 public class StaticTest3 {

7 static {

8 System.out.println("代码块1");

9 }

10 private static Test test = new Test();

11 static {

12 System.out.println("代码块2");

13 }

14

15 public static void test(){

16 System.out.println("StaticTest3 test()");

17 }

18

19 public static void main(String[] args) {

20 StaticTest3.test();

21 }

22 }

output:

代码块1

test()

代码块2

StaticTest3 test()

本篇文章分析到此结束,参考文献如下:

http://rednaxelafx.iteye.com/blog/652719

https://www.cnblogs.com/dolphin0520/p/3799052.html

以上是 Java基础(二)-static关键字分析 的全部内容, 来源链接: utcz.com/z/392067.html

回到顶部