java里的static/final含义

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

原文地址:https://www.cnblogs.com/shengulong/p/11756301.html

时间: 2024-11-05 20:44:07

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

java进阶11 static final关键字

static表示"全局"或者"静态"的意思,用来修饰成员变量和成员方法,也可以形成静态static代码块. 被static修饰的成员变量和成员方法独立于该类的任何对象,也就是说. 它不依赖类的特定的实例,被类的所有实例共享. package Static; public class Static { /* * 使用的情况 * 1:在对象之间共享值时 * 2:方便访问变量 * */ public static void main(String[] args){ Sta

java里的static

本节介绍JAVA里static的作用和使用方法以及一些需要注意的问题. static表示"全局"或"静态",用来修饰成员变量和成员方法,以及代码块. 被static修饰的成员变量和成员方法独立于该类的任何对象.也就是说,它不依赖类特定的实例,被类的所有实例共享.只要这个类被加载,JAVA虚拟机就能根据类名在运行时数据区的演绎法我内找到它们.因此,static对象可以在它的任何对象创建之前访问,无需引用任何对象. 用public修饰的static成员变量和成员方法本质

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

在java中: >表示大于,如:if(a>b)...结果是boolean类型 >>表示右移,如:int i=15; i>>2的结果是3,移出的部分将被抛弃. 转为二进制的形式可能更好理解,0000 1111(15)右移2位的结果是0000 0011(3),0001 1010(18)右移3位的结果是0000 0011(3). >>>叫什么我也不是很清楚,但是我知道它表示的含义: j>>>i 与 j/(int)(Math.pow(2,i)

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

final关键字 继承的出现提高了代码的复用性,并方便开发.但随之也有问题,有些类在描述完之后,不想被继承,或者有些类中的部分方法功能是固定的,不想让子类重写.可是当子类继承了这些特殊类之后,就可以对其中的方法进行重写,那怎么解决呢?要解决上述的这些问题,需要使用到一个关键字final,final的意思为最终,不可变.final是个修饰符,它可以用来修饰类,类的成员,以及局部变量. final的特点 final修饰类不可以被继承,但是可以继承其他类. class Yy {} final clas

java中 static,final,transient,volatile关键字的作用

static 和final static  静态修饰关键字,可以修饰 变量,程序块,类的方法: 当你定义一个static的变量的时候jvm会将将其分配在内存堆上,所有程序对它的引用都会指向这一个地址而不会重新分配内存: 修饰一个程序块的时候(也就是直接将代码写在static{...}中)时候,虚拟机就会优先加载静态块中代码,这主要用于系统初始化:当修饰一个类方法时候你就可以直接通过类来调用而不需要新建对象. final 只能赋值一次:修饰变量.方法及类,当你定义一个final变量时,jvm会将其

java基础复习:final,static,以及String类

2.final 1)为啥String是final修饰的呢? 自己答: 答案: 主要是为了“效率” 和 “安全性” 的缘故.若 String允许被继承, 由于它的高度被使用率, 可能会降低程序的性能,所以String被定义成final. 还有另一个解释: 带有final修饰符的类是不可派生的.在Java核心API中,有许多应用final的例子,例如java.lang.String.为String类指定final防止了人们覆盖length()方法. 另外,如果指定一个类为final,则该类所有的方法

Java笔记十七.java中的static和final用法

在上几篇博文中我们知道,当我们编写一个类时,实际上就是在描述该类对象的属性和行为,而并没有产生实质上的对象,只有通过new关键字才会产生出对象,这时系统才会分配内存空间给对象,其方法才可以供外部调用.但有时候,我们希望无论是否产生了对象或无论产生了多少个对象的情况下,某些特定的数据在内存空间里只有一份,那么此时static关键字就派上用场了. 一.static关键字 1.静态成员变量/方法 在类成员(变量/方法)前加上一个static关键字,那么这个成员就称为了静态成员变量/方法.静态变量在某种

浅析java修饰符之public default protected private static final abstract

浅析java修饰符之public default protected private static final abstract 一   修饰符的作用:用来定义类.方法或者变量,通常放在语句的最前端 二   分类(大致分两类) 1.访问修饰符,包括:public default protected private 2.非访问修饰符,包括:static final abstract 三 访问修饰符--Java中,可以使用访问控制符来保护对类.变量.方法和构造方法的访问.Java支持4种不同的访问权

【Java关键字-Interface】为什么Interface中的变量只能是 public static final

三个关键字在接口中的存在原因:public:接口可以被其他接口继承,也可以被类实现,类与接口.接口与接口可能会形成多层级关系,采用public可以满足变量的访问范围: static:如果变量不是static的,那么接口必须实例化才可以访问自己的变量,接口不能被实例化,故非static的变量是无效的: final:如果变量不是final的,而方法是abstract的,因此接口中的方法又不可以修改变量值,虽然可以直接修改静态成员变量,但所有实现类对应的值都被修改了,此做法等同于抽象类,故需要fina