Java——抽象类和接口

简介: 抽象类是一种不能被实例化的类,至少包含一个抽象方法(无实现体的方法),常用于定义一组相关类的共同特征,并强制子类实现特定方法。抽象方法不能被 `static` 或 `final` 修饰,且必须被重写。接口则是一个完全抽象的类,用于规范类的行为。接口使用 `interface` 关键字定义,不能实例化,并且类与接口之间是实现关系。内部类是在一个类内定义的类,分为成员内部类、静态内部类、局部内部类和匿名内部类。成员内部类可被修饰符修饰,静态内部类只能访问外部类的静态成员,局部内部类定义在方法内,匿名内部类则隐藏了名字,直接通过 `new` 关键字定义并实现接口或继承类。

抽象类

抽象类是一种不能被实例化的类,其中至少包含一个抽象方法(即没有实现体的方法)。抽象类通常用于定义一组相关的类的共同特征,并强制其子类实现特定的方法。

抽象方法

将共性的方法抽取到父类之后,由于每个子类执行的内容不一样,所以在父类中不能确定具体的方法体,这样的方法就可以定义成为抽象方法

定义格式:
public abstract 返回值类型 方法名(参数列表);

public abstract void work();

抽象方法不能被static , final 修饰,抽象方法就是为了被重写的
匿名对象的方式调用抽象方法
前提已经写好了work的抽象方法和类的继承关系

public class Text {
    public static void working(Person p){
        p.work();
    }
    public static void main(String[] args) {
        
        Student student = new Student();
        working(student);
        working(student);
        //匿名对象的方式调用方法
        working(new Student());
        working(new Student());
    }
}

普通的调用一个对象可以多次调用方法,匿名对象的方法调用每次调用都创建了对象

抽象类

如果一个类中有抽象方法,这个类就必须声明成抽象类

定义格式:
public abstract class 类名{}

public abstract class Person {
    public abstract void work();
}

注意:
1.抽象类不能实例化对象

2.抽象类中不一定有抽象方法,有抽象方法的类一定要设置成抽象类
3.抽象类可以有构造方法
4.抽象方法的子类要不重写父类的抽象方法,要不自身也是抽象类
那可能就有疑问了,既然抽象类不能实例化对象,那么要构造方法有什么用

通过向上转型的方式创建一个子类对象,通过父类的构造方法初始化子类继承的属性

接口

接口是一个完全抽象的类,用来规范类的行为,

比如有以上的继承关系,根据fish,student,teacher的共性来定义swim的行为,此时swim并不存在任何继承的关系,就可以把它定义为一个接口去被fish,student,teacher实现

接口的实现

1.接口使用关键字interface来定义
public interface 接口名{ }
2.接口不能实例化
3.接口和类是实现关系,通过关键字
implements表示
public class 类名 implements 接口名{}
4.接口的子类要么重写接口中所有的抽象方法,要么是抽象类
5.接口和类之间可以单实现,也可以多实现,接口的出现,弥补了Java不能多继承的缺陷

接口中的成员变量默认是public static final修饰的,用static修饰调用方便,接口名.方法名调用,用》>final修饰,不可更改,所以也说明了接口中定义的是一种规范
接口中的方法是public abstract修饰的
所以说接口的实现类在重写接口的方法时只能用public修饰
接口中不能有代码块和构造方法

如果方法是被default和static修饰的可以有具体的实现

以下就是接口的实现例子:

实现多个接口

以下分别定义好了两个接口

public interface IRun {
    void run();
}
public interface ISwim {
    void swim();
}

Dog类继承Animal类之后再实现两个接口

public class Dog extends Animal implements ISwim,IRun{
     public Dog() {
        super();
    }
    public Dog(String name, int age) {
        super(name, age);
    }
    @Override
    public void run(){
        System.out.println(this.name + "在跑");
    }
    @Override
    public void swim() {
        System.out.println(this.name + "在游泳");
    }
}

测试类实现:

public class Text {
    public static void main(String[] args) {
        running(new Dog("大黄", 3));
        swimming(new Dog("大黄", 3));
    }
    public static void running(IRun iRun){
        iRun.run();
    }
    public static void swimming(ISwim iSwim){
        iSwim.swim();
    }
}

接口与接口的关系

接口和接口之间是继承的关系,可以单继承也可以多继承

interface Ia{
    void showA();
}
interface Ib{
    void showB();
}
interface Ic extends Ia,Ib{
    void showC();
}
class D implements Ic{
    @Override
    public void showA() {
        
    }
    @Override
    public void showB() {
    }
    @Override
    public void showC() {
    }
}
public class Demo {
}

Ic继承了Ia,Ib,同时类D实现了Ic接口,此时Ia,Ib,Ic的方法都需要重写,所以,接口间的继承相当于把多个接口结合在一起

内部类

内部类其实就是一个类里边再定义一个类,表示是外部类的一部分
访问特点:
内部类可以直接访问外部类的成员,包括私有的
外部类要访问内部类的成员,必须创建对象

public class Car {
    String carName;
    String carColor;
    //Car this可写可不写
    public void show(Car this){
        System.out.println(this.carName);
        //创建内部类的对象才能访问内部类成员变量
        Engine e = new Engine();
        System.out.println(e.engineName);
    }
    class Engine{
        String engineName;
        int engineAge;
        public void show(){
            //可以直接调用外部类成员变量
            System.out.println(engineName);
            System.out.println(engineAge);
        }
    }
}

成员内部类

成员内部类也就是写在成员位置的,属于外部类的成员,上面的代码就是一个成员内部类的例子,成员内部类可以被一些修饰符所修饰,例如private,默认,protexted,public,static等
在JDK16版本之前,成员内部类里面不能定义静态变量,JDK16开始才可以定义静态变量
获取内部类成员对象
1.在外部类中编写方法,对外提供内部类对象
2.直接创建格式:
外部类名.内部类名 对象名 = 外部对象.内部对象;

遇到重名时的访问:

public class Outer {
    String name;
    private int a = 10;
    class Inner{
        private int a = 20;
        public void show(){
            int a = 30;
            System.out.println(Outer.this.a);//10
            System.out.println(this.a);//20
            System.out.println(a);//30
        }
    }
    //外部类编写获取内部类的方法
    public Inner getInnerInstance(){
        return new Inner();
    }
}

静态内部类

静态内部类其实就是在成员内部类的基础上加上static修饰之后,就变为了静态内部类,静态内部类只能访问外部类中的静态变量和静态方法,如果要想访问非静态的需要创建对象
1.创建静态内部类对象的格式:外部类名.内部类名 对象名 = new 外部类名.内部类名();
2.调用非静态方法的格式:先创建对象,用对象调用;
3.调用静态方法的格式:外部类名.内部类名.方法名

修改为以下代码

public class Souter {
    int a;
    static int b;
    static class Inner{
        public void print(){
            Souter s = new Souter();
            System.out.println(s.a);
            System.out.println(b);
        }
    }
}

方法的调用:

public class Souter {
    int a;
    static int b;
    static class Inner{
        public void print(){
            Souter s = new Souter();
            System.out.println(s.a);
            System.out.println(b);
        }
        public static void show(){
            System.out.println("静态内部类");
        }
    }
    public static void main(String[] args) {
        //创建对象,对象名调用非静态方法
        Souter.Inner inner = new Souter.Inner();
        inner.print();
        //类名调用静态方法
        Souter.Inner.show();
    }
}

局部内部类

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

public class Oouter {
    public void show(){
        int a;
        class Inner{
            String name;
            public void method1(){
                System.out.println("局部内部类方法");
            }
            public static void method2(){
                System.out.println("局部内部类静态方法");
            }
        }
        //创建对象访问局部内部类属性及方法
        Inner inner = new Inner();
        System.out.println(inner.name);
        inner.method1();
        //类名访问静态方法
        Inner.method2();
    }
}

匿名内部类

匿名内部类就是隐藏了名字的内部类
格式:
new 类名或接口名{
重写方法
};
大括号和前面的内容要么是实现关系,要么是继承关系,整体是一个类的子类对象或接口的实现类对象,大括号里面的是类
可以写在成员位置,也可以写在局部位置

如果不适用匿名内部类的方法,还需要再创建一个类去继承Animal,再去创建对象调用方法,效率不如匿名内部类高,这也就是匿名内部类的一个重要应用场景

下面是实现接口的例子:

相关文章
|
3天前
|
Java
Java——接口的使用实例
Comparable接口用于自定义类的对象比较。通过实现此接口并重写`compareTo`方法,可以定义自定义类型的比较规则。 接下来介绍了Comparator接口,它提供了一种更灵活的比较方式。通过实现Comparator接口并重写`compare`方法,可以根据不同属性定义不同的比较规则。例如,定义一个`BrandComparator`类来比较汽车的品牌。 最后,介绍了Cloneable接口,用于实现对象的克隆。实现该接口并重写`clone`方法后,可以创建对象的浅拷贝或深拷贝。浅拷贝仅复制对象本身,深拷贝则会递归复制所有成员变量。
12 4
Java——接口的使用实例
|
9天前
|
Java 数据库连接 数据库
Java服务提供接口(SPI)的设计与应用剖析
Java SPI提供了一种优雅的服务扩展和动态加载机制,使得Java应用程序可以轻松地扩展功能和替换组件。通过合理的设计与应用,SPI可以大大增强Java应用的灵活性和可扩展性。
42 18
|
7天前
|
Java 开发者
Java的接口详解
Java接口是编程中的一种重要特性,用于定义方法签名而不提供具体实现,作为类之间的契约,使不同类能以统一方式交互。接口使用`interface`关键字定义,可包含方法声明和常量。类通过`implements`关键字实现接口,并可同时实现多个接口,解决多重继承问题。接口中的方法默认为抽象方法,变量默认为`public static final`。Java 8引入了默认方法和静态方法,增强接口功能。接口广泛应用于回调机制和多态性实现,有助于构建更灵活和可维护的代码结构。
|
17天前
|
Java
盘点java8 stream中隐藏的函数式接口
`shigen`是一位坚持更新文章的博客作者,记录成长历程,分享认知见解,留住感动瞬间。本文介绍了函数式接口的概念及其在Java中的应用,包括`Comparator`、`Runnable`、`Callable`等常见接口,并详细讲解了`Function`、`Predicate`、`Consumer`、`Supplier`和`Comparator`等函数式接口的使用方法及应用场景,展示了如何利用这些接口简化代码并提高编程效率。**个人IP:shigen**,与shigen一起,每天进步一点点!
29 0
盘点java8 stream中隐藏的函数式接口
|
18天前
|
Java 编译器 开发者
Java中的Lambda表达式与函数式接口
【8月更文挑战第31天】本文将深入探讨Java 8中引入的Lambda表达式和函数式接口,它们如何改变我们编写代码的方式。通过简化集合操作、事件处理等示例,我们将看到这些特性如何提升代码可读性、减少冗余,并提高开发效率。准备好一起探索这个让Java编程更加简洁强大的新世界吧!
|
21天前
|
Java 开发者
Java 8新特性之Lambda表达式与函数式接口
【7月更文挑战第59天】本文将介绍Java 8中的一个重要新特性——Lambda表达式,以及与之密切相关的函数式接口。通过对比传统的匿名内部类,我们将探讨Lambda表达式的语法、使用方法和优势。同时,我们还将了解函数式接口的定义和用途,以及如何将Lambda表达式应用于函数式编程。
|
20天前
|
Java
在Java多线程领域,精通Lock接口是成为高手的关键。
在Java多线程领域,精通Lock接口是成为高手的关键。相较于传统的`synchronized`,Lock接口自Java 5.0起提供了更灵活的线程同步机制,包括可中断等待、超时等待及公平锁选择等高级功能。本文通过实战演练介绍Lock接口的核心实现——ReentrantLock,并演示如何使用Condition进行精确线程控制,帮助你掌握这一武林秘籍,成为Java多线程领域的盟主。示例代码展示了ReentrantLock的基本用法及Condition在生产者-消费者模式中的应用,助你提升程序效率和稳定性。
18 2
|
20天前
|
Java 开发者
在 Java 多线程编程中,Lock 接口正逐渐取代传统的 `synchronized` 关键字,成为高手们的首选
在 Java 多线程编程中,Lock 接口正逐渐取代传统的 `synchronized` 关键字,成为高手们的首选。相比 `synchronized`,Lock 提供了更灵活强大的线程同步机制,包括可中断等待、超时等待、重入锁及读写锁等高级特性,极大提升了多线程应用的性能和可靠性。通过示例对比,可以看出 Lock 接口通过 `lock()` 和 `unlock()` 明确管理锁的获取和释放,避免死锁风险,并支持公平锁选择和条件变量,使其在高并发场景下更具优势。掌握 Lock 接口将助力开发者构建更高效、可靠的多线程应用。
18 2
|
21天前
|
Java 开发者
Java中的接口和抽象类
Java中的接口和抽象类
24 3
|
21天前
|
Java
Java接口
Java接口
15 1