1、為什么要有靜態(tài)類變量?
引出:
過年,公司發(fā)過年禮品,假設(shè)我們有一個禮品類Gift,有一個發(fā)放禮品的類方法receive(),我想知道當(dāng)前有多少個員工領(lǐng)取禮品,怎么辦?
解決:
1、在類中定義一個屬性count,然后在receive()里每調(diào)用該方法進(jìn)行conut++?
2、在main方法定義一個count局部變量,每調(diào)用一次receive()進(jìn)行count++?
3、在類中定義一個靜態(tài)的類變量,在方法receive()中進(jìn)行count++?
答案:選擇3!第一種不管領(lǐng)取了多少禮品,每個對象中的count屬性值都是1;第二種可以是可以,但不符合oop的思想,如果需要在別的地方用到該count值,沒辦法調(diào)用??;第三種,靜態(tài)類變量多個對象共享該變量,不管是用那個對象獲取的count值,都是最新的且一致的!
#測試代碼:
public class StaticDemo {
public static void main(String[] args) {
Gift gift = new Gift("張三");
Gift gift1 = new Gift("李四");
gift.receive();
System.out.println("當(dāng)前有"+Gift.count+"個員工領(lǐng)取了禮品"+" 名字分別為:"+ Gift.str);
gift1.receive();
System.out.println("當(dāng)前有"+gift1.count+"個員工領(lǐng)取了禮品"+" 名字分別為:"+ Gift.str);
}
}
//禮品類
class Gift{
private String name;
protected static int count;
public static String str="";
public Gift(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//發(fā)放禮品
public void receive(){
giftEliminate();
count++;
str = str.concat(getName());
}
//當(dāng)領(lǐng)取人數(shù)大于5個我就調(diào)用該方法將count清零;
public void giftEliminate(){
if (count>5){
Gift.count = 0;
}
}
}
輸出:
當(dāng)前有1個員工領(lǐng)取了禮品 名字分別為:張三
當(dāng)前有2個員工領(lǐng)取了禮品 名字分別為:張三李四
小結(jié)(什么時候使用類變量?):
1、靜態(tài)類變量的作用就是存儲一些獨(dú)立于對象的數(shù)據(jù),但各對象又能共享該變量值
2、如何定義和使用靜態(tài)類變量?
定義:
1、static public int count
2、public static int count (推薦使用)
#從上面代碼可以看出,在普通屬性上聲明一個static關(guān)鍵字,靜態(tài)類方法也是如此
使用:
1、使用類名.變量名(推薦使用) Gift.count
2、對象名.變量名 gift1.count
3、類變量于實(shí)例變量(普通類屬性)的區(qū)別?
1、類變量屬于類,但被所有對象共享
2、實(shí)例變量只屬于這一個對象,獨(dú)立不被共享
4 小結(jié):
類變量:
1、使用關(guān)鍵字static聲明定義,推薦定義格式: 修飾符 static 數(shù)據(jù)類型 變量名
2、使用類名.變量名調(diào)用該類變量
3、被所有對象共享變量值
實(shí)例變量:
1、定義:修飾符 數(shù)據(jù)類型 變量名
2、使用對象名.變量名調(diào)用該變量
3、只屬于該對象本身,不被共享
1、為什么要有靜態(tài)方法?
應(yīng)用:
當(dāng)我們要寫一個方法操作一些跟對象無關(guān)的數(shù)據(jù)時,可以使用靜態(tài)方法。
2、靜態(tài)方法的定義和使用
定義:
1、public static void print(){}
2、static void print(){}
修飾符 static 返回?cái)?shù)據(jù)類型 方法名(){}
#注意:因?yàn)樾揎椃椒ǖ男揎椃挥衟ublic 或 默認(rèn)(不寫)
使用:
1、類名.方法名() (推薦使用)
2、對象名.方法名()
代碼:
public class StaticDemo {
public static void main(String[] args) {
Student student = new Student("張三");
Student student1 = new Student("李四");
Student.count_study_money(3000);
Student.count_study_money(5000);
System.out.println("當(dāng)前學(xué)費(fèi)共交了"+Student.get_study_money()+"元");
student.print();
}
}
class Student{
public String name;
private static double study_money;
static String str="";
public Student(String name){
super();
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//計(jì)算學(xué)費(fèi)
public static void count_study_money(double study_money){
//Student.study_money = Student.study_money + study_money;
Student.study_money += study_money;
}
//返回學(xué)費(fèi)
public static double get_study_money(){
return Student.study_money;
}
public void print(){
System.out.println(get_study_money());//非靜態(tài)方法中調(diào)用靜態(tài)方法
System.out.println(name);//非靜態(tài)方法中調(diào)用非靜態(tài)變量
System.out.println(str);//非靜態(tài)方法中調(diào)用靜態(tài)變量
}
}
輸出:
當(dāng)前學(xué)費(fèi)共交了8000.0元
8000.0
張三
3、使用類方法時,有哪些要注意的細(xì)節(jié)?
1、類方法中不能使用this和super與對象相關(guān)的關(guān)鍵字。 因?yàn)閠his代表調(diào)用者當(dāng)前對象本身,而靜態(tài)方法執(zhí)行是無需實(shí)例化對象,那這個this就是空,所以靜態(tài)方法中不能用this
2、類方法和類變量調(diào)用跟對象是否創(chuàng)建無關(guān),調(diào)用時都是通過類名.類變量/類方法()調(diào)用
3、而對象變量和對象方法與實(shí)例對象有關(guān),調(diào)用對象方法和對象變量時只能用對象名.變量 或 對象名.方法名(),不能使用類名.方法和變量!
4、靜態(tài)(類)方法中只能調(diào)用靜態(tài)(類)變量和靜態(tài)方法,無法使用非靜態(tài)變量和非靜態(tài)方法
5、非靜態(tài)方法可以調(diào)用非靜態(tài)變量、非靜態(tài)方法、靜態(tài)方法、靜態(tài)變量
i
public static void main(String[] args){}
1、為什么main()方法要這樣寫?
# 因?yàn)橛辛藀ublic權(quán)限,所以jvm才能調(diào)用main;
因?yàn)橛辛藄tatic,所以調(diào)用mian()方法時不需要有對象創(chuàng)建;
因?yàn)橛辛薙tring[] args字符串?dāng)?shù)組,所以運(yùn)行main里面的程序時,可以用字符串?dāng)?shù)組去存儲中轉(zhuǎn)所需的參數(shù)!
1、代碼塊的定義
1、普通代碼塊
格式:{代碼體}
2、靜態(tài)代碼塊
static{代碼體}
2、普通代碼與靜態(tài)代碼塊的使用區(qū)別
普通代碼塊:
1、是對對象進(jìn)行初始化。每創(chuàng)建一次對象就執(zhí)行一次
靜態(tài)代碼塊:
1、是對類進(jìn)行初始化。隨著類被加載的時候就執(zhí)行了,且只會執(zhí)行一次(不管new幾個對象)
#代碼驗(yàn)證:
//午餐類
class Lunch{
public static double price=20;
//普通代碼塊
{
System.out.println("普通代碼塊:先煮飯,洗菜,炒菜");
}
//靜態(tài)代碼塊
static {
System.out.println("靜態(tài)代碼塊:先煮飯,洗菜,炒菜");
}
//無參構(gòu)造器
public Lunch() {
System.out.println("這是無參構(gòu)造器");
}
//靜態(tài)方法
public static void makeLunch(){
System.out.println("這是一個靜態(tài)方法");
}
}
public class codeBlock {
public static void main(String[] args) {
Lunch lunch = new Lunch();
Lunch lunch1 = new Lunch();
Lunch lunch2 = new Lunch();
Lunch.makeLunch();
System.out.println(Lunch.price);
}
}
輸出:
靜態(tài)代碼塊:先煮飯,洗菜,炒菜
普通代碼塊:先煮飯,洗菜,炒菜
這是無參構(gòu)造器
普通代碼塊:先煮飯,洗菜,炒菜
這是無參構(gòu)造器
普通代碼塊:先煮飯,洗菜,炒菜
這是無參構(gòu)造器
這是一個靜態(tài)方法
20.0
說明:
1、執(zhí)行順序: 靜態(tài)代碼塊——》普通代碼塊——》構(gòu)造器
2、執(zhí)行次數(shù):靜態(tài)代碼塊只執(zhí)行一次,普通代碼塊執(zhí)行次數(shù)跟對象創(chuàng)建次數(shù)一樣
3、靜態(tài)方法調(diào)用一次就執(zhí)行一次
3、觸發(fā)類加載的幾種情況(靜態(tài)代碼塊)
1、創(chuàng)建對象實(shí)例時
2、當(dāng)創(chuàng)建子類對象實(shí)例時,先加載父類,再加載子類
3、使用類的靜態(tài)成員(靜態(tài)屬性、靜態(tài)方法)
4、還有一種是反射( 我還沒學(xué)>_<...)
#代碼驗(yàn)證:
public class codeBlock02 {
public static void main(String[] args) {
new CC();
//1、創(chuàng)建對象實(shí)例時會觸發(fā)類加載,執(zhí)行靜態(tài)代碼塊。
//2、當(dāng)創(chuàng)建子類對象實(shí)例時,當(dāng)前類CC向上的所有父類AA、BB類都會觸發(fā)類加載,從而執(zhí)行對應(yīng)類的靜態(tài)代碼塊
//System.out.println(CC.str);
//1、當(dāng)調(diào)用靜態(tài)成員(靜態(tài)方法和變量)時,會觸發(fā)類加載,執(zhí)行靜態(tài)代碼塊內(nèi)容
}
}
class AA{
//普通代碼塊
{
System.out.println("普通代碼塊AA");
}
//靜態(tài)代碼塊
static {
System.out.println("靜態(tài)代碼塊AA");
}
}
class BB extends AA{
//普通代碼塊
{
System.out.println("普通代碼塊BB");
}
//靜態(tài)代碼塊
static {
System.out.println("靜態(tài)代碼塊BB");
}
}
class CC extends BB{
public static String str="這是靜態(tài)變量";
//普通代碼塊
{
System.out.println("普通代碼塊CC");
}
//靜態(tài)代碼塊
static {
System.out.println("靜態(tài)代碼塊CC");
}
public CC() {
System.out.println("這是CC的無參構(gòu)造器");
}
}
執(zhí)行new CC()輸出:
靜態(tài)代碼塊AA
靜態(tài)代碼塊BB
靜態(tài)代碼塊CC
普通代碼塊AA
普通代碼塊BB
普通代碼塊CC
這是CC的無參構(gòu)造器
執(zhí)行System.out.println(CC.str)輸出:
靜態(tài)代碼塊AA
靜態(tài)代碼塊BB
靜態(tài)代碼塊CC
這是靜態(tài)變量
說明:上面結(jié)論是正確的!
4、創(chuàng)建一個類對象時,類中靜態(tài)代碼塊、靜態(tài)變量、普通代碼塊、普通變量、構(gòu)造器的執(zhí)行順序是什么?
上代碼測試:
public class codeBlock02 {
public static void main(String[] args) {
AA aa = new AA();
}
}
class AA{
//普通變量
public int numb = getNumb();
//靜態(tài)類變量
public static String str=getStr();
//普通方法
public int getNumb(){
System.out.println("getNumb被執(zhí)行了");
return 10;
}
//靜態(tài)方法
public static String getStr(){
System.out.println("getStr()方法被執(zhí)行");
return "類變量";
}
//構(gòu)造器
public AA(){
super();//當(dāng)有父類時會執(zhí)行,沒有不執(zhí)行 <1>
<2>
System.out.println("這是AA的無參構(gòu)造器"); <3>
}
// 在<2>這里我感覺隱藏了調(diào)用普通代碼塊的引用代碼,因?yàn)槊縩ew一個對象時,執(zhí)行順序都是: <1> ---> <2> ---> <3>;
//普通代碼塊
{ System.out.println("普通代碼塊AA");}
//靜態(tài)代碼塊
static {System.out.println("靜態(tài)代碼塊AA");}
}
//輸出:
// getStr()方法被執(zhí)行 ---》靜態(tài)類變量
// 靜態(tài)代碼塊AA ---》靜態(tài)代碼塊
// getNumb被執(zhí)行了 ---》普通類變量
// 普通代碼塊AA---》普通代碼塊
// 這是AA的無參構(gòu)造器 ---》構(gòu)造器
說明什么?
1、先執(zhí)行靜態(tài)static的靜態(tài)代碼塊或靜態(tài)類變量,這兩優(yōu)先級一樣,執(zhí)行順序就看定義的位置誰先誰后
2、然后執(zhí)行普通代碼塊或普通類變量,這兩優(yōu)先級也一樣,執(zhí)行順序就看定義的位置誰先誰后
3、最后執(zhí)行構(gòu)造器
4、在構(gòu)造器中super()下面還隱藏了一段看不見的調(diào)用普通代碼塊的引用代碼
5、小練習(xí)(代碼塊)
#請問以下代碼輸出什么?
public class codeBlock01 {
public static void main(String[] args) {
new B();
}
}
class A{
//靜態(tài)屬性
public static int number_A = getA1();
//靜態(tài)代碼塊
static { System.out.println("A類靜態(tài)代碼塊");}
//普通代碼塊
{ System.out.println("A類普通代碼塊"); }
//普通屬性
public int age_A = getA2();
//父類構(gòu)造方法
public A(){
System.out.println("打印A類構(gòu)造器");
}
public static int getA1(){
System.out.println("調(diào)用了getA1方法");
return 20;
}
public int getA2(){
System.out.println("調(diào)用了getA2方法");
return 31;
}
}
class B extends A{
//靜態(tài)代碼塊
static { System.out.println("B類的靜態(tài)代碼塊"); }
//靜態(tài)屬性
public static String getStringB1 = getB1();
//普通代碼塊
{ System.out.println("B類的普通代碼塊"); }
//普通屬性
public String getStringB2 = getB2();
//子類構(gòu)造方法
public B(){
super();
System.out.println("打印A類構(gòu)造器");
}
public static String getB1(){
System.out.println("調(diào)用了getB1方法");
return "B1";
}
public String getB2(){
System.out.println("調(diào)用了getB2方法");
return "B2";
}
}
輸出:
調(diào)用了getA1方法
A類靜態(tài)代碼塊
B類的靜態(tài)代碼塊
調(diào)用了getB1方法
A類普通代碼塊
調(diào)用了getA2方法
打印A類構(gòu)造器
B類的普通代碼塊
調(diào)用了getB2方法
打印A類構(gòu)造器
6、小練習(xí)
以下程序會輸出?
public class Test {
static String s = "琳";
static {
String s = "麗";
System.out.println(s); // <1> 靜態(tài)代碼塊最先執(zhí)行,輸出麗
}
public static void main(String[] args) {
new Son(s); //把"琳"傳進(jìn)去
}
}
class Father{
static int m=100;
public Father(){ m=999;} //父類的m=999,不改變靜態(tài)變量m的值
static {
m=10000;
System.out.println("父類"+m);} // <2> 輸出:父類10000
}
class Son extends Father{
int m;
{ super.m=5;} //這里修改了父類屬性m=5
static {
System.out.println("static block"); //<3> 輸出:static block
}
public Son(String name){
System.out.println(name); //<4> 輸出: "琳"
System.out.println(m);<5> 輸出: 子類屬性沒有賦值,所以m=0;
System.out.println(super.m); <6>輸出: 5
}
}
最終輸出:麗,父類10000,static block,"琳",0,5
# 使用靜態(tài)方法和靜態(tài)屬性實(shí)現(xiàn)單例模式
# 單例模式特點(diǎn):一點(diǎn)創(chuàng)建了一個對象,之后就無法創(chuàng)建新對象,一個類只能有一個對象實(shí)例
#思路
1、限制創(chuàng)建對象
2、判斷是否已經(jīng)存在一個對象實(shí)例
代碼實(shí)現(xiàn):
public class SingletonMode {
public static void main(String[] args) {
//固定式
Singleton1 singleton1 = Singleton1.getSingleton();
Singleton1 singleton2 = Singleton1.getSingleton();
System.out.println(singleton1==singleton2);//返回true,說明成功了
//靈活式
Singleton2 singleton3 = Singleton2.getSingleton("小花");
Singleton2 singleton4 = Singleton2.getSingleton("小梅");
System.out.println(singleton3==singleton4);//返回true,說明成功了
/*
實(shí)現(xiàn)單例模式
思路:
1、限制創(chuàng)建新對象
2、判斷該類中是否已經(jīng)存在一個對象實(shí)例
*/
}
}
//實(shí)現(xiàn)一:固定式
class Singleton1{ //缺點(diǎn)就是:這個name參數(shù)值在編寫時必須寫死,那有沒有自己傳參值來new一個呢,看下一個
private String name;
private static Singleton1 singleton = new Singleton1("小琳");
//私有化構(gòu)造器
private Singleton1(String name){
super();
this.name =name;
}
//提供一個static方法獲取對象
public static Singleton1 getSingleton(){
return singleton;
}
}
//實(shí)現(xiàn)二:靈活式 可以自定義單例對象的數(shù)值
class Singleton2{
private String name;
private static Singleton2 Singleton;
//私有化構(gòu)造器
private Singleton2(String name){
super();
this.name = name;
}
//提供一個判斷對象是否存在且可以返回對象的方法
public static Singleton2 getSingleton(String name){
//判斷當(dāng)前是否存在對象
if (Singleton == null){
return Singleton = new Singleton2(name);
}
return Singleton;
}
}
小結(jié)(固定式和靈活式的區(qū)別):
對象創(chuàng)建時間上:
固定式是在類加載時就創(chuàng)建了該對象,而靈活式要調(diào)用才會創(chuàng)建對象
資源浪費(fèi)上:
固定式有可能創(chuàng)建后就沒有用過所以存在浪費(fèi)資源的可能,而靈活式就不會有這情況
靈活度上:
固定式是在編寫代碼時對象就確定了,后續(xù)不能改變,而靈活式可以在第一次創(chuàng)建對象時選擇創(chuàng)建的對象值
線程安全上:
固定式是線程安全的,靈活式是線程不安全的!
1、抽象類定義
訪問修飾符 abstract 類名{ }//沒有類實(shí)現(xiàn)
2、抽象方法定義
訪問修飾符 abstract 方法名(參數(shù)列表)//沒有方法體
3、抽象類的價值更多的體現(xiàn)在設(shè)計(jì)層面,設(shè)計(jì)者設(shè)計(jì)好抽象類讓子類繼承并實(shí)現(xiàn)抽象類的功能,更多的是充當(dāng)一個模板的作用,應(yīng)用場景更多體現(xiàn)在設(shè)計(jì)模式和框架上!
1、抽象類不能被實(shí)例化創(chuàng)建
2、抽象類中,可以有抽象方法,也可以沒有抽象方法
3、一個方法一旦聲明了成抽象方法,該方法的類也必須聲明為抽象類!總結(jié):抽象類不一定有抽象方法,但有抽象方法的類一定是抽象類
4、abstract只能修飾類和方法,不能修飾類屬性(只有抽象類和方法之說,沒有抽象屬性之說)
5、普通類里可以有的抽象類都可以有(如靜態(tài)方法、靜態(tài)屬性、靜態(tài)代碼塊、普通代碼塊),普通類里沒有的抽象方法抽象類有!
6、抽象方法沒有方法體
7、如果一個類繼承了抽象類,那就必須實(shí)現(xiàn)該抽象類的所有抽象方法,除非把自己也聲明為抽象類!
8、抽象方法不能使用private、final、static修飾。
#因?yàn)槌橄蠓椒ǘx后必須實(shí)現(xiàn),而重寫也是一種實(shí)現(xiàn)的方式,private私有化不能被重寫,final不能被繼承也就無法重寫,static靜態(tài)化方法只跟類相關(guān),沒有對象去實(shí)現(xiàn)這個抽象方法,重寫是跟對象相關(guān)的!
1、多態(tài)參數(shù):
[抽象父類的引用也可以指向繼承它的所有子類對象,所以可以使用抽象父類的引用作為形參去接收傳遞過來的所有子類對象參數(shù)] 什么意思?看下面代碼
代碼:
----------------------------------------------------------------------------------------
/* 驗(yàn)證:
多態(tài)參數(shù):接收子類對象
多態(tài)數(shù)組:存儲各個子類對象
*/
//抽象父類-寵物類
abstract class Pets{
private String name;
public Pets(String name) {
super();
this.name = name;
System.out.println(name);
}
}
//寵物狗類
class petsDog extends Pets{
public petsDog(String name){
super(name);
}
}
//寵物貓類
class petsCat extends Pets{
public petsCat(String name){
super(name);
}
}
//測試類
public class Abstract01 {
public static void main(String[] args) {
Pets cat = new petsCat("加菲貓");
Pets dog = new petsDog("旺財(cái)");
//抽象父類引用Pets可以作為形參接收petsCat("加菲貓")和petsDog("旺財(cái)")
// 這兩個子類對象實(shí)例,就證明了抽象類也具有多態(tài)參數(shù)的特性
}
}
輸出:
加菲貓
旺財(cái)
2、多態(tài)數(shù)組:
[抽象父類也可以存放所有繼承的子類對象]什么意思?看下面代碼
代碼:
/* 驗(yàn)證:
多態(tài)參數(shù):接收子類對象
多態(tài)數(shù)組:存儲各個子類對象
*/
//抽象父類-寵物類
abstract class Pets{
private String name;
public Pets(String name) {
super();
this.name = name;
System.out.println(name);
}
public String getName(){
return name;
}
//定義一個公有的抽象方法play(),玩
public abstract void play();
}
//寵物狗類
class petsDog extends Pets{
public petsDog(String name){
super(name);
}
//重寫實(shí)現(xiàn)play()方法
@Override
public void play() {
System.out.println(getName()+"可以拿來擼");
}
//狗特有行為:看大門
public void guardHome(){
System.out.println(getName()+"會幫主人看家");
}
}
//寵物貓類
class petsCat extends Pets{
public petsCat(String name){
super(name);
}
@Override
public void play(){
System.out.println(getName()+"可以拿來擼");
}
//貓?zhí)赜行袨?抓老鼠
public void captureMouse(){
System.out.println(getName()+"會抓老鼠");
}
}
//測試類
public class Abstract01 {
public static void main(String[] args) {
//在這里定義一個抽象父類Pets數(shù)組,去接收不同的子類對象
Pets[] pets = new Pets[]{new petsCat("加菲貓"),new petsDog("旺財(cái)"),};
//抽象父類引用pets去接收并存儲 new petsCat("加菲貓") 和 new petsDog("旺財(cái)")子類對象,運(yùn)行時會進(jìn)行動態(tài)綁定!
new Abstract01().getObject(pets);
}
//定義一個判斷子類對象類型的方法,并打印出對象對應(yīng)的特有方法
public void getObject(Pets[] abs){
//使用instanceof進(jìn)行子類對象類型判斷
for (Pets p:abs){
if (p instanceof petsCat){
((petsCat)p).captureMouse();
}else { //因?yàn)槌橄蟾割悷o法被實(shí)例化,所以不可能會有父類的對象出現(xiàn),對象只可能兩種類型
((petsDog) p).guardHome();
}
}
}
}
1、抽象充當(dāng)了多個子類的通用模板,子類可以在繼承抽象類的基礎(chǔ)上進(jìn)行擴(kuò)展,但子類中還是保留一定的抽象父類的行為方法
2、什么是模板設(shè)計(jì)模式?
#當(dāng)有一部分功能是確定的,一部分功能是不確定的,可以用模板設(shè)計(jì)模式設(shè)計(jì)一個抽象父類,里面定義一個抽象方法,這個抽象方法做不確定功能,確定的功能在抽象父類寫一個方法實(shí)現(xiàn)好;然后讓子類繼承并實(shí)現(xiàn)這個功能不確定的抽象方法
上代碼演示:
3、需求:我想要一個抽象類,用于計(jì)算一個方法執(zhí)行的時間(什么方法不確定,但是用于計(jì)算時間的方法確定)
//抽象計(jì)算類
//抽象計(jì)算類
abstract class Calculation{
//抽象方法
abstract public void Method();
//計(jì)算耗時的方法
public void consumeTime(){
long start_time = System.currentTimeMillis();
Method();
long end_time = System.currentTimeMillis();
System.out.println("該方法耗時為:"+(end_time-start_time));
}
}
class Son1 extends Calculation{
@Override
public void Method(){
String str = "";
for (int i = 0; i < 100000; i++) {
str += "SB";
}
}
}
class Son2 extends Calculation{
@Override
public void Method(){
StringBuffer str = new StringBuffer("");
for (int i = 0; i < 100000; i++) {
str.append("SB");
}
}
}
class Son3 extends Calculation{
@Override
public void Method(){
StringBuilder str = new StringBuilder("");
for (int i = 0; i < 100000; i++) {
str.append("SB");
}
}
}
//測試類
public class Template {
public static void main(String[] args) {
//實(shí)現(xiàn)一:
//new Son1().consumeTime();
//son1先找自己consumeTime方法,沒有就找父類consumeTime方法,
// 父類consumeTime根據(jù)動態(tài)綁定調(diào)用自己的Method方法
//new Son2().consumeTime();
//new Son3().consumeTime();
//實(shí)現(xiàn)二:
Template.test(new Son1()); //調(diào)用靜態(tài)方法:類名.方法名
new Template().test(new Son2());//調(diào)用靜態(tài)方法:對象.方法名
test(new Son3()); //因?yàn)樵摲椒ㄔ谕愔?,直接方法? }
public static void test(Calculation c){
c.consumeTime();
}
}
輸出:
該方法耗時為:12139
該方法耗時為:3
該方法耗時為:2
//說明字符串拼接操作效率:StringBuilder > StringBuffer > String;
1、接口介紹:
就是把一些沒有實(shí)現(xiàn)的方法通過接口封裝到一起,當(dāng)哪個類需要使用到接口的方法的時候,該類根據(jù)需求再具體去實(shí)現(xiàn)接口里的方法
接口定義格式:
interface 接口名{
屬性
抽象方法(接口里的方法默認(rèn)是abstract抽象的)
在jdk1.8后,接口里可以有 靜態(tài)方法 和 默認(rèn)方法的實(shí)現(xiàn)
}
實(shí)現(xiàn)接口格式:
class 類名 implements 接口名{
//可以有自己的屬性和方法,但是必須實(shí)現(xiàn)(重寫)接口的所有方法,可以跟接口隔離原則去優(yōu)化
自己屬性
自己方法
必須實(shí)現(xiàn)接口的抽象方法
}
#栗子:
//接口
interface interfaceDemo{
//接口里的屬性必須定義時給定初始值
public String str="111";
//等同public static final String str = "111"
//靜態(tài)方法
public static void print01(){
System.out.println("靜態(tài)方法");
}
//默認(rèn)方法
public default void pint02(){
System.out.println("默認(rèn)方法");
}
//抽象方法
void absMethod1();
void absMethod2();
}
//測試類
public class Interface02 {
public static void main(String[] args) {
//接口里的靜態(tài)方法直接用接口名調(diào)用,跟類的靜態(tài)方法調(diào)用一樣
interfaceDemo.print01();
//默認(rèn)方法接口自己無法使用接口名調(diào)用
//interfaceDemo.print02();
}
}
//普通類
class Ordinary implements interfaceDemo{
//實(shí)現(xiàn)一個抽象方法1還是報(bào)錯,接著實(shí)現(xiàn)方法2報(bào)錯,實(shí)現(xiàn)默認(rèn)方法后不報(bào)錯,說明要全部實(shí)現(xiàn)(包含默認(rèn)方法)
@Override
void pint02() { //一旦我把print2方法的改為默認(rèn),就報(bào)錯,而根據(jù)實(shí)現(xiàn)接口的子類方法訪問權(quán)限必須 >= 接口抽象方法的訪問權(quán)限,
//那就證明接口的抽象方法的訪問權(quán)限默認(rèn)是public
}
@Override
public void absMethod1() {
}
@Override
public void absMethod2() {
}
}
//抽象類
abstract class absClass implements interfaceDemo{
//不報(bào)錯,說明抽象類可以不用實(shí)現(xiàn)接口的抽象方法
}
//測試類
public class Interface02 {
public static void main(String[] args) {
//接口里的靜態(tài)方法直接用接口名調(diào)用,跟類的靜態(tài)方法調(diào)用一樣
interfaceDemo.print01();
//默認(rèn)方法接口自己無法使用接口名調(diào)用,只能給實(shí)現(xiàn)了接口的子類調(diào)用
//interfaceDemo.print02();
}
}
小細(xì)節(jié):
1、在jdk1.8后,接口里可以有 靜態(tài)方法 和 默認(rèn)方法的實(shí)現(xiàn) 及定義接口自己屬性
2、接口里的屬性必須定義時給定初始值,等同于常量屬性
3、接口里的靜態(tài)方法直接用接口名調(diào)用,跟類的靜態(tài)方法調(diào)用一樣
4、默認(rèn)方法接口自己無法使用接口名調(diào)用,只能給實(shí)現(xiàn)了接口的子類調(diào)用
5、實(shí)現(xiàn)接口的子類方法權(quán)限 >= 接口的抽象方法訪問權(quán)限
6、抽象類可以實(shí)現(xiàn)接口,但可以實(shí)現(xiàn)接口的抽象方法
7、接口可以繼承別的接口,但是不能繼承普通類,當(dāng)然也包含抽象類
//注意:
1、當(dāng)多個接口里如果有重名的抽象方法,不會影響使用,如果是重名的常量屬性時,調(diào)用時使用接口名.屬性名區(qū)分
1、接口其實(shí)是對java單繼承缺點(diǎn)的一種彌補(bǔ)和擴(kuò)展,讓子類有更豐富的方法和屬性,而這些屬性來源于子類實(shí)現(xiàn)接口里的抽象方法!
#栗子
package P3;
//猴子父類
class Monkey{
private String name;
public Monkey(String name){
this.name = name;
}
public String getName(){
return name;
}
//爬樹
public void climbTree(){
System.out.println(getName()+"會爬樹");
}
}
//想要給悟空加技能,會上天飛,會下海潛,使用實(shí)現(xiàn)接口的抽象方法
interface FlightClass{
public void flight();//會飛行
}
interface DivingClass{
public void diving();//會潛水
}
//孫悟空類
class sunMonkey extends Monkey implements DivingClass,FlightClass{
public sunMonkey(String name) {
super(name);
}
@Override
public void climbTree() {
super.climbTree();
}
//實(shí)現(xiàn)飛行和潛水方法
@Override
public void diving(){
System.out.println(getName()+"會潛水");
}
@Override
public void flight(){
System.out.println(getName()+"會飛行");
}
}
//測試類
public class Relation {
public static void main(String[] args) {
new sunMonkey("孫悟空").diving();
new sunMonkey("孫悟空").flight();
new sunMonkey("孫悟空").climbTree();
//接口多態(tài),跟普通類多態(tài)一樣具有多態(tài)參數(shù)和多態(tài)數(shù)組特性
test1(new sunMonkey("孫大圣"));
test2(new sunMonkey("孫大圣"));
test3(new sunMonkey("孫大圣"));
}
//在別的類的方法中去接收父類對象和實(shí)現(xiàn)接口方法的對象,這就是多態(tài)
public static void test1(Monkey monkey){
monkey.climbTree();
}
public static void test2(DivingClass divingClass){
divingClass.diving();
}
public static void test3(FlightClass flightClass){
flightClass.flight();
}
}
輸出:
孫悟空會潛水
孫悟空會飛行
孫悟空會爬樹
孫大圣會爬樹
孫大圣會潛水
孫大圣會飛行
# 接口的多態(tài)跟類的多態(tài)差不多,也有多態(tài)參數(shù)和多態(tài)數(shù)組的特性
1、多態(tài)參數(shù) 與 多態(tài)數(shù)組
代碼舉栗:
package P3;
import org.omg.CORBA.PUBLIC_MEMBER;
//游戲接口
interface IGame{
public void loading();
public void start();
public void end();
}
//游戲類
class Game{
private String gameName;
public Game(){};
public Game(String gameName){ this.gameName = gameName;}
public String getGameName(){ return gameName;}
//游戲運(yùn)行
public void runGame(IGame iGame){
//這里使用接口引用去接收實(shí)現(xiàn)該接口的類的對象,體現(xiàn)了接口的多態(tài)參數(shù)
iGame.loading();
iGame.start();
iGame.end();
}
}
//LOL
class LOL extends Game implements IGame {
public LOL(){}
public LOL(String gameName){ super(gameName);}
@Override
public void loading() {
System.out.println(getGameName()+"正在加載....");
}
@Override
public void start() {
System.out.println(getGameName()+"加載完成,可以開始游戲啦....
LOL正在關(guān)閉游戲....
CF正在加載....
CF加載完成,可以開始游戲啦....
CF正在關(guān)閉游戲....
----------------------
英雄聯(lián)盟是5v5推塔游戲
穿越火線是多人槍戰(zhàn)游戲
2、接口存在多態(tài)傳遞特性
代碼舉栗:
package p4;
import com.sun.xml.internal.ws.api.model.wsdl.WSDLOutput;
//測試類
public class Interface{
public static void main(String[] args) {
Son son = new Son();
//這是實(shí)現(xiàn)了子接口Ison的子類Son對象
ISon iSon = son;
//這里可以把son對象賦值給子接口ISon的引用,說明子接口引用是可以指向并接收Son類對象的
IFather iFather = son;
//這里可以把son對象賦值給父接口IFather的引用,說明父接口引用是可以指向并接收Son類對象的
Father father = son;
//這里可以把son對象賦值給父類Father的引用,說明父類引用是可以指向并接收Son類對象的
}
}
//父接口
interface IFather{
public void father();
}
//子接口
interface ISon extends IFather{
public void son();
}
//父類
class Father {
public void print(){
System.out.println("這是父類的print()方法");
}
}
//子類
class Son extends Father implements ISon{
@Override
public void son(){
System.out.println("這是子接口的son()方法");
}
@Override
public void father(){
System.out.println("這是父接口的father()方法");
}
}
小結(jié):
1、當(dāng)一個接口B繼承接口A,而子類b繼承父類a,而b實(shí)現(xiàn)接口B方法時,b類對象可以傳遞給接口B的所有父接口的接口引用,這就是接口的多層傳遞
3、多態(tài)參數(shù)與多態(tài)數(shù)組在使用上的區(qū)別?
1、多態(tài)數(shù)組在程序運(yùn)行時,所有繼承的子類對象或?qū)崿F(xiàn)接口抽象方法的類對象,可以以數(shù)組的方式同時傳遞多個對象給父類引用
2、而參數(shù)多態(tài)只能同時傳遞一種類對象
3、所以當(dāng)需要使用多個不同類對象時,使用多態(tài)數(shù)組;反之,使用多態(tài)參數(shù)就可以了
4、小練習(xí)
//課后小練習(xí):以下程序輸出什么?如有錯誤,請修改
interface A{ int a = 0;}
class B{ int a = 1;}
class C extends B implements A{
public void method1(){
System.out.println(a);
}
public static void main(String[] args) {
new C().method1();
}
}
解:
錯誤:調(diào)用a會有歧義。如果想調(diào)用接口的a,使用接口名A.a ; 如果想用B類的a,使用super.a
1、內(nèi)部類介紹:
#一個類中有嵌入一個完整的類結(jié)構(gòu),這個嵌套的類稱為內(nèi)部類
內(nèi)部類特點(diǎn):
1、內(nèi)部類可以直接訪問外層類的私有屬性
2、內(nèi)部類的作用域在它的外部類中
3、本質(zhì)上其實(shí)也是外部類的一個成員,其他都一樣
內(nèi)部類定義格式:
class Outer{ //外部類
class Inner{//內(nèi)部類
public void Method1(){
class Inner01{} //方法里的內(nèi)部類
}
}
}
調(diào)用內(nèi)部類格式:
new 外部類().new 內(nèi)部類().內(nèi)部類方法名或?qū)傩?
代碼舉栗:
//外部類
class A{
private int a = 1;
private void A(){
System.out.println("這是外層類的A方法");
}
//內(nèi)部類
class Inner{
public void print(){
System.out.println(a);
}
}
public static void main(String[] args) {
new A().new Inner().print();
}
}
輸出:
1
2、內(nèi)部類的分類:
*在外部類的方法中
1、局部內(nèi)部類(有類名)
2、匿名內(nèi)部類(沒有類名,這是重點(diǎn),常用)
*類似外部類的成員類
1、成員內(nèi)部類(沒用static修飾)
2、靜態(tài)內(nèi)部類(用static修飾)
1、局部內(nèi)部類的介紹:
訪問權(quán)限: 可以訪問外部類所有成員和自己的成員
位置: 定義在外部類的方法或代碼塊中
修飾符: 只能使用final常量修飾符,因?yàn)樗淖饔糜騼H限于局部方法中,局部變量不能用修飾符,但final可以
作用域: 僅在外部類的方法或代碼塊中
#使用局部內(nèi)部類舉栗:
//外部類
class A{
private int a = 1;
public void f1(){
//外部類訪問局部內(nèi)部類
};
//外部類
class C1{ public void m1(){}};
private void print(){
class LocalInnerClass{
public void LocalInnerMethod(){
System.out.println("這是局部內(nèi)部類的方法");
//局部內(nèi)部類-->訪問-->外部類成員-->直接訪問
f1();
System.out.println(a);
}
}
//如果想在外部類調(diào)用局部內(nèi)部類里的方法,這里得先這樣
new LocalInnerClass().LocalInnerMethod();
}
public static void main(String[] args) {
new A().print();
}
}
1、匿名內(nèi)部類的介紹
方式一(使用接口名new)、
//接口
interface Interface1{
public void print();
}
class Anonymous {
public void Method() {
/*這是匿名內(nèi)部類方式一、
* 解讀:
*1、編譯類型是接口Interface1,
*2、運(yùn)行類型是:
* new Interface1() {
@Override
public void print() {
System.out.println("這是匿名內(nèi)部類");
}
};
* 3、匿名內(nèi)部類是一個對象,也相當(dāng)于實(shí)現(xiàn)接口Interface1的無名子類
* */
Interface1 i = new Interface1() {
@Override
public void print() {
System.out.println("這是匿名內(nèi)部類");
}
};
i.print();
}
//測試
public static void main(String[] args) {
new Anonymous().Method();
}
}
方式二(使用類名new)、
package p4;
//接口
interface Interface1{
public void print();
}
class FatherClass{
public void test(){}
}
class Anonymous {
public void Method() {
/*這是匿名內(nèi)部類方式一、
* 解讀:
*1、可以理解為:相當(dāng)于接口Interface1的子類的實(shí)例對象
*2、編譯類型是接口Interface1,
*3、運(yùn)行類型是: class p4.Anonymous$1 表示Anonymous編號為1的內(nèi)部類
Interface1() {
@Override
public void print() {
System.out.println("這是匿名內(nèi)部類");
}
};
* 3、匿名內(nèi)部類是一個對象,也相當(dāng)于實(shí)現(xiàn)接口Interface1的無名子類
* */
Interface1 i = new Interface1() {
@Override
public void print() {
System.out.println("這是匿名內(nèi)部類方式一");
}
}; //4、匿名內(nèi)部類尾部記得加;
i.print();
System.out.println(i.getClass());
}
public void Method1(){
/*匿名內(nèi)部類方式二
* 1、可以理解為:相當(dāng)于類FatherClass的子類的實(shí)例對象
* 2、編譯類型是FatherClass類
* 3、運(yùn)行類型是: class p4.Anonymous$2 表示Anonymous編號為2的內(nèi)部類
FatherClass() {
@Override
public void test() {
System.out.println("這是匿名內(nèi)部類方式二");
}
};
* */
FatherClass father = new FatherClass() {
@Override
public void test() {
System.out.println("這是匿名內(nèi)部類方式二");
}
};father.test();
System.out.println(father.getClass());
}
//測試
public static void main(String[] args) {
new Anonymous().Method();//匿名內(nèi)部類方式一
new Anonymous().Method1();//匿名內(nèi)部類方式二
}
}
輸出:
這是匿名內(nèi)部類方式一
class p4.Anonymous$1
這是匿名內(nèi)部類方式二
class p4.Anonymous$2
2、匿名內(nèi)部類的調(diào)用特點(diǎn):
1、通過對象本身調(diào)用內(nèi)部類的方法
new FatherClass() {
@Override
public void test() {
System.out.println("這是匿名內(nèi)部類方式二");
}
}.test();
2、通過對象引用調(diào)用本身內(nèi)部的方法
FatherClass father = new FatherClass() {
@Override
public void test() {
System.out.println("這是匿名內(nèi)部類方式二");
}
};father.test();
3、匿名內(nèi)部類的應(yīng)用場景
1、當(dāng)作實(shí)參直接傳遞
代碼舉栗:
public class Anonymous01 {
public static void main(String[] args) {
Kitchen kitchen = new Kitchen();
/**
* 1、匿名內(nèi)部類只執(zhí)行一次,適合作參數(shù)進(jìn)行傳遞
* */
kitchen.rinseFood(new Soup(){
public void cooking(){
System.out.println("午餐吃陽澄湖大閘蟹");
}
public void stewSoup(){
System.out.println("加三鮮湯");
}
});
kitchen.rinseFood(new Soup() {
@Override
public void cooking() {
System.out.println("午餐吃糖醋排骨");
}
@Override
public void stewSoup() {
System.out.println("加排骨蘿卜湯");
}
});
}
}
//烹飪接口
interface ICook{ void cooking();}
//煮湯接口
interface Soup extends ICook{ void stewSoup();}
//廚房類
class Kitchen {
//洗菜方法
public void rinseFood(Soup soup){
soup.cooking();
soup.stewSoup();
}
}
輸出:
午餐吃陽澄湖大閘蟹
加三鮮湯
午餐吃糖醋排骨
加排骨蘿卜湯
4、如何使用多態(tài)機(jī)制把局部內(nèi)部類接到外部類使用
##### 1、使用接口接收
?```
package p5;
public class Test {
public static void main(String[] args) {
/**
* 1、frock類型class p5.Frock; inner類型是class p5.Frock$1InnerH3
* 2、frock.h2()返回對象類型是其實(shí)是實(shí)現(xiàn)接口InnerH3類的對象類型,
* 屬于外部類Frock的成員,所以不需要向下轉(zhuǎn)型
* */
Frock frock = new Frock();
Inner inner = frock.h2();
inner.show();
System.out.println(frock.getClass());
System.out.println(inner.getClass());
}
}
//1、使用接口把內(nèi)部類InnerH3接出來
interface Inner{ public void show();}
//使用子類把InnerH3接出來
//外部類Frock
class Frock {
int a1 = 20;
//局部內(nèi)部類
public Inner h2(){
class InnerH3 implements Inner{
int a1 = 10;
public void show(){
System.out.println("------------------");
//內(nèi)部類成員與外部類成員重名時,在內(nèi)部類調(diào)用屬性遵循就近原則
System.out.println("局部內(nèi)部類-a1:"+a1);
//調(diào)用外部類成員名使用必須 外部類名.this.重名屬性名,this.重名屬性名都不行
System.out.println("外部類屬性-a1:"+Frock.this.a1);
}
}
InnerH3 innerH3 = new InnerH3();
innerH3.show();
return innerH3;
}
}
輸出:
------------------
局部內(nèi)部類-a1:10
外部類屬性-a1:20
------------------
局部內(nèi)部類-a1:10
外部類屬性-a1:20
class p5.Frock
class p5.Frock$1InnerH3
?```
##### 2、使用抽象類接收
package p5;
public class Test1 {
public static void main(String[] args) {
/**分析:
* 1、frock1對象類型是class p5.Frock1,
* 而inner1類型是 class p5.Frock1$1InnerH3,所以需要向下轉(zhuǎn)型
* 2、 frock1.h2()返回對象是抽象類的子類,轉(zhuǎn)成抽象類類型Inner1時,所以需要向下轉(zhuǎn)型
* */
Frock1 frock1 = new Frock1();
Inner1 inner1= (Inner1) frock1.h2();
inner1.show();
System.out.println(frock1.getClass());
System.out.println(inner1.getClass());
}
}
//1、使用接口把內(nèi)部類InnerH3接出來
//interface Inner{ public void show();}
//2、使用抽象類把InnerH3接出來
abstract class Inner1{ //
/**第一步,建一個抽象類和抽象方法,
* 給h2()方法提供一個接受內(nèi)部類對象
* */
public void show(){}
}
//外部類Frock
class Frock1 {
int a1 = 20;
//局部內(nèi)部類
public Inner1 h2(){
/**
* 第二步,讓內(nèi)部類繼承抽象類,
* 然后返回內(nèi)部類對象,讓抽象類接收
* */
class InnerH3 extends Inner1{
int a1 = 10;
public void show(){
System.out.println("------------------");
//內(nèi)部類成員與外部類成員重名時,在內(nèi)部類調(diào)用屬性遵循就近原則
System.out.println("局部內(nèi)部類-a1:"+a1);
//調(diào)用外部類成員名使用必須 外部類名.this.重名屬性名,this.重名屬性名都不行
System.out.println("外部類屬性-a1:"+Frock1.this.a1);
}
}
InnerH3 innerH3 = new InnerH3();
innerH3.show();
return innerH3;
}
}
1、成員內(nèi)部類介紹:
1、顧名思義,就是定義在外部類的成員位置(除方法中外),沒有static修飾,可以直接訪問外部類的所有成員,包括私有屬性!
2、它可以使用任何訪問修飾符,因?yàn)樗牡匚粚儆诔蓡T而不是局部
3、如果成員內(nèi)部類的成員與外部類的成員有重名的,那么在內(nèi)部類調(diào)用內(nèi)部類成員,直接調(diào)用;在內(nèi)部類調(diào)用外部類重名成員時,使用 外部類名.this.重名成員名
格式長這樣:
class OtherClass{
private String str="老黃牛"
class InnerClass{
public void show(){
System.out.println("向"+str+"學(xué)習(xí)")
}
}
}
代碼舉栗(成員內(nèi)部類):
package p5;
public class Test01 {
public static void main(String[] args) {
//調(diào)用成員內(nèi)部類方式一、
OtherClass otherClass = new OtherClass();
otherClass.new InnerClass().show();
//方式二、
otherClass.Method().show();
}
}
class OtherClass{
private String str="老黃牛";
private void PMethod(){
System.out.println("我是私有方法");
}
//成員內(nèi)部類
class InnerClass{
public InnerClass show(){
//1、成員內(nèi)部類訪問外部類,直接訪問
System.out.println("向"+str+"學(xué)習(xí)");
PMethod();
return null;
}
}
public InnerClass Method(){
//2、外部類訪問成員內(nèi)部類的成員,先創(chuàng)建內(nèi)部類對象.成員
return new InnerClass();
}
}
2、如果內(nèi)部成員類被私有化了,外部其他類還是想訪問該私有成員類中的方法呢,怎么辦呢?還是用接口接出來
代碼舉栗:
方式一、接口
package p5;
import javax.jws.Oneway;
public class Test01 {
public static void main(String[] args) {
//方式一、接口
OtherClass otherClass = new OtherClass();
I i = otherClass.PMethod();
i.show();
}
}
//方式一、接口
interface I{ public void show();}
//方式二、抽象類
//abstract class ABS{ public void show(){}}
class OtherClass{
private String str="老黃牛";
public InnerClass PMethod(){
return new InnerClass();
}
//成員內(nèi)部類
private class InnerClass implements I{
public void show(){
//1、成員內(nèi)部類訪問外部類,直接訪問
System.out.println("向"+str+"學(xué)習(xí)");
PMethod();
}
}
}
輸出:
向老黃牛學(xué)習(xí)
-------------------------------------------------------------------------------
方式二、抽象類
package p5;
public class Test02 {
public static void main(String[] args) {
//方式二、抽象類
OtherClass01 otherClass01 = new OtherClass01();
ABS abs = (ABS)otherClass01.PMethod();
abs.show();
}
}
//方式二、抽象類
abstract class ABS{ public void show(){}}
//外部類
class OtherClass01{
private String str="老黃牛";
public InnerClass PMethod(){
return new InnerClass();
}
//成員內(nèi)部類
private class InnerClass extends ABS{
public void show(){
//1、成員內(nèi)部類訪問外部類,直接訪問
System.out.println("向"+str+"學(xué)習(xí)");
PMethod();
}
}
}
輸出:
向老黃牛學(xué)習(xí)
3、如果成員內(nèi)部類的成員與外部類的成員有重名的,那么調(diào)用在內(nèi)部類調(diào)用外部類成員,直接調(diào)用; 在外部類調(diào)用內(nèi)部類成員時,使用 外部類名.this.內(nèi)部類成員名
1、靜態(tài)內(nèi)部類的介紹
1、靜態(tài)內(nèi)部類 = 使用static修飾內(nèi)部類
2、跟成員內(nèi)部類其他的相同,唯一區(qū)別就是:靜態(tài)內(nèi)部類只能訪問外部類的靜態(tài)成員
2、靜態(tài)內(nèi)部類的使用方式:
package p5;
public class Test03 {
public static void main(String[] args) {
//方式二、
new OtherClass02().Method01();
//方式一
OtherClass02.Method01();
}
}
//外部類
class OtherClass02{
private static int a1 = 1;
private int a2 = 2;
static class InnerClass02{
public void Method(){
System.out.println("外部類屬性a1:"+a1);
}
}
//在外部其他類,使用靜態(tài)內(nèi)部類的Method()方法
//方式一、使用靜態(tài)方法直接調(diào)用靜態(tài)方法
public static void Method01(){
new InnerClass02().Method();
}
//方式二、使用該方法返回一個靜態(tài)內(nèi)部類對象
public InnerClass02 Method02(){
return new InnerClass02();
}
}
3、當(dāng)靜態(tài)內(nèi)部類成員與外部類成員出現(xiàn)重名時,在內(nèi)部類調(diào)用內(nèi)部類重名的成員時,直接調(diào)用; 在靜態(tài)內(nèi)部調(diào)用外部類靜態(tài)重名成員,使用外部類名.重名成員名
#這里就不寫代碼舉栗了
1、枚舉的介紹:
1、枚舉是一種特殊的類,用于表示一組常量,比如性別只有男和女,一天只有24小時等常識常量
2、使用關(guān)鍵字euum來定義,常量名使用大寫,各常量之間使用,分割。 如eunum Sex{ MAN,WOWAN; }
2、枚舉的實(shí)現(xiàn)方式:
1) 方式一、自定義枚舉
public class Custom {
public static void main(String[] args) {
//類似調(diào)用靜態(tài)屬性調(diào)用,類名.屬性名
System.out.println(Season.spring);
System.out.println(Season.summer);
System.out.println(Season.autumn);
System.out.println(Season.winter);
}
}
//自定義枚舉: 季節(jié)類
class Season{
private String name;
private String description;
//把構(gòu)造器私有化,不給外部new新的對象
private Season(String name, String description) {
this.name = name;
this.description = description;
}
//外部只能讀取不能修改
public String getName() {
return name;
}
public String getDescription() {
return description;
}
//使用static + final是為了優(yōu)化底層(不會觸發(fā)類加載,但是這里new對象還是會類加載)
public static final Season spring = new Season("春季","溫暖");
public static final Season summer = new Season("夏季","炎熱");
public static final Season autumn = new Season("秋季","肅殺");
public static final Season winter = new Season("冬季","寒冷");
@Override
public String toString() {
return "季節(jié):" + name + " 特點(diǎn):"+ description;
}
}
自定義枚舉注意點(diǎn):
1、構(gòu)造器私有化
2、本類內(nèi)部使用 static+final 創(chuàng)建一組對象,對外暴露對象
3、只提供get方法,不提供set方法
2)方式二、使用enum關(guān)鍵字
package p5;
public class Custom {
public static void main(String[] args) {
//類似調(diào)用靜態(tài)屬性調(diào)用,類名.屬性名
System.out.println(Season1.SPRING);
System.out.println(Season1.SUMMER);
System.out.println(Season1.AUTUMN);
System.out.println(Season1.WINTER);
}
}
//使用enum關(guān)鍵字實(shí)現(xiàn)枚舉
enum Season1 {
//這個必須寫到這個enum類的首行
//使用enum關(guān)鍵字,默認(rèn)會讓Season1繼承Enumeration這個類
SPRING("春季", "溫暖"),
SUMMER("夏季", "炎熱"),
AUTUMN("秋季", "肅殺"),
WINTER("冬季", "寒冷");
private String name;
private String description;
private Season1(String name, String description) {
this.name = name;
this.description = description;
}
public String getName() {
return name;
}
public String getDescription() {
return description;
}
@Override
public String toString() {
return "季節(jié):" + name + " 特點(diǎn):"+ description;
}
}
小結(jié)(用enum關(guān)鍵字實(shí)現(xiàn)枚舉注意細(xì)節(jié))
1、枚舉常量必須放在枚舉類首行
2、當(dāng)有多個枚舉對象時,使用,隔開,用;結(jié)束
3、public static final Season1 枚舉對象 = new Seson1("春天","溫暖"); 等同于 SPRING("春天","溫暖"),
1、toString: Enum類已重寫過,返回的是當(dāng)前對象名(大寫),子類可重寫該方法,用于返回自定義的對象屬性信息
2、name: 返回當(dāng)前對象名(常量名),子欸不能重寫
3、ordinal: 返回當(dāng)前對象的位置編號,默認(rèn)從0開始
4、values: 返回當(dāng)前枚舉類的所有常量
5、valueOf; 將字符串轉(zhuǎn)成枚舉對象,要求字符串必須為已存在的常量名,否則報(bào)異常
6、compareTo: 比較兩個枚舉常量的位置編號,
代碼舉栗:
package p5;
import com.sun.scenario.effect.impl.sw.sse.SSEBlend_SRC_OUTPeer;
public class Custom {
public static void main(String[] args) {
Season1 autumn = Season1.AUTUMN;
System.out.println(autumn);//這里已重寫過
System.out.println(autumn.name());//返回大寫的autumn對象名:AUTUMN
System.out.println(autumn.ordinal());//返回該對象的編號(理解下標(biāo)也行),用于
System.out.println(Season1.values());//返回該枚舉中所有對象,是一個數(shù)組類型,可迭代
Season1[] season1s = (Season1.values());
for (Season1 s:season1s){
System.out.println(s);
}
System.out.println(Season1.valueOf("SPRING"));//判斷該枚舉中是否有SPRING對象,有返回該對象信息,沒有報(bào)異常
}
}
//使用enum關(guān)鍵字實(shí)現(xiàn)枚舉
enum Season1 {
//這個必須寫到這個enum類的首行
//使用enum關(guān)鍵字,默認(rèn)會讓Season1繼承Enumeration這個類
SPRING("春季", "溫暖"),
SUMMER("夏季", "炎熱"),
AUTUMN("秋季", "肅殺"),
WINTER("冬季", "寒冷");
private String name;
private String description;
private Season1(String name, String description) {
this.name = name;
this.description = description;
}
public String getName() {
return name;
}
public String getDescription() {
return description;
}
@Override
public String toString() {
return "季節(jié):" + name + " 特點(diǎn):"+ description;
}
}
輸出:
季節(jié):秋季 特點(diǎn):肅殺
AUTUMN
2
[Lp5.Season1;@14ae5a5
季節(jié):春季 特點(diǎn):溫暖
季節(jié):夏季 特點(diǎn):炎熱
季節(jié):秋季 特點(diǎn):肅殺
季節(jié):冬季 特點(diǎn):寒冷
季節(jié):春季 特點(diǎn):溫暖
1、注解的介紹:
1、注解也稱為元數(shù)據(jù),用于修飾解釋包、類、方法、屬性、構(gòu)造器、局部變量等信息
2、和注釋一相似之處在于它不影響代碼邏輯,不同之處注解可以被編譯貨或運(yùn)行,相當(dāng)于嵌入代碼中的補(bǔ)充信息
3、使用注解主要是為了標(biāo)記過時功能、忽略警告信息等
1、用于限定某個方法,常用于重寫父類方法,該注解只能用于方法中
1、用于表示某個程序中的類、方法已過時
1、用于屏蔽編譯器的警告信息
1、在java中,有常見的8種基本數(shù)據(jù)類型,分別為byte、boolean、char、short、int、long、float、double,在工作中需要頻繁使用它們進(jìn)行各種操作。java設(shè)計(jì)者就為每個基本類型封裝了一個類并提供常見的方法,大大提高了工作效率,而這些類就是包裝類
2、基本類型 ---> 包裝類
基本數(shù)據(jù)類型 | 包裝類 |
---|---|
boolean | Boolean |
char | Character |
byte | Byte |
short | Short |
int | Integer |
long | Long |
float | Float |
double | Double |
2、裝箱與拆箱
裝箱: 基本類型 ————> 包裝類型
拆箱:包裝類型 ————> 基本類型
3、裝箱拆箱舉栗:
package p5;
public class Packaging {
public static void main(String[] args) {
int i = 10;
//手動裝箱(jdk1.5前)
Integer integer = new Integer(i);
Integer integer1 = Integer.valueOf(i);//手動裝箱調(diào)用的其實(shí)是valueOf()方法
System.out.println(integer1.getClass());
System.out.println(integer.getClass()==integer1.getClass());
//手動拆箱
int i1 = integer.intValue();//拆箱調(diào)用的是intValue()方法
System.out.println(i1);
//自動裝箱
short s = 10;
Short s1 = s;//底層調(diào)用的還是Short.ValueOf(s)
System.out.println(s1.getClass());
//自動拆箱
short s2 = s1; //底層調(diào)用的還是shortValue()進(jìn)行拆箱
System.out.println(s2);
}
}
輸出:
class java.lang.Integer
true
10
class java.lang.Short
10
1、以下輸出結(jié)果是?
public static void main(String[] args) {
Integer i = new Integer(1);
Integer i1 = new Integer(1);
System.out.println(i==i1);
//false,new開辟了新的空間,所以不是同一個對象,故false
System.out.println(i.equals(i1));
//true,底成先判斷兩對象是否為同一類型對象,在判斷兩對象的值是否相等,相等返回true,否則false
Integer m = 1;
Integer n = 1;
System.out.println(n==m);
//true,底層會先判斷該基本類型的值是否在-128~127之間,是就指向同一對象,否則new一個新對象
System.out.println(n.equals(m));
//true,底成先判斷兩對象是否為同一類型對象,在判斷兩對象的值是否相等,相等返回true,否則false
Integer x = 128;
Integer y = 128;
System.out.println(x==y);
//false,超過常量池范圍-128~127之間,new新對象,不是同一對象,故false
System.out.println(x.equals(y));
//true,底成先判斷兩對象是否為同一類型對象,在判斷兩對象的值是否相等,相等返回true,否則false
}
2、下面輸出的值是?
public static void main(String[] args){
Integer i = 127;
int i2 = 127;
System.out.println(i==i2);//true,只要比較時出現(xiàn)一個基本數(shù)據(jù)類型,比較的就是值大小
Integer i3 = 128;
int i4 = 128;
System.out.println(i3==i4);//true,只要比較時出現(xiàn)一個基本數(shù)據(jù)類型,比較的就是值大小
}
小結(jié)(包裝類)
1、當(dāng)基本數(shù)據(jù)類型與包裝類==比較時,比較的是兩對象的值
2、只要是new的對象,就不可以是同一對象
3、當(dāng)兩個包裝類對象進(jìn)行==比較時,如果對象值在-128~127之間,那就指向同一常量池對象