接口和抽象类都是面对对象编程中实现抽象的两种核心机制他们都用于定义规范并支持多态但使用场景有所不同一.总的区别接口抽象类关键字interface定义implements实现关键字abstract class定义extends继承方法默认都是抽象方法可以有default和static来具体实现方法可以有抽象方法也可以有具体实现的普通方法实例化不支持接口是各种类的行为规范相当于充电绳什么设备都能充电符合就拿来用实例化不支持抽象类是各种类公共部分相当于中国的电压都是220变量全是常量变量可以有各种访问修饰符普通成员变量、常量设计目的能不能就是一个规矩你按照我的标准来我不管你内部怎么实现充电的设计目的是不是就是一个半成品我搭好结构你做剩下的事继承多个继承只能有一个二.抽象类2.1什么是抽象类如果一个类里面没有足够的信息来描述对象就是抽象类关键字 abstract 修饰的类是抽象类。抽象类即抽象化的不可描述的。理论上讲你可以把类定义任何事物和行为但是不符合面向对象编程思想既然是面向对象的行为的对象定义成类那么抽象类也应该是定义有意义的对象2.2与普通类区别抽象类不能进行实例化即不能使用 new 关键字创建实例但可以用super被动调用抽象类可以包含抽象方法可以没有具体的实现一个类当中有抽象方法这个类必须是抽象类如果一个普通类继承了这个抽象类此时这个抽象类必须重写这个抽象类当中的抽象方法抽象类的出现就是为了被继承2.3抽象类里的构造函数构造函数不是作用于实例化的主要作用是对类属性初始化操作。抽象类可以定义变量自然需要构造函数来赋值等操作抽象类属于被继承才可以实现调用属性和方法。在重写方法中第一行有个默认代码 super() 默认调用父类的构造方法所以既然有了继承、重写为了实现super()自然需要构造函数。抽象类属于特殊类而Java规定每个类都需要构造函数救急不救穷2.4抽象类里的修饰符在抽象类中可以使用权限修饰符public、private、protected修饰方法和属性默认public但private 修饰的属性和方法不能被子类继承同时private不能用来修饰抽象方法可以使用静态关键字 static 修饰普通方法、代码块、成员变量被finalprivate static修饰的方法不可以重写深层上就是他们不共存2.5抽象类方法重写抽象类中定义的抽象方法必须实现重写普通方法可以不重写如果不实现抽象方法则报错抽象类属于模板设计什么是模板化设计简而言之就是其他子类继承了抽象类抽象类属于子类的公共模块模块内的东西更新了其他子类自然也更新。2.6抽象类的应用总的目的实现共有特性特征和行为当我们把事物抽象出一个共性时确定这个事物的最基本行为和属性都不会变必须存在就可以使用抽象类的抽象方法和属性定义。比如我定义一个狗类动物的抽象类这类动物会叫、会吃等这些都是基本属性和行为新增其他狗类时直接继承扩展基本方法如果这个狗有其他特定行为在自定义独有方法即可。强调不会改变共有而且必须存在的行为和属性也就是无论什么狗都是会叫会吃的。三.接口3.1定义interface是定义接口的关键字接口是不可以进行实例化的接口不是类只是一种公共行为标准只要符合规范就可以通用在Java里接口是多个类的公共规范是一种引用数据类型但是不能直接new接口的对象接口是对行为的抽象接口里可以有成员变量不管写没写都是由public static final修饰的也就是他们都是静态成员不可修改接口里不能有静态代码块和构造方法接口里可以有方法但是都是抽象方法不管写没写都是public abstract所修饰如果接口里的方法有default修饰可以有具体的实现jdk8如果接口里的方法有static修饰也可以有具体的实现不然是不能在接口里实现的只能在实现接口的类来完成3.2实现接口和类之间可以使用关键字implements来实现而且必须实现接口当中的抽象方法的重写重写方法时不能使用默认的访问权限一个接口虽然不是类但是编译完成之后对应一个字节码文件后缀格式也是.class一般来说接口里的方法和属性不写修饰符号创建接口时接口的命名一般以大写字母I开头如果一个类不想实现这个接口当中的方法此时这个类就可以被定义为抽象类如果这个抽象类如果被继承那么就得实现所有的没有被实现的方法如果没有使用接口需要一个又一个的实例化然后存起来选择打印如果使用接口只需进行小小的改动然后直接打印如果数据多了不仅方便而且代码也少3.3实现多个接口接口的出现就是要解决Java不能多继承的问题接口和继承写好之后就可以任意调用了如下简单说继承表达的是xxx是xxx的关系接口是表达的xxxx的共性不关心具体是谁3.4接口与接口的关系利用extends关键字这里不是继承而是扩展接口1{方法1}接口2{方法2}接口3 extends 接口1 接口2{方法3}class D implements 接口3{必须重写方法123}3.5接口使用实例1.Comparable如果在Java里想比较两个数的大小可以直接用这种逻辑判断但是如果相比较两个学生谁大谁小比如年龄什么的再用这个方法就不支持了此时就要用Comparable1.比较规则需要引入Comparable原型是ComparableT这个T比较那个类型就写那个类2.具体定义需要对Comparable进行重写然后内部的if其实等价于我注释掉的这行它通过返回正负或者0来判断谁大谁小System.out.println(student1.compareTo(student2))谁调用谁就是this3.Comparable的缺点这个比较方式一般用于固定的比较不适合灵活的比较换一个动全身用在有默认的比较上4.尝试回忆之前有Array方法如果把Comparable接口和重写的方法注释掉这时候会报类型错误打开源代码发现其实Arrays.sort()也是用上了Comparable第一步它强制转换成了Comparable你如果不实现接口就不行第二步你不得不重写compareTo因为实现接口要重写里面的方法所以只要是自定义的类型涉及大小的比较一定要实现Comparable接口2.ComparatorComparator因为数字大小是明确的但对象有多个属性Java 不知道你想按哪个排。Student 有 name 和 age按哪个排 必须你自己指定规则。也就是解决了1.需要多种排序方式2. 不能修改原类3. 排序规则临时变而Comparable只适用于固定的一种排序需要有Comparable来补充解决对比Q:Comparable 和 Comparator 的区别AComparable 是内部比较器被排序的类自己实现只能有一种规则。Comparator 是外部比较器单独定义可以有多种规则更灵活。Q什么时候用哪个A类有默认排序方式用 Comparable如 Integer 默认升序。需要多种排序方式或不能修改原类时用 Comparator。Q返回值怎么理解Acompare(o1, o2) 返回负数 o1 放前面正数 o1 放后面0 相等不动。3.Clone这个Clone需要的步骤也是有点首先我们需要先解决为什么不能.点出克隆因为clone隶属于object类他并不是可以直接使用的所以我们在Person类里面重写clone其次重写之后返回值是object父类的所以我们需要对结果强转一下转完发现还是有问题这里发现需要告诉jvm我这里这个是可以进行复制克隆的最后针对克隆失败的异常进行处理对复制克隆做出修改发现只克隆了Person对象没克隆Money对象此时叫做浅拷贝如果把Money也拷贝克隆了就是深拷贝-------改造、重写方法改造前super.clone() 只复制了 Person 对象本身但 m 字段里存的是 引用地址 person1.m 和 person2.m 指向 同一个 Money 对象改一个另一个也变。改造之后tmp.m 指向新 Money 和原对象彻底断开就不会说改变一个另一个跟着改变四.objiect类1.object类是Java默认的一个类Java里除了object类所有的类都存在继承关系会默认继承object类万类之父类所有类的对象都可以使用object2.object有一些已经定义好的方法ObjectgetClass: ClasshashCode: int *****************************equals(Object): boolean *****************************clone: ObjecttoString: String *****************************notifyo: voidnotifyAlij: voidwait: voidwait(long): voidwait(long, int): voidfinalizevoid3.equals方法一样的东西通过等号判断发现他们并不相等这时候先给结论必须用equals方法进行判断。但是直接使用equals方法判断也不行由于之前学过方法的重写这时候想起来抽象类或者接口的方法都要重写呢结果重写了之后就报正确这里补充Java里的如果全是基本类型变量则是比较变量的值是否相同如果两侧是引用数据类型变量则比较的是引用变量地址是否相同如果要比较对象中的内容必须重写object里面的equals方法因为equals方法默认是按照地址来进行比较的4.hashCode如果一样的话hashCode会返回相同的值但是前提要是同类里面自己和自己比猫和狗是不互通的如何通过方法交换实参的值该法不能够改变实参不能够交换实参的值调用 swap(a, b) 时Java 把 a 的值 复制一份 给 x 把 b 的值 复制一份 给 y 。方法里交换的只是这两个复制品局部变量 x 和 y 真正的 a 和 b 在 main 里纹丝不动。所以输出还是 10 20 。调用 swap2(myValue1, myValue2) 时Java 同样传的是值的拷贝——但这里拷贝的是引用可以理解为对象的地址。 myV1 和 myValue1 指向同一块内存中的同一个对象。所以通过 myV1.val 修改对象内部的字段就等于修改了 myValue1.val 。交换的是对象里的数据而不是引用本身。也就是说基本类型传的是值的拷贝方法内改不了外面对象引用传的也是引用的拷贝但拷贝的引用指向同一个对象所以改对象内部能影响到外面。能成功是因为它交换的是对象里的字段失败是因为它试图交换局部变量的拷贝五.内部类5.1.静态内部类首先实例化有点不太一样然后静态内部类当中只能访问外部类当中的静态成员其他的成员可以通过.来引用访问创建内部类的对象不需要先创造外部类的对象5.2.实例内布类与5.1基本类似其中如果同名的话要么实例化然后直接.调用要么类.this.xxxxx实例内部类包含两个this一个是实例内部类自己的一个是外部类名.this5.3.匿名内部类一般情况和接口相关连一般的匿名内部类就如图匿名内部类与接口5.4.局部内部类很少用谁会在类里面写一个类六.