Java面向物件(八)
目錄- Java面向物件(八)
- 二十四、abstract 關鍵字
- 創建抽象類的匿名子類物件
- 二十五、模板方法設計模式(TemplateMethod)
- 二十六、介面(interface)
- 26.1 介面簡介:
- 26.2 介面的定義和實作:
- 26.3 介面的使用:
- 26.4 介面的實作類的物件創建(例子)
- 26.5 介面應用:代理模式(Proxy)
- 26.6 特殊例子:
- 26.7 Java8 介面新特性
- 26.8 介面與抽象類的區別
- 二十四、abstract 關鍵字
二十四、abstract 關鍵字
- abstract 可以用來修飾的結構:類、方法,
- abstract 修飾類:抽象類,
- 此類不能實體化,
- 抽象類中一定有構造器,便于子類實體化時呼叫,(涉及:子類物件實體化的全程序)
- 開發中,都會提供抽象類的子類,讓子類物件實體化,完成相關的操作,
- abstract 修飾方法:抽象方法,
- 抽象方法只有方法的宣告,沒有方法體,
- 包含抽象方法的類,一定是一個抽象類,反之,抽象類中可以沒有抽象方法的,
- 若子類重寫了父類中的所有的抽象方法后,此子類方可實體化,若子類沒有重寫父類中的所有的抽象方法,則此子類也是一個抽象類,需要使用abstract修飾,
- 注意:
- abstract 不能用來修飾:屬性、構造器等結構,
- abstract 不能用來修飾私有方法、靜態方法、final 的方法、final 的類,
創建抽象類的匿名子類物件
public class PersonTest {
public static void main(String[] args) {
//非匿名的類非匿名的物件
Worker worker = new Worker();
method1(worker);
//非匿名的類匿名的物件
method1(new Worker());
//創建了一匿名子類的非匿名物件:p
Person p = new Person(){
@Override
public void eat() {
System.out.println("吃東西");
}
@Override
public void breath() {
System.out.println("好好呼吸");
}
};
method1(p);
//創建匿名子類的匿名物件
method1(new Person(){
@Override
public void eat() {
System.out.println("吃好吃東西");
}
@Override
public void breath() {
System.out.println("好好呼吸新鮮空氣");
}
});
}
public static void method1(Person p){
p.eat();
p.breath();
}
}
class Worker extends Person{
@Override
public void eat() {
}
@Override
public void breath() {
}
}
二十五、模板方法設計模式(TemplateMethod)
-
抽象類體現的就是一種模板模式的設計,抽象類作為多個子類的通用模板,子類在抽象類的基礎上進行擴展、改造,但子類總體上會保留抽象類的行為方式,
-
解決的問題:
當功能內部一部分實作是確定的,一部分實作是不確定的,這時可以把不確定的部分暴露出去,讓子類去實作,
換句話說,在軟體開發中實作一個演算法時,整體步驟很固定、通用,這些步驟已經在父類中寫好了,但是某些部分易變,易變部分可以抽象出來,供不同子類實作,這就是一種模板模式,
-
例子:
public class TemplateTest {
public static void main(String[] args) {
SubTemplate t = new SubTemplate();
t.spendTime();
}
}
abstract class Template{
//計算某段代碼執行所需要花費的時間
public void spendTime(){
long start = System.currentTimeMillis();
this.code();//不確定的部分、易變的部分
long end = System.currentTimeMillis();
System.out.println("花費的時間為:" + (end - start));
}
public abstract void code();
}
class SubTemplate extends Template{
@Override
public void code() {
for(int i = 2;i <= 1000;i++){
boolean isFlag = true;
for(int j = 2;j <= Math.sqrt(i);j++){
if(i % j == 0){
isFlag = false;
break;
}
}
if(isFlag){
System.out.println(i);
}
}
}
}
- 常用場景:
- 資料庫訪問的封裝
- Junit 單元測驗
- JavaWeb 的 Servlet 中關于 doGet/doPost 方法呼叫
- Hibernate 中模板程式
- Spring 中 JDBCTemlate、HibernateTemplate 等
二十六、介面(interface)
26.1 介面簡介:
-
介面使用關鍵字 interface 來定義,
-
Java中,介面和類是并列的兩個結構,主要解決 Java 中不能實作多重繼承的(即一個子類不能同時繼承于多個父類)問題,
26.2 介面的定義和實作:
-
JDK7 及以前:只能定義全域常量和抽象方法,
-
全域常量:public static final ,但是書寫時,可以省略不寫, -
抽象方法:public abstract ,也可省略不寫,
-
-
JDK8:除了定義全域常量和抽象方法之外,還可以定義靜態方法、默認方法
-
介面中不能定義構造器的,意味著介面不可以實體化,
-
Java開發中,介面通過讓類去實作(implements)的方式來使用,
-
如果實作類覆寫了介面中的所有抽象方法,則此實作類就可以實體化,
-
如果實作類沒有覆寫介面中所有的抽象方法,則此實作類仍為一個抽象類,
-
interface i {
// 全域變數
public static final int MAX_NUM = 100; //完整寫法
int MIN_NUM = 1; //省略了public static final
// 抽象方法
public abstract void show();
//省略了public abstract
void change();
}
class I implements i {
@Override
public void show() {
System.out.println("呼叫i介面的show方法");
}
@Override
public void change() {
System.out.println("呼叫i介面的change方法");
}
}
// 實作類沒有覆寫介面中所有的抽象方法
abstract class I2 implements i{
@Override
public void show() {
}
}
public class InterfaceTest {
public static void main(String[] args) {
System.out.println(i.MAX_NUM);
System.out.println(i.MIN_NUM);
// i.MIN_NUM = 2;
I i2 = new I();
i2.show();
}
}
-
Java類可以實作多個介面 ---> 彌補了Java單繼承性的局限性
定義Java類的語法格式:先寫extends,后寫implements
格式:class AA extends BB implements CC,DD,EE
-
介面與介面之間可以繼承,而且可以多繼承,
class Bullet extends Object implements CC,DD{
@Override
public void method1() {
// TODO Auto-generated method stub
}
@Override
public void method2() {
// TODO Auto-generated method stub
}
interface AA{
void method1();
}
interface BB{
void method2();
}
interface CC extends AA,BB{
}
interface DD{
}
26.3 介面的使用:
-
介面的具體使用,體現多型性,
-
介面的主要用途就是被實作類實作,(面向介面編程)
-
介面,實際上可以看做是一種規范,
-
舉例:JDBC
public class USBTest {
public static void main(String[] args) {
Computer com = new Computer();
Flash flash = new Flash();
com.transferData(flash);
}
}
class Computer{
public void transferData(USB usb){ // USB usb = new Flash();
usb.start();
System.out.println("具體傳輸資料的細節");
usb.stop();
}
}
interface USB{
//常量:定義了長、寬、最大最小的傳輸速度等
void start();
void stop();
}
class Flash implements USB{
@Override
public void start() {
System.out.println("U盤開啟作業");
}
@Override
public void stop() {
System.out.println("U盤結束作業");
}
}
class Printer implements USB{
@Override
public void start() {
System.out.println("列印機開啟作業");
}
@Override
public void stop() {
System.out.println("列印機結束作業");
}
}
26.4 介面的實作類的物件創建(例子)
public class USBTest {
public static void main(String[] args) {
Computer com = new Computer();
//1.創建了介面的非匿名實作類的非匿名物件
Flash flash = new Flash();
com.transferData(flash);
//2. 創建了介面的非匿名實作類的匿名物件
com.transferData(new Printer());
//3. 創建了介面的匿名實作類的非匿名物件
USB phone = new USB(){
@Override
public void start() {
System.out.println("手機開始作業");
}
@Override
public void stop() {
System.out.println("手機結束作業");
}
};
com.transferData(phone);
//4. 創建了介面的匿名實作類的匿名物件
com.transferData(new USB(){
@Override
public void start() {
System.out.println("mp3開始作業");
}
@Override
public void stop() {
System.out.println("mp3結束作業");
}
});
}
}
class Computer{
public void transferData(USB usb){//USB usb = new Flash();
usb.start();
System.out.println("具體傳輸資料的細節");
usb.stop();
}
}
interface USB{
//常量:定義了長、寬、最大最小的傳輸速度等
void start();
void stop();
}
class Flash implements USB{
@Override
public void start() {
System.out.println("U盤開啟作業");
}
@Override
public void stop() {
System.out.println("U盤結束作業");
}
}
class Printer implements USB{
@Override
public void start() {
System.out.println("列印機開啟作業");
}
@Override
public void stop() {
System.out.println("列印機結束作業");
}
}
26.5 介面應用:代理模式(Proxy)
-
概述: 代理模式是Java開發中使用較多的一種設計模式,
代理設計就是為其他物件提供一種代理以控制對這個物件的訪問,
public class StaticProxyTest {
public static void main(String[] args) {
Star s = new Proxy(new RealStar());
s.confer();
s.signContract();
s.bookTicket();
s.sing();
s.collectMoney();
}
}
interface Star {
void confer();// 面談
void signContract();// 簽合同
void bookTicket();// 訂票
void sing();// 唱歌
void collectMoney();// 收錢
}
class RealStar implements Star { // 被代理類
public void confer() {
}
public void signContract() {
}
public void bookTicket() {
}
public void sing() {
System.out.println("明星:歌唱~~~");
}
public void collectMoney() {
}
}
class Proxy implements Star { // 代理類
private Star real;
public Proxy(Star real) {
this.real = real;
}
public void confer() {
System.out.println("經紀人面談");
}
public void signContract() {
System.out.println("經紀人簽合同");
}
public void bookTicket() {
System.out.println("經紀人訂票");
}
public void sing() {
real.sing();
}
public void collectMoney() {
System.out.println("經紀人收錢");
}
}
-
應用場景:
-
安全代理:屏蔽對真實角色的直接訪問,
-
遠程代理:通過代理類處理遠程方法呼叫(RMI)
-
延遲加載:先加載輕量級的代理物件,真正需要再加載真實物件
比如你要開發一個大檔案查看軟體,大檔案中有大的圖片,有可能一個圖片有100MB,在打開檔案時,不可能將所有的圖片都顯示出來,這樣就可以使用代理模式,當需要查看圖片時,用proxy來進行大圖片的打開,
-
-
分類 :
- 靜態代理(靜態定義代理類)
- 動態代理(動態生成代理類):JDK自帶的動態代理,需要反射等知識
26.6 特殊例子:
example one:
interface A {
int x = 0;
}
class B {
int x = 1;
}
class C extends B implements A {
public void pX() {
// The field x is ambiguous(編譯不通過,因為x是不明確的)
// System.out.println(x);
System.out.println(super.x);// 1
System.out.println(A.x);// 0,全域常量
}
public static void main(String[] args) {
new C().pX();
}
}
example two:
interface Playable {
void play();
}
interface Bounceable {
void play();
}
interface Rollable extends Playable,
Bounceable {
Ball ball = new Ball("PingPang");
}
class Ball implements Rollable {
private String name;
public String getName() {
return name;
}
public Ball(String name) {
this.name = name;
}
public void play() {
ball = new Ball("Football"); // 編譯報錯,在介面中已經定義了ball物件,所以該物件為 public static final,此處違反 final 不能重新賦值
System.out.println(ball.getName());
}
}
26.7 Java8 介面新特性
-
JDK8:除了定義全域常量和抽象方法之外,還可以定義靜態方法、默認方法,
- 靜態方法:使用 static 關鍵字修飾,可以通過介面直接呼叫靜態方法,并執行其方法體,我們經常在相互一起使用的類中使用靜態方法,
- 默認方法:默認方法使用 default 關鍵字修飾,可以通過實作類物件來呼叫, 我們在已有的介面中提供新方法的同時,還保持了與舊版本代碼的兼容性,
-
注意點:
(1)介面中定義的靜態方法,只能通過介面來呼叫,(2)通過實作類的物件,可以呼叫介面中的默認方法,如果實作類重寫了介面中的默認方法,呼叫時,仍然呼叫的是重寫以后的方法,
(3)如果子類(或實作類)繼承的父類和實作的介面中宣告了同名同引數的默認方法,那么子類在沒有重寫此方法的情況下,默認呼叫的是父類中的同名同引數的方法,-->類優先原則
(4)如果實作類實作了多個介面,而這多個介面中定義了同名同引數的默認方法,那么在實作類沒有重寫此方法的情況下,報錯,-->介面沖突,需要在實作類重寫該方法,
(5)在子類(或實作類)的方法中呼叫父類、介面中被重寫的方法,
- 呼叫自己重寫的方法:方法名();
- 呼叫父類的方法:super.方法名();
- 呼叫介面的默認方法:介面名.super.方法名();
例子:
public interface CompareA {
//靜態方法
public static void method1(){
System.out.println("CompareA:北京");
}
//默認方法
public default void method2(){
System.out.println("CompareA:上海");
}
default void method3(){
System.out.println("CompareA:上海");
}
}
public interface CompareB {
default void method3(){
System.out.println("CompareB:上海");
}
}
public class SuperClass {
public void method3(){
System.out.println("SuperClass:北京");
}
}
public class SubClassTest {
public static void main(String[] args) {
SubClass s = new SubClass();
// s.method1();
// SubClass.method1();
//知識點1:介面中定義的靜態方法,只能通過介面來呼叫,
CompareA.method1();
//知識點2:通過實作類的物件,可以呼叫介面中的默認方法,
//如果實作類重寫了介面中的默認方法,呼叫時,仍然呼叫的是重寫以后的方法
s.method2();
//知識點3:如果子類(或實作類)繼承的父類和實作的介面中宣告了同名同引數的默認方法,
//那么子類在沒有重寫此方法的情況下,默認呼叫的是父類中的同名同引數的方法,-->類優先原則
//知識點4:如果實作類實作了多個介面,而這多個介面中定義了同名同引數的默認方法,
//那么在實作類沒有重寫此方法的情況下,報錯,-->介面沖突,
//這就需要我們必須在實作類中重寫此方法
s.method3();
}
}
class SubClass extends SuperClass implements CompareA,CompareB{
public void method2(){
System.out.println("SubClass:上海");
}
public void method3(){
System.out.println("SubClass:深圳");
}
//知識點5:如何在子類(或實作類)的方法中呼叫父類、介面中被重寫的方法
public void myMethod(){
method3();//呼叫自己定義的重寫的方法
super.method3();//呼叫的是父類中宣告的
//呼叫介面中的默認方法
CompareA.super.method3();
CompareB.super.method3();
}
}
26.8 介面與抽象類的區別
| NO. | 區別點 | 抽象類 | 介面 |
|---|---|---|---|
| 1 | 定義 | 包含抽象方法的類 | 主要是抽象方法和全域常量的集合 |
| 2 | 組成 | 構造方法、抽象方法、普通方法、 常量、變數 | 常量、抽象方法、(jdk8.0:默認方法、靜態方法) |
| 3 | 使用 | 子類繼承抽象類(extends) | 子類實作介面(implements) |
| 4 | 關系 | 抽象類可以實作多個介面 | 介面不能繼承抽象類,但允許繼承多個介面 |
| 5 | 常見設計模式 | 模板方法 | 簡單工廠、工廠方法、代理模式 |
| 6 | 物件 | 都通過物件的多型性產生實體化物件 | |
| 7 | 局限 | 抽象類有單繼承的局限 | 介面沒有此局限 |
| 8 | 實際 | 作為一個模板 | 是作為一個標準或是表示一種能力 |
| 9 | 選擇 | 如果抽象類和介面都可以使用的話,優先使用介面,因為避免單繼承的局 |
- 在開發中,常看到一個類不是去繼承一個已經實作好的類,而是要么繼承抽象類, 要么實作介面,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/500291.html
標籤:Java
上一篇:【RocketMQ】訊息的消費
