我正在学习java概念。 我对java继承概念有疑问。 在继承中,我们可以将子类实例分配给基类引用 并且我们只能访问基类功能。 我们可以将继承层次结构中的任何子类实例分配给基类引用。对于分配给特定基类引用的实例类型,我们只能访问基类函数,但我没有发现任何差异。
任何人都可以给我实际的概念 为什么我们必须将子类实例分配给基类引用? 有什么需要这样做? 相反,我们可以从子类引用中访问那些基类函数。
通过考虑层次结构中的特定基类和许多子类来解释。
答案 0 :(得分:5)
您可能希望这样做的原因是为了创建更强大的设计。以Java中的Collections Framework为例。你有一个List接口,然后你有两个实现,ArrayList和LinkedList。
您可以编写程序以专门使用LinkedList或ArrayList。但是,您的程序将依赖于这些特定的实现。
如果您编写的程序依赖于超类型List,那么您的程序可以适用于任何一个List实现。假设您想编写一个对List执行某些操作的方法,并且您写了这个:
public void doSomething(ArrayList a){}
此方法只能使用ArrayList调用,而不能使用LinkedList调用。假设你想用LinkedList做同样的事情?那你复制你的代码吗?否。
public void doSomething(List l){}
将能够接受任何类型的List。
这背后的原理是接口的程序而不是实现。也就是说,List定义了ALL列表的功能。
这种用法有很多例子。
答案 1 :(得分:3)
继承和多态是面向对象编程的基石,简而言之,它有几个不同的用途:
等。
最后一点还强调,为什么人们可能会使用一组受限制的功能,即使实际实现提供的功能不止于此。以Collection接口为例。通过使用此界面,我们专注于isEmpty
,contains
或size
等方法,但不关注实际实现。
答案 2 :(得分:2)
你所描述的是多态性的本质。这是希腊语中的一个词,意思是“多种形式”。
如果我给你一个像这样的简单层次结构,你可以看到测试代码如何从每个对象中获得不同的计算实现,而不关心它处理的是什么样的Shape:
public interface Shape
{
double calculateArea();
}
class Circle implements Shape
{
private double radius;
Circle(double r) { this.radius = r; }
public double calculateArea() { return Math.PI*radius*radius; }
}
class Square implements Shape
{
private double side;
Square(double s) { this.side = s; }
public double calculateArea() { return side*side; }
}
// This would be a separate JUnit or TestNG annotated test.
public class ShapeTest
{
@Test
public void testCalculateArea()
{
Map<Shape, Double> expected = new HashMap<Shape, Double>()
{{
put(new Circle(1.0), Math.PI);
put(new Square(1.0), 1.0);
}};
for (Shape shape : expected.keySet())
{
Assert.assertEquals(expected.get(shape), shape.calculateArea());
}
}
}
答案 3 :(得分:1)
我是一种为您提供List<String>
的方法。关于我实际给你的东西,你需要知道的是它是一个列表,并且具有列表的行为和语义,即你可以把东西放进去,它会保持它们的顺序,你可以迭代它
你不需要知道的是我如何存储东西,我如何使它们可访问等等。这并不重要。对于您关心的所有内容,它可以是LinkedList<String>
,ArrayList<String>
或全新的内容。我只想说,我已经选择了一些东西,你可以愉快地使用它。
当你使用继承来扩展类并添加新行为时,你是完全正确的,那么你需要引用子类才能访问它。这两种方法有点互补,但用例不同。
答案 4 :(得分:1)
我们说广告是基础类,而 Car 和 Plane 是子类。让我们说Vehicle有一个方法move()。
汽车通过上路改写了这一点。飞机通过飞行覆盖了这一点。
为什么move()应该是Vehicle基类的一部分?
因为任何车辆都可以移动()。但我们无法在Vehicle中实现move(),因为所有车辆都不会以相同的方式移动,即没有共同的行为。我们仍然希望在基类中使用它,以便我们可以具有多态行为,即我们可以编写如下代码。正如您所看到的,只有一个名为runVehicle(...)的方法可以在任何Vehicle类上运行。
void runVehicle(Vehicle v)
{
v.move();
}
Car c=new Car();
runVehicle(c);
Plane p=new Plane();
runPlane(p);
答案 5 :(得分:0)
没有真正的需要来做到这一点,除非API要求它。例如,如果在特定的API或代码库中存在
void ReallyUsefulFunction(BaseClass instance)
您想要使用,您可以派生一个类Fom BaseClass并在SubClass中实现其方法。然后,您现在可以将子类传递给函数。
从技术上讲,你可以实现自己的
void MyReallyUsefulFunction(MyClass instance)
模仿相同的功能。但就像MYYM解释的那样,代码重用等的好处可能是巨大的,那就是你想要利用多态性的时候。