------- android教育訓練、java教育訓練、期待與您交流! ----------
一、 抽象類
(1)抽象:把多個類中的共性的内容進行抽取,抽取後就能形成一個繼承體系。但是,在今天的案例中,方法的聲明相同,方法體不同,這樣的抽取後,在父類中定義的時候,是不能寫方法體的,這樣的方法要想被java識别,就必須被标記為抽象的。如果一個類有抽象方法,那麼該類肯定是抽象類。反之,抽象類中不一定有抽象方法。
抽象類的由來:
多個對象都具備相同的功能,但是功能具體内容有所不同,那麼在抽取過程中,隻抽取了功能定義,并未抽取功能主體,那麼隻有功能聲明,沒有功能主體的方法稱為抽象方法。
例如:狼和狗都有吼叫的方法,可是吼叫内容是不一樣的。是以抽象出來的犬科雖然有吼叫功能,但是并不明确吼叫的細節。
(2)格式:
抽象方法隻有方法聲明,沒有方法體,定義在抽象類中。
格式:修飾符 abstract 傳回值類型 函數名(參數清單);
(2)好處:
A:抽象類中可以有成員變量和非抽象方法,也可以實作代碼的複用。
B:抽象類強制要求繼承他的子類必須完成某些功能。
(3)成員特點:
A:構造方法
抽象類有構造方法,但是本身不能被執行個體化。
它的構造方法用于子類執行個體化使用。
B:成員變量
抽象類既可以有成員變量,也可以有成員常量。
C:成員方法
抽象類既可以抽象方法,也可以有非抽象方法。
代碼示例:
abstract class Animal
{
private String name;
public final int x = 10;
public Animal()
{
System.out.println("animal");
}
public Animal(String name)
{
this.name = name;
}
public void setName(String name)
{
this.name = name;
}
public String getName()
{
return name;
}
public void show()
{
System.out.println("今天天氣不錯,适合學習");
}
public abstract void method();//定義抽象方法
}
class Dog extends Animal
{
public Dog()
{
super();
System.out.println("dog");
}
public Dog(String name)
{
super(name);
}
public void show()
{
System.out.println("今天天氣不錯,适合郊遊");
}
public void method()
{
System.out.println("dog method");
}
}
class AbstractDemo2
{
public static void main(String[] args)
{
//建立對象
//Animal a = new Animal();
Dog d = new Dog();
System.out.println(d.getName());
Dog d2 = new Dog("小白");
System.out.println(d2.getName());
d2.show();
d2.method();
}
}
(4)使用:
當一個類繼承一個抽象類的時候
要麼重寫抽象類的所有抽象方法。
要麼本身是一個抽象類。
(5)抽象類的注意事項
A:抽象類沒有構造方法,那麼有什麼用?
有,用于子類執行個體化使用。
B:是否有非抽象方法?如果沒有抽象方法類為什麼要定義為抽象類?
有,提高代碼複用性。
沒有抽象方法的抽象類就是為了不讓他能建立對象。
C:abstract不能和哪些關鍵系并存。
private:私有的功能,子類是不能重寫的。而abstract是要求子類重寫的。
fianl:最終的意思,子類不能重寫。而abstract是要求子類重寫的。
static:靜态的意思,它是跟類相關的。而我們研究的是對象間的關系。
靜态的東西,可以通過類名調用,但是,抽象的方法,用類名調用沒有實際意義。
修飾關鍵字:
預設修飾符,private,public -- 成員變量private,成員方法public
fianl:最終的,可以修飾類,成員變量,成員方法
static:讓成員多了一種調用方式。可以修飾成員。
abstract:修飾類,修飾方法,表示是抽象。
組合使用:
一般格式:
權限修飾符+static+final+成員變量/方法
代碼示例:
/*
老師示例
具體事物:基礎班老師,就業班老師
共性:姓名,年齡,講課。
根據我們學過的面向對象知識,我們就可以如下分析:
定義一個老師類,然後,分别讓基礎班老師和就業班老師繼承老師類。
如何定義一個老師類呢,就是分析基礎班老師和就業班老師的共性内容:
老師類:
成員變量:姓名,年齡
成員方法:講課 因為每個老師講課的内容不一樣,是以,我們定義為抽象方法。
基礎班老師:
重寫講課方法
輸出老師的資訊。
就業班老師:
重寫講課方法
輸出老師的資訊。
*/
abstract class Teacher
{
private String name;
private int age;
public Teacher(){}
public Teacher(String name,int age)
{
this.name = name;
this.age = age;
}
public String getName()
{
return name;
}
public int getAge()
{
return age;
}
//抽象的講課方法
public abstract void teach();
public void printMessage()
{
System.out.println(name+"***"+age);
}
}
class BaseTeacher extends Teacher
{
public BaseTeacher(String name,int age)
{
super(name,age);
}
public void teach()
{
System.out.println("基礎班老師講JavaSE");
}
/*
public void printMessage()
{
System.out.println(getName()+"***"+getAge());
}
*/
}
class WorkTeacher extends Teacher
{
public WorkTeacher(String name,int age)
{
super(name,age);
}
public void teach()
{
System.out.println("就業班老師講JavaEE");
}
}
class TeacherDemo
{
public static void main(String[] args)
{
BaseTeacher bt = new BaseTeacher("林青霞",25);
bt.teach();
bt.printMessage();
WorkTeacher wt = new WorkTeacher("郭德綱",38);
wt.teach();
wt.printMessage();
//使用多态
Teacher t = new BaseTeacher("劉姐",18);
t.teach();
t.printMessage();
t = new WorkTeacher("芙蓉姐姐",20);
t.teach();
t.printMessage();
}
}
二、接口
(1)接口:當一個抽象類中的方法都是抽象的時候,(并且都是成員常量的時候的。)java提供了一個新的表示形式,那就是接口。
(2)好處:
A:接口是對外暴露的規則(比如:USB,電腦内部的插槽,CPU的針孔)
B:接口是功能的擴充
C:接口降低了程式的耦合性
低耦合:類與類之間的關系
高内聚:類本身的能力
D:接口可以用來多實作
E:類與接口之間是實作關系,而且類可以繼承一個類的同時實作多個接口
F:接口與接口之間可以有繼承關系
(3)成員特點:
A:成員變量
成員變量都是常量,因為有預設修飾符:public static final
B:成員方法
成員方法都是抽象的,因為有預設修飾符:public abstract
建議,每次自己寫接口的時候,盡量把修飾符自己寫上。
(4)類,接口互相間的關系:
A:類與類
繼承關系,java隻支援類的單繼承,但是可以多重(層)繼承。
B:類與接口
實作關系,可以單實作,也可以多實作。
還可以在繼承一個類的同時,實作多個接口。
C:接口與接口
繼承關系,可以單繼承,也可以多繼承。
如果一個類實作一個接口,就必須實作該接口及其父接口的所有抽象方法。
代碼示例:
interface Inter//定義一個接口
{
public abstract void show();//方法是抽象的
}
interface Inter2//定義第二個接口,兩個方法都是抽象的
{
public abstract void method();
public abstract void show();
}
interface Inter3 extends Inter,Inter2//第三個接口繼承了前兩個接口
{
public abstract void function();
}
class Fu //預設有個extends Object
{
}
class Demo extends Fu implements Inter,Inter2//繼承Fu類并實作了前兩個接口
{
public void show()//複寫show方法
{
System.out.println("demo show");
}
public void method()//複寫method方法
{
System.out.println("demo method");
}
}
三、抽象類和接口的差別:
(A)成員差別:
抽象類:
構造方法
成員變量:可以是變量,也可以是常量。
成員方法:可以是抽象方法,也可以是非抽象方法。
接口:
成員變量:隻能是常量。預設修飾符:public static final
成員方法:隻能是抽象方法。預設修飾符:public abstract
(2)類隻能單繼承
而接口可以多繼承。接口的出現避免了java的單繼承的局限性。
(3)抽象類被繼承,類中定義的是繼承體系的共性内容。
接口被實作,接口中定義的是體系的擴充内容。
(4)設計了解不同:
抽象類被繼承,展現的是一種:"is a" 的關系
接口被實作,展現的是一種:"like a" 的關系
代碼示例:
abstract class Person//抽象類
{
private String name;
private int age;
public void setName(String name)
{
this.name = name;
}
public String getName()
{
return name;
}
public void setAge(int age)
{
this.age = age;
}
public int getAge()
{
return age;
}
public abstract void eat();//定義抽象方法
}
abstract class Player extends Person
{
public abstract void study();//抽象方法
}
abstract class Coach extends Person
{
public abstract void teach();//抽象方法
}
interface StudyEnglish//接口
{
public abstract void studyEnglish();//接口中的抽象方法
}
class PingPongStu extends Player implements StudyEnglish
{
public void studyEnglish()//複寫抽象方法
{
System.out.println("乒乓運動員學英語");
}
public void study()//複寫抽象方法
{
System.out.println("乒乓運動員學習乒乓");
}
public void eat()//複寫抽象方法
{
System.out.println("乒乓運動員吃乒乓");
}
}
class PingPongCoach extends Coach implements StudyEnglish
{
public void studyEnglish()//複寫抽象方法
{
System.out.println("乒乓教練學英語");
}
public void teach()//複寫抽象方法
{
System.out.println("乒乓教練教學員學乒乓");
}
public void eat()//複寫抽象方法
{
System.out.println("乒乓教練吃乒乓乒乓");
}
}
class BasketStu extends Player
{
public void study()//複寫抽象方法
{
System.out.println("籃球運動員學打籃球");
}
public void eat()//複寫抽象方法
{
System.out.println("籃球運動員吃籃球");
}
}
class BasketCoach extends Coach
{
public void teach()//複寫抽象方法
{
System.out.println("籃球教練教學員學打籃球");
}
public void eat()//複寫抽象方法
{
System.out.println("籃球教練吃籃球");
}
}
class PersonDemo
{
public static void main(String[] args)
{
PingPongStu pps = new PingPongStu();
pps.setName("王浩");
pps.setAge(44);
System.out.println("姓名是:"+pps.getName()+",年齡是:"+pps.getAge());
pps.study();
pps.eat();
pps.studyEnglish();
System.out.println("************************");
BasketStu bs = new BasketStu();
bs.setName("姚明");
bs.setAge(50);
System.out.println("姓名是:"+bs.getName()+",年齡是:"+bs.getAge());
bs.study();
bs.eat();
System.out.println("************************");
PingPongCoach ppc = new PingPongCoach();
ppc.setName("乒乓劉教練");
ppc.setAge(36);
System.out.println("姓名是:"+ppc.getName()+",年齡是:"+ppc.getAge());
ppc.teach();
ppc.eat();
ppc.studyEnglish();
System.out.println("************************");
BasketCoach bc = new BasketCoach();
bc.setName("籃球張教練");
bc.setAge(25);
System.out.println("姓名是:"+bc.getName()+",年齡是:"+bc.getAge());
bc.teach();
bc.eat();
}
}
四、Object類的使用
Object:類Object是類層次結構的根類。每個類都使用Object作為超類。
Object類中我們要掌握的功能:
A:public String toString()
傳回該對象的字元串表示。建議所有子類都重寫此方法。
如果沒有重寫,預設的結果是:
getClass().getName() + '@' + Integer.toHexString(hashCode())
類名@哈希值的十六進制
public static String toHexString(int i):把i按照十六進制的資料傳回。
為什麼要重寫呢?
因為位址值的顯示對我們來說,沒有意義。
為了讓顯示的效果有意義一些,重寫此方法。
代碼示例:
class Student extends Object
{
private String name;
public Student(){}
public void setName(String name)
{
this.name = name;
}
public String getName()
{
return name;
}
//重寫方法
public String toString()
{
//成員變量的組成:多個成員變量用,隔開。
//"name:"+name+",age:"+age;
return "name:"+name;
}
}
class ObjectDemo
{
public static void main(String[] args)
{
//建立對象
Student s = new Student();
s.setName("林青霞");
//[email protected]
//其實在用輸出語句輸出一個對象的名稱的時候,其實是用對象調用了toString()方法而已。
System.out.println(s);
System.out.println(s.toString()); //類@十六進制的hashCode()
//hashCode方法
System.out.println(s.hashCode()); //4067003 -- int
System.out.println(Integer.toHexString(4067003)); //3e0ebb
}
}
B:public int hashCode()
傳回該對象的哈希碼值。
C:finalize()
當垃圾回收器确定不存在對該對象的更多引用時,由對象的垃圾回收器調用此方法。
D:Class getClass():反射的時候講。
傳回的是該類的位元組碼檔案對象的類檔案。
E:public boolean equals(Object obj)
訓示其他某個對象是否與此對象"相等"。
如果類沒有重寫equals方法,那麼它比的還是位址值。
代碼示例:
class Student
{
private String name;
private int age;
public Student(){}
public Student(String name,int age)
{
this.name = name;
this.age = age;
}
//重寫equals方法
public boolean equals(Object obj)//重寫的是Object類中的equals方法
{
//為了提高程式的效率
if(this == obj)
{
return true;
}
//為了提高程式健壯性
if(!(obj instanceof Student))
{
return false;
}
Student s = (Student)obj; //向下轉型
//這個if語句可以使用三元運算符改進
//下邊equals是String類中重寫Object類中equals之後的
return this.name.equals(s.name) && this.age == s.age;
}
}
class Demo
{
}
class ObjectDemo3
{
public static void main(String[] args)
{
Student s1 = new Student("李建峰",18);
Student s2 = new Student("李建峰",18);
Student s3 = new Student("張學友",20);
System.out.println(s1.equals(s2));
System.out.println(s1.equals(s3));
//自己跟自己比
System.out.println(s1.equals(s1));
Demo d = new Demo();
//ClassCastException
System.out.println(s1.equals(d));
}
}
五、内部類
1、内部類定義:
将一個類定義在另一個類的裡面,對裡面那個類就稱為内部類(内置類,嵌套類)。
2、通路特點:
A:内部類可以直接通路外部類中的成員,包括私有成員
B:外部類要通路内部類中的成員必須要建立内部類的對象
代碼示例:
class Outer
{
private int num = 10;
//成員内部類
class Inner
{
public void show()
{
System.out.println("num:"+num);
}
}
//成員方法
public void method()
{
//建立對象
Inner in = new Inner();
in.show();
}
}
class InnerDemo
{
public static void main(String[] args)
{
//在外部使用
Outer o = new Outer();
o.method();
//注意格式:外部類.内部類 名字 = 外部類對象.内部類對象
Outer.Inner oi = new Outer().new Inner();
oi.show();
}
}
3、内部類位置
A:成員位置
a:如果沒有被private或者static修飾。
外部類.内部類 名字 = 外部類對象.内部類對象;
舉例:
Outer.Inner oi = new Outer().new Inner();
oi.show();
b:被private或者static修飾。
如果被private修飾後,就不能再在除了外部類的其他類中使用。
如果被static修飾,并且沒有被private修飾,使用方式如下:
外部類.内部類 名字 = 外部類.内部類對象;
舉例:
Outer.Inner oi = new Outer.Inner();
oi.show();
代碼示例:
/*
内部類被靜态修飾:
*/
class Outer
{
private static int num = 10;
static class Inner
{
public void show()
{
System.out.println("show:"+num);
}
public static void method()
{
System.out.println("method:"+num);
}
}
}
class InnerDemo3
{
public static void main(String[] args)
{
//Outer.Inner oi = new Outer().new Inner();
Outer.Inner oi = new Outer.Inner();
oi.show();
oi.method();
//靜态的不想通過對象通路
Outer.Inner.method();
}
}
内部類被private修飾:
/*
内部類被private修飾
*/
class Outer
{
private int num = 10;
private class Inner
{
public void show()
{
System.out.println("num:"+num);
}
}
public void method()
{
Inner in = new Inner();
in.show();
}
}
class InnerDemo2
{
public static void main(String[] args)
{
//内部類被private修飾後就不能再被使用
//Outer.Inner oi = new Outer().new Inner();
Outer o = new Outer();
o.method();
}
}
B:局部位置
a:有名字
按照普通的方式使用即可。
b:沒有名字,匿名内部類(掌握)
格式:
new 類或者接口()
{
重寫方法,或者自定義方法
};
其實這裡的本質是一個子類匿名對象。
前提:外部存在着一個類或者接口。
内部類定義在局部位置:
在外部類的方法中定義一個類。
為什麼局部内部類通路局部變量需要用final修飾呢?
因為内部類在使用完畢後,可能在堆記憶體還存在呢,這個時候,它要的變量也要存在。
如果沒用final修飾,變量就會從棧中消失。
final修飾的内容在哪裡?
方法區裡面有一個常量區。它的生命周期你可以想象成和static一樣。
代碼示例:
class Outer
{
//private int num = 10;
public void method()
{
final int num = 20;
//局部位置
class Inner
{
public void show()
{
System.out.println("show "+num);
}
}
//建立對象
Inner in = new Inner();
in.show();
}
}
class InnerDemo4
{
public static void main(String[] args)
{
Outer o = new Outer();
o.method();
}
}
什麼時候使用匿名内部類呢?
通常在使用方法是接口類型參數,并該接口中的方法不超過三個時,可以将匿名内部類作為參數傳遞。
增強閱讀性。
匿名内部類的使用:
interface Inter
{
public abstract void hello();
public abstract void haha();
}
class Outer
{
private int num = 10;
public void method()
{
/*
class Inner//内部類形式
{
public void show()
{
System.out.println("num:"+num);
}
}
Inner in = new Inner();
in.show();
*/
/*
new Inter(){//匿名内部類
public void hello()
{
System.out.println("hello");
}
};
*/
//怎麼調用呢?
/*
new Inter(){//匿名内部類調用方法
public void hello()
{
System.out.println("hello");
}
}.hello();
*/
/*
new Inter(){
public void hello()
{
System.out.println("hello");
}
public void haha()
{
System.out.println("haha");
}
}.hello();
new Inter(){
public void hello()
{
System.out.println("hello");
}
public void haha()
{
System.out.println("haha");
}
}.haha();
*/
//假如隻是實作了接口的方法,那麼還可以這樣用
Inter in = new Inter(){
public void hello()
{
System.out.println("hello");
}
public void haha()
{
System.out.println("haha");
}
};
in.hello();
in.haha();
}
}
class NiMingInnerDemo
{
public static void main(String[] args)
{
Outer o = new Outer();
o.method();
}
}