面向对象编程四大特征:抽象,封装,继承,(多态)
类与对象
什么是对象?
属性+行为->对象
什么是类?
由对象抽象出一个模具,通过这个模具可以产生对象。这个模具就是类。
类没有值,而对象有值。
抽象
从一个群体中,根据一些共同点,抽出一个模型的过程。
封装
- 类封装:类封装属性和方法;
- 方法封装:将一个复杂的过程封装;
- 属性封装:所有属性私有,对外提供getter,setter方法。?依然可以访问到,有什么区别吗?
tips:
*getter 和 setter中都可以加入进行其他操作的语句,比如参数校验等;
当属性类型为boolean是,getA变成 isA;
如果没有自定义构造方法,那么JAVA会为该类自动创建一个不带参数的空构造器,但是如果自己定义了构造方法,则不会自动创建无参构造器,一般的做法是都要写上。*
继承
- 只能继承非私有的属性和方法;
设计父类需要抽离出共同点,取出具体值,代码尽量成为公共性质。
继承有什么好处?
- 只需要修改父类代码,维护方便;
- 将注意力放在业务逻辑处理而非重复代码;
多态
子类可以生成父类对象,这样调用父类对象的方法时,实际上是调用子类的方法。
实现多态的两种方式:继承,实现接口。
实现多态的两个条件:有父类,子类重写父类的方法。
现在用一个例子来说明使用多态带来的好处。
硬盘类 HardDisk.java
package dt;
public class HardDisk {
public void save() {
System.out.println("HardDisk Saving...");
}
}
软盘类 SoftDisk.java
package dt;
public class SoftDisk {
public void save() {
System.out.println("SoftDisk Saving...");
}
}
计算机类 Computer.java
package dt;
public class Computer {
public void set(SoftDisk softDisk) {
System.out.println("set SoftDisk...");
softDisk.save();
}
public void set(HardDisk hardDisk) {
System.out.println("set HardDisk...");
hardDisk.save();
}
}
测试类 testMain.java
package dt;
public class testMain {
public static void main(String[] args) {
Computer computer=new Computer();
HardDisk hardDisk=new HardDisk();
SoftDisk softDisk=new SoftDisk();
computer.set(hardDisk);
computer.set(softDisk);
}
}
运行结果:
set HardDisk...
HardDisk Saving...
set SoftDisk...
SoftDisk Saving...
现在看来,隐约感觉代码有点重复,但是暂且也没遇到什么问题。
现在,我们有一个新的需求,加U盘,实现相同功能。
那么,步骤是:
1. 新建一个Udisk类;
package dt;
public class Udisk {
public void save() {
System.out.println("UDisk Saving...");
}
}
2. 在Computer类中再写一个set方法模拟放置U盘;
public void set(Udisk uDisk) {
System.out.println("set HardDisk...");
uDisk.save();
}
3. 在testMain中创建一个Udisk实例,然后调用Computer的set方法;
Udisk udisk=new Udisk();
computer.set(udisk);
可以看到,我们改了三处,而且代码重复量相当大。首先,无论是硬盘,软盘还是U盘,他们都只有一个功能一样的方法save,computer的三个set方法其实做的也是同一样事情,装盘。
那么是否可以这样做把重复代码去掉?
- 抽象出一个父类叫做Disk,该Disk有一个save方法;
package dt2;
public class Disk {
public void save() {
}
}
2. HardDisk,SoftDisk都继承Disk类,重写父类的save方法;
package dt2;
public class HardDisk extends Disk{
@Override
public void save() {
// TODO Auto-generated method stub
//super.save();
System.out.println("HardDisk Saving...");
}
}
package dt2;
public class SoftDisk extends Disk{
@Override
public void save() {
// TODO Auto-generated method stub
//super.save();
System.out.println("SoftDisk Saving...");
}
}
3. Computer类只写一个通用的set方法,为public void set(Disk disk),具体是那种Disk,不用管;
package dt2;
public class Computer {
public void set(Disk disk) {
System.out.println("set disk...");
disk.save();
}
}
4. 在测试类里,由父类生成子类,调用父类的方法实际上是在调用子类的方法,那么这样就可以在不写重复代码的前提下,减少许多代码。
package dt2;
public class testMain {
public static void main(String[] args) {
Disk hardDisk=new HardDisk();
Disk softDisk=new SoftDisk();
Computer computer=new Computer();
computer.set(hardDisk);
computer.set(softDisk);
}
}
现在,如果我们需要加U盘,有以下两个个步骤:
- 新建Udisk类,并继承Disk,重写save方法;
- 在测试类中由父类产生子类,并调用子类方法;
这样相比下来,Computer的set方法根本不用做任何修改。
接口与抽象类
如果Disk的属性和方法时专门用来给其他类继承的,那么可以将它定义为抽象类(如果一个类中有抽象属性和抽象方法,那么该类也必须是抽象类)。
public abstract class Disk {
public abstract void save();
}
如果一个类里的所有方法都是抽象方法,并且需要子类全部继承进行重写,可以直接将这个类定义为一个接口,让其他类实现这个接口,并强制让其继承并重写这些方法。
public interface MyDisk {
public void save();
}
public class SoftDisk implements MyDisk{
@Override
public void save() {
// TODO Auto-generated method stub
}
}