我之所以选择这个标题,是因为我注意到我对抽象课程的设置做错了,但我还不太确定。
我为训练目的创建了MoveAble抽象类,并从中创建了Ball类。我还为moveAble类创建了一个GetPosition()方法,并从ball类中使用它。 但是当我在任何球对象上调用GetPosition()时,我获得了Moveable Abstract对象的位置变量。
我猜测它是这样的,但是根据我的理解,无论如何我们都不能使用抽象类,所以即使我实现了,我也需要能够获得子类的位置值这种方法只适用于父母班。
注意:我是初学java程序员。可能有更好的方法来做我所做的事情,但这就是我的结果。我想听听你们对它的看法,如果你认为它都是歪曲的,并且有更好的方法可以解决所有这些问题,我很乐意学习它。
可移动的课程:
public abstract class MoveAble {
private int[] position = new int[2];
private int[] velocity = { 1, 1 };
public int[] getPosition() {
return position;
}
public abstract void move(int width, int height) ;
球类:
public class Ball extends MoveAble{
private int[] position = new int[2];
private int[] velocity = { 1, 1 };
public Ball(int x_position, int y_position) {
position[0] = x_position;
position[1] = y_position;
}
@Override
public void move(int width, int height) {
if (position[0] > width - 30 || position[0] < 1) {
velocity[0] *= -1;
}
if (position[1] > height - 30 || position[1] < 1) {
velocity[1] *= -1;
}
position[0] += velocity[0];
position[1] += velocity[1];
}
答案 0 :(得分:5)
position
内的velocity
MoveAble
和Ball
position
。如hid the fields,您无需隐藏案例中的字段。从velocity
中删除字段Ball
和Ball
,您应该很高兴。
至于为什么该程序执行的操作的原因:即使您隐藏public int[] getPosition()
中的字段,方法MoveAble
也来自MoveAble
和在MoveAble
内,MoveAble
(以及来自其超类的字段)的字段可见。
最后一点:{{1}}比抽象类更满足接口的条件。 rodit pointed out
答案 1 :(得分:1)
问题是您(重新)在类position
中定义了一个不同的velocity
和Ball
字段,它从Ball和子类中覆盖了从同一个名称继承的字段。班MoveAble
。
从班级posiition
中删除velocity
和Ball
字段。将字段的访问权限更改为基类protected
中的MoveAble
,或者提供受保护的方法以允许子类访问该数据。
答案 2 :(得分:1)
你可以使用抽象类型的引用。 (您只能实例化一个抽象类。)当您调用他们的方法时,运行时行为是他们指向的底层具体对象的行为。
抽象类可以在方法中提供默认行为(如果已知)。我的猜测是你的抽象类提供了你的Ball
子类完全可以接受的行为。
这就是多态性的全部意义所在。面向对象编程有四个重要特征:抽象数据类型,封装,多态和继承。确保你彻底理解它们。
我认为你的错误是给抽象和具体类提供相同的成员变量。那里的重用在哪里?从Ball
中删除它们并在父级中对它们进行保护。除非他们提供不同的行为,否则不要覆盖孩子的方法。
答案 3 :(得分:1)
你可以创建一个名为IMovable的接口,这样当你只关心动产时,你可以通过它的界面引用这个对象......
现在,如果您有多个子类型的公共代码,您可以创建一个Abstract类并在move中调用其基类代码,如下所示,然后在子类型中添加子类型特定的移动逻辑...请参阅下文
public class Ball extends AbstractBall {
public Ball(int x_position, int y_position) {
super(x_position, y_position);
}
public void move(int width, int height) {
super.move(width, height);
System.out.println("SUBTYPE-CLASS MOVE IS CALLED");
}
public static void main(String[] args) {
Ball ball = new Ball(10, 20);
ball.move(1, 2);
}
}
abstract class AbstractBall implements IMovable {
protected int[] position = new int[2];
protected int[] velocity = { 1, 1 };
public AbstractBall(int x_position, int y_position) {
position[0] = x_position;
position[1] = y_position;
}
public void move(int width, int height) {
System.out.println("BASE-CLASS MOVE IS CALLED");
if (position[0] > width - 30 || position[0] < 1) {
velocity[0] *= -1;
}
if (position[1] > height - 30 || position[1] < 1) {
velocity[1] *= -1;
}
position[0] += velocity[0];
position[1] += velocity[1];
}
}
interface IMovable {
public void move(int width, int height);
}
通过其界面引用实例的另一个好处是,eclipse自动完成功能将仅将其项目列表限制为接口方法。
将此与当您引用同一对象但通过其继承层次结构时在自动完成中显示的方法的爆炸性进行比较。
哪一个更有意义?
import javax.swing.JButton;
public class Demo {
public static void main(String[] args) {
IPrintable instance1 = new PrintableButton();
instance1.print();
PrintableButton instance2 = new PrintableButton();
instance2.print();
}
}
interface IPrintable {
public void print();
}
class PrintableButton extends JButton implements IPrintable {
private static final long serialVersionUID = 1L;
@Override
public void print() {
System.out.println("Printable Button");
}
}