1.1.1 類與對象
一個問題?[Demo107.java]
張老太養了兩只貓貓:一只名字叫小白,今年3歲,白色。還有一只叫小花,今年100歲,花色。請編寫一個程序,當用戶輸入小貓的名字時,就顯示該貓的名字,年齡,顏色。如果用戶輸入的小貓名錯誤,則顯示張老太沒有這只貓貓。
//用前面學習過的知識寫出代碼
public class Demo107{
public static void main(String []args){
int a=49;//輸入的名字49,50
int cat1age=3; //第一只貓
String cat1name="小白";
String cat1color="白色";
int cat2age=100; //第二只貓
String cat2name="小花";
String cat2color="花色";
switch(a){
case '1':
System.out.println(cat1age+cat1color);
break;
case '2':
System.out.println(cat2age+cat2color);
break;
default:
System.out.println("張老太沒有這只貓!");
}
}
}
java語言是面向對象的
計算機語言的發展向接近人的思維方式演變
匯編語言 [面向機器]
c語言 [面向過程]
java語言 [面向對象]
類和對象的關系
把貓的特性提取出來-->貓類-->對象(實例)-->對象(實例)-->...
注意:從貓類到對象,目前有幾種說法:
1、創建一個對象;
2、實例化一個對象;
3、對類實例化...以后大家聽到這些說法,不要模糊。( 對象就是實例,實例就是對象)java最大的特點就是面向對象。
//定義貓類
public class Demo105{
public static void main(String []args){
//創建一個貓對象
Cat cat1=new Cat();//Cat是定義的一個數據類型
//Cat cat1;
//cat1=new Cat();// 等同于 Cat cat1=new Cat();
//訪問屬性的 對象名.屬性名字
cat1.age=3;
cat1.name="小白";
cat1.color="白色";
//創建第二只貓
Cat cat2=new Cat();
cat2.age=100;
cat2.name="小花";
cat2.color="花色";
}
}
//java中如何定義一個類?[類名的首寫字母大寫]可根據程序的需要定義類
class Cat{
//下面的就是類的成員變量/屬性
int agr;
String name;
String color;
Master myMaster;
}
//引用類型,比如建個主人類
class Master{
int age;
String name;
String address;
}
類和對象的區別和聯系
1、類是抽象的,概念的,代表一類事物,比如人類,貓類..
2、對象是具體的,實際的,代表一個具體事物
3、類對象的模板,對象是類的一個個體,實例
類 -- 如何定義類
一個全面的類定義比較復雜,如:
package 包名;
class 類名 extends 父類 implements
接口名{
成員變量;
構造方法;
成員方法;
}
要透徹的掌握類,必須要了解類的構成
class 類名{ ----> 待定...
成員變量;
}
1. 類 -- 類的成員變量 :
成員變量是類的一個組成部分,一般是基本數據類型,也可是引用類型。比如我們前面定義貓類的int age 就是成員變量。
2. 對象 -- 如何創建對象 :
創建一個對象有兩種方法
1、先聲明再創建
1 、對象聲明:類名 對象名
2 、對象創建:對象名=new 類名()
2、一步到位法
類名 對象名=new 類名()
對象--如何訪問(使用)對象的成員變量
對象名 . 變量名; // 簡單先這樣理解,以后加下控制符此表達就不準確了。
- 對象總是存在內存中的
一個小思考題[Demo.105.java]
為了讓大家加深印象,我們定義一個人類(Person)(包括名字、年齡)。用一步到位法去創建一個對象
↓
我們看看下面一段代碼:
System.out.printlin(b.age);
Person a=new Person(); → 請問:b.age究竟是多少?
a.age=10;
a.name="小明";
Person b;
b=a;
- 對象總是存在內存中的
一個小思考題[Demo106.java]
在明白對象是如何在內存中存在后,請大家再看看下面的思考題,請問會輸出什么信息?
Person1 a=new Person1();
a.age=10;
a.name="小明";
Person1 b;
b=a;
System.out.println(b.name);//輸出“小明”
b.age=200;
System.out.println(a.age);//輸出a.age為200
- 重點也是難點
類--成員方法的初步介紹
在某些情況下,我們要需要定義成員方法。比如人類:除了有一些屬性外(成員變量表示的年齡、姓名...),我們人類還有一些行為比如:可以說話、跑步..,通過學習,我們人類還可以做算術題。這時就要用成員方法才能完成。現在要求對Person類完善:
1、添加speak成員方法,輸入出:我是一個好人
2、添加jisuan成員方法,可以計算從1+..+1000的結果
3、修改jisuan成員方法,該方法可以接收一個數n,計算從1+..+n的結果
4、添加add成員方法,可以計算兩個數的和
3. 類 -- 類的成員方法 ( 成員函數 ) 定義 :
成員方法也叫成員函數,這里希望大家不要被兩個名詞搞暈了。
public 返回數據類型 方法名(參數列表)
{
語句;//方法(函數)主體
}
1、參數列表:表示成員函數輸入
2、數據類型(返回類型):表示成員函數輸出
3、函數主體:表示為了實現某一功能代碼塊
//類的調用及方法調用[Demo108.java]
public class Demo108{
public static void main(String []args){
Person p1=new Person();
p1.speak();//調用speak方法
p1.jiSuan();//調用計算方法
p1.jiSuan(200);//調用可以傳入參數的計算方法
p1.add(12,10);//調用兩個數的和
int res=p1.add2(23,34);//調用兩個數的和并返回值到res中
System.out.println("res返回值是:"+res);
System.out.println("num1+num2+num3="+p1.add3(2,2.3f,4.5f));//返回類型一定要一致否則報錯。
}
}
//定義名字的幾個方法:
//1、駝峰法 如myCry;2、下劃線法my_cry
//方法名在有不同參數的情況下可以使用同一個方法名,即有參數和沒參數的方法可以同名
class Person{ //請注意類名首寫字母應為大寫如Person為類名
int age;
String name;
//1、可以輸出我是好人方法
public void speak(){ //請注意方法名的首寫字母應為小寫如speak為方法名
System.out.println("我是一個好人");
}
//2、可以計算1+..+1000的方法
public void jiSuan(){
int result=0;
for(int i=1;i<=1000;i++){
result=result+i;
}
System.out.println("1+..+1000結果是"+result);
}
//3、帶參數的成員方法,可以輸入n值并計算1+..+n
public void jiSuan(int n){
int result=0;
for(int i=1;i<=n;i++){
result+=i;
}
System.out.println("1+..+n結果是"+result);
}
//4、計算兩個數的和
public void add(int num1,int num2){
int result=0; //與下面一句等同于return num1+num2;
result=num1+num2;
System.out.println("num1+num2="+result);
}
//5、計算兩個數的和,并將結果返回給主調(調用它的)函數
//注意:返回類型和返回結果的類型要一致
//注意:在調用某個成員方法的時候,給出的具體數值的個數
//和類型要相匹配。
public int add2(int num1,int num2){
return num1+num2;
}
//6、計算兩個float數的和,并將結果返給主調函數
public float add3(int num1,float num2,float num3){
return num1+num2+num3;
}
}
類 -- 類的成員方法(函數)--如何理解
如何理解方法這個概念,給大家舉個通俗的示例:
程序員調用方法:給方法必要的輸入,方法返回結果。
類的成員方法-- 聲明 :
public int test(int a);/*方法聲明*/
這句話的作用是聲明該方法,聲明的格式為:
訪問修飾符 數據類型 函數名(參數列表);
在給Person類添加add方法的例題中,我們看到的關鍵字return ,它的功能是把表達式的值返回的值返回給主調函數的方法。
return 表達式;
類的成員方法(函數)--特別說明
1、方法的參數列表可以是多個
案例:在Person類中編寫一個成員方法,從鍵盤輸入三個數,返回最大的那個數。
參數列表可以是多個,并且數據類型可以是任意的類型int float double char..
訪問修飾符 返回數據類型 函數名(參數列表){
語句; //函數主體
}
2、方法可以沒有返回值
案例:編寫一個函數,從控制臺輸入一個整數打印出對應的金字塔。
返回類型可以是任意的數據類型(int,float,double,char..)也可以沒有返回值void表示沒有返回值
訪問修飾符 返回數據類型 函數名(形參列表){
語句; //函數主體
}
類的成員方法(函數)--小練習
案例:編寫一個成員函數,從鍵盤輸入一個整數(1-9),打印出對應的乘法表[Demo110.java]
//實例鍵盤輸入打印乘法表[Demo110.java]
import java.io.*;
public class Demo110{
public static void main(String []args){
Cfb jiu=new Cfb();
jiu.cf();
}
}
class Cfb{
public void cf(){
try{
//輸入流,從鍵盤接收數
InputStreamReader isr=new InputStreamReader(System.in);
BufferedReader br=new BufferedReader(isr);
//給出提示
System.out.println("請輸入1-9,按0退出:");
//從控制臺讀取一行數據
String a1=br.readLine();
//把String轉為int
int num1=Integer.decode(a1);
for(int i=1;i<=num1;i++){
for(int j=1;j<=i;j++){
System.out.print(i+"×"+j+"="+(i*j)+"\t");
}
System.out.println();
}
}catch(Exception e){
e.printStackTrace();
}
}
}
案例:編寫函數,使給定的一個二維數組(3×3)轉置
類定義的完善
在介紹了成員方法后,我們類的定義就可以完善一步:
class 類名{ class 類名{ 待定
成員變量; → 成員變量; →
} 成員方法;
}
小結:1.先設計類;2.然后根據類創建對象。
小練習:
1、設計計算機類,要求如下:[Demo109.java]
屬性:品牌(Brand)、顏色(Color)、cpu型號(CPU)、內存容量(Memory)、硬盤大小(Harddisk)、價格(Price)、工作狀態(Work)
方法:打開(Open)、關閉(Close)、休眠(Sleep)
創建一個計算機對象,調用打開,關閉方法
//計算機類與對象的代碼
import java.io.*;//加載IO流包
public class Demo109{
public static void main(String []args){
Computer Pc=new Computer();
Pc.Brand="品牌";
Pc.Color="顏色";
Pc.Cpu="Cpu型號";
Pc.Memory="內存容量";
Pc.Hd="硬盤容量";
Pc.Price="價格";
Pc.Work="工作狀態";
try{
//輸入流,從鍵盤接收數
InputStreamReader isr=new InputStreamReader(System.in);
BufferedReader br=new BufferedReader(isr);
//給出提示
System.out.println("請輸入0-9控制機器");
//從控制臺讀取一行數據
String a1=br.readLine();
//把String轉為float
float num1=Float.parseFloat(a1);
if(num1==0){Pc.open();}
else if(num1==1){Pc.close();}
else if(num1==2){Pc.sleep();}
else if(num1==3){System.out.println(Pc.Brand);}
else if(num1==4){System.out.println(Pc.Color);}
else if(num1==5){System.out.println(Pc.Cpu);}
else if(num1==6){System.out.println(Pc.Memory);}
else if(num1==7){System.out.println(Pc.Hd);}
else if(num1==8){System.out.println(Pc.Price);}
else if(num1==9){System.out.println(Pc.Work);}
else {System.out.println("輸入錯誤!");}
}catch(Exception e){
e.printStackTrace();
}
}
}
class Computer{
String Brand;
String Color;
String Cpu;
String Memory;
String Hd;
String Price;
String Work;
public void open(){
System.out.println("開機");
}
public void close(){
System.out.println("關機");
}
public void sleep(){
System.out.println("休眠");
}
}
1、 采用面向對象思想設計超級馬里奧游戲人物
1.1.2 構造方法(函數)
類的構造方法介紹
什么是構造方法呢?在回答這個問題之前,我們來看一個需求:前面我們在創建人類的對象時,是先把一個對象創建好后,再給他的年齡和姓名屬性賦值,如果現在我要求,在創建人類的對象時,就直接指定這個對象的年齡和姓名,該怎么做?
↓
你可以在定義類的時候,定義一個構造方法即可。
構造方法是類的一種特殊的方法,它的主要作用是完成對新對象的初始化。它有幾個特點:
1、方法名和類名相同
2、沒有返回值
3、在創建一個類的新對象時,系統會自動的調用該類的構造方法完成對新對象的初始化。
特別說明:
一個類可以定義多個不同的構造方法。
//例人類構造方法[Demo111.java]
public class Demo111{
public static void main(String []args){
Person p1=new Person(12,"順平");//給予不同的初始值,調用的構造方法不同,構造方法雖同名,但系統會根據初始值來選定構造方法。
}
}
//定義一個人類
class Person{
int age;
String name;
//默認構造方法
public Person(){
}
//構造方法的主要用處是:初始化你的成員屬性(變量)
//構造方法
public Person(int age,String name){
System.out.println("我是構造1");
age=age;
name=name;
}
//構造方法2
public Person(String name){
System.out.println("我是構造2");
name=name;
}
}
類的默認構造方法
有些同志可能會問?親愛的老師,我們在沒有學習構造函數前不是也可以創建對象嗎?
是這樣的,如果程序員沒有定義構造方法,系統會自動生成一個默認構造方法。比如Person類Person (){};
當創建一個Person對象時Person per1=new Person();默認的構造函數就會被自動調用。
類的構造方法小結:
1 、構造方法名和類名相同;
2 、構造方法沒有返回值;
3 、主要作用是完成對新對象的初始化;
4 、在創建新對象時,系統自動的調用該類的構造方法;
5 、一個類可以有多個構造方法;
6 、每個類都有一個默認的構造方法。
類定義的改進
在提出構造方法后,我們類的定義就應該更加完善了:
class 類名{ class 類名{ class 類名{
成員變量; 成員變量; 成員變量;
} → 成員方法; → 構造方法; → 待定..
} 成員方法
}
1.1.3 this
一個問題?
請大家看一段代碼:(Demo112.java)
重點:this是屬于一個對象,不屬于類的。
java虛擬機會給每個對象分配this,代表當前對象。坦白的講,要明白this不是件容易的事
注意事項:this不能在類定義的外部使用,只能在類定義的方法中使用
/*
this的必要性
*/
public class Demo112{
public static void main(String []args){
Dog dog1=new Dog(2,"大黃");
Person p1=new Person(dog1,23,"郭德綱");
Person p2=new Person(dog1,24,"劉謙");
p1.showInfo();
p1.dog.showInfo();
}
}
//定義一個人類
class Person{
//成員變量
int age;
String name;
Dog dog;//引用類型
public Person(Dog dog,int age,String name){
//可讀性不好
//age=age;
//name=name;
this.age=age; //this.age指this代詞指定是成員變量age
this.name=name; //this.name指this代詞指定是成員變量name
this.dog=dog;
}
//顯示人名字
public void showInfo(){
System.out.println("人名是:"+this.name);
}
}
class Dog{
int age;
String name;
public Dog(int age,String name){
this.age=age;
this.name=name;
}
//顯示狗名
public void showInfo(){
System.out.println("狗名叫"+this.name);
}
}
類變量--提出問題?
提出問題的主要目的就是讓大家思考解決之道。
public class Demo113{
public static void main(String []args){
/* int total=0;
Child ch1=new Child(3,"妞妞");
ch1.joinGame();
total++;
Child ch2=new Child(4,"小小");
ch2.joinGame();
total++;
*/
Child ch1=new Child(3,"妞妞");
ch1.joinGame();
Child ch2=new Child(4,"小小");
ch2.joinGame();
Child ch3=new Child(5,"大大");
ch3.joinGame();
System.out.println("共有="+Child.total);
}
}
//定義小孩類
class Child{
int age;
String name;
//static公共函數,total是靜態變量,因此它可以被任何一個對象訪問
static int total=0;
public Child(int age,String name){
this.age=age;
this.name=name;
}
public void joinGame(){
total++;
System.out.println("有一個小孩加入了");
}
}
1.1.4 類變量、類方法
什么是類變量?
類變量是該類的所有對象共享的變量,任何一個該類的對象去訪問它時,取到的都是相同的值,同樣任何一個該類的對象去修改它時,修改的也是同一個變量。
如何定義類變量?
定義語法:
訪問修飾符 static 數據類型 變量名;
如何訪問類變量?
類名 . 類變量名 或者 對象名 . 類變量名
//類變量的程序演示[Demo114.java]
public class Demo114{
static int i=1;
static{
//該靜態區域塊只被執行一次
i++;
System.out.println("執行一次");
}
public Demo114(){ //建立Demo114()構造函數
System.out.println("執行二次");
i++;
}
public static void main(String []args){
Demo114 t1=new Demo114(); //創建t1對象實例并調用Demo114函數
System.out.println(t1.i);
Demo114 t2=new Demo114();
System.out.println(t2.i);
}
}
什么是類方法,為什么有類方法?
類方法是屬于所有對象實例的,其形式如下:
訪問修飾符 static 數據返回類型 方法名(){}
注意:類方法中不能訪問非靜態變量(類變量)。
使用:類名 . 類方法名 或者 對象名 . 類方法名
重點static靜態的方法可以訪問static靜態變量,不能訪問非靜態變量(類變量)
非靜態方法可以訪問非靜態變量(類變量)同時也可以訪問static靜態變量。
//統計總學費的程序代碼,加深static靜態的方法由靜態變量的訪問[Demo115.java]
public class Demo115{
public static void main(String []args){
//創建一個學生
Stu stu1=new Stu(29,"aa",340);
Stu stu2=new Stu(29,"aa",240);
System.out.println(Stu.getTotalFee());
}
}
//學生類
class Stu{
int age;
String name;
int fee;
static int totalFee;
public Stu(int age,String name,int fee){
this.age=age;
this.name=name;
totalFee+=fee;
}
//返回總學費[這是一個類方法(靜態方法)]
//java中規則:類變量原則上用類方法去訪問或操作
public static int getTotalFee(){
return totalFee;
}
}
類變量小結
1、什么時候需要用類變量
案例[Demo115.java]:定義學生類,統計學生共交多少錢?
用類變量,屬于公共的屬性
2、類變量與實例變量區別:
加上static稱為類變量或靜態變量,否則稱為實例變量
類變量是與類相關的,公共的屬性
實例變量屬于每個對象個體的屬性
類變量可以通過 [類名 . 類變量名] 直接訪問
類方法小結
1、什么時候需要用類方法
案例[Demo115.java]:定義學生類,統計學生共交多少錢?
類方法屬于與類相關的,公共的方法
實例方法屬于每個對象個體的方法
類方法可以通過 [類名 . 類方法名] 直接訪問
java 面向對象編程的四大特征
抽象/封裝/繼承/多態
1 抽象 :
1、簡單理解
我們在前面去定義一個類時候,實際上就是把一類事物的共有的屬性和行為提取出來,形成一個物理模型(模版)。這種研究問題的方法稱為抽象。
封裝--什么是封裝
封裝就是把抽象出來的數據和對數據的操作封裝在一起,數據被保護在內部,程序的其它部分只有通過被授權的操作(成員方法),才能對數據進行操作。
封裝--訪問控制修飾符
電視機的開關,對音量,顏色,頻道的控制是公開的,誰都可以操作,但是對機箱后蓋,主機板的操作卻不是公開的,一般是由專業維修人員來玩。那么java中如何實現這種類似的控制呢?不能隨便查看人的年齡,工資等隱私[Demo116.java]
//封裝案例[Demo116.java]
public class Demo116{
public static void main(String []args){
//創建一個職員
Clerk clerk1=new Clerk("小花",24,4567.6f);
System.out.println("名字是"+clerk1.name+"薪水"+clerk1.getSal());
}
}
//職員
class Clerk{
public String name;
//private私有的,public公有的
private int age;
private float salary;
public Clerk(String name,int age,float sal){
this.name=name;
this.age=age;
this.salary=sal;
}
//通過一個成員方法去控制和訪問私有的屬性
public float getSal(){
return this.salary;
}
}
2. 封裝 -- 訪問控制修飾符 :
java提供四種訪問控制修飾符號控制方法和變量的訪問權限:
1 、公開級別:用public修飾,對外公開
2 、受保護級別:用protected修飾,對子類和同一個包中的類公開
3 、默認級別:沒有修飾符號,向同一個包的類公開
4 、私有級別:用private修飾,只有類本身可以訪問,不對外公開
包--必要性
問題的提出,請看下面的一個場景[eclipse]
現在有兩個程序員共同開發一個java項目,程序員xiaoming希望定義一個類取名Dog,程序員xiaoqiang也想定義一個類也叫Dog。兩個程序員為此還吵了起來,怎么辦?
包 -- 三大作用
1、區分相同名字的類
2、當類很多時,可以很好的管理類
3、控制訪問范圍
包 -- 換包命令
package com. 自定義名字;
注意:打包命令一般放在文件開始處。
包--命名規范
小寫字母 比如 com.sina.shunping
包--常用的包
一個包下,包含很多的類,java中常用的包有:
java.lang.* 包 自動引入 java.util.* 工具包
java.net.* 包 網絡開發包 java.awt.* 包 窗口工具包
包--如何引入包
語法:import 包;
比如import java.awt.*;
我們引入一個包的主要目的要使用該包下的類
定義類的改進
在提出包后,我們類的定義就更加完善了:
class 類名{ class 類名{ class類名{ package包名; 待定..
成員變量; → 成員變量; → 成員變量; → class 類名{ →
} 成員方法; 構造方法; 成員變量;
} 成員方法; 構造方法;
} 成員方法;
}
3繼承--為什么有?
//功能:說明繼承的重要性
package com.abc;//包名
public class Demo117 {
public static void main(String[] args) {
Pupil p1=new Pupil();
p1.printName();
}
}
//將學生的共有屬性提取,做一個父類
class Stu{
//定義成員屬性
protected int age;
public String name;
public float fee;
private String job;//私有將不被繼承
//編程中,如果你不希望子類繼承某個屬性或方法
//則將其聲明為private即可
public void printName(){
System.out.println("名字"+this.name);
}
}
//小學生類
class Pupil extends Stu{
//交學費
public void pay(float fee){
this.fee=fee;
}
}
//幼兒
class Pre extends Pupil{
//交學費
public void pay(float fee){
this.fee=fee*1.5f;
}
}
//中學生類
class MiddleStu extends Stu{
//交學費
public void pay(float fee){
this.fee=fee*0.8f;
}
}
//大學生類
class ColStu extends Stu{
//交學費
public void pay(float fee){
this.fee=fee*0.1f;
}
}
繼承 -- 解決之道
繼承可以解決代碼復用,讓我們的編程更加靠近人類思維。當多個類存在相同的屬性(變量)和方法時,可以從這些類中抽象出父類(比如剛才的Student),在父類中定義這些相同的屬性和方法,所有的子類不需要重新定義這些屬性和方法,只需要通過extends語句來聲明繼承父類:
語法:class 子類 extends 父類
這樣,子類就會自動擁有父類定義的某些屬性和方法。
繼承--深入討論
1、父類的哪些屬性(變量)、方法被子類繼承了?并不是父類的所有屬性、方法都可以被子類繼承
父類 子類
public 屬性; public 屬性;
protected 屬性; 繼承 protected 屬性;
private 屬性; → 屬性;
屬性;
public 方法; public 方法;
protected 方法; protected 方法;
private 方法; 方法;
方法;
2、結論
從圖可以看出,父類的public修飾符的屬性和方法;protected修飾符的屬性和方法;默認修飾符屬性和方法被子類繼承了,父類的private修飾符的屬性和方法不能被子類繼承。
繼承--注意事項
1、子類最多只能繼承一個父類(指直接繼承)
2、java所有類都是Object類的子類 (所有的子類都可以逐級繼承,例:爺->父->子->孫)
3、JDK6中有202個包3777個類、接口、異常、枚舉、注釋和錯誤
4、在做開發的時候,強烈建議大家多查jdk幫助文檔
5、在使用類時,實在不知道怎么辦,多使用搜索引擎
4. 定義類的改進 :
在提出包后,我們類的定義就更加完善了:
class 類名{ class 類名{ class類名{ package包名;
成員變量; → 成員變量; → 成員變量; → class 類名{
} 成員方法; 構造方法; 成員變量;
} 成員方法; 構造方法;
} 成員方法;
} ↓
↓←←←←←←←←←←←←←←←←←←←←←←←←←
package 包名;
class 類名 extends 父類{ 待定
成員變量; → ....
構造方法;
成員方法;
}
1.1.5 方法重載(overload)和方法覆蓋(override)
1 方法重載 (overload)
按順序,我們應該講解多態,但是在講解多態前,我們必須講解方法重載和方法覆蓋(override)。
請編寫一個類(Abc),編寫方法可以接收兩個整數,返回兩個數中較大的數[Demo119.java]
//方法重載(overload)getMax
public class Demo119{
public static void main(String []args){
Abc2 abc1=new Abc2();
System.out.println(abc1.getMax(12,14));
System.out.println(abc1.getMax(24f,20f));
}
}
class Abc2{
//返回較大的整數
public int getMax(int i,int j){
if(i>j){
return i;
}else{
return j;
}
}
public float getMax(float a,float b){
if(a>b){
return a;
}else{
return b;
}
}
//如果只是返回類型不一樣,能否構成重載?不能夠構成重載
/* public double getMax(float d,double c){
if(c>d){
return c;
}else{
return d;
}
}
//如果只是控制訪問修飾符不同,能否構成重載?不能夠構成重載
protected float getMax(float c,float d){
if(c>d){
return c;
}else{
return d;
}
}*/
}
方法重載(overload) 概念
簡單的說:方法重載就是在類的同一種功能的多種實現方式,到底采用哪種方式,取決于調用者給出的參數。
注意事項:
1、方法名相同
2、方法的參數類型,個數,順序至少有一項不同
3、方法返回類型可以不同(只是返回類型不一樣,不能構成重載)
4、方法的修飾符可以不同(只是控制訪問修飾符不同,不能構成重載)
2 方法覆蓋 (override)
既然子類可以繼承父類的屬性和方法,這樣可以提高代碼的復用性,這個很好,可是問題來了,假設現在我要求大家寫三個類貓貓,狗狗,豬豬。我們知道這三個東東都是動物,動物必然存在相同的特點。根據類的抽象特征,我們可以把它們的相同點提取出來,形成一個父類,然后繼承。
//子類方法覆蓋父類方法[Demo120.java]
public class Demo120{
public static void main(String []args){
//創建一只貓
Cat cat1=new Cat();
cat1.cry();
Dog dog1=new Dog();
dog1.cry();
}
}
//動物類
class Animal{
int age;
String name;
//都會叫
public void cry(){
System.out.println("我是動物,不知道怎么叫");
}
}
//貓貓類
class Cat extends Animal{
//覆蓋父類方法
public void cry(){
System.out.println("貓貓叫!");
}
}
//狗狗類
class Dog extends Animal{
//覆蓋父類方法
public void cry(){
System.out.println("汪汪叫!");
}
}
方法覆蓋(override)概念
簡單的說:方法覆蓋就是子類有一個方法,和父類的某個方法的名稱、返回類型、參數一樣,那么我們就說子類的這個方法覆蓋了父類的那個方法。比如上個案例的Cat類中的cry方法就覆蓋了Animal類的cry方法。
注意事項:
方法覆蓋有很多條件,有些書上說的比較細,總的講有兩點一定注意:
1、子類的方法的返回類型,參數,方法名稱,要和父類的返回類型,參數,方法名稱完全一樣,否則編譯出錯。
2、子類方法不能縮小父類方法的訪問權限。
===============================================================================
作業:上機實習題目
1、Josephu問題(丟手帕問題)
Josephu問題為:設編號為1,2,...n的n個人圍坐一圈,約定編號為k(1<=k<=n)的人從1開始報數,數到m的那個人出列,它的下一位又從1開始報數,數到m的那個人又出列,依次類推,直到所有人出列為止,由此產生一個出隊編號的序列。
提示:用一個不帶頭結點的循環鏈表來處理Josephu問題:先構成一個有n個結點的單循環鏈表,然后由k結點起從1開始計數,計到m時,對應結點的人從鏈表中刪除,然后再從被刪除結點的下一個結點又從1開始計數,直到最后一個結點從鏈表中刪除算法結束。
//Josephu問題(丟手帕問題)
//使用單向鏈表
public class Demo121 {
public static void main(String[] args) {
CycLink cyclink=new CycLink();
cyclink.setLen(5);//鏈表長度
cyclink.createLink();
cyclink.setK(2);//從第幾個人開始數
cyclink.setM(2);//數幾下
cyclink.show();
cyclink.play();
}
}
class Child{
int no;
Child nextChild=null;
public Child(int no){
//給一個編號
this.no=no;
}
}
//單向環形鏈表
class CycLink{
//先定義一個指向鏈表第一個小孩的引用
//指向第一個小孩的引用,不能動
Child firstChild=null;
Child temp=null;
int len=0;//表示共有多少個小孩
int k=0;
int m=0;
//設置m數幾下
public void setM(int m){
this.m=m;
}
//設置環形鏈表大小
public void setLen(int len){
this.len=len;
}
//設置從第幾個人開始數數
public void setK(int k){
this.k=k;
}
//開始play
public void play(){
Child temp=this.firstChild;
//1.先找到開始數數的人
for(int i=1;i<k;i++){
temp=temp.nextChild;
}
while(this.len!=1){
//2.數m下
for(int j=1;j<m;j++){
temp=temp.nextChild;
}
//找到要出圈的前一個小孩
Child temp2=temp;
while(temp2.nextChild!=temp){
temp2=temp2.nextChild;
}
//3.將數到m的小孩,退出圈
temp2.nextChild=temp.nextChild;
//讓temp指向下一個數數的小孩
temp=temp.nextChild;
this.len--;
}
//最后一個小孩
System.out.println("最后出圈的小孩:"+temp.no);
}
//初始化單向環形鏈表
public void createLink(){
for(int i=1;i<=len;i++){
if(i==1){
//創建第一個小孩
Child ch=new Child(i);
this.firstChild=ch;
this.temp=ch;
}else{
//創建最后一個小孩
if(i==len){
Child ch=new Child(i);
temp.nextChild=ch;
temp=ch;
temp.nextChild=this.firstChild;
}else{
//繼續創建小孩
Child ch=new Child(i);
temp.nextChild=ch;
temp=ch;
}
}
}
}
//打印該環形鏈表
public void show(){
//定義一個跑龍套
Child temp=this.firstChild;
do{
System.out.print(temp.no+" ");
temp=temp.nextChild;
}while(temp!=this.firstChild);
}
}
1.1.6 四大特征
1多態-- 概念
所謂多態,就是指一個引用(類型)在不同情況下的多種狀態。也可以理解成:多態是指通過指向父類的指針,來調用在不同子類中實現的方法。
實現多態有兩種方式:1、繼承;2、接口
多態演示[Dome122.java]
//演示繼承、方法覆蓋、多態
public class Demo122 {
public static void main(String[] args) {
//非多態演示
Cat cat=new Cat();
cat.cry();
Dog dog=new Dog();
dog.cry();
//多態演示
Animal an=new Cat();
an.cry();
an=new Dog();
an.cry();
}
}
//動物類
class Animal{
String name;
int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
//動物會叫
public void cry(){
System.out.println("不知道怎么叫");
}
}
//創建Dog子類并繼承Animal父類及覆蓋cry方法
class Dog extends Animal{
//狗叫
public void cry(){
System.out.println("汪汪叫");
}
}
class Cat extends Animal{
//貓自己叫
public void cry(){
System.out.println("貓貓叫");
}
}
2 多重多態演示[Dome123.java]
//演示子類繼承父類、方法覆蓋、多態方法
public class Demo123 {
public static void main(String[] args) {
//非多態演示
System.out.println("非多態演示:");
Cat cat=new Cat();
cat.cry();
Dog dog=new Dog();
dog.cry();
System.out.println();
//多態演示
System.out.println("多態演示:");
Animal an=new Cat();
an.cry();
an=new Dog();
an.cry();
System.out.println();
//多重多態演示
System.out.println("多重多態演示:");
Master master=new Master();
master.feed(new Dog(),new Bone());
master.feed(new Cat(),new Fish());
}
}
//主人類
class Master{
//給動物喂食物,使用多態,只要寫一個方法
public void feed(Animal an,Food f){
an.eat();
f.showName();
}
}
//食物父類
class Food{
String name;
public void showName(){
System.out.println("食物");
}
}
//食物魚子類
class Fish extends Food{
public void showName(){
System.out.println("魚");
}
}
//食物骨頭子類
class Bone extends Food{
public void showName(){
System.out.println("骨頭");
}
}
//動物類Animal父類
class Animal{
String name;
int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
//動物會叫
public void cry(){
System.out.println("不知道怎么叫");
}
//動物吃東西
public void eat(){
System.out.println("不知道吃什么");
}
}
//創建Dog子類并extends繼承Animal父類及覆蓋cry方法
class Dog extends Animal{
//狗叫
public void cry(){
System.out.println("汪汪叫");
}
//狗吃東西
public void eat(){
System.out.println("狗愛吃骨頭");
}
}
class Cat extends Animal{
//貓自己叫
public void cry(){
System.out.println("貓貓叫");
}
//貓吃東西
public void eat(){
System.out.println("貓愛吃魚");
}
}
3 多態 -- 注意事項:
1、java允許父類的引用變量引用它的子類的實例(對象)
Animal an=new Cat();//這種轉換時自動完成的
2、關于類型轉換還有一些具體的細節要求,我們在后面還要提,比如子類能不能轉換成父類,有什么要求等等...
1.1.7 抽象類
1 抽象類 -- 解決之道
當父類的一些方法不能確定時,可以用abstract關鍵字來修飾該方法[抽象方法],用abstract來修飾該類[抽象類]。
//抽象類的必要性[Demo124.java]
public class Demo124 {
public static void main(String[] args) {
//Animal an=new Animal();抽象類不允許實例化
Animal an=new Cat();
an.cry();
an=new Dog();
an.cry();
}
}
//抽象類abstract關鍵詞
abstract class Animal{
String name;
int age;
//動物會叫,使用了abstract抽象方法
abstract public void cry();//抽象類中可以沒有abstract抽象方法
//抽象類內可以有實現方法
public void sx(){
System.out.println("實現方法");
}
}
//當一個子類繼承的父類是abstract抽象類的話,需要程序員把抽象類的抽象方法全部實現。
class Cat extends Animal{
//實現父類的cry,其實類似上節學習中的子類覆蓋父類
public void cry(){
System.out.println("貓貓叫");
}
}
class Dog extends Animal{
//實現父類的cry,其實類似上節學習中的子類覆蓋父類
public void cry(){
System.out.println("汪汪叫");
}
}
2 抽象類 -- 深入討論
抽象類是java中一個比較重要的類。
1 、用abstract關鍵字來修飾一個類時,這個類就是抽象類。
2 、用abstract關鍵字來修飾一個方法時,這個方法就是抽象方法。
3 、abstract抽象類中的abstract抽象方法是不允許在抽象類中實現的,一旦實現就不是抽象方法和抽象類了。abstract抽象方法只能在子類中實現。
4 、抽象類中可以擁有實現方法。
5、抽象方法在編程中用的不是很多,但是在公司筆試時,卻是考官比較愛問的知識點。
3 抽象類****--****注意事項
1 、抽象類不能被實例化
2 、抽象類不一定要包含abstract方法。也就是說,抽象類可以沒有abstract抽象方法。
3 、一旦類包含了abstract抽象方法,則這個類必須聲明為abstract抽象類。
4 、抽象方法不能有主體。
正確的抽象方法例:abstract void abc();
錯語的抽象方法例:abstract void abc(){}
1.1.8 接口
1 接口 -- 為什么有?
USB插槽就是現實中的接口。
什么是接口?
接口就是給出一些沒有內容的方法,封裝到一起,到某個類要使用的時候,在根據具體情況把這些方法寫出來。
接口的建立語法:interface 接口名 { 方法;}
語法:class 類名 implements 接口 {
方法;
變量;
}
小結:接口是更加抽象的抽象的類,抽象類里的方法可以有方法體,接口里的所有方法都沒有方法體。接口體現了程序設計的多態和高內聚低偶合的設計思想。
2 接口 -- 注意事項
1、接口不能被實例化
2、接口中所有的方法都不能有主體。錯誤語法例:void aaa(){}←(注意不能有花括號)
接口可以看作更加抽象的抽象類。
3、一個類可以實現多個接口
4、接口中可以有變量[但變量不能用private和protected修飾]
a、接口中的變量,本質上都是static的而且是final類型的,不管你加不加static修飾
b、在java開發中,我們經常把常用的變量,定義在接口中,作為全局變量使用
訪問形式:接口名 . 變量名
5、一個接口不能繼承其它的類,但是可以繼承別的接口
//接口的實現[Demo125.java]
//電腦,相機,u盤,手機
//usb接口
interface Usb{
int a=1;//加不加static都是靜態的,不能用private和protected修飾
//聲明了兩個方法
public void start();//接口開始工作
public void stop();//接口停止工作
}
//編寫了一個相機類,并實現了usb接口
//一個重要的原則:當一個類實現了一個接口,要求該類把這個接口的所有方法全部實現
class Camera implements Usb{
public void start(){
System.out.println("我是相機,開始工作了..");
}
public void stop(){
System.out.println("我是相機,停止工作了..");
}
}
//接口繼承別的接口
class Base{
}
interface Tt{
}
interface Son extends Tt{
}
//編寫了一個手機,并實現了usb接口
class Phone implements Usb{
public void start(){
System.out.println("我是手機,開始工作了..");
}
public void stop(){
System.out.println("我是手機,停止工作了..");
}
}
//計算機
class Computer{
//開始使用usb接口
public void useUsb(Usb usb){
usb.start();
usb.stop();
}
}
public class Demo125 {
public static void main(String[] args) {
System.out.println(Usb.a);
//創建 Computer
Computer computer=new Computer();
//創建Camera
Camera camera1=new Camera();
//創建Phone
Phone phone1=new Phone();
computer.useUsb(camera1);
computer.useUsb(phone1);
}
}
3 定義類的改進
有了接口,我們類的定義就更加完善了:
class 類名{ class 類名{ class類名{ package包名;
成員變量; → 成員變量; → 成員變量; → class 類名{
} 成員方法; 構造方法; 成員變量;
} 成員方法; 構造方法;
} 成員方法;
} ↓
↓←←←←←←←←←←←←←←←←←←←←←←←←←
package 包名; package 包名;
class 類名 extends 父類{ class 類名 extends 父類 implements 接口名{
成員變量; → 成員變量;
構造方法; 構造方法;
成員方法; 成員方法;
} }
4 實現接口VS繼承類
java的繼承是單繼承,也就是一個類最多只能有一個父類,這種單繼承的機制可保證類的純潔性,比C++中的多繼承機制簡潔。但是不可否認,對子類功能的擴展有一定影響。所以:
1、實現接口可以看作是對繼承的一種補充。(繼承是層級式的,不太靈活。修改某個類就會打破繼承的平衡,而接口就沒有這樣的麻煩,因為它只針對實現接口的類才起作用)
2、實現接口可在不打破繼承關系的前提下,對某個類功能擴展,非常靈活。
//實例:建立子類并繼承了父類且連接多個接口[Demo126.java]
public class Demo126 {
public static void main(String[] args) {
System.out.println("繼承了Monkey父類");
Monkey mo=new Monkey();
mo.jump();
LittleMonkey li=new LittleMonkey();
li.swimming();
li.fly();
}
}
//接口Fish
interface Fish{
public void swimming();
}
//接口Bird
interface Bird{
public void fly();
}
//建立Monkey類
class Monkey{
int name;
//猴子可以跳
public void jump(){
System.out.println("猴子會跳!");
}
}
//建立LittleMonkey子類并繼承了Monkey父類并連接了Fish和Bird接口
class LittleMonkey extends Monkey implements Fish,Bird{
public void swimming() {
System.out.println("連接了Fish接口!");
}
public void fly() {
System.out.println("連接了Bird接口!");
}
}
5 用接口實現多態--案例[Demo127.java]
java中多態是個難以理解的概念,但同時又是一個非常重要的概念。java三大特性之一(繼承,封裝,多態),我們可以從字面上簡單理解:就是一種類型的多種狀態,以下通過賣小汽車的例子說明什么是多態。
//用接口實現多態
public class Demo127 {
public static void main(String []args){
CarShop aShop=new CarShop();
//賣出一輛寶馬
aShop.sellCar(new BMW());
//賣出一輛奇瑞QQ
aShop.sellCar(new CheryQQ());
//賣出一輛桑塔納
aShop.sellCar(new Santana());
System.out.println("總收入:"+aShop.getMoney());
}
}
//汽車接口
interface Car{
//汽車名稱
String getName();
//獲得汽車售價
int getPrice();
}
//寶馬
class BMW implements Car{
public String getName(){
return "BMW";
}
public int getPrice(){
return 300000;
}
}
//奇瑞QQ
class CheryQQ implements Car{
public String getName(){
return "CheryQQ";
}
public int getPrice(){
return 20000;
}
}
//桑塔納汽車
class Santana implements Car{
public String getName(){
return "Santana";
}
public int getPrice(){
return 80000;
}
}
//汽車出售店
class CarShop{
//售車收入
private int money=0;
//賣出一部車
public void sellCar(Car car){
System.out.println("車型:"+car.getName()+"單價:"+car.getPrice
());
//增加賣出車售價的收入
money+=car.getPrice();
}
//售車總收入
public int getMoney(){
return money;
}
}
運行結果:
車型:BMW 單價:300000
車型:CheryQQ 單價:20000
總收入:320000
繼承是多態得以實現的基礎。從字面上理解,多態就是一種類型(都是Car類型)表現出多種狀態(寶馬汽車的名稱是BMW,售價是300000;奇瑞汽車的名稱是CheryQQ,售價是2000)。將一個方法調用同這個方法所屬的主體(也就是對象或類)關聯起來叫做綁定,分前期綁這下和后期綁定兩種。下面解釋一下它們的定義:
1 、前期綁定:在程序運行之前進行綁定,由編譯器和連接程序實現,又叫做靜態綁定。比如static方法和final方法,注意,這里也包括private方法,因為它是隱式final的。
2 、后期綁定:在運行時根據對象的類型進行綁定,由方法調用機制實現,因此又叫做動態綁定,或者運行時綁定。除了前期綁定外的所有方法都屬于后期綁定。
多態就是在后期綁定這種機制上實現的。多態給我們帶來的好處是消除了類之間的偶合關系,使程序更容易擴展。比如在上例中,新增加一種類型汽車的銷售。只需要讓新定義的類實現Car類并實現它的所有方法,而無需對原有代碼做任何修改,CarShop類的sellCar(Car
car)方法就可以處理新的車型了。
新增代碼如下:
java代碼
//桑塔納汽車
class Santana implements Car{
public String getName(){
return "Santana";
}
public int getPrice(){
return 80000;
}
}
1.1.9 final
final概念
final中文意思:最后的,最終的。
final可以修飾變量或者方法。
在某些情況下,程序員可能有以下需求:
1 、當不希望父類的某個方法被子類覆蓋(override)時,可以用final關鍵字修飾。
2 、當不希望類的某個變量的值被修改,可以用final修飾。如果一個變量是final,則必須賦初值,否則編譯出錯。
3 、當不希望類被繼承時,可以用final修飾。
//final方法的使用[Demo128.java]
public class Demo128 {
public static void main(String[] args) {
Aaa aaa=new Aaa();
aaa.show();
Bbb bbb=new Bbb();
bbb.show();
}
}
class Aaa{
int a=0;//如果a不賦初值,a是0。定義類型后應賦值
//圓周率不讓修改
//帶有final修飾的變量命名時應有_下劃線來區分表示。這是java程序員的標準。
final float reate_1=3.1415926f;//使用final可以保證,需要強制不被修改的數據一定要用final鎖定
//final int b; //使用final定義變量時一定要賦初值否則報錯。
//b=1;
final public void sendMes(){//給成員方法用final來修飾則表示不可以被修改,不可被覆蓋。
System.out.println("發送消息");
}
public void show(){
System.out.println("a="+a);
}
}
final class Bbb extends Aaa{//定義類前加final表示該類不允許被繼承
public Bbb(){
a++;
//reate_1=reate+1;
}
/*public void sendMes(){
System.out.println("發送消息")
}*/
}
final-- 注意事項
1、final修飾的變量又叫常量,一般用XX_XX_XX來命名。(帶下劃線)
2、final修飾的變量在定義時,必須賦值,并且以后不能再賦值。
final-- 什么時候用
1、因為案例的考慮,類的某個方法不允許修改。
2、類不會被其它的類繼承。
3、某些變量值是固定不變的,比如圓周率3.1415926