抽象類和接口抽象類
abstract class A{ // 是定義了一個抽象類
publicstatic final String FLAG = "CHINA" ; //全局常量
privateString name = "Cym" ; // 定義一個普通的屬性
publicvoid setName(String name){
this.name = name ;
}
publicString getName(){
return this.name ;
}
publicabstract void print() ; // 定義抽象方法
};
包含一個抽象方法的類稱爲抽象類,抽象方法是隻聲明而未實現的方法,所有的抽象方法必須使用abstract關鍵字聲明,所有的抽象類也需要abstract關鍵字聲明。
abstract class A{ // 是定義了一個抽象類
publicstatic final String FLAG = "CHINA" ; //全局常量
privateString name = "Cym" ; // 定義一個普通的屬性
publicvoid setName(String name){
this.name = name ;
}
publicString getName(){
return this.name ;
}
publicabstract void print() ; // 定義抽象方法
};
class B extends A{ // 繼承抽象類,因爲B是普通類,所以必須覆寫全部抽象方法
publicvoid print(){
System.out.println("FLAG = " +FLAG) ;
System.out.println("姓名 = " + super.getName()) ;
}
};
對於抽象類來將,不能直接實例化的操作,但是可以聲明,如果要使用抽象類,則必須依靠子類,抽象類是必須被子類繼承,而且被繼承的子類需要實現抽象中的全部抽象方法。
問題:
抽象類是否可以使用final關鍵字修飾呢?
抽象類必須被子類繼承。
被final修飾的類不能被繼承。
所以得出結論,抽象類不能使用final關鍵子修飾。
抽象類是否可以存在構造方法?
abstract classA{ // 是定義了一個抽象類
public A(){
System.out.println("A、抽象類中的構造方法。") ;
}
};
class B extendsA{ // 繼承抽象類,因爲B是普通類,所以必須覆寫全部抽象方法
public B(){
super();
System.out.println("B、子類中的構造方法。") ;
}
};
public classAbstractDemo03{
public static void main(String args[]){
Bb = new B() ;
}
};
抽象類中允許有構造方法,但是此構造方法不能直接調用的,是交給子類調用的,子類對象的實例化過程中,永遠是先調用父類中的構造方法。
抽象類就是比普通類多了一個抽象方法而已。
抽象類屬性如何初始化?
abstract class Person{
privateString name ; // 定義name屬性
privateint age ; // 定義age屬性
publicPerson(String name,int age){
this.name = name ;
this.age = age ;
}
publicvoid setName(String name){
this.name = name ;
}
publicvoid setAge(int age){
this.age = age ;
}
publicString getName(){
return this.name ;
}
publicint getAge(){
return this.age ;
}
publicabstract String getInfo() ; // 抽象方法
};
使用super
class Student extends Person{
privateString school ;
publicStudent(String name,int age,String school){
super(name,age) ; // 指定要調用抽象類中有兩個參數的構造方法
this.school = school ;
}
publicvoid setSchool(String school){
this.school = school ;
}
publicString getSchool(){
return this.school ;
}
publicString getInfo(){
return "姓名:" + super.getName() +
";年齡:" + super.getAge() +
";學校:" + this.getSchool() ;
}
};
public class AbstractDemo04{
publicstatic void main(String args[]){
Student stu = new Student("張三",30,"清華大學") ;
System.out.println(stu.getInfo()) ;
}
};
抽象類中的屬性如果要想初始化,則肯定還要依賴與構造方法。
接口接口是一個特殊的類,在java中接口是由抽象方法和全局常量組成。
在java中使用interface定義一個接口
interface A{ // 定義接口A
publicstatic final String AUTHOR = "CYM" ; //全局常量
publicabstract void print() ; // 抽象方法
publicabstract String getInfo() ; // 抽象方法
}
在此接口中定義兩個抽象方法,一個全局常量,那麼接口與抽象類一樣,需要有子類,那麼子類此時不再稱爲繼承類,而是實現類,通過implements關鍵字實現完成。
接口的方法和屬性永遠是pubic修飾符
默認是方法是abstract
屬性是 static final
既然接口從定義上已經明確了要求是由抽象方法和全局常量組成,那麼在接口定義的時候就可以簡化操作
interface A{ // 定義接口A
StringAUTHOR = "Cym" ; // 全局常量
voidprint() ; // 抽象方法
StringgetInfo() ; // 抽象方法
}
一個類是雖然值能繼承一個父類,但是一個類可以同時實現多個接口。
如果一個類既要實現接口又要繼承抽象類的話,則必須按照一下的形式完成。
Class 子類extends 抽象類 implements 接口A,接口B,......{}
interface A{ // 定義接口A
publicString AUTHOR = "CYM" ; //全局常量
publicvoid print() ; // 抽象方法
publicString getInfo() ; // 抽象方法
}
abstract class B{ // 定義抽象類B
publicabstract void say() ; // 定義抽象方法
}
class X extends B implements A{ // X類線繼承B類,再實現A接口
publicvoid say(){
System.out.println("HelloWorld!!!") ;
}
publicString getInfo(){
return "HELLO" ;
}
publicvoid print(){
System.out.println("作者:" + AUTHOR) ;
}
};
public class InterfaceDemo04{
publicstatic void main(String args[]){
X x = new X() ; // 實例化子類對象
x.say() ;
x.print() ;
}
};
接口裏面的方法可以簡寫方法不寫abstract關鍵字,但是抽象類裏一定要修abstract關鍵字。
interface A{ // 定義接口A
publicString AUTHOR = "CYM" ; //全局常量
publicvoid print() ; // 抽象方法
publicString getInfo() ; // 抽象方法
}
abstract class B implements A{ // 定義抽象類B,實現接口A
publicabstract void say() ; // 定義抽象方法
}
class X extends B{ // X類線繼承B類
publicvoid say(){
System.out.println("HelloWorld!!!") ;
}
publicString getInfo(){
return "HELLO" ;
}
publicvoid print(){
System.out.println("作者:" + AUTHOR) ;
}
};
public class InterfaceDemo05{
publicstatic void main(String args[]){
X x = new X() ; // 實例化子類對象
x.say() ;
x.print() ;
}
};
一個抽象類可以實現多個接口,但是一個接口不能繼承一個抽象類。
interface A{ // 定義接口A
publicString AUTHOR = "CYM" ; //全局常量
publicvoid printA() ; // 抽象方法
}
interface B{
publicvoid printB() ;
}
interface C extends A,B{
publicvoid printC() ;
}
class X implements C{ // X類線繼承B類
publicvoid printA(){
System.out.println("A、Hello World!!!") ;
}
publicvoid printB(){
System.out.println("B、Hello MLDN") ;
}
publicvoid printC(){
System.out.println("C、Hello LXH") ;
}
};
public class InterfaceDemo06{
publicstatic void main(String args[]){
X x = new X() ; // 實例化子類對象
x.printA() ;
x.printB() ;
x.printC() ;
}
};
一個接口雖然不可以繼承一個抽象類,但是一個接口卻可以同時繼承多個接口。
對象多態性
接口和抽象類的基本概念完成了,下面最重要的就是對象的多態性,是整個java中最重要的一個部分,因爲有多態性的存在,纔可以讓程序變的更加靈活。
多態性是面向對象的最後一個特徵:
方法的重載和方法的覆寫實際上就屬於多態行的一種體現。
真正的多態性中還包含了一種爲對象多態性概念。
對象多態性主要指的是,子類和父類對象的相互轉換關係。
向上轉型:父類 父類對象 = 子類實例 --》自動完成
向下轉型:子類 子類對象 = (子類)父類實例 --》強制完成
classA{
publicvoid fun1(){
System.out.println("1、A類 --> public void fun1(){}") ;
}
publicvoid fun2(){
this.fun1() ;
}
};
class B extends A{
publicvoid fun1(){ // 將方法覆寫了
System.out.println("2、B類 --> public void fun1(){}") ;
}
publicvoid fun3(){ // 此操作爲子類自己定義的,父類中不存在
System.out.println("3、B類 --> public void fun3(){}") ;
}
};
public class PolDemo01{
publicstatic void main(String args[]){
A a = new B() ; // 發生向上轉型關係,子類實例 --> 父類實例
a.fun2() ;
}
};
父類對象 = 子類實例(向上轉型)
只能使用父類有的方法。(子類如果覆寫則使用子類覆寫的方法)
class A{
publicvoid fun1(){
System.out.println("1、A類 --> public void fun1(){}") ;
}
publicvoid fun2(){
this.fun1() ;
}
};
class B extends A{
publicvoid fun1(){ // 將方法覆寫了
System.out.println("2、B類 --> public void fun1(){}") ;
}
publicvoid fun3(){ // 此操作爲子類自己定義的,父類中不存在
System.out.println("3、B類 --> public void fun3(){}") ;
}
};
public class PolDemo02{
publicstatic void main(String args[]){
A a = new B() ; // 發生向上轉型關係,子類實例 --> 父類實例
B b = (B)a ; // 發生向下轉型關係,強制
b.fun3() ;
b.fun2() ;
}
};
父類對象 = 子類實例
子類對象 = (子類)父類對象(向下轉型)
class A{
publicvoid fun1(){
System.out.println("1、A類 --> public void fun1(){}") ;
}
publicvoid fun2(){
this.fun1() ;
}
};
class B extends A{
publicvoid fun1(){ // 將方法覆寫了
System.out.println("2、B類 --> public void fun1(){}") ;
}
publicvoid fun3(){ // 此操作爲子類自己定義的,父類中不存在
System.out.println("3、B類 --> public void fun3(){}") ;
}
};
public class PolDemo03{
publicstatic void main(String args[]){
A a = new A() ;
B b = (B)a ;
b.fun2() ;
}
};
會產生ClassCastException,表示轉換異常,造成的根本原因是兩個沒有關係的類進行相互的對象操作。
觀察對象多態性的作用:
假如:現在要設計一個方法,那麼此方法可以接受A類的所有子類的實例。
如果現在不使用對象多態性的概念完成
class A{
public void fun1(){
System.out.println("1、A類 -->public void fun1(){}") ;
}
public void fun2(){
this.fun1() ;
}
};
class B extends A{
public void fun1(){ // 將方法覆寫了
System.out.println("2、B類 -->public void fun1(){}") ;
}
public void fun3(){ // 此操作爲子類自己定義的,父類中不存在
System.out.println("3、B類 -->public void fun3(){}") ;
}
};
class C extends A{
public void fun1(){ // 將方法覆寫了
System.out.println("4、C類 -->public void fun1(){}") ;
}
public void fun4(){ // 此操作爲子類自己定義的,父類中不存在
System.out.println("5、C類 -->public void fun4(){}") ;
}
};
public class PolDemo04{
public static voidmain(String args[]){
fun(new B()) ;
fun(new C()) ;
}
public static void fun(Bb){
b.fun2() ;
b.fun3() ;
}
public static void fun(Cc){
c.fun2() ;
c.fun4() ;
}
};
以上的方式是通過重載完成,那麼使用以上方法完成會存在以上的缺點,如果現在A類的子類有N個,那麼方法就要重載N次,而且每次增加子類的時候都需要修改代碼本身。
所以,此時使用對象多態性就可以很好的解決此類問題,因爲所有的對象都會發生自動的向上轉型操作。
class A{
public void fun1(){
System.out.println("1、A類 -->public void fun1(){}") ;
}
public void fun2(){
this.fun1() ;
}
};
class B extends A{
public void fun1(){ // 將方法覆寫了
System.out.println("2、B類 -->public void fun1(){}") ;
}
public void fun3(){ // 此操作爲子類自己定義的,父類中不存在
System.out.println("3、B類 -->public void fun3(){}") ;
}
};
class C extends A{
public void fun1(){ // 將方法覆寫了
System.out.println("4、C類 -->public void fun1(){}") ;
}
public void fun4(){ // 此操作爲子類自己定義的,父類中不存在
System.out.println("5、C類 -->public void fun4(){}") ;
}
};
public class PolDemo05{
public static voidmain(String args[]){
fun(new B()) ;
fun(new C()) ;
}
public static void fun(Aa){
a.fun2() ;
}
};
class A{
public void fun1(){
System.out.println("1、A類 -->public void fun1(){}") ;
}
public void fun2(){
this.fun1() ;
}
};
class B extends A{
public void fun1(){ // 將方法覆寫了
System.out.println("2、B類 -->public void fun1(){}") ;
}
public void fun3(){ // 此操作爲子類自己定義的,父類中不存在
System.out.println("3、B類 -->public void fun3(){}") ;
}
};
class C extends A{
public void fun1(){ // 將方法覆寫了
System.out.println("4、C類 -->public void fun1(){}") ;
}
public void fun4(){ // 此操作爲子類自己定義的,父類中不存在
System.out.println("5、C類 -->public void fun4(){}") ;
}
};
public class PolDemo08{
public static voidmain(String args[]){
fun(new B()) ;
fun(new C()) ;
}
public static void fun(Aa){
a.fun2() ;
if(a instanceof B){
B b = (B)a ;
b.fun3() ;
}
if(a instanceof C){
C c = (C)a ;
c.fun4() ;
}
}
};
如果要使用子類自身的方法爲了保證對象向下轉型操作正確,在操作前最好加上instanceof關鍵字判斷。
在繼承關係中,父類的設計很重要,只要父類的設計合理了,則代碼開發非常簡便。
抽象類的應用
從對象多態性的概念來看,子類爲父類實例化是一個比較容易的操作,以爲可以發生自動的向上轉型關係,那麼調用的方法永遠是被子類覆寫過的方法。
那麼,此時就可以利用此概念通過對象多態性爲抽象類實例化。
抽象類可以實現方法,當很多類有相同方法和並且相同實現的時候,我們就可以用抽象類。當然也可以覆寫。
抽象類本身最大的用處就是在於模版設計。
接口的應用接口也可以像抽象類那樣通過多態性進行對象的實例化操作。
抽象類可以用於定義模版操作,但是接口呢?
接口實際上是作爲一個標準存在的。
接口不可以的實現方法,但很多類只要有相同方法操作的時候,我們就可以用接口作爲一種標準。
接口和抽象類適配器設計模式正常情況下一個接口的子類要實現全部的抽象方法
interface Window{
publicvoid open() ; // 打開窗口
publicvoid close() ; // 關閉窗口
publicvoid icon() ; // 最小化
publicvoid unicon() ; // 最大化
}
Class MyWindow implements Window{
}
在MyWindow類此時肯定要覆寫全部的抽象方法,但是現在希望可以根據自己的需要來選擇覆寫,那麼該怎麼實現?
用一個類先將接口實現了,但是所有的方法都屬於空實現,之後再繼承此類。
應該使用抽象類,因爲抽象類也不能直接使用。
interfaceWindow{
public void open() ; // 打開窗口
public void close() ; // 關閉窗口
public void icon() ; // 最小化
public void unicon() ; // 最大化
}
abstract classWindowAdapter implements Window{
public void open(){}
public void close(){}
public void icon(){}
public void unicon(){}
};
class MyWindowextends WindowAdapter{
public voidopen(){
System.out.println("打開窗口!");
}
};
public classAdpaterDemo{
public static void main(String args[]){
Windowwin = new MyWindow() ;
win.open();
}
}
工廠設計模式interface Fruit{
publicvoid eat() ;
}
class Apple implements Fruit{
publicvoid eat(){
System.out.println("吃蘋果。。。") ;
}
};
class Orange implements Fruit{
publicvoid eat(){
System.out.println("吃橘子。。。") ;
}
};
Public class interDemo{
Public staticvoid main(String args[]){
Fruit f = new Apple();
F.eat();
}
}
以上的程序如果開發的話是存在問題?
一直強調:主方法實際上就是一個客戶端。客戶端的代碼越簡單越好。
interface Fruit{
publicvoid eat() ;
}
class Apple implements Fruit{
publicvoid eat(){
System.out.println("吃蘋果。。。") ;
}
};
class Orange implements Fruit{
publicvoid eat(){
System.out.println("吃橘子。。。") ;
}
};
class Factory{ // 工廠類
publicstatic Fruit getFruit(String className){
Fruit f = null ;
if("apple".equals(className)){
f= new Apple() ;
}
if("orange".equals(className)){
f= new Orange() ;
}
return f ;
}
};
public class InterDemo{
publicstatic void main(String args[]){
Fruit f = Factory.getFruit(args[0]) ;
if(f!=null){
f.eat();
}
}
}
所有接口的實例化對象都是工廠類取得的。那麼客戶端調用的時候根據傳入的名稱不同,完成不同的功能。
代理設計模式interface Give{
publicvoid giveMoney() ;
}
class RealGive implements Give{
publicvoid giveMoney(){
System.out.println("把錢還給我。。。。。") ;
}
};
class ProxyGive implements Give{ // 代理公司
privateGive give = null ;
publicProxyGive(Give give){
this.give = give ;
}
publicvoid before(){
System.out.println("準備:小刀、繩索、鋼筋、鋼據、手槍、毒品") ;
}
publicvoid giveMoney(){
this.before() ;
this.give.giveMoney() ; // 代表真正的討債者完成討債的操作
this.after() ;
}
publicvoid after(){
System.out.println("銷燬所有罪證") ;
}
};
public class ProxyDemo{
publicstatic void main(String args[]){
Give give = new ProxyGive(new RealGive());
give.giveMoney() ;
}
};
當兩個類同時實現一個接口,一個類需要另外一個類代理才能實現該功能,這就叫代理模式。
抽象類與接口的區別如果抽象類和接口同時都可以使用的話、優先接口,以爲接口可以避免單繼承的侷限。
抽象類包含接口
abstract class A{
publicabstract void fun() ;
interfaceB{ // 內部接口
public void print() ;
}
};
class X extends A{
publicvoid fun(){
System.out.println("****************");
}
classY implements B{
public void print(){
System.out.println("===================");
}
};
};
public class TestDemo01{
publicstatic void main(String args[]){
A a = new X() ;
a.fun() ;
A.B b = new X().new Y() ;
b.print() ;
}
};
接口包含抽象類
interface A{
publicvoid fun() ;
abstractclass B{ // 內部抽象類
public abstract void print() ;
}
};
class X implements A{
publicvoid fun(){
System.out.println("****************");
}
classY extends B{
public void print(){
System.out.println("===================");
}
};
};
public class TestDemo02{
publicstatic void main(String args[]){
A a = new X() ;
a.fun() ;
A.B b = new X().new Y() ;
b.print() ;
}
};