八、面向?qū)ο?/h2>
1. 面向?qū)ο蟮娜齻€(gè)階段
-
面向?qū)ο蠓治?OOA --> Object Oriented Analysis
對象:張三,王五,朱六,你,我
抽取出一個(gè)類----》人類
類里面有什么:
動(dòng)詞--》動(dòng)態(tài)特性--》方法
名詞--》靜態(tài)特性--》屬性
-
面向?qū)ο笤O(shè)計(jì) OOD --> Object Oriented Design
先有類,再有對象:
類:人類: Person
對象:zhangsan ,lisi,zhuliu
面向?qū)ο缶幊?OOP --> Object Oriented Programming
2.創(chuàng)建類和對象
-
創(chuàng)建類
1). 屬性
? [修飾符] 屬性類型 屬性名 = [默認(rèn)值] ;
2).方法
? [修飾符] 方法返回值類型 方法名(形參列表) {
? // n條語句
}
package com.msb;
/**
* @Auther: msb-zhaoss
* 創(chuàng)建類:人類
*/
public class Person {
//名詞---》屬性---》成員變量---》放在類中方法外(注意:我們只把有需要的內(nèi)容寫到代碼里,不相關(guān)的東西不要放在代碼中)
int age ;//年齡
String name;//姓名
double height;//身高
double weight;//體重
//動(dòng)詞---》方法
//吃飯
public void eat(){
int num = 10;//局部變量:放在方法中
System.out.println("我喜歡吃飯");
}
//睡覺:
public void sleep(String address){
System.out.println("我在"+address+"睡覺");
}
//自我介紹:
public String introduce(){
return "我的名字是:"+name+",我的年齡是:"+age+",我的身高是:"+height+",我的體重是:"+weight;
}
}
-
創(chuàng)建對象
package com.msb;
/**
* @Auther: msb-zhaoss
*/
public class Test {//測試類
//這是一個(gè)main方法,是程序的入口:
public static void main(String[] args) {
//創(chuàng)建一個(gè)人類的具體的對象/實(shí)例:
//創(chuàng)建一個(gè)對象,對象的名字叫:zs
//Person 屬于 引用數(shù)據(jù)類型
//第一次加載類的時(shí)候,會(huì)進(jìn)行類的加載,初始化創(chuàng)建對象的時(shí)候,對象的屬性沒有給賦值,有默認(rèn)的初始化的值。
Person zs = new Person();
zs.name = "張三";
zs.age = 19;
zs.height = 180.4;
zs.weight = 170.4;
//再創(chuàng)建一個(gè)對象:
//再次創(chuàng)建類的時(shí)候,就不會(huì)進(jìn)行類的加載了,類的加載只在第一次需要的時(shí)候加載一次
Person ls = new Person();
ls.name = "李四";
ls.age = 18;
ls.height = 170.6;
ls.weight = 160.5;
//對屬性值進(jìn)行讀取:
System.out.println(zs.name);
System.out.println(ls.age);
//對方法進(jìn)行操作:
//不同的對象,屬性有自己的特有的值,但是方法都是調(diào)用類中通用的方法。
//屬性:各個(gè)對象的屬性是獨(dú)立的,
//方法:各個(gè)對象的方法是共享的。
zs.eat();
ls.eat();
zs.sleep("教室");
/*String str = zs.introduce();
System.out.println(str);*/
System.out.println(zs.introduce());
}
}
3.局部變量和成員變量的區(qū)別
-
位置不同
成員變量:類中方法外定義的變量
局部變量:方法中定義的變量 代碼塊中定義的變量
-
作用范圍不同
成員變量:當(dāng)前類的很多方法
局部變量:當(dāng)前一個(gè)方法(當(dāng)前代碼塊
-
是否有默認(rèn)值
成員變量:有
局部變量:沒有
局部變量和成員變量.png
面向?qū)ο蠓治?OOA --> Object Oriented Analysis
對象:張三,王五,朱六,你,我
抽取出一個(gè)類----》人類
類里面有什么:
動(dòng)詞--》動(dòng)態(tài)特性--》方法
名詞--》靜態(tài)特性--》屬性
面向?qū)ο笤O(shè)計(jì) OOD --> Object Oriented Design
先有類,再有對象:
類:人類: Person
對象:zhangsan ,lisi,zhuliu
面向?qū)ο缶幊?OOP --> Object Oriented Programming
創(chuàng)建類
1). 屬性
? [修飾符] 屬性類型 屬性名 = [默認(rèn)值] ;
2).方法
? [修飾符] 方法返回值類型 方法名(形參列表) {
? // n條語句
}
package com.msb;
/**
* @Auther: msb-zhaoss
* 創(chuàng)建類:人類
*/
public class Person {
//名詞---》屬性---》成員變量---》放在類中方法外(注意:我們只把有需要的內(nèi)容寫到代碼里,不相關(guān)的東西不要放在代碼中)
int age ;//年齡
String name;//姓名
double height;//身高
double weight;//體重
//動(dòng)詞---》方法
//吃飯
public void eat(){
int num = 10;//局部變量:放在方法中
System.out.println("我喜歡吃飯");
}
//睡覺:
public void sleep(String address){
System.out.println("我在"+address+"睡覺");
}
//自我介紹:
public String introduce(){
return "我的名字是:"+name+",我的年齡是:"+age+",我的身高是:"+height+",我的體重是:"+weight;
}
}
創(chuàng)建對象
package com.msb;
/**
* @Auther: msb-zhaoss
*/
public class Test {//測試類
//這是一個(gè)main方法,是程序的入口:
public static void main(String[] args) {
//創(chuàng)建一個(gè)人類的具體的對象/實(shí)例:
//創(chuàng)建一個(gè)對象,對象的名字叫:zs
//Person 屬于 引用數(shù)據(jù)類型
//第一次加載類的時(shí)候,會(huì)進(jìn)行類的加載,初始化創(chuàng)建對象的時(shí)候,對象的屬性沒有給賦值,有默認(rèn)的初始化的值。
Person zs = new Person();
zs.name = "張三";
zs.age = 19;
zs.height = 180.4;
zs.weight = 170.4;
//再創(chuàng)建一個(gè)對象:
//再次創(chuàng)建類的時(shí)候,就不會(huì)進(jìn)行類的加載了,類的加載只在第一次需要的時(shí)候加載一次
Person ls = new Person();
ls.name = "李四";
ls.age = 18;
ls.height = 170.6;
ls.weight = 160.5;
//對屬性值進(jìn)行讀取:
System.out.println(zs.name);
System.out.println(ls.age);
//對方法進(jìn)行操作:
//不同的對象,屬性有自己的特有的值,但是方法都是調(diào)用類中通用的方法。
//屬性:各個(gè)對象的屬性是獨(dú)立的,
//方法:各個(gè)對象的方法是共享的。
zs.eat();
ls.eat();
zs.sleep("教室");
/*String str = zs.introduce();
System.out.println(str);*/
System.out.println(zs.introduce());
}
}
位置不同
成員變量:類中方法外定義的變量
局部變量:方法中定義的變量 代碼塊中定義的變量
作用范圍不同
成員變量:當(dāng)前類的很多方法
局部變量:當(dāng)前一個(gè)方法(當(dāng)前代碼塊
是否有默認(rèn)值
成員變量:有
局部變量:沒有
引用數(shù)據(jù)類型默認(rèn)值: null
-
是否要初始化
成員變量:不需要,不建議初始化,后續(xù)使用的時(shí)候再賦值即可
局部變量:一定需要,不然直接使用的時(shí)候報(bào)錯(cuò) -
內(nèi)存中的位置不同
成員變量:堆內(nèi)存
局部變量:棧內(nèi)存 -
作用時(shí)間不同
成員變量:當(dāng)前對象從創(chuàng)建到銷毀
局部變量:當(dāng)前方法從開始執(zhí)行到執(zhí)行完畢
4.構(gòu)造器
-
對象創(chuàng)建的過程
1.第一次遇到Person的時(shí)候,進(jìn)行類的加載(只加載一次)
2.創(chuàng)建對象,為這個(gè)對象在堆中開辟空間
3.為對象進(jìn)行屬性的初始化動(dòng)作 -
構(gòu)造器定義
new關(guān)鍵字實(shí)際上是在調(diào)用一個(gè)方法,這個(gè)方法叫構(gòu)造方法(構(gòu)造器)
調(diào)用構(gòu)造器的時(shí)候,如果你的類中沒有寫構(gòu)造器,那么系統(tǒng)會(huì)默認(rèn)給你分配一個(gè)構(gòu)造器,只是我們看不到罷了。
可以自己顯式 的將構(gòu)造器編寫出來:
構(gòu)造器的格式:
[修飾符] 構(gòu)造器的名字(){
} -
構(gòu)造器和方法的區(qū)別:
1.沒有方法的返回值類型
2.方法體內(nèi)部不能有return語句
3.構(gòu)造器的名字很特殊,必須跟類名一樣 -
構(gòu)造器的作用
構(gòu)造器的作用:不是為了創(chuàng)建對象,因?yàn)樵谡{(diào)用構(gòu)造器之前,這個(gè)對象就已經(jīng)創(chuàng)建好了,并且屬性有默認(rèn)的初始化的值。
調(diào)用構(gòu)造器的目的是給屬性進(jìn)行賦值操作的。
注意:我們一般不會(huì)在空構(gòu)造器中進(jìn)行初始化操作,因?yàn)槟菢拥脑捗總€(gè)對象的屬性就一樣了。
實(shí)際上,我們只要保證空構(gòu)造器的存在就可以了,里面的東西不用寫==構(gòu)造器相當(dāng)于Python中的__init__方法==
-
代碼示例
package com.msb2; /** * @Auther: msb-zhaoss */ public class Person { //構(gòu)造器:沒有任何參數(shù)的構(gòu)造器我們叫做:空參構(gòu)造器--》空構(gòu)造器 public Person(){ /*age = 19; name = "lili"; height = 169.5;*/ } //屬性: String name; int age; double height; //方法: public void eat(){ System.out.println("我喜歡吃飯"); } }
5.構(gòu)造器重載
一般保證空構(gòu)造器的存在,空構(gòu)造器中一般不會(huì)進(jìn)行屬性的賦值操作
一般我們會(huì)重載構(gòu)造器,在重載的構(gòu)造器中進(jìn)行屬性賦值操作
在重載構(gòu)造器以后,假如空構(gòu)造器忘寫了,系統(tǒng)也不會(huì)給你分配默認(rèn)的空構(gòu)造器了,那么你要調(diào)用的話就會(huì)出錯(cuò)了。
當(dāng)形參名字和屬性名字重名的時(shí)候,會(huì)出現(xiàn)就近原則:
在要表示對象的屬性前加上this.來修飾 ,因?yàn)閠his代表的就是你創(chuàng)建的那個(gè)對象構(gòu)造器可以寫多個(gè),主要參數(shù)和類型不一樣(和方法一樣的)
==相當(dāng)于Python中的__init__重載==
在第一次類加載的時(shí)候會(huì)有個(gè)this關(guān)鍵字, 相當(dāng)于Python中的self,指代對象本身
在用構(gòu)造器賦值的時(shí)候用this指定變量,否則會(huì)重名,計(jì)算機(jī)會(huì)優(yōu)先使用離自己近的,就會(huì)出現(xiàn)錯(cuò)誤的值
代碼示例一
package com.msb3.msb2;
/**
* @Auther: msb-zhaoss
*/
public class Person {
//屬性:
String name;
int age;
double height;
//空構(gòu)造器
public Person(){
}
public Person(String name,int age,double height){
//當(dāng)形參名字和屬性名字重名的時(shí)候,會(huì)出現(xiàn)就近原則:
//在要表示對象的屬性前加上this.來修飾 ,因?yàn)閠his代表的就是你創(chuàng)建的那個(gè)對象
this.name = name;
this.age = age;
this.height = height;
}
public Person(String a,int b){
name = a;
age = b;
}
//方法:
public void eat(){
System.out.println("我喜歡吃飯");
}
}
代碼示例二
package com.msb3.msb2;
/**
* @Auther: msb-zhaoss
*/
public class Test {
//這是一個(gè)main方法,是程序的入口:
public static void main(String[] args) {
/*
1.一般保證空構(gòu)造器的存在,空構(gòu)造器中一般不會(huì)進(jìn)行屬性的賦值操作
2.一般我們會(huì)重載構(gòu)造器,在重載的構(gòu)造器中進(jìn)行屬性賦值操作
3.在重載構(gòu)造器以后,假如空構(gòu)造器忘寫了,系統(tǒng)也不會(huì)給你分配默認(rèn)的空構(gòu)造器了,那么你要調(diào)用的話就會(huì)出錯(cuò)了。
4. 當(dāng)形參名字和屬性名字重名的時(shí)候,會(huì)出現(xiàn)就近原則:
在要表示對象的屬性前加上this.來修飾 ,因?yàn)閠his代表的就是你創(chuàng)建的那個(gè)對象
*/
Person p = new Person();
/*p.age = 19;
p.name = "lili";
p.height = 180.4;*/
Person p2 = new Person("lili",19,180.4);
System.out.println(p2.age);
System.out.println(p2.height);
System.out.println(p2.name);
}
}
6.內(nèi)存分析
- 棧: 存放局部變量/形參和開辟方法棧幀
- 堆: new出來的對象, 存放全局變量
- 方法區(qū): 存放對象的字節(jié)碼信息, 一個(gè)對象存放一個(gè)
- 方法和構(gòu)造器運(yùn)行完畢后就會(huì)從內(nèi)存中回收
7.this
從上面的效果能夠看到:this指代的就是當(dāng)前對象, 相當(dāng)于Python中的self
-
this可以修飾屬性
當(dāng)屬性名字和形參發(fā)生重名的時(shí)候,或者 屬性名字 和局部變量重名的時(shí)候,都會(huì)發(fā)生就近原則,所以如果我要是直接使用變量名字的話就指的是離的近的那個(gè)形參或者局部變量,這時(shí)候如果我想要表示屬性的話,在前面要加上:this.修飾
如果不發(fā)生重名問題的話,實(shí)際上你要是訪問屬性也可以省略this.
-
this可以修飾方法
在同一個(gè)類中,方法可以互相調(diào)用,this.可以省略不寫, 類似于省略self
-
this可以修飾構(gòu)造器
同一個(gè)類中的構(gòu)造器可以相互用this調(diào)用,格式為 this(參數(shù))
==注意:this修飾構(gòu)造器必須放在第一行==
8. static
? static可以修飾:屬性,方法,代碼塊,內(nèi)部類。
-
static修飾屬性
1). 在類加載的時(shí)候一起加載入方法區(qū)中的靜態(tài)域中
2). 先于對象存在
3). 訪問方式: 對象名.屬性名 類名.屬性名(推薦)
4).應(yīng)用場景
? 某些特定的數(shù)據(jù)想要在內(nèi)存中共享,只有一塊 --》這個(gè)情況下,就可以用static修飾的屬性
5).屬性:
? 靜態(tài)屬性 (類變量)
? 非靜態(tài)屬性(實(shí)例變量)6).代碼示例
package com.msb5; /** * @Auther: msb-zhaoss */ public class MsbStudent { //屬性: String name; int age; static String school; //這是一個(gè)main方法,是程序的入口: public static void main(String[] args) { MsbStudent.school = "馬士兵教育"; //創(chuàng)建學(xué)生對象: MsbStudent s1 = new MsbStudent(); s1.name = "張三"; s1.age = 19; //s1.school = "馬士兵教育"; MsbStudent s2 = new MsbStudent(); s2.name = "李四"; s2.age = 21; //s2.school = "馬士兵教育"; System.out.println(s2.school); } }
- static修飾方法
- .和修飾屬性一樣, static修飾的方法也是先于對象存在
2). 在靜態(tài)方法中不能訪問非靜態(tài)的屬性
3). 再靜態(tài)方法中不能訪問非靜態(tài)的方法
4).在靜態(tài)方法中不能使用this關(guān)鍵字, 因?yàn)閠his是對象本身,但是靜態(tài)方法又先于對象存在
5).非靜態(tài)的方法可以用對象名.方法名去調(diào)用
6).靜態(tài)方法可以用對象名.方法名去調(diào)用, 也可以用類名.方法名調(diào)用(推薦)
7).在用一個(gè)類中, 方法可以直接調(diào)用
8).代碼示例
package com.msb5; /** * @Auther: msb-zhaoss */ public class Demo { int id; static int sid; public void a(){ System.out.println(id); System.out.println(sid); System.out.println("------a"); } //1.static和public都是修飾符,并列的沒有先后順序,先寫誰后寫誰都行 static public void b(){ //System.out.println(this.id);//4.在靜態(tài)方法中不能使用this關(guān)鍵字 //a();//3.在靜態(tài)方法中不能訪問非靜態(tài)的方法 //System.out.println(id);//2.在靜態(tài)方法中不能訪問非靜態(tài)的屬性 System.out.println(sid); System.out.println("------b"); } //這是一個(gè)main方法,是程序的入口: public static void main(String[] args) { //5.非靜態(tài)的方法可以用對象名.方法名去調(diào)用 Demo d = new Demo(); d.a(); //6.靜態(tài)的方法可以用 對象名.方法名去調(diào)用 也可以 用 類名.方法名 (推薦) Demo.b(); d.b(); } }
9.代碼塊
-
類的組成
屬性,方法,構(gòu)造器,代碼塊,內(nèi)部類
-
代碼塊的分類(代碼塊就是一個(gè)花括號中的內(nèi)容)
普通塊,構(gòu)造塊,靜態(tài)塊,同步塊(多線程)
-
普通塊
在方法中的塊, 普通塊限制了局部變量的作用范圍
-
構(gòu)造塊
在類中方法外的塊
-
靜態(tài)塊
在類中方法外的塊,并且被static關(guān)鍵字修飾
-
==代碼塊的執(zhí)行順序==
1). 最先執(zhí)行靜態(tài)塊,只在類加載的時(shí)候執(zhí)行一次,所以一般以后實(shí)戰(zhàn)寫項(xiàng)目:創(chuàng)建工廠,數(shù)據(jù)庫的初始化信息都放入靜態(tài)塊。一般用于執(zhí)行一些全局性的初始化操作。
2). 再執(zhí)行構(gòu)造塊,(不常用)
3). 再執(zhí)行構(gòu)造器
4). 再執(zhí)行方法中的普通塊。
10. 包 import
-
包的作用
為了解決重名問題(實(shí)際上包對應(yīng)的就是盤符上的目錄)
解決權(quán)限問題
-
包名定義
(1)名字全部小寫
(2)中間用.隔開
(3)一般都是公司域名倒著寫 : com.jd com.msb
(4)加上模塊名字:
com.jd.login com.jd.register
(5)不能使用系統(tǒng)中的關(guān)鍵字:nul,con,com1---com9.....
(6)包聲明的位置一般都在非注釋性代碼的第一行:package com.han; -
導(dǎo)包
(1)使用不同包下的類要需要導(dǎo)包: import ..; 例如:import java.util.Date;
(2)在導(dǎo)包以后,還想用其他包下同名的類,就必須要手動(dòng)自己寫所在的包,寫包的全名, 如: int a = jvaa.util.Date()。
(3)同一個(gè)包下的類想使用不需要導(dǎo)包,可以直接使用。
(4)在java.lang包下的類,可以直接使用無需導(dǎo)包:(5)IDEA中導(dǎo)包快捷鍵:alt+enter
可以自己設(shè)置自動(dòng)導(dǎo)包(6)可以直接導(dǎo)入*:
在Java中的導(dǎo)包沒有包含和被包含的關(guān)系:設(shè)置目錄平級的格式(不是包含和被包含的顯示)
-
靜態(tài)導(dǎo)入
導(dǎo)入一個(gè)類下所有的靜態(tài)方法需要加static關(guān)鍵字, 否則視為導(dǎo)入類
package com.msb11; //靜態(tài)導(dǎo)入: import static java.lang.Math.*; //導(dǎo)入:java.lang下的Math類中的所有靜態(tài)的內(nèi)容 /** * @Auther: msb-zhaoss */ public class Test { //這是一個(gè)main方法,是程序的入口: public static void main(String[] args) { System.out.println(random()); System.out.println(PI); System.out.println(round(5.6)); } //在靜態(tài)導(dǎo)入后,同一個(gè)類中有相同的方法的時(shí)候,會(huì)優(yōu)先走自己定義的方法。 public static int round(double a){ return 1000; } }
11.面向?qū)ο?-封裝
-
概念
封裝就是把過程和數(shù)據(jù)包圍起來, 對數(shù)據(jù)的訪問只能通過已定義的接口。面向?qū)ο笫加谶@個(gè)基本概念,即現(xiàn)實(shí)世界可以被描繪成一系列完全自制、封裝的對象,對這些對象通過一個(gè)受保護(hù)的接口訪問其他對象。封裝是一種信息隱藏技術(shù),在java中通過關(guān)鍵字private、protected和public實(shí)現(xiàn)封裝。
什么是封裝?封裝把對象所有組成部分合在一起,封裝定義程序如何引用對象的數(shù)據(jù),封裝實(shí)際上使用方法將類的數(shù)據(jù)隱藏起來,控制用戶對類的修改和訪問數(shù)據(jù)的程度。適當(dāng)?shù)姆庋b可以程序更容易理解和維護(hù),也增強(qiáng)了程序的安全箱
-
高內(nèi)聚、低耦合
高內(nèi)聚:類的內(nèi)部數(shù)據(jù)操作細(xì)節(jié)自己完成,不允許外部干涉;
低耦合:僅對外暴露少量的方法用于使用。
隱藏對象內(nèi)部的復(fù)雜性,只對外公開簡單的接口。便于外界調(diào)用,從而提
高系統(tǒng)的可擴(kuò)展性、可維護(hù)性。通俗的說,把該隱藏的隱藏起來,該暴露
的暴露出來。這就是封裝性的設(shè)計(jì)思想。 -
封裝的好處
提高代碼的安全性
-
以屬性封裝為例:
(1)將屬性私有化,被private修飾--》加入權(quán)限修飾符,一旦加入了權(quán)限修飾符,其他人就不可以隨意的獲取這個(gè)屬性
(2)提供public修飾的方法讓別人來訪問/使用
(3)即使外界可以通過方法來訪問屬性了,但是也不能隨意訪問,因?yàn)樵蹅冊诜椒ㄖ锌梢约尤?限制條件。 -
代碼示例一
public class Girl {//女孩 //屬性: private int age; //讀取年齡: public int getAge(){ return age; } //設(shè)置年齡: public void setAge(int age){ if(age >= 30 ){ this.age = 18; }else{ this.age = age; } } }
代碼示例二: 加入構(gòu)造器
package com.msb.test2; /** * @Auther: msb-zhaoss */ public class Student { //屬性: private int age; private String name; private String sex; //加入對應(yīng)的setter和getter方法: public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getSex() { return sex; } public void setSex(String sex) { if("男".equals(sex) || "女".equals(sex) ){//sex是男 或者 是 女 this.sex = sex; }else{ this.sex = "男"; } } //加入構(gòu)造器: public Student(){ } public Student(int age,String name,String sex){ this.age = age; this.name = name; //this.sex = sex; this.setSex(sex); } }
package com.msb.test2; /** * @Auther: msb-zhaoss */ public class Test { //這是一個(gè)main方法,是程序的入口: public static void main(String[] args) { //創(chuàng)建一個(gè)Student對象: Student s1 = new Student(); s1.setName("nana"); s1.setAge(19); s1.setSex("女"); System.out.println(s1.getName()+"---"+s1.getAge()+"----"+s1.getSex()); Student s2 = new Student(18,"菲菲","asdfasdfsadf"); System.out.println(s2.getName()+"---"+s2.getAge()+"----"+s2.getSex()); } }
12.面向?qū)ο?-繼承
1.定義和用法
-
定義
類是對對象的抽象, 繼承是對類的抽象
比如學(xué)生類,教師類,員工類,他們都有姓名/年齡/都是人, 就可以抽象出一個(gè)人類
總結(jié): 繼承就是is - a 的關(guān)系,比如教師是一個(gè)人,學(xué)生是一個(gè)人
-
語法
使用 extends
public class Student extends Person
Stedent 繼承自 Person類
-
繼承的好處
-
提高代碼的復(fù)用性, 父類定義的內(nèi)容,子類可以直接拿過來用就可以了,不用代碼上反復(fù)重復(fù)定義了
注意:
父類private修飾的內(nèi)容,子類實(shí)際上也繼承,只是因?yàn)榉庋b的特性阻礙了直接調(diào)用,但是提供了間接調(diào)用的方式,可以間接調(diào)用。
便于代碼的擴(kuò)展
為了以后多態(tài)的使用
-
一個(gè)父類可以有多個(gè)子類, 但是一個(gè)子類只能有一個(gè)直接父類, 但是可以間接的繼承自其他類
-
==繼承具有傳遞性==
Student -->繼承自 Person -->繼承自O(shè)bject
Object類是所有類的根基父類。
所有的類都直接或者間接的繼承自O(shè)bject。
2.權(quán)限修飾符
private: 在當(dāng)前類中可以訪問
default: :缺省修飾符:權(quán)限:到同一個(gè)包下的其他類都可以訪問
protected:權(quán)限:最大到不同包下的子類
public:在整個(gè)項(xiàng)目中都可以訪問
-
總結(jié)
屬性,方法:修飾符:四種:private,缺省,protected,public
類:修飾符:兩種:缺省,public以后寫代碼
一般屬性:用private修飾 ,方法:用public修飾 -
圖示
權(quán)限修飾符.png
3.方法的重寫
-
定義
發(fā)生在子類和父類中,當(dāng)子類對父類提供的方法不滿意的時(shí)候,要對父類的方法進(jìn)行重寫
-
格式要求:
子類的方法名字和父類必須一致,參數(shù)列表(個(gè)數(shù),類型,順序)也要和父類一致
-
重載和重寫的區(qū)別
重載:在同一個(gè)類中,當(dāng)方法名相同,形參列表不同的時(shí)候 多個(gè)方法構(gòu)成了重載
重寫:在不同的類中,子類對父類提供的方法不滿意的時(shí)候,要對父類的方法進(jìn)行重寫。重載和重寫.png
4.supper關(guān)鍵字
-
定義
super:指的是父類的, super可以修飾屬性,可以修飾方法;
在子類的方法中,可以通過 super.屬性 super.方法 的方式,顯示的去調(diào)用父類提供的屬性,方法。在通常情況下,super.可以省略不寫:
-
需要顯式的使用supper關(guān)鍵字的地方
在特殊情況下,當(dāng)子類和父類的屬性重名時(shí),你要想使用父類的屬性,必須加上修飾符super.,只能通過super.屬性來調(diào)用
在特殊情況下,當(dāng)子類和父類的方法重名時(shí),你要想使用父類的方法,必須加上修飾符super.,只能通過super.方法來調(diào)用
在這種情況下,super.就不可以省略不寫。supper2.png
-
supper修飾構(gòu)造器
-
supper修飾構(gòu)造器的場景
其實(shí)我們平時(shí)寫的構(gòu)造器的第一行都有:super() -->作用:調(diào)用父類的空構(gòu)造器,只是我們一般都省略不寫
所有構(gòu)造器的第一行默認(rèn)情況下都有super(),但是一旦你的構(gòu)造器中顯示的使用super調(diào)用了父類構(gòu)造器,那么這個(gè)super()就不會(huì)給你默認(rèn)分配了。如果構(gòu)造器中沒有顯示的調(diào)用父類構(gòu)造器的話,那么第一行都有super(),可以省略不寫supper修飾構(gòu)造器1.png
-
-
如果構(gòu)造器中已經(jīng)顯示的調(diào)用super父類構(gòu)造器,那么它的第一行就沒有默認(rèn)分配的super();了
supper修飾構(gòu)造器2.png
-
supper和this修飾構(gòu)造器
在構(gòu)造器中,super調(diào)用父類構(gòu)造器和this調(diào)用子類構(gòu)造器只能存在一個(gè),兩者不能共存
因?yàn)閟uper修飾構(gòu)造器要放在第一行,this修飾構(gòu)造器也要放在第一行深層原因是因?yàn)樵诶^承中,先調(diào)用supper父類給屬性賦值,在調(diào)用this的話又會(huì)調(diào)用一遍supper, 重復(fù)調(diào)用
supper修飾構(gòu)造器3.png
- IDEA中快捷自動(dòng)生成構(gòu)造器: alt + insert
5.Object類
? 所有類都直接或間接的繼承自O(shè)bject類,Object類是所有Java類的根基類。
? 也就意味著所有的Java對象都擁有Object類的屬性和方法。
? 如果在類的聲明中未使用extends關(guān)鍵字指明其父類,則默認(rèn)繼承Object類。
-
Object類的toString方法
-
作用
tostring作用.png -
方法原理
tostring原理.png -
重寫toString()方法
由于使用toString方法的時(shí)候,打印出來的東西 “不好看”,對于其他人來說不友好,可讀性不好, 所以要重寫
IDEA快捷鍵 alt + insert
-
-
Object類的equals方法
-
作用
equals作用:這個(gè)方法提供了對對象的內(nèi)容是否相等 的一個(gè)比較方式,對象的內(nèi)容指的就是屬性。
父類Object提供的equals就是在比較==地址,沒有實(shí)際的意義,我們一般不會(huì)直接使用父類提供的方法,
而是在子類中對這個(gè)方法進(jìn)行重寫。重寫就是比較兩個(gè)對象所有的屬性相等才相等equals1.png
-
-
instanceof運(yùn)算符/關(guān)鍵字
語法: a instanceof b
判斷a對象是否是b這個(gè)類的實(shí)例, 是則返回true,否則返回false
-
使用IDEA工具快捷鍵自動(dòng)生成equals方法
alt + insert
5.類和類的關(guān)系
-
如何讓類和類產(chǎn)生關(guān)系
(1)將一個(gè)類作為另一個(gè)類中的方法的形參
(2)將一個(gè)類作為另一個(gè)類的屬性 -
類和類有多少種關(guān)系
-
==繼承關(guān)系==
繼承指的是一個(gè)類(稱為子類、子接口)繼承另外的一個(gè)類(稱為父類、父接口)的功能,并可以增加它自己的新功能的能力。在Java中繼承關(guān)系通過關(guān)鍵字extends明確標(biāo)識(shí),在設(shè)計(jì)時(shí)一般沒有爭議性。在UML類圖設(shè)計(jì)中,繼承用一條帶空心三角箭頭的實(shí)線表示,從子類指向父類,或者子接口指向父接口。
繼承關(guān)系.png
-
-
==實(shí)現(xiàn)關(guān)系==
實(shí)現(xiàn)指的是一個(gè)class類實(shí)現(xiàn)interface接口(可以是多個(gè))的功能,實(shí)現(xiàn)是類與接口之間最常見的關(guān)系。在Java中此類關(guān)系通過關(guān)鍵字implements明確標(biāo)識(shí),在設(shè)計(jì)時(shí)一般沒有爭議性。在UML類圖設(shè)計(jì)中,實(shí)現(xiàn)用一條帶空心三角箭頭的虛線表示,從類指向?qū)崿F(xiàn)的接口。
實(shí)現(xiàn)關(guān)系.png
-
==依賴關(guān)系==
簡單的理解,依賴就是一個(gè)類A使用到了另一個(gè)類B,而這種使用關(guān)系是具有偶然性的、臨時(shí)性的、非常弱的,但是類B的變化會(huì)影響到類A。比如某人要過河,需要借用一條船,此時(shí)人與船之間的關(guān)系就是依賴。表現(xiàn)在代碼層面,讓類B作為參數(shù)被類A在某個(gè)method方法中使用。在UML類圖設(shè)計(jì)中,依賴關(guān)系用由類A指向類B的帶箭頭虛線表示。
依賴關(guān)系.png
-
==關(guān)聯(lián)關(guān)系==
關(guān)聯(lián)體現(xiàn)的是兩個(gè)類之間語義級別的一種強(qiáng)依賴關(guān)系,比如我和我的朋友,這種關(guān)系比依賴更強(qiáng)、不存在依賴關(guān)系的偶然性、關(guān)系也不是臨時(shí)性的,一般是長期性的,而且雙方的關(guān)系一般是平等的。關(guān)聯(lián)可以是單向、雙向的。表現(xiàn)在代碼層面,為被關(guān)聯(lián)類B以類的屬性形式出現(xiàn)在關(guān)聯(lián)類A中,也可能是關(guān)聯(lián)類A引用了一個(gè)類型為被關(guān)聯(lián)類B的全局變量。在UML類圖設(shè)計(jì)中,關(guān)聯(lián)關(guān)系用由關(guān)聯(lián)類A指向被關(guān)聯(lián)類B的帶箭頭實(shí)線表示,在關(guān)聯(lián)的兩端可以標(biāo)注關(guān)聯(lián)雙方的角色和多重性標(biāo)記。
關(guān)聯(lián)關(guān)系.png
-
==聚合關(guān)系==
聚合是關(guān)聯(lián)關(guān)系的一種特例,它體現(xiàn)的是整體與部分的關(guān)系,即has-a的關(guān)系。此時(shí)整體與部分之間是可分離的,它們可以具有各自的生命周期,部分可以屬于多個(gè)整體對象,也可以為多個(gè)整體對象共享。比如計(jì)算機(jī)與CPU、公司與員工的關(guān)系等,比如一個(gè)航母編隊(duì)包括海空母艦、驅(qū)護(hù)艦艇、艦載飛機(jī)及核動(dòng)力攻擊潛艇等。表現(xiàn)在代碼層面,和關(guān)聯(lián)關(guān)系是一致的,只能從語義級別來區(qū)分。在UML類圖設(shè)計(jì)中,聚合關(guān)系以空心菱形加實(shí)線箭頭表示。
聚合關(guān)系.png
-
==組合關(guān)系==
組合也是關(guān)聯(lián)關(guān)系的一種特例,它體現(xiàn)的是一種contains-a的關(guān)系,這種關(guān)系比聚合更強(qiáng),也稱為強(qiáng)聚合。它同樣體現(xiàn)整體與部分間的關(guān)系,但此時(shí)整體與部分是不可分的,整體的生命周期結(jié)束也就意味著部分的生命周期結(jié)束,比如人和人的大腦。表現(xiàn)在代碼層面,和關(guān)聯(lián)關(guān)系是一致的,只能從語義級別來區(qū)分。在UML類圖設(shè)計(jì)中,組合關(guān)系以實(shí)心菱形加實(shí)線箭頭表示。
組合關(guān)系.png
- ==總結(jié)==
14.面向?qū)ο?-多態(tài)
1. 定義
多態(tài)跟屬性無關(guān),多態(tài)指的是方法的多態(tài),而不是屬性的多態(tài)。
先有父類,再有子類:-->繼承 先有子類,再抽取父類 ---->泛化
-
什么是多態(tài)
多態(tài)就是多種狀態(tài):同一個(gè)行為,不同的子類表現(xiàn)出來不同的形態(tài)。
多態(tài)指的就是同一個(gè)方法調(diào)用,然后由于對象不同會(huì)產(chǎn)生不同的行為。 -
多態(tài)的好處
為了提高代碼的擴(kuò)展性,符合面向?qū)ο蟮脑O(shè)計(jì)原則:開閉原則。
開閉原則:指的就是擴(kuò)展是 開放的,修改是關(guān)閉的。
注意:多態(tài)可以提高擴(kuò)展性,但是擴(kuò)展性沒有達(dá)到最好,以后我們會(huì)學(xué)習(xí) 反射 -
==多態(tài)的要素==
1). 繼承: Cat extends Animal ,Pig extends Animal, Dog extends Animal
2). 重寫:子類對父類的方法shout()重寫
3). 父類引用指向子類對象:Pig p = new Pig(); Animal an = p; //合成一句就是 Animal an = new Pig();
示例二
public void play(Animal an){//Animal an = an = new Pig(); an.shout(); } Animal an = new Pig(); g.play(an); //
上面的代碼,也是多態(tài)的一種非常常見的應(yīng)用場合:父類當(dāng)方法的形參,然后傳入的是具體的子類的對象,
然后調(diào)用同一個(gè)方法,根據(jù)傳入的子類的不同展現(xiàn)出來的效果也不同,構(gòu)成了多態(tài)===左側(cè):編譯期的類型 Animal類型
=右側(cè):運(yùn)行期的類型 Pig類型== -
多態(tài)代碼示例
1).父類-->動(dòng)物類
public class Animal {//父類:動(dòng)物: public void shout(){ System.out.println("我是小動(dòng)物,我可以叫。。。"); } }
2).子類-->小狗類
public class Dog extends Animal{ //喊叫: public void shout(){ System.out.println("我是小狗,我可以汪汪叫"); } public void guard(){ System.out.println("我是小狗,我可以看家護(hù)院,保護(hù)我的小主人。。。"); } }
3).子類-->小貓類
public class Cat extends Animal{ //喊叫方法: public void shout(){ System.out.println("我是小貓,可以喵喵叫"); } public void scratch(){ System.out.println("我是小貓,我可以撓人"); } }
4). 女孩類
public class Girl { //跟貓玩耍: /*public void play(Cat cat){ cat.shout(); }*/ //跟狗玩耍: /*public void play(Dog dog){ dog.shout(); }*/ //跟小動(dòng)物玩耍: public void play(Animal an){ an.shout(); } }
5). 程序入口
public class Test { //這是一個(gè)main方法,是程序的入口: public static void main(String[] args) { //具體的貓:--》貓的對象 //Cat c = new Cat(); //具體的小女孩:--》女孩的對象 Girl g = new Girl(); //小女孩跟貓玩: //g.play(c); //具體的狗---》狗的對象: //Dog d = new Dog(); //小女孩跟狗玩: //g.play(d); //具體的動(dòng)物:--》動(dòng)物的對象: //Cat c = new Cat(); //Dog d = new Dog(); Pig p = new Pig(); Animal an = p; g.play(an); } }
2.向上/向下轉(zhuǎn)型
在多態(tài)中, 父類類型不能直接訪問子類獨(dú)有的屬性和方法, 如果想要訪問, 就要轉(zhuǎn)型
父類往子類轉(zhuǎn)叫做向下轉(zhuǎn)型, 子類往父類轉(zhuǎn)叫做向上轉(zhuǎn)型
-
示例
轉(zhuǎn)型1.png
現(xiàn)在我就想訪問到eat()方法和weight屬性:
public class Demo {
//這是一個(gè)main方法,是程序的入口:
public static void main(String[] args) {
Pig p = new Pig();
Animal an = p;//轉(zhuǎn)型:向上轉(zhuǎn)型
an.shout();
//加入轉(zhuǎn)型的代碼:
//將Animal轉(zhuǎn)為Pig類型:
Pig pig = (Pig)an ;//轉(zhuǎn)型:向下轉(zhuǎn)型
pig.eat();
pig.age = 10;
pig.weight = 60.8;
}
}
對應(yīng)內(nèi)存
==之前的equals方法中也涉及到轉(zhuǎn)型==
3.簡單工廠模式
-
簡述
不僅可以使用父類做方法的形參,還可以使用父類做方法的返回值類型,真實(shí)返回的對象可以是該類的任意一個(gè)子類對象
簡單工廠模式的實(shí)現(xiàn),它是解決大量對象創(chuàng)建問題的一個(gè)解決方案。將創(chuàng)建和使用分開,工廠負(fù)責(zé)創(chuàng)建,使用者直接調(diào)用即可。
-
簡單工廠模式的基本要求
1). 定義一個(gè)static方法,通過類名直接調(diào)用
2). 返回值類型是父類類型,返回的可以是其任意子類類型
3). 傳入一個(gè)字符串類型的參數(shù),工廠根據(jù)參數(shù)創(chuàng)建對應(yīng)的子類產(chǎn)品
-
代碼示例
public class Test { public static void main(String[] args) { Girl g = new Girl(); //Cat c = new Cat(); //Dog d = new Dog(); //Pig p = new Pig(); Animal an = PetStore.getAnimal("狗"); g.play(an); } }
public class PetStore {//寵物店 ---》工廠類 //方法:提供動(dòng)物 public static Animal getAnimal(String petName){//多態(tài)的應(yīng)用場合(二) Animal an = null; if("貓".equals(petName)){//petName.equals("貓") --》這樣寫容易發(fā)生空指針異常 an = new Cat(); } if("狗".equals(petName)){ an = new Dog(); } if("豬".equals(petName)){ an = new Pig(); } return an; } }
14. final關(guān)鍵字
1.final修飾變量
final修飾一個(gè)基本數(shù)據(jù)類型的變量,變量的值不可以改變,這個(gè)變量也變成了一個(gè)字符常量,約定俗稱的規(guī)定:名字大寫
-
final修飾引用數(shù)據(jù)類型,那么地址值就不可以改變
final Dog d = new Dog();//final修飾引用數(shù)據(jù)類型,那么地址值就不可以改變 //d = new Dog(); -->地址值不可以更改 //d對象的屬性依然可以改變: d.age = 10; d.weight = 13.7;
-
final修飾引用數(shù)據(jù)類型后, 在方法中可以重新賦值
final Dog d2 = new Dog(); a(d2); public static void a(Dog d){ d = new Dog(); //可以重新賦值 }
-
final修飾形參, 對象不可以重新賦值
final Dog d2 = new Dog(); a(d2); public static void b(final Dog d){//d被final修飾 ,指向不可以改變 d = new Dog(); }
2.final修飾方法
- final修飾方法,那么這個(gè)方法不可以被該類的子類重寫
3.final修飾類
- final修飾類,代表沒有子類,該類不可以被繼承
- 一旦一個(gè)類被final修飾,那么里面的方法也沒有必要用final修飾了(final可以省略不寫)
5.案例: JDK提供的Math類
- 使用Math類的時(shí)候無需導(dǎo)包,直接使用即可
- 因?yàn)楸籪inal修飾, Math類沒有子類,不能被其他類繼承了
- 里面的屬性全部被final修飾,方法也是被final修飾的,只是省略不寫了
原因:子類沒有必要進(jìn)行重寫。 - ==Math構(gòu)造器被 private修飾符修飾, 所以Math不能被示例化, 不能創(chuàng)建對象==
- ==Math所有的屬性和方法都被static修飾符修飾, 只能通過 類名.方法名/類名.屬性名 去調(diào)用==
15.抽象類/抽象方法/abstract關(guān)鍵字
-
定義
使用abstract關(guān)鍵字修飾的類和方法稱為抽象類, 抽象方法需要將方法體去掉,如:
public abstract void sleep();
-
特點(diǎn):
- 如果一個(gè)類中有方法是抽象方法, 那么這個(gè)類也要變成一個(gè)抽象類
- 一個(gè)抽象類中可以有0-n個(gè)抽象方法
- 抽象類可以被其他類繼承
- 如果一個(gè)類繼承自抽象類, 那么他的子類要么也變成抽象類, 要實(shí)現(xiàn)抽閑類的所有抽象方法, 一般是重寫抽象方法
- 抽象類不可以創(chuàng)建對象
- 抽象類的子類可以創(chuàng)建對象
-
抽象類的作用
在抽象類中定義抽象方法,目的是為了為子類提供一個(gè)通用的模板,
子類可以在模板的基礎(chǔ)上進(jìn)行開發(fā),先重寫父類的抽象方法,然后可以擴(kuò)展子類自己的內(nèi)容。
抽象類設(shè)計(jì)避免了子類設(shè)計(jì)的隨意性,通過抽象類,子類的設(shè)計(jì)變得更加嚴(yán)格,進(jìn)行某些程度上的限制。
-
==面試題==
-
抽象類不能創(chuàng)建對象,那么抽象類中是否有構(gòu)造器?
抽象類中一定有構(gòu)造器。構(gòu)造器的作用 給子類初始化對象的時(shí)候要先super調(diào)用父類的構(gòu)造器。
-
抽象類是否可以被final修飾?
不能被final修飾,因?yàn)槌橄箢愒O(shè)計(jì)的初衷就是給子類繼承用的。要是被final修飾了這個(gè)抽象類了,就不存在繼承了,就沒有子類。
-
-
代碼示例
package com.msb.test03; //4.一個(gè)類中如果有方法是抽象方法,那么這個(gè)類也要變成一個(gè)抽象類。 //5.一個(gè)抽象類中可以有0-n個(gè)抽象方法 public abstract class Person { //1.在一個(gè)類中,會(huì)有一類方法,子類對這個(gè)方法非常滿意,無需重寫,直接使用 public void eat(){ System.out.println("一頓不吃餓得慌"); } //2.在一個(gè)類中,會(huì)有一類方法,子類對這個(gè)方法永遠(yuǎn)不滿意,會(huì)對這個(gè)方法進(jìn)行重寫。 //3.一個(gè)方法的方法體去掉,然后被abstract修飾,那么這個(gè)方法就變成了一個(gè)抽象方法 public abstract void say(); public abstract void sleep(); } //6.抽象類可以被其他類繼承: //7.一個(gè)類繼承一個(gè)抽象類,那么這個(gè)類可以變成抽象類 //8.一般子類不會(huì)加abstract修飾,一般會(huì)讓子類重寫父類中的抽象方法 //9.子類繼承抽象類,就必須重寫全部的抽象方法 //10.子類如果沒有重寫父類全部的抽象方法,那么子類也可以變成一個(gè)抽象類。 class Student extends Person{ @Override public void say() { System.out.println("我是東北人,我喜歡說東北話。。"); } @Override public void sleep() { System.out.println("東北人喜歡睡炕。。"); } } class Demo{ //這是一個(gè)main方法,是程序的入口: public static void main(String[] args) { //11.創(chuàng)建抽象類的對象:-->抽象類不可以創(chuàng)建對象 //Person p = new Person(); //12.創(chuàng)建子類對象: Student s = new Student(); s.sleep(); s.say(); //13.多態(tài)的寫法:父類引用只想子類對象: Person p = new Student(); p.say(); p.sleep(); } }
16.接口
1. JDK1.8之前的接口
-
接口聲明格式
[訪問修飾符] interface 接口名 [extends 父接口1,父接口2…] {
}
-
接口的特點(diǎn)
類是類, 接口是接口, 他們是同一層次的概念
接口中沒有構(gòu)造器
接口聲明關(guān)鍵字: interface
-
在JDK1.8之前, 接口中只有兩部分
-
常量: 有固定的修飾符 public static final
public static final int NUM = 10;
-
抽象方法:固定修飾符:public abstract
public abstract void a();
==注意:修飾符可以省略不寫,IDE會(huì)幫你自動(dòng)補(bǔ)全,但是初學(xué)者建議寫上,防止遺忘。==
-
-
類和接口是什么關(guān)系?
實(shí)現(xiàn)關(guān)系, 類實(shí)現(xiàn)接口
一旦實(shí)現(xiàn)一個(gè)接口, 那么實(shí)現(xiàn)類要重寫接口中的全部抽象方法
如果沒有全部重寫抽象方法, 那么這個(gè)類可以變成一個(gè)抽象類
-
==java只有單繼承, 但是可以多實(shí)現(xiàn)==
一個(gè)類只有一個(gè)父類, 但是實(shí)現(xiàn)類實(shí)現(xiàn)接口的話, 可以實(shí)現(xiàn)多個(gè)接口
這是因?yàn)槿绻麅蓚€(gè)父類中都有相同的方法的話會(huì)產(chǎn)生沖突, 接口沒有方法體, 都是要重寫的, 所以不存在這個(gè)問題
-
可以同時(shí)有繼承和接口, 順序?yàn)橄壤^承, 再實(shí)現(xiàn)
示例: extends Person implements TestInterface01,TestInterface02
-
接口的作用
- 定義規(guī)則,只是跟抽象類不同地方在哪?它是接口不是類。
- 接口定義好規(guī)則之后,實(shí)現(xiàn)類負(fù)責(zé)實(shí)現(xiàn)即可。
-
==繼承和實(shí)現(xiàn)==
繼承: 子類對父類的實(shí)現(xiàn)
實(shí)現(xiàn): 實(shí)現(xiàn)類對接口的實(shí)現(xiàn)
示例:
繼承:手機(jī) extends 照相機(jī) “is-a”的關(guān)系,手機(jī)是一個(gè)照相機(jī), 這種寫法不合適
實(shí)現(xiàn): 手機(jī) implements 拍照功能 “has-a”的關(guān)系,手機(jī)具備照相的能力, 這種比較好
-
多態(tài)的應(yīng)用場合
- 父類當(dāng)作方法的形參, 傳入具體的子類對象
- 父類當(dāng)作方法的返回值, 返回的是具體的子類對象
- 接口當(dāng)作方法的形參, 傳入具體的實(shí)現(xiàn)類對象
- 接口當(dāng)作方法的返回值, 返回的是具體的實(shí)現(xiàn)類的對象
接口不能創(chuàng)建對象, 但是可以創(chuàng)建實(shí)現(xiàn)類的對象
-
接口中常量的訪問
- 接口.常量
- 實(shí)現(xiàn)類.常量
- 實(shí)現(xiàn)類對象.常量
-
接口和抽象類的區(qū)別
接口1.png
-
代碼示例
package com.msb.test04; /** * 1.類是類,接口是接口,它們是同一層次的概念。 * 2.接口中沒有構(gòu)造器 * 3.接口如何聲明:interface * 4.在JDK1.8之前,接口中只有兩部分內(nèi)容: * (1)常量:固定修飾符:public static final * (2)抽象方法:固定修飾符:public abstract * 注意:修飾符可以省略不寫,IDE會(huì)幫你自動(dòng)補(bǔ)全,但是初學(xué)者建議寫上,防止遺忘。 */ public interface TestInterface01 { //常量: /*public static final*/ int NUM = 10; //抽象方法: /*public abstract*/ void a(); /*public abstract*/ void b(int num); /*public abstract*/ int c(String name); } interface TestInterface02{ void e(); void f(); } /* 5.類和接口的關(guān)系是什么? 實(shí)現(xiàn)關(guān)系 類實(shí)現(xiàn)接口: 6.一旦實(shí)現(xiàn)一個(gè)接口,那么實(shí)現(xiàn)類要重寫接口中的全部的抽象方法: 7.如果沒有全部重寫抽象方法,那么這個(gè)類可以變成一個(gè)抽象類。 8.java只有單繼承,java還有多實(shí)現(xiàn) 一個(gè)類繼承其他類,只能直接繼承一個(gè)父類 但是實(shí)現(xiàn)類實(shí)現(xiàn)接口的話,可以實(shí)現(xiàn)多個(gè)接口 9.寫法:先繼承 再實(shí)現(xiàn):extends Person implements TestInterface01,TestInterface02 */ class Student extends Person implements TestInterface01,TestInterface02 { @Override public void a() { System.out.println("---1"); } @Override public void b(int num) { System.out.println("---2"); } @Override public int c(String name) { return 100; } @Override public void e() { System.out.println("---3"); } @Override public void f() { System.out.println("---4"); } } class Test{ //這是一個(gè)main方法,是程序的入口: public static void main(String[] args) { //10.接口不能創(chuàng)建對象: //TestInterface02 t = new TestInterface02(); TestInterface02 t = new Student();//接口指向?qū)崿F(xiàn)類 ---》多態(tài) //11.接口中常量如何訪問: System.out.println(TestInterface01.NUM); System.out.println(Student.NUM); Student s = new Student(); System.out.println(s.NUM); TestInterface01 t2 = new Student(); System.out.println(t2.NUM); } }
2.JDK1.8之后
-
新增兩個(gè)非抽象方法
-
被public default修飾的非抽象方法
注意1: default修飾符必須要加上,否則出錯(cuò)
注意2: 實(shí)現(xiàn)類中要是想重寫接口中的非抽象方法,那么default修飾符必須不能加,否則出錯(cuò)
代碼示例:
public interface TestInterface { //常量: public static final int NUM= 10; //抽象方法: public abstract void a(); //public default修飾的非抽象方法: public default void b(){ System.out.println("-------TestInterface---b()-----"); } } class Test implements TestInterface{ public void c(){ //用一下接口中的b方法: b();//可以 //super.b();不可以 TestInterface.super.b();//可以 } @Override public void a() { System.out.println("重寫了a方法"); } @Override public void b() { } }
-
-
新增靜態(tài)態(tài)方法
注意1: static 不能省略
注意2: 靜態(tài)方法不能被重寫
代碼示例:
public interface TestInterface2 { //常量: public static final int NUM = 10; //抽象方法: public abstract void a(); //public default非抽象方法; public default void b(){ System.out.println("-----TestInterface2---b"); } //靜態(tài)方法: public static void c(){ System.out.println("TestInterface2中的靜態(tài)方法"); } } class Demo implements TestInterface2{ @Override public void a() { System.out.println("重寫了a方法"); } public static void c(){ System.out.println("Demo中的靜態(tài)方法"); } } class A { //這是一個(gè)main方法,是程序的入口: public static void main(String[] args) { Demo d = new Demo(); d.c(); Demo.c(); TestInterface2.c(); } }
-
為什么要加入非抽象方法
如果接口中只能定義抽象方法的話,那么我要是修改接口中的內(nèi)容,那么對實(shí)現(xiàn)類的影響太大了,所有實(shí)現(xiàn)類都會(huì)受到影響。
現(xiàn)在在接口中加入非抽象方法,對實(shí)現(xiàn)類沒有影響,想調(diào)用就去調(diào)用即可。
17. 內(nèi)部類
1. 成員內(nèi)部類
類的組成: 屬性,方法,構(gòu)造器,代碼塊(普通塊,靜態(tài)塊,構(gòu)造塊,同步塊),內(nèi)部類
定義: 一個(gè)類內(nèi)部的類叫內(nèi)部類: 一個(gè)類TestOuter的內(nèi)部的類SubTest叫內(nèi)部類, 內(nèi)部類 :SubTest 外部類:TestOuter
-
內(nèi)部類分類:
成員內(nèi)部類: 和方法同級
里面有成員, 方法, 構(gòu)造器等, 和外部類一樣
修飾符:private,default,protect,public,final,abstract
靜態(tài)內(nèi)部類就是加了static修飾符的內(nèi)部類
內(nèi)部類可以訪問外部類的內(nèi)容
靜態(tài)內(nèi)部類中只能訪問外部類中被static修飾的內(nèi)容
-
外部類想要訪問內(nèi)部類的東西,需要?jiǎng)?chuàng)建內(nèi)部類的對象然后進(jìn)行調(diào)用
D d = new D(); System.out.println(d.name); d.method();
-
內(nèi)部類和外部類屬性重名的時(shí)候,如何進(jìn)行調(diào)用
System.out.println(age);//30 內(nèi)部類中的方法變量 System.out.println(this.age);//20 內(nèi)不類中的變量 System.out.println(TestOuter.this.age);//10 外部類中的變量
-
內(nèi)部類創(chuàng)建對象
-
靜態(tài)成員內(nèi)部類創(chuàng)建對象
TestOuter.E e = new TestOuter.E(); # E為內(nèi)部類
-
非靜態(tài)成員內(nèi)部類創(chuàng)建對象
TestOuter t = new TestOuter();
TestOuter.D d = t.new D();
-
-
代碼示例
package com.msb.test07; /** * 1.類的組成:屬性,方法,構(gòu)造器,代碼塊(普通塊,靜態(tài)塊,構(gòu)造塊,同步塊),內(nèi)部類 * 2.一個(gè)類TestOuter的內(nèi)部的類SubTest叫內(nèi)部類, 內(nèi)部類 :SubTest 外部類:TestOuter * 3.內(nèi)部類:成員內(nèi)部類 (靜態(tài)的,非靜態(tài)的) 和 局部內(nèi)部類(位置:方法內(nèi),塊內(nèi),構(gòu)造器內(nèi)) * 4.成員內(nèi)部類: * 里面屬性,方法,構(gòu)造器等 * 修飾符:private,default,protect,public,final,abstract */ public class TestOuter { //非靜態(tài)的成員內(nèi)部類: public class D{ int age = 20; String name; public void method(){ //5.內(nèi)部類可以訪問外部類的內(nèi)容 /*System.out.println(age); a();*/ int age = 30; //8.內(nèi)部類和外部類屬性重名的時(shí)候,如何進(jìn)行調(diào)用: System.out.println(age);//30 System.out.println(this.age);//20 System.out.println(TestOuter.this.age);//10 } } //靜態(tài)成員內(nèi)部類: static class E{ public void method(){ //6.靜態(tài)內(nèi)部類中只能訪問外部類中被static修飾的內(nèi)容 /*System.out.println(age); a();*/ } } //屬性: int age = 10; //方法: public void a(){ System.out.println("這是a方法"); { System.out.println("這是一個(gè)普通塊"); class B{ } } class A{ } //7.外部類想要訪問內(nèi)部類的東西,需要?jiǎng)?chuàng)建內(nèi)部類的對象然后進(jìn)行調(diào)用 D d = new D(); System.out.println(d.name); d.method(); } static{ System.out.println("這是靜態(tài)塊"); } { System.out.println("這是構(gòu)造塊"); } //構(gòu)造器: public TestOuter(){ class C{ } } public TestOuter(int age) { this.age = age; } } class Demo{ //這是一個(gè)main方法,是程序的入口: public static void main(String[] args) { //創(chuàng)建外部類的對象: TestOuter to = new TestOuter(); to.a(); //9.創(chuàng)建內(nèi)部類的對象: //靜態(tài)的成員內(nèi)部類創(chuàng)建對象: TestOuter.E e = new TestOuter.E(); //非靜態(tài)的成員內(nèi)部類創(chuàng)建對象: //錯(cuò)誤:TestOuter.D d = new TestOuter.D(); TestOuter t = new TestOuter(); TestOuter.D d = t.new D(); } }
2.局部內(nèi)部類
package com.msb.test08;
/**
* @Auther: msb-zhaoss
*/
public class TestOuter {
//1.在局部內(nèi)部類中訪問到的變量必須是被final修飾的
public void method(){
final int num = 10;
class A{
public void a(){
//num = 20;
System.out.println(num);
}
}
}
//2.如果類B在整個(gè)項(xiàng)目中只使用一次,那么就沒有必要單獨(dú)創(chuàng)建一個(gè)B類,使用內(nèi)部類就可以了
public Comparable method2(){
class B implements Comparable{
@Override
public int compareTo(Object o) {
return 100;
}
}
return new B();
}
public Comparable method3(){
//3.匿名內(nèi)部類
return new Comparable(){
@Override
public int compareTo(Object o) {
return 200;
}
};
}
public void teat(){
Comparable com = new Comparable(){
@Override
public int compareTo(Object o) {
return 200;
}
};
System.out.println(com.compareTo("abc"));
}
}