总体上来讲,抽象类和接口主要使用的就是多态,接口之间可以多继承其间用逗号隔开,类可以实现多个接口,其间都用逗号隔开
目录
1.抽象类
1.什么是抽象类
2.抽象类的作用
3.抽象类怎样创建
4.抽象类里面可以包含什么
5.抽象类的特殊性
6.抽象方法
7.final关键字
2.接口(也是一种类)
1.什么是接口
2.接口的作用:
3.定义一个接口
4.接口的实现
5.接口的继承
6.接口的使用
7.注意
8.综合代码
9.default和static定义的方法
abstract修饰的类就是抽象类
理解的时候就可以理解成:把类进行抽象得到的就是抽象类,就当成对象抽象成类,类抽象成抽象类那样理解就可以
类是对于对象共同属性和行为的抽象
抽象类是类的抽象
正如刚才所说,抽象类是类的抽象,所以不可以直接生成对象,也就是说,其实抽象类不可以实例化。
抽象类天生就是用来被继承的,天生就是爹
【访问权限修饰符】【修饰符】 abstract class 类名{类体}
即在"class"前写一个abstract
eg:public abstract class ChouXiang(){}
1.构造方法:
虽然抽象类不能实例化无法进行对象的创建,但是它有构造方法,是为子类创建对象用的,子类实例化对象的时候会使用super调用父类这个构造方法
2.属性
3.方法
4.抽象方法
抽象类具有抽象方法
包含抽象方法的类必须是抽象类
1.什么是抽象方法
被abstract修饰的方法就是抽象方法
特征:没有方法体和那个大括号
2.抽象方法的作用(又或者说为什么要用抽象方法):
由于一些方法的实用性不高,比如如果人类和猫类都继承了动物的行走行为,此时动物类是抽象类,人类和猫类都是普通的类,由于行走这个行为对人而言是双脚走,对猫而言是四脚着地,所以此时不同的方法应用下来就不一样了,就需要使用抽象方法,先定义出来这个方法再根据不同的子类来重写各自的方法(记住使用@Override)
3.形式:
【访问权限修饰符】 【修饰符】 abstract 返回值 方法名(形参列表);
对于抽象方法而言,不需要写方法体,包括那个大括号也不用写,只需要定义出来就可以,这种格式就像是c语言先定义,然后再写方法体一样,只不过java是在子类当中重写方法体
4.在写了抽象方法之后一定要进行所有抽象方法的重写(除非子类也是抽象类)
5.重写抽象类的时候要把abstract去掉的同时加上方法体和大括号
6.抽象类里面不一定有抽象方法,也就是说,可以但没必要
7.普通的类里面的方法不一定有方法体,例如用native修饰的内容可以没有方法体,而是去调用底层C语言,也就是说普通类里的方法不一定都有方法体,
即普通类里的方法一定有方法体 ( X )。
8.final修饰的方法不可能是抽象方法,final修饰的类不能被继承,也就是说final和abstract不能同时出现
一个账户包括账号密码和余额,还有一个打印余额的方法
工行和农行都使用了这个账户的内容
public abstract class Account {
private String accountNum;
private String password;
private int money;
public Account(){
}
public Account(String accountNum,String password){
this.password = password;
this.accountNum = accountNum;
}
public String getAccountNum(){
return accountNum;
}
public String getPassword() {
return password;
}
public int getMoney() {
return money;
}
public void setAccountNum(String accountNum){
this.accountNum = accountNum;
}
public void setPassword(String password){
this.password = password;
}
public void setMoney(int money) {
this.money = money;
}
public abstract void showMoney();
}
public class Credit extends Account{
public Credit(){
}
public Credit(String accountNum,String password){
super(accountNum,password);
}
@Override
public void showMoney(){
System.out.println("当前工行余额为:"+super.getMoney());
}
}
public class CreditNongHang extends Account{
public CreditNongHang(){
}
public CreditNongHang(String accountNum,String password){
super(accountNum,password);
}
@Override
public void showMoney(){
System.out.println("当前农行余额为:"+super.getMoney());
}
}
public class Test {
public static void main(String[] args) {
Account a = new Credit("123","123");
Account b = new CreditNongHang("123","123");
a.setMoney(500000);
b.setMoney(400000);
a.showMoney();
b.showMoney();
}
}
1.是个修饰符
2.修饰内容:
修饰类:该类无法被继承
修饰方法:该方法无法被重写
修饰成员变量:使成员变成常量无法被更改,此时一定要在类里面给这个常量进行赋值,否则会发生报错,因为按常理的:不赋值的话JVM会给默认数据,无法再更改,但是成员属性就是程序员要规定的内容,不认为规定数据就失去了成员变量原有的意义,所以SUN公司不对final修饰的常量赋初值
修饰局部变量(形参列表和方法体内的变量都是局部变量):使得该变量无法被更改
现实当中某些类出现了本不属于自己的方法,例如猫跳圈,老虎钻火圈,像是这种额外的方法,就需要用接口来写下来,然后让这些普通类来实现
接口是一个特殊的抽象类,他只包括抽象方法和常量,不可以包括普通的方法(jdk1.8之后加上某些关键字也可以包括普通方法)(接口的抽象方法加上个default修饰后可以写方法体,这个default不是前面包和权限的(default),这个default是一个切实存在的关键字)
接口没有构造方法
接口可以理解成行为的抽象,只关注行为,不关注完成这个行为的对象是否合理,就比如抽象方法是写字,一个杯子实现了这个接口,那么杯子就会重写抽象方法,但是杯子的对象难道能写字?所以说不合理,但是我依旧是让这个杯子类实现了这个接口,也就是说我这个接口根本不在乎对象的合理性,只在乎一个行为
public interface 接口名 { 常量; 抽象方法; }
接口也是抽象类的一种,不能够直接创建对象,所以它需要有实现这个接口的类,接口不可以被类继承,只可以被接口继承
使用implements实现接口,在一个类当中可以实现多个接口但是这些接口必须要用逗号间隔开
public class Anmail implements Fly,Run{
@Override
public void fly(){
System.out.println("在飞");
}
public void run(){
System.out.println("在跑");
}
}
如果一个类又有继承又有实现,那么就先继承后实现
如果继承了一个实现了接口的父类,那么此时这个子类不需要再重写抽象方法(这个是考虑子类既有继承又有实现的情况,如果子类和父类实现了同一个接口,而且父类已经重写了这个接口的抽象方法,那么子类就没必要重写了,可以但没必要)
public class Cat extends Anmail implements Run{
//之所以这里让猫飞是为了让理解一下接口的作用,即不考虑对象的合理性,本不属于该类的行为赋予给了这个类
@Override
public void fly(){
System.out.println("猫在飞");
}
//此处不报错,说明由于在Anmail中重写了run抽象方法所以此处就不用重写了
}
在接口的实现类当中必须重写所有的抽象方法(default修饰的抽象方法可以不重写)
接口只可以继承接口,接口不可以继承类也不可以被类继承,甚至不可以继承Object
(接口如果继承类的话那么就会有普通的方法了,就不想原先那样纯粹只有抽象方法和常量了)
一个接口可以继承多个接口,虽然类是单继承的,但是接口是多继承的(这和没有构造方法有一定意义的关系)
public interface MoveWay extends Run,Fly{
//这里是体现接口的多继承
}
接口虽然不能继承被继承但是可以被实现,在使用接口的时候也是使用多态,此时虽然接口不是父类,但是可以当作父类来使用。
如果说两个接口的都被同一个子类实现了,那么这两个接口创建出来的“引用”在instanceof的比较下为true,因为instanceof是看某一个引用是否可以转化为另一个类的引用,由于接口1和接口2都被类1实现了,此时可以理解为接口1先转成类1再转成接口二
public class Test {
public static void main(String[] args) {
Fly a = new Cat();
a.fly();//此处是FLy的引用调用Cat的方法
//由于run方法是Cat当中有但是a当中没有的,所以此a需要向下转型转为Cat
if(a instanceof Cat){
((Cat)a).run();//此处就可以调用特有的方法了
}
//由上述内容可见仍然是以多态的方式来使用接口
Fly b = new Anmail();
b.fly();//此处是Fly的引用调用Anmail的方法
System.out.println(a instanceof Anmail);//由于a属于Cat,Cat是Anmail的子类,所以此处是true
System.out.println(b instanceof Cat);//此处毫无影响。直接false
Run c = new Cat();
System.out.print("c");
c.run();
System.out.println(a instanceof Run);
}
}
接口里面的属性和方法都必须是public的,由于这种特性,所以在接口当中public abstract和public final可以不写,这两个东西在编译的时候会自动加上
public interface Fly {
int flyMaxHeight = 500;
void fly();
}
public interface Fly {
public abstract void fly();
}
public interface Run {
void run();
}
public interface MoveWay extends Run,Fly{
//这里是体现接口的多继承
}
public class Anmail implements Fly,Run{
@Override
public void fly(){
System.out.println("在飞");
}
public void run(){
System.out.println("在跑");
}
}
public class Cat extends Anmail implements Run{
//之所以这里让猫飞是为了让理解一下接口的作用,即不考虑对象的合理性,本不属于该类的行为赋予给了这个类
@Override
public void fly(){
System.out.println("猫在飞");
}
//此处不报错,说明由于在Anmail中重写了run抽象方法所以此处就不用重写了
}
public class Test {
public static void main(String[] args) {
Fly a = new Cat();
a.fly();//此处是FLy的引用调用Cat的方法
//由于run方法是Cat当中有但是a当中没有的,所以此a需要向下转型转为Cat
if(a instanceof Cat){
((Cat)a).run();//此处就可以调用特有的方法了
}
//由上述内容可见仍然是以多态的方式来使用接口
Fly b = new Anmail();
b.fly();//此处是Fly的引用调用Anmail的方法
System.out.println(a instanceof Anmail);//由于a属于Cat,Cat是Anmail的子类,所以此处是true
System.out.println(b instanceof Cat);//此处毫无影响。直接false
Run c = new Cat();
System.out.print("c");
c.run();
System.out.println(a instanceof Run);
}
}
static和default放的位置和abstract的位置一样,但是这里的意思是static不可重写而且是静态的方法,default还可以重写(可以但没必要),写了这两种当中的任意一种就不用写abstract了