文章目录
面对对象——抽象类
抽象类基础概念:
- 概述:
回想前面我们的猫狗案例,提取出了一个动物类。并且我们在前面也创建过了动物对象,其实这是不对的。为什么呢?因为,我说动物,你知道我说的是什么动物吗?只有看到了具体的动物,你才知道,这是什么动物。 所以说,动物本身并不是一个具体的事物,而是一个抽象的事物。只有真正的猫,狗才是具体的动物。同理,我们也可以推想,不同的动物吃的东西应该是不一样的,所以,我们不应该在动物类中给出具体体现,而是应该给出一个声明即可。
在Java中,一个没有方法体的方法应该定义为抽象方法,而类中如果有抽象方法,该类必须定义为抽象类。
抽象类的特点及成员特点:
-
抽象类的特点:
a. 抽象类和抽象方法必须用abstract关键字修饰:
抽象类格式:abstract class 类名 {}
抽象方法格式:
public abstract void eat();
b. 抽象类不一定有抽象方法,有抽象方法的类一定是抽象类
c. 抽象类中可以有构造方法,抽象类不能进直接行实例化,那么要构造方法有什么作用呢?
回答:用于子类访问父类数据时的初始化
d. 抽象类不能直接实例化那么,抽象类如何实例化呢?
回答:按照多态的方式,由具体的子类实例化。其实这也是多态的一种,抽象类多态。(即:子类可以调用抽象类的构造方法,但其他没有关系的类则不能调用该构造方法!)
示例:- 主类函数
public class Test { public static void main(String[] args) { Animal an1 = new Cat(); System.out.println(an1.age);//抽象类对象的属性 System.out.println(((Cat) an1).name);//子类对象的属性(向下转型取得) an1.eat(); an1.sleep(); ((Cat)an1).catchMouse();//向下转型 } } ------------------------------------------- 输出: 抽象类初始化已经调用! Cat类初始化函数已经被调用! 1 小猫咪 10岁的小猫咪要吃小鱼干! 10岁的小猫咪在白天睡觉! 10岁的小猫咪会抓老鼠!
- 抽象类
public abstract class Animal { int age; String name; Animal(){ System.out.println("抽象类初始化已经调用!"); age = 1; name = "动物"; } //定义吃饭的抽象方法:(具体由子类自己来实现) public abstract void eat(); //定义睡觉的抽象方法:(具体由子类自己来实现) public abstract void sleep(); }
- 子类Cat
package westos.org.test2; public class Cat extends Animal{ int age; String name; Cat(){ System.out.println("Cat类初始化函数已经被调用!"); age = 10; name ="小猫咪"; } @Override public void eat() { System.out.println(age+"岁的"+name+"要吃小鱼干!"); } @Override public void sleep() { System.out.println(age+"岁的"+name+"在白天睡觉!"); } public void catchMouse(){ System.out.println(age+"岁的"+name+"会抓老鼠!"); } }
- 子类Dog:
package westos.org.test2; public class Dog extends Animal { String name = "小狗"; int age = 10; @Override public void eat() { System.out.println(age+"岁的"+name+"要啃骨头!"); } @Override public void sleep() { System.out.println(age+"岁的"+name+"在晚上睡觉!"); } public void watchDoor(){ System.out.println(age+"岁的"+name+"会看门!"); } }
e. :抽象类的子类:
要么是抽象类
要么重写抽象类中的所有抽象方法(否则,它也必须是一个抽象类) -
引出一个问题:抽象类的构造函数调用必须依靠多态?(个人认为单纯的继承也可以!已证实:可以)
示例:public class Test { public static void main(String[] args) { Cat cat1 = new Cat(); cat1.eat(); cat1.sleep(); cat1.sleep(); } } ------------------------------------------------------- 输出: 抽象类初始化已经调用! Cat类初始化函数已经被调用! 10岁的小猫咪要吃小鱼干! 10岁的小猫咪在白天睡觉! 10岁的小猫咪在白天睡觉!
-
抽象类的成员特点:
a. 成员变量:既可以是变量,也可以是常量。
b. 构造方法:有。
用于子类访问父类数据的初始化。
c. 成员方法:既可以是抽象的,也可以是非抽象的。
注意:abstract 不能修饰变量; -
抽象类的成员方法特性:
- 抽象方法:强制要求子类做的事情。(强制子类重写抽象类中定义的抽象方法)
- 非抽象方法 :子类继承的事情(功能),提高代码复用性。(但子类也可以重写非抽象类的方法!)
抽象类的常见问题:
- 一个类如果没有抽象方法,可不可以定义为抽象类?如果可以,有什么意义?
回答:可以
意义:不能直接创建该抽象类的对象。(abstract 修饰的类不可直接进行实例化!) - abstract 在方法中使用,能不能和下面的关键字一起使用?
a. private abstract 两者互相矛盾,abstract 强制子类重写 ,private 限定后又无法继承(更不能重写了!)
b. final abstract 两者互相矛盾, abstract 强制子类重写,final 修饰的也没法重写
c. abstract static 两者也互相矛盾,abstract 强制子类重写,static 修饰过后的方法属于类方法,谈不上重写!(重写:是先造出父类的对象,再造出子类的对象,然后用子类对象与父类对象的同名方法去对父类的方法进行覆盖,但是static声明的方法属于类,不需要实例化即可使用(但实例化化以后也可以使用,这该如何解释?这样的说法有点牵强,不过现在只能理解为:static跟重写没关系!),也就谈不上实例化的继承和覆盖了!,参考内存图!) - 引出了一个问题:继承和static的关系:(待补充!)
- IEDA 神器插件-----------> 彩虹括号(方便辨别!)
面对对象——接口
接口的概念:
- 概念引出:
继续回到我们的猫狗案例,我们想想狗一般就是看门,猫一般就是作为宠物了。
但是,现在有很多的驯养员或者是驯兽师,可以训练出:猫钻火圈,狗跳高,狗做计算等。
而这些额外的动作,并不是所有猫或者狗一开始就具备的,这应该属于经过特殊的培训训练出来的。
所以,这些额外的动作定义到动物类中就不合适,也不适合直接定义到猫或者狗中,因为只有部分猫狗具备这些功能。
所以,为了体现事物功能的扩展性,Java中就提供了接口来定义这些额外功能,并不给出具体实现,将来哪些猫狗需要被培训,只需要这部分猫狗把这些额外功能实现即可 - 简单来说:用来定义实物的一些额外的扩展功能,将来哪类实物,想要具备,这些额外的功能,就可以实现这个接口
- 定义接口的语法:
interface 接口名{}
- 使用接口的语法:
一般地,这个类就是这个接口的子类,这个接口也可以叫做这个类的父接口class 类 implements 接口名{} (这是一种实现关系!)
接口的特点:
- 接口不能直接实例化
那么,接口如何实例化呢?按照多态的方式来实例化。 - 接口没有构造方法这一说
- 接口的子类有什么要求:
- 可以是抽象类。但是意义不大。
- 可以是具体类。要重写接口中的所有抽象方法。(推荐方案)
- 如果你不想重写,你这个类可以作为一个抽象类,将接口中的抽象方法继承下来即可(一般不推荐这么做,没啥意义!)1的细化描述!
- 接口中的方法存在默认修饰符 public abstract
示例:interface AA{ public abstract void aa(); void aa(); //这个与上面其实是一样的,二者取其一即可! }
- 接口的使用示例:
public class MyTest { public static void main(String[] args) { //接口不能实例化,接口里面没有构造方法 //作为接口的子类,有什么要求 //1.要求子类必须重写接口中所有的抽象方法 //2.如果你不想重写,你这个类可以为一个抽象类,将接口中的抽象方法继承即可 } } interface AA{ public abstract void aa(); void aaa();//接口中的方法,前面存在默认修饰 public abstract } class EE implements AA{ @Override public void aa() { } @Override public void aaa() { } //实现接口中的方法 ctrl+I } abstract class RR implements AA{ } abstract class QQ extends RR{ }
接口中的成员特点:
- 接口中的成员变量:
- 接口中的成员变量全是公共的静态常量(只能是常量)
- 接口中的成员变量前面存在默认修饰符 public static final(建议自己手动给出)
- 接口中的成员变量如何使用?(使用多态的方式来访问)
- 一个小规律:多态的好处就是可以访问那些不能直接实例化的类的对象中的成员属性!
- 接口中的成员方法:
- 接口中的方法存在默认修饰符 public abstract
- 接口中没有构造方法!
- 案例演示:
public class MyTest { public static void main(String[] args) { //接口中的成员特点 //接口中的成员变量:接口中的成员变量全是公共的静态常量 //接口中的成员方法,全部是抽象方法,,不存在非抽象方法 //接口中没有构造方法 int num = MyInterface.NUM;//直接访问 System.out.println(num); NN nn = new NN(); System.out.println(nn.NUM);//多态访问 System.out.println(MyInterface.A);//直接访问 System.out.println(nn.A);//多态访问 } } interface MyInterface { public static final int NUM = 200; int A = 600; //接口中成员变量 前面存在默认修饰符 public static final public abstract void hehe(); //方法存在默认修饰符 public abstract } class NN implements MyInterface { @Override public void hehe() { System.out.println("hehe"); } } ------------------------- 输出: 200 200 600 600
接口的示例:
- 接口:
public interface JumpInterface { void jump(); }
- 抽象类:
public abstract class Animal { public String name; public int age; public abstract void eat(); public abstract void sleep(); }
- Cat类:
public class Cat extends Animal{ @Override public void eat() { System.out.println("吃饭"); } @Override public void sleep() { System.out.println("睡觉"); } }
- Dog类:
public class Dog extends Animal{ @Override public void eat() { System.out.println("吃饭"); } @Override public void sleep() { System.out.println("睡觉"); } }
- 加菲猫类:
public class 加菲 extends Cat implements JumpInteface { @Override public void eat() { System.out.println("加菲猫吃猫粮"); } @Override public void sleep() { System.out.println("加菲猫想睡就睡"); } @Override public void jump() { System.out.println("加菲猫学会了调高"); } }
- 布鲁斯类:
public class 布鲁斯 extends Dog implements JumpInteface { @Override public void eat() { System.out.println("布鲁斯吃牛排"); } @Override public void sleep() { System.out.println("布鲁斯睡沙发"); } public void watchTV(){ System.out.println("看电视"); } @Override public void jump() { System.out.println("布鲁斯学会了调高"); } }
- 旺财类:
public class 旺财 extends Dog { @Override public void eat() { System.out.println("旺财爱吃骨头"); } @Override public void sleep() { System.out.println("旺财天天睡觉"); } public void lookDoor(){ System.out.println("旺财看门"); } }
- 胖橘类:
public class 胖橘 extends Cat{ @Override public void eat() { System.out.println("猫吃小鱼干"); } @Override public void sleep() { System.out.println("胖橘白天睡觉"); } public void catchMouse(){ System.out.println("胖橘抓老鼠 桔子 橘子"); } }
- 主函数:
public class MyTest { public static void main(String[] args) { /* A: 案例演示 动物类:姓名,年龄,吃饭,睡觉。 动物培训接口:跳高 猫继承动物类 狗继承动物类 部分猫继承猫类并实现跳高接口 部分狗继承狗类并实现跳高接口*/ 旺财 wc = new 旺财(); Animal an = wc; an.name="旺财"; an.age=20; System.out.println(an.name); System.out.println(an.age); an.sleep(); an.eat(); ((旺财) an).lookDoor(); 布鲁斯 bls = new 布鲁斯(); an=bls; an.name="布鲁斯"; an.age=58; System.out.println(an.name); System.out.println(an.age); an.eat(); an.sleep(); JumpInteface jumpInteface= bls; jumpInteface.jump(); } } ----------------------------------------------- 输出: 旺财 20 旺财天天睡觉 旺财爱吃骨头 旺财看门 布鲁斯 58 布鲁斯吃牛排 布鲁斯睡沙发 布鲁斯学会了调高
类与类,类与接口,接口与接口的关系:
- 类与类的关系:继承关系 extends Java中只支持单继承(可以多层继承)
- 类与接口的关系:实现关系 implements 可以多实现 一个类可以实现多个接口(自然可以单实现),并且还可以在继承一个类的同时实现多个接口。
示例:
继承的同时,也要实现接口!class MyClass implements AA,BB,CC{ }
class Zi extends MM implements AA,BB{ @Override public void aa() { } @Override public void bb() { } }
- 接口与接口之间的关系:继承关系 extends 支持多继承 一个接口可以继承多个接口(自然支持单继承)
示例:interface CCC extends AAA,BBB{ }
- JDK 1.8 允许接口的方法有功能上的实现,但这个方法用default来修饰
其引申的意思是:JAVA用接口上的多实现弥补了JAVA类不支持多继承的弊端。
面对对象——抽象类和接口的区别:
-
成员区别:
a.抽象类:
成员变量:可以变量,也可以常量
构造方法:有
成员方法:可以抽象,也可以非抽象
b.接口:
成员变量:只可以常量
成员方法:只可以抽象 -
关系区别:
a. 类与类
继承,单继承
a. 类与接口
实现,单实现,多实现
c. 接口与接口
继承,单继承,多继承 -
设计理念区别:
a. 抽象类 被继承体现的是:”is a”的关系。 抽象类中定义的是该继承体系的共性功能。
b. 接口 被实现体现的是:”like a”的关系。 接口中定义的是该继承体系的扩展功能。