來杯JAVA冷靜一下_05面向?qū)ο骭06異常_230809
# 來杯JAVA冷靜一下_05面向?qū)ο骭06異常_230809











面向?qū)ο?br>
### 1.初識(shí)面向?qū)ο?/p>
#### 面向過程思想
步驟清晰簡單,第一步做什么,第二步做什么…
面對(duì)過程適合處理一些較為簡單的問題。
#### 面向?qū)ο笏枷?/p>
物以類聚,分類的思維模式,思考問題首先會(huì)解決問題需要哪些分類,然后對(duì)這些分類進(jìn)行單獨(dú)思考。最后,才對(duì)某個(gè)分類下的細(xì)節(jié)進(jìn)行面向過程的思索。
面向?qū)ο筮m合處理復(fù)雜的問題,適合處理需要多人協(xié)作的問題!
對(duì)于描述復(fù)雜的事物,為了從宏觀上把握、從整體上合理分析,我們需要使用面向?qū)ο蟮乃悸穪矸治稣麄€(gè)系統(tǒng)。但是,具體到微觀操作,仍然需要面向過程的思路去處理。
面向?qū)ο缶幊蹋?Object- Oriented Programming,OOP)
### 面向?qū)ο缶幊痰谋举|(zhì)就是:
### -以類的方式組織代碼,
### -以對(duì)象的組織(封裝)數(shù)據(jù)。
#### 三大特征:
##### 繼承
##### 封裝
##### 多態(tài)
- 從認(rèn)識(shí)論角度考慮是先有對(duì)象后有類。對(duì)象,是具體的事物。
- 類,是抽象的,是對(duì)對(duì)象的抽象。
- 從代碼運(yùn)行角度考慮是先有類后有對(duì)象。類是對(duì)象的模板。
-?
### 2.方法回顧和加深 屬性+方法=類
對(duì)于描述復(fù)雜的事物,為了從宏觀上把握、從整體上合理分析,我們需要使用面向?qū)ο髞矸治稣麄€(gè)系統(tǒng)。但是,具體到微觀操作,讓然需要面向過程的思路去處理。
面向?qū)ο蟊举|(zhì)就是:以類的方式組織代碼,以對(duì)象的組織(封裝)數(shù)據(jù)。
從認(rèn)識(shí)論角度考慮是先有對(duì)象后有類
三大特性:封裝,繼承,多態(tài)。抽象
回顧方法的定義以及調(diào)用
定義
main方法
#### 1 方法的定義
1. 修飾符? ?public 公共類 private 私有類
2. 返回值類型
break:跳出 switch,結(jié)束循環(huán)和 return的區(qū)別。
3. 方法名:注意規(guī)范就OK,見名知意
參數(shù)列表:(參數(shù)類型,參數(shù)名) …
異常拋出:疑問,參考下文!
```java
//main方法
public static void main(String[] args){}
/*
修飾符 返回值類型 方法名(...){
//方法體
return 返回值;
}
*/
public String sayHello(){
? ? return "hello world";
}
public void print(){
? ? return;
}
public int max(int a,int b){
? ? return a>b ?a:b;
}
```
break:跳出switch循環(huán),結(jié)束循環(huán)。continue:結(jié)束依次循環(huán)。return:方法結(jié)束,返回類型和返回值相同。
```java
public class Demo01 {
? ? // main方法
? ? public static void main(String[] args) {
? ? }
? ? /*
? ? 修飾符 返回值類型 方法名(...){
? ? ? ? // 方法體
? ? ? ? return 返回值;
? ? }
? ? ?*/
? ? public String sayHello(){
? ? ? ? return "hello,world!";
? ? }
? ? public int max(int a,int b){
? ? ? ? return a>b ? a : b; // 三元運(yùn)算符
? ? }
? ? // 數(shù)組下標(biāo)越界:Arrayindexoutofbounds
? ? public void readFile(String file) throws IOException{
? ? }
}
```
### 3 方法的調(diào)用
#### 1 靜態(tài)方法?
? public static void a(){
b}//和類一起加載的
```java
public class Demo01 {
? ? public static void main(String[] args) {
? ? ? ? Student.main();
? ? }
}
//==============另一個(gè)文件?
//1 靜態(tài)方法?
public class Student {
? ? public static void main() {
? ? ? ? System.out.println("學(xué)生說話。。。");
? ? }
}
```
#### 2 非靜態(tài)方法?
public void b() {
}
//類實(shí)例化之后才存在??
```java
public class Student {
? ? public void main() {//去掉static
? ? ? ? System.out.println("學(xué)生hh說話。。。");
? ? }
}
//=======================
public class Demo01 {
? ? public static void main(String[] args) {
? ? ? ? //? Student.main();?
? ? ? ? //? 去掉static后 無法直接通過類名調(diào)用方法名
? ? ? ? //只能通過實(shí)例化
? ? ? ? Student studnet = new Student();
? ? ? ? studnet.main();
? ? }
}
```
#### 3 形參和實(shí)參
```java
public static void say(){
? ? system.out.print("1111");
}//可直接通過方法名調(diào)用,和類一起加載。
非靜態(tài)方法
public void say(){
? ? System.out.print("1111");
}
//調(diào)用
Student student = new Student();//實(shí)例化這個(gè)類new,對(duì)象類型 對(duì)象名=對(duì)象值;
student.say();
形參
public static int add(int a,int b){//int a,int b,形參
return a+b;? ??
}
實(shí)參
public static void main(String[] args){
? ? int add = Demo03.add(1,3);//1,3:實(shí)參
? ? System.out.println(add);
}
```
#### 4? java 都是值傳遞
一句話:對(duì)于**基本數(shù)據(jù)類型**來說,給形參傳遞的是實(shí)參值的副本,而對(duì)于引用數(shù)據(jù)類型來說,傳遞的則是地址的副本。但由于地址的副本和原來的相似,因此傳遞過去后的形參也指向同一個(gè)內(nèi)存空間中。
就是復(fù)制了一份給形參,自身不變
形參的有效范圍只在當(dāng)前方法內(nèi),輸出的值跟下面的a完全沒有任何關(guān)系
```java
//值傳遞
public class Demo04{
? ?public static void main(String[] args){
? ? ? ?int a=1;
? ? ? ?System.out.println(a);
? ? ? ?
? ? ? ?Demo04.change(a); //返回值為空? 運(yùn)行完,啥也沒有?
? ? ? ?System.out.println(a);
? ?}
? ??
? ? //返回值為空? 運(yùn)行完,啥也沒有?
? ? public static void change(int a){//a傳進(jìn)去1?
? ? ? ? a=10;//a= 1 ,將10 賦值給a,a=10;
? ? }
}
a=10,返回值為空,a的值還為1。
```
#### 5 引用傳遞
```java
//引用傳遞:對(duì)象,本質(zhì)還是值傳遞
public class Demo05{
? ? public static void main(String[] args){
? ? ? ? Person person = new Person();
? ? ? ??
? ? ? ? System.out.println(person.name);//null
? ? ? ??
? ? ? ? Demo05.change(person);
? ? ? ??
? ? ? ? System.out.println(person,name);//test
? ? }
? ? public static void change(Person person){
? ? ? ? //person是一個(gè)對(duì)象:指向的--->Person person=new Person();這是一個(gè)具體的人,可以改變屬性
? ? ? ? person.name = "test";
? ? };
}
//定義了一個(gè)Person類,有一個(gè)屬性:name
class Person{
? ? String name;//null
}
```
- 基本類型作為參數(shù)傳遞時(shí),是傳遞值的拷貝,無論你怎么改變這個(gè)拷貝,原值是不會(huì)改變的
- 對(duì)象作為參數(shù)傳遞時(shí),是對(duì)象在內(nèi)存中的地址拷貝一份給了參數(shù)
類和對(duì)象的關(guān)系
類是一種抽向的數(shù)據(jù)類型,它是對(duì)某一類事物整體描述/定義,但是并不能代表某一個(gè)具體的事物
對(duì)象是抽象概念的具體實(shí)例
#### 6 this關(guān)鍵字
#### 學(xué)程序好? 對(duì)世界進(jìn)行更好的建模?
### 4 類和對(duì)象的創(chuàng)建?
對(duì)象的創(chuàng)建分析
類是一種抽象的數(shù)據(jù)類型它是對(duì)某一類事物整體描述/定義但是并不能代表某一個(gè)具體的事物。
使用new關(guān)鍵字創(chuàng)建對(duì)象。
使用new關(guān)鍵字創(chuàng)建的時(shí)候,除了分配內(nèi)存空間之外,還會(huì)給刨建好的對(duì)象進(jìn)行默認(rèn)的初始化以及對(duì)類中構(gòu)造器的調(diào)用。
#### 創(chuàng)建和初始化對(duì)象
使用new關(guān)鍵字創(chuàng)建的時(shí)候,除了分配內(nèi)存空間之外,還會(huì)給創(chuàng)建好的對(duì)象進(jìn)行默認(rèn)的初始化以及類中構(gòu)造器的使用
1595485938430
一個(gè)類即使什么都不寫,它也會(huì)存在一個(gè)方法
```java
//學(xué)生類 以類的方式組織代碼?
public class Student {
//1 屬性 :字段? 不賦值 。
? ? String name;
? ? int age;
//2 方法?
? ? public void study() {
? ? ? ? System.out.println(
? ? ? ? ? ? ? ? this.name + "在學(xué)習(xí)"
? ? ? ? );
? ? }
}
```
```java
package com.zhangyy.opp;
//引用傳遞:對(duì)象,本質(zhì)還是值傳遞
public class Demo05 {
? ? public static void main(String[] args) {
? ? ? ? //類:抽象的 示例化
? ? ? ? //類:抽象的,實(shí)例化
? ? ? ? // 類實(shí)例化后會(huì)返回一個(gè)自己的對(duì)象!
? ? ? ? // student對(duì)象就是一個(gè)student類的具體實(shí)例!
Student xiaoming=new Student();
Student xh =new Student();
xiaoming.name = "小明";
? ? ? ? xiaoming.age=23;
? ? ? ? System.out.println(xiaoming.name);
? ? ? ? System.out.println(xiaoming.age);
? ? ? ? System.out.println(xh.name);
? ? ? ? System.out.println(xh.age);
? ? }
? ? ;
}
/*
小明
23
null
0
*/
```
```java
//引用傳遞:對(duì)象,本質(zhì)還是值傳遞
public class Demo05 {
? ? public static void main(String[] args) {
? ? ? ? //類:抽象的 示例化
? ? ? ? //類:抽象的,實(shí)例化
? ? ? ? // 類實(shí)例化后會(huì)返回一個(gè)自己的對(duì)象!
? ? ? ? // student對(duì)象就是一個(gè)student類的具體實(shí)例!
Student xiaoming=new Student();
Student xh =new Student();
xiaoming.name = "小明";
? ? ? ? xiaoming.age=18;
? ? ? ? System.out.println(xiaoming.name);
? ? ? ? System.out.println(xiaoming.age);
? ? ? ? System.out.println(xh.name);
? ? ? ? System.out.println(xh.age);
? ? }
? ? ;
}
```
### 5 構(gòu)造器
#### 構(gòu)造器:
```java
//Person.class
public class Person {
}
```
#### Person.class默認(rèn)無參構(gòu)造方法
```java
//Person.class默認(rèn) 無參構(gòu)造 方法
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package com.zhangyy.opp;
public class Person {
? ? public Person() {
? ? }
}
```
#### 類中的構(gòu)造器也稱為構(gòu)造方法,是在進(jìn)行創(chuàng)建對(duì)象的時(shí)候必須要調(diào)用的。
#### 并且構(gòu)造器有以下倆個(gè)特點(diǎn):
//一個(gè)類即使什么都不寫,它也會(huì)存在一個(gè)方法
//顯示的定義構(gòu)造器
##### 1.必須和類的名字相同;
##### 2.必須沒有返回類型也不能寫void。
#### 構(gòu)造器: Command + N 方法的重載
快捷鍵 Command + N 打開Generate 操作菜單; 選擇Constructor,然后根據(jù)需要選擇相應(yīng)的構(gòu)造函數(shù)參數(shù); 點(diǎn)擊OK,即可生成相應(yīng)的構(gòu)造函數(shù)。
##### 1.和類名相同
##### 2.沒有返回值類型,也不能寫void
#### 作用:
##### 1.new本質(zhì)在調(diào)用構(gòu)造方法,默認(rèn)無參構(gòu)造方法;
##### 2.初始化對(duì)象的值。
#### 有參構(gòu)造與無參構(gòu)造
#### 注意:定義有參構(gòu)造之后,如果想使用無參構(gòu)造,顯示的定義一個(gè)無參構(gòu)造。
構(gòu)造器是無參構(gòu)造,方法也可以無參構(gòu)造
顯示定義無藏構(gòu)造:
//定義有參構(gòu)造器后,就會(huì)把系統(tǒng)默認(rèn)的無參構(gòu)造器給覆蓋掉了。如果想使用無參構(gòu)造器,那就得自己寫出來,即顯示的定義無參構(gòu)造器。
定義有參構(gòu)造器,它會(huì)覆蓋無參構(gòu)造器,如果你想要它還存在,那么就自己定義出來。
方法重載:有參無參都寫上,有參數(shù)就走有參,無參數(shù)就走無參,出來的是定義 的值

```java
public class Person {
? ? String name;
//? ? public Person(){
//
//? ? ? ? this.name="雪之下雪乃";
//? ? }
? ? public? Person( String name){
? ? ? ? this.name = name;
? ? }
}
```
```java
public class Demo01 {
? ? public static void main(String[] args) {
Person person? ?= new Person("雪之下");
? ? ? ? System.out.println(person.name);
? ? }
}
//雪之下
```
#### A 未使用構(gòu)造器?
```java
public class Person {
? ? String name;
}
```
```java
public class Demo01 {
? ? public static void main(String[] args) {
Person person? ?= new Person();
? ? ? ? System.out.println(person.name);
? ? }
}
//null
```
#### B 使用構(gòu)造器?
//一個(gè)類即使什么都不寫,它也會(huì)存在一個(gè)方法
//顯示的定義構(gòu)造器
//實(shí)例化初始值
//1。使new關(guān)鍵字,本質(zhì)是在調(diào)用構(gòu)造器
```java
public class Person {
? ? String name;
? ? public Person(){
? ? ? ? this.name="雪之下雪乃";
? ? }
```
```java
public class Demo01 {
? ? public static void main(String[] args) {
Person person? ?= new Person();
? ? ? ? System.out.println(person.name);
? ? }
}
//雪之下雪乃
```

### 6 內(nèi)存分析


沒有static時(shí),b調(diào)用的是對(duì)象的方法,而b是用A類new的,即b是A new出來的對(duì)象,因此調(diào)用了A的方法
### 7 小結(jié)類與對(duì)象
#### 1.類與對(duì)象
###### ?類是一個(gè)模板:抽象,對(duì)象是一個(gè)具體的實(shí)例
#### 2.方法
###### ?定義,通用
#### 3.對(duì)應(yīng)的引用
###### ?引用類型:基本類型(8)
###### ?對(duì)象是通過引用來操作的:棧--->堆(地址)
#### 4.屬性:字段Field? ? 成員變量
###### ?默認(rèn)初始化:
###### ?數(shù)字:0? ? 0.0
###### ?char:u0000
###### ?boolean:false
###### ?引用類型(String等):null
###### ?修飾符 屬性類型 屬性名=屬性值;
(方法省略 不要死循環(huán))
#### 5.對(duì)象的創(chuàng)建和使用
- 必須使用new關(guān)鍵字創(chuàng)建對(duì)象, 構(gòu)造器Person xiaoming=new Perosn();
- 對(duì)象的屬性 xiaoming.name
- 對(duì)象的方法 xiaoming.sleep()
#### 6.類
###### ?靜態(tài)的屬性 屬性
###### ?動(dòng)態(tài)的行為 方法
***
***
***
> # 面向?qū)ο笕筇匦裕悍庋b 繼承 多態(tài)
### 8 封裝 屬性私有,get/set 高內(nèi)聚低耦合
**主要是針對(duì)類的屬性進(jìn)行封裝**
該露的露,該藏的藏 類比ATM機(jī)
我們程序設(shè)計(jì)要追求**”高內(nèi)聚,低耦合“**。高內(nèi)聚就是類的內(nèi)部數(shù)據(jù)細(xì)節(jié)由自己完成,不允許外部干涉;低耦合:僅暴露少量的方法給外部使用。
#### 封裝(數(shù)據(jù)的隱藏)
通常,應(yīng)禁止直接訪問一個(gè)對(duì)象中數(shù)據(jù)的實(shí)際表示,而應(yīng)該通過操作接口來訪問,稱為信息隱藏。
#### 屬性私有,get/set
快捷鍵 Command + N = Mac中對(duì)應(yīng)的是:control+enter
可以在get方法里面對(duì)傳入的數(shù)據(jù)做合法性判斷
這就相當(dāng)于銀行取錢,我能看見余額,但不能修改余額
因?yàn)槟闶莗rivate的所以要設(shè)置getter和setter, 如果不需要更改就不用設(shè)置, public安全程度低
示例1:
```java
public class Person {
? ?private String name;
? ? public String getName() {
? ? ? ? return name;
? ? }
? ? public void setName(String name) {
? ? ? ? this.name = name;
? ? }
? ? public Person() {
? ? }
? ? public Person(String name) {
? ? ? ? this.name = name;
? ? }
}
```
示例2:
```java
public class Student{
//名字
private String name;
//學(xué)號(hào)
private int id;
//性別
private char sex;
//年齡
private int age;
public int getAge(){
? ? if(age>120 || age<0){
? ? ? ? this.age=3;
? ? }else{
? ? ? ? this.age=age;
? ? }
? ? return age;
}
public void setAge(int age){
? ? this.age=age;
}
public String getName(){
? ? this.name=name;
}
public void setName(String name){
? ? this.name=name;
}
public int getId(){
? ? return id;
}
public void setId(int id){
? ? this.id=id;
}
public char getSex(){
? ? return sex;
}
public void setSex(char sex){
? ? this.sex=sex;
}
}
//==========
public class a{
{
? ? psvm{
Students s1=new Students();? ? ? ??
s1.setAge(1200);? ? ? ??
System.out.println(s1.getAge());}
? ? }
}
```
#### 作用
###### 1. 提高程序的安全性,保護(hù)數(shù)據(jù)?
###### 2. 隱藏代碼的實(shí)現(xiàn)細(xì)節(jié)
###### 3. 統(tǒng)一接口
###### 4. 系統(tǒng)可維護(hù)性增加了
### 9 繼承
#### 類 = 屬性 + 方法?
但是 鳥類 魚類 蟲類 猴類。。。
類太多了 也要進(jìn)行抽象
1. 繼承的本質(zhì)是對(duì)某一批類的抽象,從而實(shí)現(xiàn)對(duì)世界更好的建模
2. extends的意思是“擴(kuò)展”。子類是父類的擴(kuò)展,使用extends來表示
3. Java中只有單繼承,沒有多繼承!一個(gè)類只能繼承一個(gè)父類
4. 繼承是類與類之間的一種關(guān)系,此外還有依賴、組合、聚合等
5. 繼承關(guān)系的兩個(gè)類,一個(gè)是子類(派生類),一個(gè)是父類(基類)子類繼承父類
6. 子類繼承了父類,就會(huì)擁有父類的全部方法,而private私有屬性及方法無法繼承
7. 在Java中,所有類,都默認(rèn)直接或間接繼承Object類(Ctrl+H可以查看類關(guān)系)
8. 被final修飾的類,無法繼承(斷子絕孫)
### 10 super&this
#### super注意點(diǎn):
###### ?1.super調(diào)用父類的構(gòu)造方法,必須在構(gòu)造方法的第一個(gè)(默認(rèn)調(diào)用)
###### ?2.super必須只能出現(xiàn)在子類的方法或者構(gòu)造方法中
###### ?3.super和this不能同時(shí)調(diào)用構(gòu)造方法
#### VS this
###### 代表的對(duì)象不同:
###### this:本身調(diào)用者這個(gè)對(duì)象
###### super:代表父類對(duì)象的應(yīng)用
###### 前提
###### this:沒有繼承也可以使用
###### super:只能在繼承條件下可以使用
###### 構(gòu)造方法
###### this():本類的構(gòu)造
###### super():父類的構(gòu)造
super與this的區(qū)別:super代表父類對(duì)象的引用,只能在繼承條件下使用;this調(diào)用自身對(duì)象,沒有繼承也可以使用
super(); //隱藏代碼,默認(rèn)調(diào)用了父類的無參構(gòu)造,要寫只能寫第一行

###? 11 方法的重寫
#### 重寫:需要有繼承關(guān)系,子類重寫父類的方法!方法名必須相同
#### 參數(shù)列表必須相同
#### 修飾符可以擴(kuò)大但是不可以縮小
#### public>protected>default>private
#### 拋出的異常:范圍,可以被縮小,但是不能擴(kuò)大:ClassNotFoundException-->Exception(大)
#### 重寫是方法的重寫,與屬性無關(guān)
#### 重寫方法只與非靜態(tài)方法有關(guān),與靜態(tài)方法無關(guān)(靜態(tài)方法不能被重寫)
#### 被static(屬于類,不屬于實(shí)例),final(常量方法),private(私有)修飾的方法不能重寫


```java
public class B{
? ? public static void test(){靜態(tài)方法
? ? ? ? System.out.println("B==>test()")
? ? }
}
public class A extends B{//繼承
? ? public static void test(){
? ? ? ? System.out.println("A==>test()")
? ? }
}
public class Application(){
? ? public static void main(String[] args){
? ? ? ? //方法的調(diào)用只和左邊的定義的類型有關(guān)
? ? ? ? A a = new A();
? ? ? ? a.test();//打印A==>test()
? ? ? ??
? ? ? ? //父類的引用指向了子類,但靜態(tài)方法沒有被重寫
? ? ? ? B b = new A();
? ? ? ? b.test();//打印B==>test()
? ? }
}
修改A.Java,B.java
public class B{
? ? public void test(){//非靜態(tài)方法
? ? ? ? System.out.println("B==>test()");
? ? }
}
public class A extends B{
? ? @Override //重寫了B的方法
? ? public void test(){
? ? ? ? System.out.println("A==>test()");
? ? }
}
//父類的引用指向了子類
B b = new A();
//子類重寫了父類的方法,執(zhí)行子類的方法
b.test();//打印變成了A==>test()
/*
靜態(tài)方法是類的方法,非靜態(tài)方法是對(duì)象的方法。有static時(shí),b調(diào)用了B類的方法,因?yàn)閎是B類定義的。沒有static時(shí),b調(diào)用的是對(duì)象的方法,而b是A類new出來的對(duì)象,調(diào)用A的方法
*/
```
重寫:子類的方法名必須和父類保持一致,方法體不同
被static(屬于類,不屬于實(shí)例),final(常量方法),private(私有)修飾的方法不能重寫
#### 為什么重寫:
父類的功能,子類不一定需要,或者不一定滿足
Alt + Insert ; override;
### 12 多態(tài)
即同一方法可以根據(jù)發(fā)送對(duì)象的不同而采用不同的行為方式
一個(gè)對(duì)象的實(shí)際類型是確定的,但可以指向?qū)ο蟮囊每梢杂泻芏?/p>
#### 多態(tài)存在條件
有繼承關(guān)系
子類重寫父類的方法
父類引用指向子類對(duì)象
#### 注意點(diǎn)
多態(tài)是方法的多態(tài),沒有屬性的多態(tài)
父類和子類,有聯(lián)系 類型轉(zhuǎn)換溢出:ClassCastException
存在條件:繼承關(guān)系,方法需要重寫,父類引用指向了子類對(duì)象
instanceof和類型轉(zhuǎn)換
instanceof引用類型比較,判斷一個(gè)對(duì)象是什么類型
```java
private static int age;
private double score;
public void run(){ }
public static void go(){ }
public static void main(String[] args){
? ? Student s1 = new Student();
? ? System.out.println(Student.age);
? ? System.out.println(Student.score);
? ? System.out.println(s1.ahe);
? ? System.out.println(s1.score);
? ? go();
? ? run();
}
```
#### 多態(tài)的內(nèi)存分析

#### -編譯看左 運(yùn)行看右? 調(diào),但具體調(diào)子類的方法 父.方法();//輸出son。
編譯看左,運(yùn)行看右” 是指在面向?qū)ο缶幊讨?,Java編譯器在編譯時(shí)會(huì)根據(jù)引用變量的類型(左邊)來確定可以調(diào)用哪些方法和屬性,
而在運(yùn)行時(shí)則會(huì)根據(jù)實(shí)際對(duì)象的類型(右邊)來決定執(zhí)行哪個(gè)方法。這涉及到多態(tài)性的概念。
讓我用一個(gè)例子來解釋這個(gè)概念:
假設(shè)有一個(gè)類 Animal 和一個(gè)繼承自 Animal 的類 Dog:
```java
class Animal {
? ? public void makeSound() {
? ? ? ? System.out.println("動(dòng)物發(fā)出聲音");
? ? }
}
class Dog extends Animal {
? ? public void makeSound() {
? ? ? ? System.out.println("汪汪汪!");
? ? }
}
```
```java
Animal myAnimal = new Dog();
myAnimal.makeSound();? // 輸出:"汪汪汪!"
```
**在這里,myAnimal 是一個(gè) Animal 類型的引用,但是它實(shí)際指向了 Dog 類的一個(gè)實(shí)例。**
在編譯時(shí),編譯器看到 myAnimal 是 Animal 類型,所以它知道可以調(diào)用 makeSound 方法。
但是在運(yùn)行時(shí),因?yàn)?myAnimal 實(shí)際上指向 Dog 類的實(shí)例,所以**會(huì)調(diào)用 Dog 類的 makeSound 方法**,從而輸出 "汪汪汪!"。
這就是“編譯看左,運(yùn)行看右”這個(gè)概念的含義。在編譯時(shí),編譯器會(huì)根據(jù)左邊的類型來確定可用的方法和屬性,但在運(yùn)行時(shí),實(shí)際上會(huì)根據(jù)右邊的實(shí)際對(duì)象來執(zhí)行相應(yīng)的方法。

### 13 instanceof (類型轉(zhuǎn)換)引用類型
1. 能否編譯通過,看類是否有關(guān)系,x與y的類(實(shí)際x,y本身就是類)?
2. 若存在父子或子父關(guān)系責(zé)可編譯
3. 編譯過后T/F 看引用指向?qū)ο? 引用變量名x指向的對(duì)象 如果是后面y的子類的實(shí)例化,即是T。
說到底,就是比較左邊的物件? 右邊的大容器能不能裝得下
instanceof 是 Java 中的一個(gè)關(guān)鍵字,用于檢查一個(gè)對(duì)象是否是某個(gè)類的**實(shí)例,或者是否實(shí)現(xiàn)了某個(gè)接口**。它返回一個(gè)布爾值,如果對(duì)象是指定類或接口的實(shí)例,則返回 true,否則返回 false。
instanceof 主要用于實(shí)現(xiàn)多態(tài)性中的類型檢查,讓我們來看一個(gè)例子:
```java
class Animal {
}
class Dog extends Animal {
}
class Cat extends Animal {
}
```
##### 使用 instanceof 來檢查一個(gè)對(duì)象是否是某個(gè)類的實(shí)例:
```java
Animal animal = new Dog();
if (animal instanceof Dog) {
? ? System.out.println("這是一只狗!");
} else if (animal instanceof Cat) {
? ? System.out.println("這是一只貓!");
} else {
? ? System.out.println("這是一只動(dòng)物!");
}
```
在這個(gè)例子中,animal 是一個(gè) Animal 類型的引用,但它實(shí)際指向了 Dog 類的一個(gè)實(shí)例。通過使用 instanceof,我們可以判斷實(shí)際對(duì)象的類型,然后輸出相應(yīng)的信息。
#### instanceof 關(guān)鍵字主要作用和意義:
1. 類型檢查和多態(tài)性: 一個(gè)程序中可能會(huì)有許多不同的類和對(duì)象,而這些類可能存在繼承關(guān)系。通過使用 instanceof,可以在運(yùn)行時(shí)確定對(duì)象的實(shí)際類型,從而進(jìn)行相應(yīng)的操作。這在實(shí)現(xiàn)多態(tài)性時(shí)非常有用,讓不同的對(duì)象以一種統(tǒng)一的方式被處理。
2. 避免類型轉(zhuǎn)換錯(cuò)誤: 在使用繼承和多態(tài)性的情況下,如果嘗試將一個(gè)對(duì)象轉(zhuǎn)換為錯(cuò)誤的類型,會(huì)導(dǎo)致運(yùn)行時(shí)的異常。使用 instanceof 可以在進(jìn)行類型轉(zhuǎn)換之前先檢查對(duì)象的類型,從而避免此類錯(cuò)誤。
3. 動(dòng)態(tài)適應(yīng)性: instanceof 允許程序在運(yùn)行時(shí)根據(jù)對(duì)象的實(shí)際類型做出決策。這種動(dòng)態(tài)適應(yīng)性使得程序可以根據(jù)不同情況做出不同的處理,從而提高了代碼的靈活性和可維護(hù)性。
4. 接口和抽象類判斷: 除了用于類的判斷外,instanceof 也可以用于判斷一個(gè)對(duì)象是否實(shí)現(xiàn)了某個(gè)接口或是抽象類的子類。
5. 安全的類型轉(zhuǎn)換: 在使用類型轉(zhuǎn)換之前使用 instanceof 進(jìn)行檢查,可
以避免不安全的類型轉(zhuǎn)換,從而減少潛在的運(yùn)行時(shí)錯(cuò)誤。
總的來說,instanceof 關(guān)鍵字幫助你處理繼承和多態(tài)性的情況,確保你在操作對(duì)象時(shí)能夠正確地處理不同的對(duì)象類型,從而增強(qiáng)代碼的穩(wěn)定性和可讀性。它是面向?qū)ο缶幊讨幸粋€(gè)重要的工具,幫助你更好地利用Java的特性。
#### 類型轉(zhuǎn)換
在Java中,子類和父類之間可以進(jìn)行類型轉(zhuǎn)換,但需要注意一些規(guī)則和限制。類型轉(zhuǎn)換可以分為向上轉(zhuǎn)型(Upcasting)和向下轉(zhuǎn)型(Downcasting)兩種情況。
##### 1. 向上轉(zhuǎn)型(Upcasting):
向上轉(zhuǎn)型是指將一個(gè)子類對(duì)象賦值給父類引用變量,這是安全的,因?yàn)樽宇愂歉割惖奶鼗?。在向上轉(zhuǎn)型時(shí),你可以調(diào)用父類中定義的方法,但不能調(diào)用子類中特有的方法。
示例:
```java
class Animal {
? ? void sound() {
? ? ? ? System.out.println("動(dòng)物發(fā)出聲音");
? ? }
}
class Dog extends Animal {
? ? void sound() {
? ? ? ? System.out.println("汪汪汪!");
? ? }
? ? void fetch() {
? ? ? ? System.out.println("狗會(huì)接?xùn)|西");
? ? }
}
//編譯看左 運(yùn)行看右
public class Main {
? ? public static void main(String[] args) {
? ? ? ? Animal animal = new Dog();? // 向上轉(zhuǎn)型
? ? ? ? animal.sound();? ? ? ? ? ? ?// 調(diào)用的是 Dog 類中的 sound 方法 汪汪汪
? ? ? ? // animal.fetch();? ? ? ? ? // 錯(cuò)誤!Animal 類沒有 fetch 方法
? ? }
}
```
##### 2. 向下轉(zhuǎn)型(Downcasting):
向下轉(zhuǎn)型是指將一個(gè)父類引用變量轉(zhuǎn)換為子類引用變量,但這需要在編譯時(shí)和運(yùn)行時(shí)都要進(jìn)行**安全檢查**。只有在父類引用實(shí)際上指向一個(gè)**子類對(duì)象**時(shí),向下轉(zhuǎn)型才會(huì)成功。如果轉(zhuǎn)型失敗,會(huì)拋出 ClassCastException 異常。
示例:
```java
class Animal {
? ? void sound() {
? ? ? ? System.out.println("動(dòng)物發(fā)出聲音");
? ? }
}
class Dog extends Animal {
? ? void sound() {
? ? ? ? System.out.println("汪汪汪!");
? ? }
? ? void fetch() {
? ? ? ? System.out.println("狗會(huì)接?xùn)|西");
? ? }
}
public class Main {
? ? public static void main(String[] args) {
? ? ? ? Animal animal = new Dog();? ?// 向上轉(zhuǎn)型
? ? ? ? if (animal instanceof Dog) {
? ? ? ? ? ? Dog myDog = (Dog) animal;? // 向下轉(zhuǎn)型
? ? ? ? ? ? myDog.sound();? ? ? ? ? ? ?// 調(diào)用 Dog 類中的 sound 方法
? ? ? ? ? ? myDog.fetch();? ? ? ? ? ? ?// 調(diào)用 Dog 類中的 fetch 方法
? ? ? ? } else {
? ? ? ? ? ? System.out.println("對(duì)象不是 Dog 類的實(shí)例");
? ? ? ? }
? ? }
}
```
##### instanceof在類型轉(zhuǎn)換中的作用
因此,需要注意的是,向下轉(zhuǎn)型時(shí)需要使用 (子類類型) 進(jìn)行顯式的類型轉(zhuǎn)換,并且最好在轉(zhuǎn)型前使用 **instanceof **來進(jìn)行類型檢查,以避免可能的異常。
父類型引用指向子類型對(duì)象,需要調(diào)用子類所特有的方法時(shí),需要強(qiáng)制類型轉(zhuǎn)換
父類是高類型,子類是低類型;低轉(zhuǎn)高,自動(dòng)轉(zhuǎn)換;高轉(zhuǎn)低,要舍棄。所以強(qiáng)制剝奪轉(zhuǎn)換
#### 子類和父類之間的類型轉(zhuǎn)換在Java中有其優(yōu)點(diǎn)和缺點(diǎn):
#### 優(yōu)點(diǎn):
###### 代碼靈活性:
?類型轉(zhuǎn)換允許你在不同的情境下使用相同的代碼處理不同類型的對(duì)象。這在實(shí)現(xiàn)多態(tài)性和通用代碼時(shí)非常有用,使得代碼更具靈活性和可重用性。
###### 動(dòng)態(tài)適應(yīng)性:
?類型轉(zhuǎn)換允許你在運(yùn)行時(shí)根據(jù)實(shí)際對(duì)象的類型做出決策。這在根據(jù)不同的條件采取不同的操作時(shí)很有用,增加了程序的動(dòng)態(tài)適應(yīng)性。
###### 代碼共享:?
使用父類引用來處理多個(gè)子類對(duì)象,可以將共享的代碼抽象到父類中,避免了重復(fù)編寫相似的代碼,提高了代碼的重用性。
#### 缺點(diǎn):
###### 編譯時(shí)類型檢查不足:
?在向下轉(zhuǎn)型時(shí),如果沒有進(jìn)行適當(dāng)?shù)念愋蜋z查,可能會(huì)導(dǎo)致編譯時(shí)的錯(cuò)誤或者運(yùn)行時(shí)的異常。因此,必須小心地進(jìn)行類型檢查和轉(zhuǎn)換,以避免潛在的錯(cuò)誤。
###### 安全性問題:?
類型轉(zhuǎn)換可能會(huì)引入安全性問題。如果沒有正確地進(jìn)行類型檢查,可能會(huì)在運(yùn)行時(shí)出現(xiàn) ClassCastException 異常,從而導(dǎo)致程序崩潰。
###### 可讀性和維護(hù)性:?
大量的類型轉(zhuǎn)換可能會(huì)使代碼更難以閱讀和理解。特別是在復(fù)雜的繼承關(guān)系中,類型轉(zhuǎn)換可能會(huì)導(dǎo)致代碼的復(fù)雜性,降低代碼的可讀性和可維護(hù)性。
###### 違背封裝原則:?
使用類型轉(zhuǎn)換可能會(huì)違反封裝原則,因?yàn)樗试S在外部訪問子類特有的方法和屬性,從而可能破壞了封裝的隔離性。
總的來說,子類和父類之間的類型轉(zhuǎn)換在合適的情況下可以提高代碼的靈活性和重用性,但也需要小心地進(jìn)行類型檢查,避免潛在的錯(cuò)誤和安全性問題。最佳實(shí)踐是使用類型轉(zhuǎn)換時(shí)要充分理解其優(yōu)缺點(diǎn),并根據(jù)具體情況做出明智的決策。
#### 父類引用指向子類的對(duì)象
把子類轉(zhuǎn)換為父類,(替代老子 )向上轉(zhuǎn)型,會(huì)丟失子類自己原來的特有的方法
把父類轉(zhuǎn)換為子類,(剝奪地位)向下轉(zhuǎn)型,強(qiáng)制轉(zhuǎn)換(丟失精度 ),才調(diào)用子類方法
**類似,子類轉(zhuǎn)父類,會(huì)丟失方法,子類不能繼承父類的私有方法
;
而父類轉(zhuǎn)子類,(Person-->dog 高轉(zhuǎn)低 向上強(qiáng)轉(zhuǎn) )只需要強(qiáng)制轉(zhuǎn)換,還能使用子類的方法!多好**
方便方法的調(diào)用(轉(zhuǎn)型),減少重復(fù)的代碼,簡潔
### 14?
靜態(tài)變量可以直接用類名訪問,也稱類變量
靜態(tài)變量(或方法)對(duì)于類,所有對(duì)象(實(shí)例)共享
靜態(tài)變量可以直接調(diào)用,但是非靜態(tài)變量不可以直接調(diào)用
### 14 Static
### 作用:
#### 1. 靜態(tài)變量(Static Variables):
靜態(tài)變量是屬于類而不是對(duì)象的變量。它在類的所有對(duì)象之間共享相同的值。在創(chuàng)建一個(gè)對(duì)象時(shí),所有該類的實(shí)例都會(huì)共享同一個(gè)靜態(tài)變量的值。靜態(tài)變量通過使用 static 關(guān)鍵字來聲明。
java
Copy code
class Counter {
? ? static int count = 0;? // 靜態(tài)變量,所有 Counter 對(duì)象共享這個(gè)值
? ? public Counter() {
? ? ? ? count++;? // 每次創(chuàng)建對(duì)象時(shí),計(jì)數(shù)器增加
? ? }
? ? static int getCount() {
? ? ? ? return count;? // 靜態(tài)方法可以訪問靜態(tài)變量
? ? }
}
public class Main {
? ? public static void main(String[] args) {
? ? ? ? Counter c1 = new Counter();
? ? ? ? Counter c2 = new Counter();
? ? ? ? System.out.println("對(duì)象數(shù)量:" + Counter.getCount());? // 輸出:對(duì)象數(shù)量:2
? ? }
}
#### 2. 靜態(tài)方法(Static Methods):
靜態(tài)方法是屬于類而不是對(duì)象的方法。它可以在不創(chuàng)建類的實(shí)例的情況下被調(diào)用。靜態(tài)方法通過使用 static 關(guān)鍵字來聲明。
java
Copy code
class MathUtil {
? ? static int add(int a, int b) {
? ? ? ? return a + b;
? ? }
}
public class Main {
? ? public static void main(String[] args) {
? ? ? ? int result = MathUtil.add(5, 3);? // 調(diào)用靜態(tài)方法
? ? ? ? System.out.println("結(jié)果:" + result);? // 輸出:結(jié)果:8
? ? }
}
#### 3. 靜態(tài)代碼塊(Static Initialization Block):
靜態(tài)代碼塊在類被加載時(shí)執(zhí)行,通常用于進(jìn)行類的初始化操作。它也使用 static 關(guān)鍵字來聲明。
java
Copy code
class MyClass {
? ? static int count;
? ? static {
? ? ? ? count = 10;? // 靜態(tài)代碼塊在類加載時(shí)執(zhí)行
? ? }
}
public class Main {
? ? public static void main(String[] args) {
? ? ? ? System.out.println("Count:" + MyClass.count);? // 輸出:Count:10
? ? }
}
總的來說,static 關(guān)鍵字用于創(chuàng)建與類本身相關(guān)聯(lián)的屬性和方法,而不是與類的實(shí)例相關(guān)聯(lián)。希望這些例子能幫助你理解 static 的概念。如果還有疑問,隨時(shí)提問!
#### 代碼塊
```java
靜態(tài)區(qū)代碼加載類時(shí)一起被初始化,最早執(zhí)行且只執(zhí)行一次(第一次new)
public class Person{
? ? {
? ? ? ? System.out.println("匿名代碼塊");
? ? }
? ? static {
? ? ? ? System.out.println("靜態(tài)代碼塊");
? ? }
? ? public Person(){
? ? ? ? System.out.println("構(gòu)造方法");
? ? }
? ? public static void main(String[] args){
? ? ? ? Person person = new Person();
? ? ? ? System.out.println("=====================")
? ? ? ? Person person2 = new Person();
? ? ? ? System.out.println("=====================")
? ? ? ? Person person3 = new Person();
? ? }
}
//靜態(tài)代碼塊
//匿名代碼塊
//構(gòu)造方法
//======
//匿名代碼塊
//構(gòu)造方法
```
?
####? Math->隨機(jī)數(shù):
###### //靜態(tài)導(dǎo)入包
```java
import static java.lang.Math.random;
public class Application {? ??
? ? public static void main(String[] args) {? ? ? ??
? ? ? ? //第一種隨機(jī)數(shù),不用導(dǎo)包? ? ? ??
? ? ? ? System.out.println(Math.random());?
? ? ? ? //0.7562202902634543? ? ? ??
? ? ? ? //第二種隨機(jī)數(shù),靜態(tài)導(dǎo)入包? ? ? ??
? ? ? ? System.out.println(random());?
? ? ? ? //0.5391606223844663? ??
? ? }
}
```
#### -不能重寫的方法?
1、static方法,屬于類它不屬于實(shí)例? ? ?2、final? 常量? ? ?3、private? 私有類不能重寫
### 15 抽象類 子類強(qiáng)制重寫抽象方法 老子省事 模板設(shè)計(jì)模式
創(chuàng)建一個(gè)人,必須要有五官、身高體重。但是長多帥、多高、多重,你可以自己決定。
接口可以多繼承,抽象單繼承

abstract修飾的類就是抽象類,修飾的方法就是抽象方法
抽象類中可以沒有抽象方法,但有抽象方法的類一定要聲明為抽象類
抽象類不能使用new來創(chuàng)建對(duì)象,它是用來讓子類繼承的
抽象方法只有方法的聲明,沒有實(shí)現(xiàn),讓其子類實(shí)現(xiàn)
子類繼承抽象類,必須實(shí)現(xiàn)抽象類的所有方法, 否則該子類也要聲明為抽象類
編譯器給抽象類添加了一個(gè)無參構(gòu)造方法。
### 16【接口】
#### 接口最能體現(xiàn)OOP的精髓,對(duì) 對(duì)象 的抽象
#### 抽象類是對(duì)事物屬性的抽象,接口是對(duì)行為的抽象
public abstract class? ?Person{
}
pubnlic class Students? enxtends Person{
@Override
? ? public void do Something(){
? ? }
}
類里面有方法的實(shí)現(xiàn),接口里面只有方法的定義。
因?yàn)樗浅橄蟮模辗椒0妫?,所以在類中?shí)現(xiàn)(調(diào)用)接口的時(shí)候,必須要進(jìn)行方法重寫才能使用。
- 在Java編程語言中是一個(gè)抽象類型,是抽象對(duì)象的集合,對(duì)象通常以interface關(guān)鍵字來聲明。
#### 普通類:只有具體實(shí)現(xiàn) 屬性+方法
##### 抽象類:具體實(shí)現(xiàn)和規(guī)范(抽象方法)共存 模版設(shè)計(jì)
##### 接口:只有規(guī)范,無法自己實(shí)現(xiàn) 約束規(guī)范
##### 約束和實(shí)現(xiàn)分離->面向接口編程
接口就是規(guī)范,定義一組規(guī)則,**它的本質(zhì)是契約**,制定好之后大家都要遵守。
OO的精髓,是對(duì)對(duì)象的抽象,最能體現(xiàn)這一點(diǎn)的就是接口。為什么我們討論設(shè)計(jì) 模式都只針對(duì)具備了抽象
能力的語言(比如c++、java、c#等),就是因?yàn)樵O(shè)計(jì)模式所研究的,實(shí)際上就是如何合理的去抽象。
#### 接口的特性
接口是隱式抽象的,當(dāng)聲明一個(gè)接口的時(shí)候,不必使用abstract關(guān)鍵字。
接口中每一個(gè)方法也是隱式抽象的,聲明時(shí)同樣不需要abstract關(guān)鍵字
接口中的方法都是公有的。
實(shí)現(xiàn)
#### 1 接口的聲明
```java
[可見度] interface 接口名稱 [extends 其他的接口名] {? ? ? ?
? ? // 聲明變量??
? ??
? ? // 抽象方法?
}
```
```java
/**
*用戶接口,需要實(shí)現(xiàn)類
*鍛煉抽象的思維
*/
public interface UserService{
? ? //定義的屬性默認(rèn)是靜態(tài)常量:public static final
? ? int age = 10;
? ??
? ? //定義的方法默認(rèn)是公共抽象:public abstract 因此可以省略 不寫
?public abstract? void add(String str);
? ? void delete(String str);
? ? void update(String str);
? ? void query(String str);
}
public interface TimeService{
? ? void timer();
}
```
#### 2 接口的實(shí)現(xiàn)?
```java
/*
抽象類用繼承:extends
接口用實(shí)現(xiàn):implements
類可以實(shí)現(xiàn)接口,需要實(shí)現(xiàn)所有方法!
利用接口實(shí)現(xiàn)偽多繼承~
*/
public class UserServiceImplement implements UserService,TimeService{
? ? @Override
? ? public void add(String str){
? ? ? ??
? ? }
? ??
? ? @Override
? ? public void delete(String str){
? ? ? ??
? ? }
? ??
? ? @Override
? ? public void update(String str){
? ? ? ??
? ? }
? ??
? ? @Override
? ? public void query(String str){
? ? ? ??
? ? }
? ??
? ? @Override
? ? public void timer(){
? ? ? ??
? ? }
}
```
類在實(shí)現(xiàn)接口的方法時(shí),不能拋出強(qiáng)制性異常,只能在接口中,或者繼承接口的抽象類中拋出該強(qiáng)制性異常
#### 在實(shí)現(xiàn)接口的時(shí)候,也要注意一些規(guī)則:
#### Mac快捷鍵是command+回車
###### 1. 一個(gè)類只能繼承一個(gè)類,但是能實(shí)現(xiàn)多個(gè)接口
###### 2. 一個(gè)接口能繼承另一個(gè)接口,這和類之間的繼承比較相似
###### 繼承
###### 3. 接口的繼承使用extends關(guān)鍵字,子接口繼承父類接口的方法
```java
//文件名:Sports.java
public interface Sports{
? ? public void setHomeTeam(String name);
? ? public void setVisitingTeam(String name);
}
//文件名:Football.java
public interface Foorball extends Sports{
? ? public void homeTeamScored(int points);
? ? public void visitingTeamScored(int points)
? ? public void endOfQuarter(int quarter);
}
//文件名:Hockey.java
public interface Hockey extends Sports{
? ? public void homeGoalScored();
? ? public void visitingGoalScored();
? ? public void endOfPeriod(int period);
? ? public void overtimePeriod(int ot);
}
```
#### 多繼承
###### 類不允許多繼承
###### 接口允許多繼承
接口與類相似,一個(gè)接口可以有多個(gè)方法
#### 接口與類的區(qū)別
接口不能被實(shí)例化
接口沒有構(gòu)造方法
接口中所有的方法必須是抽象方法
接口不能包含成員變量,除了static和final變量
接口不是被類繼承,而是被類實(shí)現(xiàn)
接口支持多繼承(實(shí)現(xiàn)類(implements) 可以實(shí)現(xiàn)多個(gè)接口)
實(shí)現(xiàn)類必須要重寫接口中的方法
JDK8之后的新特性,支持在接口中實(shí)現(xiàn)具體方法,但需要default修飾。default修飾方法只能在接口中使用。
### 17 內(nèi)部類
內(nèi)部類:在一個(gè)類的內(nèi)部再定義一個(gè)類
class A{
? ? class B{
? ? ? ??
? ? }
}
A是B的外部類,B是A的內(nèi)部類。
#### 1 成員內(nèi)部類
###### 定義成員內(nèi)部類
```java
public class Outer{
? ? private int id = 10;
? ? public void out(){
? ? ? ? System.out.println("外部類的方法");
? ? }
? ??
? ? //成員內(nèi)部類
? ? public class Inner{//若內(nèi)部類加上static 靜態(tài) 則getOuterId()方法失效。因?yàn)?靜態(tài)? ?
? ? ? ? public void inner(){
? ? ? ? ? ? System.out.println("內(nèi)部類的方法");
? ? ? ? }
? ? ? ? ? ??
? ? ? ? //可以直接使用外部類的屬性/方法
? ? ? ? public void getOuterId(){
? ? ? ? ? ? System.out.println("內(nèi)部類調(diào)用外部類屬性和方法");
? ? ? ? ? ? //創(chuàng)建成員內(nèi)部類之前肯定要?jiǎng)?chuàng)建外部類對(duì)象
? ? ? ? ? ? //即使id不是靜態(tài)變量,out不是靜態(tài)方法,但創(chuàng)建外部類對(duì)象時(shí)已經(jīng)存在。
? ? ? ? ? ? System.out.pirntln(id);
? ? ? ? ? ? out();
? ? ? ? }
? ? }
}
```
#### 實(shí)現(xiàn)內(nèi)部類
```java
import com.oop.demo10.Outer;
public class Application {
public static void main(String[] args) {
Outer outer = new Outer();//通過這個(gè)外部類來實(shí)例化內(nèi)部類
Outer.Inner inner = outer .new Inner();
inner.getID();
```
#### 匿名內(nèi)部類
public class Application{
? ? public static void main(String[] args){
? ? ? ? //匿名內(nèi)部類在多線程中使用,到時(shí)候再深究
? ? ? ? Thread thread = new Thread(new Runnable(){
? ? ? ? ? ? @Override
? ? ? ? ? ? public void run(){
? ? ? ? ? ? ? ? System.out.println("匿名內(nèi)部類實(shí)現(xiàn)線程的邏輯操作");
? ? ? ? ? ? }
? ? ? ? });
? ? ? ? //開啟操作
? ? ? ? thread.start();
? ? }
}
# 06 異常
### 1 Error 和 Exception
異常
#### 1.什么是異常
? ? 實(shí)際工作中,遇到的情況不可能是非常完美的。比如:你寫的某個(gè)模塊,用戶輸入不一定符合你的要求、你的程序要打開某個(gè)文件,這個(gè)文件可能不存在或者文件格式不對(duì),你要讀取數(shù)據(jù)庫的數(shù)據(jù),數(shù)據(jù)可能是空的等。我們的程序再跑著,內(nèi)存或硬盤可能滿了。等等。
? ? 軟件程序在運(yùn)行過程中,非??赡苡龅絼倓偺岬降倪@些異常問題,我們叫異常,英文是:Exception,意思是例外。這些,例外情況,或者叫異常,怎么讓我們寫的程序做出合理的處理。而不至于程序崩潰。
? ? 異常指程序運(yùn)行中出現(xiàn)的不期而至的各種狀況如:文件找不到、網(wǎng)絡(luò)連接失敗、非法參數(shù)等。異常發(fā)生在程序運(yùn)行期間它影響了正常的程序執(zhí)行流程。
要理解Java異常處理是如何工作的,需要掌握以下三種類型的異常:
#### 2 三種類型的異常
###### 檢查性異常:
最具代表的檢查性異常是用戶錯(cuò)誤或問題引起的異常,這是程序員無法預(yù)見的例如要打開一個(gè)不存在文件時(shí),一個(gè)異常就發(fā)生了,這些異常在編譯時(shí)不能被簡單地忽略。
###### 運(yùn)行時(shí)異常:
運(yùn)行時(shí)異常是可能被程序員避免的異常。與檢查性異常相反,運(yùn)行時(shí)異??梢栽诰幾g時(shí)被忽略。
###### 錯(cuò)誤ERROR:
錯(cuò)誤不是異常,而是脫離程序員控制的冋題。錯(cuò)誤在代碼中通常被忽略。例如,當(dāng)棧溢出時(shí),一個(gè)錯(cuò)誤就發(fā)生了,它們在編譯也檢查不到的。
#### 3.異常體系結(jié)構(gòu)

Java把異常當(dāng)作對(duì)象來處理,并定義一個(gè)基類 java. lang.Throwable作為所有異常的超類。
在 Java API中已經(jīng)定義了許多異常類,這些異常類分為兩大類,錯(cuò)誤Error和異常 Exception。
在這里插入圖片描述
#### Error
Error類對(duì)象由Java虛擬機(jī)生成并拋出,大多數(shù)錯(cuò)誤與代碼編寫者所執(zhí)行的操作無關(guān)。
Java虛擬機(jī)運(yùn)行錯(cuò)誤( Virtual Machine Error),當(dāng)JVM不再有繼續(xù)執(zhí)行操作所需的內(nèi)存資源時(shí),將出現(xiàn) OutofMemory Error。這些異常發(fā)生時(shí),Java虛擬機(jī)(JVM)一般會(huì)選擇線程終止。
還有發(fā)生在虛擬機(jī)試圖執(zhí)行應(yīng)用時(shí),如類定義錯(cuò)誤( NoClass Deffound error)、鏈接錯(cuò)誤( Linkage Error)。這些錯(cuò)誤是不可查的,因?yàn)樗鼈冊趹?yīng)用程序的控制和處理能力之外,而且絕大多數(shù)是程序運(yùn)行時(shí)不允許出現(xiàn)的狀況。
#### Exception
##### 運(yùn)行時(shí)異常(還有非運(yùn)行異常 檢查異常)
在 Exception分支中有一個(gè)重要的子類 Runtime Exception(運(yùn)行時(shí)異常)
ArraylndexOutOfBoundsException(數(shù)組下標(biāo)越界)
NullPointerException(空指針異常)
ArithmeticException(算術(shù)異常)
Missing Resource Exception(丟失資源)
ClassNotFound Exception(找不到類)等異常,這些異常是不檢查異常,程序中可以選擇捕獲處理,也可以不處理。
這些異常一般是由程序邏輯錯(cuò)誤引起的,程序應(yīng)該從邏輯角度盡可能避免這類異常的發(fā)生;
#### Error和 Exception的區(qū)別:
###### Error通常是災(zāi)難性的致命的錯(cuò)誤,是程序無法控制和處理的,當(dāng)出現(xiàn)這些異常時(shí),Java虛擬機(jī)(JVM)一般會(huì)選擇終止線程;
###### Exception通常情況下是可以被程序處理的,并且在程序中應(yīng)該盡可能的去處理這些異常。
### 2 Java異常處理機(jī)制與處理異常
### 拋出異常
### 捕獲異常
異常處理五個(gè)關(guān)鍵字:
try、catch、 finally、throw、throws
```java
public static void main(String[] args) {
? ? ? ? int a=1;
? ? ? ? int b=0;
? ? ? ? try{
? ? ? ? ? ? System.out.println(a/b);
? ? ? ? }catch (Error e){
? ? ? ? ? ? System.out.println("Error");
? ? ? ? }catch(Exception e){
? ? ? ? ? ? System.out.println("Exception");
? ? ? ? }catch (Throwable t){
? ? ? ? ? ? System.out.println("Throwable");
? ? ? ? }finally {
? ? ? ? ? ? System.out.println("finally");
? ? ? ? }
? ? }
? ? public void a(){b();}
? ? public void b(){a();}
? ??
? ??
```
```java
int a = 1;
int b = 0;
try{
// try 監(jiān)控區(qū)域
if(b == 0)
{
? ? // 主動(dòng)拋出異常,一般在方法上使用
throw new ArithmeticException();?
}
System.out.println(a/b);
}catch (ArithmeticException e){
// catch 捕獲異常
System.out.println("程序出現(xiàn)異常,變量b不能為0");
}catch (Throwable t){
// catch 可以有多個(gè)
t.printstackTrace(); // 打印錯(cuò)誤的棧信息
System.out.println("從小到大捕獲異常");
}finally {
// 處理善后工作
System.out.println("finally"); // 可以不要,多用于IO、資源的關(guān)閉。
}
// 假設(shè)在這個(gè)方法中,處理不了這個(gè)異常,在方法上拋出異常。
public void test(int a,int b) throws ArithmeticException{
if(b == 0)
{
throw new ArithmeticException();?
}
}
```
#### throws和throw的區(qū)別
是不管程序有沒有異常,只要執(zhí)行到throw語句就一定會(huì)拋一個(gè)異常
快捷鍵:mac command+option+T
### 3.自定義異常
使用Java內(nèi)置的異常類可以描述在編程時(shí)岀現(xiàn)的大部分異常情況。除此之外,用戶還可以自定義異常。用戶自定義異常類,只需繼承 Exception類即可。
在程序中使用自定義異常類,大體可分為以下幾個(gè)步驟:
創(chuàng)建自定義異常類。
在方法中通過 throw關(guān)鍵字拋出異常對(duì)象。
如果在當(dāng)前拋出異常的方法中處理異常,可以使用try- catch語句捕獲并處理;否則在方法的聲明處通過 throws關(guān)鍵字指明要拋岀給方法調(diào)用者的異常,繼續(xù)進(jìn)行下一步操作。
在出現(xiàn)異常方法的調(diào)用者中捕獲并處理異常。
在這里插入圖片描述
5.總結(jié)
處理運(yùn)行時(shí)異常時(shí),采用邏輯去合理規(guī)避同時(shí)輔助 try-catch ;
處理在多重 catch塊后面,可以加一個(gè) catch( Exception)來處理可能會(huì)被遺漏的異常;
對(duì)于不確定的代碼,也可以加上try- catch,處理潛在的異常;
盡量去處理異常,切忌只是簡單地調(diào)用 printStackTrace0去打印輸出;
具體如何處理異常,要根據(jù)不同的業(yè)務(wù)需求和異常類型去決定;
盡量添加 finally!語句塊去釋放占用的資源。
-=========================
Java把溢出當(dāng)做對(duì)象來處理,并定義了一個(gè)基類Java.lang.Throwable作為所有異常的超類。
Java語言定義了許多異常類在Java.lang標(biāo)準(zhǔn)包中,主要分為Error和Exception兩大類。
img
五個(gè)關(guān)鍵字try、catch、finally、throw、throws
使用try和catch關(guān)鍵字可以捕獲異常。try/catch代碼塊放在異??赡馨l(fā)生的地方。
try/catch代碼塊中的代碼稱為保護(hù)代碼。
finally區(qū)可以不要,在IO流,資源關(guān)閉時(shí)使用。
捕獲多個(gè)溢出:從小到大!
IDEA快捷鍵:選中健康區(qū)域代碼-->Ctrl + Alt + T
? ??
拋出異常
throws是用來聲明一個(gè)方法可能拋出的所有異常信息,throws是將異常聲明但是不處理,而是將異常往上傳,誰調(diào)用我就交給誰處理。而throw則是指拋出的一個(gè)具體的異常類型
throws是用在方法名尾部,可以聲明拋出多個(gè)溢出,多個(gè)溢出之間用逗號(hào)隔開。
import java.io.*;
public class className{
? ? public void withdraw(double amount) throws RemoteException,InsufficientFundsException{
? ? ? ? //Method implementation
? ? }
? ? //Remainder of class definition
}
throw是用在方法體內(nèi),主動(dòng)拋出異常
public class ThrowTest{
? ? public static void main(String[] args){
? ? ? ? int a = 1;
? ? ? ? int b = 0;
? ? ? ??
? ? ? ? try{
? ? ? ? ? ? System.out.println(divide(a,b));
? ? ? ? }catch (Exception e){
? ? ? ? ? ? System.out.println("分母不能為0");
? ? ? ? ? ? //e.printStackTrace();
? ? ? ? }
? ? }
? ??
? ? public static double divide(int a,int b){
? ? ? ? if(b == 0){
? ? ? ? ? ? //主動(dòng)拋出異常
? ? ? ? ? ? throw new ArithmeticException();
? ? ? ? }
? ? ? ? return 1.0*a/b;
? ? }
}
自定義異常
在這里插入圖片描述
//自定義的異常類
public class MyException extends Exception{
? ? private int detail;
? ??
? ? public Myexception(int a){
? ? ? ? this.detail = a;
? ? }
? ??
? ? //異常的處理信息
? ? //tostring
? ? @Override
? ? public String toString(){
? ? ? ? return "Myexception{" + "detail=" + detail + "}";
? ? }
}
public class Appcication{
? ? //可能存在異常方法
? ? static void test(int a) throws MyException{
? ? ? ? System.out.println("傳遞的參數(shù)為:" + a);
? ? ? ? if(a>10){
? ? ? ? ? ? throw new MyException(a);//拋出
? ? ? ? }
? ? ? ? System.out.println("ok");
? ? }
}
public static void main(String[] args){
? ? try{
? ? ? ? test(11);
? ? }catch (MyException e){
? ? ? ? System.out.println("MyException=>" + e);
? ? }
}
#### 總結(jié)
處理運(yùn)行是異常時(shí),采用邏輯去合理規(guī)避,同時(shí)輔助try-catch處理
在多重catch塊后面,可以加一個(gè)catch(Exception)來處理可能會(huì)被遺漏的異常
對(duì)于不確定的代碼,也可以加上try-catch,處理潛在的異常
盡量去處理異常,切忌只是簡單的調(diào)用printStackTrace()去打印輸出
具體如何處理異常,要根據(jù)不同的業(yè)務(wù)需求和異常類型去決定
盡量添加finally語句塊去釋放占用的資源。