我知道常量池的概念和JVM用来处理String文字的String常量池.但我不知道JVM使用哪种类型的内存来存储String常量文字.堆栈还是堆?由于它是一个与任何实例无关的文字,我会认为它将存储在堆栈中.但是如果它没有被任何实例引用,那么必须通过GC运行收集文字(如果我错了,请纠正我),那么如果它存储在堆栈中怎么处理呢?
当以(显然)不正确的方式使用时,哪些类的Java Standard API会导致内存泄漏?如何避免/修复这些内存泄漏?
示例: ObjectInputStream并ObjectOutputStream保留对他们所见过的所有对象的引用,以便发送与引用相同的对象的后续出现而不是副本(从而处理循环引用).当您无限期地保持此类流(例如,当使用它通过网络进行通信时)时,这会导致内存泄漏.
修复:定期或在每个顶级对象之后调用reset().
这个访谈问题的共同商定答案是代码创建了两个对象.但我不这么认为; 我写了一些代码来确认.
public class StringTest {
public static void main(String[] args) {
String s1 = "a";
String s2 = "a";
String s3 = new String("a");
System.out.println("s1: "+s1.hashCode());
System.out.println("s2: "+s2.hashCode());
System.out.println("s3: "+s3.hashCode());
}
}
Run Code Online (Sandbox Code Playgroud)
输出是:

这是否意味着只创建了一个对象?
重申:我的问题是以下代码创建了多少个对象:
String s = new String("xyz")
Run Code Online (Sandbox Code Playgroud)
而不是StringTest代码.
在@Don Branson的启发下,我调试了以下代码:
public class test {
public static void main(String[] args) {
String s = new String("abc");
}
}
Run Code Online (Sandbox Code Playgroud)
结果是:

s的id是84,"abc"的id是82.这究竟是什么意思?
在一个非常简单的HelloWorld应用程序上运行javap时,我对常量池周围的输出有些困惑.
测试代码
public class TestClass {
public static void main(String[] args) {
System.out.println("hello world");
}
}
Run Code Online (Sandbox Code Playgroud)
Javap -c -verbose输出(剪切)
// Header + consts 1..22 snipped
const #22 = String #23; // hello world
const #23 = Asciz hello world;
public static void main(java.lang.String[]);
Signature: ([Ljava/lang/String;)V
Code:
Stack=2, Locals=1, Args_size=1
0: getstatic #16; //Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #22; //String hello world
5: invokevirtual #24; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: return
// Debug info snipped
}
Run Code Online (Sandbox Code Playgroud)
好的,所以在第3行我们看到通过#22将"hello world"常量推送到堆栈上,但const#23似乎保持实际值.我想我对#(数字)在打印输出右侧出现时的含义有点困惑.
Oracle/Sun的javap手册页有很多不足之处.
我正在查看String API,突然我遇到一个String空构造函数,即我们可以使用构造一个空的String对象 String s = new String()
我想知道它有用吗?
正如在本文中所解释的那样,我们应该在字符串常量上使用字符串的实际方法发布字符串文字是自动合并但是对于使用new构造的对象不是,因此使用该实习方法.但即使我们使用实习方法,也会创建一个新对象,那么实习方法的用途是什么?
String s = "Example";
String s1 = new String("Example"); // will create new object
String s2 = new String("Example").intern(); // this will create new object
// but as we are calling intern we will get reference of pooled string "Example"
Run Code Online (Sandbox Code Playgroud)
现在
System.out.println(s == s1); // will return false
System.out.println(s == s2); // will return true
System.out.println(s1 == s2); // will return false
Run Code Online (Sandbox Code Playgroud)
那么实习方法的用途是什么?
编辑
我理解实习生方法的工作,但我的问题是为什么有实习方法?因为要调用intern方法我们必须使用new创建字符串对象,这将创建新的字符串实例!
String s3 = new String("Example"); // again new …Run Code Online (Sandbox Code Playgroud) 使用关键字new创建String时,它使用带有String文字的构造函数创建一个新的String对象.我想知道在调用String构造函数之前文字是否存储在常量池中.
我问的原因是,在"OCA Java SE 7程序员I认证指南"中,Mala Gupta写道:
public static void main(String[] args)
{
String summer = new String("Summer"); //Line 1: The code creates a new String object with the value "Summer". This object is not placed in the String constant pool.
String summer2 = "Summer" //Line 2: The code creates a new String object with the value "Summer" and places it in the String constant pool.
}
Run Code Online (Sandbox Code Playgroud)
她在第一行说,new创建的String对象没有存储在常量池中.这很好,但不清楚的是,如果第一行的构造函数中的文字"Summer"是.
在第二行,她说"Summer"的分配到summer2将它存储在常量池中,这意味着第一行的文字没有放在池中.
我的问题
我听到一位同事说如果我在Java类中删除一个String成员,即使String为空,我也会支付"24字节".那是准确的吗?Integer,Float,Double是一样的吗?(而不是int,float,double,每个只有4,4和8个字节).
在面向对象的语言中,新对象的创建是通过使用new关键字(因为java中的内存分配是动态完成的).
即使String是一个类,如何在没有新关键字的情况下创建其对象?
即使它使用字符串池我也无法清楚地理解它: "可以创建一个用户定义的类,我们可以像String一样直接初始化变量"
这是来自OCJP 6考试的问题,因此故意不完全正确(但合法).
给定代码:
class ToDos {
String day;
public ToDos(String d) {
day = d;
}
public boolean equals(Object o) {
return ((ToDos) o).day == day;
}
public int hashCode() { return 9; }
}
public class MapEQ {
public static void main(String[] args) {
Map<ToDos, String> map = new HashMap<ToDos, String>();
ToDos t1 = new ToDos("Monday");
ToDos t2 = new ToDos("Mond" + "a" + "y");
ToDos t3 = new ToDos("Tuesday");
map.put(t1, "a");
map.put(t2, "b");
map.put(t3, "c");
System.out.println(map.size());
}
} …Run Code Online (Sandbox Code Playgroud) val hello1 = "hello"
val hello2 = "hello"
printf(hello1 === hello2)
Run Code Online (Sandbox Code Playgroud)
为什么打印真实?
我猜kotlin有一个原始类型的池(或类似的东西).如果值是相等的,则指针指向同一个地方.我不确定.
所以我的问题是关于声明和分配字符串.
我通常声明字符串的方式是执行以下操作:
String s1 = "Stackoverflow";
Run Code Online (Sandbox Code Playgroud)
然后,如果我需要更改s1的值,我会执行以下操作:
s1 = "new value";
Run Code Online (Sandbox Code Playgroud)
今天我找到了另一种方法,然后声明一个字符串就像:
String s2 = new String("Stackoverflow");
Run Code Online (Sandbox Code Playgroud)
然后更改值将是:
s2 = new String("new value");
Run Code Online (Sandbox Code Playgroud)
我的问题是两者之间有什么区别,还是只是优惠.从第四行查看代码
s2 = new String ("new value");
Run Code Online (Sandbox Code Playgroud)
我假设这样做会创建一个新的内存位置,然后s2指向它,所以我怀疑它会用于更改值,但我可以看到它在声明字符串时被使用.