Java Static 用法总结

本文深入讲解Java中的Static关键字,涵盖Static实体(静态变量、静态方法、静态内部类)、Static块及静态导入等内容,并通过示例代码帮助理解。

前言:

以下大部分内容我从谷歌上搜索,结合官方的文档总结的。我认为会使用谷歌、会阅读官方的文档非常作用,这里都是最权威的参考。

Java中的Static关键字用的很多,但是总结起来,大概有三部分内容:

  • Static member
  • Static Block
  • Static import
下面分别介绍

Static Entity

Static实体包括静态变量、静态方法、静态内部类。

首先理解一下Static这个词,在Java中,这个词的意思是这些实体归类所有,与类绑定在一起,所有该类的实例共享这些实体。例如同一个厂商生产的自行车,把自行车抽象为一个类,对象就是每一辆自行车。每一辆自行车有价格、颜色等属性,这些属性每一辆自行车都不一样,但是,他们的生产厂商都是一样的,这个时候就可以把生产厂商定义成一个静态类型。Static实体在内存中单独存放,不跟对象的变量存放在一起。

静态变量:

定义如下:

private static int VENDOR = 'ABC' ;
一般情况下,我们将静态变量用大写字母表示,有多个单词的时候,用下划线分开。静态变量也称为类变量,顾名思义,这些变量属于类的,而不是实例对象的。对于特定的类加载器来说,只存在一个静态变量,无论你创建多少个对象,或者你根本就没有创建对象。注意我的前提,对于特定的类加载器,也就是说,不同的类加载器可能会有多个静态变量。访问静态变量时,可以直接通过类访问:ClassName.VENDOR. 当然也可以通过实例访问,不过不建议那么做,因为体现不出“静态”二字。

那么,在哪些地方可以声明静态变量呢?对于一般的类中,可以在类中直接声明(与方法并列),注意不能在方法中声明静态变量,不管该方法是否为静态。在内部类当中,情况有些不一样,非静态内部类中不能声明静态变量(事实上,非静态内部类不能声明任何静态实体)。静态内部类则可以声明静态变量。一句话,静态变量只能在外层类中或者静态内部类中定义。

静态方法:

定义格式如下:

public static void doSomething() {...

一样的,静态方法也属于类所有,但是对象一样可以调用。静态方法一般用于对静态变量进行操作,在静态方法中,不能直接引用非静态变量。因为非静态变量属于某个实例所有,如果还没有创建对象,那就没有实例变量存在,如何引用?如果要引用非静态变量,只能通过对象引用。静态方法中不能使用this、super这些关键字。


最常见的静态方法当然是main()方法。因为在其他所有对象创建之前,main方法就必须被调用,此时只能通过类来调用这个main方法。在main方法中,是不能直接引用非静态变量的。

public class StaticMethod {

	private int age = 0 ;
	private static String VENDOR = "JAC";
	
	/**
	 * @param args
	 */
	public static void main(String[] args) {
		/*
		 * doesn't work
		 */
		System.out.println(age);
		/**
		 * OK
		 */
		System.out.println(VENDOR);

	}

}
静态方法中同样不能直接调用非静态方法,只能通过对象引用。总结一下:实例方法可以直接访问实例变量、静态变量,可以直接调用实例方法、静态方法。但是,静态方法只能直接访问静态变量、调用静态方法,如果要访问非静态变量或方法,只能通过对象引用。举例如下:
public class StaticMethod {

	private int age = 0 ;
	private static String VENDOR = "JAC";
	
	public void show() {
		System.out.println("Non-Static");
	}
	
	public static void staticShow() {
		System.out.println("Static");
	}
	
	public static void main(String[] args) {
		//直接访问
		System.out.println(VENDOR); 
		staticShow();
		 //通过对象引用
		StaticMethod staticMethod = new StaticMethod();
		System.out.println(staticMethod.age);
		staticMethod.show();

	}

}
那么,在哪里可以定义静态方法呢?官方说法是这样的,Static methods can only be declared in a static or top-level type.也就是说,在外层的类中,可以定义静态方法。但是在内层的类当中,只有静态的内部类才能定义静态方法。跟静态变量的情况其实是一样的。


 静态类

只能在内部类中定义静态类。也就是说,内部类有静态和非静态之分。静态内部类与外层类绑定,即使没有创建外层类的对象,它一样存在。但是非静态内部类不一样,它是与特定的外层类对象绑定的,只有外部类对象存在,内部类才存在。

内部静态内中的方法一样有静态与非静态之分,如果是静态方法,在外层中可以通过内部静态内直接调用,如果是非静态方法,则必须先创建内部静态类的对象之后再调用。

public class Test{

	public static void main(String[] args) {
		StaticInnerClass.diaplay();
	    StaticInnerClass i = new StaticInnerClass();
	    i.test();
	    
	}
	
	static class StaticInnerClass {
		private static String VENDOR = "JAC";
		private static void diaplay() {
			System.out.println("Inner static class, static method");
		}
		
		private void test() {
			System.out.println("Inner static class,non-static methon");
		}
		
	}

}
至于非静态内部类,不是本文的探讨内容,参考http://docs.oracle.com/javase/tutorial/java/javaOO/nested.html。静态实体的探讨就到这里。


Static Block

静态块的格式如下:(下面是一个完整例子,接下来说明用)

import java.util.HashMap;
import static java.lang.Math.PI;
/**
 * 
 * @author bingduanLin
 *
 */


public class StaticBlock {

	{
		System.out.println("Instance Initializer, run when an object is created! ");
	} // can bu reuser in constructors!!
	
	
	
	private static final HashMap<String, String> MAP = new HashMap<String, String>();
	static {
	    MAP.put("banana", "honey");
	    MAP.put("peanut butter", "jelly");
	    MAP.put("rice", "beans");
	  }
	static {
		System.out.println("Static Initializer, run when the class is loaded!");
		MAP.put("cons", "cons");
	}
	
	
	/**
	 * @param args
	 */
	public static void main(String[] args) {
		new StaticBlock();
		new StaticBlock();
		new StaticBlock();
		System.out.println(MAP);
		/**
		 * The static import declaration is analogous to the normal import declaration. 
		 * Where the normal import declaration imports classes from packages, allowing 
		 * them to be used without package qualification, the static import declaration 
		 * imports static members from classes, allowing them to be used without
		 * class qualification.
		 */
		System.out.println(PI);

	}

}
static { }这一部分就是静态块,当类加载器载入类的时候,这一部分代码被执行,常用于对静态变量进行初始化工作。当然,可以声明一个静态方法来完成这些初始化工作,这样做的好处就是这些初始化工作可以再次被调用,而在初始化块中,代码只能执行一次,不能再调用。在静态块中,可以访问静态变量,调用静态方法。

如果去掉static,{ }中的代码则会在创建类对象实例的时候才执行,(相当于把这部分代码复制到各个构造函数中)这样可以实现块中的内容在多个构造函数中的复用。上面的代码输出结果如下:

Static Initializer, run when the class is loaded!
Instance Initializer, run when an object is created! 
Instance Initializer, run when an object is created! 
Instance Initializer, run when an object is created! 
{banana=honey, rice=beans, peanut butter=jelly, cons=cons}
3.141592653589793

可以看到, static{ }中的代码只执行一次,而{ }中的代码每当创建一个新对象的时候就会被执行。{ } 这样的代码块也被称为构造函数块(Constructor Block)。再举个例子:

package learn.study;

public class StaticExample{
    static {
        System.out.println("This is first static block");
    }

    public StaticExample(){
        System.out.println("This is constructor");
    }

    public static String staticString = "Static Variable";

    static {
        System.out.println("This is second static block and refer to STATIC VARIABLES:"
		                                        + staticString);
    }

    public static void main(String[] args){
        /*StaticExample statEx = new StaticExample();
        StaticExample.staticMethod2();*/
    	staticMethod2();
    }

    static {
        System.out.println("This is third static block and refer to STATIC METHOD");
        staticMethod();
    }

    public static void staticMethod() {
        System.out.println("This is static method");
    }

    public static void staticMethod2() {
        System.out.println("This is static method2");
    }
}
输出:
This is first static block
This is second static block and refer to STATIC VARIABLES:Static Variable
This is third static block and refer to STATIC METHOD
This is static method
This is static method2
当然,静态块也有它的局限性,比如静态块代码大小不能超过JVM规定的某个值,不能用this,super关键字,不能从静态块中返回值,增加调试难度等等。因此,必须小心处理静态块中可能出现的异常。


静态导入:

最后提一下静态导入,如上面的代码: static import java.lang.Math.PI

看上面的注释,import之后,我们可以省略Class前面的包名直接使用类,如System.out.println(Math.PI).

静态导入之后,可以把类名也省略掉,直接使用类当中的变量或者方法,即System.out.println(Math.PI).静态导入虽然有它的一些方便,但使用的时候要非常小心。参考官方文档:http://docs.oracle.com/javase/1.5.0/docs/guide/language/static-import.html


<think>首先,用户查询的是“Java static关键字的使用方法”。我需要基于提供的引用信息来回答。引用来自多个来源:[1]、[2]、[3]、[4]、[5]。 关键点是引用中提到的static关键字的用法: - 引用[1]: Static关键字的四种用法,但没有详细列出。 - 引用[2]: 解释了private static的组合用法。 - 引用[3]: 提到了static修饰属性(类属性),共享值。 - 引用[4]: static修饰成员方法,允许通过类名调用方法;提到在工具类和接口中的应用。 - 引用[5]: 提到了static变量在方法区存储,以及与final的区别。 从这些引用中,我可以总结出static关键字的常见用法: 1. **修饰静态变量(类变量)**:变量属于类,而非对象实例。所有实例共享同一个变量。例如,static int age; 在加载时初始化。 2. **修饰静态方法(类方法)**:方法属于类,可以直接通过类名调用,无需实例化对象。常用于工具类。 3. **静态代码块**:在类加载时执行,用于初始化静态变量。 4. **静态内部类**:引用中没有明确提到,但根据Java知识,static可以修饰内部类,使其不依赖于外部类的实例。 5. **在接口中的static方法**:JDK8之后,接口可以定义静态方法。 回顾引用: - 引用[3]讨论静态属性。 - 引用[4]讨论静态方法。 - 引用[2]涉及访问修饰符如private static。 - 引用[5]对比static和final。 我需要结构化回答: - 回答结构清晰,逐步解决问题。 - 使用中文。 - 根据系统指令: - 行内数学表达式用$...$(但这里可能不涉及数学)。 - 独立公式用$$...$$(但Java中不常用)。 - 添加引用标识在末尾:[^n] 最后,生成相关问题。 组织回答: 1. **引言**:简要介绍static关键字。 2. **主要用法**: - 静态变量(类变量) - 静态方法(类方法) - 静态代码块 - 其他用法如静态导入(但引用中未提) - 可能提到接口中的静态方法。 3. **示例代码**:结合引用给出简单代码片段。 4. **总结**。 5. **相关问题**:基于主题生成几个问题。 确保引用正确:在回答中提及内容时,添加引用标识,如[^1]。 引用内容: - [^1]: Static关键字的四种用法。 - [^2]: private static的访问权限。 - [^3]: 静态属性共享值。 - [^4]: 静态方法使用。 - [^5]: static vs final。 在回答中自然地引用。 回答大纲: - 什么是static关键字? - 用途1:修饰变量 – 类变量,共享。 - 用途2:修饰方法 – 类方法,可直接调用。 - 用途3:静态代码块 – 类加载时执行。 - 用途4:在接口中(JDK8+)。 - 注意事项:如访问控制。 然后,相关问题如: - static变量和实例变量的区别? - static方法能访问非静态成员吗? - 如何优化static使用? 最后,确保语言流畅、可靠。 </think>### Javastatic关键字的使用方法详解 在Java中,`static`关键字用于修饰类成员(变量、方法、代码块),使其属于类本身,而非类的单个实例对象。这意味着`static`成员可以在类加载时初始化,并通过类名直接访问,无需创建对象实例。使用`static`可以提高代码性能和可维护性,常用于共享数据或工具类方法。下面我将基于提供的引用信息,逐步解释其主要用法,并给出代码示例。注意,在解释中我会自然地添加引用标识来表示来源。 #### 1. **修饰静态变量(类变量)** - **作用**:将一个成员变量声明为静态变量(类变量),该变量在类加载时初始化,并被所有实例对象共享。即所有实例操作的都是同一个内存值,这节省了内存资源。 - **引用依据**:引用[3]指出,静态属性属于类所有,而非实例对象;所有实例共享同一个值,并在类的加载阶段初始化。引用[5]补充说,静态变量存储在方法区(元空间)中[^3][^5]。 - **示例代码**: ```java public class Person { static int age; // 静态变量,初始值为0 static int high = 175; // 静态变量,直接在声明时初始化 public static void main(String[] args) { System.out.println(high); // 直接输出175 age = 20; // 修改静态变量 Person p1 = new Person(); System.out.println(p1.age); // 输出20,因为共享同一个值 } } class PersonTest { public static void main(String[] args) { System.out.println(Person.high); // 输出175,通过类名访问 } } ``` - **注意事项**:静态变量可以被所有实例访问,但修改会影响所有对象。如果加上访问修饰符如`private static`,则只能在类内部访问(引用[2]说明:`private`限定访问,`static`表示不需实例化即可使用)[^2]。 #### 2. **修饰静态方法(类方法)** - **作用**:将一个成员方法声明为静态方法,允许通过类名直接调用,无需创建对象。这常用于工具类(如`Math`类的方法),避免不必要的对象创建开销。在JDK8及以上版本,`static`还可用于接口中定义具体方法。 - **引用依据**:引用[4]强调,静态方法存储在类的定义中(方法区),可通过类名调用,并在工具类或接口中使用以优化性能[^4]。引用[1]也提到,`static`和`final`关键字能提高程序性能[^1]。 - **示例代码**: ```java public class Demo { public static int add(int a, int b) { return a + b; // 静态方法 } } class Test { public static void main(String[] args) { System.out.println(Demo.add(1, 2)); // 输出3,直接通过类名调用 } } // JDK8+接口中的静态方法示例 interface Tool { static void print() { System.out.println("Static method in interface"); } } ``` - **注意事项**:静态方法只能访问静态成员(变量或方法),不能访问非静态成员,因为非静态成员依赖于对象实例。此外,`static`方法不能被重写(但可以隐藏)。 #### 3. **静态代码块** - **作用**:用于初始化静态变量或执行类加载时的预备操作。静态代码块在类首次加载到内存时执行一次,优先于任何对象创建或其他代码执行。 - **引用依据**:引用[2]隐含提到,静态代码块可以用于初始化过程[^2]。尽管引用未直接列出,但这是Java标准用法。 - **示例代码**: ```java public class Config { static String databaseUrl; // 静态变量 static { databaseUrl = "jdbc:mysql://localhost:3306/test"; // 静态代码块初始化 System.out.println("Static block executed."); } public static void main(String[] args) { System.out.println(databaseUrl); // 输出jdbc:mysql://localhost:3306/test } } ``` - **注意事项**:静态代码块常用于加载配置文件或设置全局资源。 #### 4. **其他用法** - **静态内部类**:`static`可以修饰内部类,使其不依赖于外部类的实例(引用中未直接提及,但基于Java知识)。 - **静态导入(JDK5+)**:使用`import static`直接导入静态成员,简化代码(引用中未提)。 - **与`final`结合**:`static final`用于定义常量(如`public static final int MAX_SIZE = 100;`),引用[5]对比了`static`和`final`:`final`用于成员常量(堆中存储),`static`用于类变量(方法区存储)[^5]。 #### 总结 - **核心优势**:`static`关键字减少了对象创建开销,提升了性能(尤其在工具类中),但过度使用可能导致全局状态问题(如线程安全风险)。 - **适用场景**:共享计数器、工具方法(如`Math.sqrt()`)、单例模式初始化。 - **最佳实践**:优先在不需要对象状态的场景使用静态方法;避免在静态上下文中访问非静态成员,以免引发`NullPointerException`。 - **引用整合**:综合引用[1]-[5], `static`的用法主要集中在变量、方法和初始化块上,能优化程序结构和性能[^1][^2][^3][^4][^5]。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值