static关键字的作用

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值