Java 面向对象进阶(3)

抽象类和抽象方法

  • 抽象方法:将共性的行为抽取到父类之后,由于每一个子类执行的内容是不一样的,所以在父类中不能确定具体的方法体,该方法就可以定义为抽象方法
  • 抽象类:如果一个类中存在抽象方法,那么该类就必须声明为抽象类

抽象类的定义格式

public abstract class 类名{}

抽象方法的定义格式

public abstract 返回值类型 方法名(参数列表);
没有方法体,直接;结束

注意事项

  • 抽象类不能实例化,也就是不能创建对象
  • 抽象类中不一定有抽象方法,有抽象方法的类一定是抽象类
  • 抽象类可以有构造方法
    这里的构造方法的作用:当创建子类对象的时候,给属性进行赋值的
  • 抽象类的子类
    a. 要么重写抽象类中的所有抽象方法
    b. 要么子类本身也是一个抽象类

抽象类在实际开发中有何意义

规范代码
子类必须强制以某种格式重写,否则会报错

接口

  • 就是一种规则,是对行为的抽象
  • 与抽象类的异同:接口更侧重于行为,而抽象类更侧重于事物

定义接口和使用

  • 使用关键字interface定义
    public interface 接口名 {}
  • 接口不能实例化
  • 接口和类之间是实现关系,通过implements关键字表示
    public class 类名 implements 接口名 {}
  • 接口的子类,叫做实现类
    a. 要么重写接口中的所有抽象方法(常用)
    b. 要么本身是抽象类

注意

  1. 接口与类之间是实现关系,可以单实现,也可以多实现。
    public class 类名 implements 接口名1, 接口名2 {}
  2. 实现类在继承一个类的同时实现多个接口
    public class 类名 extends 父类 implements 接口名1, 接口名2 {}

接口中成员的特点

  • 成员变量
    只能是常量
    默认修饰符:public static final
  • 构造方法
    没有,因为接口不能创建对象,所以没有构造方法
  • 成员方法
    只能是抽象方法
    默认修饰符:public abstract
    a. JDK7以前:接口中只能定义抽象方法
    b. JDK8新特性:接口中可以定义有方法体的方法
    c. JDK9新特性:接口中可以定义私有方法
  • 示例:
public interace InterfaceDemo {
 // 定义成员变量
 int a = 10; // 默认是public static abstract修饰
 //等于
 public static final int a = 10;

 //定义成员方法
 void show(); // 默认是public abstract修饰
 // 等于
 public public static show();
} 

接口和类之间的关系

类和类的关系

继承关系。只能单继承,不能多继承,但是可以多层继承

类和接口的关系

实现关系。可以单实现,也可以多实现,还可以在继承一个类的同时实现多个接口

如果多个接口中有同名的抽象方法怎么办?
只用重写一次

接口和接口的关系

继承关系,可以单继承,也可以多继承
细节:如果实现类实现了最下面的子接口,那么就需要重写所有的抽象方法

小练习:

描述:

# 编写带有接口和抽象类的标准Javabean类

乒乓球运动员和篮球运动员,乒乓球教练和篮球教练
跟乒乓球相关的人员需要学习英语

乒乓球运动员:姓名、年龄、学习打乒乓球、说英语
篮球运动员:姓名、年龄、学习打篮球
乒乓球教练:姓名、年龄、教打乒乓球、说英语
篮球教练:姓名、年龄、教打篮球

分析:

分析:接口类--->说英语
Javabean类:
1. Person(抽象类)
    属性:name、age
    方法:构造方法、get和set
2. 运动员(抽象类)
    属性:继承Person
    方法:构造方法、抽象方法--->学习 
3. 教练(抽象类)
    属性:继承Person
    方法:构造方法、抽象方法--->教
4. 乒乓球运动员:
    属性:继承Sporter,实现Speak接口
    方法:重写study和speak
5. 篮球运动员
   属性:继承Sporter
   方法:重写study
6. 乒乓球教练
   属性:教练Coach,实现Speak接口
   方法:重写teach和speak
7. 篮球教练
   属性:教练Coach
   方法:重写teach

实现:
根据分析实现,此处省略

关于接口的扩展

JDK8开始接口中新增的方法

一、JDK8之后,接口中可以定义有方法体的方法(默认、静态)

  • 允许接口中定义默认方法,需要使用关键字default修饰
    作用:解决接口升级的问题
    接口中默认方法的定义格式:public default void show(...args){...}
    接口中默认方法的注意事项:
    a. 默认方法不是抽象方法,所以不强制被重写。但是如果被重写,重写的时候去掉default关键字
    b. public可以省略,但是default不可以省略
    c. 如果实现了多个接口,多个接口中存在相同名字的默认方法,就必须对该方法进行重写
  • 允许在接口中定义静态方法,需要用static修饰
    接口中静态方法的定义格式:public static void show(..args){...}
    接口中静态方法的注意事项:
    a. 只能通过接口名调用,不能通过实现类名或对象名调用
    b. public可以省略,static不能省略
    c. 静态方法是不需要重写的
    二、JDK9之后,接口中也可以定义私有方法
    只为接口内部提供服务
    定义格式:
  • 格式1:private void show(){} 为默认方法服务的
  • 格式2:private static void method(){} 为静态方法服务的

接口的应用

  • 把多个类都有可能用到的规则都设计成接口。对于实现类来讲,想要实现类有什么功能,就实现对应的接口
  • 在定义方法的时候,将参数定义为一个接口类型,那么这个方法就可以接受该接口的所有实现类作为参数。这种方式称为接口多态
    例如:
// 方法定义
public void show(Impel imp){
	...
}
// 方法调用--->Impel imp = new ClassImpel()--->接口的多态
ClassImpel kkk = new ClassImpel();
show(kkk)
// 这个kkk是Impel的实现类对象

适配器设计模式

什么是设计模式?
是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性、程序的重用性
什么是适配器设计模式?
解决接口与接口实现类之间的矛盾问题
具体理解:也就是如果一个接口中存在好多个抽象方法,在实现类中只想要重写其中一个,但是接口的抽象方法都是全部都要重写的。这时就需要用到适配器设计模式
如何实现
a. 新建一个中间类:Xxx(接口名)Adapter,实现接口
b. 对接口中所有的方法进行空实现
c. 在真正的实现类继承这个中间类XxxAdapter并重写用到的那一个方法
注意
这个中间类创建对象是没有意义的,所以一般加上abstract,给写成抽象类,

内部类

类的五大成员:
属性、方法、构造方法、代码块、内部类
什么是内部类?
在一个类的里面,再定义一个类
为什么要内部类?
1.内部类表示的事物是外部类的一部分
2.内部类单独出现没有什么意义
就比如汽车的发动机,发动机就是汽车的一个内部类、ArrayList的迭代器
内部类的访问特点:
1.内部类可以直接访问外部类的成员,包括私有
2.外部类要访问内部类的成员,必须创建对象
示例:

public class Car {
    String carName;
    int carAge;
    String carColor;
	// 在外部不能访问内部类里的成员
	// 例
	public void show(){
		
        System.out.println(engineAge); // 是错误的写法
        // 必须先创建内部类对象
        Engine e = new Engine();
        sout(e.engineAge); 
    }
    class Engine {
        String engineBrand;
        int engineAge;
        
        public void show(){
            System.out.println(carAge);
        }
    }
}

内部类的分类:
1.成员内部类—了解
2.静态内部类—了解
3.局部内部类—了解
4.匿名内部类—掌握

成员内部类

成员内部类的代码如何写

  • 写在成员位置,属于外部类的成员
  • 可以被一些修饰符所修饰,比如:private、空着不写、protected、public、static
  • 成员内部类里面,JDK16之前不能定义静态变量,JDK16之后才可以

如何创建成员内部类的对象

方式一:
在外部类中编写方法,对外提供内部类的对象(一般来讲,只有使用private修饰内部类的时候会使用这种方法)
例:

	private class Inner{
		...
	}
	public Inner getInstance() {
		return new Inner;
	}

方式二:
直接创建:外部类名.内部类名 对象名 = new 外部类对象.内部类对象
例:Outer.Inner oi = new Outer().new Inner()

成员内部类如何获取外部类的成员变量

如果不重名,直接使用即可。
针对重名的情况
例:

package com.day.a02innerclassdemo2;

public class Outer {
    private int a = 10;

    class Inner {
        private int a = 20;
        void show() {
            int a = 30;
            System.out.println(a);  // 内部变量
            System.out.println(this.a);// 内部类的成员变量
            System.out.println(Outer.this.a); // 外部类的成员变量
        }
    }
}

内部类的内存图

内部类对象里会有一个隐藏的this,记录外部类的地址,所以Outer.this记录了外部类对象的地址值
在这里插入图片描述

静态内部类

  • 也是成员内部类的一种
  • 只能访问外部类中的静态变量静态方法。如果要访问非静态的需要创建外部类的对象
    例:

public class Outer {
    int a = 10;
    static int b = 20;

    static class Inner {
        public void show() {
            Outer o = new Outer();  // 创建外部类对象,访问非静态方法
            System.out.println(o.a);
        }
        public static void show2() {
            Outer o = new Outer();  // 创建外部类对象,访问非静态方法
            System.out.println(o.a);
        }
    }
}

创建静态内部类对象的格式:
外部类名.内部类名 对象名 = new 外部类名.内部类名()
例:Outer.Inner oi = new Outer.Inner();
如何调用静态内部类中的方法
1.调用非静态方法的格式: 先创建对象,用对象调用
例: oi.show() 调用非静态方法
2.调用静态方法的格式: 外部类名.内部类名.方法名()
例:Outer.Inner,show2()

局部内部类

1.将内部类定义在方法里面,类似于方法里面的局部变量
2.外界无法直接使用,需要在方法内创建对象并使用
3,可以直接访问外部类的成员,也可以访问方法中的局部变量
例:

public class Outer {
    int b = 20;

    // 局部内部类
    public void show() {
        int a = 10;

        class Inner {
            String name;
            int age;
            public void method1(){
                System.out.println(b);
                System.out.println(a);
                System.out.println("局部内部类中的方法1");
            }
            public static void method2(){
                System.out.println("局部内部类中的方法2");
            }
        }

        // 创建局部内部类的对象
        Inner i = new Inner();

        System.out.println(i.name);
        i.method1();
    }
}

匿名内部类

本质是隐藏了名字的内部类。可以写在成员位置,也可以写在局部位置
格式:

new 类名或接口名(){
	重写方法;
};

格式的细节:
包含了1.继承/实现关系
2.方法的重写
3.创建对象
整体就是一个类的子类对象或者接口的实现类对象
例:

// 先写一个接口Swik,定义一个抽象方法swim
public interface Swim {
    public abstract void swim();
}
// 再写一个测试类
package com.day.a05innerclassdemo5;

public class Test {
    public static void main(String[] args) {
    	// 匿名内部类
        new Swim() {
            // 重写swim中所有的抽象方法
            @Override
            public void swim() {
                System.out.println("重写了Swim中的抽象方法swim");
            }
        };
    }
}

**使用场景:
当方法的参数是接口或者类时
以接口为例:可以传递这个接口的所有实现类对象。如果实现类只使用一次,就可以使用匿名内部类简化代码

  • 9
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值