我想根据对象的类型执行多个操作,而不使用instanceof
。起初我正在考虑基于类型重载方法(如下所示),并认为Java可能会适当地选择方法(基于最具体的对象类)。
import java.util.ArrayList;
import java.util.List;
public class TestA {
public static void main(String[] args)
{
List<Object> list = new ArrayList();
list.add(new A());
list.add(new B());
list.add(new C());
list.add(new Object());
TestA tester = new TestA();
for(Object o: list)
{
tester.print(o);
}
}
private void print(A o)
{
System.out.println("A");
}
private void print(B o)
{
System.out.println("B");
}
private void print(C o)
{
System.out.println("C");
}
private void print(Object o)
{
System.out.println("Object");
}
}
class A {
}
class B extends A {
}
class C {
}
输出结果为:
Object
Object
Object
Object
然而我所追求的输出是:
A
B
C
Object
instanceof
visitor.accept(this)
中的class A
会导致调用函数visitor.accept(A o)
。instanceof
,因为我读过它是不好的做法;在这种情况下,它仍然是不好的做法吗?答案 0 :(得分:11)
我的答案是让A,B和C类实现一个通用接口。
然后他们每个人都可以拥有自己特定的接口实现。
这样,您可以为所有对象调用相同的方法(从而避免重载方法),并且还可以根据对象的类型确保自定义功能(即从中实例化的类。)
答案 1 :(得分:4)
这个答案认为修改给定的类及其关系不是一种选择。
有没有办法让Java选择最基于的方法 特定类型的参数对象?
Java编译器无法为你强制转换,因为这可能不是你想要的(在你的情况下,这就是你想要的,但也许其他人不想要这种行为,他们也不会解决它们)。由于您将Object
引用传递给print()
,编译器将调用print(Object)
。
如果没有,我可以考虑使用哪些替代功能, 没有instanceof的帮助
您可以将Object
及其类型包装在包装类中,例如:
public class ObjectWrapper {
private final Object object;
private final int type;
}
这样,您可以安全地转换为Object
的类型而不使用instanceof
。虽然这个恕我直言比简单地使用instanceof
更复杂,实际上它只创建了你自己的instanceof
......
我老实说反对instanceof因为我读过它很糟糕 实践;在这种情况下,它仍然是不好的做法吗?
在编程中,没有什么是不好的做法。一切都取决于具体情况。在这种情况下,我认为您可以使用instanceof
并进行不安全的投射,因为设计需要这样做。无论如何,如果语言中存在instanceof
运算符,那是因为它被使用了。如果instanceof
总是是一种不好的做法,那么它就不会作为语言的一部分存在。请参阅this和this。
我实际上是在尝试模拟访问者模式 看来,访客模式的作用是因为双重因素 dispatch,使参数“被接受”是正确的 函数调用期间键入,特别是类中的visitor.accept(this) A导致函数visitor.accept(A o)被调用。
检查我的第二个链接是否使用访客模式。
答案 2 :(得分:3)
方法重载是一个编译时多态,在for
循环中,您已将o
声明为Object
,因此将始终调用print(Object o)。
解决方案: 使用动态多态性:
class A{
void print(){
System.out.println('in A');
}
}
class B{
void print(){
System.out.println('in B');
}
}
和for循环
for(Object o: list){
o.print();
}
答案 3 :(得分:2)
考虑访客设计模式http://en.wikipedia.org/wiki/Visitor_pattern。虽然它需要更改A,B,C,否则没有别的办法。
答案 4 :(得分:1)
我会在这里使用instanceof
。这很简单明了。
不像硬规则不使用instanceof
。没有硬性规则:) instanceof
的大量使用可能表明您可以更改内容以使编译器为您做更多工作。这是否真的值得做,需要逐个查看。在你的情况下,你提到你无法改变有问题的类,所以它甚至都不是一个选项。
答案 5 :(得分:0)
package com.ank.says;
import java.util.ArrayList;
import java.util.List;
class Base{
public void print(){
System.out.println("Base");
}
}
class A extends Base{
@Override
public void print() {
System.out.println("A");
}
}
class B extends Base{
@Override
public void print(){
System.out.println("B");
}
}
class C extends Base{
@Override
public void print(){
System.out.println("C");
}
}
public class TestPlayGround {
public static void main(String[] args) throws ParseException {
List<Base> list = new ArrayList<Base>();
list.add(new A());
list.add(new B());
list.add(new C());
list.add(new Base());
TestPlayGround tester = new TestPlayGround();
for(Base o: list)
{
o.print();
}
}
}
输出: - 一个 乙 C 基
答案 6 :(得分:0)
现在没有使用instanceof就出现了什么:
代码:
public interface YourInterface {
public void doStuff();
}
public class A implements YourInterface {
@Override
public doStuff() {
System.out.print("A");
}
}
public class B implements YourInterface {
@Override
public doStuff() {
System.out.print("A");
}
}
List<YourInterface> list = new ArrayList<YourInterface>();
list.add(new A());
list.add(new B());
for(YourInterface e: list)
{
e.doStuff();
}
代码:
public enum YourEnum {
TYPE1 {
@Override
public void doStuff() {
System.out.print("Type 1");
},
TYPE2 {
@Override
public void doStuff() {
System.out.print("Type 2");
};
public abstract void doStuff();
}
List<YourEnum> list = new ArrayList<YourEnum>();
list.add(YourEnum.TYPE1);
list.add(YourEnum.TYPE2);
for(YourEnum e: list)
{
e.doStuff();
}
答案 7 :(得分:0)
阅读上述答案后
我可以建议的一个解决方案是使用o.getClass
检查对象类型并继续
然而,发布了许多更好的解决方案。我完全同意@krisna kishor shetty所说的话
答案 8 :(得分:0)
从我的观点来看,这不是使用instanceof的问题。问题是如何最大限度地减少这种情况所带来的影响。所以我会推荐实例适配器,以防有多个操作需要处理。这样你至少可以避免在整个系统中传播这种复杂性:
public abstract class Adapter {
public abstract void print();
public static Adapter wrap(Object o) {
if (o instanceof A) {
return new AAdapter();
}
if (o instanceof B) {
return new BAdapter();
}
return new ObjectAdapter():
}
public class AAdapter {
public void print() {
System.out.printLn("A");
}
}
然后循环:
for (Object o: things) {
Adapter.wrap(o).print();
}
当然,我们的Adapter将引用包装对象,如方法名称所示。这样,您就可以获得接近直接修改这些类的编码模型。