Java基础部分总结—03

Java基础部分总结—03

  • 接口
  • 多态
  • final关键字
  • 内部类

1 接口—interface

定义格式
  public interface 接口名称 {
    // 抽象方法		abstract 不实现,没有ff体
    // 默认方法		default 实现, 有方法体	
    // 静态方法		static 实现, 有方法体
    // 私有(静态)方法		private/private static
    //成员函数		public static final(表示不可改变)  可省略,但可是不可改变,且定义的时候必须进行赋值,
    						//【类似与C++中的const】
}
  • 抽象方法:使用 abstract 关键字修饰,可以省略,没有方法体。该方法供子类实现使用。

  • 默认方法:使用 default 修饰,不可省略,供子类调用或者子类重写

  • 静态方法:使用 static 修饰,供接口直接调用

  • 私有方法和私有静态方法:使用 private 修饰,供接口中的默认方法或者静态方法(只能调用私有静态方法)调用。

实现—implements

非抽象子类实现接口
1. 必须重写接口中所有抽象方法。
2. 继承了接口的默认方法,即可以直接调用,也可以重写。

class 类名 implements 接口名 {
    // 重写接口中抽象方法【必须】
   // 重写接口中默认方法【可选】   
}
  • 抽象方法的使用
    和抽象类中的抽象方法一致,都必须进行@override重写,否则该类为抽象类。
    如果抽象方法有重名的,只需重写一次。

  • 默认方法的使用
    由于默认方法在接口中方法体,故可以继承,可以进行重写,但是只能通过实现类的对象来调用。
    接口中,有多个默认方法时,实现类都可以继承使用。如果默认方法有重名的,必须重写一次。

  • 静态方法的使用
    静态方法只能使用接口名来调用,不可以通过实现类的类名或实现类的对象调用。
    接口中,存在同名的静态方法并不会冲突,原因是只能通过各自接口名访问静态方法。
    不能通过接口的实现类来调用接口中的静态方法,因为接口可以多继承,会带来重名的情况。

  • 私有方法和私有静态方法
    私有(静态)方法只能为接口中的默认方法和静态方法调用,即只能私自使用,外部实现类不能用。
    存在的原因:如果一个接口中有多个默认方法,并且方法中有重复的内容,那么可以抽取出来,封装到私有方法中,供默认方法去调用。从设计的角度讲,私有的方法是对默认方法和静态方法的辅助。

    • 私有方法
      只有默认方法可以调用。
    • 私有静态方法
      默认方法和静态方法可以调用。
      换句话说,静态方法里面只能是私有静态方法,默认方法里可以有私有方法和私有静态方法。
      在这里插入图片描述
  • 成员常量
    接口中,无法定义成员变量,但是可以定义常量,其值不可以改变(在定义时就要进行赋值),默认使用public static final修饰。

接口和继承同时存在时的优先级

当一个类,既继承一个父类,又实现若干个接口时,父类中的成员方法与接口中的默认方法重名,子类就近选择执
行父类的成员方法

接口的继承

一个接口能继承另一个或者多个接口,这和类之间的继承比较相似。接口的继承使用 extends 关键字,子接口继
承父接口的方法。如果父接口中的默认方法有重名的,那么子接口需要重写一次。

  • 一些重名的区分:
    • 1)静态方法的重名:静态方法有方法体,在调用时直接用接口名.静态方法,所以在接口的多继承和实现出现重名情况时,并不需要重写。
    • 2)抽象方法的重名:抽象方法没有方法体,在实现的时候必须重写,否则其为抽象类,在接口的实现类中出现与其他抽象方法重名的情况下,只需重写一次即可。
    • 3)默认方法的重名:默认方法有方法体,在实现类或多继承时出现重名的情况必须对默认方法进行重写。
      小贴士:
      子接口重写默认方法时,default关键字可以保留。
      接口实现类重写默认方法时,default关键字不可以保留。
代码演示
  • 接口A
public interface A {
    public static final int a = 10;//成员常量
    //public static int b ;//成员常量定义时必须初始化
    int c=10;//不写static系统会默认加上public static final

    public abstract void methodA();//抽象方法

    public default void methodB() {//默认方法
        System.out.println("A::methodB");
        this.methodD();//默认方法调用私有方法
        methodE();//默认方法调用私有静态方法(注意!静态的没有this指针)
    }

    public default void methodF() {//默认方法
        System.out.println("A::methodF");
        this.methodD();//默认方法调用私有方法
        methodE();//默认方法调用私有静态方法(注意!静态的没有this指针)
    }

    public static void methodC() {//静态方法
        System.out.println("A::methodC");
        //methodD();//Err静态方法不能调用非静态的成员变量
        methodE();//静态方法调用私有静态方法(注意!静态的没有this指针)

    }

    //私有方法
    private void methodD() {
        System.out.println("我是私有方法");
    }

    //私有静态方法
    private static void methodE() {
        System.out.println("我是私有静态方法");
    }
}
  • 接口B
/*
 * 接口B,抽象、默认、静态方法与接口A重名
 * */
public interface B {
    public abstract void methodA();//抽象方法-->与接口A的抽象方法重名

    public default void methodB() {//默认方法--->与接口A的默认方法重名
        System.out.println("B::methodB");
    }

    public static void methodC() {//静态方法--->与接口A的静态方法重名
        System.out.println("B::methodC");

    }

}
  • 类D的子类C
/*
 * 用于继承的类C,其为类D的子类
 * */
public class C {
    public void methodF() {//默认方法//抽象方法--->与接口A中的抽象方法重名
        {
            System.out.println("我是子类C中的与接口A的抽象方法重名的成员方法methodF()");
        }
    }
}
  • 接口的实现类
/*
 * 接口实现类,实现了接口A、B
 * */
public class D extends C implements A, B {
    @Override
    public void methodA() {//接口的实现类中出现抽象方法重名只需重写一个抽象方法即可
        System.out.println("我是实现类中的抽象方法");
    }

    @Override
    public /*default*/ void methodB() {//接口实现类中的默认方法出现重名时,一定要重写,且不能加default,default只能出现在接口中
        System.out.println("我是实现类中重写的默认方法");

    }


    //接口实现类中重复的默认方法不用重写
}
  • 主函数
public class testMain {
    public static void main(String[] args) {
        D d = new D();
        d.methodA();// 调用实现类重写的抽象方法  out :我是实现类中的抽象方法
        d.methodB();// 调用实现类重写的默认方法  out: 我是实现类中重写的默认方法
        A.methodC();// 直接接口名.静态方法调用接口A中的静态方法 out: A::methodC 我是私有静态方法
        int re = A.a;// 接口名.静态常量调用接口A中的静态常量
        System.out.println("re=" + re);// out: re=10
        d.methodF();// 调用继承和接口A同名的方法 out: 我是子类C中的与接口A的抽象方法重名的成员方法methodF()

    }
    
}

多态

同一行为,通过不同的事物,可以体现出来的不同形态。

实现条件【前提】
  • 1)继承或实现(接口)【二选一】。
  • 2)方法的重写【意义体现:不重写,无意义】
  • 3)父类指针指向之类对象【格式体现】
    可在创建对象或传参时实现。

注意:
多态指的是成员方法,对于成员变量不能被重写,故通过对象直接访问成员变量时不能发生多态现象,但是可以通过成员方法访问,且方法被重写时可以方法多态。

  • 父类
/*
父类
* */
public abstract class Fu {
    private String name;
    private int id;
    public int socre = 10;

    public Fu() {
    }

    public Fu(String name, int id) {
        this.name = name;
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }


    public abstract void funcA();//抽象方法

    public void funcB() {
        System.out.println("Fu::funcB");
    }

}
  • 子类
public class Zi extends Fu {
    public int socre = 100;

    @Override
    public void funcA() {
        System.out.println("子类抽象方法的重写");
    }

    @Override
    public void funcB() {
        super.funcB();// 调用父类的成员方法
        System.out.println("覆盖重写了父类的方法");
    }
    
    public void funcC() {
        System.out.println("子类特有的成员方法");
    }
}
  • Main函数
public class MainTest {
    public static void main(String[] args) {

        /* 父类指针指向子类对象[多态]
         * 此时会自动方法向上转型:Zi---->Fu
         * 成员方法:编译看左,运行看右 [编译的时候,只有左边的Fu类中有相关方法,编译才通过,因为只有父类中有才可以点出来其方法]
         * 成员变量:编译运行都看左,因为成员变量不会方法多态现象,谁.的就看谁的成员变量
         * */
        Fu fu = new Zi();
        fu.funcA();// 子类抽象方法的重写
        fu.funcB();// Fu::funcB   覆盖重写了父类的方法
        System.out.println("socre=" + fu.socre);// socre=10
       // 为了调用子类特有的成员方法,强制向下转型,转型前需判断
        if (fu instanceof Zi) {
            Zi zi = (Zi) fu;
            zi.funcC();// 子类特有的成员方法
        }
        System.out.println("=============================");
        test(new Zi());// 子类抽象方法的重写 Fu::funcB 覆盖重写了父类的方法 socre=10

    }

    //在传参时发生父类引用指向子类对象发生多态
    private static void test(Fu fu) {
        fu.funcA();
        fu.funcB();
        System.out.println("socre=" + fu.socre);
    }
}

final关键字

学习了继承后,我们知道,子类可以在父类的基础上改写父类内容,比如,方法重写。那么我们能不能随意的继承API中提供的类,改写其内容呢?显然这是不合适的。为了避免这种随意改写的情况,Java提供了 final 关键字,用于修饰不可改变内容。

  • final: 不可改变。可以用于修饰类、方法和变量。
    • 类:被修饰的类,不能被继承。
    • 方法:被修饰的方法,不能被重写。
    • 变量:被修饰的变量,不能被重新赋值。变量可以是基本类型也可以是引用类型
      【相当于c++或c#中的const】

注意:

  • 被final修饰的常量名称,一般都有书写规范,所有字母都大写
  • final修饰成员变量的时候,由于成员变量有默认值问题,故必须手动给起赋值–>显示初始化或构造方法初始化,当使用构造方法赋值的时候,必须保证所有的构造方法都对final的成员变量赋值。
修饰类

API中的String类:public final class String ,由于其被final修饰,所以使得数组的长度不能发生改变。
格式:

 final class 类名 {
  
}
修饰方法

格式:

修饰符 final 返回值类型 方法名(参数列表){
    //方法体
}

重写被 final 修饰的方法,编译时就会报错

修饰变量
  • 1)局部变量—基本类型
    基本类型的局部变量,被final修饰后,只能赋值一次,不能再更改。
    局部变量没有默认值,成员变量有默认值
    注意和接口中的常量区分,接口中的常量需要定义时就赋值,而这里可以定义与赋值分开
public class FinalDemo1 {
    public static void main(String[] args) {
        // 声明变量,使用final修饰
        final int a;
        // 第一次赋值 
        a = 10;
        // 第二次赋值
        a = 20; // 报错,不可重新赋值
 
 
        // 声明变量,直接赋值,使用final修饰
        final int b = 10;
        // 第二次赋值
        b = 20; // 报错,不可重新赋值
    }
}
  • 2)局部变量—引用类型
    引用类型的局部变量,被final修饰后,只能指向一个对象,地址不能再更改。**但是不影响对象内部的成员变量值的修改,**代码如下:
public class FinalDemo2 {
    public static void main(String[] args) {
        // 创建 User 对象
        final   User u = new User();
        // 创建 另一个 User对象
        u = new User(); // 报错,指向了新的对象,地址值改变。
 
        // 调用setName方法
        u.setName("张三"); // 可以修改
    }
}
  • 图解:
    在这里插入图片描述
    【注】final修饰的是对象,即创建的对象的地址不变但是创建的对象内部的成员没有被final修饰,故可以改变,像c/c++中的二级指针的概念,这里final修饰的是一级指针。

  • 3)成员变量

  • final修饰成员变量的时候,由于成员变量有默认值问题,故必须在创建对象的同时手动给其赋值–>显示初始化或构造方法初始化,当使用构造方法赋值的时候,必须保证所有的构造方法都对final的成员变量赋值

  • 成员变量的初始化分为显示初始化和构造函数初始化两种。

  • 显示初始化:【在定义时直接赋初值】

public class User {
    final String USERNAME = "张三";
    private int age;
}
  • 构造方法初始化。
    【当使用构造方法赋值的时候,必须保证所有的构造方法都对final的成员变量赋。】
public class User {
    final String USERNAME ;
    private int age;
    public User(String username, int age) {
        this.USERNAME = username;
        this.age = age;
    }
}

内部类

将一个类A定义在另一个类B里面,里面的那个类A就称为内部类,B则称为外部类。

  • 成员内部类

定义在类中方法外的类。【内部类相当与外部类的一个成员】
在描述事物时,若一个事物内部还包含其他事物,就可以使用内部类这种结构。
定义格式:

  class 外部类 {
    class 内部类{
 
    }
}

注意:

  • 内部类的this指针指的是内部类本身
访问特点
  • 内部类可以直接访问外部类的成员,包括私有成员。【外部类中的成员对于本类都是可以访问的】
  • 外部类要访问内部类的成员,必须要建立内部类的对象。【有内部类的实体对象才有内部类的成员】,外部类可以直接访问内部类的私有成员。【不需要通过Get()Set()方法】

创建内部类对象格式:

// 有了外部类才有内部类,故先要new外部类,在创建内部类对象
外部类名.内部类名. 对象名 = new 外部类型().new 内部类型();
代码实现
/*
创建并调用匿名内部类
* */
public class InnerClass {
    private int Id = 10;
    private String name = "张三";

    public void methodA() {
        System.out.println("InnerClass::methodA");
    }

    public void methodC() {
        // 外部类要访问内部类的成员,必须要建立内部类的对象
        // 外部类可以直接访问内部类的私有成员,不需要通过Get\Set方法
   
        InnerClass2 innerClass2 = new InnerClass2();
        innerClass2.Id2 = 111;
        innerClass2.name2 = "李四";
        System.out.println("name:" + innerClass2.name2 + "id:" + innerClass2.Id2);
    }

    public class InnerClass2 {
         //  Id、name和InnerClass2处于平等的位置,都是InnerClass的成员,也就是Id、name和Id2、name2处于平等平等的地位
         // 唯一的区别是Id2、name2的访问要先创建InnerClass2的实例,所以外部类可以创建对象后直接访问其成员,包括私有成员
        private int Id2;
        private String name2;


        public void methodB() {
            System.out.println("name:" + name + "id:" + Id);
        }
    }
    
}
public class MainTest {
    public static void main(String[] args) {
        InnerClass innerClass = new InnerClass();
        innerClass.methodA();
        innerClass.methodC();
        // 创建内部类对象
        InnerClass.InnerClass2 innerClass2 = new InnerClass().new InnerClass2();
        innerClass2.methodB();

    }
}
  • 匿名内部类

是内部类的简化写法。它的本质是一个带具体实现的父类或者父接口的匿名的子类对象。开发中,最常用到的内部类就是匿名内部类了。以接口举例,当你使用一个接口时,似乎得做如下几步操作,

  • 1.定义子类
  • 2.重写接口中的方法
  • 3…创建子类对象
  • 4.调用重写后的方法
    我们的目的,最终只是为了调用方法,那么能不能简化一下,把以上四步合成一步呢?匿名内部类就是做这样的快
    捷方式。
代码实现
  • 定义接口:
/*
* 定义接口:
* */
public interface Innerable {
    abstract void func();
}
  • 创建并调用匿名内部类
/*
创建并调用匿名内部类
* */
public class InnerClass {
    public static void main(String[] args) {
    //     1.等号右边:定义并创建该接口的子类对象
    //     2.等号左边:是多态,接口类型引用指向子类对象
        Innerable innerable = new Innerable() {// 匿名内部类
            @Override
            public void func() {
                System.out.println("func().....");
            }
        };

        innerable.func();

    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值