// >> TODO 继承的语法就是在类名后面使用extends 加 要继承的类名
// >> TODO 被继承的类叫做父类(Parent Class),比如本例中的MerchandiseV2。
// >> TODO 继承者叫做子类(Sub Class),比如本例中的PhoneExtendsMerchandise。
// >> TODO Java中只允许一个类有一个直接的父类(Parent Class),即所谓的单继承
// >> TODO 没错,别的类也可以继承子类,比如可以有一个HuaweiPhone继承PhoneExtendsMerchandise
// TODO 这时候,HuaweiPhone就是PhoneExtendsMerchandise的子类了。
// >> TODO 子类继承了父类什么呢?所有的属性和方法。
// >> TODO 但是子类并不能访问父类的private的成员(包括方法和属性)。
public class PhoneExtendsMerchandise extends MerchandiseV2 {}
// >> TODO 继承,其实表达的是一种"is-a"的关系,也就是说,在你用类构造的世界中,"子类是父类的一种特殊类别"
// >> TODO 组合和继承,是拿到一个问题,设计相应的Java类的时候,不得不面对的来自灵魂的拷问
// TODO "XX到底是YY的一种,还是只是组合了YY?","手机到底是手电筒的一种,还是组合了一个可以当手电的闪光灯?"
// TODO 在组合的情况下,怎么限制一次只能买五个手机呢?
// TODO 1)首先不能修改MerchandiseV2这个类,否则你会限制所有商品一次购买的数量
// TODO 2)其次,在现实情况下,这个类可能根本不受你控制,你无权修改其代码
// TODO 3)在每次调用buy方法的地方做限制,是不行的,
// TODO - 你无法控制别人怎么用你的类,
// TODO - 而且会面临到处复制代码的糟糕情况,
// TODO - 如果说限制改成10个,所有复制的代码都要改,程序员都应该很懒,这不是一个程序员该做的事情
// TODO 4)在只能修改手机类的情况下,我们可以提供一个buyPhone的方法,实现限制购买数量的逻辑。
// TODO 但是这样并不能阻止别人像下面这样调用merchandise的buy方法,这个方法是会修改库存的,所以还是无法硬性的限制一次性购买手机的数量
// TODO 我们来理清一下自己的核心诉求:针对手机,限制一次性购买的数量。必须限制死,必须不影响别的商品,必须只能改手机类的代码
// TODO 这时候,组合就无能为力了,继承可以发挥其应有的作用。
// >> TODO 继承不是组合,继承也不只是为了能简单的拿来父类的属性和方法。如果仅仅如此,原封不动的拿来主义,组合也能做到。
// TODO 继承也不是通过组合的方式来实现的。和组合相比,继承更像是"融合"
// TODO 所谓融合,即合二为一,可以互相影响。父类影响子类没问题,子类怎么影响父类呢?如何限制手机一次只能最多买五个?
覆盖
// >> TODO 通过使用和父类方法签名一样,而且返回值也必须一样的方法,可以让子类覆盖(override)掉父类的方法
// >> TODO ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓下面才是继承的终极奥义↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
// >> TODO 也就是说,子类并不是只能把父类的方法拿过来,而且可以通过覆盖来替换其中不适合子类的方法
// >> TODO ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑上面才是继承的终极奥义↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
// >> TODO 题外话:属性是联动的,可能是有特殊意义的。
// TODO 所以直接给属性赋值是危险的,因为没有办法检查新的值是否有意义,也没法对这个修改做联动的修改
// TODO 这个方法里代码大部分和父类一样,肯定有方法解决
// >> TODO 返回值必须一样,不是类型兼容,而是必须一摸一样。
// >> TODO 如果签名一样,但是返回值不一样,会是错误
// >> TODO 返回值必须一样,不是类型兼容,而是必须一摸一样
// >> TODO 覆盖可以覆盖掉父类的方法。同一个方法,不同的行为。
// >> TODO 这,就是多态!
// >> TODO 方法可以覆盖,属性访问不可以,所以这也是使用方法的一个原因。
// TODO 即使在父类里,只是一个简单的getName,但是这样做,子类就可以覆盖掉父类的方法
// TODO 方法不止眼前的代码,还有子类的覆盖。用方法,才能覆盖,才能多态。
// TODO 根据我们对覆盖的理解,Phone类里的describePhone方法应该叫做describe
// TODO 同样的,我们想哟调用父类里的describe方法,试试看?
super:子类和父类之间沟通的桥梁
// >> TODO 使用super可以调用父类的方法和属性(当然必须满足访问控制符的控制)
public double buy(int count) {
if (count > MAX_BUY_ONE_ORDER) {
System.out.println("购买失败,手机一次最多只能买" + MAX_BUY_ONE_ORDER + "个");
return -2;
}
return super.buy(count);
}
public void describe() {
System.out.println("此手机商品属性如下");
super.describe();
System.out.println("手机厂商为" + brand + ";系统为" + os + ";硬件配置如下:\n" +
"屏幕:" + screenSize + "寸\n" +
"cpu主频" + cpuHZ + " GHz\n" +
"内存" + memoryG + "Gb\n" +
"存储空间" + storageG + "Gb");
// >> TODO super是子类和父类交流的桥梁,但是并不是父类的引用
// >> TODO 所以,super和this自引用不一样,不是简单可以模拟的(可以模拟的话不就成了组合了吗)
// >> TODO 使用super可以调用父类的public属性,但是super不是一个引用。
public void accessParentProps() {
System.out.println("父类里的name属性:" + super.name);
}
public void useSuper() {
// >> TODO super的用法就像是一个父类的引用。它是继承的一部分,像组合的那部分,但不是全部
super.describe();
super.buy(66);
System.out.println("父类里的count属性:" + super.count);
}
public Phone(
String name, String id, int count, double soldPrice, double purchasePrice,
double screenSize, double cpuHZ, int memoryG, int storageG, String brand, String os
) {
// >> TODO 可以认为,创建子类对象的时候,也就同时创建了一个隐藏的父类对象
this.screenSize = screenSize;
this.cpuHZ = cpuHZ;
this.memoryG = memoryG;
this.storageG = storageG;
this.brand = brand;
this.os = os;
// >> TODO 所以,才能够setName,对name属性进行操作。
this.setName(name);
this.setId(id);
this.setCount(count);
this.setSoldPrice(soldPrice);
this.setPurchasePrice(purchasePrice);
}
用super调用父类的构造方法
public Phone(
String name, String id, int count, double soldPrice, double purchasePrice,
double screenSize, double cpuHZ, int memoryG, int storageG, String brand, String os
) {
// >> TODO 使用super调用父类的构造方法,必须是子类构造方法的第一个语句
// >> TODO 可以使用表达式
// >> TODO super调用构造方法,不可以使用super访问父类的属性和方法,不可以使用子类成员变量和方法
// >> TODO 可以使用静态变量和方法
// >> TODO 都是<init>方法,我们来看一下
super(name, id, count, soldPrice * 1.2, purchasePrice);
init(screenSize, cpuHZ, memoryG, storageG, brand, os);
}
父类引用和子类引用之间的赋值关系
//继承关系
public class Students extends user
1.可以用子类的对象给父类对象赋值,也就是说可以用父类对象指向子类对象
Students students=new Students(
"Marry",
12,
'w',
"11204",
"BeiJing forth school",
"grade four class 1");
user user=students;//新建一个父类对象指向子类对象的引用
2.父类对象指向子类对象之后,只能操作父类对象里定义的方法和属性,并不能操作子类定义的方法和属性;
3.如果一定要在已经指向子类对象的父类对象上操作子类对象的方法和属性,可以把该引用强制类型转换成子类对象类型;
Students X = (Students)user;//转换成子类对象的类型
就可以操作子类对象的方法和属性