抽象类
首先我们思考一个问题:为什么会出现抽象类呢?也就是说抽象类主要是解决什么类型的问题而出现的?
抽象类是从多个具体类中抽象出来的父类,它具有更高层次的抽象。从多个具有相同特征的类中抽象出一个抽象类,以这个抽象类作为子类的模板,避免了子类设计的任意性。抽象类体现的是一种模板模式的设计,抽象类作为多个子类的模板,子类在这个已有的父类基础上进行扩展,改造,但是子类总体上还是会保留抽象类的行为和方法。(疯狂java讲义中的理解,我认为很好)
注意:
1、抽象类中可以没有抽象方法,但是一旦一个类中有了抽象方法,那么这个类必须被定义为抽象类。
2、abstract修饰的抽象方法是一个没有方法体的方法,他必须在继承了该基类的子类中重写。所以没有static abstract修饰的方法,因为abstract修饰的方法没有方法体,那么他也就不能被类调用,他只能被子类对象调用。但是又static abstract 修饰的类。
3、抽象类,抽象方法更好的发挥了多态的优势,使得程序更加灵活。
4、抽象类不能创建实例。
接口
接口是一种特殊的抽象类,因为接口中的方法全部是抽象的,不存在普通方法,接口中的方法都被默认用abstract修饰了。接口定义的是多个类共同的行为规范,这些行为是与外部交流的通道,这就意味着接口里通常定义的是一组公用方法。
乍一看,貌似和抽象类没有区别,但是这两个东西设计出来的目的是不一样的,这也导致了他们有着本质的区别。
首先,也是最重要的,抽象类是为了更好的发挥多态以及避免子类设计的任意性,但是另一方面,接口是一种规范,凡是实现了这个接口的类,他的对象都会具有接口所赋予的能力,也就是拥有了与外部交流的能力。这个能力分为两个方面:一方面来说,实现该接口的类必须提供接口所规定的服务;另一方面,接口的调用者可以调用哪些服务。
感觉说点有点晕,我们看看代码:
1、抽象类相关代码:
abstract class Animal{
public abstract void say();
public abstract void breath();
public abstract void eat();
}
class Dog extends Animal{
public void say(){
System.out.println("我是一只狗,我发出的声音是“汪汪”");
}
public void breath(){
System.out.println("我是一只狗,我靠肺呼吸");
}
public void eat(){
System.out.println("我是一只狗,我吃的是骨头");
}
}
class Fish extends Animal{
public void say(){
System.out.println("我是一条鱼,我发出的声音很小");
}
public void breath(){
System.out.println("我是一条鱼,我靠泡呼吸");
}
public void eat(){
System.out.println("我是一条鱼,我吃的是蚯蚓");
}
}
public class JavaDemo16{
static Dog d = new Dog();
static Fish f = new Fish();
public static void main(String []args){
d.say();
d.breath();
d.eat();
f.say();
f.breath();
f.eat();
}
}
运行结果:
上面的Animal作为一个基类,定义了动物所具有的公共特征,但是Dog和Fish具有不同的动物行为,所以Dog类和Fish类需要继承Animal并重写Animal中表示动物特征的方法。这样的代码实现,表现了面向对象的多态,并避免了子类设计的随意性。
2、接口代码:
interface Output{
void out();
}
public class Person implements Output{
private String name;
private String sex;
public Person(){
this.name = "李明";
this.sex = "未知";
}
public void out(){
System.out.println("姓名:"+name+",性别:"+sex);
}
public static void main(String []args){
new Person().out();
}
}
运行结果:
上面的代码中定义了一个Output的接口,Person则是实现该接口的类。没有实现这个接口之前,Person还不能完成输出基本信息这个功能,完成后能够输出了。有些人说这没有用,其实,在java中有一些接口如Parcelable,实现该接口就能序列化,这样一来就能使Person的实例对象在进程间传递了。
3、Lambda表达式:
Lambda表达式是为了简化创建只有一个抽象方法的接口的实现类的实例的代码,java 8之后才有这个表达式。
interface Output{
void out();
}
public class Person{
public static void main(String []args){
Output op = ()->{
System.out.println("输出了一个东西");
};
op.out();
}
}
Lambda简化了代码,且只能在创建只有一个抽象方法的接口的实现类的实例对象时使用。