抽象类
abstrac关键字修饰的类
有抽象方法的类,必须是抽象类(方法和类都得加abstract关键字);
抽象类里可以没有抽象方法。
注意:1,抽象类和其他类的区别就是他不可以实例化对象(他就是用来被继承的),但可以有自己的成员变量,构造方法,成员方法。
2,可以有构造方法(当子类创建对象给其赋值)
3,抽象类的子类:要么是继续做抽象类,要么重写抽象类里的所有抽象方法
抽象方法
abstract修饰, 将子类共性的方法 (行为)抽取到 父类,由于每个子类执行的方法内容不一样, 父类不能确定方法体,就可以将其定义为抽象方法. 子类需要时再 进行重写,这样做可以统一规范子类方法的名字,形参,返回值类型等问题。
抽象方法不能被private,final,static修饰,因为修饰了子类就不能重写.
作用
因为方法重写只能是方法体不一样, 强制子类按照这个抽象方法格式重写,对同一行为方法统一名字,方便项目开发---其他开发人员对整个项目的理解和维护更加容易。
虽然用普通类也可以实现这个目的,但用抽象类,不规范的地方编译器会报错。比如创建了父类示例 ,重写改变了形参的格式
public abstract class Animal{
//抽象方法不需要写方法体,他定义为抽象方法就是为了让其他类重写
public abstract void eat(){}
}
//子类 Dog.java
public class Dog extends Animal{
@override
public void eat(){
//不重写就会报错,提醒子类重写方法体
System.out.println(name + "不吃饭");
}
}
// 子类 Cat.Java
public class Cat extends Animal{
@override
public void eat(){
System.out.println(name + "喜欢吃面");
}
}
接口
什么是接口?
接口定义了一种规则,行为规范,一种引用数据类型。想让哪个类拥有这类行为就让这个类去实现相应的接口。
接口多态:当一个方法的参数是接口时,可以传递接口的所有实现类对象.
格式
跟定义类的格式相同,将class关键字换成interface就实现了接口的定义
public interface 接口名{};

接口中成员的特点
属性:只能初始化常量,默认修饰符public static final
构造方法:没有( 接口不能被实例化 )
方法:只能是抽象方法,默认修饰符public abstract
注:jdk7以前只能定义抽象方法
jdk8可以定义默认方法,静态方法
jdk9可以定义私有方法
在接口中,只有static ,default,private修饰的方法可以有方法体,因为不能被重写。
默认方法
格式: default 返回值格式 方法名(参数列表){
}
用default修饰,不能省略,省略了就是默认修饰符;
提供默认实现,实现类可选择覆盖;
主要用于接口演化(向后兼容);
要实现多个接口中的默认方法,若存在多个默认方法的名字相同,则子类必须对该默认方法进行重写(因为名字相同对象就会不知道到底该调用哪一个方法)
静态方法
格式:public static 返回值格式 方法名(参数列表){
}
方法static不能省略,直接用接口名调用
私有方法
方法中重复的代码抽取出来定义的方法 ,减小代码冗余
这是为内部方法服务的外界调用没有意义,所以用private修饰
为默认方法服务
格式:private void 名(){}
为静态方法服务
格式:private static void 名(){}
接口和类之间的关系
类与类: 只能单继承(extends), 不能多继承,但是可以多层继承.
类与接口:可以单实现(implements),也可以多实现.可以在继承一个类的同时实现多个接口
接口与接口:可以单继承(extends),也可以多继承.继承的子类必须重写全部父类的抽象方法
extends扩展的意思,实现继承的作用,接口继承接口,相当于是把所有的抽象方法结合在一起。
实现接口可以解决类不能多继承的局限性,就是让很多类用同一个规范实现自己的特性。
interface IRunning {
void run();
}
interface ISwimming {
void swim();
}
// 两栖的动物, 既能跑, 也能游
interface IAmphibious extends IRunning, ISwimming {
}
class Frog implements IAmphibious {
...
}
接口的使用
一个类实现多个接口时,所有接口的抽象方法都要重写,如果不能则应设置为抽象类,因为抽象类里面可以存在其他非抽象方法。
interface IFlying {
void fly();
}
interface IRunning {
void run();
}
interface ISwimming {
void swim();
}
子类继承父类并实现三个接口(想让duck实现哪种行为就实现相应接口,并重写里面的所有方法)
class Duck extends Animal implements IRunning, ISwimming, IFlying {
public Duck(String name) {
super(name);
}
@Override
public void fly() {
System.out.println(this.name + "正在用翅膀飞");
}
@Override
public void run() {
System.out.println(this.name + "正在用两条腿跑");
}
@Override
public void swim() {
System.out.println(this.name + "正在漂在水上");
}
}
空接口
一些接口里面没有抽象方法,名字又一般是形容词后缀-able的空接口,他的作用是标识,又称为标识接口。
public interface Cloneable{}; 继承这个接口的类表示可以被克隆,拷贝。
克隆,拷贝是什么?
将原来对象里的内容复制一份,放在另一个独立的内存空间,他们的地址不一样。
什么是浅拷贝?
拷贝的当前对象里还有其他类型的对象没有被拷贝。
深拷贝
克隆出完全独立于原来对象的对象。
实现排序的接口
public interface comparable{} ;
Arrays.sort(),Collections.sort()这两个方法内部都实现了comparable接口,来实现对数组,集合的升序排序。
排序需要类实现comparable接口,重写内部的方法。但接口里只有comparTo(T),根据一个属性进行升序或者降序排序,不能适用复杂多变的情况。
public class User implements Comparable<User>{ //实现接口后,指定泛型具体的类型
private int id;
private String name ;
@Override
public int compareTo(User o) {
return this.id-o.id;//根据id升序,o.id-this.id就是降序
//根据id升序排列, 就不能用其他的方法排列,有很大局限性
}
}
public interface comparator{};
如果要实现根据多个属性排序,自定义排序规则,就需要实现comparator接口,自定义比较器。
比较器有很多方法,可以满足很多需求。
Comparator有@FunctionalInterface,表明是函数式接口,可以用lambda表示式表示;
ArrayList<User> num=new ArrayList<>();
//匿名内部类形式
Collections.sort(num, new Comparator<User>() {//匿名内部类实现了Comparator接口,重写compare方法
@Override
public int compare(User o1, User o2) {
return o1.getId()-o2.getId();//根据User的id进行排序,
}
});
//lambda表达式形式
Collections.sort(num,((o1, o2) -> o1.getName().compareTo(o2.getName())));//字符串根据字典序排序
比较
特性 | Comparable | Comparator |
---|---|---|
包位置 | java.lang | java.util |
接口定义 | int compareTo(T o) | int compare(T o1, T o2) |
排序逻辑位置 | 类的内部 | 类的外部(定制排序) |
使用场景 | 类有默认排序规则时 | 需要多种排序方式时 |
修改要求 | 需要修改类本身(在类上实现comparable接口) | 无需修改原类(自定义比较器,参数类型为要比较的对象) |
接口特性
1.因为接口是引用数据类型,所以不能new对象,接口中不能有静态代码块和构造方法;
2.接口的方法默认是public修饰,不用加其他权限修饰符(要能被其他类实现),重写接口方法也只能是public(重写的方法访问权限不能小于父类);
3.接口虽然不是类,但是接口编译完成后字节码文件的后缀格式也是.class。
抽象类和接口的区别
1.虽然都不能实例化,但抽象类可以有构造方法,非抽象方法和成员变量,接口只能有成员常量和抽象方法 ;
2.抽象类之间只能单继承,接口之间可以多继承;
3.定义的关键字不一样,类class,接口interface;
实现他们的关键字也不一样,类extends,接口implements。