class A
{
public static void main(String [] args)
{
String a="my";
String b="my";
System.out.println(a==b);//此处.输出true;我不明白,String为引用类型啊?
//如果借用c++的思想来说:a,b分别为一个一级指针.a代表内存中的一个地址,同样
//b也代表内存中的一个地址,此时怎么会相等呢?应当输出false才对啊?
}
}
{
public static void main(String [] args)
{
String a="my";
String b="my";
System.out.println(a==b);//此处.输出true;我不明白,String为引用类型啊?
//如果借用c++的思想来说:a,b分别为一个一级指针.a代表内存中的一个地址,同样
//b也代表内存中的一个地址,此时怎么会相等呢?应当输出false才对啊?
}
}
可能是为了提高效率吧,字符串有个常量池,在编译的时候就确定了
比如上面的代码常量池中会有一个字符串常量,其内容是"my",而2个引用a和b都是指向此常量,因此是相同的
String b = new String("my");这样才是定义了2个不同的地址呢String a="my";
String b="my";这个就是同一个地址
是值的比较
String b="my";没有通过new 关键字,而new是java中本质上分配内存所必须的,故第一个赋值是查找内存,没找到"my",它会自己new一个,第二次一样的道理,却查到了一摸一样的,就指向它了,但如果还有第三个,却用了new,那就会分配内存初始化一个独立的"my"。还有,String a;a是一个指向String类型对象的引用。所以,我们通常说a是String类型的,起始我们说的是a是一个指向String类型对象的引用。
a,b本来都是指向"my",就是同一地址
String b="my";这个就是同一个地址
是值的比较
上面是引用楼上的朋友的回答.想问一下.
如果像上面那样声明:
可否这样理解呢:a代表一个内存地址假如是:0xF1,b代表一个内存地址:0xF2
a==b;您的意思是说:不是0xF1和0xF2比较而是my和my比较;
那么你有没有想过下面这种情况呢:如下:
String a="abc";
String a="bcd";
a==a此时的比较是内存地址的比较,还是abc=bcd的比较?
String b="my";怎么和C++的思想完全不一样了呢?
变量a a的内存地址为:0xf1 指向my;
变量b b的内存地址为:0xf2 指向my;(;暂时不讨论两个my是否是在同一个地址下)
想问一下,a==b的比较在java当中到底是自己本身地址的比较,不是指向地址的比较?
String s= "Hello";
s = s + "world!"; s所指向的对象是否改变了呢?从本系列第一篇的结论很容易导出这个结论。我们来看看发生了什么事情。在这段代码中,s原先指向一个String对象,内容是"Hello",然后我们对s进行了+操作,那么s所指向的那个对象是否发生了改变呢?答案是没有。这时,s不指向原来那个对象了,而指向了另一个String对象,内容为"Helloworld!",原来那个对象还存在于内存之中,只是s这个引用变量不再指向它了。 通过上面的说明,我们很容易导出另一个结论,如果经常对字符串进行各种各样的修改,或者说,不可预见的修改,那么使用String来代表字符串的话会引起很大的内存开销。因为String对象建立之后不能再改变,所以对于每一个不同的字符串,都需要一个String对象来表示。这时,应该考虑使用StringBuffer类,它允许修改,而不是每个不同的字符串都要生成一个新的对象。并且,这两种类的对象转换十分容易。 同时,我们还可以知道,如果要使用内容相同的字符串,不必每次都new一个String。例如我们要在构造器中对一个名叫s的String引用变量进行初始化,把它设置为初始值,应当这样做: Code:
public class Demo{
private Strings;
...
public Demo{
s="Initialvalue";
}
...
}
而非
s=new String("Initialvalue");
后者每次都会调用构造器,生成新对象,性能低下且内存开销大,并且没有意义,因为String对象不可改变,所以对于内容相同的字符串,只要一个String对象来表示就可以了。也就说,多次调用上面的构造器创建多个对象,他们的String类型属性s都指向同一个对象。 上面的结论还基于这样一个事实:对于字符串常量,如果内容相同,Java认为它们代表同一个String对象。而用关键字new调用构造器,总是会创建一个新的对象,无论内容是否相同。 至于为什么要把String类设计成不可变类,是它的用途决定的。其实不只String,很多Java标准类库中的类都是不可变的。在开发一个系统的时候,我们有时候也需要设计不可变类,来传递一组相关的值,这也是面向对象思想的体现。不可变类有一些优点,比如因为它的对象是只读的,所以多线程并发访问也不会有任何问题。当然也有一些缺点,比如每个不同的状态都要一个对象来代表,可能会造成性能上的问题。所以Java标准类库还提供了一个可变版本,即StringBuffer。
String a = new String("abc");
String b = "abc";
System.out.println(a==b);
}
输出是false。我看了楼上一位的话了,String b = "abc";是在编译时作为常量池写入的,故实际b的那个"abc",在a的那个"abc"出生之前就已经出生了,只是比较慢进入内存里而已,看来我理解中的内存查找是错的,应该是编译期查找了。
你后面还说“按照这个理论,用=进行赋值效率是很低的,还不如new来得快?”,new的作用是初始化,即调用构造器,赋值指的是将一个对象的内存引用地址告诉另一个引用,和初始化是两个过程。我猜你问的是常量赋值吧,即="ss";或=(int)12;对复杂对象的不用考虑,对基本数据类型的不需要考虑(因为它们是栈存储,不是对象的堆存储),特例其实只有String这样的,它跟基础数据类型关系密切,可以作为常量池变量。类对象初始化过程中,它们作为常量池先被初始化,基础数据类型到栈离去,String到堆里去,而象new String("abc")这样的,在常量初始化之后才开始初始化,而且在内存中,不查找之前是否已存在了这样的对象,我再说一遍,是在编译期查找,不然java就慢死了。以下归纳了几句,new是唯一的初始化过程,它让构造器执行了。
赋值是赋引用的过程,仅仅是把一个引用的值改成另一个,指向了另一个对象。
to longyuxinxinxin:java中不会对同一变量两次声明,所以你的
String a="abc";
String a="bcd";
是
String a="abc";
a="bcd";
意思吧,如果不是,那编译就限制它通不过了,不讨论。如果是,
a是一个引用,它的值指向内存中的对象地址,故a被赋值是它引用的值指向了其他对象的地址。
a==a,比较的是它引用的值。
public class Equivalence{
public static void main(String args[]){
Integer n1=new Integer(47);
Integer n2=new Integer(47);
System.out.println(n1==n2);
System.out.println(n1!=n2);
}
}
//先false后true. 是比较对象的引用而不是对象的内容
public class EqualsMethod1{
public static void main(String args[]){
Integer n1=new Integer(47);
Integer n2=new Integer(47);
System.out.println(n1.equals(n2));
}
}//true. 是比较对象的内容而不是对象的引用class Value{
int i;
}public class EqualsMethod{
public static void main(String args[]){
Value v1=new Value();
Value v2=new Value();
v1.i=v2.i=100;
System.out.println(v1.equals(v2));
}
}//false 缺省行为是比较引用,要么在新类里复写