从 Java 中的基类访问子类字段

Posted

技术标签:

【中文标题】从 Java 中的基类访问子类字段【英文标题】:Access subclass fields from a base class in Java 【发布时间】:2011-05-29 13:53:19 【问题描述】:

我有一个名为 Geometry 的基类,其中存在一个子类 Sphere

public class Geometry 

 String shape_name;
 String material;

 public Geometry()
 
     System.out.println("New geometric object created.");
 

和一个子类:

public class Sphere extends Geometry

 Vector3d center;
 double radius;

 public Sphere(Vector3d coords, double radius, String sphere_name, String material)
 
  this.center = coords;
  this.radius = radius;
  super.shape_name = sphere_name;
  super.material = material;
 

我有一个包含所有 Geometry 对象的 ArrayList,我想对其进行迭代以检查是否正确读取了来自文本文件的数据。到目前为止,这是我的迭代器方法:

public static void check()
 
  Iterator<Geometry> e = objects.iterator();
  while (e.hasNext())
  
   Geometry g = (Geometry) e.next();
   if (g instanceof Sphere)
   
    System.out.println(g.shape_name);
    System.out.println(g.material);
   
  
 

我如何访问和打印出 Sphere 的 半径和中心场? 在此先感谢:)

【问题讨论】:

这与***.com/questions/2701182/… 非常相似。这能回答你的问题吗? 基类了解子类数据的需要指出您的抽象可能不正确。您应该退后一步,问问自己检查在做什么,是否需要在对象模型外部的实用程序类的基础、子或可能的方法上。 另外,您不需要“超级”。子类中的任何地方,因为它们继承了字段。 【参考方案1】:

你必须cast(特别是downcast):

((Sphere) g).radius

【讨论】:

【参考方案2】:

使用 instanceof 和 Cast 到所需的子类。您可能希望将这些字段公开或使用 getter 和 setter 的私有字段的标准习惯用法。

【讨论】:

【参考方案3】:

如果您想访问子类的属性,您将不得不强制转换为子类。

if (g instanceof Sphere)

    Sphere s = (Sphere) g;
    System.out.println(s.radius);
    ....

不过,这并不是最面向对象的处理方式:一旦您拥有更多的 Geometry 子类,您将需要开始对每种类型进行强制转换,这很快就会变得一团糟。如果要打印对象的属性,您应该在 Geometry 对象上有一个名为 print() 的方法或类似的方法,它将打印对象中的每个属性。像这样的:


class Geometry 
   ...
   public void print() 
      System.out.println(shape_name);
      System.out.println(material);
   


class Shape extends Geometry 
   ...
   public void print() 
      System.out.println(radius);
      System.out.println(center);
      super.print();
   

这样,您无需进行强制转换,只需在 while 循环中调用 g.print()。

【讨论】:

【参考方案4】:

我同意 rwhat,但不是实现您自己的 print() 函数,而是通过覆盖 toString() 函数来避免向下转换,这可能会使您受益(并且更加面向对象)。

public class Geometry 

 String shape_name;
 String material;

 public Geometry()
 
     System.out.println("New geometric object created.");
 

 public String toString() 
      StringBuilder result = new StringBuilder();
      result.append("Shape name: " + shape_name + "\t");
      result.append("Material: " + material + "\t");
      return result.toString();
 
 public static void check (Geometry[] gList) 
     for (Geometry g: gList) 
         System.out.println(g.toString());
     
 

注意check() 不关心 g 是球体还是立方体。这将有助于最大限度地减少对instanceof 的调用。 在球体上...

public class Sphere extends Geometry
 
  Vector3d center;
  double radius;

  public Sphere(Vector3d coords, double radius, String sphere_name, String material)
  
   this.center = coords;
   this.radius = radius;
   shape_name = sphere_name;
   super.material = material;
  
  public String toString() 
      StringBuilder result = new StringBuilder();
      result.append("Radius: " + radius + "\t");
      result.append("Center: " + center.toString() + "\t");
      result.append(super.toString());
      return result.toString();
  
 

具有 toString() 函数的任何新形状(例如圆锥)都会受益,但缺少它只会打印出 Geometry 的版本。

【讨论】:

以上是关于从 Java 中的基类访问子类字段的主要内容,如果未能解决你的问题,请参考以下文章

C++ VS代码爆红:不允许对不可访问的基类进行转换(子类继承父类时必须加上继承属性,比如public)

C++ VS代码爆红:不允许对不可访问的基类进行转换(子类继承父类时必须加上继承属性,比如public)

C# 包含继承类的基类数组,访问非继承字段

属性类型与访问器类型不匹配(子类化时)

从 Typescript 中的基类创建子类的新实例 [重复]

从子类中的基类添加构造函数