面向對象編程
1. 什麼是面向對象
- 面向過程思想
- 步驟清晰簡單,第一部做什麼,第二部做什麼…
- 面向過程適合處理一些較爲簡單的問題
- 面向對象思想
- 物以類聚,分類的思維模式,思考問題首先會解決問題需要哪些分類,然後對這些分類進行單獨思考。最後,纔對某個分類下的細節進行面向過程的思索。
- 面向對象適合處理複雜的問題,適合處理需要多人協作的問題。
對於描述複雜的事物,爲了從宏觀上把握、從整體上合理分析,我們需要使用面向對象的思路去處理。
-
面向對象的本質:以類的方式組織代碼,以對象的組織(封裝)數據。
-
三大特性
- 封裝:
- 繼承
- 多態
2. 類與對象的創建
一個類由n個屬性和n個方法組成
創建與初始化對象
- 使用new關鍵字創建對象
- 使用new關鍵字創建的時候,除了分配內存空間之外,還會給創建好的對象進行默認的初始化以及對類中構造器的調用。
- 類中的構造器也稱爲構造方法(分爲無參構造和有參構造,且無參構造在沒有主動創建構造器時,默認存在),是進行創建對象的時候必須調用的。
- 構造器有以下特點:
- 必須和類的名字相同
- 必須沒有返回類型,也不能寫void
- 構造方法中不能用return返回值,但可以用return作爲方法的結束
構造器
- 和類名相同,權限修飾符一般只能是public
- 沒有返回值
作用:
- new 本質在調用構造方法
- 初始化對象的值
注意點:
- 如果沒有顯式定義任何構造方法,默認調用無參構造
- 定義有參構造之後,必須顯式地定義無參構造
實例代碼
public class Person{
//無參構造
private String name;
private int age;
public Person() {
System.out.println("這是無參構造!");
}
public Person(String name, int age) {
this.name = name;
this.age = age;
System.out.println("這是有參構造:"+name+"今年"+age+"歲了。");
}
}
class TestAre{
public static void main(String[] args) {
new Person();
new Person("阿凡",20);
}
}
3. oop小結
1.類與對象
類是一個模板:抽象 對象是一個具體的實例
2.方法
定義與調用
3.對象的引用
引用類型:對象通過引用來操作
4.屬性:也叫成員變量
默認初始值:
數字:0 0.0
char:u0000
boolean:false
引用:null
修飾符 屬性類型 屬性名 = 屬性值!
5.對象的創建和使用
必須使用new關鍵字創造對象,構造器
對象的屬性 person.name
對象的方法 person。sleep()
6.類:
靜態的屬性 屬性
動態的行爲 方法
- 封裝 繼承 多態 -
4. 封裝
-
該露的露,該藏的藏
- 我們程序要追求“ 高內聚,低耦合”。
- 高內聚就是類的內部數據操作細節自己完成,不允許外部干涉;
- 低耦合:僅暴露少量的方法給外部使用。
- 我們程序要追求“ 高內聚,低耦合”。
-
封裝
- 禁止直接訪問某一個對象中數據的實際表示,而應通過操作接口來訪問,這稱爲信息隱蔽。
-
總言:屬性私有,get/set
實例代碼
public class Person{
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) {
if(age <=120 && age >= 0){
this.age = age;
}else{
System.out.println("年齡不合實際");
}
}
}
class TestAre{
public static void main(String[] args) {
Person person = new Person();
person.setAge(30);
System.out.println(person.getAge());
}
}
5. 繼承
- 關鍵字extends,所有類默認繼承object類
- 繼承的本質是對某一批類的抽象,從而實現對現實世界更好的建模。
- java類中只有單繼承,沒有多繼承!即一個類只有一個直接父類
- 子類繼承父類,會自動擁有父類所有public,protected,默認修飾符修飾的屬性和方法(不能繼承或重寫父類的私有成員,構造器,靜態方法,final方法)。
實例代碼
public class Person {
private String name;
private char sex;
public void say(String name,char sex){
System.out.println("我叫"+name+",性別"+sex);
}
}
class Man extends Person{
public static void main(String[] args) {
Man man = new Man();
man.say("阿凡",'男');
}
}
6. this和super注意點
this用法:
形式參數可以被認爲是局部變量
- 用this關鍵字調用成員變量,防止與局部變量名稱衝突
- 用this關鍵字調用該類中其他成員方法(this可以省略)
- 用this([參數1,參數2,…])調用該類中的構造方法:
- 只能在構造方法中使用this調用其他構造方法,不能在成員方法中使用
- 在構造方法中使用this調用其他構造方法的語句只能寫在第一句
- 不能在一個類的兩個構造方法中使用this互調
super用法:
- 使用super來調用父類的成員變量和方法,構造方法
super.成員變量
super.成員方法
super([參數1,參數2,…])
- 通過super調用父類構造方法的語句只能出現在子類構造方法的第一行,並且只能出現一次
super VS this:
- 代表的對象不同:
- this:本身調用這個對象
- super:代表父類對象的應用
- 前提:
- this:沒有繼承也可以使用
- super:只能在繼承條件纔可以使用
- 構造方法
- this():本類的構造
- super():父類的構造
注意:
-
在構造方法中,this與super不能同時出現
-
static靜態方法中不能使用this和super
-
super可以調用父類的靜態方法
實例代碼
//person類
public class Person {
private String name = "person";
public void print(){
System.out.println("阿凡person");
}
}
//student類 繼承 person類
class Student extends Person{
private String name = "阿凡student";
public void test1(){
print(); //阿凡student
test(); //阿凡person
super.print(); //阿凡person
}
public void test(){
System.out.println(name); //阿凡student
super.print(); //阿凡person
}
public void print(){
System.out.println(this.name);
}
}
//測試類
class TestAre{
public static void main(String[] args) {
new Student().test();
new Student().test1();
}
}
7. 重寫
重寫:需要有繼承關係,子類重寫父類的方法!
- 方法名、參數列表、返回值類型必須相同
- 子類重寫父類方法時,不能使用比父類被重寫的方法更嚴格的訪問權限
修飾符訪問權限大小:public>protected>default>private
- 拋出的異常:範圍可以被縮小,但不能擴大:
classNotFoundException(小) -->Exception(大)
爲什麼需要重寫:
- 父類的功能,子類不一定需要,或者不一定滿足!
- Alt + Insert : @override
//person類
public class Person {
private String name = "阿凡公民";
public void print(){
System.out.println(name+"去上班!!");
}
}
//student類 繼承與 person類
class Student extends Person{
private String name = "阿凡同學";
@Override
public void print(){ //重寫print方法
System.out.println(name+"去上學!!");
}
}
class TestAre{
public static void main(String[] args) {
new Student().print(); //阿凡同學去上學!!
}
}
8. 多態
定義:不同類的對象在調用同一方法時所呈現出的多種不同行爲。
優點:提高了程序的可拓展性和可維護性。
-
多態一般在接口被實現或類被繼承時使用
-
對象的類型轉換:
- 父類引用子類對象時**(向上轉型),不能通過父類變量去調用子類特有方法**
- 將父類引用對象強制轉換爲子類時**(向下轉型)**,儘量用instanceof判斷一個對象是否是某個類(或接口)的實例或子類對象。
對象 instanceof 類(或接口)
instanceof 用來測試一個對象是否爲一個類的實例
boolean result = obj instanceof class
注意點:
1. obj必須爲引用類型,不能爲基本類型
2. obj可以爲null
3. obj可以爲class類的直接或間接子類
4. obj可以爲class接口的實現類
實例代碼
//Person類
public abstract class Person {
public abstract void work();
}
//老師類繼承Person類
class Teacher extends Person{
@Override
public void work() {
System.out.println("老師上課");
}
//老師特有方法
public void write(){
System.out.println("老師寫教案");
}
}
//醫生類繼承Person類
class Doctor extends Person{
@Override
public void work() {
System.out.println("醫生看病");
}
//醫生特有方法
public void operation(){
System.out.println("醫生做手術");
}
}
//測試類
class Test{
public static void main(String[] args) {
Person p1 = new Teacher();
Person p2 = new Doctor();
p1.work(); //老師上課
p2.work(); //醫生看病
if( p1 instanceof Teacher){ //判斷p1是否是Teacher類的對象
Teacher teacher = (Teacher)p1;
teacher.write(); //老師寫教案
}
else{
Doctor doctor = (Doctor)p2;
doctor.operation();
}
}
}
9. final關鍵字
final關鍵字可以修飾類、變量、方法:
-
final修飾的類不能被繼承
-
final修飾的方法不能被子類重寫
-
final修飾的變量(成員變量和局部變量)是常量,只能被賦值一次
注意:
成員變量被final修飾時,聲明變量的同時必須初始化賦值
局部變量被final修飾時,可以先聲明,再賦值一次
10. static關鍵字
static用於修飾類的屬性,方法,代碼塊等,稱爲靜態Xxx。
static只能修飾成員變量,不能修飾局部變量
注意點:
- 靜態變量(也叫全局變量)可以被該類的所有實例對象共享
類名.變量名
- 在同一類中,成員方法可以直接調用靜態方法,但是靜態方法不能直接調用成員方法,必須創建對象後才能訪問成員方法
類名.靜態方法();
或者
實例對象名.靜態方法();
- 靜態代碼塊在類第一次被new 對象 實例化後纔會被執行,且只會執行一次,一般用來加載初始化信息。
static{
…
}
**static和final同時使用 **
-
static final用來修飾成員變量和成員方法,可簡單理解爲“全局常量”!
-
對於變量,表示一旦給值就不可修改,並且通過類名可以訪問。
-
對於方法,表示不可覆蓋,並且可以通過類名直接訪問。
實例代碼
class Student{
private static int age;
private double score;
public static void main(String[] args) {
Student s1 = new Student();
System.out.println(Student.age);
System.out.println(s1.age);
System.out.println(s1.score);
}
}
靜態代碼塊
實例代碼
public class Person {
//賦初始值
{
System.out.println("匿名代碼塊");
}
//只執行一次
static{
System.out.println("靜態代碼塊");
}
public Person(){
System.out.println("構造方法");
}
public static void main(String[] args) {
new Person();
}
}
11. 抽象類
- 關鍵字:abstract 抽象類,屬於類 單繼承 (接口是多繼承)
- abstract修飾的抽象方法只有方法名字,沒有方法的實現!
- 注意點:
- 抽象類中的成員變量定義沒有要求
- 包含抽象方法的類必須定義爲抽象類
- 抽象類不能new出來,只能靠子類實現
- 抽象類中可以寫普通方法,包括靜態方法
- 抽象方法必須寫在抽象類中,但抽象類可以沒有抽象方法
12. 接口
接口:只有規範,比抽象類更嚴格,是抽象類的特殊形式
public interface 接口名{
}
作用
- 接口裏面定義的成員變量都是 public static final修飾,只能是常量,必須賦初始值。
- 接口中的成員方法只能是抽象方法。默認修飾符 public abstract,但public abstract可以省略不寫。
- 注意:接口不可以有構造方法,但抽象類可以
- 接口不能實例化,接口中沒有構造方法,其他類使用implements 可以實現多個接口,
- 必須要重寫接口中的所有方法
- 接口中的成員方法權限只能且都是public
- 接口是多繼承
實例代碼
public interface Animal {
void shout(String name);
}
class Cat implements Animal{
@Override
public void shout(String name) {
System.out.println(name + "在喵喵叫!");
}
}
class Dog implements Animal{
@Override
public void shout(String name) {
System.out.println(name+"在汪汪叫!");
}
}
class AnimalTest{
public static void main(String[] args) {
Animal a1 = new Cat();
Animal a2 = new Dog();
a1.shout("貓");
a2.shout("狗");
}
}
13. 4種內部類
非常重要:內部類不能有靜態方法或屬性。
成員內部類
外部類名 對象名 = new 外部類名();
外部類名.內部類名 變量名 = new 外部類名().內部類名();
注意:
- 在成員內部類中,內部類可以直接(不用new 外部類創建對象)調用外部類的所有屬性+方法(包括靜態和非靜態)。
- 在外部類中,不可以直接調用內部類中的屬性+方法,但可以創建內部類對象後調用。
實例代碼
//person類 外部類
public class Person {
String name = "Afan";
int age = 20;
public void doSomething(){
System.out.println("AFan在喫飯!");
}
public void say(){
Heart heart = new Heart();
heart.fleed();
System.out.println("AFan說你好!");
}
//心臟 成員內部類
class Heart{
public void jump(){
System.out.println("心臟跳動!!");
doSomething();//直接調用外部類方法
say();
}
public void fleed(){
System.out.println("血在流");
}
}
}
class Test{
public static void main(String[] args) {
Person person = new Person();
Person.Heart heart = person.new Heart();
heart.jump();
heart.fleed();
}
}
局部內部類
也叫方法內部類,在方法中定義,有效範圍只限於方法內部,等同於局部變量。
注意:
- 局部內部類可以在new 外部類對象後調用外部類的屬性+方法
- 局部內部類可以 直接調用 自身在外部類中所在方法裏的局部變量。
- 只有在創建局部內部類的方法中才可以創建局部內部類的對象,並調用內部類的所有屬性+方法。
實例代碼
/person類
public class Person {
String name = "Afan";
int age = 20;
public void doSomething(){
System.out.println("AFan在喫飯!");
}
public void say(){
System.out.println("AFan說你好!");
}
public void produce(){
String product_name = "電腦";
//產品類 局部內部類
class Production{
// String product_name = "電腦";
public void use(){
Person person = new Person(); //外部類對象
person.doSomething();
System.out.println(product_name+"的使用");
}
}
Production production = new Production();
production.use();
}
}
class Test{
public static void main(String[] args) {
Person person = new Person();
person.produce();
}
}
靜態內部類
本質:使用static關鍵字修飾的成員內部類
- 靜態內部類只能直接調用外部類中的靜態屬性和靜態方法
- 其他類需要調用靜態內部類的屬性和方法時,可以跳過外部類,直接new 內部類對象來訪問其成員。
外部類名.靜態內部類名 對象名 = new 外部類名.靜態內部類名();
實例代碼
//person類
public class Person {
static String name = "Afan";
public static void doSomething(){
System.out.println("AFan在喫飯!");
}
public void say(){
System.out.println("AFan說你好!");
}
//心臟類 就在成員內部類前面加個static
static class Heart{
public void jump(){
doSomething();
// Person person = new Person(); 訪問非靜態成員必須創建對象。
//person.say();
System.out.println(name+"的心臟在跳動!!");
}
}
}
class Test{
public static void main(String[] args) {
Person.Heart heart = new Person.Heart();
heart.jump();
}
}
匿名內部類
java類調用某個方法時,如果該方法的參數類型是接口類型,那麼除了傳遞一個接口的實現類,也可以使用匿名內部類實現該接口來作爲該方法的參數。(開發中常用)
[修飾符] 方法名(new 父類名或者接口名(){
// 方法重寫
@Override
public void method() {
// 執行語句
}
};)
實例代碼
//接口類
public interface Animal {
void shout(String name);
}
class AnimalTest{
String name;
public void animalShout(Animal animal){
animal.shout(name);
}
public static void main(String[] args) {
AnimalTest a1 = new AnimalTest();
a1.name = "貓";
//匿名內部類
a1.animalShout(new Animal() {
@Override
public void shout(String name) {
System.out.println(name+"在叫!!!");
}
});
}
}
JDK8的Lamabda表達式
使用條件:只適用於在匿名內部類中只有一個抽象方法的接口實現,簡化代碼。
([數據類型1 變量名1,數據類型2 變量名2,…]) ->{表達式主體}
注意點:
- 參數列表只有一個參數時可以省略”()“和變量的數據類型
- 表達式主體只有一條語句時,可以省略主體的大括號
- 表達式主體可以有return返回值,當只有一條return語句,可以省略return
實例代碼
//接口類
public interface Animal {
void shout(String name);
}
class AnimalTest{
String name;
public void animalShout(Animal animal){
animal.shout(name);
}
public static void main(String[] args) {
AnimalTest a1 = new AnimalTest();
a1.name = "小貓";
//Lamabda表達式
a1.animalShout(name ->
System.out.println(name+"在叫!!!")
);
}
}
進一步簡化Lamabda表達式(瞭解)
使用條件:Lamabda表達式主體只有一條語句
用法:程序省略主體的大括號,用英文雙冒號“::”來引用方法和構造器
Lamabda表達式對普通方法和構造方法的引用形式
種類 | 對應的引用示例 |
---|---|
類名引用普通方法 | 類名::類普通方法名 |
類名引用靜態方法 | 類名::類靜態方法名 |
對象名引用方法 | 對象名::實例方法名 |
構造器引用 | 類名::new |
14. 異常
定義:程序在編譯、運行過程中出現的非正常狀況
java的異常類都繼承於java.lang.Throwable類
Throwable的繼承體系
- Error類:錯誤類,比較嚴重(瞭解)
- Exception類:異常類,程序本身可以處理,java開發中進行的異常處理都是針對Exception類及其子類
Throwable類常用方法
方法說明 | 功能描述 |
---|---|
String getMessage() | 返回此throwable的詳細消息字符串 |
void printStackTrace() | 打印完整的異常信息 |
處理異常的兩種方式:
-
使用try…catch語句對異常進行捕獲處理
try{ //可能發生異常的語句 }catch(Exception類或其子類 e){ e.printStackTrace(); //打印輸出異常原因 //對捕獲的異常做相應處理 }finally{ //無論程序是否異常都必須執行的語句 }
實例代碼
public class Example { public static void main(String[] args) { int result = divide(4,0); if(result == -1){ System.out.println("程序出現異常");} else{ System.out.println(result); } } //運行結果:出現的異常:/ by zero // 無論程序是否異常都必須執行的finally語句 // 程序出現異常 //除法運算 public static int divide(int a,int b){ try{ int result = a/b; return result; }catch(Exception e){ System.out.println("出現的異常:"+e.getMessage()); }finally{ System.out.println("無論程序是否異常都必須執行的finally語句"); } return -1; //如果程序異常,返回-1 } }
-
使用throws拋出異常,等以後再處理有可能的異常,
[修飾符] 返回值類型 方法名([參數列表]) throws Exception{ //方法體 }
有可能出現異常的方法加上throws關鍵字後,其他類調用它時首先要處理完異常之後才能使用該方法。
實例代碼
public class Example {
public static void main(String[] args) {
try {
int result = divide(4, 0);
System.out.println(result);
}catch(Exception e){
System.out.println("出現異常:"+e.getMessage());
}
}
//運行結果:出現異常:/ by zero
//除法運算
public static int divide(int a,int b) throws Exception{
int result = a/b;
return result;
}
}