草庐IT

详解java中的【接口】(关键字implements)

快到锅里来呀 2023-04-04 原文

目录

🌏1. 理解接口的概念

🌎2. 学会接口的语法(关键字implements)

🌍3. 掌握接口的用法

🌏4. 明白接口的特性

🌏5. 教你如何实现多个接口

🌎6. 接口之间是怎么继承的

🌏7. 给接口举个例子

🗺️7.1 Comparable接口

🗺️7.2 比较器Comparator 

🌍8. Clonable接口和深拷贝

🗺️8.1 Cloneable接口 

🗺️8.2 浅拷贝

🗺️8.3 深拷贝

🌎9. 接口和抽象类的区别


🌏1. 理解接口的概念

接口就是公共的规范标准,如果要使用就要遵守这个标准,
而在Java中,接口可以看成是:一种特殊的类,
它的规范标准就是,里面全部都是由全局常量和公共的抽象方法组成,
并且它是解决java无法使用多继承的一种手段,所以如果要使用就要遵守这个标准

🌎2. 学会接口的语法(关键字implements)

🟩使用interface来修饰接口

注意:

(1)创建接口时,接口的命名一般以大写字母 I 开头

(2)建议接口中的方法和属性不要加任何修饰符号, 保持代码的简洁性


🌍3. 掌握接口的用法

🟥接口是不能直接使用的,必须要有一个类来实现该接口,实现接口中的所有抽象方法

格式就是这样

 class 类名称   implements  接口名称{

       //

}


🌏4. 明白接口的特性

🤠(1)接口当中的成员变量,默认都是 public static final 修饰的

🤠(2) 接口中的成员方法,默认都是抽象方法

          也就是public abstract 修饰的

 

🤠(3)接口中的普通成员方法,是不能有具体的实现的

 这里就报错了

 🤠(4)接口中的普通成员方法,如果要有具体实现,就必须加上default【从JDK8开始】

 

🤠(5) 接口中可以有静态的成员方法,

          但是不管是静态方法还是default方法都是public修饰的

 🤠(6)接口本身也是不可以进行实例化的

🤠(7) 类和接口的关系是使用 implements 来关联的

 🤠(8)一个接口可以引用,具体实现类的,向上转型

🤠 (9)接口中不能有静态代码块,实例代码块,构造方法

 🤠(10)一个抽象类实现一个接口,可以不重写这个抽象方法,但是这个类一旦被使用,就也要重写构造方法


🌏5. 教你如何实现多个接口

java中是不支持多继承的,一个类只能有一个父类,那么如何实现多个类的使用

这就要用到接口了

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

下面看例子

这个是个抽象类动物

abstract class Animal {
    public String name;
    public int age;

    public Animal(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public abstract void eat() ;
}

然后再看两个接口

interface IRunning {
    public void run() ;
}
interface IFlying {
    public void fly();
}

 下面创建一个动物 

⚜️如何使用接口呢,很简单,直接在子类继承父类的后面 加关键字 然后连接接口就可以了

class Dog extends Animal implements IRunning{
    public Dog(String name, int age) {
        super(name, age);
    }

    @Override
    public void eat() {
        System.out.println(name + "正在吃狗粮! ");
    }
    @Override
    public void run(){
        System.out.println(name+" 正在跑 ");
    }
}

再创建一个动物 

这里注意,在创建鸟时使用了两个接口 关键字implements后面 跟两个接口,中间用逗号连接

并且还要注意的是,一个类在实现多个接口的时候,每个接口中的抽象方法都要实现,否则类必须设置成抽象类

class Bird extends Animal implements IRunning,IFlying{

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

    @Override
    public void eat() {
        System.out.println(name + "正在吃鸟粮! ");
    }
    @Override
    public void run(){
        System.out.println(name+" 正在慢跑走 ");
    }
    @Override
    public void fly(){
        System.out.println(name+" 正在用翅膀飞 ");
    }
}

 上面的这个例子,说明了java中 ,

一个类继承一个父类,同时实现多种接口

而接口表达的作用是,具有___功能或特性


🌎6. 接口之间是怎么继承的

类和类之间是单继承的,一个类可以有多个接口,接口和接口之间是可以多继承的。

也就是,用接口就可以实现多继承。

下面看代码,例子

interface IA {
    void funcA();
}
interface IB{
    void funcB();
}
//扩展功能--接口的继承
interface IC extends IA,IB{
    void funC();
}
class T implements IC {
    @Override
    public void funcA() {
    }
    @Override
    public void funcB() {
    }
    @Override
    public void funC() {
    }
}

这个例子中,为了实现接口的继承,

使用了extends关键字,在关键字后面跟两接口,中间用逗号连接 

接口之间的继承相当于把多个接口合并在一起,也就是扩展功能


🌏7. 给接口举个例子

🗺️7.1 Comparable接口

🤠比较自定义类型的大小接口Comparable<>

 如果是自定义类型数据,需要比较大小,那就要先明确根据什么去比较大小,

 

 

 这里也可以简化一下代码

    @Override
    public int compareTo(Student o) {
        return this.age - o.age;
    }

 这里的this就是student,o就是student1,这两个根据age比较大小

    public static void main(String[] args) {
        Student student = new Student("zhang san",20,60);
        Student student1 = new Student("li si",21,70);
        Student student2 = new  Student("wang wu",21,80);
        if(student.compareTo(student1) > 0){
            System.out.println("student > student1");
        }else if (student.compareTo(student1) == 0){
            System.out.println("student == student1");
        }else {
            System.out.println("student < student1");
        }
    }
    public static void main(String[] args) {
        Student[] students = new Student[3];
        students[0] = new Student("zhang san",22,60);
        students[1] = new Student("li si",21,70);
        students[2] = new  Student("wang wu",21,80);
        System.out.println("排序前" + Arrays.toString(students));
        Arrays.sort(students);
        System.out.println("排序后" + Arrays.toString(students));
    }

 ⚜️如果以后是自定义类型的数据,牵扯到大小比较,需要进行一些设计的。比如实现接口 


🗺️7.2 比较器Comparator 

🤠比较器Comparator   

比较器Comparator比前面的Comparable<>更加灵活,

因为Comparable比较是写的固定的,而Comparator可以根据用户的需求去指定选择根据什么样的方式进行比较,

比如说比较年龄

class AgeComparator implements Comparator<Student> {

    @Override
    public int compare(Student o1, Student o2) {
        return o1.age - o2.age;
    }
}

 比如说比较分数

class AgeComparator implements Comparator<Student> {

    @Override
    public int compare(Student o1, Student o2) {
        return o1.age - o2.age;
    }
}

需要比较什么就选择什么,非常的灵活

    public static void main(String[] args) {
        Student student = new Student("zhang san",20,60);
        Student student1 = new Student("li si",21,70);
        AgeComparator ageComparator =new AgeComparator();
        int ret = ageComparator.compare(student,student1);
        System.out.println(ret);

        ScoreComparator scoreComparator = new ScoreComparator();
        int ret2 = scoreComparator.compare(student,student1);
        System.out.println("分数比较" + ret2);
    }

 ⚜️当然两个也是可以共存的

compareTo是根据学生对象去调用的,而Comparator是根据对应选择比较来调用的

⚜️前面比较的都是数字,那么Compartor是如何来比较字符串的 

下面来进行name的比较

注意看name是String类型,String实现了Comparable接口

 所以它默认有Comparable方法那就可以直接这样做了

class NameComparator implements Comparator<Student> {
    @Override
    public int compare(Student o1, Student o2) {
        return o1.name.compareTo(o2.name);
    }
}

我们也可以自己写一个sort方法来实现排序过程,使用冒泡排序

    public static void sort(Comparable[] array) {
        for (int i = 0; i < array.length - 1; i++) {
            for (int j = array.length - 1 - i; j > i; j--) {
                if (array[j].compareTo(array[j+1]) > 0) {
                    // 顺序不符合要求, 交换两个变量的位置
                    Comparable tmp = array[j - 1];
                    array[j - 1] = array[j];
                    array[j] = tmp;
                }
            }
        }
    }

🌍8. Cloneable接口和深拷贝

🗺️8.1 Cloneable接口 

这是一个空接口(标记接口),没有抽象方法,也就是类可以被克隆 

Cloeable表示person这个类可以被克隆 

 但是如果要克隆那就必须要重写clone这个方法

 可以看到调用的是Object这个cloen方法

 可以简单的看一下克隆过程

class person implements Cloneable{
    public int age = 11;

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

    @Override
    public String toString() {
        return "person{" +
                "age=" + age +
                '}';
    }
}
public class Test01 {
    public static void main(String[] args) throws CloneNotSupportedException {
        person person = new person();
        person person1 = (person) person.clone();
    }
}

🤠所以,Object 类中存在一个 clone 方法, 调用这个方法可以创建一个对象的 "拷贝".

但是要想合法调用 clone 方法, 必须要 先实现 Clonable 接口,

🗺️8.2 浅拷贝

下面看这样的一段代码

class Money {
    public double money = 19.9;
}

class person implements Cloneable{
    public int age = 10;
    public Money m = new Money();

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

    @Override
    public String toString() {
        return "person{" +
                "age=" + age +
                '}';
    }
}
public class Test01 {
    public static void main(String[] args) throws CloneNotSupportedException {
        person person = new person();
        person person1 = (person) person.clone();
        System.out.println(person.m.money);
        System.out.println(person1.m.money);
    }
}

 它会输出什么

 如果此时修改

     person1.m.money = 99;

 那么输出会不会变化呢,要明白这个问题,就要先搞清楚这段代码的存储方式

 都是指向同一个money的所以,修改一个,另一个也会变化,这样的存储方法就叫做浅拷贝


🗺️8.3 深拷贝

 但是最后指向的都是

所以修改一个另一个也会被改变,这个也就是浅拷贝

所以深拷贝就是希望,最后指向的不是一块空间,修改一个另一个不会被改变

深拷贝就是希望实现这样的一个效果,

下面修改一下试试看

   person1.m.money = 99;

 和我们希望的一样,修改后不影响另一个值


🌎9. 接口和抽象类的区别

区别抽象类接口
成员变量普通类一样默认被public static final修饰
成员方法构造方法或普通方法抽象方法,静态方法,default默认方法
子类使用用extends关键字继承抽象类用implements关键字实现接口
子类限制一个子类继承一个抽象类一个子类实现多个接口
关系一个抽象类可以实现若干接口

接口不能继承抽象类,但接口可以使用

extends关键字继承多个父接口

权限和普通类一样public


有关详解java中的【接口】(关键字implements)的更多相关文章

  1. ruby - 如何从 ruby​​ 中的字符串运行任意对象方法? - 2

    总的来说,我对ruby​​还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用

  2. ruby - 其他文件中的 Rake 任务 - 2

    我试图在一个项目中使用rake,如果我把所有东西都放到Rakefile中,它会很大并且很难读取/找到东西,所以我试着将每个命名空间放在lib/rake中它自己的文件中,我添加了这个到我的rake文件的顶部:Dir['#{File.dirname(__FILE__)}/lib/rake/*.rake'].map{|f|requiref}它加载文件没问题,但没有任务。我现在只有一个.rake文件作为测试,名为“servers.rake”,它看起来像这样:namespace:serverdotask:testdoputs"test"endend所以当我运行rakeserver:testid时

  3. ruby-on-rails - Ruby net/ldap 模块中的内存泄漏 - 2

    作为我的Rails应用程序的一部分,我编写了一个小导入程序,它从我们的LDAP系统中吸取数据并将其塞入一个用户表中。不幸的是,与LDAP相关的代码在遍历我们的32K用户时泄漏了大量内存,我一直无法弄清楚如何解决这个问题。这个问题似乎在某种程度上与LDAP库有关,因为当我删除对LDAP内容的调用时,内存使用情况会很好地稳定下来。此外,不断增加的对象是Net::BER::BerIdentifiedString和Net::BER::BerIdentifiedArray,它们都是LDAP库的一部分。当我运行导入时,内存使用量最终达到超过1GB的峰值。如果问题存在,我需要找到一些方法来更正我的代

  4. ruby-on-rails - Rails 3 中的多个路由文件 - 2

    Rails2.3可以选择随时使用RouteSet#add_configuration_file添加更多路由。是否可以在Rails3项目中做同样的事情? 最佳答案 在config/application.rb中:config.paths.config.routes在Rails3.2(也可能是Rails3.1)中,使用:config.paths["config/routes"] 关于ruby-on-rails-Rails3中的多个路由文件,我们在StackOverflow上找到一个类似的问题

  5. ruby-on-rails - Rails - 一个 View 中的多个模型 - 2

    我需要从一个View访问多个模型。以前,我的links_controller仅用于提供以不同方式排序的链接资源。现在我想包括一个部分(我假设)显示按分数排序的顶级用户(@users=User.all.sort_by(&:score))我知道我可以将此代码插入每个链接操作并从View访问它,但这似乎不是“ruby方式”,我将需要在不久的将来访问更多模型。这可能会变得很脏,是否有针对这种情况的任何技术?注意事项:我认为我的应用程序正朝着单一格式和动态页面内容的方向发展,本质上是一个典型的网络应用程序。我知道before_filter但考虑到我希望应用程序进入的方向,这似乎很麻烦。最终从任何

  6. ruby-on-rails - Rails 3.2.1 中 ActionMailer 中的未定义方法 'default_content_type=' - 2

    我在我的项目中添加了一个系统来重置用户密码并通过电子邮件将密码发送给他,以防他忘记密码。昨天它运行良好(当我实现它时)。当我今天尝试启动服务器时,出现以下错误。=>BootingWEBrick=>Rails3.2.1applicationstartingindevelopmentonhttp://0.0.0.0:3000=>Callwith-dtodetach=>Ctrl-CtoshutdownserverExiting/Users/vinayshenoy/.rvm/gems/ruby-1.9.3-p0/gems/actionmailer-3.2.1/lib/action_mailer

  7. ruby-on-rails - Rails 应用程序中的 Rails : How are you using application_controller. rb 是新手吗? - 2

    刚入门rails,开始慢慢理解。有人可以解释或给我一些关于在application_controller中编码的好处或时间和原因的想法吗?有哪些用例。您如何为Rails应用程序使用应用程序Controller?我不想在那里放太多代码,因为据我了解,每个请求都会调用此Controller。这是真的? 最佳答案 ApplicationController实际上是您应用程序中的每个其他Controller都将从中继承的类(尽管这不是强制性的)。我同意不要用太多代码弄乱它并保持干净整洁的态度,尽管在某些情况下ApplicationContr

  8. ruby-on-rails - form_for 中不在模型中的自定义字段 - 2

    我想向我的Controller传递一个参数,它是一个简单的复选框,但我不知道如何在模型的form_for中引入它,这是我的观点:{:id=>'go_finance'}do|f|%>Transferirde:para:Entrada:"input",:placeholder=>"Quantofoiganho?"%>Saída:"output",:placeholder=>"Quantofoigasto?"%>Nota:我想做一个额外的复选框,但我该怎么做,模型中没有一个对象,而是一个要检查的对象,以便在Controller中创建一个ifelse,如果没有检查,请帮助我,非常感谢,谢谢

  9. ruby - rspec 需要 .rspec 文件中的 spec_helper - 2

    我注意到像bundler这样的项目在每个specfile中执行requirespec_helper我还注意到rspec使用选项--require,它允许您在引导rspec时要求一个文件。您还可以将其添加到.rspec文件中,因此只要您运行不带参数的rspec就会添加它。使用上述方法有什么缺点可以解释为什么像bundler这样的项目选择在每个规范文件中都需要spec_helper吗? 最佳答案 我不在Bundler上工作,所以我不能直接谈论他们的做法。并非所有项目都checkin.rspec文件。原因是这个文件,通常按照当前的惯例,只

  10. ruby-on-rails - active_admin 目录中的常量警告重新声明 - 2

    我正在使用active_admin,我在Rails3应用程序的应用程序中有一个目录管理,其中包含模型和页面的声明。时不时地我也有一个类,当那个类有一个常量时,就像这样:classFooBAR="bar"end然后,我在每个必须在我的Rails应用程序中重新加载一些代码的请求中收到此警告:/Users/pupeno/helloworld/app/admin/billing.rb:12:warning:alreadyinitializedconstantBAR知道发生了什么以及如何避免这些警告吗? 最佳答案 在纯Ruby中:classA

随机推荐