zoukankan      html  css  js  c++  java
  • java基础知识系列---字符串

    Java字符串类(java.lang.String)是Java中使用最多的类,也是最为特殊的一个类。

    String 类相关基础认知:

    1、String类是final的,不可被继承。public final class String。
    2、String类是的本质是字符数组char[], 并且其值不可改变。private final char value[];
    然后打开String类的API文档,可以发现:
    3、String类对象有个特殊的创建的方式,就是直接指定比如String x = "abc","abc"就表示一个字符串对象。而x是"abc"对象的地址,也叫做"abc"对象的引用。
    4、String对象可以通过“+”串联。串联后会生成新的字符串。也可以通过concat()来串联。
    5、创建字符串的方式很多,归纳起来有三类:
      其一,使用new关键字创建字符串,比如String s1 = new String("abc");
      其二,直接指定。比如String s2 = "abc";
      其三,使用串联生成新的字符串。比如String s3 = "ab" + "c";
    6、Java运行时会维护一个String Pool(String池),JavaDoc翻译很模糊“字符串缓冲区”。String池用来存放运行时中产生的各种字符串,并且池中的字符串的内容不重复。而一般对象不存在这个缓冲池,并且创建的对象仅仅存在于方法的堆栈区

    对象创建

    字符串对象创建的原理

    原理1:当使用任何方式来创建一个字符串对象s时,Java运行时(运行中JVM)会拿着这个X在String池中找是否存在内容相同的字符串对象,如果不存在,则在池中创建一个字符串s,否则,不在池中添加。

    原理2:Java中,只要使用new关键字来创建对象,则一定会(在堆区或栈区)创建一个新的对象。

    原理3:使用直接指定或者使用纯字符串串联来创建String对象,则仅仅会检查维护String池中的字符串,池中没有就在池中创建一个,有则罢了!但绝不会在堆栈区再去创建该String对象。

    原理4:使用包含变量的表达式来创建String对象,则不仅会检查维护String池,而且还会在堆栈区创建一个String对象。

    另外,String的intern()方法是一个本地方法,定义为public native String intern();

    intern()方法的价值在于让开发者能将注意力集中到String池上。当调用 intern 方法时,如果池已经包含一个等于此 String 对象的字符串(该对象由 equals(Object) 方法确定),则返回池中的字符串。

    否则,将此 String 对象添加到池中,并且返回此 String 对象的引用。

    字符串中的方法(待补充)

    1.equals方法

    和equals经常作为对比的是==,简单区别就是equils比较对象的值, == 用于比较引用和比较基本数据类型时具有不同的功能:
         a:比较基本数据类型,如果两个值相同,则结果为true
         b:比较引用时,如果引用指向内存中的同一对象,结果为true)

     public  boolean equals(Object obj)

    public boolean equals(Object obj) {
        return (this == obj);
    }

       其比较规则为:当参数obj引用的对象与当前对象为同一个对象时,就返回true,否则返回false.

       equals()方法的本意为确定两个对象的引用是否相同。

     注:在String中equals()方法被进行了覆盖,使其意义变为比较两个对象的内容是否一致。String中的equals是平时开发中最经常用到的,源码如下:

    public boolean equals(Object anObject) {
            if (this == anObject) {
                return true;
            }
            if (anObject instanceof String) {
                String anotherString = (String) anObject;
                int n = value.length;
                if (n == anotherString.value.length) {
                    char v1[] = value;
                    char v2[] = anotherString.value;
                    int i = 0;
                    while (n-- != 0) {
                        if (v1[i] != v2[i])
                                return false;
                        i++;
                    }
                    return true;
                }
            }
            return false;
        }

    2.hashCode方法

    public native int hashCode();
    根据这个方法的声明可知,该方法返回一个int类型的数值,并且是本地方法,因此在Object类中并没有给出具体的实现。
    作用:
    对于包含容器类型的程序设计语言来说,基本上都会涉及到hashCode。在Java中也一样,hashCode方法的主要作用是为了配合基于散列的集合一起正常运行,这样的散列集合包括HashSet、HashMap以及HashTable。
    为什么这么说呢?考虑一种情况,当向集合中插入对象时,如何判别在集合中是否已经存在该对象了?(注意:集合中不允许重复的元素存在)

     也许大多数人都会想到调用equals方法来逐个进行比较,这个方法确实可行。但是如果集合中已经存在一万条数据或者更多的数据,如果采用equals方法去逐一比较,效率必然是一个问题。此时hashCode方法的作用就体现出来了,当集合要添加新的对象时,先调用这个对象的hashCode方法,得到对应的hashcode值,实际上在HashMap的具体实现中会用一个table保存已经存进去的对象的hashcode值,如果table中没有该hashcode值,它就可以直接存进去,不用再进行任何比较了;如果存在该hashcode值, 就调用它的equals方法与新元素进行比较,相同的话就不存了,不相同就散列其它的地址,所以这里存在一个冲突解决的问题,这样一来实际调用equals方法的次数就大大降低了,说通俗一点:Java中的hashCode方法就是根据一定的规则将与对象相关的信息(比如对象的存储地址,对象的字段等)映射成一个数值,这个数值称作为散列值。下面这段代码是java.util.HashMap的中put方法的具体实现:

    public V put(K key, V value) {
    
            if (key == null)
                return putForNullKey(value);
            int hash = hash(key.hashCode());
            int i = indexFor(hash, table.length);
            for (Entry<K,V> e = table[i]; e != null; e = e.next) {
               Object k;
                if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
                   V oldValue = e.value;
                    e.value = value;
                   e.recordAccess(this);
                   return oldValue;
                }
            }
    
            modCount++;
            addEntry(hash, key, value, i);
            return null;
        }

    put方法是用来向HashMap中添加新的元素,从put方法的具体实现可知,会先调用hashCode方法得到该元素的hashCode值,然后查看table中是否存在该hashCode值,如果存在则调用equals方法重新确定是否存在该元素,如果存在,则更新value值,否则将新的元素添加到HashMap中。从这里可以看出,hashCode方法的存在是为了减少equals方法的调用次数,从而提高程序效率。

    有人会说,可以直接根据hashcode值判断两个对象是否相等吗?肯定是不可以的,因为不同的对象可能会生成相同的hashcode值。虽然不能根据hashcode值判断两个对象是否相等,但是可以直接根据hashcode值判断两个对象不等,如果两个对象的hashcode值不等,则必定是两个不同的对象。如果要判断两个对象是否真正相等,必须通过equals方法。

      也就是说对于两个对象,如果调用equals方法得到的结果为true,则两个对象的hashcode值必定相等;

      如果equals方法得到的结果为false,则两个对象的hashcode值不一定不同;

      如果两个对象的hashcode值不等,则equals方法得到的结果必定为false;

      如果两个对象的hashcode值相等,则equals方法得到的结果未知。

    一般情况下,当我们重写equals时,一般也会去重写hashCode方法。

  • 相关阅读:
    6.Docker中上传镜像到docker hub中
    altermanager使用报错
    Grafana官方和社区提供的dashboard
    什么是 云原生?
    prometheus被OOM杀死
    新版GRANAFA K8S插件 K8S NODE 图表不显示问题解决方法
    python2和python3的不同
    一次使用Python连接数据库生成二维码并安装为windows服务的工作任务
    Python连接oracle
    numpy.ndarray的赋值操作
  • 原文地址:https://www.cnblogs.com/myadmin/p/5126950.html
Copyright © 2011-2022 走看看