先单独说一个每个的概念和用法,最后再总结两者的区别就很明显了!
抽象:
abstract修饰类和方法的时候:
什么是抽象类?
抽象类是一个不完整的类,不能实例化,他只能做某个类的父类
Java中声明一个类时,可以不给出该类的所有实现细节。然后再定义一个或者多个子类继承抽象父类,重用父类中的代码、扩充并实现其未实现的功能。
抽象类只能声明引用,不能创建对象
什么是抽象方法?
抽象方法只有声明,没有实现
可以这样理解,抽象表示不具体的事务或者东西,既然方法是抽象的类(比如Animal动物类),没有什么是动物,动物只是猫,够,猴子等抽象出来的一个共性叫做动物,所以这种类不具体当然就不能去new对他创建对象。只能通过声明来引用它。
而抽象方法相当于抽象的不具体的动作,既然不具体如何去实现?,
如果一个类中有抽象方法,这个类就必须是抽象类。
但是抽象类中未必有抽象方法;
抽象类中可以有构造方法;
子类继承抽象类,如果子类不希望也成为抽象类,
就必须实现父类中声明的 所有 抽象方法;
抽象类的注意事项:
- 1,抽象类不能实例化
- 2,一个类B继承了抽象类A,若B中没有A中所有抽象方法的具体实现,则B必须声明为抽象类;
- 3,一个类B继承了抽象类A,若B中重写了A所有的抽象方法,则B可以实例化;
抽象方法的访问控制符不能是private。因为抽象方法在代码中是作为被重写方法出现的,如果他是private的,那么抽象类(父类)的外部引用是无法访问private的成员的,破坏了多态机制;
抽象方法也不能是静态的。因为static方法独立于任何实例,因此static方法必须被实现,而不能是抽象的abstract
package test; class TestAbstract{ /** * 抽象 * 类 * 抽象类,只能声明引用,不能创建对象(即抽象类不能实例化 * 方法 * 抽象方法,只有声明,没有实现 * * @param args [description] */ public static void main(String[] args) { Super s; //抽象类,只能声明引用,不能创建对象 //s = new Super(); s = new Sub(); //多态第二条:只能对引用调用其引用类型中声明的方法 s.method(); } } abstract class Super{ //抽象方法,只有声明,没有实现 public abstract void method(); // 空 } class Sub extends Super{ public void method(){ System.out.println("Sub()"); } }
抽象的作用:
利用抽象可以实现把方法声明抽象到父类中,包装一组行为的抽象描述。
而方法实现留在子类,禁止某个类的实例化。
更好的体现“共性放在父类”原则!
接口:
特殊的抽象类
1,所有的属性都是公开静态常量,即接口中的成员变量默认都是public static final 类型的(都可省略,默认有),必须被显示初始化;(接口之间的成员变量为静态常量要大写,单词之间用“_”分隔)
2,所有的方法都是公开抽象方法,即默认都是public abstract 类型的(可省略,默认有),没有方法体,不能被实例化;
3,没有构造方法 ,不能被实例化
4,一个接口不能实现(implements)另一个接口,但可以继承(extends)多个其他的接口
5,接口必须通过类来实现他的抽象方法
6,类实现接口,要实现接口所有抽象方法,否则这个类必须声明为抽象的
接口和接口之间也可以定义继承关系,关键字还是extends
类和类之间是单继承
接口和接口之间还可以多继承
一个类在继承另外一个类的同时,还可以实现多个接口
必须得先写继承类,后实现 接口
因此,要是把接口也看成抽象类,java其实是可以实现多继承
package test; public class TestInterface{ /** * 接口: 特殊的抽象类 *1,所有的属性都是公开静态常量 *2,所有的方法都是公开抽象方法 *3,没有构造方法 * 不能创建对象,可以声明引用 * * @param args [description] */ public static void main(String[] args) { IA a = new Impl(); a.m1(); a.m2(); Impl i = new Impl(); IA a1 = i; IB b = i; IC c = i; ID d = i; ClassE e = i; a1.m(); a1.m1(); a1.m2(); b.mb(); c.mc(); d.mb(); d.mc(); d.md(); e.me(); } } /* 为什么要定义抽象类 留给子类继承 子类需要继承抽象类,实现里面的抽象方法,这样子类可以创建对象; */ interface IA{ public static final int M = 10; //public static final可以不写,默认有 int M1 = 10; double N = 2.78; public abstract void m(); //public abstract也可以省略不写,默认有 void m1(); void m2(); } abstract class ClassA{ abstract void ma(); } interface IB{ void mb(); } interface IC{ void mc(); } interface ID extends IB,IC{ void md(); } abstract class ClassE{ public abstract void me(); } //实现类 //一个类去实现接口,如果这个类不希望也成为抽象类,就必须实现接口中所有方法 //否则这个类也是抽象类 class Impl extends ClassE implements IA,ID{ //public 必须要写,不写的话是默认default public void m1(){ System.out.println("1111"); } public void m2(){ System.out.println("22222"); } @Override public void m() { // TODO Auto-generated method stub } @Override public void me() { // TODO Auto-generated method stub } @Override public void mb() { // TODO Auto-generated method stub } @Override public void mc() { // TODO Auto-generated method stub } @Override public void md() { // TODO Auto-generated method stub } }
作用:
接口的多继承
- 利用接口去实现多继承,不会破坏类之间树状关系的简单性
- java中,多个子类主要的共性抽象成父类,次要的共性抽象成接口
- 接口中所有方法都是抽象方法
- Java中的弱耦合,遵循同一标准;
package test; public class TestInterface2 { public static void main(String[] args) { // TODO Auto-generated method stub //创建一个台灯对象 Lamp l = new Lamp(); //创建一个黄灯泡对象 YellowLight light = new YellowLight(); //将黄灯泡传入到台灯的setLight方法中 l.setLight(light); //然后执行台灯的开灯方法 l.powerOn(); /* * 思考一个问题: * 这只能传入一个黄灯泡对象,如果想要再传入其他灯泡呢,这种方式就不行了 * setLight方法中传入的是YellowLight对象,所以要想再传入其他灯泡就得重新写一个方法 * 这样程序的耦合度就太高了, *例如: */ RedLights redLight = new RedLights(); //将黄灯泡传入到台灯的setLight方法中 //l.setLight(redLight**);//所以这里台灯Lamp没有传入红灯泡 的方法 //然后执行台灯的开灯方法 //l.powerOn(); } } class Lamp{ YellowLight light = null; public void setLight(YellowLight light){ this.light = light; } //台灯的开灯方法 public void powerOn(){ light.LightOn(); } } class YellowLight { public void LightOn(){ System.out.println("黄灯泡发黄光"); } } class RedLights { public void RedLightOn(){ System.out.println("红灯泡发红光"); } }
- 解耦合的工具, 标准
- 把标准的使用者和标准的实现者分离
package test; //接口的解耦合作用 public class TestInterface3 { /** * 为解决上面提到的程序无法解耦的问题,这就引入了interface 的作用, * 利用interface可以很好的使程序达到弱耦合的效果, * 就是在台灯和灯泡之间加一个统一的标准, * * * 接口中所有方法都是抽象方法 * Java中的弱耦合,遵循同一标准; * * 解耦合的工具, 标准 * 把标准的使用者和标准的实现者分离 * * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub //创建台灯对象 Lamps l = new Lamps(); //创建黄灯泡对象 YellowLights light = new YellowLights(); //创建红灯泡对象 RedLight r = new RedLight(); //台灯里面传入什么就调用什么,不用再更改Lamp程序中的代码,达到弱耦合效果 l.setLight(light); l.setLight(r); //再调用开灯方法 l.powerOn(); } } class Lamps{ private Light light = null; //传入接口对象; public void setLight(Light light){ this.light = light; } //开灯方法 public void powerOn(){ light.On(); } } //创建灯泡的接口 interface Light{ public void On(); } class YellowLights implements Light{ public void On(){ System.out.println("黄灯泡发黄光"); } } class RedLight implements Light{ public void On(){ System.out.println("红灯泡发红光!"); } }
修饰符的组合:
static final abstract (都不能修饰构造方法)
在方法中:
private
static
final
abstract
final 和abstract 相矛盾,不能同时出现
抽象类中可以有一个final属性;
一个类同时是final和abstract 是不对的
一个方法同时是final和abstract 是不对的
一个final类中有抽象方法也是不对的(final类没有子类)
static 和 abstract 不能同时出现 静态方法的覆盖没有多态 private 和 abstract 不能同时出现; 私有方法不能继承给子类
所以
private static final 可以随意组合,但均不能和abstract联用;
abstract
总结一下:abstract class 和 interface 有什么区别?
含有 abstract 修饰符的 class 即为抽象类,abstract 类不能创建的实例对象。含有 abstract 方法的类必须定义为 abstract class,abstract class 类中的方法不必是抽象的。abstract class 类中定义抽象方法必须在具体(Concrete)子类中实现,所以,不能有抽象构造方法或抽象静态方法。如果的子类没有实现抽象父类中的所有抽象方法,那么子类也必须定义为 abstract 类型。
接口(interface)可以说成是抽象类的一种特例,接口中的所有方法都必须是抽象的。接口中的方法定义默认为public abstract 类型,接口中的成员变量类型默认为 public static final。
下面比较一下两者的语法区别:
1.抽象类可以有构造方法,接口中不能有构造方法。
2.抽象类中可以有普通成员变量,接口中没有普通成员变量
3.抽象类中可以包含非抽象的普通方法,接口中的所有方法必须都是抽象的,不能有非抽象的普通方法。
4. 抽象类中的抽象方法的访问类型可以是 public,protected 和(默认类型,虽然 eclipse 下不报错,但应该也不行),但接口中的抽象方法只能是 public 类型的,并且默认即为 public abstract 类型。
5. 抽象类中可以包含静态方法,接口中不能包含静态方法
6. 抽象类和接口中都可以包含静态成员变量,抽象类中的静态成员变量的访问类型可以任意,但接口中定义的变量只能是 public static final 类型,并且默认即为为 public static final 类型。
7. 一个类可以实现多个接口,但只能继承一个抽象类。