一、继承
-
面向对象的三大特征:封装性、继承性、多态性
- 继承是多态的前提,如果没有继承就没有多态
- 继承主要解决的问题就是:共性抽取
- 共性抽取的类叫做父类,也叫基类、超类。子类也叫派生类。
- 继承关系的特点:1.子类可以拥有父类的内容。2.继承还可以有自己专有的内容。
- 在继承的关系中,”子类就是一个父类“。也就是说子类也可以被当做父类看待。
- 定义子类的格式:public class 子类名称 extends 父类名称{ ... ... }
- 在父子类的继承关系当中,如果成员变量重名,则创建子类对象时,访问有两种方式:1.直接通过子类对象访问成员变量。谁调用的成员变量就看谁创建时等号左边是谁,就优先用谁,没有则向上找。2.间接通过成员方法访问成员变量,该方法属于谁,就优先用谁,没有则向上找。
-
public class Fu{ int num = 100; public void methodFu(){ System.out.println(num); } } public class Zi extends Fu{ int num = 200; public void methodZi(){ System.out.println(num); } } public class Test{ public static void main(String[] args){ Fu fu = new Fu(); Zi zi = new Zi(); zi.methodFu();// 输出100 } }
- 局部变量、本类的成员变量、父类的成员变量重名问题:局部变量直接写,本类的成员变量用this.本类的成员变量,父类的成员变量用super.父类成员变量。
-
在父子类的继承关系当中,创建子类对象,访问成员方法的规则:创建对象的是谁,就优先用谁,如果没有则向上找。无论成员方法还是成员变量,如果没有都是向上找父类,不会向下找子类。
-
重写(override):在继承关系当中,方法的名称一样,参数列表也一样,也叫覆盖、复写。重载(overload)是方法名称一样,参数列表不一样。
-
方法覆盖重写的特点:创建的是子类对象,则优先用子类方法。
-
方法覆盖重写的注意事项:1.必须保证父子类方法的名称相同,参数列表也一样。在子类覆写的方法前可以加@override注解,用来检查方法名称和参数列表是否一样。该注解是一种可选的安全检测选项,不写也不会报错。2.子类方法的返回值必须小于等于父类方法的返回值范围。Object类是所有类的公共最高父类(祖宗类),即子类的返回值类型要么和父类一样,要么是父类返回值类型的子类。比如父类返回值类型是Object,子类可以是String,但是颠倒不行。3.子类方法的权限必须大于等于父类方法的权限修饰符。权限从大到小依旧是:public、protected、什么都不写、private。
-
对于已经投入使用的类,尽量不要进行修改。推荐定义一个新的类,来重复利用其中共性内容,并且添加改动新的内容。在子类覆写的方法中,先通过super.父类的方法调用父类的方法。
-
继承关系中,父子类构造方法的访问特点:1.子类构造方法中有一个默认隐含的super()调用,所以一定是先调用父类构造,再调用子类构造。2.可以通过super关键字来调用父类重载构造。3.super的父类构造调用,必须是子类构造方法的第一个语句。不能子类构造方法中调用多次super构造。总的来说,子类必须调用父类构造方法,不写则赠送super(),写了则使用写的super构造。
-
super关键字的三种用法:1.在子类的成员方法中,访问父类的成员变量。2.在子类的成员方法中,访问父类的成员方法。3.在子类的构造方法中,访问父类的构造方法。
-
this关键字的三种用法:1.在本类的成员方法中,访问本类的成员变量。2.在本类的成员方法中,访问本类的另一个成员方法。3.在本类的构造方法中,访问本类的另一个构造方法。要注意this(...)调用本类的构造方法也必须是第一个语句。通过this调用本类的其他构造方法时,默认的super()也不在赠送,并且也不能自行通过super关键字调用父类的构造方法。即super和this两种构造调用,不能同时使用。
-
-
二、抽象
-
抽象方法就是加上abstract关键字,然后去掉大括号,直接分号结束。抽象方法所在类,必须是抽象类才行。在class之前写上abstract即可。
-
抽象方法格式:public abstract class Animal { public abstract void eat(); }
-
如何使用抽象类和抽象方法。1.不能直接new抽象类对象。2.必须用一个子类来继承抽象父类。3.子类必须覆盖重写抽象父类当中所有的抽象方法。即子类去掉父类抽象方法中的abstract关键字,然后补上方法体大括号。4.创建子类对象进行使用。
-
抽象类和抽象方法的注意事项:抽象类不能创建对象,如果创建,编译无法通过而报错。只能创建其非抽象子类的对象。2.抽象类中吗,可以有构造方法,是供子类对象创建时,初始化父类成员使用的。3.抽象类中,不一定包含抽象方法,但是有抽象方法的类必定是抽象类。4.抽象类的子类,必须重写抽象父类中所有的抽象方法,否则,编译无法通过而报错。除非该子类也是抽象类。
三、接口
- 生活中的接口就是一种公共的规范标准。只要符合规范标准,就可以大家通用。
- 代码中,接口就是多个类的公共规范。
- 接口是一种引用数据类型,最重要的内容就是其中的抽象方法。
- 接口定义规范:public interface 接口名称 { 接口内容 }
- 接口编译生成的字节码文件格式任然是.class文件。
- 在java7中,接口中可以包含常量、抽象方法。java8开始还可以包含默认方法和静态方法,java9开始还可以包含私有方法。
- 接口中抽象方法的定义:
public interface MyInterfaceAbstract { public abstract void methodAbs(); }
接口中的抽象方法,修饰符必须是两个固定的关键字:public和abstract。这两个关键字修饰符可以选择性的省略。方法的三要素可以随意定义。
- 接口使用的步骤:1.接口不能直接使用,必须有个“实现类”来“实现”该接口。实现的具体格式为:
public class 实现类名称 implements 接口名称{ // ... ... }
- 接口的实现类必须覆盖重写(实现)接口中的所有抽象方法。实现:去掉abstract关键字,加上方法体大括号。然后可以创建实现类实例。
- 如果实现类并没有覆盖重写接口中的所有抽象方法,那么这个实现类必须是抽象类。
- 从java8开始,接口里可以定义默认方法,格式为:
public interface MyInterface { public default 返回值类型 方法名称(参数列表); }
抽象当中的默认方法,可以解决接口升级的问题。
- 接口的默认方法会被实现类继承,实现类对象可以直接调用默认方法。调用默认方法,如果实现类中没有,会向上找到接口中的默认方法。接口的默认方法,也可以被实现类覆盖重写。
- 从java8开始,接口里可以定义静态方法,格式为:
public interface MyInterfaceStatic { public static 返回值类型 方法名称(参数列表){ 方法体 } }
就是将abstract或者default替换为static即可,并带上方法体。
- 接口的静态方法无法通过接口的实现类进行直接调用其中的静态方法。只能通过接口名称.静态方法名调用静态方法。
- 从java开始接口里可以定义私有方法,格式为:
public interface MyInterfacePrivateA { private 返回类型 方法名称(参数列表){ 方法体 } }
对于接口中的存在的重复代码,应该抽取出一个共有方法,用来解决两个默认方法之间重复代码的问题。这个共有方法不应该让实现类使用,应该是私有化的。从java9开始,接口中就允许定义私有方法。其中普通私有方法用来解决多个默认方法之间重复代码问题,静态私有方法用来解决多个静态方法之间重复代码问题。
- 接口中可以包含“成员变量”,这个成员变量必须使用public static final三个关键字进行修饰,这三个关键字随意省略,效果是一样的。从效果上看,这其实就是接口的常量,一旦赋值就不可以被修改。接口中的常量必须进行赋值,不能不赋值。
- 访问接口中的常量:接口名称.常量名。常量名称推荐使用全部大写的字母,单子之间通过下划线分开。
- 总结:
- 从java9开始,接口的内容可以有: 1.成员变量其实就是常量,格式: [public][static][final] 数据类型 常量名称 = 数据值; 注意: 常量必须进行赋值,而且一旦赋值不能改变。 常量名称完全大写,用下划线进行分隔。 2.接口中最重要的就是抽象方法,格式: [public][abstract] 返回值类型 方法名称(参数列表); 注意:实现类必须覆盖重写接口的所有抽象方法,除非实现类是抽象类。 3.从java8开始,接口里允许定义默认方法,格式: [public] default 返回值类型 方法名称(参数列表) { 方法体 } 注意:默认方法也可以被覆盖重写。 4.从java8开始,接口里允许定义静态方法,格式: [public] static 返回值类型 方法名称(参数列表) { 方法体 } 注意:应该通过接口名称进行调用,不能通过实现类对象调用静态接口方法。 5.从java9开始,接口里允许定义私有方法,格式: 普通私有方法: private 返回值类型 方法名称(参数列表) { 方法体 } 静态私有方法: private static 返回值类型 方法名称(参数列表) { 方法体 } 注意:private的方法只有接口自己才能调用,不能被实现类或被人使用。 ==================================================================================== - 注意事项: 1.接口没有静态代码块或者构造方法的。 2.一个类的直接父类是唯一的,但是一个类可以同时实现多个接口。 格式:public class MyInetrfaceImpl implements MyInterfaceA,MyInterfaceB { 覆盖重写两个接口里的所有抽象方法 } 3.如果实现类所实现的多个接口中,存在重复的抽象方法,那么只需覆盖重写一次即可。 4.如果实现类没有覆盖重写所有接口中的所有抽象方法,那么实现类必须是一个抽象类。 5.如果实现类所实现的多个接口当中,存在重复的默认方法,那么实现类一定要对冲突的默认方法进行覆盖重写。 6.一个类如果直接父类当中的方法,和接口当中的默认方法产生了冲突,优先用父类当中的方法。java中继承关系是大于实现关系的。 ==================================================================================== 1.类与类之间是单继承的,直接父类只有一个。 2.类与接口之间是多实现的。一个类可以实现多个接口。 3.接口与接口之间是多继承的。 public interface MyInterface extends MyInterfaceA,MyInterfaceB { } 实例化MyInterface的对象要覆写MyInterface、MyInterfaceA、MyInterfaceB所有的抽象方法。 4.多个父接口当中的默认方法如果重复,那么子接口必须进行默认方法的覆盖重写,而且带着default关键字。
四、多态
- extends继承或者implements实现,是多态性的前提。
- 一个对象拥有多种形态,这就是对象的多态性。
- 多态性的定义与格式:
代码中体现多态性就是父类引用过指向子类对象。 父类名称 对象名 = new 子类名称() 接口名称 对象名 = new 实现类名() Fu obj = new Zi(); obj.method();// 优先用子类的method方法
- 多态中,成员变量的访问规则为:1.直接通过对象名称访问成员变量,看等号左边是谁就优先用谁,没有则向上找。2.间接通过成员方法访问成员变量,看该方法属于谁,优先用谁,没有则向上找。如:
public class Fu { int num = 10; public void methodFu(){ System.out.println(num); } public showNum(){ System.out.println(num); } } public class Zi extends Fu { int num = 20; public void methodZi(){ System.out.println(num); } public showNum(){ System.out.println(num); } } pulblic class Test{ public static void main(String[] args){ Fu obj = new Zi(); System.out.println(obj.num); // 此处为父类的num 输出为10 obj.showNum(); // 此处调用的是子类的showNum,输出为20 obj.methodFu(); // 此处调用的是父类的方法,输出为10 } }
多态中调用成员方法,看new的是谁,就优先用谁,没有则向上找。如果子类没有覆盖重写父类方法,调用的是父类的方法,如果子类覆盖重写了父类方法,调用的是子类的方法。成员方法的口诀:编译看左边,运行看右边。成员变量的口诀:编译看左边,运行还看左边。
-
多态的好处:
- 对象的上下转型
向上转型一定是安全的,没有问题的,正确的。但是也有一个弊端:对象一旦向上转型为父类,那么就无法调用子类原本特有的内容。向上转型是自动进行的,比如函数参数是接口类型,可以传实现类,会自动向上转型。向上转型是为了调用父类的方法,向下转型是为了调用子类特有的方法,向下转型之前必须要通过instanceof关键字来判断
- instanceof关键字,格式:对象 instanceof 类名称。用来判断前面的对象能不能当做后面类型的实例。
if (Animal instanceof Cat){ 方法体 }