目录
一、抽象类与抽象方法
1、抽象类
在面对对象的概念中,所有的对象都是通过类来描绘的,但是反之,并不是所有的类都是用来描绘对象的,抽象类就是这样的一种特殊的类。抽象类不能实例化对象,但是类的其他功能依然存在,正是因为抽象类不能实例化对象,所以抽象类必须被继承才能被使用。在java中抽象类表示的其实是一种继承关系,一个类只能继承一个抽象类,而一个类却可以实现对个接口。
可能你会疑惑,既然抽象类不能实例化对象,但是又有其他类一样的功能,那要它干嘛,不是多余嘛?其实抽象类起的作用就是一个规范作用。抽象类为所有子类提供了一个通用模版,子类可以在这个模版基础上进行扩展。 通过抽象类,可以避免子类设计的随意性。通过抽象类,我们就可以做到严格限制子类的设计, 使子类之间更加通用。
抽象类的实现:在java中使用abstract 来定义抽象类。
2、抽象方法
抽象方法包含在抽象类中,它是一种特殊的成员方法,它没有方法体,只有声明,它与抽象类一样,定义的是一种“规范”,该方法具体的实现由它的子类确定。abstract关键字同样用来定义抽象方法,抽象方法没有定义,方法名后面直接跟分号,而不是花括号。
声明抽象方法会造成两个结果:
①、如果一个类包含抽象方法,那么这个类必须是抽象类。
②、继承抽象方法的子类必须重写该方法,否则,该子类也必须声明为抽象类。最终,必须有子类实现该抽象方法,否 则,从最初的父类到最终的子类都不能用来实例化对象。
要点:
1、抽象类和抽象方法必须用abstract关键字来修饰
2、抽象类不能被实例化,只有抽象类的非抽象子类才可以创建对象;
3、抽象类可以包含变量、方法和构造方法。
4、抽象类中不一定含有抽象方法,但是有抽象方法的类必定是抽象类
5、抽象类中的抽象方法只是声明,没有方法体。
6、抽象类的子类必须给出抽象类中抽象方法的具体实现,否则该子类也是必须是抽象类。
7、构造方法、类方法(用static修饰的方法)不能声明为抽象方法。
package cn.cou.pack;
public class TestAbstract {
public static void main(String agrs[]) {
//Animal animal = new Animal(); //抽象类不能实例化对象,所以此处不允许
Lion lion = new Lion();//可以使用
lion.name = "辛巴";
lion.age = 3;
lion.address = "非洲大草原";
System.out.print(lion.name+",年龄"+lion.age+"岁,来自"+lion.address+",");
lion.carnivore();
lion.germ();//调用子类重写的germ方法
}
}
abstract class Animal{ //定义Animal抽象类
String name;
int age;
String address;
void carnivore() {
System.out.println("喜欢吃肉");
}
void herbivore() {
System.out.println("喜欢吃草");
}
abstract void germ();//声明一个抽象方法;只有声明,没有方法体
}
class Lion extends Animal{ //子类Lion类继承抽象类
void germ() { //子类重写该抽象方法
System.out.println("微生物啥都吃");
}
}
二、接口( interface )
在java中,接口是一个抽象类型,是抽象方法的集合,是比“抽象类”还“抽象”的“抽象类”,(但是接口不是类,后面再说)可以更加规范的对子类进行约束。 接口可以简单理解为就是规范,定义的是一组规则,体现了现实世界中“如果你是…则必须能…”的思想。接口的本质是契约,就像我们的法律一样。制定好后大家都必须遵守。
接口通常以interfce来声明。一个类通过继承接口的方式来继承接口的抽象方法。接口并不是类,它们属于不同的概念,但是编写接口的方式和类很相似。类描述对象的属性和方法。接口则包含类要实现的方法。接口无法被实例化,但是可以被实现。一个实现接口的类必须实现接口内所描述的所有方法,否则就必须声明为抽象类。
接口与类的相似点:
1、一个接口与一个类一样,都可以有多个方法
2、接口文件保存在 .java结尾的文件中,文件名使用接口名(即在我们创建一个接口时,不在是点class,而是点interface)
3、接口的字节码文件保存在 .class 结尾的文件中
4、接口相应的字节码文件必须在与包名称相匹配的目录结构中
接口与类的区别:
1、接口不能用于实例化对象
2、接口没有构造方法
3、接口中所有的方法都必须是抽象方法
4、接口不能包含成员变量,但是可以有static 和 final 变量
5、接口不是被类继承了,而是要被类实现
6、接口支持多继承
接口与抽象类的区别:
1、抽象类中的普通方法可以有方法体,能实现方法的具体功能;但是接口中的方法都是抽象方法,所以全部没有方法体,不能实现方法的具体功能。(注意:在jdk1.8以后,接口里可以有静态方法和方法体了,这个我在最后进行了补充,详情请看最后补充部分)
2、抽象类中的成员变量可以是各种类型的,而接口中的成员变量只能是public static final类型的。
3、接口中不能含有静态代码块以及静态方法,而抽象类是可以有的。
4、一个类只能继承一个抽象类,而一个类可以实现多个接口。
接口的特点:
1、接口是隐式抽象的,当声明一个接口时,不必使用abstract关键字。
2、接口中的每一个方法都是隐式抽象的,接口中的方法会被隐式的指定为 public abstract ,所以当声明方法时,也不必写abstract关键字,同时接口的方法都是公有的。
3、接口中可以含有变量,但是接口中的变量会被隐式的指定为 public static final 变量。
4、接口中的方法是不能在接口中实现的,只能由实现接口的类来实现接口中的方法。
接口的声明:
public interface 接口名称 [extends 其他接口名]
{
//声明变量
//抽象方法
}
案例:
/*文件名 TestInterface.java */
package cn.cou.pack;
public abstract interface TestInterface {
public void eat();
public void wear();
public void live();
public void move();
}
接口的实现:类使用implements关键字实现接口,在类声明中,implements关键字放在class声明后面。在类实现接口的时候,要实现接口中所有的方法。否则,该类必须声明为抽象类。
案例:
/*文件名 TestInterfaceClass.java */
package cn.cou.pack;
public class TestInterfaceClass implements TestInterface { //实现TestInterface接口
public void eat() { //重写方法时与接口的方法名保持一致
System.out.println("吃");
}
public void wear() {
System.out.println("穿");
}
public void live() {
System.out.println("住");
}
public void move() {
System.out.println("行");
}
public static void main(String[] args) {
TestInterfaceClass tic = new TestInterfaceClass();
tic.eat();
tic.wear();
tic.live();
tic.move();
}
}
接口的继承:一个接口可以继承另一个接口,和类之间的继承方式相似。接口的继承也是使用extends 关键字。
案例:
/* 文件名: TestInterface1.java */
package cn.cou.pack;
public interface TestInterface1 extends TestInterface{ //接口的继承
public void study();
public void play();
}
/*文件名 TestInterfaceClass1.java */
package cn.cou.pack;
public class TestInterfaceClass1 implements TestInterface1 { //实现TestInterface1接口
/*
* TestInterface1接口继承了TestInterface接口的四个方法,本身自己有2个方法,一共六个方法,必须全部实现
*/
public void eat() { //重写方法时与接口的方法名保持一致
System.out.println("吃");
}
public void wear() {
System.out.println("穿");
}
public void live() {
System.out.println("住");
}
public void move() {
System.out.println("行");
}
public void study() {
System.out.println("学习");
}
public void play() {
System.out.println("玩");
}
public static void main(String[] args) {
TestInterfaceClass tic = new TestInterfaceClass();
tic.eat();
tic.wear();
tic.live();
tic.move();
tic.study();
tic.play();
}
}
接口的多继承:在java中,类的多继承是不合法的,但接口允许多继承。在接口的多继承中只使用extends一次,后面跟继承接口
//程序片段
public interface 接口名称 extends 接口名称1,接口名称2...{
}
一个类可以同时实现多个接口:
public class 类名称 implements 接口名称,接口名称1,接口名称2....{
}
注意:实现的接口中,父接口与子接口不能同时存在。
补充:
在前面我们说,接口中没有静态方法和方法体,但是在jdk1.8之后(后来更名后称为jdk8,如今最新的是jdk13),接口中开始允许定义默认方法和静态方法
1、默认方法
格式:
public default 返回值类型 方法名(参数列表){
//方法体
}
默认方法是一种扩展接口的方法,而且不破坏现有代码。比如说:如果一个已经投入使用的接口需要扩展添加新的方法,在java8之前,我们必须在该接口的所有实现类中都新添加该方法的实现,否则就会编译出错,对于实现类少且有修改权限的可能工作量会小,但是对于实现类很多或者没有修改权限的就很难去解决了,而默认方法就提供了一个实现,这样新添加的方法就不破坏现有代码,而且大大减少了工作量。默认方法允许接口方法定义默认实现,子类方法不用必须实现此方法就可以拥有该方法及实现。
案例分析:
接口:
/*文件名 InterfaceSup.java */
public interface InterfaceSup { //接口
public void method();//
public default void defaltMethod() {
System.out.println("这个是新添加的默认方法");
}
}
实现类:
/* 文件名:InterfaceClass.java */
public class InterfaceClass implements InterfaceSup{ //实现类
public void method() {
System.out.println("重写接口中的抽象方法");
}
public static void main(String[] args) {
InterfaceClass ic = new InterfaceClass();
ic.method();
ic.defaltMethod();//如果在实现类中重写了默认方法,则调用的是重写后的方法
}
}
2、静态方法
格式:
public static 返回值类型 方法名 (参数列表) {
//方法体
}
接口中的静态方法类似于类中的静态方法,接口中定义的静态方法可以独立于任何对象调用。所以,在调用静态方法时,不需要实现接口,也不用接口的实例,调用方法和类调用静态方法的方式类似。
值得注意的是:接口中的静态方法不能被子接口继承;使用static修饰的接口中的方法必须有主体;接口的静态方法不能被实现类重写或者直接调用;接口中的静态方法只能被接口本身调用。
案例:
接口:
/*文件名:InterfaceSup1.java */
public interface InterfaceSup1 {
public void method1();
public static void staticMethod() {
System.out.println("静态方法");
}
}
实现类:
/*文件名:InterfaceClass1.java */
public class InterfaceClass1 implements InterfaceSup1{
public void method1() {
System.out.println("重写抽象方法");
}
public static void main(String[] agrs) {
InterfaceClass1 in = new InterfaceClass1();
in.method1();
//in.staticMethod();//不能被实现类的对象调用
InterfaceSup1.staticMethod();//接口本身直接调用
}
}
3、私有方法
从java9开始,接口中允许定义私有方法,当我们在一个接口里写多个默认方法或者静态方法的时候,可能会遇到程序重复的问题,创建一个新方法,用private进行修饰,这样就创造了一个只有接口可以调用的私有方法。所以,私有方法又分为静态私有方法和普通私有方法。
普通私有方法:解决多个默认方法之间重复代码的问题
格式:
private 返回值类型 方法名称(参数列表) {
//方法体
}
静态私有方法:解决多个静态方法之间重复代码的问题,静态私有方法不需要通过实现类使用,通过接口名直接调用,
格式:
private static 返回值类型 方法名称(参数列表){
//方法体
}
案例分析:
接口:
/* 文件名:InterfaceSup2.java */
public interface InterfaceSup2 {
private static void methodStaticPrivate() {
System.out.println("静态私有方法");
}
private void methodDefaultPrivate() {
System.out.println("普通私有方法");
}
public static void methodStatic() {
System.out.println("静态方法");
methodStaticPrivate(); //私有方法只能在本接口中使用
//methodDefaultPrivate();//不能对非静态方法进行静态引用
}
public default void methodDefault() {
System.out.println("默认方法");
methodStaticPrivate();//静态方法可以进行非静态引用
methodDefaultPrivate();
}
}
实现类:
/*文件名: InterfaceClass2.java */
public class InterfaceClass2 implements InterfaceSup2{
public static void main(String[] args) {
InterfaceClass2 m = new InterfaceClass2();
m.methodDefault();//实现类对象引用非静态方法
System.out.println("\n");
InterfaceSup2.methodStatic();//静态方法通过接口直接调用
}
}