如果使用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关键字的一些总结 (^__^)