-
static关键字
static是一个静态的修饰符,用于修饰成员(成员变量、成员函数)。当成员被静态修饰后,就多了一个调用方式,除了可以使用对象调用,还可以直接被类名调用,类名.静态成员。
class Person
{
String name; //实例变量,或成员变量
static String country = "CN"; //静态成员变量,或类变量
public void show() {
System.out.println(name+"::"+country);
}
}
public class Main{
public static void main(String[] args) {
//使用p.show(),则是对象调用
Person p = new Person();
p.name = "zhangsan";
p.show();
System.out.println(p.country);
//还可以使用类名.静态变量
System.out.println(Person.country);
}
}
static特点:
1、随着类的加载而加载,会随着类的消失而消失。它的生命周期最长。
2、优先于对象而存在。明确一点:静态是先存在的,对象是后存在的。静态成员先被加载入方法区,而不是堆内存中。
3、静态数据被所有对象共享。
4、可以直接被类名所调用。
静态变量(类变量)与非静态变量(实例变量)的区别:
1、存放位置:类变量随着类的加载而存在与方法区中;实例变量随着对象的建立而存在与堆内存中。
2、生命周期:类变量生命周期最长,随着类的消失而消失;实例变量生命周期随着对象的消失而消失。
静态使用注意事项:
1、静态方法只能访问静态成员,非静态方法可以访问静态成员也可以访问非静态成员。
如:若将show方法改为static修饰,则在show方法内部的输出name则会出错,这是因为name为非静态成员变量,不能被静态方法所调用。但是原来的无static修饰的show方法,既可以访问非静态成员变量name,又能访问静态成员变量country。
2、静态方法不可以定义this、super关键字。这是因为静态优先于对象而存在,所以静态方法中不能出现this,this的出现是由于有对象的构建。
static修饰有利有弊:
利:对对象的共享数据进行单独空间的存储,节省空间,没有必要每一个对象中都存有一份静态成员。可以直接被类名调用。

弊:生命周期过长。访问出现局限性。(静态只能访问静态)
-
main函数
public static void main(String[] args)
主函数:是一个特殊的函数,作为程序的入口,可以被jvm所调用。
主函数的定义:
public:代表着该函数具有最大的访问权限;
static:代表主函数随着类的加载就已经存在了;
void:主函数没有具体的返回值;
main:不是关键字,但是是一个特殊的单词,可以被jvm所识别;
String[] args:函数的参数,参数类型是一个数组,该数组中的元素是字符串,表示字符串类型的数组。
主函数是固定格式的:jvm识别。
jvm在调用主函数时,传入的时new String[0];这个通过System.out.println(args.length)得到的结果为0所知道的。
一般不传入参数,但是在使用命令行进行运行Java程序时,可以传入需要的参数,如下面的实例:
class MainTest{
public static void main(String[] aegs){
System.out.println(args.length);
}
}
使用命令行编译与运行:
javac MainTest.java
java MainTest haha hehe heihei
能够得到结果args数组的长度为3。
-
静态什么时候使用
这包括两方面,因为静态修饰的内容有成员变量和成员方法。
什么时候定义静态变量:当对象中出现共享数据时,该数据被静态所修饰;对象中的特有数据要定义成非静态存在于堆内存中。
什么时候定义静态方法:当方法内部没有访问到非静态数据(对象的特有数据),那么该方法可以被定义为静态的。
静态的应用
比如现在在两个类别中都有一个获得最大值的方法,可以将这些共性的功能抽取出来,独立进行封装以便于复用。
现在可以定义一个工具类ArrayTool来抽取一些获得数组最值、数组排序等功能的类。
class ArrayTool{
public int getMax(int[] arr){}
public int getMin(int[] arr){}
public void sort(int[] arrr){}
}
这样就可以通过建立ArrayTool的对象来使用这些工具方法,对数组进行操作:
int[] arr = {3,6,23,63,21};
ArrayTool at = new ArrayTool();
at.getMax(arr);
但是有一些问题:
1、对象是用于封装数据的,可是ArrayTool对象并未封装特有数据;
2、操作数组的每一个方法都没有用到ArrayTool对象中的特有数据。
因此可以不使用ArrayTool对象,可以将ArrayTool中方法都定义成static的,直接使用类名调用即可:
ArrayTool.getMax(arr);
将方法都静态修饰后,可以方便使用,但是该类还是可以被其他程序建立对象的。为了更严谨,强制该类不能建立对象,可以通过将构造函数私有化来实现:private ArrayTool(){}。
-
静态代码块
格式:
static{
静态代码块中的执行语句;
}
static{
System.out.println("a");
}
特点:随着类的加载而执行,只执行一次,并且优先于主函数。用于给类初始化。和前面的构造代码块区别下:构造代码块是给对象属性初始化的。
class StaticTest{
StaticTest(){
System.out.println("a");
}
static {
System.out.println("b");
}
{
System.out.println("c");
}
StaticTest(int x){
System.out.println("d");
}
}
class Main{
public static void main(String[] args) {
new StaticTest(4);
}
}
先调用静态代码块,在调用构造代码块,然后调用对应的构造函数,故输出:b c d。
若StaticTest类中有int num = 9;,即有特定成员变量,则在静态代码块中就不能这样输出:System.out.println("a"+num);,因为num为非静态变量,不能被静态方法所调用。
-
对象的初始化过程
class Person{
private String name;
private int age;
private static String country = "cn";
Person(String name,int age){
this.name = name;
this.age = age;
}
public void setName(String name) {
this.name = name;
}
public void info() {
System.out.println(this.name+"..."+this.age);
}
public static void showCountry() {
System.out.println("country="+country);
}
}
class Main{
public static void main(String[] args) {
Person p = new Person("zhangsan",20);
}
}
在上面的程序中Person p = new Person("zhangsan",20);,这条语句都做了如下事情:
1、因为new用到了Person.class,所以会先找到Person.class文件并加载到内存中;
2、执行该类中的static代码块,如果有的话,给Person.class类进行初始化;
3、在堆内存中开辟空间,分配内存地址;
4、在堆内存中建立对象的特有属性,并进行默认初始化;
5、对属性进行显式初始化(定义属性时,属性赋予了初始值);
6、对对象进行构造代码块初始化;
7、对对象进行对应的构造函数初始化;
8、将内存地址赋给栈内存中的类变量p。
-
对象调用成员过程

注意方法区中,一部分为静态成员变量及方法,属于类中的共享成员。
在栈中,首先将main方法压入栈中,新建一个Person类指向p,name=zhangsan,age=20,将该对象存入堆中;
调用setName方法之后,将该方法压入栈,并且将堆中p指向的Person对象的地址传递到调用setName方法的栈中,将当前方法对应的对象的name修改为lisi;
之后又新建一个Person类指向p1,继续修改,整个调用过程就是如此。
本文深入解析Java中的static关键字,探讨其在成员变量和成员方法上的应用,以及它带来的优势和限制。同时,文章还介绍了static代码块的作用和对象初始化过程。

被折叠的 条评论
为什么被折叠?



