第 13 章 常用类(1)

目录

包装类 

 包装类和基本数据的转换

 练习题

 包装类型和 String 类型的相互转换

包装类(Integer)->String

String -> 包装类(Integer)

 Integer 类和 Character 类的常用方法

 练习题

 String 类

String 类的理解和创建对象

创建 String 对象的两种方式

"=="和 equals 方法究竟有什么区别?

先说”==”

再来看”equals”

练习题

字符串的特性

练习题:

题目一:

题目二:

课外习题

题目三:

​题目四:


包装类 

=====================================================================

String类并不是基本数据类,而是一个类(class),是C++、java等编程语言中的字符串。
String类是不可变的,对String类的任何改变,都是返回一个新的String类对象。 String 对象是 System.Char 对象的有序集合,用于表示字符串。String 对象的值是该有序集合的内容,并且该值是不可变的。这里的值是指地址。(后面可以讲到)
而java的8大基本数据类型分别是:
逻辑类 boolean
文本类 char
整数类 byte, short, int, long
浮点类 double, float。

在 Java 中,除了有 8 种基础类型,还有引用类型。

引用类型一般情况下统称有 3 类。分别是: 类、接口、数组。

不过也可以说, 除了基础类型外,其余的都是引用类型。

在 Java 的引用类型有点类似 C 和 C++ 的指针概念。引用类型是一种对象类型,它的值是指向内存空间中的引用。 对应的是引用的地址。

并且在 8 种基础类型上又为每种基本类型提供了对应的封装类型。

=====================================================================

1) 针对八种基本数据类型相应的引用类型--------包装类。

2) 有了类的特点,就可以调用类中的方法。

 怎么打开Boolean的类图?

我们可以看到这两个包装类的继承关系,绿色虚线表示实现,蓝色的实线表示继承。

 

剩下五个包装类的类图怎么看?

我们看了类图应该清楚地知道,这五个包装类继承了Number类,而且实现了Comparable接口。

 包装类和基本数据的转换

 

 或者

 

  手动拆箱

自动装箱和拆箱

 

 

 

 练习题

Object obj1 = true? new Integer(1):new Double(2.0);

System.out.println(obj1)

//试问输出结果是什么?

答:1.0 
三元运算符要看做一个整体,
因为Double的存在,会提升优先级,
所以输入的是1.0,而不是1。

 包装类型和 String 类型的相互转换

包装类(Integer)->String

public class WrapperVSString {
    public static void main(String[] args) {
        //包装类(Integer)->String
        Integer i = 100;//自动装箱

        //方式1
        String str1 = i + "";
        //方式2
        String str2 = i.toString();
        //方式3
        String str3 = String.valueOf(i);
}

String -> 包装类(Integer)

 

 Integer 类和 Character 类的常用方法

 练习题

第一题:

public class WrapperExercise02 {
    public static void main(String[] args) {
        Integer i = new Integer(1);
        Integer j = new Integer(1);
        System.out.println(i == j);  
      }
  }

 

第二题:

public class WrapperExercise02 {
    public static void main(String[] args) {
      
        Integer m = 1; //底层 Integer.valueOf(1);
        Integer n = 1;//底层 Integer.valueOf(1);
        System.out.println(m == n); 
        
        }
}

 继续解释上面这个源码:IntegerCache是一个数组,里面存放这从-128到127这256个数,如果我们传进去的数字为128,那它就重新new一个, 但是如果传进去的数字在-128到127之间,那么就是直接返回对应的数字,比如传入的i是-126, 那么返回的数就是数组下标为-126+(-(-128))的数,然后数组里面下标为2的正是-126。

第三题:

public class WrapperExercise02 {
    public static void main(String[] args) {

        //所以,这里主要是看范围 -128 ~ 127 就是直接返回
        //,否则,就new Integer(xx);
        Integer x = 128;//底层Integer.valueOf(1);
        Integer y = 128;//底层Integer.valueOf(1);
        System.out.println(x == y);

    }
}

 第四题:

public class WrapperExercise03 {
    public static void main(String[] args) {
        //示例一
        Integer i1 = new Integer(127);
        Integer i2 = new Integer(127);
        System.out.println(i1 == i2);//F
//示例二
        Integer i3 = new Integer(128);
        Integer i4 = new Integer(128);
        System.out.println(i3 == i4);//F

//示例三
        Integer i5 = 127;//底层Integer.valueOf(127)
        Integer i6 = 127;//-128~127
        System.out.println(i5 == i6); //T
//示例四
        Integer i7 = 128;
        Integer i8 = 128;
        System.out.println(i7 == i8);//F
//示例五
        Integer i9 = 127; //Integer.valueOf(127)
        Integer i10 = new Integer(127);
        System.out.println(i9 == i10);//F
      }
}

第五题:

public class WrapperExercise03 {
    public static void main(String[] args) {

     //示例六
        Integer i11=127;
        int i12=127;
     //只有有基本数据类型,判断的是 值是否相同,127等于127,对的
        System.out.println(i11==i12); //T
      //示例七
        Integer i13=128; 
        int i14=128;
        System.out.println(i13==i14);//T
        
    }
}

int是基本数据类型,判断是是值相同。

只有有基本数据类型,判断的是 值是否相同。

 String 类

String 类的理解和创建对象

1.String 对象用于保存字符串,也就是一组字符序列
String name = "jack";
2. "jack" 字符串常量, 双引号括起的字符序列,name是变量。
3. 字符串的字符使用Unicode字符编码,一个字符(不区分字母还是汉字)占两个字节
4. String 类有很多构造器,构造器的重载
   常用的有 String  s1 = new String();
   String  s2 = new String(String original);
   String  s3 = new String(char[] a);
   String  s4 =  new String(char[] a,int startIndex,int count)
   String s5 = new String(byte[] b)
5. String 类实现了接口 Serializable (String 可以串行化,也就是说它的对象可以在网络传输)
                 接口 Comparable (String 对象可以比较大小)
6. String 是final 类,不能被其他的类继承

=====================================================================

难点来了

7. String 有属性 private final char value[]; 用于存放字符串内容

String name = "jack";
我们保存字符串jack其实保存到了的value[]这个数组里面,所以字符串的本质就是char数组。

 8.这个value[]是final类型,final类型其实就是个常量,一旦被赋值了,以后不能被改变,不是里面的字符不可修改,而是它的地址不可修改。

比如你的value本来指向的是tom这一块地址空间,你不可以让value再指向Jack另一块

地址空间 (你相当于把value指向另一个对象,那这个value[]数组对象对象就变了,因为地址变化了),但你Tom中的字母m换成字母H是可以的,因为value[]数组的的地址没有改变。

下面用一段代码演示一下第八条

总结:final会约束我们这个value这个数组不要去指向其他的数据空间,我们可以修改value这个数组里面的内容。 但是我们不能value数组指向一个新的地址空间。

===================================================================

从上面第七点和第八点我们得出:

String name = "jack";
name = "tom";

我们的jack和tom存放在value[]数组里面的,开始我们的name指向了jack,然后name不可能再去指向tom,因为value[]数组前面带final,那我们的name怎么指向的Tom,很显然,这不是一个name,会重新创建一次字符串对象name,然后第二句等价于:

String name = "tom";

所以一共创建了两次对象,第一次name指向jack,第二次name就指向tom。

创建 String 对象的两种方式

 

 最终这两种方式创建的是两个不同的对象,他们地址不一样,一个是0x11,一个是0x99

总结:

"=="和 equals 方法究竟有什么区别?

先说”==”

1.对于基本数据类型 (byte,short,char,int,long,float,double,boolean)的变量,”==”比较的是两个变量的值是否相等。比如:int a = 3; int b = 3; a==b;返回就是true。

2.对于引用类型如,则比较的是该变量所指向的地址.

拿我们最常用的String型来举例:

比如:String a = “abc”; String b = “abc”;

在这种情况下 字符串直接赋值给变量,该字符串会进入到常量池中,当第一次将 “abc”赋值给a的时候,会去常量池中找看有没有”abc”这个字符串,如果有的话,就将a指向该字符串在常量池中的地址,如果没有则在常量池中创建,第二次赋值 将 “abc”赋值给b的时候同样去常量池中找”abc”这个字符串,然后将他的地址赋值给b。

所以我们在做 a==b操作的时候返回的为true。

再来看另一种情况:String a = new String(“abc”) ; String b = new String(“abc”);

这种情况下我们在做 a==b操作的时候返回的为false。

当我们使用 String a = new String(“abc”)创建一个字符串对象时在内存里面是这样分配空间的,首先会去常量池中找”abc”,如果找到了再创建一个”abc”对象存到堆中,并且他的值指向堆中的”abc”,如果没有找到,则先在常量池中创建”abc”,再在堆内存开辟一块内存空间创建”abc”,并且他的值指向堆中的”abc”。

再来看”equals”

Equals方法是在Object类中定义的,所有的类都继承于Object类,所以所有的类都有equals方法。

可以看到在Object类的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;
        }

从源码我们可以看出,在String的equals方法中对字符串的字符进行了逐一比较如果都相同则返回true。所以对于String中的equals方法比较的是两个字符串的内容对于:

String a = new String(“abc”) ; String b = new String(“abc”);

由于a和b的内容相同,返回true。

最后:

1. 对于字符串的比较“==”比较的是两个字符串的地址。

2. 对于字符串的比较 “equals”比较的是两个字符串的内容。

练习题

第一题:

public class StringExercise03 {
    public static void main(String[] args) {
        String a = "hsp"; //a 指向 常量池的 “hsp”
        String b =new String("hsp");//b 指向堆中对象
        System.out.println(a.equals(b));
        //T  因为equals比较的是字符串的内容
        System.out.println(a==b);
        //F  因为“==”比较的是两个字符串的地址

第二题:

  

 第三题:

 

 第四题:

这个equals方法我们点进去,就到了string类的源码里面,我们发现,它这个方法还是比较字符串的内容,如果内容一样就返回true 。

public class StringExercise05 {
    public static void main(String[] args) {
        Person p1 = new Person();
        p1.name = "hspedu";
        Person p2 = new Person();
        p2.name = "hspedu";

        System.out.println(p1.name.equals(p2.name));//比较内容: True
        System.out.println(p1.name == p2.name);  //T
        System.out.println(p1.name == "hspedu");   //T

        String s1 = new String("bcde");
        String s2 = new String("bcde");
        System.out.println(s1==s2); //False

    }
}
class Person {
    public String name;
}

 

 分别讲解:

1.第一个true: 内容一样,返回true.

2.第一个true: name在堆里,name都指向常量池里的同一个地址,所以返回true.

3.第一个true:  "hspedu"  这个字符串常量放在常量池里面的,它返回的地址和p1.name返回的地址相同,所以返回的是true。

4.第四个false,因为是s1和s2返回堆中的地址不同,所以返回false。

字符串的特性

 

 当我们执行到s1= "haha",它会在常量池里找有没有haha这个常量。如果有,就指向它,如果没有,就在常量池中创建haha这个字符串常量对象,然后s1指向haha,s1就不指向hello这个字符串常量对象了。

练习题:

题目一:

 题目二:

下面我们通过代码调试看一下

 

 

 我们现在还是不明白我们的字符串hello去了哪里,执行什么操作。

接着追踪

看到这里我们明白了,str.getChars(0, len, value, count); 它是想把我们的hello复制到value数组,然后这里0就是hello的第0个索引,len就是要复制的字符串中最后一个字符之后的索引(这里就是这样规定的,要想知道为什么,需要向下追踪,这里我们不追踪了),这样hello复制到value数组了。

====================================================================

针对getChars方法我们下面练习一下

public class StringExercise08 {
    public static void main(String[] args) {
        String a = "hello"; //创建 a对象
        char[] value =new char[10];
        int  count = 0;
       int len= a.length();
        a.getChars(0, len, value, count);
        //如果0,就是从hello的索引为0的字母开始开始存
        //这里改为1,就是从hello的索引为1的字母开始开始存,这样h就存不进去了
        //value是要存放的目标数组
        // len就是要复制的字符串中最后一个字符的后面一个的索引(规定这样的)
        System.out.println(value);

        count =len +count;
        //这个count是目标数组中的起始存放索引
        //这里是5,就是说我们的字符串ren从数组的5号索引开始存放
        //就是字母r存放在value数组中索引为5的位置
        String d =  "ren";
        int len1= d.length();
        d.getChars(0, len1, value, count);
        System.out.println(value);
    }
}

 

 ====================================================================

 接着我们继续追踪

 

 

 现在我们总结一下这个题目

a,b肯定创建对象了。
再分析String c= a+b;
1. 先创建一个对象 StringBuilder sb = new StringBuilder()
2. 执行  sb.append("hello");
3. sb.append("abc");
4. String c= sb.toString()
最后其实是 c 指向堆中的对象(String)value[],(String) value[]指向常量池中 "helloabc"

老韩说一共创建三个对象(a,b,c),我认为是这是在代码最外层是三个对象,但是如果考虑源码里面那创建的对象更多了,比如这个题目还是一个答案就是创建了五个对象,另外两个 new   StringBuilder()这个对象,还有常量池中 "helloabc"这个对象。(欢迎指正)

 

 再延伸一点,看看这个题:

=====================================================================

课外习题

关于创建几个对象的课外习题(不想看就跳过)

1、String str = “hello”;
创建了一个对象
jvm在编译阶段会判断常量池中是否有“hello”这个常量对象,如果有,str就直接指向这个常量的引用,如果没有就会在常量池中创建这个对象。
2、String str = new String(“hello”);
创建了两个对象
jvm编译阶段会判断常量池中是否有“hello”这个常量对象,进而判断是否创建常量对象,然后运行阶段通过new关键字在java 堆上开辟一块儿空间来创建String 对象。常量池中一个,堆中一个。还有一种说法就创建了一个对象 new String(“hello”)(欢迎指正)
3、String str = “hello” + “world”;
创建了一个对象
jvm编译阶段通过编译器优化后,会把字符串常量直接合并成“helloworld”,所以在常量池中只创建了一个对象。还有一种说法就创建了三个对象,常量池里的“hello” ,“world”,“helloworld”(欢迎指正)
4、String str = “hello” + new String(“world”);
创建了五个对象
常量池对象"hello",“world”,new String(“world”)创建堆对象,还有一个堆对象“helloworld”,还有一个StringBuilder对象。还有一种说法就创建了两个对象,常量池里的“hello” ,new String(“world”)(欢迎指正)

5.

String s1 = new String("ab");

String s2 = new String("ab");

s1 == s2  //false;

一共创建了三个对象,首先在堆中new了两个对象,常量池中先有了ab",s2不需要再创建,所以是三个,常量池中一个,堆中两个。还有一种说法就创建了两个对象,s1的new String(“ab”),s2的new String(“ab”)(欢迎指正)

6、

String s3 = "ab";

String s4 ="ab";

一个对象,常量池中只有一个"ab"

7、

String s5 = "ab"+"cd";

三个对象:常量池中有:ab,cd,abcd。还有一种说法就创建了一个对象,常量池里的“helloworld”(欢迎指正)

--------------------------------------------

创建了几个对象?

-----------------------------------------

1.

String s1 = "ab"+"cd";

-----------------------------------------

2.

String s1 ="ab" ;

String s2 ="cd" ;

String s3 =s1+s2;

-----------------------------------------

3.

String s1=new String("ab") +new String("cd");

-----------------------------------------

4.

String s1 ="ab" ;

String s2=s1 +"cd"; 

-----------------------------------------

5.

String s1="ab";

String s2=s1 +new String("cd");

-----------------------------------------

6.

String s2="ab" +new String("cd");

-----------------------------------------

=====================================================================

题目三:

 题目四:

 图看不懂直接看下面视频

0470_韩顺平Java_String对象特性2_哔哩哔哩_bilibili

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值