JAVA-static关键字

目录

1、为什么需要static关键字

2、static关键字作用

3、成员变量何时声明为静态的?

4、方法何时声明为静态的?

5、总结

6、用对象调用静态成员

7、为什么不能全部定义为静态的?

8、static静态代码块

9、拓展:实例代码块

10、拓展:main方法可重载


        static关键字,静态的,可以用于修饰变量、方法和代码块

1、为什么需要static关键字

        举例子,有一个中国人类,类中属性有id(身份证号)、name(姓名)、country(国家)代码如下:

public class Chinese {
    private String id;
    private String name;
    private String country;
    public String getId() {
        return id;
    }
    public void setId(String id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getCountry() {
        return country;
    }
    public void setCountry(String country) {
        this.country = country;
    }
}

        那么在主方法中进行对象的创建和信息的获取如下:

public class test04 {
    public static void main(String[] args) {
        Chinese c1=new Chinese();
        Chinese c2=new Chinese();
        c1.setName("张三");
        c1.setId("130634001");
        c1.setCountry("China");
        c2.setName("李四");
        c2.setId("130634002");
        c2.setCountry("China");
    }
}

        这是两个对象,如果需要更多对象呢,比如现在这个是某个系统中的代码,中国十四亿之多的人口都要注册这个功能,那就是十四亿个对象,仔细观察这些内容,在中国,country字段是绝对相同的,都等于“China”,这个字段对于每一个Chinese类的对象来说都是已知的,但是每一个对象都重新为其分配空间,每个对象都单独拥有这样一个属性,浪费内存空间。

        如下是代码的内存分析图:

        所以static就是来解决这个问题的

2、static关键字作用

        用static声明的变量和方法就提升到了类的层级,通过类进行调用,和对象无关,这样就使其成为一个公共的成分,这些成分在类加载的时候进行初始化,先于其他代码执行之前,不需要创建对象,通过“类名·成分名”就可以访问,是在JVM的方法区内存中开辟空间进行存储的,相当于一个公共的内存空间,值可以被进行任意的调用和修改,但是使用该关键字声明要谨慎,因为其开放性,数据相对不安全,使用不当会导致变量在某一时刻的值有时候很难掌控。

3、成员变量何时声明为静态的?

        当所有或者多数对象都拥有这个属性,并且所有对象的这个属性的值是相同的,或者该变量的值不变且频繁使用的情况下(但是注意,这个方法中一定不需要访问到和实例相关的数据成分和信息,否则就不能声明为静态的)建议定义为静态的,可以理解为一个C语言中的类似的全局变量,例如:圆周率Pai,上文中的country变量,这样可以节省一定的内存开销。

那么成员变量什么时候声明为常规的实例变量呢?

        当某个变量的值有可能会因为对象的不同而呈现不同的值的时候,这种情况下,变量应该设置成对象级别的变量,通过“引用·变量名”进行调用每个对象都有一个自己的属性,而不是公用同一个变量去当做属性,例如:十四亿中国人,每两个中国人之间身份证号都绝对不会相同

4、方法何时声明为静态的?

        和变量的使用基本相同,如果该段方法,对于不同的对象来说,执行后具有相同的操作和效果,这种情况下,就将方法定义为类级别的方法,即通过static关键字将其声明为静态方法,而不是对象级别的方法,通过“类名·方法名”进行调用,例如:在登陆的时候,查询用户是否存在于数据库中,这个对于所有的对象都是一视同仁的,操作相同,可以设置为静态的方法,如图:(这个是C#的例子)

5、总结

        ①static关键字用于修饰变量、方法、代码块,成为静态变量、静态方法、静态代码块。

        ②用static关键字修饰的成分,通过“类名·方法名”的方式进行调用访问

        ③这也就意味着用static修饰的成分和对象没有关联,是类级别的

6、用对象调用静态成员

        可以用对象访问静态的成员,但是不建议这样做。因为成分和对象无关,即便通过对象去进行调用,系统还是默认的以“类名·方法名”的形式进行调用,这个对象没有什么意义,即便当前对象指向的内存空间为NULL,也不会报错,只会报警告,但是在编程过程中,警告有时候……可以忽略 |ヽ(* ̄▽ ̄*)ノミ|

        例如:

public class test04 {
    //int data;   //定义成员变量
    public static  int a=0;
    public static void main(String[] args) {
        test04 t4=null;
        t4.sys();
    }
    public  static  void sys(){
        System.out.println("i love  you");
    }
}

        运行后的输出结果:

i love  you

Process finished with exit code 0

        如上述代码,t4引用的值为null,如果说这个引用调用方法,必然会引起空指针的异常,但是很明显引用调用sys()方法不仅没有出现问题还顺利的运行得出了结果,这说明这个引用根本没有发挥作用,这也证明了我们上文的理论。

回顾:什么时候会触发空指针的异常

        当空引用去调用实例成员时,一定会产生空指针异常

        因为实例成员是实例级别的,也就是对象级别的,他们依赖于对象而存在,如果引用为空,那么它就并没有指向某个对象所在的堆内存的内存单元,而对于对象的访问只能通过引用的方式进行,这个对象没有被引用所指向,那么垃圾回收机制会考虑将堆内存中的对象内存单元进行回收,所以对象就不存在,通过引用也就无法访问到对象内存中存在的实例成员,这就导致了空的指针的异常。

7、为什么不能全部定义为静态的?

        可能会想,通过类名·方法名的方式进行访问多简单快捷,但是如果所有成分全都定义为静态的,那么就不存在对象这个概念了,所有的东西不用创建对象直接访问即可,这样其实代码的编写就从面向对象的角度退化到了面向过程,这样不利于代码的开发和维护。

回顾:面向对象和面向过程的区别?

        面向对象的开发理念,将现实中的事物进行抽象总结归纳,更符合人对于这个世界的看待方式,同时以对象为单位进行设计和开发,代码更加的具有独立性,代码重用性增强,有利于逻辑关系复杂的大型项目的开发,但是因为要对现实的事物进行抽象分析,所以在设计方面会消耗一定的时间,同时投入成本较高,但是一劳永逸,更加便于开发和后期维护的进行。

        面向过程的开发理念,以逻辑为中心,通过各模块之间的因果关系进行代码的编写,逻辑关系更加的清晰,前期投入成本较低,有利于逻辑关系简单的小型项目的开发,但是因为逻辑关系紧密,模块间具有较强的耦合性,所以代码的重用性较低,代码的维护相对困难。

8、static静态代码块

        8.1、语法结构:static{  java语句;}

        8.2、注意静态代码块在类加载的时候执行,也就是说这类静态代码块会先于main方法执行,注意他们不能定义在方法里而是定义在类体里,因为在类开始加载的时候,方法还没有开始运行,无法执行到这些代码块,会报错。静态代码块可以有多个,执行和普通代码一样遵循从上到下执行。

        8.3、怎么用?:它是为程序员准备的一个特殊的时刻——类加载时刻,这个根据程序员的需求,如果有想要在类加载的时候,即先于其他代码的操作需要执行,就可以利用静态代码块,将操作写到静态代码块里。通常可以用于完成必要的预备工作和数据的准备工具,例如:初始化连接池等,这些代码会先于main方法中的代码执行。

        8.4、举个例子:

public class test04 {
    public static void main(String[] args) {
        System.out.println("main方法执行");
    }

    static {
        System.out.println("静态代码-1-块执行");
    }
    static {
        System.out.println("静态代码-2-块执行");
    }
    static {
        System.out.println("静态代码-3-块执行");
    }
}

        输出结果如下:很明显,在程序主方法开始执行之前,static方法就已经执行结束了,并且多个静态代码块之间的执行是遵循自上到下执行的顺序。 

Connected to the target VM, address: '127.0.0.1:2655', transport: 'socket'
静态代码-1-块执行
静态代码-2-块执行
静态代码-3-块执行
main方法执行
Disconnected from the target VM, address: '127.0.0.1:2655', transport: 'socket'

Process finished with exit code 0

9、拓展:实例代码块

        除了静态代码块,还有一种代码块是实例代码块,其使用的规则和静态代码块一样,写在类体之中方法区之外。

        9.1、语法结构:  {   java语句;}

        首先我们和静态代码块一样运行看一下:

public class test04 {
    //int data;   //定义成员变量
    public static  int a=0;
    public static void main(String[] args) {
        System.out.println("main方法执行");
    }

    {
        System.out.println("实例代码-1-块执行");
    }
    {
        System.out.println("实例代码-2-块执行");
    }
    {
        System.out.println("实例代码-3-块执行");
    }
}

        运行后和静态代码块的运行结果有些不同,如下所示:这些代码块并没有运行

main方法执行

Process finished with exit code 0

        代码块是实例代码块,从名字上大概可以猜出和对象有关,那么现在创建其所在类的对象,看一下输出结果:

public class test04 {
    //手动添加当前类的构造方法
    public test04(){
        System.out.println("构造方法执行");
    }

    public static void main(String[] args) {
        System.out.println("main方法执行");
        test04 t4=new test04();   //在这里创建了新的当前类对象
    }

    {
        System.out.println("实例代码-1-块执行");
    }
    {
        System.out.println("实例代码-2-块执行");
    }
    {
        System.out.println("实例代码-3-块执行");
    }
}

  输出结果:

        很明显,实例代码块如果不创建其所在类的对象,是不会执行的,但是如果有对象的创建,那么在创建对象之前即构造方法执行之前,会执行这些实例代码块,然后再创建对象。构造方法执行一次,这些代码块就会对应的执行一次,即只要创建对象,在创建之前,这些代码就会执行。

main方法执行
实例代码-1-块执行
实例代码-2-块执行
实例代码-3-块执行
构造方法执行

Process finished with exit code 0

        实例代码块可以编写多个,遵循从上到下的顺序依次执行

        这同样为程序员提供了一个时机,即再创建对象之前的一个时机,供程序员根据需求完成一定的操作。 

10、拓展:main方法可重载

        main方法也是一个方法,不要神化,方法都具有重载的特性,main方法也不例外。但是程序的入口始终只有一个。

        如下所示:

public class test04 {
    public static void main(String[] args) {
        System.out.println("main方法执行");
        main(5);
    }
    public static void main(int i){
        System.out.println("main方法的重载方法执行");
    }
}

        输出结果:代码顺利执行,并且main的重载方法在main方法当中可以进行调用。

main方法执行
main方法的重载方法执行

Process finished with exit code 0

 拓展:其实对于main入口静态方法的调用,计算机也是通过“类名·方法名”的形式进行调用的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值