文章目录
面向对象的继承含义
面向对象的三大特征:封装性、继承性和多态性。
继承是多态的前提,如果没有继承、就没有多态。
举例:
继承关系中,”子类就是一个父类“,也就是说子类也可以当作父类来看。
定义父类的格式:(一个普通的类定义)
public class 父类名称{
//成员函数和成员变量
}
定义子类的格式:(一个普通的类定义)
public class 子类名称 extends 父类名称{
//成员函数和成员变量
}
重点原则
【1】成员变量和成员方法重名,访问有两种方式:
在父子类的继承关系中,如果成员变量重名,则创建子类对象时,访问有两种方式:
【直接】通过子类对象访问成员变量:等号左边是谁,就优先用谁,没有就向上找。
【间接】通过成员方法可以访问成员变量:该方法属于谁,就优先用谁,没有再向上找
举例:
父类:
package cn.itcast.day01.demo05;
import java.lang.reflect.Method;
public class Fu {
int numFu=10;
int num=100;
public void methodFu(){
System.out.println(num);
}
}
子类
package cn.itcast.day01.demo05;
public class Zi extends Fu{
int numZi=20;
int num=200;
public void methodZi(){
System.out.println(num);
}
}
kage cn.itcast.day01.demo05;
public class ExtendsField {
public static void main(String[] args) {
System.out.println("************成员变量**************");
Fu fu=new Fu();
System.out.println(fu.numFu);//10有,自己的】
System.out.println(fu.num);//相同变量【num】【自己】100
Zi zi=new Zi();
System.out.println(zi.numZi);//20
System.out.println(zi.num);//相同变量【num】【自己】200
System.out.println(zi.num);//200
//System.out.println(zi.ccc);//都没有,访问错误
System.out.println("************成员方法**************");
zi.methodZi();//200【属于Zi,结果为Zi】
fu.methodFu();//100【属于F,结果为Fu】
zi.methodFu();//100【属于Fu,结果为Fu】
}
}
【2】同名变量的不同的使用方法
- 局部变量:直接写成员变量名
- 本类的成员变量:this.成员变量
- 父类的成员变量:super.成员变量名
父类:
package cn.itcast.day01.demo05;
import java.lang.reflect.Method;
public class Fu {
int num=10;
}
子类:
package cn.itcast.day01.demo05;
public class Zi extends Fu{
int numZi=20;
public void method(){
int i=30;
System.out.println(num);//30
System.out.println(this.num);//20
System.out.println(super.num);//10
}
}i
主函数:
kage cn.itcast.day01.demo05;
public class ExtendsField {
public static void main(String[] args) {
zi.method();//30,20,10
}
}
【3】同名成员方法的不同使用方法
在父子类的继承关系中,创建子类对象,访问成员方法的规则:
创建的对象是谁,就优先用谁,如果没有则向上找。
注意事项
无论是成员函数还是成员变量,如果没有都是向上找父类,绝对不会向下找子类。
父类:
package cn.itcast.day01.demo05;
import java.lang.reflect.Method;
public class Fu {
public void methodFu(){
System.out.println("父类方法调用");
}
public void method(){
System.out.println("子类方法调用");
}
}
子类:
package cn.itcast.day01.demo05;
public class Zi extends Fu{
int numZi=20;
public void method(){
public void method(){
System.out.println("子类方法调用");
}
public void methodZi(){
System.out.println("子类方法调用");
}
}
主函数:
kage cn.itcast.day01.demo05;
public class ExtendsField {
public static void main(String[] args) {
//创建的是new子类对象,所以优先用子类方法。
zi.method();//子类方法调用
//
zi.methodZi();//子类方法调用
zi.methodFu();//父类方法调用
}
}
方法的重写(Override)
概念:
在继承关系中,方法的名称一样,参数列表也一样。
注意事项:
- 必须保证父子类之间方法的名称相同,参数列表也相同。
- @overdide:写在方法的前面,用来检测是不是有效的覆盖重写。这个注解就算不写也是正确的方法。
- 子类方法的返回值必须【小于等于】父类方法的返回值范围。object类是所有类的公共最高父类,String是object的子类。
- 子类方法的权限必须【大于等于】父类方法的权限修饰符。public>protected>(default)留空>private
什么时候使用
对父类中一个方法的功能进行扩展和增加时,需要创建一个子类对原有的方法进行复写。
举例:
父类:
package cn.itcast.day01.demo05;
public class Phone {
public void call(){
System.out.println("打电话");
}
public void sent(){
System.out.println("发短信");
}
public void show(){
System.out.println("显示号码");
}
}
package cn.itcast.day01.demo05;
public class NewPhone extends Phone {
@Override
public void show(){
super.show();
System.out.println("显示地区");
System.out.println("显示姓名");
}
}
主函数
package cn.itcast.day01.demo05;
public class PhoneDemo {
public static void main(String[] args) {
Phone p=new Phone();
p.call();
p.sent();
p.show();
System.out.println("***************************");
NewPhone np=new NewPhone();
np.show();
np.call();
np.sent();
}
}
运行结果:
打电话
发短信
显示号码
***************************
显示号码
显示地区
显示姓名
打电话
发短信
父子构造方法的访问特点
- 子类构造方法中有一个默认隐含的super()调用;所以一定是先调用的父类构造,后执行的子类构造。
- 子类构造可以通过supper关键字来调用父类重载构造。
- super的父类构造调用,必须是【子类构造方法】的【第一个】语句。不能在一个子类构造中多次调用super()构造.
举例:
父类:
package cn.itcast.day01.demo05;
public class GouzaoFu {
public GouzaoFu(){
System.out.println("父类的无参构造");
}
public GouzaoFu(int num){
System.out.println("父类的有参构造");
}
}
子类:
package cn.itcast.day01.demo05;
public class GouzaoZi extends GouzaoFu{
public GouzaoZi(){
//super();默认是父类的无参构造【其一】
super(20);//可以调用父类的有参构造【其一】
System.out.println("子类的无参构造");
}
public void method(){
//super.();//只能在子类的构造方法中才可以使用
}
}
主函数:
package cn.itcast.day01.demo05;
public class Gouzaodemo {
public static void main(String[] args) {
GouzaoZi zi=new GouzaoZi();
}
}
运行结果:
父类的有参构造
子类的无参构造
super关键字的使用方法
- 在子类的成员方法中,访问父类的成员变量。在子类中, super.【父类】成员变量。
- 在子类的成员方法中,访问父类的成员方法。在子类中,super.【父类】成员方法();
- 在子类的构造方法中,访问父类的构造方法。super()//super(参数)。
举例:
package cn.itcast.day01.demo05;
public class GouzaoZi extends GouzaoFu{
public GouzaoZi(){
//super();默认是父类的无参构造【其一】
super(20);//可以调用父类的有参构造【其一】
System.out.println("子类的无参构造");
}
public void method(){
super.method();
System.out.println(super.num);
//super.();//只能在子类的构造方法中才可以使用
}
public void methodZi(){
System.out.println(super.num);
//super.();//只能在子类的构造方法中才可以使用
}
this关键字的使用方法
- 1.在本类的成员方法中,访问本类的成员变量。
- 2.在本类的成员方法中,访问本类的另一个成员方法。
- 3.在本类的构造方法中,访问本类的另一个构造方法。
- 4.第三种方法中要注意:A—>this(…)调用也必须是构造方法的第一个语句,唯一的一个。B—>super和this两个种构造调用,不能同时使用。
举例:
package cn.itcast.day01.demo05;
public class Zi extends Fu{
int numZi=20;
int num=200;
public Zi(){
this(123);//本类的无参构造调用有参构造【构造方法的重载构造】
}
public Zi(int n){
System.out.println("子类的有参构造"+n);
}
public void methodZi(){
int num=2000;
System.out.println(num);//局部变量2000
System.out.println(this.num);//本类的成员变量200
System.out.println(super.num);//父类的成员变量10
this.show();
}
public void show(){
System.out.println("AAA");
}
}
Super和This的内存情况
接口的含义
接口是一种公共的规范标准。只要符合规范标准,就可以大家通用。例如,USB接口,电源插座。
接口的定义格式
publid interface 接口名称{
//接口内容
}
备注:编译生成的字节码文件仍然是:.Java---->.class文件
接口的内容
如果是Java7,那么接口内容为:
- 常量
- 抽象方法
如果是Java8,还有内容: - 默认方法
- 静态方法
如果Java9,还有内容: - 私有方法
接口的使用步骤:
1.接口不能直接使用,必须有一个“实现类”来【实现】该接口
格式:
继承:public class 类名称 extends 父类名称{//内容}
接口:public class 实现类名称 implements 接口名称{
//内容
}
2.接口的实现类必须覆盖重写(实现)接口所有的抽象方法。
实现:去掉abstract关键字,加上方法体大括号。
3.创建实现类的对象,进行使用。
注意事项:
如果实现类并没有覆盖重写接口中所有的抽象方法,那么这个实现类自己就必须是抽象类。
抽象方法
格式:
public abstract 返回值类型 方法体名称(参数列表);无方法体
抽象类:
package cn.itcast.day01.demo07;
public interface MyInterfaceAbs {
public abstract void abs1();
public void abs2();
abstract void abs3();
void abs4();
}
实现类:
package cn.itcast.day01.demo07;
public class MyInterfaceAbsImpl implements MyInterfaceAbs {
@Override
public void abs1() {System.out.println("抽象方法一实现");
}
@Override
public void abs2() {System.out.println("抽象方法二实现");
}
@Override
public void abs3() {System.out.println("抽象方法三实现");
}
@Override
public void abs4() {System.out.println("抽象方法四实现");
}
}
主函数:
package cn.itcast.day01.demo07;
public class InterfaceDemo {
public static void main(String[] args) {
MyInterfaceAbsImpl impl=new MyInterfaceAbsImpl();
impl.abs1();impl.abs2();
impl.abs3();impl.abs4();
}
}
运行结果:
抽象方法一实现
抽象方法二实现
抽象方法三实现
抽象方法四实现
默认方法
格式:
public default 返回值类型 方法体名称(参数列表){
//方法体
}
- 接口的默认方法,可以通过接口实现类对象,直接调用。//找不到就向接口找该方法。
- 接口的默认方法,也可以被接口实现类进行覆盖重写。//用实现类自己的方法
接口内添加新的默认方法,可以保持实现类内容不变,而且不会出错。
package cn.itcast.day01.demo07;
public interface MyInterfaceAbs {
public abstract void abs1();
public void abs2();
abstract void abs3();
void abs4();
//public abstract void method2();//实现类会有问题,实现类只实现了四个抽象方法
public default void method1(){
System.out.println("这是新添加的默认方法");
}
}
主函数:实现类直接调用默认方法。
package cn.itcast.day01.demo07;
public class InterfaceDemo {
public static void main(String[] args) {
MyInterfaceAbsImpl impl=new MyInterfaceAbsImpl();
impl.abs1();impl.abs2();
impl.abs3();impl.abs4();
impl.defaultmethod1();
}
}
运行结果:
抽象方法一实现
抽象方法二实现
抽象方法三实现
抽象方法四实现
这是新添加的默认方法
静态方法
格式:
public static 返回值类型 方法体名称(参数列表){
//方法体
}//类名称.静态方法
//接口名称.静态方法
接口类:静态方法的添加,实现类没动,直接接口名.静态方法实现。
package cn.itcast.day01.demo07;
public interface MyInterfaceAbs {
public abstract void abs1();
public void abs2();
abstract void abs3();
void abs4();
//public abstract void method2();//实现类会有问题,实现类只实现了四个抽象方法
public default void defaultmethod1(){
System.out.println("这是新添加的默认方法");
}
public static void staticmethod(){
System.out.println("这是新添加的静态方法");
}
}
实现类:
package cn.itcast.day01.demo07;
public class MyInterfaceAbsImpl implements MyInterfaceAbs {
@Override
public void abs1() {System.out.println("抽象方法一实现");
}
@Override
public void abs2() {System.out.println("抽象方法二实现");
}
@Override
public void abs3() {System.out.println("抽象方法三实现");
}
@Override
public void abs4() {System.out.println("抽象方法四实现");
}
}
主函数:直接接口名.静态方法。
package cn.itcast.day01.demo07;
public class InterfaceDemo {
public static void main(String[] args) {
MyInterfaceAbsImpl impl=new MyInterfaceAbsImpl();
impl.abs1();impl.abs2();
impl.abs3();impl.abs4();
impl.defaultmethod1();
MyInterfaceAbs.staticmethod();
}
}
抽象方法一实现
抽象方法二实现
抽象方法三实现
抽象方法四实现
这是新添加的默认方法
这是新添加的静态方法
私有方法
问题描述:我们需要抽取一个共有方法,来解决两个默认方法之间代码重复的问题。
但是这个共有方法不应该让实现类使用,应该进行私有化。
java 9开始,接口当中允许定义私有方法。
package cn.itcast.day01.demo07;
public interface MyInterFacePrivate {
public default void methodDefault1(){
System.out.println("默认方法1");
comment();
}
public default void methodDefault2(){
System.out.println("默认方法2");
comment();
}
public default void comment(){
System.out.println("AAA");
System.out.println("BBB");
System.out.println("CCC");
}
}
- 普通私有方法,解决多个默认方法之间的代码重复问题;格式:private 返回值类型 方法名称(参数列表){ //方法体}
- 静态私有方法,解决多个静态方法之间的代码重复问题;格式:private static 返回值类型 方法名称(参数列表){ //方法体}
举例:
package cn.itcast.day01.demo07;
public interface MyInterFacePrivate {
public default void methodDefault1(){
System.out.println("默认方法1");
comment();
}
public default void methodDefault2(){
System.out.println("默认方法2");
comment();
}
private void comment(){
System.out.println("AAA");
System.out.println("BBB");
System.out.println("CCC");
}
public static void methodDefault1(){
System.out.println("默认方法1");
comment();
}
public static void methodDefault2(){
System.out.println("默认方法2");
comment();
}
private void comment2(){
System.out.println("DDD");
System.out.println("EEE");
System.out.println("TTT");
}
}
成员变量
接口当中也可以定义”成员变量“,但是必须使用 public static final三个关键字进行修饰。
从效果上看,就是接口的【常量】
格式:
piblic static final 数据类型 常量名称(完全大写)=数据值;
备注:
一旦使用了final关键字进行修饰,将永远改变不了。
注意事项:
- 接口当中的常量,可以【省略】public static final,注意:不写也照样是这样
- 接口当中的常量,必须【赋值】。
- 接口当中的常量名称,使用完全【大写字母】,用【下划线】进行分隔(推荐)
使用方法:
接口名称.常量。
接口使用的注意事项
- 没有静态代码块或者构造方法的。
格式:
static{//只执行一次,初始化类中的初始变量,优先于构造函数。
}
public MyInterfaceA(){} - 一个类的直接父类只有一个,但是一个类可以同时实现多个接口。
格式:
public class MyInterfaceImpl implements MyinterfaceA,MyinterfaceA{
//覆盖重写所有的抽象方法
} - 如果实现类,在实现多个接口,但是多个抽象接口的【抽象方法】重名,只需要重写一个重名抽象方法就可以。
- 如果实现类没有覆盖重写所有的接口当中的抽象方法,那么实现类就必须是一个抽象类。
- 如果实现类实现的多个接口当中,存在的重复【默认方法】,那么实现类一定要对冲突的默认方法进行覆盖重写。
- 一个类如果直接父类当中的方法,和接口当中的默认方法,产生了冲突,优先用父类的方法。
接口A
package cn.itcast.day01.demo07;
public interface MyInterfaceA {
public abstract void mathod1();
public abstract void abs();
public default void defaultmethod(){
System.out.println("接口A的默认方法");
}
}
接口B
package cn.itcast.day01.demo07;
public interface MyInterfaceB {
public abstract void mathod2();
public abstract void abs();
public default void defaultmethod(){
System.out.println("接口B的默认方法");
}
}
实现类:
package cn.itcast.day01.demo07;
public class MyInterfaceABimpl implements MyInterfaceA,MyInterfaceB{
@Override
public void mathod1() {
System.out.println("覆盖重写了1方法");
}
@Override
public void mathod2() {
System.out.println("覆盖重写了2方法");
}
@Override
public void abs() {
System.out.println("覆盖重写了A和B接口都有的【抽象方法】abs");
}
@Override
public void defaultmethod() {
System.out.println("对多个接口当中冲突的【默认方法】进行了覆盖重写");
}
}
类和接口之间的关系
- 类和类之间是单继承的。直接父类只有一个。
- 类和接口之间是多实现的。一个类可以实现多个接口。
- 接口和接口之间是多继承的。
注意事项:
多个父接口当中的【抽象方法】如果重复了,没关系。【抽象方法没有方法体】
多个父接口当中的【默认方法]如果重复了,有关系。那么子接口必须进行默认方法的覆盖重写,而且带着【default】关键字。
接口A
package cn.itcast.day01.demo07;
public interface MyInterfaceA {
public abstract void mathod1();
public abstract void abs();A
public default void defaultmethod(){
System.out.println("接口A的默认方法");
}
}
接口B
package cn.itcast.day01.demo07;
public interface C {
public abstract void mathod2();
public abstract void abs();
public default void defaultmethod(){
System.out.println("接口B的默认方法");
}
}
接口C:拥有四种方法,继承了三个,自己还有一个
package cn.itcast.day01.demo07;
public interface MyInterfaceC extends MyInterfaceA, MyInterfaceB {
public abstract void mathod();
}
实现类:有四个重写方法,继承了子接口。
package cn.itcast.day01.demo07;
public class MyInterfaceABimpl implements MyInterface{
@Override
public void mathod1() {
System.out.println("A覆盖重写了1方法");
}
@OverrideA
public void mathod2() {
System.out.println("B覆盖重写了2方法");
}
@Override
public void abs() {
System.out.println("覆盖重写了A和B接口都有的【抽象方法】abs");
}
@Override
public void method() {
System.out.println("覆盖重写方法");
}
@Override
public default void defaultmethod(){
System.out.println("带着子接口【default】关键字,对默认方法进行覆盖重写");
}
}