2013-10-21 27 views
0

就像问题所述。理想情况下,答案应该是错误的,因为它将使用仅仅是参考比较的Object#相等。为什么等于不使用铸造等号方法?

String cat = new String("cat"); 
    String cat2 = new String("cat"); 

    System.out.println(((Object) cat).equals((Object) cat2)); // returns true, but should be false 

这与多态性有关;我知道如何equals()和实习工作。

相关主题:铸造GRAPHICS - >的Graphics2D

上述场景是上溯造型其中字符串是被downcasted到对象的情况。

然而,这是一个常见的用途实际上向下转换GraphicsGraphics2D使用升级版或没有在显卡本身存在的新方法。我们怎么能够上传而不是沮丧。

import java.awt.*; 
import javax.swing.*; 

    public class Example extends JPanel { 
     public static void main (String []args){ 
     JFrame frame = new JFrame(); 
    } 
    public void paintComponent(Graphics g){ 
     Graphics2D g2 = (Graphics2D) g;    // How can we be sure the informal 
     g2.drawLine(0,0, getWidth(), getHeight()); // parameter contains those methods? 
    } 
} 
+0

你为什么说“...是一个上传的情况下,字符串被降频为对象”?这是一个错字吗?无论如何,你*无法确定''g''''' Graphics2D'没有测试它,或准备好'ClassCastException'。 Java仍将调用最具体的方法,而不管你称之为参考。 –

回答

3

你投catObject,但catString实例不会改变的事实。 Java执行dynamic binding(又名后期绑定),这意味着方法调用在运行时基于对象是实例的类来解析。在这种情况下,这仍然是String,这意味着将使用String#equals()而不是Object#equals()。事实上,您将cat2转换为Object几乎没有什么区别 - equals()无论如何都需要一个Object的说法。

这里有一个简单的方法来证实这一点:

String s = "abc"; 
Object o = (Object) s; // we don't really need an explicit cast 

System.out.println(s.getClass()); 
System.out.println(o.getClass()); 
 
class java.lang.String 
class java.lang.String 

同样的原理是在这里工作。 o类型为Object,但它是String实例,因此StringgetClass()被调用。


考虑下面的类结构:

class A { 
    public void foo() { 
     System.out.println("A foo"); 
    } 
} 

class B extends A { 
    public void foo() { 
     System.out.println("B foo"); 
    } 

    public void bar() { 
     System.out.println("B bar"); 
    } 
} 

现在,当我们有一些像

A b = new B(); 
b.foo(); 

然后Bfoo方法将被调用。这是上述现象。你问这样的:

A b = new B(); 
b.bar(); // error 

我们这里有一个错误的原因是因为没有保证b将有一个bar()方法。对于我们所知道的(或者说,编译器知道),b可能是一个带有who-knows-what的C实例。出于这个原因,我们必须进行显式转换:

A b = new B(); 
((B) b).bar();  

这是从一个事实,即Java的是静态类型的(即使它结合执行动态)。

+0

在这种情况下,为什么我们可以使用'((Graphics2D)g).drawLine(...)'...来使用Graphics2D中的升级方法。上溯造型。 – bluejamesbond

+0

@ mk2在这种情况下'g'可能是用一个没有'drawLine()'方法的超类型声明的。 –

+0

@ mk1所以我们可以访问超类中没有定义的方法。 – arshajii

0

这不是Java如何解决应该使用哪种方法。即使您在运行时将其转换为Object,也会使用String的equals。和String的equals不检查引用的相等性,但如果字符串是“逻辑上”相等的。

这是由于所谓的“动态链接”,你可以谷歌或尝试阅读关于它here.

1

由于所有的方法都是默认虚拟在Java所以即使你键入它铸造于Object,它会调用Stringequals方法,因为对象是StringObject类型。

这也称为后期绑定或运行时多态性。

+0

+1 ... :) –

+0

@JoshM你的观点碰巧是我的1000分。将永远是特别的。谢谢。 – Trying

2

实例方法在运行时根据其动态类型进行解析。 这是多态性/后期绑定。无论将对象投射到静态类型Object,它的运行时类型仍为String,因此将使用String#equals(Object)

我们怎么能够上传而不是沮丧。

鉴于两类

public class A { 

} 

public class B extends A { 
    public void doSomething() {} 
} 

A a = new B(); 
a.doSomething(); // this won't compile because A doesn't declare a doSomething() method 
((B) a).doSomething(); // this is fine because you are now calling the method on the static type B 
// you might get a ClassCastException here if the runtime type of a wasn't B 
+0

但在'paintComponent'的情况下,我们收到Graphics not Graphics2D的副本。我们如何确认给定的参数实际上具有该方法? – bluejamesbond

+1

@ mk1在投射前,你应该检查参数是否是'instanceof Graphics2D'。 –

-1

String对象是不可改变的对象之一,有些人喜欢整数。

所以这里是一个简单的比较,你创建了2个Integer对象(相同的值)并做相同的操作。返回2个整数是平等的更有意义。

从示例中,我猜你现在可能知道不可变类的目标:它们被设计为保留它们的状态并简化与它们相关的操作,就像int一样。