我是OOP的新手,所以我对一个班级extends
另一个班级有一个愚蠢的问题。
这是我的例子:
public class Test {
public Monitor getMonitor(){
return new LCD();
}
class LCD extends Monitor { NO-ERROR
class LCD { ERROR at line `return new LCD`
//some other method or function not in Monitor Class. Example:
boolean isSamsung;
public LCD whatkindLCD(){
}
}
}
我对上面的代码有一个问题:因为LCD
是从Monitor
扩展而LCD
有一些其他属性/方法,而Monitor没有。因此,LCD
是Monitor
的孩子,对吧?
这意味着你试图放一个"大盒子"到一个"小盒子"。那么,为什么当我return new LCD
时,Eclipse没有注意到错误,就像我只使用class LCD {
一样。
谢谢:)
答案 0 :(得分:5)
在您的第二个(错误)案例中,您忘记声明LCD
确实延伸Monitor
。您只是定义了一个“正常”的独立类 - 因此new LCD()
不是 Monitor
的实例。
如果您声明LCD
类,编译器应该感到高兴:
class LCD extends Monitor {
//some other method or function not in Monitor Class. Example:
boolean isSamsung;
public LCD whatkindLCD(){
}
}
编辑(以回应评论):与LCD
相比,Monitor
类具有额外的属性/方法根本不是问题。要调用getMonitor()
的代码,只关心它返回Monitor
- 也就是说,它具有Monitor
的所有方法,属性和行为。
因此,如果您的turnOff
课程中有displayBitmap(int[][] data)
和Monitor
方法,那么您的LCD
课程也会有这些方法。当需要时,LCD
的任何实例都可以表现为Monitor
- 这是OO语言中子类化的基本原则。因此,无论什么时候需要Monitor
,你都可以给它一个LCD
,或CRT
或SamsungLCD
的实例,如果有的话,编译器可以满足正确的方法/属性将存在并且可以被调用。
(从技术上讲,如果您喜欢正式定义,这是Liskov substitution principle,但您不需要在详细程度上理解它。)
答案 1 :(得分:3)
方框的比喻是错误的,请改为考虑is a
关系。
在第一个例子中,LCD extends Monitor
,即LCD is a Monitor
,因此在预期显示器的任何地方,LCD都可以。当您在现实世界中考虑而不是查看代码时,您会意识到这是正确的。你可以期待一般显示器所做的一切(例如显示图片),液晶显示器都可以。
在第二个示例中,LCD不是监视器,因此您会收到错误消息。
答案 2 :(得分:1)
将继承理解为“是一种”关系。这是我在新手时期用来理解继承的一个简单例子。
class Employee
{
String name;
int salary;
Employee()
{
name = "Employee";
salary = 5000;
}
public String getName()
{
return name;
}
public int getSalary()
{
return salary;
}
}
class Manager extends Employee
{
int bonus;
int salary;
Manager()
{
bonus = 1000;
salary = 6000;
}
public int getBonus()
{
return bonus;
}
public int getSalary()
{
return salary;
}
}
class Test
{
public static void main(String[] args)
{
Employee e = new Employee();
System.out.println(e.getName());
//System.out.println(e.getBonus());
System.out.println(e.getSalary());
System.out.println();
Manager m = new Manager();
System.out.println(m.getName());
System.out.println(m.getBonus());
System.out.println(m.getSalary());
System.out.println();
Employee em = new Manager();
System.out.println(em.getName());
//System.out.println(em.getBonus());
System.out.println(((Manager)em).getBonus());
System.out.println(em.getSalary());
}
}
编译器在调用任何操作之前查找引用类型。 em.getBonus()不起作用,因为Employee没有奖金方法。 但是使用演员阵容我们可以让它发挥作用。 ((经理)EM)getBonus()
编译器在调用任何操作之前查找引用类型的原因如下:
经理[]经理=新经理[10];
将此数组转换为Employee []数组是合法的:
员工[]员工=经理; //好的
当然,为什么不呢,你可能会想。毕竟,如果经理[i]是经理,那么它也是一名员工。但事实上,令人惊讶的事情正在发生。请记住,经理和员工都是对同一个数组的引用。
现在考虑声明
staff [0] =新员工(“John Eipe”,......);
编译器会愉快地允许这个赋值。 但是员工[0]和经理[0]是相同的参考,所以看起来我们设法将一名员工走私到管理层 行列。
那将是非常糟糕的 - 调用管理器[0] .setBonus(1000)将尝试访问a 不存在的实例字段会破坏相邻的内存。 为了确保不会发生此类损坏,所有数组都会记住元素类型 它们是创建的,它们监视只存储兼容的引用 他们。例如,作为新Manager [10]创建的数组会记住它是一个数组 经理。尝试存储Employee引用会导致ArrayStoreException。
答案 3 :(得分:0)
您的方法getMonitor
返回“监视器”类型。
当您使用Monitor扩展类LCD时,您说的是LCD 是显示器的编译器。 当您删除 extends 时,LCD类将变为普通类,而不是监视器类型。 如果您将getMonitor修改为
public LCD getMonitor(){
// code here
}
错误将会消失。