Java基础:String不可变性和final修饰

转载请注明出处: jiq?钦‘s technical Blog - 季义钦

String的不可变性

Java规定String是不可变的(immutable)。事实上这个不可变具备两层含义:

1 内容不可变

不论什么看起来改动它们的操作。实际上都是又一次new出一个对象。

String s = new String("111");
String newS = s;
newS = "dsfsd";
System.out.println(s);  //111

假设不能做到内容不可变。在两个引用同一时候指向一个内存的时候,改动当中一个也会影响到另外一个。

2 实现方式不可变

使用String类型变量时,其不能表现出其他行为。这就是为什么String类须要用finalkeyword来进行修饰的原因,设想一下String不用final修饰。则其能够被继承并重写方法:

/**
 * 模拟非final的String
 * @author jiyiqin
 *
 */
class MyString{
    public char value[] = new char[10];
    MyStringtoLowerCase(MyString s)
    {
       System.out.println("将s转换为小写,但不改变原有s");
       char newValue[] = new char[s.value.length];
       for(int i = 0; i < s.value.length; i++)
           newValue[i]= LowerUtils.Lower(s.value[i]);
       MyStringnewString = newMyString();
       newString.value = newValue;
       return newString;
    }
}

/**
 * 继承MyString,将其toLowerCase重写
 * @author jiyiqin
 *
 */
class OverrideString extends MyString{
    MyStringtoLowerCase(MyString s)
    {
       System.out.println("直接改动传递进来的s的内存。将s转换为小写");
       for(int i = 0; i < s.value.length; i++)
           s.value[i] = LowerUtils.Lower(s.value[i]);
       return s;
    }
}

public classFinalStringTest {
    /**
     * 測试函数,java设计String是不可变的
     * 所以必须将String修饰为final。否则其
     * 一旦被继承。相似以下这样的调用时。若传递
     * 进来的參数是其被继承的子类。调用的就是
     * 被重写的方法,这个重写的方法可能会破坏
     * String的不可变特性。
     * @param s
     * @return
     */
    static MyStringLowerCusString(MyString s)//多态
    {
       return s.toLowerCase(s);
    }

    public static void main(String[] args) {
       OverrideStringss = newOverrideString();
       LowerCusString(ss);//传入重写后的字符串类
       LowerUtils.testFinalClass();
    }
}

能够看到LowerCusString方法想要的是MyString对象,可是其子类能够传递进来使用,调用之后发现传递进来的对象s的内容被改动了,表现出和父类不同的行为!!

同样地。应用程序能够编写新的String类,改动hasCode方法,让内容同样的String对象返回的hashCode不同,这样HashMap在使用String类型变量作为Key的时候,发现同样内容的Key居然哈希到不同的位置。

除了实现方法不可改动这个原因。将String修饰为final另一个优点就是效率。

String其他特性

除了上面讲的不可变性。String还其具备以下特性:

特性1:编译时和执行时差别

u  编译时能确定的String对象都放入常量池

u  执行时才干确定或者new出的String对象都放入堆

特性2:hasCode唯一性

两个内容同样的String对象hashCode返回值一定同样

以下通过一个样例总结一下这两个特性:

final String tmp = "ji"; //常量池、编译时确定
String tmp2 = "ji"; //常量池、编译时确定
String s1 = "jiyiqin"; //常量池、编译时确定

String s2 = "jiyiqin"; //常量池、编译时确定
String s3 = "ji" + "yiqin"; //常量池、编译时确定
String s4 = tmp + "yiqin";  //常量池、编译时确定(final一旦初始化就不可变)
String s5 = tmp2 + "yiqin";//堆、执行时确定
String s6 = new String("jiyiqin");//堆、执行时确定

System.out.println(s1.hashCode());
System.out.println(s2.hashCode());
System.out.println(s3.hashCode());
System.out.println(s4.hashCode());
System.out.println(s5.hashCode());
System.out.println(s6.hashCode()); //所有同样

System.out.println(s1 == s2); //true。指向常量池中同样内存
System.out.println(s1 == s3); //true,指向常量池中同样内存
System.out.println(s1 == s4); //true,指向常量池中同样内存
System.out.println(s1 == s5); //false,一个指向堆一个指向常量池
System.out.println(s1 == s6); //false,一个指向堆一个指向常量池
System.out.println(s5 == s6); //false,指向堆中不同内存区域

Double、Long、Integer

对于String的不可变性(包含内容不可变和实现方式不可变),以及hashCode唯一性,Double、Long、Integer也是一样的。

不同的是它们没有执行时和编译时的差别,都是在堆上分配内存。

时间: 2024-11-28 15:28:32

Java基础:String不可变性和final修饰的相关文章

Java基础String的方法

Java基础String的方法 字符串类型写法格式如下: 格式一: String 变量名称; 变量名称=赋值(自定义或传入的变量值); 格式二: String 变量名称=赋值(自定义或传入的变量值);在输出时任何数据类型与字符串进行拼接,结果一般是字符串 1 public class StringFunc { 2 3 public static void main(String[] args){ 4 //字符串拼接 5 String str1; 6 str1 = "hello"; 7

不惑JAVA之JAVA基础 - String

本文适合有一定java基础的同学.本博客宗旨:突出重点,分析难点. String的本质 先看一下String源码 public final class String implements java.io.Serializable, Comparable<String>, CharSequence { /** The value is used for character storage. */ private final char value[]; /** Cache the hash cod

Java基础-String、StringBuffer、StringBuilder

看下面这段代码: public class Main { public static void main(String[] args) { String string = ""; for(int i=0;i<10000;i++){ string += "hello"; } } } 这句 string += "hello";的过程相当于将原有的string变量指向的对象内容取出与"hello"作字符串相加操作再存进另一个新

Java基础——String

前言 从去年八月末开始工作一年了,有了大半年的java开发经验,自认为比在大学时候编码能力强了很多,但是基础方面叫不准的地方感觉越来越多了 (:′д`)ゞ 所以,我准备把这些问题以及工作中遇到的问题总结,记录下来,造福自己和大家~ヾ(o?ω?)?   当然,如果大家发现我哪里写的有错误,欢迎在下方评论指出来. 那我们开始吧! String 1.String是一个final类,不能被继承 2.String底层维护是一个数组,静态创造一个字符串时,此字符串存在于String池,当下一个String对

java基础4:深入理解final关键字

本文主要介绍了final关键字的使用方法及原理 具体代码在我的GitHub中可以找到 https://github.com/h2pl/MyTech 文章首发于我的个人博客: https://h2pl.github.io/2018/04/23/javase4 final关键字可以修饰类.方法和引用. 修饰类,该类不能被继承.并且这个类的对象在堆中分配内存后地址不可变. 修饰方法,方法不能被子类重写. 修饰引用,引用无法改变,对于基本类型,无法修改值,对于引用,虽然不能修改地址值,但是可以对指向对象

Java基础知识强化98:final、finally、finally区别

1. final修饰符(关键字)     如果一个类被声明为final,意味着它不能再派生出新的子类,不能作为父类被继承.因此,一个类不能既被声明为abstract,又被声明为final.     将变量或方法声明为final,可以保证它们在使用中不被改变.其初始化可以在两个地方: 一是其定义处,也就是说,在final变量定义时直接给赋值: 二是在构造函数中.这两个地方只能选其一,要么在定义时给值,要么在构造函数中给值,不能同时既在定义时给了值,又在构造函数中给另外的值,而在以后的引用中只能读取

一、图解Java中String不可变性

这里有一堆例子来说明Java的String的不可变性. 1.声明一个String String s = "abcd"; s 变量保存string对象的引用,下面的箭头解释成保存了哪个对象的引用. 2. 给一个String 变量赋值为另外一个String 变量. String s2 = s; String对象不可变展示2变量s2 保存这相同引用的值,它们都指向了同一对象的值. 3.连接String s = s.concat("ef"); 变量s 现在保存的是新创建的s

黑马程序员----java基础--String字符串

------Java培训.Android培训.iOS培训..Net培训.期待与您交流! ------- 一.String类概述 java中用String类进行描述对字符串进行了对象的封装.这样的好处是可以对字符串这种常见数据进行方便的操作.对象封装后,可以定义N多属性和行为. String类是final的,也就是说它没有子类. 二.String字符串的特点 1.字符串一旦被初始化就不可以被改变.并且存放在方法区中的常量池中. 1 class StringDemo{ 2 public static

黑马程序员-java基础-String类

1.概述 String 类适用于描述字符串事务.提供了多种对字符串进行操作的方法. > 字符串的最大的特点:一旦被初始化就不能被改变. 2.常见的操作方法: 2.1 获取: 1 public class StringText1 { 2 public static void main(String srgs[]) 3 { 4 // str 是一个类类型变量,"abc"是一个对象. 5 String str = "hello java!" ; 6 // str 和