Java学习---day09_接口与内部类

本文介绍了Java中的接口和内部类。接口用于实现多继承,提供了抽象方法和静态方法,并详细讲解了接口的定义、实现、继承和多态。内部类包括成员内部类、静态内部类、局部内部类和匿名内部类,它们各具特点,可以增强代码的封装性和可读性。文章还探讨了接口与抽象类的异同以及内部类的作用和使用场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Java学习—day09_接口与内部类

接口

接口的定义
  • 属性

    • 接口中的属性,默认都是静态常量,访问权限都是public

    • 例:

      public static final String INTERFACE_FIELD = "value";
      
  • 方法

    • 接口中的方法,默认都是抽象方法,访问 权限都是public

    • 例:

      public abstract void method();
      

ps:一般接口中不写成员变量,只写方法,相当于制定规则,所以又将接口称为方法列表

接口的作用:

java从单继承间接的实现了多继承,扩充了原来的功能,我们可以认为接口是类的补
充。

接口和抽象类的异同(经常出面试题)
  • 相同点:
    • 都可以编译成字节码文件
    • 都不能创建对象
    • 都可以声明引用
    • 都具备Object类中所定义的方法
    • 都可以写抽象方法
  • 不同点:
    • 接口中所有的属性,都是公开静态常量,可以省略使用 public static final 修饰。
    • 接口中所有的方法,都是公开抽象方法,可以省略使用 public abstract 修饰。
    • 接口中没有构造方法、构造代码段、静态代码段。
接口的实现

接口,需要让类实现,表示这个类具有了这个接口定义的能力。因为接口中有很多的
抽象方法,因此类在实现接口的时候,如果不是抽象类,必须要重写实现接口中所有
的抽象方法。

定义接口,需要使用到关键字interface

public interface MyInterface {
    //这里默认省去abstract,即public abstract interface MyInterface
    public static final String INTERFACE_FIELD = "value";   // 接口中的属性定义
    public abstract void method();                         // 接口中的方法定义
}
 
// 非抽象类实现接口,必须重写实现接口中所有的抽象方法
class MyInterfaceImpl implements MyInterface {
    @Override
    public void method() {}
}
 
// 抽象类实现接口,接口中的抽象方法,可以实现,也可以不实现
abstract class MyInterfaceAbstractImpl implements MyInterface {}

ps:

  • 一个类可以实现多个接口

  • 如果两个接口中定义了两个同名、同参数的方法,但是返回值不同。那么类是没
    有办法同时实现这两个接口的。因为在同时实现的时候,无法最终确定这个方法
    的返回值类型。

接口的继承
  • 接口之间也是存在继承关系的,与类的继承相似,子接口可以继承到父接口中所有的
    成员的。
  • 与类的继承不同,接口之间的继承是多继承。也就是说,一个接口是可以有多个父接
    口的。子接口可以继承到所有的父接口中的成员
interface SuperInterface1 {
    void method1();
}
interface SupeInterface2 {
    void method2();
}
// 此时,在这个接口中,继承到了所有的父接口中的方法,同时定义了自己独有的方// 实现类在实现这个接口的时候,需要实现 method1、method2、method3 三个
方法
interface SubInterface extends SuperInterface1, SuperInterface2 
{
    void method3();
}

ps:一个类实现多个接口的时候,多个接口中不能存在有冲突的方法。接口在继承
父接口的时候,也不允许同时继承两个有方法冲突的接口。

  • 父类与接口的功能如何分配?
    • 一般父类中放的是主要功能,接口中放的是额外的功能,接口作为父类的补充
  • 当一个类实现的接口中出现了相同的方法,子类中实现方法的时候会不会混淆?
    • 不会,接口中的方法都是抽象的,要通过子类写具体的实现.我们在调用方法时,最终看的
      功能,而功能只有子类中的一份.
接口中的多态

接口的引用,可以指向实现类的对象。与类的多态相似,同样存在向上转型和向下转
型。

  • 向上转型:实现类类型转型为接口类型。
    • 是一个隐式转换,不需要任何的修饰。
    • 向上转型后的接口引用,只能访问接口中的成员。
  • 向下转型:接口类型转型为实现类类型。
    • 是一个显式转换,需要强制类型转换。
    • 向下转型后的实现类引用,将可以访问实现类中的成员。
接口的新特性【了解】

Java8中,为接口添加了两个新特性:

  • static方法:可以在接口中定义静态方法,静态方法不是抽象方法,是有实现部
    分的。同时,这个静态方法,只能由当前的接口名字调用,接口的引用和实现类
    都是不能使用的。
interface MyInterface {
    public static void method1() {
        System.out.println("接口中的静态方法实现");
    }
}
 
class Person implements MyInterface{
    //这里不可以重写method1方法
}
 
public class Demo8 {
    public static void main(String[] args) {
            MyInterface.method1();  //正确,只能通过接口名字来调用
        MyInterface m = new Person(); //接口的多态
        m.method1();  //错误
        Person.method1();//错误
    }
}
  • default方法:修饰接口中的方法,default修饰的方法可以添加默认的实现部
    分。此时,实现类在实现接口的时候,对于这些方法可以重写,也可以不重写
interface MyInterface {
    public default void method2() {
        System.out.println("接口中的方法默认实现");
    }
}
 
class Person implements MyInterface{
    //可以重写method2方法
}
 
public class Demo8 {
    public static void main(String[] args) {
     	MyInterface m = new Person();
        m.method2();  //正确
        Person.method2();//错误
    }
}

内部类【了解】

内部类的分类(会)

内部类,按照定义的位置和修饰符不同,可以分为:

  • 成员内部类
  • 静态内部类
  • 局部内部类
  • 匿名内部类(其实也算是一种局部内部类)
成员内部类【会】

概念:定义在一个类的内部的类.内部类的地位与外部类的成员变量,成员方法平等,内部类也
可以看做是外部类的成员,成员之间可以相互调用

特点:

  • 书写位置:与属性、方法平级别,且没有使用static修饰的类。
  • 访问权限:内部类可以是任意的访问权限。
  • 成员内部类中,不能写静态属性、静态方法。
  • 编译之后生成的字节码文件格式:外部类$内部类.class
  • 实例化对象,需要借助外部类的对象完成。

使用:

  • 外部类的一个成员部分,创建内部类对象时,必须依赖外部类对象。
    Outer outer = new Outer();
    Inner inner = outer.new Inner();
    Inner inner1 = new Outer().new Inner()
class OuterClass {
    public String name;
    public class InnerClass {
        public String name;
        public void show(String name) {
            System.out.println(name);            // 访问参数 name    
            System.out.println(this.name);        // 访问内部类属性 name
            System.out.println(OuterClass.this.name);  //访问外部类属性 name
        }
    }
  
    public void  test(){
        System.out.println("Outer-show");
 
        InnerClass inner = new InnerClass();
        inner.show();
    }
}
class Program {
    public static void main(String[] args) {
        // 实例化外部类对象
        OuterClass outer = new OuterClass();
        //调用内部类的方法的方式
       //第一种:借助于外部类的方法实现
       outer.test();
       //方式二:借助外部类对象,实例化内部类对象
        //引用:外部类.内部类
        //构成:外部类对象的引用.new 内部类的构造方法
        OuterClass.InnerClass inner = outer.new InnerClass();
        inner.show();
    }
静态内部类【了解】

概念:在类的内部定义,与实例变量、实例方法同级别的,使用static修饰的类。

特点:

  • 书写位置:和类中的属性、方法平级,且使用关键字 static 修饰
  • 静态内部类中,可以写属性、方法、构造方法…
  • 静态内部类中,可以写静态属性、方法
  • 编译之后生成的字节码文件,格式:外部类$内部类.class
  • 对象的实例化,不需要借助外部类对象。

使用:

  • 不依赖外部类对象,可以直接创建或通过类名访问。
  • Outer.Inner inner = new Outer.Inner();
public class OuterClass {
  //静态内部类不一定有静态方法,有静态方法的一定是静态内部类
    static class InnerClass {
        String name;
        public  void show(String name) {
            System.out.println(name);
            System.out.println(this.name);
        }
    }
}
class Test {
    public static void main(String[] args) {
        // 1. 实例化静态内部类的对象
        //构成:  new  +  外部类名字.内部类的构造方法
        OuterClass.InnerClass innerClass = new 
OuterClass.InnerClass();
        // 2. 可以通过导包的形式,
        //    先导包 import 包.OuterClass.InnerClass
        // InnerClass innerClass = new InnerClass();
        innerClass.show("aaa");
    }
}
局部内部类【了解】

概念:定义在外部类的方法中,作用范围和创建对象范围仅限于当前方法。

特点:

  • 局部内部类访问外部类当前方法中的局部变量时,因无法保障变量的生命周期与自身相同,变量必须修饰为final。
  • 不能使用访问权限修饰符修饰。
  • 书写位置:写在一个类的方法内部,作用域仅限于当前方法。
  • 局部内部类,编译后生成的字节码文件格式:外部类$序号内部类名.class
public class Program {
    public static void main(String[] args) {
        Outer1 outer1 = new Outer1();
        outer1.show();
    }
}
 
class  Outer1{
    public void  show(){
        System.out.println("Outer-show");
        // 定义一个局部变量
        // 如果这个局部变量,被包裹在了一个局部代码段中(比如局部内部类、
匿名内部类),此时这个局部变量会被隐式的定义为final
        int height=0;
        //局部内部类
        // 在一个类的方法中,直接定义一个内部类
        class  Inner{
            public  void run(){
                System.out.println("Inner-run"+height);
            }
        }
        
      //创建局部内部类对象
        Inner inner = new Inner();
        inner.run()
        }
}      
局部内部类的作用

通过局部内部类实现了功能的私有化,并对方法内部的代码进行了整理,增强了代码的
可读性和可操作性.

class Test{
    public void play() {
      
//当我们想将这两个方法变成play的私有功能时,发现play中不能直接写方法的定义,
所以写入局部内部类
//        public void gongneng1(){
//            System.out.println("功能1");
//        }
//        public void gongneng2(){
//            System.out.println("功能2");
//        }
        class Inner{
      //通过编写gongneng1,gongneng2两个方法,将play的整体功能实现了分类整理
            public void gongneng1(){
                System.out.println("功能1");
            }
            public void gongneng2(){
                System.out.println("功能2");
            }
        }
 
        Inner inner = new Inner();
        inner.gongneng1();
        inner.gongneng2();
    }
 
    public void run(){
       //因为两个方法是play的局部内部类方法.play之外不可⻅
//         gongneng1();
//         gongneng2();
    }
}
局部内部类所在方法中局部变量的使用【了解】
  • final:被final修饰的变量会被放在常量区,而常量区的值存在的时间要大于局部变
    量所在的方法,相当于从原来的基础上扩大了作用域
  • 当方法中同时存在局部内部类与局部变量时,局部变量的使用范围就会从原来的基
    础上进行扩大.
  • 原因:在当前程序执行时,程序会默认让final去修饰height.所以当局部变量所在的方法
    结束的时候,变量没有被释放,保存的值还在.
  • 关于变量前面的final的说明:
    • 前提:变量必须与局部内部类同时存在.并且在局部内部类中使用了当前的局
      部变量
    • jdk1.7之前要想保住局部变量的值,要手动添加final
    • jdk1.7之后,程序执行时,java的内部机制已经在变量的前面默认添加了fin

模拟jdk1.7时局部变量前面有final修饰时的情况
结论:发现虽然show方法已经结束,但是我们仍然可以拿到age的值

public class Demo4 {
    public static void main(String[] args) {
        Outer4 outer4 = new Outer4();
        outer4.show();
        outer4.eat();//show方法已经结束,但是 获取age的值 age = 6
    }
}
 
class Outer4{
    Object object = null;
    public void show() {
     int  age = 6;
        class Inner{//局部内部类
 
            public void run() {
                System.out.println("跑"+age);
            }
             @Override
            public String toString() {
                // TODO Auto-generated method stub
                return "toString    "+age;
            }
        }
 
        //show的内部使用局部内部类
        object = new Inner();//多态
 
    }
 
    public void eat(){
        System.out.println(object.toString());
        System.out.println("eat");
    }
}
匿名内部类【了解】

概念:

匿名内部类(对象):定义在一个类的方法中的匿名子类对象,属于局部内部类
其实这个概念我们可以分成两部分看
先学习匿名子类对象:没有名字的子类对象
再学习匿名内部类对象:一个类的方法中的匿名子类对象

特点:

  • 一切特征与局部内部类相同。
  • 必须继承一个父类或者实现一个接口。
  • 定义类、实现类、创建对象的语法合并,只能创建一个该类的对象

匿名内部类作用:

  • 当只用到当前子类的一个实例对象的时候,定义好⻢上使用,使用完立刻释放
  • 当不好起名字的时候
  • 可以更好的定义运行时的回调(知道即可)

创建匿名子类对象 :

  • 创建方式

第一种方式:使用已有的子类创建匿名子类对象

使用场景:已经创建好的子类可以多次使用,适用于相同的功能被多次调用

第二种方式:直接使用Animal创建匿名子类对象

构成: new +  父类的名字/接口的名字 + () + {写当前子类的成员} + ;
 
使用场景:只能使用一次,使用完会被当做垃圾回收,适用于每次都使用不同的功能
public class Demo6 {
    public static void main(String[] args) {
        Animal animal = new Animal();
        //匿名对象
        new Animal().eat();
      
        //匿名子类对象
        //第一种方式:使用已有的子类创建匿名子类对象
        new Dog().eat();
        //第二种方式:直接使用Animal创建匿名子类对象
        //直接创建没有名字的Animal的匿名子类对象
        new Animal(){
            @Override
            public void eat() {
                System.out.println("匿名子类对象-eat");
            }
        }.eat();
    }
}
//研究匿名子类对象
class Animal {
    public void eat() {
        System.out.println("fu-eat");
    }
}
class Dog extends Animal
{
    public void eat() {
        System.out.println("zi-eat");
    }
}

创建匿名内部类

  • 说明
    • 代码中的Animal对象就是一个匿名内部类
    • 我们可以用匿名内部类做方法的参数或返回值
    • 匿名内部类的父类可以是父类也可以是父接口
public class Demo6 {
    public static void main(String[] args) {
        //测试匿名内部类
        Test1 test1 = new Test1();
        test1.canShuTest();//com.qf.test.Animal@1b6d3586
        test1.canShuTest1();//com.qf.test.Test1$2@4554617c  使用
外部类+$+序号表示当前的匿名内部类
    }
}
 
class Animal {
    public void eat() {
        System.out.println("fu-eat");
    }
}
 
//研究匿名内部类
class  Test1{
    public  void  show(){
        //匿名内部类
        new Animal(){
            @Override
            public void eat() {
                System.out.println("匿名子类对象-eat");
            }
        }.eat();
    }
 
    //普通的匿名对象作为参数
    public void canShuTest(){
        System.out.println(new Animal());
    }
    //匿名内部类作为参数
    public  void  canShuTest1(){
        System.out.println(new Animal(){
            @Override
            public void eat() {
                System.out.println("eat");
            }
        });
    }
 
    //普通的匿名对象作为返回值
    public Animal fanHuiZhiTest(){
        return  new Animal();
    }
 
    //匿名内部类作为返回值
    public Animal fanHuiZhiTest1(){
        return  new Animal(){
//            public void jump(){
//
//            }
        };
    }
}

ps:除了new Object类是匿名对象,其他所有类的匿名对象本质上都是匿名子类对象

内部类作用【会】

  • 间接实现了多继承
  • 方便定义
  • 只有外部类可以访问创建的内部类的属性和方法,包括私有方法
  • 同一个包中其他的类不可⻅,有了很好的封装性

要求:要让X同时继承来自A和B的内容,并且A和B没有关系

class  A{}
class  B{}
class  X extends  A{
    class  Y extends  B{}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值