1. 抽象类
1.1 抽象类概念
在面向对象的概念中,所有的对象都是通过类来描绘的,但是反过来,并不是所有的类都是用来描绘对象的,如果 一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类。
比如: 一个图形类,因为图形包括很多,圆,三角形,矩形。所以,图形类就可以设置成抽象类,因为它没办法描述一个具体的图形。
1.2 抽象类语法
要使一个类称为抽象类,需要用到 abstract 关键字。
public abstract class Shape {
// 抽象方法:被abstract修饰的方法,没有方法体
abstract public void draw();
abstract void calcArea();
// 抽象类也是类,也可以增加普通方法和属性
public double getArea(){
return area;
}
protected double area; // 面积
}
抽象类也是类,内部可以包含普通方法和属性,甚至构造方法。
1.3 抽象类特征和作用
特征:
1. 抽象类不能实例化对象
abstract class Shape {
....
}
.....
Shape shape = new Shape();
//error
2. 抽象方法不能用 private 修饰
abstract class Shape {
abstract private void draw(); //error
}
3. 抽象方法不能被 final 和 static 修饰,因为抽象方法要被子类重写
abstract class Shape {
abstract final void methodA();
abstract public static void methodB();
//error
}
4. 抽象类必须被继承,并且继承后子类要重写父类中的抽象方法,否则子类也是抽象类,必须要使用 abstract 修饰
abstract class Shape {
abstract public void draw();
abstract void calcArea ();
}
abstract class Triangle extends Shape {
private double a;
private double b;
private double c;
//重写
@Override
public void draw() {
System.out.println("三角形:a = "+a + " b = "+b+" c = "+c);
}
public void calcArea(){
}
}
5. 抽象类中不一定包含抽象方法,但是有抽象方法的类一定是抽象类
6. 抽象类中可以有构造方法,供子类创建对象时,初始化父类的成员变量
7. final 和 abstract 不能同时存在
8. 当一个抽象类不想被普通类继承,可以把这个普通类改为抽象类
作用:
抽象类本身不能被实例化, 要想使用, 只能创建该抽象类的子类。然后让子类重写抽象类中的抽象方法。所以,使用抽象类相当于多了一重编译器的校验。
使用抽象类的场景就如上面的代码, 实际工作不应该由父类完成, 而应由子类完成。那么此时如果不小心误用成父类了, 使用普通类编译器是不会报错的。 但是父类是抽象类就会在实例化的时候提示错误, 让我们尽早发现问题。
2. 接口
2.1 接口的概念
接口是Java中的一个特别的功能,可以根据字面意思来看,和电脑上的一些接口差不多的性质。
电脑的USB口上,可以插:U盘、鼠标、键盘...所有符合USB协议的设备。
接口就是公共的行为规范标准,大家在实现时,只要符合规范标准,就可以通用。 在Java中,接口可以看成是:多个类的公共规范,是一种引用数据类型。
2.2 接口的语法
接口需要用到 interface 关键字,在 IntelliJ IDEA 中可以在源文件中鼠标右键创建接口
//接口
public interface Iusb {
void openDevice();
void closeDevice();
}
接口的一些语法规则:
- 接口中的成员变量,默认是public static final
- 接口中的成员方法,默认是public abstract
- 接口中不可以有普通方法(除非前面加default)
- 接口中用static修饰的方法是可以具体实现的
- 接口不可以通过new实例化
- 接口可以通过关键字implements来实现接口
2.3 接口的用法
要实现接口,需要用到 implements 关键字,我们可以写一个Java文件,里面有一些设备类,然后实现这些设备的打开和关闭。
//接口的实现
class Mouse implements Iusb{
//实现接口的方法
@Override
public void openDevice() {
System.out.println("打开鼠标");
}
@Override
public void closeDevice() {
System.out.println("关闭鼠标");
}
public void Click(){
System.out.println("使用鼠标");
}
}
class Keyboard implements Iusb{
@Override
public void openDevice() {
System.out.println("打开键盘");
}
@Override
public void closeDevice() {
System.out.println("关闭键盘");
}
public void use(){
System.out.println("使用键盘");
}
}
class Computer implements Iusb{
@Override
public void openDevice() {
System.out.println("打开电脑");
}
@Override
public void closeDevice() {
System.out.println("关闭电脑");
}
public void useC(){
System.out.println("使用电脑");
}
//传入接口作为参数,控制接口
public void useDevice(Iusb iusb){
iusb.openDevice();
if (iusb instanceof Mouse){
Mouse mouse = (Mouse) iusb; //强转接口为鼠标,以便调用鼠标的方法
mouse.Click(); //和父类强转子类差不多
} else if (iusb instanceof Keyboard) {
Keyboard keyboard = (Keyboard) iusb; //同理
keyboard.use();
}
iusb.closeDevice();
}
}
public class Device {
public static void main(String[] args) {
Computer computer = new Computer();
computer.openDevice();
computer.useC();
//接口的具体实现
computer.useDevice(new Mouse());
computer.useDevice(new Keyboard());
computer.closeDevice();
}
}
注意,在类连接接口后,要重写接口的方法。然后在方法中传入 接口 作为参数,真正控制接口。
2.4 接口的特征
1. 接口类型是一种引用类型,不能用 new 关键字实例化。
2. 接口中每一个方法都是public的抽象方法, 即接口中的方法会被隐式的指定为 public abstract(只能是 public abstract,其他修饰符都会报错,例如: private)
3. 接口中的方法是不能在接口中实现的,只能由实现接口的类来实现,如上述代码。
4. 重写接口中方法时,不能使用默认的访问权限。因为接口中的方法是 public,所以重写时,权限不能小于接口中的权限。
5. 接口中可以含有变量,但是接口中的变量会被隐式的指定为 public static final 变量。所以,相当于常量,不能在其他类中修改。
6. 接口中不能有静态代码块和构造方法
7. 如果类没有实现接口中的所有的抽象方法(如果没有重写所有方法),则类必须设置为抽象类。
2.5 多接口
我们前面说过,继承中不支持多继承,即一个子类继承多个父类。但是在接口中,可以支持多接口,也就是一个类可以连接多个接口。
比如我们现在创建多个接口:
现在我们创建了三个接口,分别在三个文件中。
然后创建一个类,连接多个接口:
abstract class Animal {
public String name;
public int age;
public Animal(String name, int age){
this.name = name;
this.age = age;
}
public abstract void eat();
}
class Dog extends Animal implements IRunning,ISwimming{
public Dog(String name, int age) { //重写父类的构造方法
super(name, age);
}
@Override
public void eat() { //重写父类的方法
System.out.println(name + "正在吃狗粮");
}
@Override
public void run() { //重写接口 IRunning 的方法
System.out.println(name + "正在奔跑");
}
@Override
public void swim() { //重写接口 ISwimming 的方法
System.out.println(name + "正在游泳");
}
}
我们可以看到,Dog类在继承了 Animal 类后,连接了两个接口。
需要注意的是:一个类实现多个接口时,每个接口中的抽象方法都要实现,否则类必须设置为抽象类。
接口的好处就是可以让设计者不必关注具体类型,只关注某个类是否具备某种 “能力”。比如,不一定继承Animal类的一定是动物,只要需要名字或年龄的都可以继承,然后看是否具备接口的 “能力”。
2.5 接口间的继承
接口直接也是可以继承的,而且接口可以实现多继承,这是类不能实现的。
interface IRunning {
void run();
}
interface ISwimming {
void swim();
}
// 两栖的动物, 既能跑, 也能游
interface IAmphibious extends IRunning, ISwimming {
...
}
class Frog implements IAmphibious {
...
}
以上就是接口的内容。
2.6 抽象类和接口的区别
核心区别:抽象类中可以包含普通方法和普通字段, 这样的普通方法和字段可以被子类直接使用(不必重写), 而接口中不能包含普通方法, 子类必须重写所有的抽象方法.
再次提醒:抽象类存在的意义是为了让编译器更好的校验, 像 Animal 这样的类我们并不会直接使用, 而是使用它的子类. 万一不小心创建了 Animal 的实例, 编译器会及时提醒我们.
小结:
到此为止,Java SE中的重要语法都介绍的差不多了。后面还有一些比较零碎的语法,内部类,String的一些用法等。