static关键字的作用

时间:2022-04-26 19:39:25

如果使用static定义属性,那么这个变量就被称为静态属性。那什么是静态属性呢?使用静态属性又有什么好处呢?

我们举一个例子:

1、静态属性和静态方法

package com.feiyu.myapplication;

/**
* Created by qianye on 2017/6/15.
*/


class People {
String name;
String sex;

public People(String name, String sex) {
this.name = name;
this.sex = sex;
}

public String show() {
return "name = " + this.name + " sex = " + this.sex;
}
}

public class Student {
public static void main(String[] args) {
People p1 = new People("盖伦", "男");
People p2 = new People("赵信", "男");
People p3 = new People("嘉文", "男");
System.out.println(p1.show());
System.out.println(p2.show());
System.out.println(p3.show());
}
}

这样运行代码输出的结果必然是:

name = 盖伦 sex = 男
name = 赵信 sex = 男
name = 嘉文 sex = 男

那么如果我创建了100个对象,这100个对象全部是男性呢?我是不是要给每一个对象都设置一遍参数呢?
这样做实在太繁琐。这个时候我们就需要用到static关键字了。我们修改People类:

class People {
String name;
static String sex;//使用static修饰sex

public People(String name, String sex) {
this.name = name;
this.sex = sex;
}

public String show() {
return "name = " + this.name + " sex = " + this.sex;
}
}

public class Student {
public static void main(String[] args) {
People p1 = new People("盖伦", "男");
People p2 = new People("赵信", "男");
People p3 = new People("嘉文", "男");
System.out.println(p1.show());
System.out.println(p2.show());
System.out.println(p3.show());

p1.sex = "女";
System.out.println("修改后");
System.out.println(p1.show());
System.out.println(p2.show());
System.out.println(p3.show());

}
}

输出结果:

name = 盖伦  sex = 男
name = 赵信 sex = 男
name = 嘉文 sex = 男
修改后
name = 盖伦 sex = 女
name = 赵信 sex = 女
name = 嘉文 sex = 女

由此我们看出:

statci修饰的属性被类的所有对象所共享,我们可以称之为公共属性。

static修饰的属性也可以直接被类调用,比如 People.sex = “无性别”;

同样的,static也可以用来修饰方法,我们称之为静态方法,静态方法同样可以由类名称直接调用,也可以由对象调用。

java代码的主函数之所以写成public static是因为:1、java虚拟机要调用类的main方法,所以它必须是public的。2、虚拟机在执行main方法时不必创建对象,所以它必须是static的。

2、静态代码块:

一个类使用静态代码块,当这个类被加载的时候会首先执行静态代码块,并且只执行一次。静态代码块的执行要优先于静态方法,因此它可以对静态属性初始化。

我们可以做一个试验:

package com.feiyu.myapplication;

class People {
String name;
static String sex;

//静态代码块,如果不使用static修饰,此代码块就会在每次构建对象时执行。
static
{
System.out.println("静态代码块测试");
}

public People(String name, String sex) {
this.name = name;
this.sex = sex;
}

public String show() {
return "name = " + this.name + " sex = " + this.sex;
}

public static void setSex(String newSex) {
sex = newSex;
}
}

public class Student {
public static void main(String[] args) {
People p1 = new People("盖伦", "男");
People p2 = new People("赵信", "男");
People p3 = new People("嘉文", "男");
System.out.println(p1.show());
System.out.println(p2.show());
System.out.println(p3.show());

}
}

输出结果:

静态代码块测试
name = 盖伦 sex = 男
name = 赵信 sex = 男
name = 嘉文 sex = 男

以上就是static的基本介绍。

那么在android里使用static需要注意什么呢?

1、静态变量在类加载的时候就会分配内存
启动APP(或启动进程)的时候加载
2、静态变量在类被卸载的时候销毁
关闭APP(或销毁进程)的时候卸载
3、由于进程被杀死的时候静态变量也会销毁,所以不能保证静态变量一直存在。(想想这也是理所当然的吧(^__^) )
4、每次打开APP静态变量都会被赋予初始值,这就是为什么APP内部一些常量字符串,访问地址被设置成static的原因了。

5、使用static构建单例模式的时候,小心内存泄露:

比如我们写一个单例:

public class SingleManager {
private Context context;
private static SingleManager manager;


public static SingleManager getInstance(Context context) {
if (manager == null)
manager = new SingleManager(context);
return manager;
}

public SingleManager(Context context) {
this.context = context;
}
}

然后我们在某一个activity里获取这个单例:

public class MainActivity extends AppCompatActivity {

private SingleManager manager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//这里传入当前activity的context,会导致activity没法释放而造成内存泄露
manager = SingleManager.getInstance(this);
}
}

这就是一个典型的内存泄露。我们知道静态变量是和进程的生命周期相关的,当APP运行的时候这个静态变量会一直存在,那么它也就会一直持有MainActivity的引用,从而导致MainActivity无法释放而造成内存泄露。
那么应该怎么写单例呢?其实我们只要传入Application的contenxt就可以了。
如下:

public class SingleManager {
private Context context;
private static SingleManager manager;


public static SingleManager getInstance(Context context) {
if (manager == null)
manager = new SingleManager(context);
return manager;
}

public SingleManager(Context context) {
//this.context = context;
//使用Application的context
this.context = context.getApplicationContext();
}
}

另外一种不太明显看出来的内存泄露:
非静态内部类和匿名内部类持有外部类的引用造成的内存泄露。
如:


public class MainActivity extends AppCompatActivity {

private SingleManager manager;

//
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
};

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//这里传入当前activity的context,会导致activity没法释放而造成内存泄露
manager = SingleManager.getInstance(this);

//延时10分钟发送一个消息
handler.postDelayed(new Runnable() {
@Override
public void run() {

}
}, 60 * 10 * 1000);
finish();
}
}

通过handler发送runable对象,当activity销毁以后,这个handler发送的消息仍然在消息队列中活着,直到10分钟以后被处理,然而这个handler对象会持有activity的引用导致acitivity不能被销毁从而造成内存泄露。

那么怎么解决呢?这个时候又要用到我们的static关键字了。我们可以定义一个静态内部类,静态内部类是不会持有外部类引用的。

修改如下:

public class MainActivity extends AppCompatActivity {

private SingleManager manager;

//1、使用static创建匿名类的静态实例,不会持有外部类的引用
private static Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
};
private static MyHandler myHandler;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//这里传入当前activity的context,会导致activity没法释放而造成内存泄露
manager = SingleManager.getInstance(this);

//延时10分钟发送一个消息
handler.postDelayed(new Runnable() {
@Override
public void run() {

}
}, 60 * 10 * 1000);

myHandler.postDelayed(new Runnable() {
@Override
public void run() {

}
}, 60 * 10 * 1000);

finish();
}

//2、静态内部类的实例也不会持有外部类的引用
private static class MyHandler extends Handler {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
}
}

以上就是我对static关键字的一些总结 (^__^)