在定义一个类时,常常需要定于一些方法来描述该类的行为特征,但是有时候这些方法的实现方式是无法确定的。如定义了一个Employee类,它的work()方法描述的是工作,但是对于不同的岗位,他们的工作也是不一样的。为此,我们使用abstract关键字,我们只需要在父类中只是定义方法名,而不实现具体的方法体。
abstract可以修饰类、修饰方法
1.abstract修饰类:抽象类
① 无法实例化,可以没有抽象方法
② 一定有其构造器,便于子类实例化调用
③ 抽象方法由其子类实现
2.abstract修饰方法:抽象方法
① 抽象方法没有方法体
② 抽象类中可以没有抽象方法
③ 子类实现了父类的所有抽象方法,才可以实例化
1.什么是接口?
如果一个类中所有的方法都是抽象的,则可以把这个类定义为Java中的另一种形式—接口,接口是一种特殊的抽象类,和类是并列的结构。
JDK 7及以前,接口中不能包含普通方法,只能在接口内部定义抽象方法和全局常量。
JDK 8及以后,除了JDK 7中的性质,还可以有默认方法和静态方法(也叫类方法),默认方法使用default修饰,静态方法使用static修饰,这两种方法都允许有方法体。
2.接口如何使用?
使用interface定义,其中[]括号内修饰的关键字可以省略不写。
[权限修饰符] interface 接口名 [extends 父接口1,父接口2,...]{
[public] [static] [final] 常量类型 常量名 = 常量值;
[public] [abstract] 返回值类型 方法名([参数列表]);
[public] default 返回值类型 方法名([参数列表]){
//默认方法的方法体;
}
[public] static 返回值类型 方法名([参数列表]){
//静态方法的方法体
}
}
public class Test {
public static void main(String[] args) {
Dog dog = new Dog();
Animal.show(); //静态方法调用:接口名.方法名
dog.eat(); //抽象方法调用:对象名.方法名
dog.sleep(); //默认方法调用:对象名.方法名
//Cat cat = new Cat(); //无法实例化类型Cat
//cat.eat();
}
}
interface Animal{
public static final int id = 1; //常量
String name = "小黄"; //常量
public abstract void eat(); //抽象方法eat()
public abstract void getName(); //抽象方法getName()
public static void show() { //静态方法
System.out.println("id = "+id+", name = "+name);
}
public default void sleep() { //默认方法
System.out.println("所有的动物都要睡觉!");
}
}
class Dog implements Animal{
public void eat() {
System.out.println("狗吃肉!");
}
public void getName() {
System.out.println("name = "+name);
}
}
abstract class Cat implements Animal{ //只实现了一个抽象方法,定义为抽象类(无法实例化)
public void eat() {
System.out.println("猫吃鱼!");
}
}
3.关于接口的说明:
① 接口中不能定义构造器,意味着接口无法实例化,若子类实现(implements)了接口中所有的抽象方法,则子类可以实例化;反之,若实现(implements)了部分的抽象方法,则无法实例化。
② 接口之间可以单继承也可以多继承,一个类可以继承某个父类的同时实现多个接口。
JDK 8以后接口的新特性:
三.内部类(了解认识即可)① 实现类调用接口中的默认方法:对象名.方法名。如果实现类重写了接口中的默认方法,调用时,调用的是重写以后的方法
② 如果实现类继承的父类和实现的接口中声明了同名同参数的默认方法,那么子类在没有重写此方法的情况下,默认调用的是父类中的同名同参数的方法。—>类优先原则
③ 如果实现类实现了多个接口,而这多个接口中定义了同名同参数的默认方法,那么在实现类没有重写此方法的情况下,报错。—>接口冲突。这就需要我们必须在实现类中重写此方法
④ 子类中调用重写之前的父类或接口中的方法:接口名.super.方法名() 或 父类名.super.方法名();
⑤ 默认方法只允许在接口中使用,实现类中需要重写时去掉default关键字。
在java中,允许一个类A的内部再定义一个类B,这个类B就成为内部类,类A称为外部类。根据内部类的位置,分为成员内部类、局部内部类。
1.成员内部类:
① 外部类的成员:
调用外部类的结构,可以用static修饰,可以使用四种权限修饰符修饰;
② 作为一个类:
可以定义属性、方法,可以被final、abstract修饰,分别表示不能被继承、不能实例化。
创建内部类对象:
外部类名.内部类名 对象名 = new 外部类名().new 内部类名()
创建静态内部类:
外部类名.静态内部类名 对象名 = new 外部类名.静态内部类名()
//内部类的使用说明1:成员内部类、静态内部类、
public class Exampletest01 {
public static void main(String[] args) {
Outer.Inner inner = new Outer().new Inner(); //创建内部类的对象
inner.print();
// inner.show(); //在Inner类中show()方法未定义,不可以调用外部类的show方法
Outer.Inner01 inner01 = new Outer.Inner01(); //创建静态内部类的对象
inner01.say();
Outer outer = new Outer(); //创建外部类的对象,调用局部内部类
outer.show();
}
}
class Outer{ //外部类
int m = 0;
public void show(){
System.out.println("外部类的show方法!");
}
class Inner{ //1.成员内部类
int n = 0;
public void print() {
System.out.println("成员内部类的print方法!");
}
}
static class Inner01{ //2.静态内部类
int x = 5;
public void say() {
System.out.println("静态内部类的say方法!");
}
}
}
//内部类的说明2:匿名内部类的使用
public class Example02 {
public static void main(String[] args) {
String name = "小花";
animalShout(new Animal() { //定义匿名内部类传递参数给animalShout()方法
public void shout() { //实现shout方法
System.out.println(name+"喵喵...");
}
});
}
public static void animalShout(Animal an) {
an.shout(); //调用传入对象的shout方法
}
}
interface Animal{ //定义动物类接口
public void shout();
}
2.局部内部类:
也叫方法内部类,他和局部变量一样,是定义在方法内部的,有效范围仅限于方法内部。
1.下面的程序是否编译出错?不出错结果是多少呢?
答:编译出错,因为x不明确是父类B中的还是接口A中的,若想输出父类A中的x,则父使用super.x调用;若使用接口B中的x,则使用接口名B.x调用,因为接口中定义的只能是常量。
2.下面的程序是否编译出错?不出错结果是多少呢?
答:箭头处变量ball是常量,不允许再次赋值。关于play()方法重写,认为是对接口Playable和接口Bounceable的重写。
3.抽象类和接口有何异同?
相同点:
不能实例化,都可以包含抽象方法;
不同点:
抽象类:有构造器,可以实例化,可以没有抽象方法,只能定义常量。
接口:没有构造器,不能实例化,必须有抽象方法,可以继承一个类的同时实现多个接口,接口之间可以单继承也可以多继承;jdk 8 及以后,接口中可以定义默认方法、静态方法,都可以有方法体。



