java关键字----static(值得看)

一:static关键字之基本用法:

     1. static关键字概念:

               一句话描述就是:方便在没有创建对象的情况下进行调用。也就是说:被static修饰的成员不需要通过创建对象来调用,直接根据类名就可以访问。

     2.static修饰变量和方法:

             用static声明的成员变量为静态成员变量(类变量);

             static声明的成员方法为static方法(静态方法)。

         * static是不允许用来修饰局部变量。不要问为什么,这是Java语法的规定

     3. static修饰代码块:

            static块:也叫静态初始化块,用于类的初始化操作,在类第一次被加载时执行,并且只执行一次;

            注意:在静态初始化块中不能直接方法非静态成员;

            作用:提升程序性能。(该作者的文章里有最好的例子:https://blog.csdn.net/kuangay/article/details/81485324)

          静态初始化块可以置于类中的任何地方,类中可以有多个静态初始化块。
          在类初次被加载时,会按照静态初始化块的顺序来执行每个块,并且只会执行一次。

      4. static修饰类:

               static只可以修饰内部类,普通类是不允许被声明为静态的。代码如下:

public class StaticTest{

    //内部类
    public static class InnerTest(){
        public InnerTest(){
            System.out.println("-----静态内部类-----");
        }
        public void InnerMethod(){
            System.out.println("-----静态内部方法-----");
        }
    }
    //main方法
    public static void main(String[] args){
        //直接通过类名访问静态内部类
        InnerTest test = new StaticTest.InnerTest();
        //静态内部类可以和普通类一样使用
        test.InnerMethod();
    }
}

                 上面这段代码静态内部类的写法,输出结果:

                   -----静态内部类-----

                   -----静态内部方法-----

                  *  如果没有用static修饰InterTest,则只能new 一个外部类实例。再通过外部实例创建内部类。

          这里再顺便说一下类初始化顺序

             父类静态变量
             父类静态代码块
             子类静态变量
             子类静态代码块
             父类普通变量
             父类普通代码块
             父类构造函数
             子类普通变量
             子类普通代码块
             子类构造函数

            *有关类初始化输出顺序的面试题,请查看该作者的文章,很不错:https://blog.csdn.net/kuangay/article/details/81485324

      5.static修饰和普通的区别:

               * static声明的成员变量和方法,从属于类;生命周期和类相同,在整个应用程序执行期间都有效;不依赖于任何对象(也就是没有this);

               * 普通变量和方法从属于对象;必须依赖于具体的对象才能被调用

               * 静态方法不能调用非静态的方法和变量,编译会报错;但是非静态的方法可以调用静态的成员方法和成员变量。

               * 静态变量被所有对象共享,在内存中只有一个副本,在类初次加载时加载;

               * 非静态变量是对象所拥有的,在内存中存在多个副本,各个对象所拥有的副本互不影响;每创建一个对象就初始化一个副本。

             代码实例:

              

             从代码中看出:

              * 非静态成员方法test2可以访问静态成员方法test1静态成员变量name的;

              * 静态成员方法test1调用非静态成员变量sex,编译不通过;原因:编译器没有对象生成,所以sex变量不存在;

              * 静态成员方法test1调用非静态成员方法test2,编译不通过;原因:编译器无法预知在test2方法中是否访问了非静态成员变量,所以禁止在静态成员方法调用非静态成员方法。

            特别说明:static方法是属于类的,非实例对象,在JVM加载类时,就已经存在内存中,不会被虚拟机GC回收掉,这样内存负荷会很大,但是非static方法会在运行完毕后被                                虚拟机GC掉,减轻内存压力

              

二:深入分析static关键字:

          问题:想要了解为什么static会有上面的那些特性?

          解决:我们需要从JVM内存开始,先附一张java的内存结构图:

                

                从上图问你可以看出,静态变量存放在方法区里,并且被所有的线程所共享,下面说一下各个结构。

                 1. 堆区:

                        * 存储的全部为对象,每个对象都包含一个与之对应的class的信息。(class的目的是得到操作指令);

                        * JVM 只有一个堆区(heap)被所有对象所共享,堆中不存放基本类型和对象引用,只存放对象本身。

                 2. 栈区:

                        * 每个线程包含一个栈区,栈中只保存基础数据类型的对象和自定义对象的引用(不是对象,对象都存放在堆区中);

                        * 每个栈中的数据(原始类型和对象引用)都是私有的,其他栈不能访问;

                        * 栈分为3部分:基本类型变量区、执行环境上下文、操作指令区(存放操作指令)。

                 3. 方法区:

                        * 又叫静态区,跟堆一样,被所有的线程所共享。该区包含所有的class和static变量;

                        * 方法区包含的都是在整个程序中永远唯一的元素,如:class、static变量;

                通过一个案例从内存角度来看:

public class Person{
    //静态变量
    static String firstName;
    //普通变量
    String lastName;
    //普通方法
    pubic void showName(){
        System.out.println(firstName+lastName);
    }
    //静态方法
    public static void viewName(){
        System.out.println(firstName);
    }

    public static void main(String[] args){
        Person p = new Person();
        Person.firstName = "张";
        p.lastName="三";
        p.showName();
        
        Person p2 = new Person();
        Person.firstName = "李";
        p2.lastName="四";
        p2.showName();
    }
}

   内存角度:

       

            解释:从上面可以看到,我们的方法在调用的时候,是从方法区调用的,但是堆内存不一样,堆内存中的成员变量lastName是随着对象的的产生而产生,对象的消失而消失;

                      静态变量是被所有线程所共享的,所以不会消失。

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值