Java 访问数组中子类的字段
我在Java中测试继承,我有一个带有两个字段的抽象类和三个带有自己字段的扩展类。在另一个类中,我实例化并在数组中添加该类的对象,但我不确定如何访问子类的字段,该数组是主抽象类: 以下是抽象类和扩展类之一的完整代码:Java 访问数组中子类的字段,java,arrays,object,foreach,iterator,Java,Arrays,Object,Foreach,Iterator,我在Java中测试继承,我有一个带有两个字段的抽象类和三个带有自己字段的扩展类。在另一个类中,我实例化并在数组中添加该类的对象,但我不确定如何访问子类的字段,该数组是主抽象类: 以下是抽象类和扩展类之一的完整代码: public abstract class MusicRecord { private String type; private int length; public MusicRecord(String type, int length){ t
public abstract class MusicRecord {
private String type;
private int length;
public MusicRecord(String type, int length){
this.type = type;
this.length = length;
}
public String getType(){
return type;
}
public int getLength(){
return length;
}
public void setType(String type){
this.type = type;
}
public void setLength(int length){
this.length = length;
}
}
如何从子类中获取字段
通过访问子类的字段,数组是主要的抽象类:
java类型系统是协变的。(除了在泛型中,方差是可选择的,并且默认情况下,不变的)。对于本答案的其余部分,您需要了解:
- Integer扩展了java.lang.Number
- Double扩展了java.lang.Number
- java.lang.Number扩展了java.lang.Object
Integer
的表达式,并在需要数字的地方使用它:当需要超类型时,任何子类型都可以。(不变性意味着只有特定类型的数字表达式才可以,反之亦然:如果需要整数,数字或对象也可以)
因此:
一切都好
这也意味着,如果你把它翻过来,如果一个表达式是Number类型的,那么它很可能是Number的某个子类型。鉴于这个数字是抽象的,这实际上是一种保证!数字本身不可能存在,只能存在其子类的实例
您可以使用instanceof和casting以及模式匹配来处理此问题:
注意:这使用了java15中引入的新java特性
Object[] x = new Object[2];
x[0] = "hello";
if (x[0] instanceof String y) {
y.toLowerCase();
}
这里我们首先检查x[0]
是否为字符串(可能是。也可能是整数,也可能是FileInputStream,也可能是com.sun.internal.impl.HttpRequestImpl$1
——协方差意味着实际的事物类型可能是,通常是一些内部细节,这些细节无法保证,并且可以在java版本和实现之间更改).如果它是一个字符串,那么对于所有只有在它是字符串时才能访问的代码(这里是If块的内部),y
作为变量存在,并且包含对完全相同的对象的引用,但这次是作为字符串键入的,因此您可以自由调用它上的字符串方法,例如.toLowerCase()
如果您尚未使用JDK15,“旧”方法是:
if (x[0] instanceof String) {
String y = (String) x[0];
y.toLowerCase();
}
这就是所谓的cast操作符,它只是一个类型断言:如果x[0]
确实是一个字符串,那么这段代码什么也不做。这就像你写的(String y=x[0];
),除了不会编译之外,效果是一样的:y现在指向同一个东西x[0]
指出,cast只告诉编译器您知道这是断言类型,并添加运行时测试)
另一方面,如果x[0]
没有指向某个j.l.String实例,则该行将抛出ClassCastException
因此,您可以执行以下操作:
int totalPrice = 0;
for (MusicRecord mr : records) {
if (mr instanceof CD cd) totalPrice += cd.price;
}
注意:用java编写的正确方法是Cd
,而不是Cd
。当然,按照惯例,java规范允许您编写任何您想要的东西。但是,如果您希望您的代码与库交互良好,并可供其他java代码编写者阅读,那么遵循既定惯例是一个好主意,这些惯例规定您必须全部使用这些东西,即使是缩写词,在普通写作中,都是以大写形式呈现的。DvdPlayer,而不是DvdPlayer。Cd,而不是Cd。当你使用它时,直接字段访问按惯例是不好的-改为制作getter。应该是Cd.getPrice()
多亏了Lino、Rzwitserroot和Federico klez Culloca,我才能够通过以下补充解决这个问题
for(MusicRecord r : mr){
if(r instanceof CD){
System.out.println("Type: " + r.getType() + "\nLength: " + r.getLength() + "\nTitle: " + ((CD)r).getTitle() + "\nPrice: " + ((CD)r).getPrice() + "\n ***************");
} else if (r instanceof SD){
System.out.println("Type: " + r.getType() + "\nLength: " + r.getLength() + "\nTitle: " + ((SD)r).getTitle() + "\nPrice: " + ((SD)r).getPrice() + "\n ***************");
} else {
System.out.println("Type: " + r.getType() + "\nLength: " + r.getLength() + "\nTitle: " + ((BlueRay)r).getTitle() + "\nPrice: " + ((BlueRay)r).getPrice() + "\n ***************");
}
为什么你想从子类中获取字段?我不太明白你想要实现什么。你想使用多态性来打印每个子类的特定内容->创建一个被覆盖的方法。你只是想专门访问字段->使用instanceof
和castsIf,如果你想调用>getPrice
在声明为MusicRecord
但在运行时实际上是CD
的对象上,您必须强制转换它,如((CD)r).getPrice()
,但我想知道为什么MusicRecord
本身没有一个getPrice
方法作为开始。而且这看起来像是子类的滥用。因为每个子类看起来都一样,即具有相同的字段。->MusicRecord
应该是一个具体的类,并且您应该能够提供一个类型,例如enum R生态类型{CD,SD,BLUE_-RAY}
您自己,在创建recordhi实例时,这只是一个测试,我想知道是否有办法访问添加到给定数组中的子类中的对象字段。子类将有自己的字段,这些字段与其他子类的字段不匹配。我已将它们命名为相同的字段,但假设t嘿,是不同的。casting会给我一个错误,但我已经用instanceof的if语句解决了这个问题。再次,rzwitserloot,这实际上回答了我的问题,我正在阅读我能找到的所有文档,但是没有详细的解释来指出你发布的这些详细信息。所以谢谢你,我记住你的帮助关于命名约定也有很多建议。
if (x[0] instanceof String) {
String y = (String) x[0];
y.toLowerCase();
}
int totalPrice = 0;
for (MusicRecord mr : records) {
if (mr instanceof CD cd) totalPrice += cd.price;
}
for(MusicRecord r : mr){
if(r instanceof CD){
System.out.println("Type: " + r.getType() + "\nLength: " + r.getLength() + "\nTitle: " + ((CD)r).getTitle() + "\nPrice: " + ((CD)r).getPrice() + "\n ***************");
} else if (r instanceof SD){
System.out.println("Type: " + r.getType() + "\nLength: " + r.getLength() + "\nTitle: " + ((SD)r).getTitle() + "\nPrice: " + ((SD)r).getPrice() + "\n ***************");
} else {
System.out.println("Type: " + r.getType() + "\nLength: " + r.getLength() + "\nTitle: " + ((BlueRay)r).getTitle() + "\nPrice: " + ((BlueRay)r).getPrice() + "\n ***************");
}