我试图将一个Object转换为一个类实例。类实例的Object当然应该继承所有方法。
所以这是我在示例代码(2)中遇到的问题,因为我无法准确解释我的意思:
Class Fish {}
Class Dog {}
class Instances() {
private Fish fish = new Fish();
private Dog dog = new Dog();
public Object getInstance(String className) {
if( className.equals("fish") )
return fish;
else
return dog;
}
}
class test() {
Instances in = new Instances();
public static void main(String[] args) {
// 1: works (transmits all the methods of fish)
Fish fish = (Fish)in.getInstance("fish");
// 2: doesn't work (fishObj only has access to the methods of an object and can't access the methods of Fish!)
Object fishObj = null;
fishObj = (Fish)in.getInstance("fish");
}
}
提前谢谢!
答案 0 :(得分:1)
当您为变量指定对象引用时,您对引用变量执行的任何其他操作都将限制为为其类型定义的操作。
因此,您可以将Fish
分配给Object
变量。但只要您使用Object
变量,就只能使用Object
中定义的方法,例如toString()
,hashCode()
等。
但是你在评论中注意到你想在两个类中运行类似的方法。我认为这意味着您的Dog
和Fish
类的方法具有相似的名称,参数和返回类型,例如getLegCount()
会为4
返回Dog
和0
Fish
。
当出现这种情况时,您必须将两个类型声明为另一个类的子类,它具有所需的方法:
public abstract class Animal {
public abstract int getLegCount();
}
class Fish extends Animal {
@Override
public int getLegCount() {
return 0;
}
}
然后,getInstance()
的返回类型应为Animal
,而不是Object
。然后将结果放在Animal
变量中,然后您可以使用getLegCount()
方法。
另一个选择是将所需的常用方法定义为接口。它的工作方式相同,如果预期的Animal
类型中没有实现细节,只有方法定义,那么它更可取:
public interface Animal {
int getLegCount();
}
class Fish implements Animal {
@Override
public int getLegCount() {
return 0;
}
}
同样,您可以将getInstance
的返回类型声明为Animal
,将变量声明为Animal
而不是Object
。
答案 1 :(得分:1)
java编译器会阻止您使用除fishObj
以外的Object
上的任何方法,因为您声明变量fishObj
属于Object
类型。编译器无法预测该变量在运行时实际将被引用的对象类型,因此它遵循声明。
当然,你和我可以弄清楚fishObj
在调用方法的时候会持有对Fish
的引用,但是通常不可能解决这些问题,并且Java编译器不会尝试。
你的演员没有做任何事。它通知编译器表达式的值实际上是Fish
,但是然后将该值赋给类型为Object
的变量,并且在编译器如何查看该变量方面没有任何变化。 (如果#getInstance
实际上返回的内容不是Fish
,那么您的演员阵容的唯一可能影响就是,在这种情况下,您将在运行时获得ClassCastException
。)
您可以使用Java的反射类来获取通过变量声明的类型无法访问的对象的方法。 E.g:
fishObj.getClass().getMethod("swim").invoke(fishObj);
答案 2 :(得分:1)
让我们来看看你的一些代码:
Object fishObj = null;
fishObj = (Fish)in.getInstance("fish");
那么为什么可以将类Fish的Object分配给数据类型为Object的变量? 在Java中,每个类都派生自Object类,因此Object是每个类的超类。我们可以将子类的对象分配给超类的变量。这就是你在这里做的事情。
fishObj = (Fish)in.getInstance("fish");
将类Fish的Object分配给变量fishObj。这是可能的,因为Fish扩展了Object(即使你没有明确地注明它)。 所以我们可以说fishObj有静态类型Object(在这种情况下是一般数据类型),动态类型Fish(分配给变量的Object)。
静态类型定义可访问的方法,而动态类型定义方法的行为方式。
现在是什么意思?让我们来看看Oracle Documentation for the class Object。 我们可以看到它有各种方法,如hashCode()或equals()。如果静态类型是Object,则可以调用所有这些方法,因为每个子类都需要具有这些方法。所以无论发生什么,呼叫都不会失败。
假设您的类Fish有方法swim()并再次查看一些代码。
Object fishObj = new Fish();
那么静态是什么,这里的动态类型是什么? 对象将是静态类型,再次捕获动态类型。 现在我们不打算做以下的电话。
fishObj.swim(); //won't work
为什么会这样?静态类型Object的类没有名为swim()的方法。所以我们不能肯定地说我们可以分配给变量fishObj的每个Object肯定会实现mehtod swim()。
总结我们可以说,由于你的静态类型是Object,所以类Fish的特定方法对你是隐藏的,以确保对赋予Variable fishObj的Object的调用始终有效。
答案 3 :(得分:0)
Object fishObj = null; fishObj = (Fish)in.getInstance("fish");
对象被转换为Fish with(Fish),但是当你的引用是一个Object引用时,它会被扩展回Object,因此这些是你看到的唯一方法。
答案 4 :(得分:0)
((Fish)fishObj ).printFish();
首先,您的Instances in = new Instances(); 应该是静态的,因为你在静态变量中使用它
您已将Fish对象分配给基本的java对象
答案 5 :(得分:0)
这称为运行时多态或动态方法调度是在运行时而不是编译时解析对重写方法的调用的过程。 More