Java String创建对象实例解析

2025-05-27 0 46

本文研究的主要是Java String创建对象的问题,具体介绍如下。

首先我们要明白两个概念,引用变量和对象,对象一般通过new在堆中创建,String只是一个引用变量。

所有的字符串都是String对象,由于字符串常量的大量使用,java中为了节省时间,在编译阶段,会把所有字符串常量放在字符串常量池中,字符串常量池的一个好处就是可以把相同的字符串合并,占用一个空间。

虽然在Java中无法直接获取变量的地址,但是可以用==判断一下两个引用变量是否指向了一个地址即一个对象。

栈内存 堆内存
基础类型,对象引用( 堆内存地址 ) 由new 创建的对象和数组
存取速度快 相对于栈内存较慢
数据大小在声明周期必须确定 分配的内存由java 虚拟机自动垃圾回收器管理。动态分配内存大小
共享特性,栈中如果有字符串,则直接引用;如果没有,开辟新的空间存入值 每new一次都在堆内存中生成一个新的对象。不存在任何复用
?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127
package com.demo.test;

import java.lang.reflect.Field;

public class StringDemo {

public static void main(String[] args) {

//先在内存中查找有没有这个字符串对象存在,如果存在就指向这个字符串对象;

String str1 = "abc";

String str2 = "abc";

/*

public String toString() {

return this;

}

*/

String str3 = "abc".toString();

//不论内存中是否已经存在这个字符串对象,都会新建一个对象。

String str4 = new String("abc");

String str5 = new String("abc");

String str6 = str5;

String str7 = "a" + "b" + "c";

String str8 = "a" + "b" + new String("c");

//String是不可变字符串对象,StringBuilder和StringBuffer是可变字符串对象(其内部的字符数组长度可变),StringBuffer线程安全,StringBuilder非线程安全

String str9 = new StringBuilder().append("a").append("b").append("c").toString();

String str10 = new StringBuffer().append("a").append("b").append("c").toString();

System.out.println("--------> ==");

System.out.println("---> 1");

System.out.println(str1==str2);//true

System.out.println("---> 3");

System.out.println(str3==str1);//true

System.out.println("---> 4");

System.out.println(str4==str1);//false

System.out.println(str4==str3);//false

System.out.println(str4==str5);//false

System.out.println(str4==str6);//false

System.out.println("---> 7");

System.out.println(str7==str1);//true

System.out.println(str7==str3);//true

System.out.println(str7==str4);//false

System.out.println("---> 8");

System.out.println(str8==str1);//false

System.out.println(str8==str3);//false

System.out.println(str8==str4);//false

System.out.println(str8==str7);//false

System.out.println("---> 9");

System.out.println(str9==str1);//false

System.out.println(str9==str3);//false

System.out.println(str9==str4);//false

System.out.println(str9==str7);//false

System.out.println(str9==str8);//false

System.out.println("---> 10");

System.out.println(str10==str1);//false

System.out.println(str10==str3);//false

System.out.println(str10==str4);//false

System.out.println(str10==str7);//false

System.out.println(str10==str8);//false

System.out.println(str10==str9);//false

System.out.println("--------> equals");

System.out.println(str1.equals(str4));//true

System.out.println(str1.equals(str7));//true

System.out.println(str1.equals(str8));//true

System.out.println("--------> hashCode");

/*

hashCode计算公式: s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]

因此hashCode都是一样的,而且是每次运行都一样

*/

System.out.println(str1.hashCode());//96354

System.out.println(str2.hashCode());

System.out.println(str3.hashCode());

System.out.println(str4.hashCode());

System.out.println(str5.hashCode());

System.out.println(str6.hashCode());

System.out.println(str7.hashCode());

System.out.println("--------> normal change value");

//String是不可变类,string只是指向堆内存中的引用,存储的是对象在堆中的地址,而非对象本身,给string赋值只是改变其引用对象而非对象本身

str6 = "123";

System.out.println(str5);//abc

System.out.println(str6);//123

System.out.println("--------> reflect change value");

/*

如果非要改变String的值,也不是不可行。只能使用反射了。

public final class String implements java.io.Serializable, Comparable<String>, CharSequence {

// The value is used for character storage.

private final char value[];

……

}

*/

str6 = str5;

try {

Field field = String.class.getDeclaredField("value");

// Field field = str6.getClass().getDeclaredField("value");

if(!field.isAccessible()) {

field.setAccessible(true);

}

char[] value = (char[])field.get(str6);

value[0] = '0';

System.out.println(str5);//0bc

System.out.println(str6);//0bc

} catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {

e.printStackTrace();

}

System.out.println("--------> obj.toString()");

Object obj = new Object();

/*

public String toString() {

return getClass().getName() + "@" + Integer.toHexString(hashCode());

}

*/

System.out.println(obj.toString());//java.lang.Object@15db9742

String[] arr1 = {"0"};

String[] arr2 = {"0"};

System.out.println(arr1.equals(arr2));//false

}

}

总结

  • 如果String指向的是一个字符串常量,那么会先在字符串常量池(栈)中查找,如果有就直接指向它;没有则在字符串常量池中创建该常量,然后String指向该常量。
  • 如果String使用关键字new初始化,则会在堆中开辟固定的空间存放该字符串的值,然后String指向该常量。
  • 使用字符串常量拼接,由于表达式先计算右值,因此相当于将String指向一个新拼接好的字符串常量。同样会在字符串常量池中查找,如果有就直接指向它;没有则在字符串常量池中创建该常量,然后String指向该常量。但是如果拼接中存在使用new生成的字符串,则新的字符串就等价于使用new在堆中创建的一样。
  • 修改String的值,只能改变String的指向,不会改变String指向的对象本身。如果非要改变指向的对象本身,可以使用反射。
  • 如果是数组,由于它是对象,那么equals只比较其数组指针地址,并不会去比较其中的元素是否相等。

以上就是本文关于Java String创建对象实例解析的全部内容,希望对大家有所帮助。感兴趣的朋友可以继续参阅本站其他相关专题,如有不足之处,欢迎留言指出。感谢朋友们对本站的支持!

原文链接:http://blog.csdn.net/chy555chy/article/details/52795984

收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。

快网idc优惠网 建站教程 Java String创建对象实例解析 https://www.kuaiidc.com/76380.html

相关文章

发表评论
暂无评论