“Java编程简介”,说:
要启用通用编程, 定义具有超类型的变量是一种很好的做法,它可以接受任何子类型的值。
代码示例:
Object myObject = new Circle();
... // Some lines of code
System.out.println("The circle diameter is " +
((Circle)myObject) .getDiameter());
... // Some lines of code
为什么不首先将myObject定义为Circle类型?
答案 0 :(得分:2)
让我们用类Fruit
public class Fruit {
public void eat() {
//some code
}
}
另外两个班级
public class Banana extends Fruit{
}
//
public class Apple extends Fruit{
}
现在让我们创建一个人
public class Person {
public void eat(Fruit f) {
f.eat();
}
}
让我们现在使用
public static void main(String[] args) {
Person p = new Person();
// We are creating a random Fruit, and pass it to the person to eat.
// We can´t be more specific here and don´t need to be more specific
Fruit f = getRandomFruit();
p.eat(f);
}
public static Fruit getRandomFruit() {
if(new Random().nextInt(2) == 0) {
return new Banana();
} else {
return new Apple();
}
}
答案 1 :(得分:1)
我认为在这种情况下,这个例子弊大于利。要执行任何Circle
或Shape
相关操作,您需要投射当前对象。除了增加潜在开销之外,这可能会导致诸如不兼容类型之类的问题。
通常建议进行泛型编程,因为它允许您的代码灵活。 与您发布的示例不同,建议仅在完成时才建议。将所有内容创建为对象几乎总是弊大于利。
以List
为例,如果您在哪里找到一个返回ArrayList<String>
的方法:public ArrayList<String> foo()
,那么,您将被绑定到该特定类型。如果您想要一个链表,您可能需要编写某种转换器,从LinkedList<String>
创建一个ArrayList<String>
。
另一方面,如果您使用通用界面,您的方法将变为如此:public List<String> foo()
。这将允许曾经消费foo
的人能够创建任何一个实现List
接口的数据结构,而无需通过箍。
ObjectInputStream
提供的readObject()
方法。当您正在阅读ObjectInputStream
不知道的自定义对象时,将使用此方法。因为在Java中,所有内容都扩展了Object
类,所以此方法会生成一个对象。即便如此,我所看到的这种方法的每个插图最终都会将其转化为其他内容。
答案 2 :(得分:1)
如果你稍微修改一下这个例子,从Circle
而不是从Square
派生RectAngle
,Shape
,Shape
,这将是有道理的。 getArea()
可以使用Shape circle = new Circle();
Shape rectangle = new Rectagle();
等方法以及高度和宽度等属性,这些属性可以被派生类覆盖。
methods
在现实生活中的示例中,最好为派生类使用Base泛型类型,以便实现可以在运行时更改。
如果您正在寻找对象创建,请使用简单的Factory。
如果您希望在运行时更改对象的行为,请使用Strategy_pattern。
如果您正在制定多种功能策略,则可以通过将基础更改为新的派生策略来动态替换策略。
看看下面的例子:
Design Patterns: Factory vs Factory method vs Abstract Factory