一、抽象类
1.抽象类概述
回想前面我们的猫狗案例,提取出了一个
动物类。并且我们在前面也创建过了动物
对象,其实这是不对的。为什么呢?因为,
我说动物,你知道我说的是什么动物吗?
只有看到了具体的动物,你才知道,这是
什么动物。所以说,动物本身并不是一个
具体的事物,而是一个抽象的事物。只有
真正的猫,狗才是具体的动物。同理,我们
也可以推想,不同的动物吃的东西应该是
不一样的,所以,我们不应该在动物类中
给出具体的体现,而是应该给出一个声明
即可。在java中,一个没有方法体的方法
应该定义为抽象方法,而类中如果有抽象
方法,该类必须定义为抽象类。
2.抽象类的特点
抽象类的概述:
动物不应该定义为具体的东西,而动物中
的吃,睡等也不应该是具体的。
我们把一个不是具体的功能称为抽象的
功能,而一个类中如果有抽象的功能,
该类也必须是抽象类。
抽象类的特点:
A:抽象类和抽象方法必须用abstract关键字修饰
B:抽象类中不一定有抽象方法,但是有抽象方法的类,必须定义为抽象类。
C:抽象类不能实例化。
因为他不是具体的。
抽象类有构造方法,但是不能实例化,构造方法的作用是什么呢?
用于子类访问父类数据的初始化。
D:抽象类的子类
a:如果不想重写抽象方法,该子类必须是一个抽象类
b:重写所有的抽象方法,这个时候子类是一个具体的类。
抽象类的实例化其实是可以靠具体的子类实现的,是多态的方式。
(就是通过重写方法,然后向下转型来调用子类中的具体的实现的方法)
Animal a = new Cat();
多态用的最多的地方就是在抽象类中。
abstract class Animal{
//抽象方法
//public abstract void eat(){}//空方法体,这个会报错。抽象方法不能有主体
public abstract void eat();//没有方法体
public Animal(){}
}
//子类是抽象类
abstract class Dog extends Animal{
}
//子类不是抽象类,重写抽象方法
class Cat extends Animal{
public void eat(){
System.out.println("猫吃鱼");
}
}
class AbstractDemo{
public static void main(String[] args){
//错误: Animal是抽象的; 无法实例化
//Animal a = new Animal();
//通过多态的方式,实例化抽象类
Animal a = new Cat();
a.eat();
}
}
3.抽象类的成员特点
抽象类的成员特点:
成员变量:既可以是变量也可以是常量。
构造方法:有,用于子类访问父类数据的初始化(不可以实例化)
成员方法:可以是抽象的,也可以是非抽象的。
抽象类的成员方法特性:
A:抽象方法 强制要求子类做的事情
B:非抽象方法 子类继承的事情,提高代码的复用性。
abstract class Animal{
public int num = 10;
public final int num2 = 20;
public Animal(){}
public Animal(String name,int age){}
public abstract void show();
public void method(){
System.out.println("method");
}
}
class Dog extends Animal{
public void show(){
System.out.println("show dog");
}
}
class AbstractDemo{
public static void main(String[] args){
//创建对象
Animal a = new Dog();
a.num = 100;
System.out.println(a.num);
//错误: 无法为最终变量num2分配值
//a.num2 = 200;
System.out.println(a.num2);
System.out.println("----------");
//错误: Dog不是抽象的, 并且未覆盖Animal中的抽象方法show()
//a.show();
a.show();
a.method();
}
}
4.抽象类的猫狗案例
/*
猫狗案例
具体事务:猫、狗
共性:姓名,年龄,吃饭
分析:从具体到抽象
猫:
成员变量:姓名,年龄
构造方法:无参,带参
成员方法:吃饭(鱼)
狗:
成员变量:姓名,年龄
构造方法:无参,带参
成员方法:吃饭(肉)
因为有共性的内容,所以就提取了一个父类。动物。
但是又由于吃饭的内容不一样,所以吃饭的方法是抽象的。
而方法是抽象的,类就必须定义为抽象类。
实现:从抽象到具体
动物类:
成员变量:姓名,年龄
构造方法:无参,带参
成员方法:吃饭
狗类:
继承自动物类
重写吃饭();
猫类:
继承自动物类
重写吃饭();
*/
//定义抽象的动物类
abstract class Animal{
//姓名
private String name;
//年龄
private int age;
public Animal(){}
public Animal(String name,int age){
this.name = name;
this.age = age;
}
public String getName(){
return name;
}
public void setName(String name){
this.name = name;
}
public int getAge(){
return age;
}
public void setAge(int age){
this.age = age;
}
public abstract void eat();
}
//定义具体的狗类
class Dog extends Animal{
public Dog(){}
public Dog(String name,int age){
super(name,age);
}
public void eat(){
System.out.println("狗吃肉");
}
}
//定义具体的猫类
class Cat extends Animal{
public Cat(){}
public Cat(String name,int age){
super(name,age);
}
public void eat(){
System.out.println("猫吃鱼");
}
}
//测试类
class AbstractDemo{
public static void main(String[] args){
//测试狗类
//方式1
Dog d = new Dog();
d.setName("旺财");
d.setAge(6);
System.out.println(d.getName()+"---------"+d.getAge());
d.eat();
Dog d2 = new Dog("旺财",5);
System.out.println(d2.getName()+"---------"+d2.getAge());
d2.eat();
//方式2
Animal a = new Dog();
a.setName("旺财");
a.setAge(5);
System.out.println(a.getName()+"-----"+a.getAge());
a.eat();
Animal a2 = new Dog("旺财",5);
System.out.println(a2.getName()+"-----"+a2.getAge());
a2.eat();
}
}
5.抽象类中的小问题
一个类如果没有抽象方法,可不可以定义为抽象类?如果可以,有什么意义
A:可以,意义是可以不让外界创建对象。
抽象类不能和那些关键字共存
private 冲突 private修饰的不能被继承,而abstract要求必须重写
final 冲突 final修饰的不能被修改,而abstract要求必须重写
static 无意义 abstract修饰的方法没有方法体,而用static修饰的方法还可以用类名
直接调用的,访问一个没有方法体的方法是毫无意义的。
二、接口
1.接口概述
接口概述:
继续回到我们的猫狗案例,我们想象狗
一般就是看门的,猫一般就是作为宠物,
对不。但是,现在有很多的驯养员或者
驯兽师,可以训练出,猫钻火圈,狗跳
高,狗做计算等。而这些额外的动作,
并不是所有猫或者狗一开始就具备的,这
应该属于经过特殊的培训训练出来的。对不,
所以,这些额外的动作定义到动物类中就
不合适,也不适合直接定义到猫或者狗中,
因为只有部分猫狗具备这些功能。所以,
为了体现事物功能的扩展性,java中就提供了
接口来定义这些额外功能,并不给出具体实现
,将来那些猫狗需要被培训,只需要这部分
猫狗把这些功能实现即可。
*/
接口只是事物功能的扩展,而并不是事物本身具备的功能,所以不能定义到事物的类中
作为方法。只能定义为接口。
2.接口的特点
/*
接口的特点:
A:接口用关键字interface表示
interface 接口名{}
B:类实现接口用implements表示
class 类名 implements 接口名{}
C:接口不能实例化
那么,接口如何实例化呢?
按照多态的方式来实例化。
D:接口的子类
a:可以是抽象类,但是意义不大。
b:可以是具体类,要重写接口中的所有抽象方法。(推荐方法)
由此可见:
A:具体类多态(几乎没有)
B:抽象类多态(常用)
C:接口类多态(最常用)
*/
//定义动物培训接口
/*
由此可见,接口并不是实际意义上的一个类
它仅仅是功能的扩展
*/
//定义一个接口
interface AnimalTrain{
public abstract void jump();
}
//抽象类实现接口,这种方法不常见。
abstract class Dog implements AnimalTrain{
}
//具体类重写接口中的所有抽象方法,这种方法很常见。
class Cat implements AnimalTrain{
public void jump(){
System.out.println("猫可以跳高了");
}
}
class InterfaceDemo{
public static void main(String[] args){
//AnimalTrain是抽象的,无法实例化
//AnimalTrain at = new AnimalTrain();
AnimalTrain at = new Cat();
at.jump();
}
3.接口的成员特点
成员变量:只能是常量,并且是静态的。
默认修饰符:public static final
完整格式:public static final int num = 20;
建议:自己手动给出
构造方法:接口没有构造方法
成员方法:只能是抽象方法
默认修饰符:public abstract
建议:自己手动给出。
所有的类都默认继承自一个类:object
类object是类层次结构的根类,每个类都使用object作为超类
interface Inter{
public int num = 10;
public final int num2 = 20;
//public Inter(){}//错误: 需要<标识符>
//public void show(){}//错误: 接口方法不能带有主体
//public abstract void show();
public void show();//默认抽象的abstract
}
//接口名+ Impl这种格式是接口的实现类格式
/*
class InterImpl implements Inter{
public InterImpl(){
super();//既然父类接口没有构造方法,那么这里如何调用呢?
}
}
*/
//因为所有的类都默认继承自object
class InterImpl extends Object implements Inter{
public InterImpl(){
super();
}
public void show(){}
}
//测试类
class InterfaceDemo{
public static void main(String[] args){
//创建对象
Inter i = new InterImpl();
System.out.println(i.num);//结果是10
System.out.println(i.num2);//结果是20
//i.num = 100;
//i.num2 = 200;
//System.out.println(i.num);//错误: 无法为最终变量num分配值
//System.out.println(i.num2);//错误: 无法为最终变量num2分配值
System.out.println(Inter.num);
System.out.println(Inter.num2);
System.out.println("--------------");
}
}
4.类与类,类与接口,接口与接口
类与类:只能单继承,可以多层继承
类与接口:
实现关系:可以是单实现,也可以是多实现
并且还可以在继承一个类的同时实现多个接口。
接口与接口:
继承关系:可以单继承,也可以多继承
interface Father{
public abstract void show();
}
interface Mother{
public abstract void show2();
}
interface Sister extends Father,Mother{
}
//class Son extends Object implements Father,Mother
//错误: Son不是抽象的, 并且未覆盖Father中的抽象方法show()
class Son extends Object implements Father,Mother{
public void show(){
System.out.println("show son");
}
public void show2(){
System.out.println("show mother");
}
}
class InterfaceDemo{
public static void main(String[] args){
//创建对象
Father f = new Son();
f.show();
//f.show2();//报错
Mother m = new Son();
//m.show();//报错
m.show2();
}
}
5.抽象类和接口的区别
A:成员区别
抽象类:
成员变量:可以是变量,也可以是常量
构造方法:有
成员方法:可以是抽象的,也可以是非抽象的
接口:
成员变量:只可以是常量
成员方法:只可以是抽象的。
B:
类与类
继承 单继承
类与接口
实现 单实现,多实现
接口与接口
继承 单继承,多继承
C:设计理念区别**(这个很重要)
抽象类 被继承体现的是“is a”的关系 抽象类中定义的是该继承体系的共性功能。
接口 被继承体现的是“like a”的关系 接口中定义的是该继承体系的扩展功能。
6.加入调高的猫狗案例分析
/*
猫狗案例 加入调高的额外功能
分析:从具体到抽象
猫:
姓名,年龄
吃饭,睡觉
狗:
姓名,年龄
吃饭,睡觉
由于有共性功能,所以,我们抽取出一个父类;
动物:
姓名,年龄
吃饭();
睡觉(){}
猫:继承自动物
狗:继承自动物
跳高的额外功能是一个新的扩展功能,所以我们要
定义一个接口
接口:
跳高
部分猫:实现跳高
部分狗:实现跳高
实现:从抽象到具体
使用:具体类
*/
//定义跳高功能
interface Jumpping{
public abstract void jump();
}
//定义动物类(抽象类)
abstract class Animal{
private String name;
private int age;
public Animal(){}
public Animal(String name,int age){
this.name = name;
this.age = age;
}
public void setName(String name){
this.name = name;
}
public String getName(){
return name;
}
public void setAge(int age){
this.age = age;
}
public int getAge(){
return age;
}
//定义睡觉功能
public void sleep(){
System.out.println("睡觉喽!");
}
//定义吃饭功能,抽象方法
public abstract void eat();
}
//定义猫类,继承自动物类
class Cat extends Animal{
public Cat(){}
public Cat(String name,int age){
super(name,age);
}
public void eat(){
System.out.println("猫吃鱼");
}
}
//定义狗类,继承自动物类
class Dog extends Animal{
public Dog(){}
public Dog(String name,int age){
super(name,age);
}
public void eat(){
System.out.println("狗吃肉");
}
}
//定义跳高猫类,继承自猫类,实现跳高接口
class JumpCat extends Cat implements Jumpping{
public JumpCat(){}
public JumpCat(String name,int age){
super(name,age);
}
public void jump(){
System.out.println("跳高猫");
}
}
//定义跳高狗类,继承自狗类,实现跳高接口
class JumpDog extends Dog implements Jumpping{
public JumpDog(){}
public JumpDog(String name,int age){
super(name,age);
}
public void jump(){
System.out.println("跳高狗");
}
}
class CatAndDog{
public static void main(String[] args){
JumpCat jc = new JumpCat();
jc.setName("哆啦A梦");
jc.setAge(3);
System.out.println(jc.getName()+"-------"+jc.getAge());
jc.eat();
jc.sleep();
jc.jump();
System.out.println("-----------------------------");
JumpCat jc2 = new JumpCat("加菲猫",2);
System.out.println(jc2.getName()+"-------"+jc2.getAge());
jc2.eat();
jc2.sleep();
jc2.jump();
}
}
/*
记住:在实现某一个接口的时候,只是其中的某一部分要实现这个功能,
所以,我们需要单独去写一个实现这个功能的类(继承自原类+实现接口)
*/