JAVA學習---抽象類,介面
週日我們進一步學習了抽象類,介面,還好好分析了四種許可權修飾符的特性。
抽象類
- 定義:
我們先從一個例子引出抽象類的定義:比如我說一隻動物,你知道我說的是什麼具體動物嗎?只有看到了具體的動物,你才知道,這是什麼動物。 所以說,動物本身並不是一個具體的事物,而是一個抽象的事物。只有真正的貓,狗才是具體的動物。同理,我們也可以推想,不同的動物吃的東西應該是不一樣的,所以,我們不應該在動物類中給出具體體現,而是應該給出一個宣告即可。所以,在Java中,一個沒有方法體的方法應該定義為抽象方法,而類中如果有抽象方法,該類必須定義為抽象類。父類當中不給出所有子類共性功能的實現,強制子類根據各自的差異性去重寫
- 抽象類的特點: 1.抽象類和抽象方法必須用abstract關鍵字修飾
抽象類:abstract class 類名{} 抽象方法:public abstract void 方法名(); //抽象方法:只給出方法宣告,不給出方法的具體實現
2.抽象類不一定有抽象方法,有抽象方法的類一定是抽象類。可是抽象類中的構造方法不能進行例項化,因此它沒有意義。 3.抽象類不能直接例項化,而是需要按照多型的方式,由具體的子類例項化,即抽象類多型。 4.如果一個類中如果有了抽象方法,則此類必須為抽象類。 5.抽象類的子類要門時抽象類,要麼 必須重寫抽象類中的所有抽象方法。所以說抽象類的成員方法是強制要求子類做的事情。
//定義抽象類Animal寫了兩個抽象方法eat(),sleep();
public abstract class Animal {
public abstract void eat();
public abstract void sleep();
}
//定義子類Cat繼承抽象類Animal
public class Cat extends Animal{
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override //重寫父抽象類中的所有方法。
public void eat() {
System.out.println("貓吃魚");
}
@Override
public void sleep() {
System.out.println("貓經常睡覺");
}
public void catcheMouser(){ //定義了一個Cat獨有的方法
System.out.println("貓抓老鼠");
}
}
//定義子類Dog繼承抽象類Animal
public class Dog extends Animal{
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override ////重寫父抽象類中的所有方法。
public void eat() {
System.out.println("夠吃骨頭");
}
@Override
public void sleep() {
System.out.println("狗晚上睡覺");
}
public void lookDoor(){ //定義了一個Dog獨有的方法
System.out.println("狗看門");
}
}
//定義測試類test
public class Test4 {
public static void main(String[] args) {
Animal an = new Dog(); //多型
an.sleep();
an.eat();
Dog dog = (Dog) an; //向下轉型
dog.setName("旺財");
dog.setAge(5);
System.out.println(dog.getName());
System.out.println(dog.getAge());
dog.lookDoor();
System.out.println("-----------------------");
an = new Cat();
an.eat();
an.sleep();
Cat cat = (Cat) an; //向下轉型
cat.setName("小白");
cat.setAge(2);
cat.catcheMouser();
System.out.println(cat.getAge());
System.out.println(cat.getName());
}
}
以上的例子充分展示了抽象類以及多型的使用方法。子類繼承抽象父類,並且重寫父類中的所有方法,同時定義了自身特有的方法,並通過多型向下轉型呼叫使用。
注意抽象類關鍵字abstract和一些關鍵字是衝突的。 a. private 衝突(abstract定義抽象類,它強制要求子類重寫方法,而private有將它私有,不許繼承和重寫,因此衝突)。 b. final 衝突(與private相似) c. static 不能共存,這樣無意義(static 修飾的方法算不上重寫)
上面我們討論了一些修飾符的特點,那我們就來詳細討論一下修飾符: 四種許可權修飾符:private(私有) ,預設,protected(受保護的),public(公共的)
- 許可權表:
本類 | 同一個包下(子類和無關類) | 不同包下(子類) | 不同包下(無關類) | |
---|---|---|---|---|
private | Y | |||
預設 | Y | Y | ||
protect | Y | Y | Y | |
public | Y | Y | Y | Y |
許可權修飾符:private,預設的,protected,public 狀態修飾符:static,final 抽象修飾符:abstract
介面
- 概述: 我們繼續之前的案例,貓狗除了吃飯睡覺(繼承)我們想想狗一般就是看門,貓一般就是作為寵物了(多型,重寫)。但是,現在有很多的馴養員或者是馴獸師,可以訓練出:貓鑽火圈,狗跳高,狗做計算等。而這些額外的動作,並不是所有貓或者狗一開始就具備的,這應該屬於經過特殊的培訓訓練出來的。所以,這些額外的動作定義到動物類中就不合適,也不適合直接定義到貓或者狗中,因為只有部分貓狗具備這些功能。 所以,為了體現事物功能的擴充套件性,Java中就提供了介面來定義這些額外功能,並不給出具體實現,將來哪些貓狗需要被培訓,只需要這部分貓狗把這些額外功能實現即可 介面:定義一些擴充套件功能或者規範.哪個類想要具備這些擴充套件功能可以實現這個介面。
- 定義: 關鍵字:interface 格式:interface 介面名{} 實現:implements class 類名 implements 介面名{}
- 特點: 1.介面中的成員變數前面有預設修飾符 public static final 。 2.方法前面預設有修飾符 public abstract 你可以省略不寫,建議你寫出來 3.介面中所有的方法都是抽象方法,抽象類中可以有抽象,也可以有非抽象方法 4.介面中沒有構造方法 5.介面中所有的成員變數都是公共的靜態常量 6.介面的子類可以是抽象類 7.介面跟介面之間可以繼承,而且是多繼承 8.介面不能建立物件,即介面不能例項化,如果想例項化要按照多型的方式來例項化。 9.介面可以實現多繼承,而default關鍵字可以允許在介面中定義預設類,這也相當於變相承認java多繼承。
介面例項:
//定義抽象父類Animal
public abstract class Animal {
public abstract void eat();
public abstract void sleep();
}
//定義介面MyInterface
public interface MyInterface {
int NUM = 100;
(public static final) double D = 100; //括號裡的可以沒有,預設修飾符。
(public abstract) void fire();
void hehe();
}
//implements 實現 用來實現一個介面的
//定義子類Dog,繼承抽象父類Animal,同時呼叫介面MyInterface
public class Dog extends Animal implements MyInterface{
//先重寫抽象父類中的方法eat(),sleep().
@Override
public void eat() {
}
@Override
public void sleep() {
}
//例項化介面的方法fire(),jump().
@Override
public void fire() {
System.out.println("狗鑽火圈了");
}
@Override
public void jump() {
System.out.println("狗跳高了");
}
}
//test測試類
public class Test {
public static void main(String[] args) {
//介面不能例項化
MyInterface my = new Dog(); //多型的形式
my.fire();
my.jump();
}
}
-
!引數傳遞: 下面我們來說說java中的引數傳遞。 1.如果一個方法的形參要一個 類 型別,則傳一個該類的物件。 2.如果一個方法的形參要一個 抽象類型別 那麼你就傳該類的一個子類物件 。 3.如果一個方法的返回值型別要一個 介面 型別 你就返回一個該介面的子類物件。 4.如果一個方法的返回值型別 要一個==類= 型別,你就返回一個該類的物件。 這裡引數的傳遞給了我們一個很好的程式設計方法,鏈式程式設計(連調),這樣可以簡化程式設計的複雜性,但是需要我們對引數的傳遞有深刻的理解。
-
內部類: 1.定義: 將一個類 定義到另一個類的內部,我們就稱之為內部類;將類A 定義到B類當中 我們稱A為內部類,B 我們可以叫外部類;同時根據定義位置的不同,我們分為成員內部類,區域性內部類; 成員內部類:內部類在外部類的成員位置。 區域性內部類:內部類在外部類的區域性位置(方法中)。 2.內部類的特點: (1):內部類可以直接訪問外部類的成員,包括私有的; (2):內部類被private 修飾後,外界不能建立內部類物件; (3):static 可以修飾內部類,同時靜態內部類只能訪問外部類的靜態成員; (4):區域性內部類訪問區域性變數必須用final修飾 在JDK1 .8之後預設就加上了; 因為區域性變數會隨著方法的呼叫完畢而消失,這個時候,區域性物件並沒有立馬從堆記憶體中消失,還要使用那個變數。 為了讓資料還能繼續被使用,就用fianl修飾,這樣,在堆記憶體裡面儲存的其實是一個常量值。
public class Outer {
int num=100;
private String name="abc";
public void waiMethod(){
//定義區域性內部類
//內部類可以直接訪問外部類的成員 包括私有的
class Inner{
int nei=10;
public void neiShow(){
System.out.println(num);
System.out.println(name);
}
public void neiTest(){
waiTest();
}
}
Inner inner = new Inner();
System.out.println(inner.nei);
inner.neiShow();
inner.neiTest();
}
private void waiTest(){
System.out.println("我是外部類的私有方法");
}
}
public class Test5 {
public static void main(String[] args) {
//區域性內部類,外界無法直接建立其物件
new Outer().waiMethod();
}
}