在java中使用Upcasting有什么需要?

我已经浏览了网上的大部分论文,但我仍然无法理解,为什么我们必须使用upcasting。

class Animal { public void callme() { System.out.println("In callme of Animal"); } } class Dog extends Animal { public void callme() { System.out.println("In callme of Dog"); } public void callme2() { System.out.println("In callme2 of Dog"); } } public class UseAnimlas { public static void main (String [] args) { Dog d = new Dog(); Animal a = (Animal)d; d.callme(); a.callme(); ((Dog) a).callme2(); } } 

您可以将此示例视为向上转换。 在这里使用向上转换有什么用? da给出相同的输出!

在大多数情况下,明确的上传完全没有必要,也没有效果。

在您的示例中,显式向上转发

  Animal a = (Animal)d; 

可以用这个代替:

  Animal a = d; // implicit upcast 

隐式upcast(对于Java对象类型)的目的是“忘记”静态类型信息,以便具有特定类型的对象可以在需要更通用类型的情况下使用。 这会影响编译时类型检查,而不会影响运行时行为。

(对于基本类型,upcast会导致转换,并且在某些情况下会导致精度损失;例如long – > float 。)


但是,在某些情况下,显式upcast的存在会改变语句/表达式的含义。

需要在Java中使用upcasting的一种情况是当你想强制使用特定的方法覆盖时; 例如,假设我们有重载方法:

 public void doIt(Object o)... public void doIt(String s)... 

如果我有一个字符串,我想调用第一个重载而不是第二个,我必须这样做:

 String arg = ... doIt((Object) arg); 

相关案例是:

 doIt((Object) null); 

如果没有类型转换,代码将无法编译。 (我不确定这是否算作上传,但无论如何都是这样。)

第二种情况涉及varadic参数:

 public void doIt(Object... args)... Object[] foo = ... doIt(foo); // passes foo as the argument array doIt((Object) foo); // passes new Object[]{foo} as the argument array. 

第三种情况是对原始数字类型执行操作; 例如

 int i1 = ... int i2 = ... long res = i1 + i2; // 32 bit signed arithmetic ... might overflow long res2 = ((long) i1) + i2; // 64 bit signed arithmetic ... won't overflow 

在java中使用Upcasting有什么需要?

不确定你是否有正确的术语,但这里是一个澄清的引用 :

上溯造型
从派生类转换为更通用的基类。

这是一个实际问题的场景:

 class A { } class B extends A { } public class Test { static void method(A a) { System.out.println("Method A"); } static void method(B b) { System.out.println("Method B"); } public static void main(String[] args) { B b = new B(); method(b); // "Method B" // upcasting a B into an A: method((A) b); // "Method A" } } 

当你有重载方法并且不想调用专用方法时,可能需要向上转换,就像aioobe写的那样。 (你可以在那里分配一个类型A的新变量。)

另一个需要upcast的例子涉及?:运算符,但我现在不记得了。 有时你需要在varargs-methods的情况下进行upcast:

 public void doSomething(Object... bla) {} 

如果我们想要将Object[] array作为单个参数传递(而不是将其作为单个参数),我们必须编写

 doSomething((Object)array); 

要么

 doSomething(new Object[]{array}); 

上传在你的例子中绝对没有意义(实际上我无法想象它有任何情况),应该避免,因为它只会让开发人员感到困惑。 一些IDE(肯定是IntelliJ)会在此行发出警告并建议删除向上转发)。

编辑:此代码给出相同的结果,因为Java中的所有对象方法都是虚拟的,这意味着目标方法是在运行时由对象的实际类型而不是引用类型发现的。 尝试使callme()静态,看看会发生什么。

考虑一个场景,Bank是一个提供获取利率的方法的类。 但是,根据银行的不同,利率可能会有所不同。 例如,SBI,ICICI和AXIS银行提供8.4%,7.3%和9.7%的利率。

 class Bank{ float getRateOfInterest(){return 0;} } class SBI extends Bank{ float getRateOfInterest(){return 8.4f;} } class ICICI extends Bank{ float getRateOfInterest(){return 7.3f;} } class AXIS extends Bank{ float getRateOfInterest(){return 9.7f;} } class TestPolymorphism{ public static void main(String args[]){ Bank b; b=new SBI(); System.out.println("SBI Rate of Interest: "+b.getRateOfInterest()); b=new ICICI(); System.out.println("ICICI Rate of Interest: "+b.getRateOfInterest()); b=new AXIS(); System.out.println("AXIS Rate of Interest: "+b.getRateOfInterest()); } } 

输出:

 SBI Rate of Interest: 8.4 ICICI Rate of Interest: 7.3 AXIS Rate of Interest: 9.7 

鉴于Java的对象方法默认是虚拟的,我根本看不到任何用于向上转换的用法。

您在哪里看到教程报告有必要进行向上转换? 这是我第一次听到它的Java。 (注意它在C#或C ++中有意义 – 但它通常是糟糕设计的标志。)

一些答案:

  • 只要将特定对象传递给接受更通用对象的方法,就会隐式发生向上转换。 在您的示例中,当您将Dog传递给接受Animal的方法时,会发生向上转换,尽管您没有使用括号明确地执行此操作。
  • 正如其他人在这里所提到的,在方法重载方案中,您有一般和特定的方法。 在您的示例中,想象一个接受Dog的方法,以及另一个接受Animal的同名的方法。 如果由于某种原因需要调用通用版本,则需要明确地转换对象。
  • 明确的上传可以用作文件的一种forms; 如果你的代码中的某些时候你不再需要将Dog称为Dog,而是继续将其视为Animal,那么让其他开发人员了解正在发生的事情可能是一个好主意。

在这个例子中,我们创建了两个类Bike和Splendar。 Splendar类扩展了Bike类并覆盖了其run()方法。 我们通过Parent类的引用变量调用run方法。 由于它引用子类对象和子类方法会覆盖Parent类方法,因此在运行时调用子类方法。

由于方法调用由JVM而非编译器确定,因此称为运行时多态。

 class Bike{ void run(){System.out.println("running");} } class Splender extends Bike{ void run(){System.out.println("running safely with 60km");} public static void main(String args[]){ Bike b = new Splender();//upcasting b.run(); } } 

对上流的简单解释是……

有两个类,一个是父类(Demo1),第二个是它的子类(Demo)。

  1. 如果方法run1没有参数,那么方法的输出将是相同的。 没有使用Upcasting。

      class Demo1{ void run1(){ System.out.println("hello"); } } class Demo extends Demo1 { void run1(){ System.out.println("hello1"); } public static void main(String args[]){ Demo d = new Demo(); d.run1(); Demo1 d1 = new Demo(); d1.run1(); } } 

    d.run1()的输出;d1.run1(); 会是一样的。

      output: hello1 
    1. 如果我们使用参数化重载,则可以清楚地看到使用向上转换 。 有向上倾向的感觉。

        class Demo1{ void run1(int a){ System.out.println(a); } } class Demo extends Demo1 { void run1(String b){ System.out.println(b); } public static void main(String args[]){ Demo d = new Demo(); d.run1("b"); Demo1 d1 = new Demo(); d1.run1(2); } } 

d.run1()的输出;d1.run1(); 将是不同的。

 output: b 2