Java面对对象-接口接口的使用接口和抽象类区别接口的默认方法匿名内部类和接口抽象类

Posted ggzx666

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java面对对象-接口接口的使用接口和抽象类区别接口的默认方法匿名内部类和接口抽象类相关的知识,希望对你有一定的参考价值。

接口的概念:

官方解释:Java接口是一系列方法的声明,是一些方法特征的集合,一个接口只有方法的特征没有方法的实现,因此这些方法可以在不同的地方被不同的类实现,而这些实现可以具有不同的行为(功能,即子类可以重写抽象类的方法)。
在接口中,它的方法是绝对抽象的(jdk8以前),用来抽象子类的能力、规则。例如鸟的fly,🐟的swim,数字能够Compare,这就是鸟类,🐟类的能力。

在现实中也有很多事物用到了接口的概念
例如:数据线,在使用数据线充电时,只要你使用安卓的数据线,一般都能够给安卓手机充电,因为这类充电线的插口都按照android的规则、规格来生产数据线,这里使用到的是接口能定义规则(数据线并不是真正使用了JAVA中的接口。而是数据线的插口被制定了一个生产规则,包括插口大小,内部接线规则,假如我们要写一个数据线的类,那么我们可以将这些规则以常量或者无方法体的抽象方法写入接口中)
生活中很多物品的规格都是严格要求好的,这有利于产品的拓展。
对于面对对象的java语言也是如此,对象是用来描述、描绘一个事物的,有了接口,可以提高对象的扩展性,灵活性。


接口中除了默认方法和静态方法,都没有方法体

  1. 在jdk8以前,所有方法都是抽象的.
  2. 接口没有方法体,是因为,接口是用来规范代码,使得代码结构更清晰。
  3. jdk8,接口可以有默认方法,默认方法有方法体,并且子类可以不实现默认方法,直接使用,也可以覆盖接口的方法
    意义:现在有一个接口和若干个实现该接口的类,假如只是部分接口需要这个新方法,那怎么办?
    1.在接口中直接添加新方法:所有类都要实现该方法,很麻烦
    2.使用抽象类(建议看完下面抽象类再来看这个):使用抽象类实现接口并添加新方法,需要实现的子类继承自抽象类即可
    3.在接口中添加默认方法!!
  4. 接口无法实例化


一个类可以实现多个接口


接口可以继承其他接口,并且可以多继承接口,但是接口接口需要使用extends

public interface InterfaceB extends InterfaceA,InterfaceC

//这里要注意了,接口继承接口,接口可以不实现其父接口的抽象方法
//虽然这个接口里面没有抽象方法,但是实现这个接口的类必须实现接口A中的方法
//即:类实现某个接口,从层级关系上讲,类必须实现其接口层级往上的所有的抽象方法
public interface InterfaceA 
	void doWork();

public interface InterfaceC 



一个类如果要实现某个接口,需要实现其中所有的抽象方法
1.因为接口是提取规则、能力,实现这个接口肯定就有这种能力,既然接口都抽象了这种方法,那子类都应该有这些方法。


为什么需要接口?

  1. java无法多继承,接口可以用来抽象特性,可以弥补无法多继承的局限,同时也避免了多继承的复杂性
  2. 良好的代码书写规范和清晰的代码层级关系利于源码的阅读和理解

接口无法实例化


接口的方法都是public的

  1. 因为接口是提取规则,没有子类实现接口,接口就没存在的意义了。要被子类实现,public是最好的,不同包内也可以实现这个接口

接口中的属性默认public static final

  1. 因为接口中抽象的是规则,规则不应该能被改变,并且能被子类使用。定义静态常量时候必须有初始值

接口也有标识作用:

  1. 例如Serializable,其内部是连抽象方法都没有的,没有内容,这个接口的作用只是标识这个类具有某种功能。



抽象类的概念:
面对对象中,对象都是通过类来描述的,有很多相似的对象,这些类中有很多相似的内容,抽象类提取这些类的共性内容后,作为子类的模板。
1. 抽象类中必须含有抽象方法,可以有普通方法
2. 可以有变量、常量
3. 子类只能单继承,即子类继承了某抽象类无法继承其他类
4.抽象类不能实例化,抽象类用来就是提取子类模板,是用来被继承的。
但是可以以匿名内部类的形式来创建一个对象

  •   public static void main(String[] args) 
          Animals sheep=new Animals() 
              @Override
              public void eat(String food) 
                  System.out.println("羊吃"+food);
              
          ;
          sheep.eat("草");
          Animals fish=new Animals() 
              @Override
              public void eat(String food) 
                  System.out.println("鱼吃"+food);
              
          ;
          fish.eat("水草");
      
    


这里就是两个匿名抽象类对象,这里$就代表是匿名对象。匿名内部类?为什么匿名内部类有引用?以及接口怎么实现匿名方式?

public class Anonymous 
    public static void main(String[] args) 
        Outer outer = new Outer();
        outer.tiger.cry();
        outer.dog();
    

interface IA
    void cry();


class Outer
    //如果要使用IA接口,并创建对象,传统方式是写一个类实现接口并创建对象
    //但是这个类只需要使用一次所以使用匿名内部类来简化开发
    //匿名内部类的名字由系统自动分配,需要使用对象.getclass
    //接口其实是无法new的,但是这里通过大括号并实现其中的方法,是的其可以创建并且将地址传递给tiger
    //匿名内部类只能使用一次,但是已经创建的tiger可以多次使用
    //这里其实是实现IA接口的内部类
    IA tiger=new IA() 
        @Override
        public void cry() 
            System.out.println("老虎狂啸");
        
    ;

    public void dog() 
        IA dog = new IA() 
            @Override
            public void cry() 
                System.out.println("小狗汪汪");
            
        ;
    
    new Father()
      @Override
      publi void ih()
        sop("匿名内部类调用了hi方法")
      
    .hi();//这样甚至都不用创建变量,直接调用
    //体现了匿名内部类的对象的特征
    
    Father father=new Father("jack")
        //匿名内部类中不能重写构造器,不能创建特有方法
        //运行类型是Outer$3
        //这里可以重写father的方法
        //这里相当于继承了一个类,省去了创建不必要的新的子类
        @Override
        public void test() 
            super.test();
        
    ;//这里有大括号,所有是匿名内部类
//    Father father=new Father("jack");这里是直接创建father对象



class Father
    String name;
    public Father(String name)
        this.name=name;
    
    public void test()
        System.out.println("name="+name);
    

接口和抽象类的区别

但是我先举一个实际的例子,来解释接口的作用,在此同时也会介绍抽象类和接口的区别


这里我们先假设我们需要实现一种抽象的数字类,来思考一下其需要实现什么功能

  1. 能保存用户传给的值
  2. 能和其他数字比较(数字不能比较还有什么意义)
  3. 可以来输出保存的值
  4. 最大能保存数字的范围
  5. 能和其他数字进行转换

先别急,现在我们来看一下Java中是如何实现数字类及其子类的
这个是IDEA中的Digrams,想使用可以IDEA中Digrams的使用
来看一下源代码

public abstract class Number implements java.io.Serializable 
    public abstract int intValue();//对应上方的保存值功能,注意这里的所有方法都没有方法体
    public abstract long longValue();//返回值(相当于保存值、输出值)
    public abstract float floatValue();//同上
    public abstract double doubleValue();
    public byte byteValue() //强制转换
        return (byte)intValue();
    
    public short shortValue() 
        return (short)intValue();
    
    private static final long serialVersionUID = -8742448824652078965L;


再看一下实现Number抽象类的Integer的源码

public final class Integer extends Number implements Comparable<Integer>//注意这里继承了Number抽象类和Comparable接口
	//保存值的范围
    @Native public static final int   MIN_VALUE = 0x80000000;
    @Native public static final int   MAX_VALUE = 0x7fffffff;
   
    //输出值
    public static String toString(int i, int radix)
    ....省略
    
    //保存值
    public int intValue() 
        return value;
    
    static int formatUnsignedInt(int val, int shift, char[] buf, int offset, int len) 
    ....省略
    
    //和其他Integer类比较
    public int compareTo(Integer anotherInteger) 
        return compare(this.value, anotherInteger.value);
    
    //转换成其他数字类
    public long longValue() 
        return (long)value;
    
   

再来看一下Comparable接口

public interface Comparable<T> 
    public int compareTo(T o);

//comparable接口中参数使用了泛型,不同的类实现不同的comparable接口即可,实现comparable接口的类需要实现其中的compareTo方法

现在我们思考几个问题(以下问题均是个人的想法,若不全,若有错误可联系我补充或者更改答案)

  1. 为什么Comparable是一个接口
    解:在编写代码的时候,我们要使得代码结构清晰,需要规范代码,这也是抽象类,父类,接口存在的意义之一.使用接口可以提取类的规则,抽象类可以提取类的共性内容。对于比较功能,数字肯定是可以比较是吧,但是很多其他类,比如自己创建一个employee和employer类,两个类之间可以有工资的比较方法或者其他比较方法,所以说Comparable应该是一个规则,Comparable作为接口最好,这样有比较功能的类实现该接口就行,如果,有比较功能的类的不实现comparable接口,却私自定义一个compare方法,那么接口存在的意义就被忽略了。
    其次,Java无法实现多继承,这意味着假如Comparable是抽象类的话,那我们又如何让Integer继承Number类,两个类无法同时被一个类继承。这里也侧面体现了,接口可以解决java无法多继承的局限。
  2. 为什么Number是一个抽象类
    解:抽象类抽取的是子类的特性、共性内容,可以看见Number类中有一些返回数值和保存数值的方法以及转换方法,这很明显是所有数字类的共性内容。先前介绍了数字类应该有的五个个功能,返回和保存以及转换只是其中三个功能,但是
    为什么数字范围没在抽象类中:上面Integer保存范围是用的final常量,抽象类虽然可以有final属性,但是不同数字类保存范围不一样,不是共同内容
    为什么Number中没有实现Comparable接口,而是其子类去实现Comparable接口:因为Comparable接口有泛型参数T,实现该接口的时候需要填写参数,所以放在抽象类Number的子类中最合适,方便实现Comparable的CompareTo方法。


    我这里写了一个小代码
public class IntegetTest extends NumberTest
    @Override
    public int compare(NumberTest numberTest) 
        return 0;
    
    @Override
    public int compareTo(NumberTest o) 
        return 0;
    


假如有数字类继承了这个接口,其子类需要实现这个compare方法以及compareTo方法并且参数是NumberTest抽象类。


我们看看Double继承了Number抽象类,那Double怎么实现compareTo方法的

	  ......上方其他代码省略
    public int compareTo(Double anotherDouble) 
        return Double.compare(value, anotherDouble.value);
			//value是newDouble类是保存在Double类中的一个值,体现了Double保存数值的功能
    
    public static int compare(double d1, double d2) 
        if (d1 < d2)
            return -1;           // Neither val is NaN, thisVal is smaller
        if (d1 > d2)
            return 1;            // Neither val is NaN, thisVal is larger

        // Cannot use doubleToRawLongBits because of possibility of NaNs.
        long thisBits    = Double.doubleToLongBits(d1);
        long anotherBits = Double.doubleToLongBits(d2);

        return (thisBits == anotherBits ?  0 : // Values are equal
                (thisBits < anotherBits ? -1 : // (-0.0, 0.0) or (!NaN, NaN)
                 1));                          // (0.0, -0.0) or (NaN, !NaN)
    
    ....下方其他代码省略

不需要理解很多,这里的compareTo方法使用了Double中保存的value,我们思考一下,假如是Number实现comparable接口,那么子类方法参数应该就是抽象类了,但是抽象类中虽然有保存数值的方法,但是并没有方法体,如果Number实现该接口,其子类的CompareTo方法和Compare方法的实现会变得麻烦很多。(希望有人能提出关于这部分更好的意见!!)

  1. 为什么Number不能设计成一个接口
    Number是一种模板,它偏向于提取子类的共性内容,接口偏向于提取规则。所以写成抽象类比较方便

案例总结:

  1. 抽象类偏向于提取子类共有内容,接口偏向于提取规则。
  2. 抽象类是一种子类模板
  3. 合理的接口、抽象类使用可以让代码的关系更加清晰,事实上,接口可以提供多继承的大多数好处,同时还能避免多继承的复杂性。
    如何查看自己所写的类的关系 ,可以使用Idea的Digrams功能
    Idea中超赞的的Digrams功能

以上是关于Java面对对象-接口接口的使用接口和抽象类区别接口的默认方法匿名内部类和接口抽象类的主要内容,如果未能解决你的问题,请参考以下文章

java抽象类和接口使用及区别

java 中interface和抽象类的区别

java接口和类有啥区别?

、接口与类的区别;

java抽象类和接口区别

java的接口和抽象类区别