一、abstract抽象类
1、在继承的层次结构中,随着每个新子类的不断出现,类会变得越来越明确和具体,而从子类追溯父类,那么类就会更加通用和不明确。当一个父类设计得非常抽象时,以至于它都没有具体的实现时,这样的类就可以用abstract申名为抽象类。
2、抽象类的好处是:可以使用抽象类来实现多态,即让JVM在运行时根据对象的类型动态地决定调用哪个方法。
例如:
public abstract class Geometric {
private String color;
private Date dateCreated;
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public Date getDateCreated() {
return dateCreated;
}
public void setDateCreated(Date dateCreated) {
this.dateCreated = dateCreated;
}
public abstract double getArea();
}
public class Circle extends Geometric {
private double radius;
public double getRadius() {
return radius;
}
public void setRadius(double radius) {
this.radius = radius;
}
public Circle(double radius) {
super();
this.radius = radius;
}
public double getArea() {
return radius * radius * Math.PI;
}
}
public class Rectangle extends Geometric {
private double width;
private double length;
public Rectangle(double width, double length) {
super();
this.width = width;
this.length = length;
}
public double getWidth() {
return width;
}
public void setWidth(double width) {
this.width = width;
}
public double getLength() {
return length;
}
public void setLength(double length) {
this.length = length;
}
public double getArea() {
return length * width;
}
public double getPerimeter(){
return 2 * (length + width);
}
}
public class TestGeometric {
public static boolean equalArea(Geometric geometric1,
Geometric geometric2) {
return geometric1.getArea() == geometric2.getArea();
}
public static void main(String[] args){
Geometric circle = new Circle(2);
Geometric rectangle = new Rectangle(1, 3);
System.out.println("The two objects have same area?");
System.out.println(equalArea(circle, rectangle));
}
}
当调用equalArea方法时,由于circle是一个圆,所以getArea()使用的是Circle类定义的getArea()方法,而rectangle使用的则是Rectangle类的getArea()方法。JVM会在运行时,根据对象的类型动态的决定调用哪一个方法。
注意:因为我们使用抽象类Geometric类引用子类Rectangle,所以我们只能使用Geometric中定义的方法,而不能使用它的子类中特殊的方法。例如:rectangle.getArea()运行正确,但是rectangle.getPerimeter()则会报错。
二、接口
1、接口和抽象类很相似,区别在于:抽象类是将多个相似的对象的相同属性和行为进行抽象组成的,是一种父子类的关系,区别在于抽象的程度不同。而接口则是定义多个对象的共同行为,这些对象可以相似或者不相似,但他们拥有相同的行为。
2、例如:
/*
* 可食用的接口定义了相关的与吃的动作
*/
public interface Edible {
public void howToEat();
}
public abstract class Animal {
}
public class Chicken extends Animal implements Edible{
public void howToEat() {
System.out.println("Chicken: fry it");
}
}
public abstract class Fruit {
}
public class Apple extends Fruit implements Edible{
public void howToEat() {
System.out.println("Apple:Make apple pie");
}
}
Edible接口定义了如何吃的接口,所有实现Edible接口的类,说明他们都有共同的行为怎么吃。
注意:接口中的所有的数据域都是 public fianl static,所有的方法都是public abstract
3、一个类可以实现多个接口,而只能继承一个抽象类
4、接口和抽象类类似,也可以作为引用变量的数据类型或类型转换的结果。
5、Comparable接口:java类库中的许多类(String,Date)实现了Comparable接口,以定义对象的自然顺序。而Comparable接口如下:
public interface Comparable {
public int compareTo(Object o);
}
当这个对象相对于给定的对象o是大于,小于,等于时,分别返回正整数,0,负整数。
现在我们就来实现一个求相同类型对象中较大者的通用方法。
两个通用的类,要可以比较大小,那么它们必须实现了Comparable接口,因此可以用接口类Comparable来引用它们。
public class Max {
public static Comparable max(Comparable o1, Comparable o2){
if(o1.compareTo(o2) > 0){
return o1;
}
else{
return o2;
}
}
}
6、Cloneable接口
我们可以使用clone方法进行对象拷贝。
在java.lang包中的Cloneable接口定义如下
public interface Cloneable{
}
没有常量和方法,只是用来标记继承该接口的类可以克隆。clone方法已经在Object中实现了,它的方法头如下
protected native Object clone() throws CloneNotSupportedException
native 表明这个方法不是用java写的。关键字protected限制了方法只能在同一个包内或者子类使用。因而要使用clone的类,在实现Cloneable接口标记该类可以克隆之外,还需要重载这个方法,用public来修饰,使得它可以在任何一个包中使用。
具体举个例子:
public class House implements Cloneable {
private int id;
private double area;
public House(int id, double area) {
super();
this.id = id;
this.area = area;
}
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
public static void main(String[] args) throws Exception {
House house1 = new House(1, 1750.50);
House house2 = house1;
House house3 = (House) house1.clone();
System.out.println("house1==house2?" + (house1 == house2));
System.out.println("house1==house3?" + (house1 == house3));
}
}
结果为:
house1==house2?true
house1==house3?false
house2只是将house1的引用赋给它。
Object类中的clone方法将原始对象中的每个数据域复制给目标对象。如果一个数据域是原始类型,复制的就是它的值。如果一个数据域是对象,复制的就是该域的引用。
这称为浅复制。如果希望完成深复制,可以在调用super.clone()之后,自定制克隆操作来覆盖clone方法。
三、接口与抽象类
1、抽象类与接口都是用来明确多个对象的共同特征的,但是抽象类更多的描述父子关系中的strong-is-a relationship(公历是一种日历),接口则是weak-is-a relationship,它更多的描述对象拥有的某种属性(例如所有的字符串都是可比较的Comparable接口)。
推荐使用接口而不是抽象类是因为接口可以定义不相关类共有的父类型