1. 程式人生 > >7.29總結 抽象類和介面

7.29總結 抽象類和介面

1. 定義

抽象類

非private訪問修飾符 abstract 返回值型別 方法名(引數列表) ;

簡單的說,抽象類是一個不能例項化的類,它可以具有抽象方法或者普通方法,也可以有構造方法。

普通方法和抽象方法的區別

普通方法必須要有方法體,抽象方法不能有方法體(大括號也沒有);
抽象方法只能存在於抽象類/介面中,用abstract修飾,訪問修飾符不能用private。

普通方法:
public void Test(){
System.out.println("hello");
}
抽象方法:
public abstract void Test(); //沒有例項化,就是沒有具體實現方法

抽象類和普通類有什麼區別?

抽象類要用abstract修飾;普通類可以例項化,抽象類不能例項化;
抽象類體現的的是一種模板模式的設計。

抽象類:
public abstract class Person{
    Person p=new Person();  //錯誤,不能例項化
}
普通類:
public class Person{
    Person p=new Person();  //正確,普通類可以例項化
}

判斷圓形和矩形的面積

//抽象類
public abstract class Shape {

    public abstract void showArea
(); public abstract double compare(); public boolean compareTo(GeometricObject g){ return this.compare()>g.compare(); //子類(圓形) public class Circle extends GeometricObject { double s; double i; public Circle(double i){ this.i=i; } @Override public void
showArea() { s=Math.PI*i*i; System.out.println("圓形的面積為:"+s); } @Override public double compare() { return this.s; } //子類(矩形) public class Rectangle extends GeometricObject { double w,h; double s; public Rectangle(double w, double h){ this.w=w; this.h=h; } @Override public void showArea() { s=w*h; System.out.println("矩形的面積為:"+s); } @Override public double compare() { return this.s; } //main方法 public class Client { public static void main(String[] args) { Scanner sc=new Scanner(System.in); System.out.println("請輸入一個數:"); double input=sc.nextDouble(); GeometricObject c=new Circle(input); //c.showArea(input); c.showArea(); System.out.println("請輸入兩個值:"); double w=sc.nextDouble(); double h=sc.nextDouble(); GeometricObject r=new Rectangle(h,w); //r.showArea(input, w); r.showArea(); System.out.print("圓形的面積比長方形的大嗎?"); //System.out.println(c.compare()>r.compare()); System.out.println(c.compareTo(r)); } }

結果為:
這裡寫圖片描述

介面

介面(interface)是一種與類相似的結構,只包含常量和抽象方法。介面在許多方面與抽象類相近,但是抽象類除了包含常量和抽象方法之外,還可以包含變數和具體方法。

定義介面的語法是什麼?

[public] interface 介面名{
//介面成員
}

public interface Person{
    public String howToEat(); //抽象方法
}

2. 區別和聯絡

抽象類和介面的相同點和不同點分別是什麼?

相同:

  1. 都位於繼承的頂端,用於被其他類實現或繼承;
  2. 自身不能例項化,都是依靠物件多型性,通過實現類/子類進行物件例項化;
  3. 都可以包含抽象方法,其實現類/子類都必須重寫這些抽象方法;

不同:

1、抽象類體現繼承關係,一個類只能單繼承;介面體現實現關係,一個類可以多實現介面。
2、抽象類中可以定義非抽象方法,供子類直接使用;
3、介面中只能包含抽象方法(無須使用abstract關鍵字)和常量,介面中的成員都有固定修飾符。

二者的選用:

優先使用介面,儘量避免使用抽象類;
需要定義子類的行為,又要為子類提供共性功能時才考慮選用抽象類;

抽象類:
public abstract void Show{
//抽象方法
//普通方法
}
介面:
public interface Show{
//抽象方法
}

3. 抽象類的特點

  1. 抽象類中的方法不一定都是抽象的,抽象類中可以包含抽象的方法,也可以包含具體的方法。
  2. 不能例項化抽象類
    例:如果Course是抽象類,則以下語句是錯誤的
    Course c = new Course();
    但是可以宣告對Course物件的引用:
    Course x;
  3. 抽象類有子類的時候,除非子類採用具體的方法替代抽象類中的全部抽象方法,否則子類本身也被自動被認為是抽象的。
注意:抽象類之所以被稱之為“抽象”的,是因為抽象類省略了要執行的一種或多種特定行為的細節。

總結:

判斷正誤

①抽象類中只能定義抽象方法。 //錯誤,抽象類中還可以定義普通方法
②抽象類中不能定義構造方法。
//錯誤,抽象類中可以定義構造方法,只是不能直接建立抽象類的例項物件而已

③抽象方法可以同時是靜態方法。
//錯誤
abstract:用來宣告抽象方法,抽象方法沒有方法體,不能被直接呼叫,必須在子類overriding後才能使用。
static:用來宣告靜態方法,靜態方法可以被類及其物件呼叫。
用static宣告方法表明這個方法在不生成類的例項時可直接被類呼叫,而abstract方法不能被呼叫,兩者矛盾。

④抽象類中可以沒有抽象方法。但是含抽象方法的一定是抽象類。//正確
⑤宣告抽象類和抽象方法都使用abstract關鍵字。//正確
⑥抽象類不能例項化。 //正確
⑦抽象類中可以有靜態方法。 //正確 在繼承實現後,在main方法中可以直接用類名呼叫

介面可以繼承介面嗎?如果可以,能繼承多個嗎?介面可以實現介面嗎?

介面可以繼承一個或多個介面;介面不能實現介面。

需求說明(練習)

實現某公司各種崗位(經理、銷售人員、普通員工)的員工薪水計算。經理的薪水為基本工資+獎金,銷售人員的薪水為基本工資+銷售量*每件提成,普通員工只有基本工資;
要求輸出不同崗位各一名員工的工資,使用抽象類實現;

分析

定義員工抽象類,具有姓名、基本工資的屬性和計算薪水的抽象方法

定義子類:經理類、銷售人員類、普通員工類,分別繼承員工抽象類,定義各自的屬性,重寫計算薪水的方法

定義測試類,包含輸出員工薪水的靜態方法,引數為員工物件(抽象父類的引用指向子類的物件,可以實現多型)

程式碼:

//抽象類
public abstract class Employee {
    public String name;
    public double salary;

    public abstract double testSalary();

}
//子類(經理)
public class Manager extends Employee {
    public double  prize; 
    public Manager(double prize,double salary,String n){
        this.prize=prize;
        this.salary=salary;
        name = n;
    }
    public double testSalary() {

        return salary+prize;
    }

}
//子類(普通員工)
public class CommonStaff extends Employee {

    public CommonStaff(double salary,String na){
        this.salary=salary;
        name=na;
    }
    @Override
    public double testSalary() {
        return salary;
    }

}
//子類(銷售人員)
public class SalesMan extends Employee {

    private int num;
    private double tc;
    public SalesMan(int num,double tc,double salary,String n){
        this.num=num;
        this.tc=tc;
        this.salary=salary;
        name = n;
    }
    @Override
    public double testSalary() {

        return salary+num*tc;
    }

}
//輸出計算結果的類
public class Show {
    public static void show(Employee e){
         System.out.println(e.name+"的工資為:"+e.testSalary());
    }
}
//main方法
import java.util.Scanner;

public class Test {
    public static void main(String[] args) {
        while(true){

        Employee e;
        Scanner sc=new Scanner(System.in);
        System.out.println("請輸入你想計算什麼崗位的員工工資?經理,銷售人員,普通員工,退出系統");
        String i=sc.nextLine();
        if(i.equals("退出系統")){
            System.out.println("您已經退出系統!");
            break;
        }else{
            System.out.println("請輸入"+i+"的基本工資為:");
            double s=sc.nextDouble();
            switch (i){
            case "經理":
                System.out.println("請輸入"+i+"的獎金為:");
                double j=sc.nextDouble();
                e=new Manager(j,s,i);
                Show.show(e);
                break;
            case "銷售人員":
                System.out.println("請輸入"+i+"的銷售量為:");
                int n=sc.nextInt();
                System.out.println("請輸入"+i+"的提成為:");
                double t=sc.nextDouble();
                e=new SalesMan(n,t,s,i);
                Show.show(e);
                break;
            case "普通員工":
                e=new CommonStaff(s,i);
                Show.show(e);
                break;
            default:
                System.out.println("你輸入的員工種類暫時不存在,請重新輸入!");
                break;
            }
            }
            }
    }
}

結果為:
這裡寫圖片描述

內部類

在Java中,可以將一個類定義在另一個類裡面或者一個方法裡面,這樣的類稱為內部類。廣泛意義上的內部類一般來說包括這四種:成員內部類、區域性內部類、匿名內部類和靜態內部類。

內部類的作用

  1. 內部類提供了更好地封裝
  2. 內部類成員可以直接訪問外部類的私有資料
  3. 匿名內部類適合用於建立那些僅需要一次使用的類

1.成員內部類

成員內部類是最普通的內部類,它的定義為位於另一個類的內部,形如下面的形式:

public class Circle{
        public static void main(String args[]){
            Circle c=new Circle(14.0);//建立一個外部類物件
            Circle.Draw d=c.new Draw();//建立一個內部類物件
            d.drawShape();
        }
        double radius=0;
        public Circle(double radius){
            this.radius=radius;
        }
        class Draw{
            public void drawShape(){

                System.out.println(radius);
            }
        }
    }
    結果為:14.0

2. 區域性內部類

區域性內部類是定義在一個方法或者一個作用域裡面的類,它和成員內部類的區別在於區域性內部類的訪問僅限於方法內或者該作用域內。

class Circle{
public static void main(String args[]){
            //定義區域性內部類
            class inner{
                int  a;
            }
            //定義區域性內部類的子類
            class InnerSub extends inner{
                int b;
            }
            InnerSub sb=new InnerSub();
            sb.a=3;
            sb.b=8;
            System.out.println(sb.a+sb.b);
        }
    }
    結果為:11

3. 靜態內部類

靜態內部類也是定義在另一個類裡面的類,只不過在類的前面多了一個關鍵字static。靜態內部類是不需要依賴於外部類的,這點和類的靜態成員屬性有點類似,並且它不能使用外部類的非static成員變數或者方法,這點很好理解,因為在沒有外部類的物件的情況下,可以建立靜態內部類的物件,如果允許訪問外部類的非static成員就會產生矛盾,因為外部類的非static成員必須依附於具體的物件。

public class Circle{
private int p=5;
        private static int p1=8;
        static class Inner{
            //靜態內部類可以包含靜態成員
            private static int a=3;
            private int c=9;
            public void accout(){

            //靜態內部類可以訪問外部類的靜態成員
                System.out.println(p1);

        //外部類可以通過使用靜態內部類的類名作為呼叫者來訪問靜態內部類的成員
                System.out.println(Inner.a);

                System.out.println(new Inner().c);//外部類可以使用靜態內部類物件作為呼叫者來訪問靜態內部類的例項成員
            }
        }
        public static void main(String args[]){
            Circle.Inner in=new Inner();
            in.accout();
        }
    }
    結果為:8  3   9

4. 匿名內部類

匿名內部類應該是平時我們編寫程式碼時用得最多的,在編寫事件監聽的程式碼時使用匿名內部類不但方便,而且使程式碼更加容易維護。

interface Product{
        public double getPrice();
        public String getName();
    }
    public class Circle{
        public void test(Product p){
            System.out.println("購買了一個"+p.getName()+",花掉了"+p.getPrice());
        }
        public static void main(String[] args) {
            Circle ta=new Circle();
            ta.test(new Product(){
                public double getPrice()
                {
                    return 567.8;
                }
                public String getName()
                {
                    return "AGP顯示卡";
                }
            });
        }
    }
    結果為: 購買了一個AGP顯示卡,花掉了567.8

補充:

Ctrl+Shift+f 快捷鍵 可以修改eclipse的繁體字和簡體字互換
v+2 可以輸出一些平常不容易敲出來的字元。如圖所示:
這裡寫圖片描述

debug模式有三種:

列印 logger debug

包裝類的常用方法

以Integer為例

MIN_VALUE = 0x80000000;
MAX_VALUE = 0x7fffffff;
byteValue() 取得用byte型別表示的整數

compareTo/compare 比較大小

    Integer i=124; Integer j=124;
    System.out.println(i==j);  //true
    Integer a=246; Integer b=246;
    System.out.println(a==b);  //false  超過了整型的範圍


    Integer c=258;
    System.out.println(c.byteValue()); //2 取低八位的二進位制值
    Integer d=0x89345f0;
    System.out.println(d.byteValue());  //-16  f0為11110000  1為負,-128+64+32+16+=-16

    System.out.println(c.compareTo(d));  //-1  c(前者)小於d(後者) 返回-1,大於返回1,等於返回0
    System.out.println(c.compare(3, 3)); //0  兩者相等,返回0
    System.out.println(c.compare(d, c)); //1  d>c   返回1