java里的static/final含义

static

  • static可以修饰:属性,方法,代码段,内部类(静态内部类或嵌套内部类)
  • static修饰的属性的初始化在编译期(类加载的时候),初始化后能改变。因此static修饰的属性必须有初始值(数值型变量默认值为0,布尔型默认值为false,引用类型默认值为null)。类加载后,存储在方法区(metaspace)
  • static修饰的属性所有对象都只有一个值(但是多个实例都可以同时修改,因此不具有线程安全性)。
  • static修饰的属性强调(在多个实例中)只有一个。
  • static修饰的属性、方法、代码段跟该类的具体对象无关,不创建对象也能调用static修饰的属性、方法等
  • static和“this、super”势不两立,static跟具体对象无关,而this、super正好跟具体对象有关。
  • static不可以修饰局部变量。

final

  • final可以修饰:属性,方法,类,局部变量(方法中的变量)
  • final修饰的属性的初始化可以在编译期,也可以在运行期,初始化后不能被改变。final修饰的属性没有默认值
  • final修饰的属性跟具体对象有关,在运行期初始化的final属性,不同对象可以有不同的值。
  • final修饰的属性表明是一个常数(创建后不能被修改)。
  • final修饰的方法表示该方法在子类中不能被重写,它可以防止任何继承类修改方法的意义和实现,而且,使用final修饰方法的执行效率一般高于普通方法
  • 当final修饰一个类时,表明其为最终类,它不能被继承,并且类中所有的属性和方法都默认是final类型,如String,Integer等包装类均为final类
  • 对于基本类型数据,final会将值变为一个常数(大写字母表示,创建后不能被修改)
  • 对于对象句柄(亦可称作引用或者指针),final会将句柄变为一个常数(进行声明时,必须将句柄初始化到一个具体的对象。而且不能再将句柄指向另一个对象。但是,对象的本身是可以修改的。这一限制也适用于数组,数组也属于对象,数组本身也是可以修改的。方法参数中的final句柄,意味着在该方法内部,我们不能改变参数句柄指向的实际东西,也就是说在方法内部不能给形参句柄再另外赋值
  • final修饰的参数有一个只读的属性,即可以读取该参数,但是无法更改参数的值,同修饰变量一样,当参数为基本类型时,该参数的值不可改变;当参数为引用类型时,参数的引用地址不可改变

demo

由于final修饰的String变量不可更改,所以,当一个String变量被final修饰时,这个值在编译期就可以确定,所有将该变量直接替换为它对应的值,如下:

public class test {
public static void main(String[] args) {
final String a = "hello";
String b = "hello"; // String是对象,一旦赋值不可以改变,但是b可以执行其他对象
// b = "test";
final String c = "world";
String d = "hello" + "world";
String e = a + c;
String f = b + c; // 运行时,在堆内分配内存
String g = "helloworld"; // 在字符串常量池内
StringBuilder y = new StringBuilder("test");
y.append("demo");
y.append("good");
System.out.println(g == d);//true,“==”表示判断二者的内存地址是否相同
System.out.println(g == e);//true,“==”号在比较对象时是比较对象在内存中的地址是否一致
System.out.println(g == f);//false
System.out.println(y);
}
}

在编译期,由于a和c的值已经确定并且不会再更改(效果同d),所以e的值能够在编译期就确定下来,直接指向了常量区的g,前两个均为true;再看下f,由于b值的不确定性,所以在编译期不能确定其值,只能在运行时确认,所以二者内存地址不同,(g == f)为false。

static final

  • 修饰的属性没有默认值,必须进行初始化
  • static final:static修饰的属性强调它们只有一个,final修饰的属性表明是一个常数(创建后不能被修改)。
  • static final修饰的属性表示一旦给值,就不可修改,并且可以通过类名访问。
  • static final也可以修饰方法,表示该方法不能重写,可以在不new对象的情况下调用

final变量初始化

public class MainTest {
//-----------------成员变量(实例变量)------------------//
// 初始化方式一(编译时赋值),在定义变量时直接赋值,如果不赋值,不会有默认值,必须后续进行赋值
private final int i = 3; // 初始化方式二(运行时赋值),声明变量后在构造方法中为其赋值,如果采用用这种方式,那么每个构造方法中都要有j赋值的语句
private final int j;
public MainTest() {
j = 3;
}
// 为了方便我们可以这样写,final变量多于1个时,就没有办法使用这种方式实现了
public MainTest(int int1) {
this(3);
} // 初始化方式三(运行时赋值),声明变量后在构造代码块中为其赋值,如果采用此方式,就不能在构造方法中再次为其赋值,构造代码块中的代码会在构造方法之前执行,如果在构造方法中再次赋值,就会造成final变量的重复赋值
private final int k;
{
k = 4;
} //-----------------类变量(静态变量)------------------//
// 初始化方式一,在定义时直接赋值(不赋值使用默认值)
public static int p = 3;
// 初始化方式二,在静态代码块中赋值
public static int q;
static {
q = 3;
}
// 成员变量可以在构造方法中赋值,但是类变量却不可以。因为成员变量属于对象(类的实例)独有,每个对象创建时都必然调用一次构造方法而切只会调用一次构造方法,因此可以保证该成员变量只被初始化一次;而类变量是该类的所有对象共有,如果每个对象创建时都会对该变量赋值,这样就会造成变量的重复赋值。 }
实例变量具有默认值,数值型变量的默认值是0,布尔型变量的默认值是false,应用类型变量的默认值是null

不同变量类型在JVM内的存储

  1. 基本局部变量存在栈中(虚拟机栈),但是方法里的数组和对象存在于堆中
  2. 静态变量储存在方法区
  3. 实例变量/成员变量储存在堆中

常量池(jdk>=1.7)

  1. class常量池:位于方法区,存放字面量和符号引用

    • 字面量类似与我们平常说的常量,主要包括:

      • 文本字符串:就是我们在代码中能够看到的字符串,例如String a = "aa"。其中"aa"就是字面量。
      • 被final修饰的变量
    • 符号引用:

      • 类和接口和全限定名:例如对于String这个类,它的全限定名就是java/lang/String。
      • 字段的名称和描述符:所谓字段就是类或者接口中声明的变量,包括类级别变量(static)和实例级的变量。
      • 方法的名称和描述符。所谓描述符就相当于方法的参数类型+返回值类型
  2. 运行时常量池:class文件中的常量池,它会在类加载后进入方法区中的运行时常量池。并且需要的注意的是,运行时常量池是全局共享的,多个类共用一个运行时常量池。并且class文件中常量池多个相同的整数在运行时只会存一份在字符串常量池

  3. 字符串常量池:存在堆中。class文件中的文本字符串在运行时就存在这里。并且class文件中常量池多个相同的字符串在运行时只会存一份在字符串常量池

  4. 整数常量池:方法区,在运行时常量池内,范围-128~127

然后看一段代码,问:这里产生了几个对象?:

string s1= new string("abc")

根据上面的意思,我们可以这样说,如果常量池中已经有了abc对象,那么就只会在堆中产生一个对象。如果没有,那么先在常量池中创建一个对象,然后复制到堆内存中再创建一个,所以创建了两个。

参考

https://zhuanlan.zhihu.com/p/42184392

https://zhuanlan.zhihu.com/p/40798413

java里的static/final含义的更多相关文章

  1. java里的static和final

    本节介绍JAVA里static和final的作用和使用方法以及一些需要注意的问题. 一.static static表示"全局"或"静态",用来修饰成员变量和成员 ...

  2. Java 面向对象之static,final,匿名对象,内部类,包,修饰符

    01final关键字概念 A: 概述 继承的出现提高了代码的复用性,并方便开发.但随之也有问题,有些类在描述完之后,不想被继承, 或者有些类中的部分方法功能是固定的,不想让子类重写.可是当子类继承了这 ...

  3. 在Java里>、>>、>>>的含义

    在java中: >表示大于,如:if(a>b)...结果是boolean类型 >>表示右移,如:int i=15; i>>2的结果是3,移出的部分将被抛弃. 转为二 ...

  4. 对php和java里面的static函数和static的一些理解

    static function: "static方法就是没有this的方法.在static方法里面不可以调用非静态方法,反过来是可以的.并且可以在没有创建任何对象的前提下,仅仅通过类名来调用 ...

  5. java笔记之static&final&abstract

    知识需要不断回顾和重新认识 一:static static类型变量初始值只能被赋值一次,它的整个生命周期是源程序,程序结束前变量都不会被释放. 例如: for(int i = 0; i<10; ...

  6. java面试官:兄弟简单谈谈Static、final、Static final各种用法吧

    前言 对Static.final.Static final这几个关键词熟悉又陌生?想说却又不知怎么准确说出口?好的,本篇博客文章将简短概要出他们之间的各自的使用,希望各位要是被你的面试官问到了,也能从 ...

  7. java中的Static、final、Static final各种用法详解

    前言 对Static.final.Static final这几个关键词熟悉又陌生?想说却又不知怎么准确说出口?好的,本篇博客文章将简短概要出他们之间的各自的使用,希望各位要是被你的面试官问到了,也能从 ...

  8. Java基础学习笔记十 Java基础语法之final、static、匿名对象、内部类

    final关键字 继承的出现提高了代码的复用性,并方便开发.但随之也有问题,有些类在描述完之后,不想被继承,或者有些类中的部分方法功能是固定的,不想让子类重写.可是当子类继承了这些特殊类之后,就可以对 ...

  9. 2017.10.23 Java 面向对象深入学习---final 关键字、static关键字、匿名对象等

    今日内容介绍 1.final 关键字 2.static 关键字 3.匿名对象 4.内部类 5.包的声明与访问 6.访问修饰符 7.代码块 第一节课 01(面向对象)final关键字概念.avi 02: ...

随机推荐

  1. centos 7 修改密码

    linux管理员忘记root密码,需要进行找回操作. 注意事项:本文基于centos7环境进行操作,由于centos的版本是有差异的,继续之前请确定好版本. 操作步骤 一.重启系统,在开机过程中,快速 ...

  2. 用Queue控制python多线程并发数量

    python多线程如果不进行并发数量控制,在启动线程数量多到一定程度后,会造成线程无法启动的错误. 下面介绍用Queue控制多线程并发数量的方法(python3). # -*- coding: utf ...

  3. 在windbg调试.net时遇到的问题

    调试.net应用程序时,有时会在windbg中收到错误消息.以下是我最常遇到的几个问题. Failed to start stack walk---启动堆栈遍历失败 如果你运行sos命令!clrsta ...

  4. SVN 常用 还原项目

    1.先修改本来两个文件,然后再提交到SVN 2.在日志界面,查看提交的文件,找到对应的版本号 3.找到对应的版本号(这里的版本号是1995,我提交生成的版本号 的前一个版本 才是我未作出修改的版本), ...

  5. CF468C 【Hack it!】

    构造题果然都非常神仙啊 首先翻译有点问题,\(L, R\)的范围应该为\([1, 10^{200}]\) 由于模数a达到了\(10^{18}\),所以我们可以发现,当\(i<10^{18}\)时 ...

  6. C博客作业--我的第一篇博客作业

    1你对网络专业或计算机专业了解是怎样的 由于从小就与电脑打交道,对于各类软件的生产非常感兴趣,所以在高三开学查询有什么专业的时候,就打算报与计算机有关的专业.我对计算机专业感到非常神奇,毕竟只是看似简 ...

  7. (7)Go切片

    切片 切片(Slice)是一个拥有相同类型元素的可变长度的序列.它是基于数组类型做的一层封装.它非常灵活,支持自动扩容. 切片是一个引用类型,它的内部结构包含地址.长度和容量.切片一般用于快速地操作一 ...

  8. Java-根据经纬度计算距离(百度地图距离)

    最近碰到一个需求,需要根据两个点的经纬度查询两点的距离.感觉以后还会用到,所以小记一波. 第一步:添加Maven依赖. <dependency> <groupId>org.ga ...

  9. PHP base_convert() 函数

    16进制转8进制 <?php $hex = "E196"; echo base_convert($hex,,); ?> 8进制数转换为10进制数 <?php $o ...

  10. 四个大点,搞懂 Redis 到底快在哪里

    来源:https://mp.weixin.qq.com/s/4kPlBE3C6lTuSvt5mY5hUQ 前言 一. 开发语言 二. 纯内存访问 三. 单线程 四. 非阻塞多路I/O复用机制 前言 R ...