抽象类、接口及内部类

一、抽象类

1、抽象方法

  • 抽象方法的定义格式:

    public abstract 返回值类型 方法名(参数列表);

  • 抽象类的定义格式:

    public abstract class 类名{}

2、抽象类和抽象方法的注意事项

  • 抽象类不能实列化

  • 抽象类中不一定有抽象方法,有抽象方法的类一定是抽象类

  • 可以有构造方法

  • 抽象类的子类

    • 要么重写抽象类中的所有抽象方法

    • 要么是抽象类

3、抽象类的作用是什么样的?

抽取共性时,无法确定方法体,就把方法定义为抽象的。

强制让子类按照某种格式重写。

抽象方法所在的类,必须时抽象类

二、接口

1、接口的定义和使用

  • 接口用关键字interface来定义

    public interface 接口名{}

  • 接口不能实例化

  • 接口和类之间是实现关系,通过implements关键字表示

public class 类名 implements 接口名{}

  • 接口的子类(实现类)

    • 要么重写接口中的所有抽象方法

    • 要么是抽象类

注意1:接口和类的实现关系,可以单实现,也可以多实现。

public class 类名 implements 接口名1,接口名2{}

注意2:实现类还可以在继承一个类的同时实现多个接口。

public class 类名 extends 父类 implements 接口名1,接口名2{}

2、接口中成员的特点

  • 成员变量

    • 只能是常量

    • 默认修饰符:public static final

  • 构造方法

    • 没有

  • 成员方法

    • 只能是抽象方法

    • 默认修饰符:public abstract

  • JDK7以前:接口中只能定于抽象方法

  • JDK8的新特性:接口中可以定义有方法体的方法。

  • JDK9的新特性:接口中可以定义私有方法。

3、接口和类之间的关系

  • 类和类的关系

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

  • 类和接口的关系

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

  • 接口与接口的关系

    • 继承关系,可以单继承,也可以多继承

练习:编写带有接口和抽象类的标准Javabean类

我们现在有乒乓球运动员和篮球运动员,乒乓球教练和篮球教练

为了出国交流,跟乒乓球相关的人员都需要学习英语。

请用所有知识分析,在这个案例中,哪些是具体类,哪些是抽象类,哪些是接口?

乒乓球运动员:姓名,年龄,学打乒乓球,说英语

篮球运动员:姓名,年龄,学打篮球

乒乓球教练:姓名,年龄,教打乒乓球,说英语

篮球教练:姓名,年龄,教打篮球

人类 

//人类
public abstract class Person {

    private String name;
    private int age;


    public Person() {
    }

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }


    /**
     * 获取
     * @return name
     */
    public String getName() {
        return name;
    }

    /**
     * 设置
     * @param name
     */
    public void setName(String name) {
        this.name = name;
    }

    /**
     * 获取
     * @return age
     */
    public int getAge() {
        return age;
    }

    /**
     * 设置
     * @param age
     */
    public void setAge(int age) {
        this.age = age;
    }

    public String toString() {
        return "Person{name = " + name + ", age = " + age + "}";
    }
}

运动员类 

//运动员类
public abstract class Sporter extends Person{
    public Sporter() {
    }

    public Sporter(String name, int age) {
        super(name, age);
    }

    public abstract void study();
}

教练类

//教练类
public abstract class Coach extends Person{
    public Coach() {
    }

    public Coach(String name, int age) {
        super(name, age);
    }

    public abstract void teach();
}

 说英语的接口

//说英语接口
public interface English {
    public abstract void speakEnglish();
}

乒乓球运动员

//乒乓球运动员
public class PingPangSporter extends Sporter implements English{

    public PingPangSporter() {
    }

    public PingPangSporter(String name, int age) {
        super(name, age);
    }

    @Override
    public void speakEnglish() {
        System.out.println("乒乓球运动员在说英语");
    }

    @Override
    public void study() {
        System.out.println("乒乓球运动员在学习如何打乒乓球");
    }
}

篮球运动员

//篮球运动员
public class BasketballSporter extends Sporter{

    public BasketballSporter() {
    }

    public BasketballSporter(String name, int age) {
        super(name, age);
    }

    @Override
    public void study() {
        System.out.println("篮球运动员在学习如何打篮球");
    }

}

乒乓球教练

//乒乓球教练
public class PingPangCoach extends Coach implements English{
    public PingPangCoach() {
    }

    public PingPangCoach(String name, int age) {
        super(name, age);
    }

    @Override
    public void teach() {
        System.out.println("乒乓球教练正在教如何打乒乓球");
    }

    @Override
    public void speakEnglish() {
        System.out.println("乒乓球在学习说英语");
    }
}

//篮球教练

//篮球教练
public class BasketballCoach extends Coach{

    public BasketballCoach() {
    }

    public BasketballCoach(String name, int age) {
        super(name, age);
    }

    @Override
    public void teach() {
        System.out.println("篮球教练正在教如何打篮球");
    }

}

测试类

//测试类
public class Test {
    public static void main(String[] args) {

        //创建运动员或教练的对象
        PingPangSporter pingPangSporter = new PingPangSporter("刘诗雯",23);
        System.out.println(pingPangSporter.getName() +","+pingPangSporter.getAge());
        pingPangSporter.study();
        pingPangSporter.speakEnglish();

    }
}

JDK8开始接口中新增的方法

  • JDK7以前:接口中只能定义抽象方法。

  • JDK8的新特性:接口中可以定义有方法体的方法。(默认 、静态)

  • JDK9的新特性:接口中可以定义私有方法

JDK8以后接口中新增的方法

  • 允许在接口中定义默认方法,需要使用关键字default修饰

    • 作用:解决接口升级的问题

接口中默认方法的定义格式:

  • 格式:public default 返回值类型 方法名(参数列表){}

  • 范例:public default void show(){}

接口中默认方法的注意事项

  • 默认方法不是抽象方法,所以不强制被重写。但是如果被重写,重写的时候去掉default关键字

  • public可以省略,default不能省略

  • 如果实现了多个接口,多个接口中存在相同名字的默认方法,子类就必须对该方法进行重写

  • 允许在接口中定义定义静态方法,需要用static修饰

接口中静态方法的定义格式:

  • 格式:public static 返回值类型 方法名(参数列表){}

  • 范例:public static void show(){}

接口中静态方法的注意事项

  • 静态方法只能通过接口名调用,不能通过实现类名或者对象名调用

  • public可以省略,static不能省略

 

JDK9新增的方法

接口中私有方法的定义格式:

  • 格式1:private 返回值类型 方法名(参数列表){}

  • 范例1:private void show(){}

  • 格式2:private static 返回值类型 方法名(参数列表){}

  • 范例2:private static void method(){}

public interface Inter{
    public default void show1(){
        System.out.println("show1方法开始执行了");
    }
    
    public static void show2(){
        System.out.println("show2方法开始执行了");
    }
    
    //普通的私有方法,给默认方法服务的
    private void show3(){
        System.out.println("记录程序在运行过程中的各种细节,这里有100行代码");
    }
    
    //静态的私有方法,给静态方法服务的
    private static void show3(){
        System.out.println("记录程序在运行过程中的各种细节,这里有100行代码");
    }
    
}

接口的应用

  1. 接口代表规则,是行为的抽象。想要让那个类拥有一个行为,就让这个类实现对应的接口就可以了。

  2. 当一个方法的参数是接口时,可以传递接口所有实现类的对象,这种方式称之为接口多态。

适配器设计模式

  • 设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性、程序的重用性。

简单理解:设计模式就是各种套路

  • 适配器设计模式:解决接口与接口实现类之间的矛盾问题

  1. 当一个接口中抽象方法过多,但是我只要使用其中一部分的时候,就可以适配器设计模式

  2. 书写步骤:

    • 编写中间类XXXAdapter,实现对应的接口

    • 对接口中的抽象方法进行空实现

    • 让真正的实现类继承中间类,并重写需要用的方法

    • 为了避免其他类创建适配器类的对象,中间的适配器类用abstract进行修饰

三、内部类

类的五大成员:属性、方法、构造方法、代码块、内部类

1、什么是内部类

在一个类的里面,再定义一个类。

举例:在A类的内部定义B类,B类就被称为内部类

public class Outer{	//外部类
    public class Inner{	//内部类
        
    }
}

2、为什么要学习内部类

需求:写一个Javabean类描述汽车。

属性:汽车的品牌,车龄,颜色,发动机的品牌,使用年限。

public class Car{	//外部类
    String carName;
    int carAge;
    int carColor;
    
    //内部类表示的事物是外部类的一部分
    //内部类单独出现没有任何意义
    class Engine{	//内部类
        String engineName;
        int engineAge;
    }
}

内部类的访问特点

  • 内部类可以直接访问外部类的成员,包括私有

  • 外部类要访问内部类的成员,必须创建对象

1、成员内部类(没多大用)

  • 写在成员位置的,属于外部类的成员。

  • 成员内部类可以被一些修饰符所修饰,比如:private,默认,protected,public,static等。

  • 在成员内部类里面,JDK16之前不能定义静态变量,JDK16开始才可以定义静态变量。

public class Car{	//外部类
    String carName;
    int carAge;
    int carColor;

    private class Engine{	//成员内部类
        String engineName;
        int engineAge;
    }
}

获取内部类对象

方式一:

在外部类中编写方法,对外提供内部类的对象(private

方式二:直接创建

格式:外部类名.内部类名 对象名 = 外部类对象.内部类对象;

范例:Outter.Inner oi = new Outer().new Inner();

public class Outer{
    String name;
    
    class Inner{
        
    }
}
//当内部类没有被私有化时
public class Test{
    public static void main(String[] args){
        Outer.Inner oi = new Outer().new Inner();
    }
}
public class Outer{
    String name;
    
    private class Inner{
        
    }
    
    public Inner getInstance(){
        return new Inner();
    }
}
//当内部类被私有化时,可以这样做
public class Test{
    public static void main(String[] args){
        Outer o = new.Outer();	
        //这样可以
        Object Inner = o.getInstance();
        System.out.println(Inner);
        //这样也可以
        System.out.println(o.getInstance());
    }
}

外部类成员和内部类成员变量重名时,在内部类如何访问

public class Outer{
    private int a = 10;
    
    class Inner{
        private int a = 20;
        
        public void show(){
            int a = 30;
            System.out.println(a);	//30
            System.out.println(this.a);	//20
            System.out.println(Outer.this.a);	//10
        }
    }
}

2、静态内部类(没多大用)

静态内部类只能访问外部类中的静态变量和静态方法,如果想要访问非静态的需要创建对象

public class Car{	//外部类
    String carName;
    
    int carAge;
    int carColor;

    static private class Engine{	//静态内部类
        String engineName;
        int engineAge;
    }
}

创建静态内部类对象的格式:外部类名.内部类名 对象名 = new 外部类名.内部类名();

调用非静态方法的格式:先创建对象,用对象调用

调用静态方法的格式:外部类名.内部类名.方法名();

3、局部内部类(没多大用)

  1. 将内部类定义在方法里面就叫做布局内部类,类似于方法里面的局部变量。

  2. 外界是无法直接使用,需要在方法内部创建对象并使用

  3. 该类可以直接访问外部类的成员,也可以访问方法内的局部变量。

public class Outer{
    public void show(){
        int a = 10;
        
        //局部内部类
        class Inner{
            String name;
            int age;
            
            public void method1(){
                System.out.println("局部内部类中的method1方法");
            }
            
            public static void method2(){
                System.out.println("局部内部类中的method2静态方法");
            }
        }
        
        //创建局部内部类的对象
        Inner i = new Inner();
        System.out.println(i.name);
        System.out.println(i.age);
       	i.method2();
        Inner.method2();
        
        
    }
}

4、匿名内部类(重要)

匿名内部类本质上就是隐藏了名字的内部类。

1、什么是匿名内部类?

隐藏了名字的内部类,可以写在成员位置,也可以写在局部位置。

2、匿名内部类

格式:

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

(格式细节)

包含了继承或实现,方法重写,创建对象。

整体就是一个类的子类对象或者接口的实现类对象

举例:

new Inter(){
		public void show(){
            
        }
	};
//接口
public interface Swin{
    public abstract void swim();
}

public class Animal(){
    public abstract void eat();
}

public class Test{
    public static void main(String[] args){
        //编写匿名内部类的代码
        new Swim(){
            @Override
            public void swim(){
                System.out.println("重写了游泳方法");
            }
        };
        new Animal(){
            @Override
            public void eat(){
                System.out.println("重写了吃饭方法");
            }
        };
        
        
        method(
        	new Animal(){
            	@Override
            	public void eat(){
                	System.out.println("狗吃骨头");
          	 	}
    	    }
        );
        
    }
    
    public static void method(Animal a){
        a.eat();
    }
    
}

3、使用场景

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

题外扩展

public interface Swin{
    public abstract void swim();
}

public class Test {

    public static void main(String[] args) {
        /*
        *   回顾一下匿名内部类的格式
        *       new 类/接口(){
        *           重写的方法;
        *       }
        *
        * */

        //整体我们可以理解为Swim接口的实现类对象
        //接口多态
        Swim s = new Swim(){
            @Override
            public void swim() {
                System.out.println("重写之后游泳的方法");
            }
        };

        //编译看左边,运行看右边
        s.swim();


        new Swim(){
            @Override
            public void swim() {
                System.out.println("重写之后游泳的方法");
            }
        }.swim();

    }

}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值