java的static关键字

 

一、在类中,用static声明的成员变量为静态成员变量,他为该类的公用变量,在第一次使用时被初始化,对于该类的全部对象来讲static成员变量只有一份函数

二、用static声明的方法为静态方法,在调用该方法时,不会将对象的引用传递给他,因此在static方法中不可访问非static的成员布局

  静态方法不在是针对某个对象调用,因此不能访问非静态成员性能

三、能够经过对象引用或类名(不须要实例化)访问静态成员学习

static 方法:优化

  static 修饰的方法称为静态方法,能够不用建立对象便可使用,对于静态方法来讲没有this的,由于它不依附于任何对象,既然没有对象就谈不上this,而且这个因为特性,在静态方法中不能访问类的非静态成员变量和非静态方法,由于非静态成员方法/变量都是必须依赖于具体的对象才能够被调用,注意:在静态方法中不能访问非静态成员方法和非静态成员变量,可是在非静态成员方法中能够访问静态成员方法/变量的this

下面例子:spa

在上面的代码中,因为print2方法是独立于对象存在的,能够直接用过类名调用。假如说能够在静态方法中访问非静态方法/变量的话,那么若是在main方法中有下面一条语句:code

  MyObject.print2();对象

  此时对象都没有,str2根本就不存在,因此就会产生矛盾了。一样对于方法也是同样,因为你没法预知在print1方法中是否访问了非静态成员变量,因此也禁止在静态成员方法中访问非静态成员方法。blog

  而对于非静态成员方法,它访问静态成员方法/变量显然是毫无限制的。

  所以,若是说想在不建立对象的状况下调用某个方法,就能够将这个方法设置为static。咱们最多见的static方法就是main方法,至于为何main方法必须是static的,如今就很清楚了。由于程序在执行main方法的时候没有建立任何对象,所以只有经过类名来访问。

static变量:

  static变量也称做静态变量,静态变量和非静态变量的区别是:静态变量被全部的对象所共享,在内存中只有一个副本,它当且仅当在类初次加载时会被初始化。而非静态变量是对象所拥有的,在建立对象的时候被初始化,存在多个副本,各个对象拥有的副本互不影响。

  static成员变量的初始化顺序按照定义的顺序进行初始化。

static代码块:

  static关键字还有一个比较关键的做用就是 用来造成静态代码块以优化程序性能。static块能够置于类中的任何地方,类中能够有多个static块。在类初次被加载的时候,会按照static块的顺序来执行每一个static块,而且只会执行一次。

  为何说static块能够用来优化程序性能,是由于它的特性:只会在类加载的时候执行一次。下面看个例子:

class Person{
    private Date birthDate;
     
    public Person(Date birthDate) {
        this.birthDate = birthDate;
    }
     
    boolean isBornBoomer() {
        Date startDate = Date.valueOf("1946");
        Date endDate = Date.valueOf("1964");
        return birthDate.compareTo(startDate)>=0 && birthDate.compareTo(endDate) < 0;
    }
}

isBornBoomer是用来这我的是不是1946-1964年出生的,而每次isBornBoomer被调用的时候,都会生成startDate和birthDate两个对象,形成了空间浪费,若是改为这样效率会更好:

class Person{
    private Date birthDate;
    private static Date startDate,endDate;
    static{
        startDate = Date.valueOf("1946");
        endDate = Date.valueOf("1964");
    }
     
    public Person(Date birthDate) {
        this.birthDate = birthDate;
    }
     
    boolean isBornBoomer() {
        return birthDate.compareTo(startDate)>=0 && birthDate.compareTo(endDate) < 0;
    }
}

static关键字的误区:

1.static关键字不会改变类中成员的访问权限

  Java中的static关键字不会影响到变量或者方法的做用域。在Java中可以影响到访问权限的只有private、public、protected(包括包访问权限)这几个关键字。看下面的例子就明白了:

  

  提示错误"Person.age 不可视",这说明static关键字并不会改变变量和方法的访问权限。

2.能经过this访问静态成员变量吗?

public class Main {  
    static int value = 33;
 
    public static void main(String[] args) throws Exception{
        new Main().printValue();
    }
 
    private void printValue(){
        int value = 3;
        System.out.println(this.value);
    }
}

输出33

这里面主要考察队this和static的理解。this表明什么?this表明当前对象,那么经过new Main()来调用printValue的话,当前对象就是经过new Main()生成的对象。而static变量是被对象所享有的,所以在printValue中的this.value的值毫无疑问是33。在printValue方法内部的value是局部变量,根本不可能与this关联,因此输出结果是33。在这里永远要记住一点:静态成员变量虽然独立于对象,可是不表明不能够经过对象去访问,全部的静态方法和静态变量均可以经过对象访问(只要访问权限足够)。

3.static能做用于局部变量么?

  static是不容许用来修饰局部变量。

下面利用画内存学习更加深入的需东西这一小节:

package satic;
public class Cat {
    private static int sid = 0; // sid是静态的能够直接用类名变量名直接用

private String name; //Cat类私有的属性name 初始值为0 int id; //变量 Cat(String name) { this.name = name; //将调用Cat方法时传入的值赋值给name属性 id = sid++; //将sid的值赋值给id而且sid自增1 } //info方法输入name和id的值 public void info(){ System.out.println ("My name is "+name+" No."+id); } public static void main(String arg[]){ Cat.sid = 100; //将sid的值变为100 /* * 调用Cat 方法更改name与id的值并打印 * */ Cat mimi = new Cat("mimi"); Cat pipi = new Cat("pipi"); mimi.info(); pipi.info(); } }

 先从main函数入口开始,

  Cat.sid = 100在数据区当中有一个sid,被赋值为100,Cat mimi = new Cat("mimi")时,在栈内存当中有一个叫mimi的内存具体内容不知,但他指向堆内存当中的一块内存,在堆内存当中有两个分别是id和name的属性,而mimi这个字符串是存储在数据区的,字符串也是个引用类型,因此说字符串能够看做是一个对象,执行

Cat(String name) {
        this.name = name;  //将调用Cat方法时传入的值赋值给name属性
        id = sid++; //将sid的值赋值给id而且sid自增1
 }
时在栈内存里面有一个name的内存而后,这个"mimi"的引用交到name中,如今name指向"mimi"字符串,this.name = name,这句话中
将栈内存的name的值赋值给堆内存中mimi这个对象的name,也就是mimi这个对象的name也指向数据区里面的“mimi”字符串,而后将sid的
值赋值给id,sid自身+1,这时候的内存中的图以下:

 

 

而后构造方法执行完毕,给这个构造方法分配的局部变量所占的内存空间所有消失,因此位于栈内存的name这块内存消失了,栈内存里面指向数据区里面的字符串对象"mimi"的引用也随之消失,此时只剩下堆内存里面的字符串对象“mimi”的引用没有消失,此时的内存布局以下

 

执行Cat pipi  = new Cat("pipi"),执行过程u第一次同样,这里就不过多解释了,此时的内存布局以下图:

The result is:

My name is mimi No.100
My name is pipi No.2000

 

 由此能够看出这个静态的sid能够计数用的

这里调用构造方法Cat(String name) 建立出两只猫,首先在栈内存里面分配两小块空间mimi和pipi,里面分别装着能够找到这两只猫的地址,mimi和pipi对应着堆内存里面的两只猫的引用。这里的构造方法声明有字符串类型的变量,字符串常量是分配在数据区里面的,因此这里会把传过来的字符串mimi和pipi都存储到数据区里面。因此数据区里面分配有存储字符串mimi和pipi的两小块内存,里面装着字符串“mimi”和“pipi”,字符串也是引用类型,除了那四类8种的基础数据类型以外,其余全部的数据类型都是引用类型。因此能够认为字符串也是一个对象。

  这里是new了两只猫出来,这两只猫都有本身的id和name属性,因此这里的id和name都是非静态成员变量,即没有static修饰。因此每new出一只新猫,这只新猫都有属于它本身的id和name,即非静态成员变量id和name是每个对象都有单独的一份。但对于静态成员变量来讲,只有一份,无论new了多少个对象,哪怕不new对象,静态成员变量在数据区也会保留一份。如这里的sid同样,sid存放在数据区,不管new出来了多少只猫在堆内存里面,sid都只有一份,只在数据区保留一份。

  静态成员变量是属于整个类的,它不属于专门的某个对象。那么如何访问这个静态成员变量的值呢?首先第一点,任何一个对象均可以访问这个静态的值,访问的时候访问的都是同一块内存。第二点,即使是没有对象也能够访问这个静态的值,经过“类名.静态成员变量名”来访问这个静态的值,因此之后看到某一个类名加上“.”再加上后面有一个东西,那么后面这个东西必定是静态的,如”System.out”,这里就是经过类名(System类)再加上“.”来访问这个out的,因此这个out必定是静态的

下面再看这段代码:

package satic;
public class Cat {
    /*
     * 这里的sid不在是静态的了
     */
    private  int sid = 0; 
    /*
     * 这里的name和id是非静态的成员变量
     * 
     */
    private String name;  //Cat类私有的属性name 初始值为0
    int id; //变量
    Cat(String name) {
        this.name = name;  //将调用Cat方法时传入的值赋值给name属性
        id = sid++; //将sid的值赋值给id而且sid自增1
    }
    //info方法输入name和id的值
    public void info(){
        System.out.println
               ("My name is "+name+" No."+id);
    }
    public static void main(String arg[]){

        //Cat.sid = 100;   上面的sid不在是静态的了,因此不能这样来访问了
        
        /*
         * 调用Cat 方法更改name与id的值并打印
         * 
         */
        Cat mimi = new Cat("mimi"); 
        mimi.sid = 2000;
        Cat pipi = new Cat("pipi");
        mimi.info(); 
        pipi.info();
    }
}

这段代码与上面的代码不一样的是,将sid变成了非静态的,就再也不有计数功能了,sid和name与id同样都属于属性,固然在面的代码当中也不能使用Cat.sid访问了,把Cat.sid那行去掉便可,这样的话,内存图就变成了下面的:

 

 成员变量(属性)与局部变量的区别在于,成员变量(属性)初始的值为0,而局部变量没有初始化不能使用,因此,每次执行Cat方法,sid由0变为1,这样sid就没有了计数的功能

在一个静态方法里,若是想访问一个非静态的成员变量,是不能直接访问的,必须在静态方法里new一个对象出来才能访问。若是是加了static的成员变量,那么这个成员变量就是一个静态的成员变量,就能够在main方法里面直接访问了。

  main方法是一个静态的方法,main方法要执行的时候不须要new一个对象出来。

 动态方法是针对于某一个对象调用的,静态方法不会针对某一个对象来调用,没有对象照样能够用。因此可使用”classname.method()”.的形式来调用静态方法。因此想在main方法里面访问非静态成员变量是不能够的,想在main方法里面访问非静态方法也是不能够的,由于非静态方法只能针对于某个对象来调用,没有对象,就找不到方法的执行者了。

成员变量只有在new出一个对象来的时候才在堆内存里面分配存储空间。局部变量在栈内存里面分配存储空间。

  静态方法再也不是针对某一个对象来调用,因此不能访问非静态的成员。

  非静态成员专属于某一个对象,想访问非静态成员必须new一个对象出来才能访问。

  静态的变量能够经过对象名去访问,也能够经过类名去访问,二者访问的都是同一块内存。

相关文章
相关标签/搜索