1.接口
概述: 接口是Java語言中的一種引用類型,是方法的"集合",是以接口的内部主要就是定義方法,包含常量,抽象方法(JDK 7及以前),預設方法和靜态方法(JDK 8),私有方法(jdk9)。
- 抽象方法【重要】
- 預設方法
- 靜态方法
- 私有方法
- 自定義常量
接口的定義,它與定義類方式相似,但是使用
interface
關鍵字。它也會被編譯成.class檔案,但一定要明确它并不是類,而是另外一種引用資料類型。
public class 類名.java–>.class
public interface 接口名.java–>.class
引用資料類型:數組,類,接口。
接口的使用,它不能建立對象,但是可以被實作(
implements
,類似于被繼承)。一個實作接口的類(可以看做是接口的子類),需要實作接口中所有的抽象方法,建立該類對象,就可以調用方法了,否則它必須是一個抽象類。
小結:
- 接口是Java語言中的一種引用類型,
- 接口中主要用來定義方法的:
- jdk7及其以前: 常量,抽象方法
- jdk8: 額外增加預設方法和靜态方法
- jdk9及其以上: 額外增加了私有方法
- 定義接口使用interface關鍵字, 編譯之後也會産生class檔案
- 接口不能建立對象, 需要實作接口(implements), 實作接口的類叫做實作類(接口的子類)
- 實作類: 普通類 必須重寫接口中的抽象方法
- 實作類 ;抽象類 可以不用重寫接口中的抽象方法
定義格式
格式
public interface 接口名稱 {
// 常量
// 抽象方法
// 預設方法
// 靜态方法
}
案例
public interface IA {
// 常量 預設修飾符 public static final 這三個修飾符可以省略
public static final int NUM1 = 10;
int NUM2 = 20;
// 抽象方法 預設修飾符 public abstract 這2個修飾符可以省略
public abstract void method1();
void method2();
// 預設方法 預設修飾符 public default public修飾符可以省略,default不可以省略
public default void method3(){
System.out.println("預設方法 method3");
}
default void method4(){
System.out.println("預設方法 method4");
}
// 靜态方法: public static修飾 static修飾符不可以省略 public可以省略
public static void method5(){
System.out.println("靜态方法 method5");
}
// 私有靜态方法 使用private static修飾 不可以省略
private static void method6(){
System.out.println("私有靜态方法 method6");
}
// 私有非靜态方法 使用private修飾
private void method7(){
System.out.println("私有靜态方法 method7");
}
}
public class Test {
public static void main(String[] args) {
/*
接口的定義:
public interface 接口名{
jdk7及其以前: 常量,抽象方法
jdk8: 額外增加預設方法和靜态方法
jdk9及其以上: 額外增加了私有方法
}
*/
System.out.println(IA.NUM1);// 10
}
// 類中的預設方法,使用預設權限修飾符(空)
void method(){
}
}
實作概述
類與接口的關系為實作關系,即類實作接口,該類可以稱為接口的實作類,也可以稱為接口的子類。實作的動作類似繼承,格式相仿,隻是關鍵字不同,實作使用
implements
關鍵字。
實作格式
- 類可以實作一個接口,也可以同時實作多個接口。
- 類實作接口後,必須重寫接口中所有的抽象方法,否則該類必須是一個“抽象類”。
public interface IA{ public void show1(); } public interface IB{ public void show2(); } public class Zi implements IA ,IB{ public void show1(){ } public void show2(){ } }
- 類實作接口後,必須重寫接口中所有的抽象方法,否則該類必須是一個“抽象類”。
- 類可以在“繼承一個類”的同時,實作一個、多個接口;
public class Fu{} public interface IA{} public interface IB{} public class Zi extends Fu implements IA,IB{//一定要先繼承,後實作 }
接口中成員的通路特點
接口中成員的通路特點:
接口中的常量: 主要是供接口直接使用
接口中的抽象方法: 供實作類重寫的
接口中的預設方法: 供實作類繼承的(實作類中可以直接調用,實作類對象也可以直接調用)
接口中的靜态方法: 隻供接口直接調用,實作類繼承不了
接口中的私有方法: 隻能在接口中直接調用,實作類繼承不了
案例示範
接口
/**
* @Author:pengzhilin
* @Date: 2020/4/16 11:57
*/
public interface IA {
// 接口中的常量: 主要是供接口直接使用
public static final int NUM = 10;
// 接口中的抽象方法: 供實作類重寫的
public abstract void method1();
// 接口中的預設方法: 供實作類繼承使用(實作類中可以直接調用,實作類對象也可以直接調用)
public default void method2(){
System.out.println("預設方法method2");
method4();
method5();
}
// 接口中的靜态方法: 隻供接口直接調用,實作類繼承不了
public static void method3(){
System.out.println("靜态方法method3");
method5();
}
// 接口中的私有方法: 隻能在接口中直接調用,實作類繼承不了
private void method4(){// 隻能在接口的預設方法中調用
// 方法體
method5();
}
private static void method5(){//
// 方法體
}
}
實作類:
/**
* @Author:pengzhilin
* @Date: 2020/4/16 11:59
*/
public class ImpA implements IA{
/* @Override
public void method2() {
}*/
@Override
public void method1() {
System.out.println("重寫接口中的method1抽象方法");
}
}
測試類:
/**
* @Author:pengzhilin
* @Date: 2020/4/16 11:54
*/
public class Test {
public static void main(String[] args) {
/*
接口中成員的通路特點:
接口中的常量: 主要是供接口直接使用
接口中的抽象方法: 供實作類重寫的
接口中的預設方法: 供實作類繼承的(實作類中可以直接調用,實作類對象也可以直接調用)
接口中的靜态方法: 隻供接口直接調用,實作類繼承不了
接口中的私有方法: 隻能在接口中直接調用,實作類繼承不了
*/
System.out.println(IA.NUM);// 10
// 建立實作類對象,通路NUM常量
ImpA ia = new ImpA();
System.out.println(ia.NUM);// 10
// 調用method2方法
ia.method2();
// 通過接口名調用接口中的靜态方法
IA.method3();
//ia.method3();// 編譯報錯,
}
}
多實作時的幾種沖突情況
公有靜态常量的沖突
了解即可, 一般會使用靜态所在類的類名去調用
- 實作類不繼承沖突的變量
interface IA{
public static final int a = 10;
public static final int b= 20;
}
interface IB{
public static final int a = 30;
}
class Zi implements IA,IB{
//隻繼承了b,沒有繼承a,因為a沖突了
}
public class Demo {
public static void main(String[] args) {
Zi z = new Zi();
// System.out.println(z.a);//編譯錯誤
System.out.println(z.b);
}
}
公有抽象方法的沖突
- 實作類==隻需要重寫一個 ==
interface IA{
public void show();
}
interface IB{
public void show();
}
class Zi implements IA,IB{
@Override
public void show() {//子類隻需要重寫一個show()即可
System.out.println("子類的show()...");
}
}
public class Demo {
public static void main(String[] args) {
Zi z = new Zi();
z.show();
}
}
公有預設方法的沖突
- 實作類必須重寫一次最終版本
interface IA{
public default void show(){
System.out.println("IA");
}
}
interface IB{
public default void show(){
System.out.println("IB");
}
}
class Zi implements IA,IB{
@Override
public void show() {//必須重寫一次的show()
System.out.println("Zi的show()....");
}
}
public class Demo {
public static void main(String[] args) {
Zi z = new Zi();
z.show();
}
}
公有靜态方法的沖突
- 靜态方法是直接屬于接口的,不能被繼承,是以不存在沖突
interface IA{ public static void show(){ System.out.println("IA"); } } interface IB{ public static void show(){ System.out.println("IB"); } } class Zi implements IA,IB{ } public class Demo { public static void main(String[] args) { Zi z = new Zi(); z.show();//編譯錯誤,show()不能被繼承。 } }
私有方法的沖突
- 私有方法隻能在本接口中直接使用,不存在沖突
接口和接口的關系
- 接口可以“繼承”自另一個“接口”,而且可以“多繼承”。
interface IA{} interface IB{} interface IC extends IA,IB{//是“繼承”,而且可以“多繼承” }
接口繼承接口的沖突情況
公有靜态常量的沖突
interface IA{
public static final int a = 10;
public static final int b = 30;
}
interface IB{
public static final int a = 20;
}
interface IC extends IA,IB{//沒有繼承a
}
//測試:
main(){
System.out.println(IC.a);//錯誤的
}
公有抽象方法沖突
interface IA{
public void show();
}
interface IB{
public void show();
}
interface IC extends IA,IB{//IC隻繼承了一個show()
}
class Zi implements IC{
//重寫一次show()
public void show(){
}
}
公有預設方法的沖突
interface IA{
public default void d1(){
}
}
interface IB{
public default void d1(){
}
}
interface IC extends IA,IB{//必須重寫一次d1()
public default void d1(){
}
}
公有靜态方法和私有方法
- 不沖突,因為靜态方法是直接屬于接口的,隻能使用接口直接通路,而私有方法隻能在接口中通路,也沒有沖突
抽象類和接口的練習
通過執行個體進行分析和代碼示範抽象類和接口的用法。
1、舉例:
犬: 父類 ---->抽象類
行為:吼叫;吃飯;
緝毒犬: 繼承犬類
行為:吼叫;吃飯;緝毒;
public abstract class Dog{
// 吼叫 抽象方法
// 吃飯 抽象方法
}
public interface JiDu{
// 緝毒 抽象方法
}
public class JiDuDog extends Dog implements JiDu{
// 重寫吼叫,吃飯方法
// 實作緝毒的方法 ---- 緝毒方式
}
緝毒豬,緝毒貓,緝毒候....
- 如果一個父類中的某個方法,所有子類都有不同的實作,那麼該方法就應該定義成抽象方法,是以該父類就是抽象類 (父類一般都是抽象類)
- 如果某個功能是一個類額外增加的,那麼就可以把這個額外的功能定義到接口中,再這個類去實作
分析:
由于犬分為很多種類,他們吼叫和吃飯的方式不一樣,在描述的時候不能具體化,也就是吼叫和吃飯的行為不能明确。當描述行為時,行為的具體動作不能明确,這時,可以将這個行為寫為抽象行為,那麼這個類也就是抽象類。
可是有的犬還有其他額外功能,而這個功能并不在這個事物的體系中 , 例如 : 緝毒犬。緝毒的這個功能有好多種動物都有 , 例如 : 緝毒豬 , 緝毒鼠。我們可以将這個額外功能定義接口中 ,讓緝毒犬繼承犬且實作緝毒接口 , 這樣緝毒犬既具備犬科自身特點也有緝毒功能。
- 額外的功能—> 在接口中定義,讓實作類實作
- 共性的功能—> 在父類中定義,讓子類繼承
實作:
//定義緝毒接口 緝毒的詞組(anti-Narcotics)比較長,在此使用拼音替代
interface JiDu{
//緝毒
public abstract void jiDu();
}
//定義犬科,存放共性功能
abstract class Dog{
//吃飯
public abstract void eat();
//吼叫
public abstract void roar();
}
//緝毒犬屬于犬科一種,讓其繼承犬科,擷取的犬科的特性,
//由于緝毒犬具有緝毒功能,那麼它隻要實作緝毒接口即可,這樣即保證緝毒犬具備犬科的特性,也擁有了緝毒的功能
class JiDuQuan extends Dog implements JiDu{
public void jiDu() {
}
void eat() {
}
void roar() {
}
}
//緝毒豬
class JiDuZhu implements JiDu{
public void jiDu() {
}
}
小結:
- 額外的功能—> 在接口中定義,讓實作類實作
- 如果可以确定的通用功能,使用預設方法
- 如果不能确定的功能,使用抽象方法
- 共性的功能—> 在父類中定義,讓子類繼承
- 如果可以确定的通用功能,使用預設方法
- 如果不能确定的功能,使用抽象方法
2.多态
多态是繼封裝、繼承之後,面向對象的第三大特性。
生活中,比如跑的動作,小貓、小狗和大象,跑起來是不一樣的。再比如飛的動作,昆蟲、鳥類和飛機,飛起來也是不一樣的。可見,同一行為,通過不同的事物,可以展現出來的不同的形态。多态,描述的就是這樣的狀态。
定義
- 多态: 是指同一行為,對于不同的對象具有多個不同表現形式。
- 同一種事物的多種形态
- 程式中多态: 是指同一方法,對于不同的對象具有不同的實作.
前提條件【重點】
- 繼承或者實作【二選一】
- 父類引用指向子類對象【格式展現】
- 方法的重寫【意義展現:不重寫,無意義】
小結:
- 多态: 是指同一行為,對于不同的對象具有多個不同表現形式。
- 條件:
- 繼承或者實作
- 父類引用指向子類的對象
- 方法的重寫
多态的展現:父類的引用指向它的子類的對象:
父類類型 變量名 = new 子類對象;
變量名.方法名();
父類類型:指子類對象繼承的父類類型,或者實作的父接口類型。
class Animal{}
class Cat extends Animal{}
class Dog extends Animal{}
clsss Person{}
//測試類:
main(){
Animal a1 = new Cat();
Animal a2 = new Dog();
Animal a3 = new Person();//編譯錯誤,沒有繼承關系。
}
多态時通路成員的特點
- 多态時成員變量的通路特點
- 編譯看左邊,運作看左邊
- 簡而言之:多态的情況下,通路的是父類的成員變量
- 編譯看左邊,運作看左邊
- 多态時成員方法的通路特點
- 非靜态方法:編譯看左邊,運作看右邊
- 簡而言之:編譯的時候去父類中查找方法,運作的時候去子類中查找方法來執行
- 靜态方法:編譯看左邊,運作看左邊
- 簡而言之:編譯的時候去父類中查找方法,運作的時候去父類中查找方法來執行
- 非靜态方法:編譯看左邊,運作看右邊
- 注意:多态的情況下是無法通路子類獨有的方法
- 示範代碼:
public class Demo1 {
public static void main(String[] args) {
// 父類的引用指向子類的對象
Animal anl1 = new Dog();
// 通路非靜态方法
anl1.eat();
// 通路成員變量num
System.out.println(anl1.num);//10
// 通路靜态方法
anl1.sleep();
// 多态想要調用子類中獨有的方法
// anl1.lookHome(); 錯誤的,無法通路 多态的弊端:無法通路子類獨有的方法
}
}
public class Animal {
int num = 10;
public void eat(){
System.out.println("吃東西...");
}
public static void sleep(){
System.out.println("Animal類中的睡覺方法...");
}
}
public class Dog extends Animal {
int num = 20;
// 重寫
public void eat() {
System.out.println("狗吃骨頭");
}
public static void sleep(){
System.out.println("Dog類中的睡覺方法...");
}
public void lookHome(){
System.out.println("狗正在看家...");
}
}
多态的幾種表現形式
- 多态的表現形式:
- 普通父類多态
public class Fu{} public class Zi extends Fu{} public class Demo{ public static void main(String[] args){ Fu f = new Zi();//左邊是一個“父類” } }
- 抽象父類多态
public abstract class Fu{} public class Zi extends Fu{} public class Demo{ public static void main(String[] args){ Fu f = new Zi();//左邊是一個“父類” } }
- 父接口多态
public interface A{} public class AImp implements A{} public class Demo{ public static void main(String[] args){ A a = new AImp(); } }
- 普通父類多态
小結:
略
多态的應用場景:
- 變量多态 -----> 意義不大
- 形參多态----> 常用
- 傳回值多态—> 常用
多态的幾種應用場景:
定義一個Animal類,讓Dog和Cat類繼承Animal類:
public class Animal {
public void eat(){
System.out.println("吃東西...");
}
}
public class Cat extends Animal {
@Override
public void eat() {
System.out.println("貓吃魚...");
}
}
public class Dog extends Animal {
@Override
public void eat() {
System.out.println("狗吃骨頭...");
}
}
public class Demo1 {
public static void main(String[] args) {
/*
多态的應用場景:
1.變量多态
2.形參多态
3.傳回值多态
*/
// 1.變量多态
Animal anl = new Dog();
anl.eat();
// 2.形參多态
Dog dog = new Dog();
invokeEat(dog);
Cat cat = new Cat();
invokeEat(cat);// 實參指派給形參: Animal anl = new Cat();
// 3.傳回值多态
Animal anl2 = getAnimal();// 傳回值指派給變量: Animal anl2 = new Dog()
}
// 3.傳回值多态
// 結論:如果方法的傳回值類型為父類類型,那麼就可以傳回該父類對象以及其所有子類對象
public static Animal getAnimal(){
// return new Animal();
return new Dog();
// return new Cat();
}
// 形參多态: 當你調用invokeEat方法的時候,傳入Animal類的子類對象
// Animal anl = dog; ====> Animal anl = new Dog();
// 結論:如果方法的參數是父類類型,那麼就可以接收所有該父類對象以及其所有子類對象
// Object類:是java中所有類的父類,是以如果參數為Object類型,那麼就可以傳入一切類的對象
public static void invokeEat(Animal anl){
anl.eat();
}
}
多态的好處和弊端
- 實際開發的過程中,父類類型作為方法形式參數,傳遞子類對象給方法,進行方法的調用,更能展現出多态的擴充性與便利。但有好處也有弊端
- 好處
- 提高了代碼的擴充性
- 弊端
- 多态的情況下,隻能調用父類的共性内容,不能調用子類的特有内容。
- 示例代碼
// 父類
public abstract class Animal {
public abstract void eat();
}
// 子類
class Cat extends Animal {
public void eat() {
System.out.println("吃魚");
}
public void catchMouse(){
System.out.println("貓抓老鼠");
}
}
class Dog extends Animal {
public void eat() {
System.out.println("吃骨頭");
}
}
定義測試類:
多态的好處:
public class Test {
public static void main(String[] args) {
// 建立對象
Cat c = new Cat();
Dog d = new Dog();
// 調用showCatEat
showCatEat(c);
// 調用showDogEat
showDogEat(d);
/*
以上兩個方法, 均可以被showAnimalEat(Animal a)方法所替代
而執行效果一緻
*/
showAnimalEat(c);
showAnimalEat(d);
}
public static void showCatEat (Cat c){
c.eat();
}
public static void showDogEat (Dog d){
d.eat();
}
public static void showAnimalEat (Animal a){
a.eat();
}
}
多态的弊端============
public static void main(String[] args) {
// 多态形式,建立對象
Aniaml anl = new Cat();
anl.eat();
anl.catchMouse();// 編譯報錯, 編譯看父類(左邊),父類中沒有定義catchMouse方法
}
引用類型轉換
目标:
- 向上轉型與向下轉型,instanceof關鍵字
步驟:
- 向上轉型
- 向下轉型
- instanceof關鍵字
講解:
向上轉型
- 子類類型向父類類型向上轉換的過程,這個過程是預設的。
向下轉型
- 父類類型向子類類型向下轉換的過程,這個過程是強制的。
Aniaml anl = new Cat(); Cat c = (Cat)anl;//向下轉型 c.catchMouse();// 可以通路 子類獨有的功能,解決多态的弊端
instanceof關鍵字
- 向下強轉有風險,最好在轉換前做一個驗證 :
- 格式:
變量名 instanceof 資料類型 如果變量屬于該資料類型,傳回true。 如果變量不屬于該資料類型,傳回false。 if( anl instanceof Cat){//判斷anl是否能轉換為Cat類型,如果可以傳回:true,否則傳回:false Cat c = (Cat)anl;//安全轉換 }
3.内部類
将一個類A定義在另一個類B裡面,裡面的那個類A就稱為内部類,B則稱為外部類。
成員内部類
- 成員内部類 :定義在類中方法外的類。
定義格式:
class 外部類 {
class 内部類{
}
}
在描述事物時,若一個事物内部還包含其他事物,就可以使用内部類這種結構。比如,汽車類
Car
中包含發動機類
Engine
,這時,
Engine
就可以使用内部類來描述,定義在成員位置。
代碼舉例:
class Car { //外部類
class Engine { //内部類
}
}
通路特點
- 内部類可以直接通路外部類的成員,包括私有成員。
- 外部類要通路内部類的成員,必須要建立内部類的對象。
建立内部類對象格式:
外部類名.内部類名 對象名 = new 外部類型().new 内部類型();
通路示範,代碼如下:
public class Body {// 外部類
// 成員變量
private int numW = 10;
int num = 100;
// 成員方法
public void methodW1(){
System.out.println("外部類中的methodW1方法...");
}
public void methodW2(){
System.out.println("外部類中的methodW2方法...");
// 建立内部類對象
Body.Heart bh = new Body().new Heart();
// 通路内部類成員變量
System.out.println("内部類成員變量numN:"+bh.numN);
// 通路内部類成員方法
bh.methodN2();
}
public class Heart{// 成員内部類
// 成員變量
int numN = 20;
int num = 200;
// 成員方法
public void methodN(){
System.out.println("内部類中的methodN方法...");
// 通路外部類成員變量
System.out.println("外部類成員變量:"+numW);
// 通路外部類成員方法
methodW1();
}
public void methodN2(){
System.out.println("内部類中的methodN2方法...");
}
public void methodN3(){
int num = 300;
System.out.println("局部變量num:"+num);// 300
System.out.println("内部類成員變量num:"+this.num);// 200
System.out.println("外部類成員變量num:"+Body.this.num);// 100
}
}
}
public class Demo {
public static void main(String[] args) {
// 測試
// 建立外部類對象,調用外部類的方法methodW2
Body body = new Body();
body.methodW2();
System.out.println("=======================");
// 建立内部類對象,調用内部類的methodN方法
Body.Heart heart = new Body().new Heart();
heart.methodN();
System.out.println("=======================");
heart.methodN3();// 300 200 100
}
}
小結:
内部類:将一個類A定義在另一個類B裡面,裡面的那個類A就稱為内部類,B則稱為外部類。
成員内部類的格式:
public class 外部類名{
public class 内部類名{
}
}
成員内部類的通路特點:
- 内部類可以直接通路外部類的成員,包括私有成員。
- 外部類要通路内部類的成員,必須要建立内部類的對象。
成員内部類的建立方式:
外部類名.内部類名 對象名 = new 外部類名().new 内部類名();
成員内部類的建立方式:
外部類名.内部類名 對象名 = new 外部類名().new 内部類名();
知識點-- 匿名内部類
- 匿名内部類 :是内部類的簡化寫法。它的本質是一個
帶具體實作的
父類或者父接口的
子類對象。匿名的
代碼一
public abstract class Animal {
public abstract void eat();
}
public class Dog extends Animal {
@Override
public void eat() {
System.out.println("狗吃骨頭...");
}
}
public class Test {
public static void main(String[] args) {
/*
- 匿名内部類的概述:本質就是繼承了父類或者實作了接口的匿名子類的對象
- 匿名内部類的格式:
new 類名\接口名(){
方法重寫
};
- 匿名内部類的作用: 為了簡化代碼,并沒有什麼特殊的功能
需求: 調用Aniaml類的eat()方法
1.建立一個子類繼承Animal類
2.在子類中重寫eat方法
3.建立子類對象
4.使用子類對象調用eat方法
想要調用抽象類中的方法,必須具備以上4步,那能不能減後呢? 可以 使用匿名内部類
*/
Animal anl1 = new Dog();
anl1.eat();
Animal anl2 = new Animal() {
@Override
public void eat() {
System.out.println("Animal子類的eat方法...");
}
};
anl2.eat();
}
}
代碼二
public interface AInterface {
void method();
}
public class AImp implements AInterface {
@Override
public void method() {
System.out.println("AImp 實作類重寫method方法....");
}
}
public class Demo {
public static void main(String[] args) {
/*
匿名内部類:
本質是一個繼承了父類的匿名子類的對象
本質是一個實作了接口的匿名實作類的對象
案例: A接口中有一個抽象方法method(),現在需要調用A接口中的method方法
思路:
1.建立一個實作類實作A接口
2.重寫A接口中的抽象方法method()
3.建立實作類對象
4.使用實作類對象調用method方法
想要調用A接口中的method方法,按照傳統方式,必須有以上4步,一步都不可少
前面三步就是為了得到A接口的實作類對象
現在: 匿名内部類可以表示一個接口的匿名實作類對象,是以,可以直接建立接口的匿名内部類來調用method方法即可
*/
AInterface a = new AInterface(){
@Override
public void method() {
System.out.println("匿名内部類方式重寫method方法....");
}
};
a.method();
System.out.println("==================");
AInterface a2 = new AImp();
a2.method();
System.out.println("======================");
AInterface a3 = new AInterface() {
@Override
public void method() {
// 實作
}
};
}
}
4.引用類型使用小結
實際的開發中,引用類型的使用非常重要,也是非常普遍的。我們可以在了解基本類型的使用方式基礎上,進一步去掌握引用類型的使用方式。基本類型可以作為成員變量、作為方法的參數、作為方法的傳回值,那麼當然引用類型也是可以的。在這我們使用兩個例子 , 來學習一下。
- 類名作為方法參數和傳回值
- 類名作為方法的參數: 調用方法傳入的是該類的對象
- 類名作為方法的傳回值: 方法傳回的是該類的對象
- 抽象類作為方法參數和傳回值
- 抽象類作為方法的參數, 調用方法傳入的是該類的子類對象
- 抽象類作為方法的傳回值: 方法傳回的是該類的子類對象
- 接口作為方法參數和傳回值
- 類作為成員變量
- 抽象類作為成員變量 不常見
- 接口作為成員變量 不常見
講解
6.1 類名作為方法參數和傳回值
public class Person{
public void eat(){
System.out.println("吃飯");
}
}
public class Test{
public static void main(String[] args){
method(new Person());
Person p = createPerson();
}
//引用類型作為方法參數,在前面筆記本案例中我們也使用了接口類型作為方法參數
pubic static void method(Person p){
p.eat();
}
//引用類型作為傳回值
public static Person createPerson(){
return new Person();
}
}
6.2 抽象類作為方法參數和傳回值
- 抽象類作為形參:表示可以接收任何此抽象類的"子類對象"作為實參;
- 抽象類作為傳回值:表示"此方法可以傳回此抽象類的任何子類對象";
/* 定義一個抽象類 */
public abstract class Person{
public void eat(){
System.out.println("吃飯");
}
public abstract void work();
}
/*定義子類Student*/
public class Student extends Person{
public void work(){
System.out.println("學生的工作是學習...");
}
}
/*測試類*/
public class Test{
public static void main(String[] args) {
//調用方法
//當抽象類作為參數時,實際傳入的是抽象類的子類對象
method(new Student());
}
public static void method(Person p){
}
//用抽象類作為方法傳回值類型
public static Person method2(){
//當抽象類作為傳回值類型時,實際傳回的是抽象類的子類對象
return new Student();
}
}
6.3 接口作為方法參數和傳回值
- 接口作為方法的形參:【同抽象類】
- 接口作為方法的傳回值:【同抽象類】
/*定義一個接口*/
public interface USB{
public void run();
}
/*定義子類*/
public class Keyboard implements USB{
public void run(){
System.out.println("使用鍵盤...");
}
}
public class Mouse implements USB{
public void run(){
System.out.println("使用滑鼠...");
}
}
/*定義測試類*/
public class Test{
public static void main(String[] args){
//1.調用method1()方法,需要傳入USB的任何子類對象都可以
method1(new Keyboard());
method2(new Mouse());
//2.調用method2()方法,此方法可能傳回一個Keyboard對象,也可能傳回一個Mouse對象
USB usb = method2();
usb.run();
}
//接口作為形參
public static void method1(USB usb){
usb.run();
}
//接口作為傳回值
public static USB method2(){
// return new Keyboard();//OK的
return new Mouse();//OK的
}
}
6.4 類名作為成員變量
我們每個人(Person)都有一個身份證(IDCard) , 為了表示這種關系 , 就需要在Person中定義一個IDCard的成員變量。定義Person類時,代碼如下:
class Person {
String name;//姓名
int age;//年齡
}
使用
String
類型表示姓名 ,
int
類型表示年齡。其實,
String
本身就是引用類型,我們往往忽略了它是引用類型。如果我們繼續豐富這個類的定義,給
Person
增加身份證号 , 身份證簽發機關等屬性,我們将如何編寫呢?這時候就需要編寫一個IDCard類了
定義IDCard(身份證)類,添加身份證号 , 簽發地等屬性:
class IDCard {
String idNum;//身份證号
String authority;//簽發地
//getter和setter方法
//...
//toString方法
//...
}
修改Person類:
public class Person {
String name;//姓名
int age;//年齡
IDCard idCard;//表示自己的身份證資訊
//name和age的getter、setter方法
//...
public IDCard getIdCard() {
return idCard;
}
public void setIdCard(IDCard idCard) {
this.idCard = idCard;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", idCard=" + idCard +
'}';
}
}
測試類:
public class TestDemo {
public static void main(String[] args) {
//建立IDCard對象
IDCard idCard = new IDCard();
//設定身份證号
idCard.setIdNum("110113201606066666");
//設定簽發地
idCard.setAuthority("深圳市寶安區警察局");
//建立Person對象
Person p = new Person();
//設定姓名
p.setName("小順子");
//設定年齡
p.setAge(2);
//設定身份證資訊
p.setIdCard(idCard);
//列印小順子的資訊
System.out.println(p);
}
}
輸出結果:
Person{name='小順子', age=2, idCard=IDCard{idNum='110113201606066666', authority='深圳市寶安區警察局'}}
類作為成員變量時,對它進行指派的操作,實際上,是賦給它該類的一個對象。同理 , 接口也是如此 , 例如我們筆記本案例中使用usb裝置。在此我們隻是通過小例子 , 讓大家熟識下引用類型的用法 , 後續在咱們的就業班學習中 , 這種方式會使用的很多。
6.5 抽象類作為成員變量
- 抽象類作為成員變量——為此成員變量指派時,可以是任何它的子類對象
/*定義抽象類*/
public abstract class Animal{
public abstract void sleep();
}
/*定義子類*/
public class Cat extends Animal{
public void sleep(){
System.out.println("小貓睡覺...");
}
public String toString(){
return "一隻可愛的小貓";
}
}
/*定義Student類*/
public class Student{
private String name;
private int age;
private Animal animal;//表示學生有一個動物,可以是Cat,也可以是Dog
public Student(String name,int age,Animal animal){
this.name = name;
this.age = age;
this.animal = animal;
}
public void setName(String name){
this.name = name;
}
public String getName(){
return this.name;
}
public void setAge(int age){
this.age = age;
}
public int getAge(){
return this.age;
}
public void setAnimal(Animal animal){
this.animal = animal;
}
public Animal getAnimal(){
return this.animal;
}
public String toString(){
return "Student [name = " + name +
" , age = " + age +
" , animal = " + animal +
"]";
}
}
/*定義測試類*/
public class Test{
public static void main(String[] args){
Student stu = new Student();
stu.setName("章子怡");
stu.setAge(19);
stu.setAnimal(new Cat());//表示Student有一隻貓
System.out.println(stu);//隐式調用stu.toString(),而stu.toString()中會隐式調用animal的toString().
}
}
6.6 接口作為成員變量
- 接口類型作為成員變量——【同抽象類】
/*定義接口*/
public interface Animal{
public abstract void sleep();
}
/*定義子類*/
public class Cat implements Animal{
public void sleep(){
System.out.println("小貓睡覺...");
}
public String toString(){
return "一隻可愛的小貓";
}
}
/*定義Student類*/
public class Student{
private String name;
private int age;
private Animal animal;//表示學生有一個動物,可以是Cat,也可以是Dog
public Student(String name,int age,Animal animal){
this.name = name;
this.age = age;
this.animal = animal;
}
public void setName(String name){
this.name = name;
}
public String getName(){
return this.name;
}
public void setAge(int age){
this.age = age;
}
public int getAge(){
return this.age;
}
public void setAnimal(Animal animal){
this.animal = animal;
}
public Animal getAnimal(){
return this.animal;
}
public String toString(){
return "Student [name = " + name +
" , age = " + age +
" , animal = " + animal +
"]";
}
}
/*定義測試類*/
public class Test{
public static void main(String[] args){
Student stu = new Student();
stu.setName("章子怡");
stu.setAge(19);
stu.setAnimal(new Cat());//表示Student有一隻貓
System.out.println(stu);//隐式調用stu.toString(),而stu.toString()中會隐式調用animal的toString().
}
}