zoukankan      html  css  js  c++  java
  • java的static关键字

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

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

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

    3、可以通过对象引用或类名(不需要实例化)访问静态成员

    static 方法:

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

    下面例子:

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

      MyObject.print2();

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

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

      因此,如果说想在不创建对象的情况下调用某个方法,就可以将这个方法设置为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一个对象出来才能访问。

      静态的变量可以通过对象名去访问,也可以通过类名去访问,两者访问的都是同一块内存。

  • 相关阅读:
    mysql 执行计划 explain
    深度学习论文翻译解析(二十):YOLOv4: Optimal Speed and Accuracy of Object Detection
    卷积神经网络学习笔记——轻量化网络MobileNet系列(V1,V2,V3)
    OpenCV计算机视觉学习(13)——图像特征点检测(Harris角点检测,sift算法)
    人工智能必备数学基础:概率论与数理统计(2)
    人工智能必备数学基础:概率论与数理统计(1)
    深度学习论文翻译解析(十九):Searching for MobileNetV3
    深度学习论文翻译解析(十八):MobileNetV2: Inverted Residuals and Linear Bottlenecks
    深度学习论文翻译解析(十七):MobileNets: Efficient Convolutional Neural Networks for Mobile Vision Applications
    卷积神经网络学*笔记——SENet
  • 原文地址:https://www.cnblogs.com/white-the-Alan/p/10188574.html
Copyright © 2011-2022 走看看