栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

day12

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

day12

接口

接口是Java语言中的一种引用类型,是方法的"集合",所以接口的内部主要就是定义方法,包含常量,抽象方法(JDK 7及以前),默认方法和静态方法(JDK 8),私有方法(jdk9)。接口的定义,它与定义类方式相似,但是使用 interface 关键字。它也会被编译成.class文件,但一定要明确它并不是类,而是另外一种引用数据类型。接口的使用,它不能创建对象,但是可以被实现(implements ,类似于被继承)。一个实现接口的类(可以看做是接口的子类),需要实现接口中所有的抽象方法,创建该类对象,就可以调用方法了,否则它必须是一个抽象类。接口就是规范,定义的是一组规则,体现了现实世界中“如果你是/要...则必须能...”的思想。继承是一个"是不是"的is-a关系,而接口实现则是 "能不能"的has-a关系。

定义格式

代码示例

public interface Demo {
    // 常量(jdk7及其以前) 使用public static final关键字修饰,这三个关键字都可以省略
    public static final int NUM1 = 10;
    int NUM2 = 20;

    // 抽象方法(jdk7及其以前) 使用public abstract关键字修饰,这2个关键字都可以省略
    public abstract void method1();
    void method2();

    // 默认方法(jdk8) 使用public default关键字修饰,public可以省略,default不可以省略
    public default void method3(){
        System.out.println("默认方法 method3");
    }

    // 静态方法(jdk8) 使用public static关键字修饰,public可以省略,static不可以省略
    public static void method4(){
        System.out.println("静态方法 method4");
    }
    // 私有方法(jdk9) 使用private关键字修饰,private不可以省略
    private static void method5(){
        System.out.println("私有静态方法  method5");
    }

    private void method6(){
        System.out.println("私有非静态方法  method6");
    }
}

如何实现接口

类与接口的关系为实现关系,即类实现接口,该类可以称为接口的实现类,也可以称为接口的子类。实现的动作类似继承,格式相仿,只是关键字不同,实现使用 implements关键字

实现方式:类可以实现一个接口,也可以同时实现多个接口。类实现接口后,必须重写接口中所有的抽象方法,否则该类必须是一个“抽象类”。默认方法可以选择保留,也可以重写。 重写时,default单词就不要再写了,它只用于在接口中表示默认方法,到类中就没有默认方法的概念了

不能重写静态方法

代码示例

public interface IA {

    public void show1();
}

public interface IB {

    public void show2();
}

public class Zi implements IA, IB {

    public void show1() {
    }

    public void show2() {
    }
}

类可以在“继承一个类”的同时,实现一个、多个接口

public class Fu{}//父类

public interface IA{}//父接口

public interface IB{}//父接口

public class Zi extends Fu implements IA,IB{//一定要先继承,后实现
}

接口中成员访问特点

  • 接口中的常量: 主要是供接口直接使用,推荐使用接口名直接调用
  • 接口的抽象方法、默认方法:只能通过实现类对象才可以调用。接口不能直接创建对象,只能创建实现类的对象
  • 接口中的静态方法: 对于接口的静态方法,直接使用“接口名.”进行调用即可。也只能使用“接口名."进行调用,不能通过实现类的对象进行调用
  • 接口中的私有方法: 只能在接口中直接调用,实现类无法调用
interface IA {
    // 常量
    public static final int NUM = 10;

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

    // 默认方法
    public default void method2(){
        //method4();
        //method5();       私有方法: 只能在本接口中调用
        System.out.println("IA 接口中的默认方法method2");
    }

    // 静态方法
    public static void method3(){
        //method5();    私有方法: 只能在本接口中调用
        System.out.println("IA 接口中的静态方法method3");
    }

    // 私有方法
    private void method4(){
        System.out.println("IA 接口中的私有方法method4");
    }

    private static void method5(){
        System.out.println("IA 接口中的私有方法method5");
    }
}



class Imp implements IA {
    // 重写接口的抽象方法
    @Override
    public void method1() {
        System.out.println("实现类重写IA接口中的抽象方法");
    }

    // 重写接口的默认方法
    @Override
    public void method2() {
        System.out.println("实现类重写IA接口中的默认方法");
    }

}


public class Test {
    public static void main(String[] args) {
        
        // 访问接口常量
        System.out.println(IA.NUM);// 10  推荐
        //System.out.println(Imp.NUM);// 10 不推荐 常量被实现类继承了

        // 创建实现类对象调用方法
        Imp imp = new Imp();

        // 访问抽象方法
        imp.method1();

        // 访问默认方法
        imp.method2();

        // 接口名访问静态方法
        IA.method3();
        //Imp.method3();// 编译报错,没有继承
    }
}

实现类实现多个接口,其中接口中发生了冲突怎么办?冲突就是说多个父接口拥有相同名字的方法或者属性

  • 公有静态常量的冲突:实现类不继承冲突的常量
interface A{
    public static final int NUM1 = 10;
}
interface B{
    public static final int NUM1 = 20;
    public static final int NUM2 = 30;
}
class Imp implements A,B{

}
public class Test {
    public static void main(String[] args) {
        
        //System.out.println(Imp.NUM1);// 编译报错,无法访问
        System.out.println(Imp.NUM2);// 30
    }
}
  • 公有抽象方法的冲突:实现类只需要重写一个
interface A{
    public abstract void method();
}
interface B{
    public abstract void method();
}
class Imp implements A,B{
    @Override
    public void method() {
        System.out.println("实现类重写");
    }
}
public class Test {
    public static void main(String[] args) {
        
    }
}
  • 公有默认方法的冲突:实现类必须重写一次最终版本
interface A{
    public default void method(){
        System.out.println("A 接口的默认方法method");
    }
}
interface B{
    public default void method(){
        System.out.println("B 接口的默认方法method");
    }
}
class Imp implements A,B{
    @Override
    public void method() {
        System.out.println("实现类重写的默认方法");
    }
}
public class Test {
    public static void main(String[] args) {
        
        Imp imp = new Imp();
        imp.method();
    }
}
  • 公有静态方法的冲突:静态方法是直接属于接口的,不能被继承,所以不存在冲突
  • 私有方法的冲突:私有方法只能在本接口中直接使用,不存在冲突

接口与接口之间的关系

接口可以“继承”自另一个“接口”,而且可以“多继承”。

代码示例 

interface IA {//父接口
}

interface IB {//父接口
}

interface IC extends IA, IB {//是“继承”,而且可以“多继承”

}

接口多继承接口的冲突情况,我们应该怎么办?

  • 公有静态常量的冲突:子接口无法继承父接口中冲突的常量
interface A{
    public static final int NUM1 = 10;
}
interface B{
    public static final int NUM1 = 20;
    public static final int NUM2 = 30;
}
interface C extends A,B{

}
public class Test {
    public static void main(String[] args) {
        
        //System.out.println(C.NUM1);// 编译报错,说明无法继承
        System.out.println(C.NUM2);// 30
    }
}
  • 公有抽象方法冲突 :子接口只会继承一个有冲突的抽象方法  
interface A{
    public abstract void method();
}
interface B{
    public abstract void method();
}
interface C extends A,B{

}
class Imp implements C{
    @Override
    public void method() {
        System.out.println("实现接口的抽象方法");
    }
}

public class Test {
    public static void main(String[] args) {
        
        Imp imp = new Imp();
        imp.method();
    }
}
  • 公有默认方法的冲突  :子接口中必须重写一次有冲突的默认方法
interface A{
    public default void method(){
        System.out.println("A 接口中的默认方法method");
    }
}
interface B{
    public default void method(){
        System.out.println("B 接口中的默认方法method");
    }
}

interface C extends A,B{

    @Override
    public default void method() {
        System.out.println("重写父接口中的method方法");
    }
}

class Imp implements C{

}

public class Test {
    public static void main(String[] args) {
        
        Imp imp = new Imp();
        imp.method();// 重写父接口中的method方法
    }
}
  • 公有静态方法和私有方法:不冲突,因为静态方法是直接属于接口的,只能使用本接口直接访问,而私有方法只能在接口中访问,也没有冲突

实现类继承父类又实现接口时的冲突

  • 父类和接口的公有静态常量的冲突:子类无法继承有冲突的常量
  • 父类和接口的抽象方法冲突:子类必须重写一次有冲突的抽象方法
  • 父类和接口的公有默认方法的冲突:优先访问父类的
  • 父类和接口的公有静态方法:只会访问父类的静态方法
  • 父类和接口的私有方法:不存在冲突

使用场景

额外的功能: 在接口中定义,让实现类实现

  • 如果可以确定的通用功能,使用默认方法
  • 如果不能确定的功能,使用抽象方法

共性的功能: 在父类中定义,让子类继承

  • 如果可以确定的通用功能,使用默认方法
  • 如果不能确定的功能,使用抽象方法
多态

生活中,比如跑的动作,小猫、小狗和大象,跑起来是不一样的。可见,同一行为,通过不同的事物,可以体现出来的不同的形态。多态,描述的就是这样的状态。程序中多态: 是指同一方法,对于不同的对象具有不同的实现.

前提条件

  • 继承或者实现【二选一】
  • 父类引用指向子类对象接口引用指向实现类对象【格式体现】
  • 方法的重写【意义体现:不重写,无意义】

多态的体现:

父类的引用指向它的子类的对象

代码示例

class Animal{//父类
    public void eat(){
        System.out.println("吃东西");
    }
}

class Dog extends Animal{//子类Dog
    @Override
    public void eat() {
        System.out.println("狗吃骨头...");
    }
}

class Cat extends Animal{//子类Cat
    @Override
    public void eat() {
        System.out.println("猫吃鱼...");
    }
}

public class Test1 {
    public static void main(String[] args) {
        
        // 父类引用指向子类对象
        Animal anl = new Dog();// 多态
        anl.eat();// 狗吃骨头...

        Animal anl1 = new Cat();
        anl1.eat();// 猫吃鱼...
    }
}

多态的几种形式

普通父类多态

public class Fu{}
public class Zi extends Fu{}
public class Demo{
    public static void main(String[] args){
        Fu f = new Zi();//左边是一个“父类”
    }
}

抽象父类多态

public abstract class Fu{}
public class Zi extends Fu{}
public class Demo{
    public static void main(String[] args){
        Fu f = new Zi();//左边是一个“父类”
    }
}

 父接口多态

public interface A{}
public class AImp implements A{}
public class Demo{
    public static void main(String[] args){
        A a = new AImp();
    }
}

多态情况下,创建子类对象,去访问成员,到底是访问父类的还是子类的??

成员变量的访问特点

  • 编译看左边,运行看左边。简而言之:多态的情况下,访问的是父类的成员变量

成员方法的访问特点

  • 非静态方法:编译看左边,运行看右边。简而言之:编译的时候去父类中查找方法,运行的时候去子类中查找方法来执行
  • 静态方法:编译看左边,运行看左边。简而言之:编译的时候去父类中查找方法,运行的时候去父类中查找方法来执行

代码示例

class Animal {
    int num = 10;

    public void method1() {
        System.out.println("Animal 非静态method1方法");
    }

    public static void method2() {
        System.out.println("Animal 静态method2方法");
    }
}

class Dog extends Animal {
    int num = 20;

    public void method1() {
        System.out.println("Dog 非静态method1方法");
    }

    public static void method2() {
        System.out.println("Dog 静态method2方法");
    }
}

public class Test {
    public static void main(String[] args) {
        
        // 父类的引用指向子类的对象
        Animal anl = new Dog();
        System.out.println(anl.num);// 10

        anl.method1();// Dog 非静态method1方法

        anl.method2();// Animal 静态method2方法

    }
}

多态的应用场景:

  • 多态应用在形参实参:参数类型为父类类型,该参数就可以接收该父类类型的对象或者其所有子类对象
  • 多态应用在数组:数组元素类型声明为父类类型,可以存储父类类型的对象或者子类的对象
  • 多态应用在返回值:如果返回值类型为父类类型,那么就可以返回该父类类型的对象或者其所有子类对象
  • 如果变量的类型为父类类型,该变量就可以接收该父类类型的对象或者其所有子类对象

多态的好处和弊端

  • 好处:提高了代码的扩展性
  • 弊端:多态的情况下,只能调用父类的共性内容,不能调用子类的特有内容。无法访问子类独有的方法或者成员变量,因为多态成员访问的特点是,编译看父类

引用类型转换

因为多态,我们就不能调用子类拥有,而父类没有的方法了。这也是多态给我们带来的一点"小麻烦"。所以,想要调用子类特有的方法,必须做类型转换。不管是向上转型还是向下转型,一定满足父子类关系或者实现关系

向上转型:当左边的变量的类型(父类) > 右边对象/变量的类型(子类),我们就称为向上转型。此时,编译时按照左边变量的类型处理,就只能调用父类中有的变量和方法,不能调用子类特有的变量和方法了此时,一定是安全的,而且也是自动完成的。例如:

//父类是Animal 子类是Cat
Aniaml anl = new Cat();  

向下转型:当左边的变量的类型(子类)<右边对象/变量的类型(父类),我们就称为向下转型。此时,编译时按照左边变量的类型处理,就可以调用子类特有的变量和方法了。

 Aniaml anl = new Cat();  
 Cat c = (Cat)anl;//向下转型

不是所有通过编译的向下转型都是正确的,可能会发生ClassCastException,为了避免ClassCastException的发生,Java提供了 instanceof 关键字,给引用变量做类型的校验,只要用instanceof判断返回true的,那么强转为该类型就一定是安全的,不会报ClassCastException异常。

返回值:

  •  如果前面变量指向的对象类型是属于后面的数据类型,那么就返回true
  •  如果前面变量指向的对象类型不是属于后面的数据类型,那么就返回fals

所以,转换前,我们最好先做一个判断,代码如下:

  // 向上转型  
        Animal a = new Cat();  
        a.eat();               // 调用的是 Cat 的 eat

        // 向下转型  
        if (a instanceof Cat){
            Cat c = (Cat)a;       
            c.catchMouse();        // 调用的是 Cat 的 catchMouse
        } else if (a instanceof Dog){
            Dog d = (Dog)a;       
            d.watchHouse();       // 调用的是 Dog 的 watchHouse
        }
    }  

 总结一下

class Animal {//父类
    public void eat() {
        System.out.println("吃东西...");
    }
}

class Dog extends Animal {
    @Override
    public void eat() {
        System.out.println("狗吃骨头...");
    }

    // 特有的功能
    public void lookHome() {
        System.out.println("狗在看家...");
    }
}

class Cat extends Animal {
    @Override
    public void eat() {
        System.out.println("猫吃鱼...");
    }

    // 特有的功能
    public void catchMouse() {
        System.out.println("猫抓老鼠...");
    }
}

public class Test {
    public static void main(String[] args) {
        Dog d = new Dog();
        method(d);

        System.out.println("==========================");

        Cat c = new Cat();
        method(c);
    }

    // 形参多态: 如果父类类型作为方法的形参类型,那么就可以接收该父类类型的对象或者其所有子类的对象
    public static void method(Animal anl) {
        anl.eat();
        //anl.lookHome();// 编译报错
        // anl.catchMouse();// 编译报错
        if (anl instanceof Dog) {
            Dog d = (Dog) anl;// 向下转型 Dog类型
            d.lookHome();
        }

        if (anl instanceof Cat) {
            Cat c = (Cat) anl;// 向下转型 Cat类型
            c.catchMouse();
        }

    }
}
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/298846.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号