java——抽象类、接口、二者区别
抽象类:
抽象方法:不包含方法体的方法为抽象方法,抽象方法必须使用abstract关键字来修饰:
abstract void method();
抽象类:当一个类中包含了抽象方法时,该类必须使用abstract关键字来修饰。抽象类可以不包含抽象方法,但是有抽象方法的类一定是抽象类。
abstract ABC {
public abstract String getXXX();
...
}
抽象类不能创建一个类的对象。
子类必须实现抽象类定义的抽象方法。
抽象类不能被关键字final修饰(final关键字修饰的类不可被继承), abstract不能和static(static是静态的,而abstrict是动态的,必须通过类继承或接口实现来动态重写abstrict方法)、private(private修饰的方法只能在类中调用,重写时是访问不到这些方法和属性的)、final(final关键字修饰的方法不可被重写)、native并列修饰同一方法。
举个栗子:
abstract class Goods {
public Goods(String name, double price, double num) {
this.name = name;
this.price = price;
this.num = num;
}
public String getName() {
return this.name;
}
public double getPrice() {
return this.price;
}
//返回总消费
public abstract double getTotalPrice();
//输出商品信息
public abstract String toString();
//同一包中以及不同包中该类的子类,如果用private 那子类就不能用这个属性了
protected String name;
private double price;
protected double num;
}
class AmountGoods extends Goods{
public AmountGoods(String name, double price, int amount) {
super(name, price, amount);
}
//自己特有的方法
public int getAmount() {
return (int)this.num;
}
public double getTotalPrice() {
return this.getPrice() * this.num;
}
public String toString() {
return this.getName()+"\t"+this.getPrice()+"\t¥/个";
}
}
class GravityGoods extends Goods{
public GravityGoods(String name, double price, double gravity) {
super(name, price, gravity);
}
public double getTotalPrice() {
return this.getPrice()*this.num;
}
public String toString() {
return this.name+"\t"+this.getPrice()+"\t¥/斤";
}
public double getGravity() {
return this.num;
}
}
public class AbstractDemo{
public static void main(String[] args) {
AmountGoods goods1 = new AmountGoods("苹果", 2.5, 5);
GravityGoods goods2 = new GravityGoods("草莓", 10, 8);
System.out.println(goods1.toString()+"\t 数量"+goods1.getAmount()+"\t 计价"+goods1.getTotalPrice());
System.out.println(goods2.toString()+"\t 数量"+goods2.getGravity()+"\t 计价"+goods2.getTotalPrice());
}
}
接口:
1.如果一个抽象类的所有方法都是抽象的,则可以将这个类用另外一种方式来定义,即接口。
2.接口是由常量和抽象方法组成的特殊类,是对抽象类的进一步抽象,接口的目的是为了实现多继承。
3.用interface来声明。
4.要继承接口的类需要用implements关键字,需要注意的是一个类实现一个接口,必须给出接口中所有方法的实现,如果不能实现某方法,也必须写出一个空方法。
5.一个类在继承另一个类的同时还可以实现接口,此时extends关键字必须位于implements关键字之前。
抽象类实现接口:
在接口中没有实现的方法必须声明为抽象方法。
派生接口:
一个接口可以派生一个新的接口,该接口称为拓展接口。
接口之间的继承用extends。
Comparable接口:
Arrays类中的sort方法可以对数组进行排序,可以通过实现Comparable实现想要的排序。
下面是上述几个接口的例子
package follow_pack; import java.util.Arrays; public class exp { public static void main(String[] args) { RectangleSort[] rect = new RectangleSort[10]; for(int i = 0; i<10; i++) { rect[i] = new RectangleSort(i+1,(10-i+0.5)*0.5); } System.out.println("排列前:"); for(RectangleSort e: rect) System.out.println("边长为:\t"+e.getRlong()+"\t"+e.getRwidth()+"\t 面积 = \t"+e.getArea()); Arrays.sort(rect); System.out.println("排序后:"); for(RectangleSort e: rect) System.out.println("边长为:\t"+e.getRlong()+"\t"+e.getRwidth()+"\t 面积 = \t"+e.getArea()); } } // 定义一个接口 interface Shape{ public double getArea(); public double getSideLong(); public static final double PI = 3.14; } // 定义一个类 实现接口 class Rectangle implements Shape{ public Rectangle(double l, double w) { rlong = l; rwidth = w; } public void setRlong(double l) { rlong = l; } public void setRwidth(double w) { rwidth = w; } public double getRlong() { return rlong; } public double getRwidth() { return rwidth; } public double getArea() { return rlong*rwidth; } public double getSideLong() { return (rlong+rwidth)*2; } private double rlong; private double rwidth; } // 抽象类实现接口 abstract class Polygon implements Shape{ protected int sidenumber; public void setSideNumber(int sn) { sidenumber = sn; } public int getSideNumber() { return sidenumber; } public abstract double getArea(); public abstract double getSideLong(); } // 派生接口 interface PolygonInterface extends Shape{ public void setSideNum(int sn); public int getSideNum(); } // Comparable接口 class RectangleSort implements Shape, Comparable<RectangleSort>{ public RectangleSort(double l, double w) { rlong = l; rwidth = w; } public void setRlong(double l) { rlong = l; } public void setRwidth(double w) { rwidth = w; } public double getRlong() { return rlong; } public double getRwidth() { return rwidth; } public double getArea() { return rlong*rwidth; } public double getSideLong() { return 2*(rlong + rwidth); } // 声明compareTo方法 public int compareTo(RectangleSort other) { if(this.getArea()<other.getArea()) return -1; else if(this.getArea()>other.getArea()) return 1; else return 0; } private double rlong; private double rwidth; }
接口中定义常量:
任何接口中定义的常量必须为public static final类型,因此java允许省略此类修饰符。
Cloneable接口:
clone()方法是object类的一个protected方法,因此用户不能直接调用该方法。clone()方法默认实现浅拷贝。
如果一个程序要进行克隆处理,就要继承这个接口。
public class Audience implements Cloneable{ //声明构造方法 public Audience(String name) { this.name = new StringBuffer(name); id = flag; } public void setName(String name){ StringBuffer temp = new StringBuffer(name); if(this.name != null) { this.name.replace(0, name.length(), name); }else { this.name = temp; } } public String toString(){ return "name:\t" + name +"\tid:\t" +id; } //初始化语句块,如果不加{}会怎样? { flag++; } //浅拷贝,这种重写clone()只是把clone变成了public // public Object clone() throws CloneNotSupportedException{ // return (Audience)super.clone(); // } //深拷贝,和浅拷贝不同的是,这个clone返回的对象是这个方法中新建的一个对象,占用了一块新的内存单元 public Object clone() { Audience object = null; try { //完成数值类型变量的值传递,也就是说先把被拷贝对象的值赋值给新对象。 object = (Audience)super.clone(); }catch(CloneNotSupportedException e){ System.out.println(e.toString()); } //因为是au1.clone(),所以name是au1.name,也就是“quanquan” //当执行了au2.setName()之后au2.name里面就变成了“duoduo” //因为string不是基本数据类型, //上一步已经把属于基本数据类型的变量复制到一个新的内存单元了 //所以这一步就要把不是基本数据类型的string类型变量放到一个新的内存单元中去 object.name = new StringBuffer(name); return object; } private StringBuffer name; private static int flag=0; private int id; public static void main(String[] args) { Audience au1 = new Audience("quanquan"); Audience au2 = null; au2 = (Audience)au1.clone(); // try{ // au2 = (Audience)au1.clone(); // }catch(CloneNotSupportedException e){ // System.out.println(e.toString()); // } System.out.println(au1.toString()); System.out.println(au2.toString()); au2.setName("duoduo"); System.out.println(au1.toString()); System.out.println(au2.toString()); } }
二者区别:
抽象类:
抽象类不能创建类对象。
表示一种继承关系。
一个类只能继承一个父类。
可以有自己的变量,也可以由非abstract方法。
变量默认为default,变量值可以再子类中重新定义,重新赋值。
接口:
接口的access为public或default。
接口不是类,不能创建接口对象。
表示一种契约关系。
一个类可以实现多个接口。
只允许定义常量,所有方法都是public abstract类型并且可以省略。
接口定义的变量默认是public static final类型,可以省略但是必须给定初值,实现类中不能重新定义,也不能改变其值。