static关键字的作用

来源:互联网 发布:制作视频片头软件 编辑:程序博客网 时间:2024/06/10 16:39

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

原创粉丝点击