假设您有一个Shape
基类和各种派生类型:Circle
等。
通过写这个:
,在制作新物品时是否有任何理由在那里进行向上翻转Shape s = new Circle();
而不是:
Circle s = new Circle();
并且这两个语句中的每一个所做的s
对象是否以任何方式彼此不同?
答案 0 :(得分:3)
就JVM而言,这两个语句将产生相同的对象。显示您只计划将对象用于基类或接口并不罕见。例如。这很常见:
List<String> list = new ArrayList<String>();
虽然通常不是一个好主意,但如果您确定它是一个Shape
,则可以将Circle
投回Shape s
,例如使用Circle c
,您可以将其带回if (s instanceof Circle) {
Circle c = (Circle) s;
// handle Circle case
}
:
{{1}}
答案 1 :(得分:3)
你可以说你的第一个例子(即Shape s = new Circle();
)可以具有与“编码到界面”相同的优点,即使Shape可能是抽象的甚至是具体的基类。因此,例如,如果您只使用Shape上定义的方法而不是Circle特有的方法,那么您可以很容易地将您正在使用的实现更改为Square,例如只需更改一行代码,即{{1 }}
两个示例中的对象都是相同的,第一个选项可以被认为更好的原因更多的是样式事物。对接口进行编码可以使代码库更容易扩展和修改。
答案 2 :(得分:1)
实例化的对象完全相同。
向上转播的后果是:
答案 3 :(得分:1)
在回答你的问题时,这两个对象完全相同。两个引用都可以指向同一个对象:
Circle c = new Circle();
Shape s = c;
编码到接口允许您更改实现类,而对代码的影响最小。说你有这个:
Set<String> names = new HashSet<String>(); // using Set reference not HashSet
names.add("Frank");
names.add("John");
names.add("Larry");
for(String name: names) {
System.out.println(name + " is in the team");
}
现在您的需求发生了变化,您希望按字母顺序打印名称,即使用HashSet而不是TreeSet。因为您已编码到接口而未使用任何特定于HashSet类的方法,所以您只需更改一行:
Set<String> names = new TreeSet<String>(); // the only line of code that changes
names.add("Frank");
names.add("John");
names.add("Larry");
for(String name: names) {
System.out.println(name + " is in the team");
}
接口还允许您使用依赖注入。它允许您使用在编写代码时可能不存在的类。
答案 4 :(得分:0)
不,对象本身并没有什么不同。只有编译器认为他所看到的是不同的(例如,哪些方法可用)。
进行此类演员的一个原因是表达您希望如何对待对象(以便您可以轻松地插入不同的派生类)。
答案 5 :(得分:0)
我同意@WhiteFang34所说的话。
见Coding to interfaces? 这可能会对你有所帮助。
答案 6 :(得分:-2)
Circle s = new Circle();
这里的对象是指圆圈
Shape s = new Circle(); 这里反对它引用接口
两者都是一样的。