轉載請聲明出處:http://blog.csdn.net/zhongkelee/article/details/44831675
我們接着上一篇博客“面向對象(上)”的內容,繼續往下說。
抽象類
描述一個事物,卻沒有足夠信息,這時就將這個事物稱爲抽象事物。面對抽象的事物,雖然不具體,但是可以簡單化,不用面對具體的事物。(這樣其實更方便於面對同一類對象)
抽象類:籠統,模糊,看不懂,不具體!
抽象類也是不斷地向上抽取而來的。但是隻抽取了方法聲明,並不抽取具體的方法實現。只在乎有哪些功能,具體功能實現內容,由不同子類完成。抽象類中,可以定義抽象內容讓子類實現,也可以定義非抽象內容讓子類直接使用。它裏面定義的都是一些體系中的基本內容。
抽象類的特點:
1.抽象方法只能定義在抽象類中,抽象類和抽象方法都需要用abstract來修飾。(abstract可以描述類和方法,不可以描述變量)
2.抽象類中,也可以定義非抽象方法。
3.抽象方法只定義方法聲明,並不定義方法實現。
4.抽象類不能實例化。不能用new關鍵字創建對象。
5.只有子類繼承抽象類並覆蓋了抽象類中的所有抽象方法後,子類才能具體化(實例化),子類纔可以創建對象。否則,該子類還是一個抽象類。(好處:強制抽象類的子類具備並實現所有的抽象方法,才能實例化。)
abstract class 犬科{
abstract void 吼叫();
}
class 狗 extends 犬科{
void 吼叫(){
System.out.println("汪汪");
}
}
class 狼 extends 犬科{
void 吼叫(){
System.out.println("嗷嗷");
}
}
class AbstractDemo{
public static void main(String[] args){
}
}
關於抽象類,這裏註明幾個細節問題:1.抽象類中有構造函數嗎?
有。抽象類的構造函數雖然不能給抽象類對象實例化,因爲抽象類不能創建對象,
但是抽象類有子類,它的構造函數可以給子類對象實例化。
2.抽象類和一般類的異同?
相同點:
抽象類和一般類都是用來描述事物的,都在內部定義了成員,進行屬性和行爲的描述。
不同點;
a.抽象類描述事物的信息不具體。
一般類描述事物的信息具體。
b.一般類中不能定義抽象方法,只能定義非抽象方法。
抽象類中可定義抽象方法,同時也可以定義非抽象方法。
c.一般類可以被實例化。
抽象類不可以被實例化。
3.抽象類一定是個父類嗎?
是的。因爲需要子類覆蓋所有抽象方法後,纔可以對子類實例化,使用這些方法。
abstract class Demo extends Fu{}
class Sub extends Demo{}
4.抽象類中可以不定義抽象方法嗎?
可以。但是很少見,目的就是不讓該類創建對象。AWT的適配器對象就是這種類。
通常這個類中的方法有方法體,但是卻沒有內容。
abstract class Demo{
void show1()
{}
void show2()
{}
}
5.抽象關鍵字abstract和哪些關鍵字不能共存呢?final: final修飾類或者方法不可以被繼承或覆蓋,abstract修飾的類或方法必須有子類或被覆蓋。
private:私有的方法,子類無法訪問到,不叫覆蓋。(public不能覆蓋private。final不能被覆蓋。)
static:靜態區中的內容不需要對象,直接類名調用,抽象類名調用抽象方法沒有意義。
需求:公司中程序員有姓名,工號,薪水,工作內容。
項目經理除了有姓名,工號,薪水,還有獎金,工作內容。
對給出需求進行數據建模。
分析:
程序猿:
屬性:姓名,工號,薪水
行爲:工作內容
項目經理:
屬性:姓名,工號,薪水,還有獎金
行爲:工作內容
兩者不存在所屬關係,但是有共性內容,可以向上抽取。
兩者的共性類型是什麼?僱員。
僱員:
屬性:姓名,工號,薪水
行爲:工作內容
abstract class Employee{//對於老闆而言,面對僱員來指揮做事情,比面對程序猿和經理做事情,簡單得多。
private String name;
private String id;
private double pay;
Employee(String name, String id, double pay){
this.name = name;
this.id = id;
this.pay = pay;
}
public abstract void work();
}
class Programmer extends Employee{
Programmer(String name, String id, double pay){
super(name,id,pay);
}
public void work(){
System.out.println("code");
}
}
class Manager extends Employee{
private double bonus;
Manager(String name, String id, double pay, double bonus){
super(name,id,pay);
this.bonus = bonus;
}
public void work(){
System.out.println("manage");
}
}
class AbstractDemo{
public static void main(String[] args){
new Manager("lichunchun","SA14010001",200000,5000).work();
}
}
模板方法設計模式
解決的問題:當功能內部一部分實現時確定,一部分實現是不確定的。這時可以把不確定的部分暴露出去,讓子類去實現。
abstract class GetTime{
public final void getTime(){//此功能如果不需要複寫,可加final限定
long start = System.currentTimeMillis();
code();//不確定的功能部分,提取出來,通過抽象方法實現
long end = System.currentTimeMillis();
System.out.println("runtime : "+(end - start)+" ms");
}
public abstract void code();//抽象不確定的功能,讓子類複寫實現
}
class SubDemo extends GetTime{
public void code(){//子類複寫功能方法
for(int x = 0; x < 1000; x++){
System.out.println("x");
}
}
}
class TemplateDemo{
public static void main(String[] args){
new SubDemo().getTime();
}
}
接口
abstract class AbsDemo{
public abstract void show1();
public abstract void show2();
}
抽象類中所有的方法都是抽象的。這時,可以把抽象類用另一種形式來表示:接口。初期可以理解爲接口是特殊的抽象類。定義接口使用的關鍵字不是class,是interface。
接口中包含的成員,最常見的有全局常量、抽象方法。
注意:接口中的成員都有固定的修飾符,即使不寫,編譯器也會自動補全。
成員變量:public static final
成員方法:public abstract
共性:成員都是public修飾的。
interface Inter{
public static final int NUM = 4;
public abstract void show1();
public abstract void show2();
}
class Demo implements Inter{
public void show1(){}
public void show2(){}
}
class InterfaceDemo{
public static void main(String[] args){
new Demo();
}
}
接口的特點:1.接口不可以實例化。因爲接口中的方法都是抽象方法。
2.接口的子類必須實現了接口中所有的抽象方法後,該子類纔可以實例化。否則,該子類還是一個抽象類。
3.接口是用來被實現的。
類與類之間存在着繼承關係,類與接口中間存在的是實現關係。繼承用extends,實現用implements。
class Fu1{
<span style="white-space:pre"> </span>void show(){
sop("Fu1 show");
}
}
class Fu2{
void show(){
sop("Fu2 show");
}
}
class Zi extends Fu1,Fu2{
}
new Zi().show();//調用的不確定性。原因在於方法主體內容不同。
Java中不直接支持多繼承,而是對該機制進行改良。通過接口來解決問題。將多繼承轉換成了多實現,在子類具體實現時,子類中才有方法主體,不會出現調用的不確定性。interface InterA{
public abstract void show();
}
interface InterB{
public abstract void show();
}
class SubInter implements InterA,InterB{//多實現
public void show(){
System.out.println("inter show");
}
}
class InterfaceDemo2{
public static void main(String[] args){
SubInter in = new SubInter();
in.show();
}
}
其實,我們可以形象地將繼承和實現比喻爲只認一個爹,但可以有很多個叔叔,只不過這裏的叔叔沒有方法主體。
class Fu{
void show(){
System.out.println("fu show");
}
}
interface Inter{
public abstract void show1();
}
class Zi extends Fu implements Inter{
public void method(){
System.out.println("zi method");
}
public void show1(){
System.out.println("zi show1");
}
}
class InterfaceDemo3{
public static void main(String[] args){
Zi z = new Zi();
z.show();
z.show1();
z.method();
}
}
類與類之間:單繼承關係。is a,是什麼。類與接口之間:實現關係。like a,像什麼。
接口與接口之間:多繼承關係。
interface Inter1{
public abstract void show1();
}
interface Inter2{
public abstract void show2();
}
interface Inter3 extends Inter1,Inter2{
public abstract void show3();
}
class Inter implements Inter3{
public void show1(){}
public void show2(){}
public void show3(){}
}
爲了方便創建Inter接口的子類對象,可以用一個類先把接口中的所有方法都空實現。該類創建對象沒有意義,所以可以將該類抽象。這就是傳說中的沒有抽象方法的抽象類。interface Inter{
public abstract void show1();
public abstract void show2();
public abstract void show3();
public abstract void show4();
}
abstract class Demo implements Inter{//沒有抽象方法的抽象類,方便創建接口的子類對象。
//private Demo(){} 不抽象,光私有化構造函數是不可以的。
//因爲Demo類是需要被子類繼承的,子類對象初始化是要訪問父類構造函數的,不可以私有化。
public void show1(){}
public void show2(){}//空實現
public void show3(){}
public void show4(){}
}
class DemoA extends Demo /*implements Inter*/{
public void show1(){
System.out.println("show1");
}
}
class DemoB extends Demo /*implements Inter*/{
public void show3(){
System.out.println("show3");
}
}
class InterfaceDemo4{
public static void main(String[] args){
}
}
接口的思想:筆記本電腦的USB接口。
1.接口的出現擴展了功能。
2.接口其實就是暴露出來的規則。
3.接口的出現降低了耦合性。解耦~
接口的出現,產生了兩方:一方在使用接口(筆記本),一方在實現接口(USB鼠標)。
開發順序:接口->使用接口的類->實現接口的類,這其中,使用接口的類面向的是接口。
class Mouse{}
interface USB{}
class NewMouse extends Mouse implements USB{}
抽象類:用於描述事物的共性基本功能,是一個體系單元的共性內容的向上抽取。接口:用於定義的都是事物的額外擴展功能。
共性:都是不斷向上抽取的結果。
抽象類和接口的區別:
1.類與類之間是繼承關係,而且只能單繼承
類與接口之間是實現關係,而且可以多實現
2.抽象類中可以定義抽象和非抽象方法,子類可以直接使用,或者覆蓋使用。
接口中定義的都是抽象方法,子類必須全部實現纔可以使用。
3.抽象類使用的是 is a 關係
接口使用的是 like a 關係
4.抽象類的成員修飾符可以自定義(除了abstract部分前面說的那些限制條件)
接口中的成員修飾符都是固定的。(public static final 和 public abstract)
5.抽象類有構造函數
接口沒有構造函數
abstract class 犬{
public abstract void 吃();
public abstract void 叫();
}
interface 緝毒
{
public abstract void 緝毒();
}
class 緝毒犬 extends 犬 implements 緝毒{
public void 吃(){}
public void 叫(){}
public void 緝毒(){}
}
多態
下面我們再來說面向對象核心思想的最後一個特徵:多態。
多態在程序中的體現:父類的引用或者接口的引用指向了子類的對象。
多態的好處:提高了代碼的擴展性。
多態的弊端:不能使用子類的特有方法。(即訪問的侷限性)
多態的前提:
1.必須有關係,繼承,實現。
2.通常有覆蓋。
多態的出現思想上也做着變化:以前是創建對象並指揮對象做事情。有了多態以後,我們可以找到對象的共性類型,直接操作共性類型做事情即可,這樣可以指揮一批對象做事情,即通過操作父類或接口實現。
abstract class Animal{
public abstract void eat();
}
class Dog extends Animal{
public void eat(){
System.out.println("bones");
}
public void lookHome(){
System.out.println("look home");
}
}
class Cat extends Animal{
public void eat(){
System.out.println("fish");
}
public void catchMouse(){
System.out.println("catch mouse");
}
}
class Pig extends Animal{
public void eat(){
System.out.println("si liao");
}
public void gongDi(){
System.out.println("gong di");
}
}
class DuotaiDemo{
public static void main(String[] args){
/*
Animal a = new Dog();
a.eat();//子類方法覆蓋父類,運行的是子類方法
*/
method(new Cat());
}
//當面對共性類型時,所有的子類對象都可以接收,說明提高了代碼的擴展性。
public static void method(Animal a){//a = new Dog(); a = new Cat(); a = new Pig();
a.eat();
}
}
向上向下轉型
向上轉型好處:隱藏了子類型,提高了代碼的擴展性。
向上轉型弊端:只能使用父類中的功能,不能使用子類特有功能。功能被限定了。
如果不需要面對子類型,通過提高擴展性,或者使用父類的功能即可完成操作,就使用向上轉型。
向下轉型好處:可以使用子類型的特有功能。
向下轉型弊端:面對具體的子類型。向下轉型有風險。容易發生ClassCastException。只要轉換類型和對象類型不匹配就會發生。想要安全,必須要進行判斷。
判斷一個對象是否匹配某一個類型,需要使用一個關鍵字 instanceof ,用法 對象 instanceof 類型。
什麼時候用向下轉型:需要使用子類型的特有方法時。但一定要用 instanceof 判斷。
abstract class Animal{
public abstract void eat();
}
class Dog extends Animal{
public void eat(){
System.out.println("bones");
}
public void lookHome(){
System.out.println("look home");
}
}
class Cat extends Animal{
public void eat(){
System.out.println("fish");
}
public void catchMouse(){
System.out.println("catch mouse");
}
}
class DuotaiDemo2{
public static void main(String[] args){
Animal a = new Cat();
//a.eat();
if (!(a instanceof Dog)){//判斷對象是否實現了指定的接口或繼承了指定的類
System.out.println("類型不匹配");
return;
}
Dog d = (Dog)a;
d.eat();
d.lookHome();
}
}
轉型過程中,至始至終,只有子類對象這一個實例在做着類型的變化。
練習:
畢姥爺:講課。釣魚。
畢老師 extends 畢姥爺:講課。看電影。
要求體現多態,要看到向上轉型,向下轉型。
class 畢姥爺{
public void 講課(){
System.out.println("管理");
}
public void 釣魚(){
System.out.println("釣魚");
}
}
class 畢老師 extends 畢姥爺{
public void 講課(){
System.out.println("java");
}
public void 看電影(){
System.out.println("看電影");
}
}
class DuoTaiTest{
public static void main(String[] args){
//多態形式
畢姥爺 x = new 畢老師();//向上轉型
x.講課();
x.釣魚();
//要想使用畢老師的特有方法 看電影
畢老師 y = (畢老師)x;//向下轉型
y.講課();
y.釣魚();
y.看電影();
}
//轉型過程中,至始至終,只有子類對象這一個實例在做着類型的變化。
}
多態在子父類成員上的特點
多態中對成員的調用。
1.成員變量。
當子父類中出現同名成員變量時,
多態調用時,只看調用該成員變量的引用所屬類中的成員變量。
簡單說:無論編譯或者運行,都看等號左邊的就哦了。
(編譯時不產生對象,只檢查語法錯誤)
2.成員函數。
當子父類中出現一模一樣的函數時,多態調用,
編譯時,看的是引用變量所屬的類中的方法。(編譯時,還沒有創建對象)
運行時,看的是對象所屬的類中的方法。(注意,此時父類方法,子類都已繼承,若一模一樣,則子類的覆蓋)
簡單說:編譯看左邊,運行看右邊。
成員方法動態綁定到當前對象上。
3.靜態方法
當子父類中出現一模一樣的函數時,多態調用,
編譯和運行是看引用變量所屬的類中的方法。
簡單說:編譯運行都是看左邊。
其實,真正調用靜態方法是不需要對象的,直接類名調用。
因爲靜態方法綁定到該方法所屬的類上,不所屬於對象。
注:
class Fu{
int num = 4;
void show(){
System.out.println("fu show");
}
static void staticMethod(){
System.out.println("fu static method");
}
}
class Zi extends Fu{
int num = 6;
void show(){
System.out.println("zi show");
}
static void staticMethod(){
System.out.println("zi static method");
}
}
class DuoTaiDemo3{
public static void main(String[] args){
Fu f = new Zi();
System.out.println(f.num);
f.show();
f.staticMethod();
}
}
4.this.成員變量
始終代表的是本類引用。
執行哪個類的成員函數,那個成員函數中的this就代表那個類的引用。
class Fu{
int num = 5;
void show(){
System.out.println("num = "+this.num);//this代表的是本類引用。//成員變量:編譯運行看左邊。
}
}
class Zi extends Fu{
int num = 6;
}
class DuoTaiTest2{
public static void main(String[] args){
Fu f = new Zi();
f.show();//運行看右邊。右邊是Zi類對象,其實Zi類也是有show()函數的,是繼承的Fu類的。所以運行的是父類的show。
}
}
class Fu{
int num = 5;
void show(){}
}
class Zi extends Fu{
int num = 6;
void show(){
System.out.println("num = "+this.num);//此時,這個this所在的show函數在Zi類中,所以,這個this代表Zi類對象,只要是執行Zi的show函數,都是打印Zi的num值。
}
}
class DuoTaiTest2{
public static void main(String[] args){
Fu f = new Zi();
f.show();//成員函數,編譯看左邊,運行看右邊。運行的是子類的show。
}
}
多態練習:USB接口。
//先定義一個規則。java中可以通過接口的形式來完成規則的定義,進行解耦。
//讓設備和筆記本的耦合性降低,易於擴展和維護。
interface USB{
public abstract void open();
public abstract void close();
}
class NoteBook{
public void run(){
System.out.println("NoteBook run");
}
/**
使用符合規則的外圍設備。這樣就不用每次面對具體的類型,
後期加進來的設備都符合這個規則,只要面對規則就可以了。
*/
public void useUSB(USB usb){//定義了一個接口類型的引用//USB usb = new MouseByUSB();//多態提高了筆記本的擴展性
if (usb != null){
usb.open();
usb.close();
}
}
}
class MouseByUSB /*extends Mouse*/ implements USB{
public void open(){
System.out.println("mouse open");
}
public void close(){
System.out.println("mouse close");
}
}
class KeyBoardByUSB/*extends KeyBoard*/ implements USB{
public void open(){
System.out.println("keyboard open");
}
public void close(){
System.out.println("keyboard close");
}
}
class USBTest{
public static void main(String[] args){
NoteBook book = new NoteBook();
book.run();
book.useUSB(null);
book.useUSB(new MouseByUSB());
book.useUSB(new KeyBoardByUSB());
}
}
Object類
Object:所有類的直接或者間接父類,Java認爲所有的對象都具備一些基本的共性內容,這些內容可以不斷的向上抽取,最終就抽取到了一個最頂層的類中的,該類中定義的就是所有對象都具備的功能。
具體方法:
1,boolean equals(Object obj):用於比較兩個對象是否相等,其實內部比較的就是兩個對象地址。
而根據對象的屬性不同,判斷對象是否相同的具體內容也不一樣。
所以在定義類時,一般都會複寫equals方法,建立本類特有的判斷對象是否相同的依據。
2,String toString():將對象變成字符串。
默認返回的格式:類名@哈希值 = getClass().getName() + '@' + Integer.toHexString(hashCode())
爲了對象對應的字符串內容有意義,可以通過複寫,建立該類對象自己特有的字符串表現形式。
3,Class getClass():獲取任意對象運行時的所屬字節碼文件對象
4,int hashCode():返回該對象的哈希碼值。支持此方法是爲了提高哈希表的性能。
通常equals,toString,hashCode,在應用中都會被複寫,建立具體對象的特有的內容。
//java.lang.Object
class Person extends Object{
private int age;
private String name;
Person(String name, int age){
this.age = age;
this.name = name;
}
public boolean equals(Object obj){//覆蓋父類方法 //Object obj = new Person();
//提高效率。如果兩個引用指向的是同一個對象,不用再轉換並比較內容了。直接判斷地址就可以。
if (this == obj)
return true;
//Object.age是錯誤的,因爲Object中沒有age屬性。
//要想使用子類對象的特有屬性或者行爲,必須對其進行向下轉型。並且需要進行類型判斷。
if (!(obj instanceof Person))
throw new ClassCastException("類型錯誤");
Person p = (Person)obj;
//判斷兩個人的名字是否相同,不要用==,字符串本身就是一個對象。使用String類的equals方法判斷。
return this.name.equals(p.name) && this.age == p.age;
}
/**
建立Person對象特有的字符串表現形式。只要覆蓋toString方法即可。
*/
public String toString(){
return "Person [ name = "+this.name+", age = "+this.age+" ]";
}
}
class ObjectDemo{
public static void main(String[] args){
Person p1 = new Person("lisi",22);
Person p2 = new Person("wanger",23);
System.out.println(p1);//Person@1db9742
System.out.println(p1.toString());
System.out.println(p2.toString());
System.out.println(p1.equals(p2));//判斷的是對象的內容,用equals。
System.out.println(p1 == p2);//判斷的是對象的地址。
}
}
內部類
內部類其實就是將類定義到了另一個類內部。A類要直接訪問B類中的成員時,可以將A類定義到B類中。作爲B類的內部類存在。
訪問規則:內部類可以直接訪問外部類中的成員。外部類要想訪問內部類,只能創建內部類的對象來訪問。
當內部類定義在外部類中的成員位置上,可以使用一些成員修飾符修飾 private、static。
1:默認修飾符。
直接訪問內部類格式:外部類名.內部類名 變量名 = 外部類對象.內部類對象;
Outer.Inner in = new Outer.new Inner();//這種形式很少用。
但是這種應用不多見,因爲內部類之所以定義在內部就是爲了封裝。
想要獲取內部類對象通常都通過外部類的方法來獲取。這樣可以對內部類對象進行控制。
2:私有修飾符。
通常內部類被封裝,都會被私有化,因爲封裝性不讓其他程序直接訪問。
3:靜態修飾符。
如果內部類被靜態修飾,相當於外部類,會出現訪問侷限性,只能訪問外部類中的靜態成員。
注意;如果內部類中定義了靜態成員,那麼該內部類必須是靜態的。
內部類編譯後的文件名爲:“外部類名$內部類名.java”;
class Outer{
private static int num = 4;
class Inner{//內部類,相當於外部類中的一個成員。可以被成員修飾符所修飾。//外部類先加載,如果沒有用到非靜態內部類,非靜態內部類的class文件一直不加載。
static final int count = 5;//在非靜態的內部類中只允許定義靜態的常量。不能定義其它靜態成員。//這是因爲,非靜態內部類如果被調用,需要new Inner()對象,而靜態成員不需要對象即可調用,這是矛盾的。
void show(){
System.out.println(num);//Outer.this.num
}
}
static class Inner2{//靜態內部類。相當於一個外部類。隨着Outer的加載而加載。
void show2(){
System.out.println("show2..."+num);
}
static void show3(){
System.out.println("show3..."+num);
}
}
public void method(){
Inner in = new Inner();
in.show();
}
}
class InnerClassDemo{
public static void main(String[] args){
Outer out = new Outer();
out.method();
//=========非靜態,非私有的內部類訪問方式=========
Outer.Inner in = new Outer().new Inner();//需要外部類對象
in.show();
//=========靜態,非私有的內部類訪問方式1,訪問非靜態成員=========
Outer.Inner2 in = new Outer.Inner2();//不需要外部類對象
in.show2();
//=========靜態,非私有的內部類訪問方式2,訪問靜態成員=========
Outer.Inner2.show3();
}
}
爲什麼內部類就可以直接訪問外部類中的成員?
那是因爲內部類持有了外部的引用:外部類名.this
class Outer{
int num = 2;
class Inner{
int num = 3;
void show(){
int num = 4;
System.out.println("show..."+Outer.this.num);//Inner.this.num
}
}
public void method(){
new Inner().show();
}
}
class InnerClassDemo2{
public static void main(String[] args){
new Outer().method();
}
}
內部類可以定義在外部類中的成員位置上,也可以定義在外部類中的局部位置上。
注意:局部內部類,只能訪問被final修飾的局部變量。
因爲非final修飾的,生命週期不夠,因爲局部變量消失,建立的對象還沒有消失。
class Outer{
private int num = 4;
public void method(){
final int x = 5;
class Inner{
void show(){
System.out.println("x = "+x);
System.out.println("num = "+num);
}
}
}
}
class InnerClassDemo2{
public static void main(String[] args){
new Outer().method();
}
}
匿名內部類
匿名內部類:簡化書寫的內部類。
前提:內部類需要繼承或者實現外部的類或者接口。
格式:new 父類or接口名(){定義子類成員或者覆蓋父類方法}.方法。
匿名內部類其實就是一個子類對象。
new Demo();---------後面加;號, 就是父類對象。
new Demo(){}-------後面加{}號,就是子類對象。
abstract class Demo{
abstract void show();
}
class Outer{
private int num = 4;
public void method(){
new Demo(){
public void show(){
System.out.println("show..."+num);
}
}.show();
}
}
class InnerClassDemo3{
public static void main(String[] args){
new Outer().method();
}
}
當出現多個方法時,可以如下使用:
interface Inter{
public abstract void show1();
public abstract void show2();
}
class Outer{
private int num = 2;
/*class Inner implements Inter{
public void show1(){}
public void show2(){}
}*/
public void method(){
//Inner in = new Inner();
//in.show1();
//in.show2();
Inter in = new Inter(){
public void show1(){}
public void show2(){}
};
in.show1();
in.show2();
}
}
class InnerClassDemo4{
public static void main(String[] args){
//new Outer().method();
new Inner();//不可以。主函數是靜態的,無法訪問靜態成員。靜態方法中,不可以出現this。
new InnerClassDemo4().new Inner();//可以。
}
class Inner{
}
public void show(){
this.new Inner();//可以。
}
}
經典面試題:如下的1、2寫法正確嗎?有何區別?class Outer{
/*class Inner extends Object{
}*/
public void method(){
//1
new Object(){
public void show(){
System.out.println("show run");
}
}.show();//匿名內部類就是子類對象。子類對象.子類方法
//2
Object obj = new Object(){//object obj指向了自己的子類對象。對象向上提升爲了Object。就不能調用子類的特有方法。
public void show(){
System.out.println("show run");
}
};
obj.show();//不可以。
}
}
class InnerClassDemo5{
public static void main(String[] args){
}
}
寫法是正確,1和2都是在通過匿名內部類建立一個Object類的子類對象。
區別:
第一個可是編譯通過,並運行。
第二個編譯失敗,因爲匿名內部類是一個子類對象,當用Object的obj引用指向時,就被提升爲了Object類型,而編譯時檢查Object類中是否有show方法,所以編譯失敗。
class InnerClassDemo6 {
+(static)class Inner{
void show(){}
}
public void method(){
this.new Inner().show();//可以
}
public static void main(String[] args) {//static不允許this
this.new Inner().show();//錯誤,Inner類需要定義成static
}
}
經典筆試題:通過匿名內部類補足Outer類中的代碼。
interface Inter{
void show();
]
class Outer{//通過匿名內部類補足Outer類中的代碼
}
class InnerClassDemo6{
public static void main(String[] args){
Outer.method().show();
}
}
分析:
Outer.method():意思是Outer中有一個名稱爲method的方法,而且這個方法是靜態的。
Outer.method().show():當Outer類調用靜態的method方法運算結束後的結果又調用了show方法,意味着:method()方法運算完一個是對象,而且這個對象是Inter類型的。
答案:
interface Inter{
void show();
]
class Outer{//通過匿名內部類補足Outer類中的代碼
public static Inter method(){
return new Inter(){
public void show(){}
};
}
}
class InnerClassDemo6{
public static void main(String[] args){
Outer.method().show();
}
}
此外,當函數的參數是接口類型引用時,匿名內部類還可以作爲方法的參數進行傳遞。
interface Inter{
public abstract void show();
}
class InnerClassDemo7{
public static void main(String[] args){
function(new Inter(){
public void show(){}
});//匿名內部類作爲方法的參數進行傳遞
}
public static void function(Inter in){//如果function不是static,主函數是無法調用的
in.show();
}
}
後面一片博客將會介紹,JavaSE面向對象中的異常、包。
有任何問題請和我聯繫,共同進步:[email protected]
轉載請聲明出處:http://blog.csdn.net/zhongkelee/article/details/44831675