# 大數據學習筆記第7天 - 面向對象1 #
## 回顧
### 二維數組
元素本身是一維數組的數組。
三種初始化方式:
1) int[][] arr = new int[2][];
2) int[][] arr = new int[2][2];
3) int[][] arr = new int[][]{{1,2}, {3,4,5}}; // 簡化寫法見第4種
4) 簡化寫法省略掉公共的部分:int[][] arr = {{1,2}, {3,4,5}};
### 面向對象OOP
類的設計:一定是先有具體事物或者腦海中想象中的事物.然后對屬性和行為進行抽取.
現實中的事物屬性 --> 成員變量
現實中的事物行為(功能) --> 成員方法
類一般情況下不能直接使用.主要用來創建對象.
new 類名(); <-實際上就是在調用空參構造方法
面向對象的三大特點:封裝,繼承,多態.
匿名對象:
沒有名對象(沒有變量引用到的對象)
使用場景:
1.某個對象的方法只使用一次
2.對象作為參數傳遞給方法
3.對象作為返回值返回
自定義類的使用:
1.可以作為形參類型
public void test(Student s){...}
實際上需要的是此類的一個對象
2.可以作為返回值類型
public Student getInstance(){
...
//Student s = new Student();
//return s;
return new Student();
}
封裝:把不想讓外界操作的成員隱藏起來.
實現:使用private關鍵字
對成員變量使用private修飾,提供公有的get/set方法.
this關鍵字:
1.區分成員變量和局部變量
2.本類中方法之間互相調用(此時this可以省略)
3.構造方法之間互相調用(this必須是第一條語句)
構造方法:
他也是一種成員方法.
特點:與類同名沒有返回值(沒有返回值類型定義,沒有return關鍵字)
多個構造方法以重載的形式出現.
如果沒有提供任何構造方法,系統默認有一個空參構造方法,方法體為空.
如果提供構造方法,系統就不再提供任何構造方法.
標準的javabean:
1.私有的成員變量
2.公有的get/set方法
3.空參構造方法
### 作業
自定義Laptop類,做好封裝,并測試。
*E:\01\01 Java\day07\code*
/*
自定義類
*/
class Laptop{
//成員屬性
private String brand;
private int price;
//封裝方法
public void setBrand(String brand){
this.brand = brand;
}
public String getBrand(){
return brand;
}
public void setPrice(int price){
this.price = price;
}
public int getPrice(){
return price;
}
//構造函數
public Laptop(){}
public Laptop(String brand){
this.brand = brand;
}
public Laptop(int price){
this.price = price;
}
public Laptop(String brand, int price){
this(brand);
this.price = price;
}
//成員方法
public void show(){
System.out.println("Brand:" + brand + ", Price:" + price);
}
}
*E:\01\01 Java\day07\code*
/*
測試類
*/
public class LaptopDemo{
public static void main(String[] args){
Laptop pc = new Laptop("Dell", 3500);
pc.show();
}
}
效果如圖:

## 大綱
### 第一節課
- 面向對象編程思想
- 類與對象的關系
- 封裝private
- 構造方法
- this關鍵字
- static關鍵字(javadoc制作工具類)
- 代碼塊
### 第二節課
- static關鍵字
- main方法傳參
- 工具類的制作
- API文檔的使用
- 代碼塊
### 第三節課
- 繼承
- 子類使用變量的原則
- super關鍵字
- 方法重寫與子類對象實例化
- final關鍵字
### 第四節課
- 抽象類
- 抽象方法
- 接口
<hr>
## 面向對象編程思想
### 1. 理解面向對象
- 面向對象是相對面向過程而言
- 面向對象和面向過程都是一種思想
- 面向對象是基于面向過程的


### 舉例
- 電腦組裝
- 建造汽車
- 泡咖啡
- 使用JDK的Scanner類
### 2. 面向對象的特點
- 是一種符合人們思考習慣的思想
- 可以將復雜的事情簡單化
- 將程序員從執行者轉換成指揮者
- 完成需求時:
- 先要去找具有所需的功能的對象來用
- 如果該對象不存在,那么創建一個具有所需功能的對象
- 簡化開發并提高復用
### 3. 面向對象開發、設計、特征
- 開發的過程:其實就是不斷的創建對象,使用對象,指揮對象做事情;
- 設計的過程:其實就是在管理和維護對象之間的關系;
- 面向對象的特征:
- 封裝
- 繼承
- 多態
### 3.2 類與對象的關系
- 使用計算機語言就是不斷的在描述現實生活中的事物
- java中描述事物通過類的形式體現,類是具體事物的抽象,概念上的定義
- 對象(實例)即是該類事物實實在在的個體
- 萬物皆對象

### 什么是類?
可以理解為:
- 類就是從對象中抽象出來的共性;
- 具體學生對象就是實實在在的個體;
- 一個類可以創建多個對象;
### 實例:Dog類

定義一個類主要是兩方面內容:成員變量(事物的屬性)、成員方法(事物的行為)。
/*
定義一個Dog類:
成員屬性:事物的屬性
成員方法:事物的行為
*/
public class Dog{
// 成員屬性:名字、年紀、性別
String name="wancai";
int age=2;
int sex=0;
// 成員方法:吃、喝、叫
public void eat(String food){
System.out.println("正在吃:"+food);
}
}
### 類的定義
- 生活中描述事物無非就是描述事物的屬性和行為。如:狗有顏色和年齡等屬性,有跑和叫等行為。
- Java中用類Class來描述事物也是如此:
- 事物的屬性:對應類中的成員屬性
- 事物的行為:對應類中的成員方法
- 定義一個類,其實就是定義類中的成員(也就是成員屬性和成員方法)
### 類成員的寫法
- 成員變量:
- 和之前定義變量的規則是一致的
- 寫在類中,成員方法的外面
- 成員方法:
- 和之前定義的方法一樣
- 暫時去掉static
代碼實例:
*E:\01\01 Java\day07\code\Car.java*
/*
自定義類:從具體事物到抽象概念的過程。
自定義Car類:
- 成員變量:對應的是事物的屬性
- 成員方法:對應的是事物的行為(功能)
成員變量有默認值
類是一個抽象的概念,具體使用的是創建的實例(對象)。
如何從一個類創建出對象呢?
創建對象 Scanner s = new Scanner(System.in)
類型名 對象名 = new 類型名()
Car car = new car();
*/
public class Car{
String brand;
String color;
int age;
public void run(){
System.out.println("the car is running");
}
public void load(){
System.out.println("the car can load people");
}
}
*E:\01\01 Java\day07\code\CarDemo.java*
/*
演示Car類如何創建對象
成員變量:
賦值
訪問
成員方法:
訪問
JDK里非java.lang下的包才需要手動導入。
Scanner, Math都不需要手動導入。
*/
public class CarDemo{
public static void main(String[] args){
Car car=new Car();
//對成員屬性進行賦值
car.brand="BMW";
car.color="White";
car.age=2;
//對成員屬性進行訪問
System.out.println(car.brand); //默認值是null
System.out.println(car.color); //默認值是null
System.out.println(car.age); //默認值是0
//訪問成員方法
car.run();
car.load();
}
}
2018-08-18_162923.png
作業:自定義一個Laptop類。
*E:\01\01 Java\day07\code\Laptop2.java*
/*
自定義Laptop類
成員變量:
品牌
尺寸
價格
成員方法:
放電影
放音樂
*/
public class Laptop2{
//成員變量
String brand;
double size;
int price;
//成員方法
public void playMovie(String name){
System.out.println("正在播放電影:" + name);
}
public void playMusic(String name){
System.out.println("正在播放音樂:" + name);
}
}
*E:\01\01 Java\day07\code\Laptop2Demo.java*
/*
Laptop類測試
*/
public class Laptop2Demo{
public static void main(String[] args){
Laptop2 pc1 = new Laptop2();
//對成員變量賦值
pc1.brand="聯想";
pc1.size=15.6;
pc1.price=5000;
//成員方法調用
System.out.println(pc1.brand);
System.out.println(pc1.size);
System.out.println(pc1.price);
Laptop2 pc2 = new Laptop2();
//對成員變量賦值
pc2.brand="DELL";
pc2.size=18.6;
pc2.price=6000;
//成員方法調用
System.out.println(pc2.brand);
System.out.println(pc2.size);
System.out.println(pc2.price);
//創建自定義類型的變量,指向已經存在的對象
Laptop2 pc3 = pc1;
//成員方法調用
System.out.println(pc3.brand);
System.out.println(pc3.size);
System.out.println(pc3.price);
}
}
效果如圖:
2018-08-18_173027.png
### 成員變量和局部變量的區別
- 成員變量
- 成員變量定義在類中,作用范圍是整個類
- 實例變量隨著對象的創建而存在,隨著對象而消失
- 存在于對象所在的"堆內存"中
- 成員變量有默認初始化值(0,0.0,false,null)
- 局部變量
- 局部變量定義在局部范圍內:方法內、形參上、代碼塊內
- 局部變量存在于"棧內存"中
- 方法或者語句執行完,變量空間自動釋放
- 局部變量沒有默認初始值,除了形參,使用之前必須賦值
### 對象內存圖
oop-06.jpg
### 形式參數的問題
Java中參數傳遞的原則:值傳遞
- 基本數據類型
- 數組
- 自定義類
舉例形參是一個對象的例子:
*E:\01\01 Java\day07\code\Student.java*
/*
自定義Student類
*/
public class Student{
String name;
int age;
String sex;
public void study(){
System.out.println("正在學習");
}
}
*E:\01\01 Java\day07\code\StudentTest.java*
/*
此類用于對Student的實例進行測試
調用實例的一個方法
*/
public class StudentTest{
public void test(Student s){
//調用形參對象的方法
s.study();
}
}
*E:\01\01 Java\day07\code\StudentDemo.java*
/*
對形參是自定義類型的方法進行測試
*/
public class StudentDemo{
public static void main(String[] args){
//創建測試類的對象
StudentTest st = new StudentTest();
//創建學生對象,當成參數傳給test方法
Student s = new Student();
//調用test方法
st.test(s);
}
}
效果如圖:
2018-08-18_180418.png
### 匿名對象
匿名對象是對象的簡寫形式。
例子:
new StudentTest().test(new Student());
匿名對象兩種使用情況:
- 對象方法僅進行一次調用時,多次調用不適合
- 匿名對象可以作為實際參數進行傳遞
使用匿名對象的好處:
- 簡化寫法,不必定義變量接住對象引用
- 對象用完之后就編程垃圾內存,可以被垃圾回收器回收(一個對象,只要有變量指向它,就不能被垃圾回收器回收)
## 封裝
封裝:是指隱藏對象的屬性和實現細節,僅對外提供公共訪問方式,面向對象的三大特點之一,其余兩個:繼承和多態。
好處:
- 防止數據被任意篡改,提高安全性
- 隱藏了實現細節,僅暴露方法
如何實現封裝:
- 使用private關鍵字修飾成員變量
- 對外提供公有的setter和getter方法
private關鍵字:
- 是一個權限修飾符
- 用于修飾成員(成員變量和成員方法)
- 被私有化的成員只能在本類中直接訪問
oop-07.jpg
常見方法:
- 將成員變量設為私有,這樣就防止在類外進行訪問,對外提供相應的公有的setxxx和getxxx方法
- 好處是提高對數據訪問的安全性,并且可以增加復雜的邏輯控制
封裝前,可以給對象的屬性直接進行賦值操作,如圖:
2018-08-20_015056.png
封裝后,訪問私有變量會直接報錯,如圖
2018-08-20_015730.png
代碼實例:
*E:\01\01 Java\day07\code\Person.java*
[code]
/*
自定義Person類
*/
public class Person{
//使用關鍵字private進行封裝
private String name;
private int age;
//定義setter方法和getter方法
public void setName(String n){
name = n;
}
public String getName(){
return name;
}
public void setAge(int m){
age = m;
}
public int getAge(){
return age;
}
}
[/code]
*E:\01\01 Java\day07\code\PersonDemo.java*
[code]
/*
測試Person類
*/
public class PersonDemo{
public static void main(String[] args){
Person p = new Person();
//p.name="張三";
//p.age=200;
//System.out.println(p.name);
//System.out.println(p.age);
p.setName("李四");
p.setAge(80);
System.out.println(p.getName());
System.out.println(p.getAge());
}
}
[/code]
### this關鍵字
作用:this代表當前正在調用的方法對象。
使用場景:
- setXxx方法中對成員變量賦值,區分成員變量和局部變量
- 構造方法互相調用:this(...); 注意:構造方法中使用this或者super調用其他構造方法必須是構造方法中的第一條語句。
- 方法中調用本類其他方法
代碼實例:
*E:\01\01 Java\day07\code\ThisDemo.java*
[code]
/*
this關鍵字:用來區分局部變量和成員變量。使用this引用的就是成員變量。
*/
class Demo{
private int age;
public void setAge(int age){
//根據究竟原則,此時的age,都是取的局部變量,沒有從參數傳遞過來的age
//age = age;
this.age = age;
}
public int getAge(){
return age;
}
}
public class ThisDemo{
public static void main(String[] args){
Demo d = new Demo();
d.setAge(100);
System.out.println(d.getAge()); //0
}
}
[/code]
### 構造方法
特點:
- 構造方法是一種特殊的方法,它的方法名和類名相同
- 不用定義返回值類型,不用return關鍵字
- 其返回值可以理解為是新創建對象的引用,不用顯式定義
作用:給對象初始化,即給成員變量賦值。
注意:
- 如果沒有寫,系統提供一個默認(空參)構造方法,一旦定義了構造方法就不會,系統不會提供任何構造方法
- 多個構造方法是以重載的形式存在的
- 使用new Student();實際上就是在調用“空參”構造方法
代碼實例:
[code]
/*
構造方法實例
*/
class People{
private int age;
public void setAge(int age){
this.age=age;
}
public int getAge(){
return age;
}
//定義無參構造方法
public People(){
System.out.println("訪問了無參構造方法");
}
//定義有參構造方法,利用了方法重載
public People(int age){
System.out.println("訪問了有參構造方法");
this.age=age;
}
public void show(){
System.out.println("當前年齡是:" + age);
}
}
public class PeopleDemo{
public static void main(String[] args){
People p1 = new People();
p1.show();
People p2 = new People(10);
p2.show();
}
}
[/code]
如圖:
2018-08-20_024437.png
注意:由于某些框架專門使用類的空參構造來創建對象,所以在定義類時,最好加上空參構造。
### 一個標準類的定義和使用
以Student類為例,定義標準的javabean
成員變量:自己分析,用私有修飾
成員方法:
- 空參構造方法
- 普通成員方法
- get/set方法
如果不希望單獨獲取成員變量的值,可以不定義setXxx方法
給成員變量賦值的方式有兩種:set方法和構造方法
代碼實例:
*E:\01\01 Java\day07\code\NoteBook.java*
[code]
/*
定義一個標準類:
1.私有的成員屬性
2.公有的set/get方法
3.空參構造方法
*/
public class NoteBook{
private String brand;
private int price;
private double size;
public void setBrand(String brand){
this.brand=brand;
}
public String getBrand(){
return brand;
}
public void setPrice(int price){
this.price=price;
}
public int getPrice(){
return price;
}
public void setSize(double size){
this.size=size;
}
public double getSize(){
return size;
}
//空參構造
public NoteBook(){
}
//帶參構造函數
public NoteBook(String brand, int price, double size){
this.brand=brand;
this.price=price;
this.size=size;
}
public void playMusic(){
System.out.println("正在播放音樂");
}
public void show(){
System.out.println(brand + "," + price + "," + size);
}
}
[/code]
*E:\01\01 Java\day07\code\NoteBookDemo.java*
[code]
/*
NoteBook測試類
*/
public class NoteBookDemo{
public static void main(String[] args){
//訪問空參構造方法
NoteBook book1 = new NoteBook();
book1.setBrand("Dell");
book1.setPrice(3500);
book1.setSize(16.8);
book1.show();
book1.playMusic();
//訪問帶參構造方法
NoteBook book2 = new NoteBook("Lenovo", 5800, 24.8);
book2.show();
book2.playMusic();
}
}
[/code]
效果顯示:
2018-08-20_144055.png
### this關鍵字在構造方法中的使用:
- 在某個構造方法中調用本類的其他構造方法
- 必須放在構造方法的第一句
代碼實例:
[code]
public NoteBook(String brand, int price, double size){
this(brand, price);
this.size=size;
}
//this關鍵字的使用
public NoteBook(String brand, int price){
this(price);
this.brand=brand;
}
public NoteBook(int price){
this.price=price;
}
[/code]
### 一個對象的初始化(實例化)過程
以Student s=new Student();為例
- 加載Student.class文件到方法區;
- 在棧內存中定義變量s;
- 在堆內存中開辟空間;
- 對成員變量進行默認初始化(0,0.0,false,null)
- 對成員變量進行顯式初始化(定義成員變量時賦值)
- 調用構造方法(成員變量賦值)
- 成員變量初始化完畢,將對象地址值返回給棧中的變量s
oop-08.jpg
### 練習
什么時候將變量定義為成員變量?
變量是用來描述類的,如果變量是這個類的描述信息,就定義為成員變量,否則,應該定義為方法形參或者方法體內,即:局部變量。
變量定義的原則:范圍越小越好,能夠被及時回收。
練習題:
1. 定義長方形類,其中包含求周長(perimeter)和面積(area)的方法。注意:由于沒有必要單獨獲取長和寬,所以不需要定義get方法。
2. 定義員工類,自己分析有什么成員變量,包含一個顯示所有成員變量的方法,然后測試。
3. 自定義計算類,提供基本的加減乘除運算,并測試。被計算的數和類之間沒有從屬關系,最好不要定義成員變量,而是方法的參數。
例1:
2018-08-20_203214.png
*E:\01\01 Java\day07\code\Rectangle.java*
[code]
/*
自定義長方形類
*/
public class Rectangle{
private int length;
private int width;
public void setLength(int length){
this.length=length;
}
public void setWidth(int width){
this.width=width;
}
public int getPerimeter(){
return 2*(length+width);
}
public int getArea(){
return length * width;
}
}
[/code]
*E:\01\01 Java\day07\code\RectangleDemo.java*
[code]
/*
測試長方形類
*/
import java.util.Scanner;
public class RectangleDemo{
public static void main(String[] args){
Rectangle r = new Rectangle();
Scanner s = new Scanner(System.in);
System.out.println("請輸入長方形的長度:");
r.setLength(s.nextInt());
System.out.println("請輸入長方形的寬度:");
r.setWidth(s.nextInt());
System.out.println("周長:"+r.getPerimeter());
System.out.println("面積:"+r.getArea());
}
}
[/code]
例2:
2018-08-20_203946.png
*E:\01\01 Java\day07\code\Employee.java*
[code]
/*
自定義員工類
*/
public class Employee{
private String name;
private String dept;
private int age;
public void setName(String name){
this.name = name;
}
public String getName(){
return name;
}
public void setDept(String dept){
this.dept = dept;
}
public String getDept(){
return dept;
}
public void setAge(int age){
this.age = age;
}
public int getAge(){
return age;
}
public Employee(){}
public Employee(String name, String dept, int age){
this.name=name;
this.dept=dept;
this.age=age;
}
public void show(){
System.out.println(name + ", " + dept + ", " + age);
}
}
[/code]
*E:\01\01 Java\day07\code\EmployeeDemo.java*
[code]
/*
測試員工類
*/
public class EmployeeDemo{
public static void main(String[] args){
Employee e = new Employee("Leon", "IT", 31);
e.show();
}
}
[/code]
例3:
2018-08-20_205036.png
*E:\01\01 Java\day07\code\Calc.java*
[code]
/*
自定義兩個數用于加減乘除
*/
public class Calc{
private int num1;
private int num2;
public Calc(){}
public int add(int num1, int num2){
return num1+num2;
}
public int sub(int num1, int num2){
return num1-num2;
}
public int mul(int num1, int num2){
return num1*num2;
}
public double div(int num1, int num2){
return num1/num2;
}
}
[/code]
*E:\01\01 Java\day07\code\CalcDemo.java*
[code]
/*
用于計算類的測試用例
*/
import java.util.Scanner;
public class CalcDemo{
public static void main(String[] args){
Calc c = new Calc();
Scanner s=new Scanner(System.in);
int num1;
int num2;
System.out.println("請輸入第1個數:");
num1 = s.nextInt();
System.out.println("請輸入第2個數:");
num2 = s.nextInt();
System.out.println("加:" + c.add(num1, num2));
System.out.println("減:" + c.sub(num1, num2));
System.out.println("乘:" + c.mul(num1, num2));
System.out.println("除:" + c.div(num1, num2));
}
}
[/code]
## static關鍵字
用于修飾成員(成員變量和成員方法),稱為類成員。
代碼實例:
2018-08-20_223134.png
*E:\01\01 Java\day07\code\StaticTest.java*
[code]
/*
演示static關鍵字
*/
public class StaticTest{
//修飾類成員屬性
static int age;
//修飾類成員方法
public static void show(){
System.out.println("Hello");
}
}
[/code]
*E:\01\01 Java\day07\code\StaticDemo.java*
[code]
/*
測試Staic修飾關鍵字的使用
*/
public class StaticDemo{
public static void main(String[] args){
//使用類名直接訪問類成員
StaticTest.age=10;
System.out.println(StaticTest.age);
StaticTest.show();
//使用對象來訪問類成員
StaticTest st = new StaticTest();
st.age=20;
System.out.println(st.age);
st.show();
}
}
[/code]
總結:靜態方法不能訪問非靜態成員;非靜態方法則可以訪問靜態成員。(原因是先有靜態成員)
圖2018-08-20_223724.png
被修飾后的類成員有如下特點:
- 隨著類的加載而加載
- 優先于對象而存在
- 被這個類的所有對象共享
- 可以直接被類名調用,也可以使用對象調用,但推薦使用類名調用,因為static修飾的成員就是類成員
使用時注意:
- 靜態方法只能訪問靜態成員(變量,方法)
- 靜態方法中不可以使用this, super關鍵字
- 非靜態方法可以訪問靜態成員
圖oop-09.jpg
### 演示Staic關鍵字的例子
圖2018-08-20_224744.png
*E:\01\01 Java\day07\code\StaticTest2.java*
[code]
/*
演示Static關鍵字
*/
public class StaticTest2{
static String country="China";
String name;
public void show(){
System.out.println(country + " - " + name);
}
}
[/code]
*E:\01\01 Java\day07\code\StaticTest2Demo.java*
[code]
/*
演示StaticTest2類
*/
public class StaticTest2Demo{
public static void main(String[] args){
StaticTest2 st1 = new StaticTest2();
st1.name="Leon";
st1.show();
StaticTest2 st2 = new StaticTest2();
st2.name="Tom";
st2.country="USA";
st2.show();
}
}
[/code]
### 靜態變量和實例變量之間的區別
- 所屬不同
- 靜態變量屬于類,也稱為類變量
- 實例變量屬于對象,也稱為對象(實例)變量
- 在內存中的位置不同
- 靜態變量在方法區中
- 實例變量在堆內存
- 生命周期不同
- 靜態變量隨著類的加載而加載,隨著類的消失而消失
- 實例變量隨著對象的創建而存在,隨著對象的消失而消失
- 調用方法不同
- 靜態變量可以通過類名和對象名兩種方式調用,推薦使用類名調用
- 實例變量只能使用對象名的方式調用
## main方法傳參與格式說明
public static void main(String[] args){...}
- public: 修飾符,用來控制訪問權限的。
- static: 修飾main方法屬于類方法,通過類名直接調用,JVM不用創建對象即可直接調用。
- void: 返回值為空,main方法不用返回任何值。
- main: 默認的程序入口,不是關鍵字,JVM從這里開始執行。
- String[] args: 形參列表,String類型的數組。
- args: 形參名,也就數數組名。
如何使用?早期可以從鍵盤輸入,但后面JDK1.5以后則被Scanner取代。如圖所示:
圖2018-08-20_231526.png
代碼實例:
*E:\01\01 Java\day07\code\Args.java*
[code]
/*
試驗main方法的參數傳遞
*/
public class Args{
public static void main(String[] args){
for(int i=0; i<args.length; i++){
System.out.println(args[i]);
}
}
}
[/code]
## 工具類的制作
1. 寫一個類,包含一個方法用來遍歷一維數組。
2. 使用static修飾,可以直接使用類名來調用,方法在main中調用。
3. 將這個類單獨放到一個文件中,形成工具類。
4. 可以繼續定義更多的關于數組的操作,獲得最值等,豐富工具類。
注意:
- 編譯的時候,只編譯測試類即可
- 通過類名和對象名的方式都能調用,如果不想讓使用對象名的方式調用的話,將構造方法私有化即可
### 制作一個工具類實例
圖2018-08-20_234158.png
代碼實例:
*E:\01\01 Java\day07\code\ArrayTool.java*
[code]
/*
求一個求數組的最值工具類
@author webjust
@version 1.0
*/
public class ArrayTool{
/**
* 求最大值
* @param arr 需要查找最大值的數組
* @return 返回數組的最大值
*/
public static int getMax(int[] arr){
int max = arr[0];
for(int i=1; i<arr.length; i++){
if(arr[i] > max){
max=arr[i];
}
}
return max;
}
/**
* 求最小值
* @param arr 需要查找最小值的數組
* @return 返回數組的最小值
*/
public static int getMin(int[] arr){
int min = arr[0];
for(int i=1; i<arr.length; i++){
if(arr[i] < min){
min=arr[i];
}
}
return min;
}
}
[/code]
*E:\01\01 Java\day07\code\ArrayToolTest.java*
[code]
/*
測試工具類
*/
public class ArrayToolTest{
public static void main(String[] args){
int[] arr = {1,2,4,7,9,10};
int max = ArrayTool.getMax(arr);
int min = ArrayTool.getMin(arr);
System.out.println(max + " - " + min);
}
}
[/code]
### 工具類說明書的制作
- 寫一個完整的工具類,需要使用public修飾
- 類名上加@author, @version標簽
- 方法上加@param, @return標簽
- 注意:方法上標簽中不用加類型
- 最終使用命令生成文檔:`javadoc -d mydoc -version -author ArrayTool.java`
生成的doc文檔如圖:
2018-08-20_234459.jpg
## API文檔
圖2018-08-20_235711.jpg
- 在線版
- 離線版
- 關注事項
- 所在包
- 構造方法
- 形參,返回值類型
- 是否是static靜態的
- 從哪個版本開始的
代碼實例:
*E:\01\01 Java\day07\code\MathDemo.java*
[code]
/*
API文檔的使用:Math類
*/
public class MathDemo{
public static void main(String[] args){
System.out.println(Math.max(1, 8)); //8
System.out.println(Math.min(-1, 2));//-1
}
}
[/code]
## 代碼塊
局部代碼塊:
在方法內部,用于限定變量的生命周期,及時釋放內存。
構造代碼塊:
定義在成員位置,用于抽取不同構造方法中相同的部分。構造方法調用一次,構造代碼塊就執行一次。
靜態代碼塊:
static修飾的構造代碼塊,用于對類進行初始化。靜態代碼塊隨著類的加載而執行,整個過程中只執行一次。
代碼演示實例:
*E:\01\01 Java\day07\code\BlockDemo.java*
[code]
/*
代碼塊測試類
*/
class BlockTest{
static int num;
//構造代碼塊:在任何一個構造方法前都執行一次
{
System.out.println("歡迎來到:");
}
//靜態代碼塊:對類進行初始化,在類開始加載時就執行,整個過程只執行一次
static {
System.out.println("靜態代碼塊1");
}
static {
System.out.println("靜態代碼塊2");
}
public BlockTest(){
System.out.println("歡迎來到1:");
System.out.println("無參構造方法");
}
public BlockTest(int num){
System.out.println("歡迎來到2:");
System.out.println("帶參構造方法");
}
//局部代碼塊演示
public void show(){
{
int a=10;
}
{
int a=20;
}
}
}
public class BlockDemo{
public static void main(String[] args){
BlockTest bt1=new BlockTest();
BlockTest bt2=new BlockTest(1);
}
}
[/code]
圖2018-08-21_234114.png
面試題:靜態代碼塊,構造代碼塊,構造方法的執行順序和特點?
答:靜態代碼塊 -> 構造代碼塊 -> 構造方法。
## 繼承 extends
- 多個類中存在多個相同的屬性和行為時,將這些內容抽取到單獨一個類中,那么多個類無需再定義這些屬性和行為,只需從抽取出來的那那個類擴展(extends)即可
- 需要擴展的類稱為子類,抽取出來的那個類稱為父類,或者超類,或者基類
- 通過關鍵字 extends 讓類與類之間產生繼承關系
class 子類名 extends 父類{/*類體*/}
繼承的出現,提高了代碼的可復用性。
繼承的出現讓類和類之間開始產生了關系,提供了多態的前提。
代碼實例:
圖2018-08-22_221057.png
*E:\01\01 Java\day07\code\Stu.java*
[code]
/*
繼承:繼承人類
*/
class Stu extends Human{
}
[/code]
*E:\01\01 Java\day07\code\Human.java*
[code]
/*
繼承:基類
*/
class Human{
public void eat(){
System.out.println("eat....");
}
public void sleep(){
System.out.println("sleep....");
}
}
[/code]
*E:\01\01 Java\day07\code\Teacher.java*
[code]
/*
繼承:繼承人類
*/
class Teacher extends Human{
}
[/code]
*E:\01\01 Java\day07\code\HumanDemo.java*
[code]
/*
繼承的測試
*/
public class HumanDemo{
public static void main(String[] args){
Stu s = new Stu();
s.eat();
s.sleep();
Teacher t = new Teacher();
t.eat();
t.sleep();
}
}
[/code]
### 繼承的特點
- Java只支持單繼承,不支持多繼承。一個類只能有一個父類,不能由多個父類。
- Java支持多層繼承
- 定義繼承需要注意,不僅要為了獲得其他類的某個功能才去繼承。類與類之間,需要有所屬關系,即子類是父類的一種。
- 私有成員不能被繼承
- 繼承關系中成員變量的關系:子類中方法使用變量的“就近原則”
- 1. 現在子類方法中查找
- 2. 再在子類的成員變量中查找
- 3. 再找父類的成員變量
實例1:
圖2018-08-22_221625.png
*E:\01\01 Java\day07\code\ExtendDemo.java*
[code]
/*
測試一個類只能繼承一個父類
*/
class A{
}
class B{
}
class C extends A,B{
}
public class ExtendDemo{
public static void main(String[] args){
}
}
[/code]
實例2:
圖2018-08-22_222217.png
*E:\01\01 Java\day07\code\ExtendDemo2.java*
[code]
/*
繼承特點:不能繼承私有成員
*/
class A{
private int num = 1; //num 在 A 中是 private 訪問控制
//int num = 1;
}
class B extends A{
public void show(){
System.out.println(num);
}
}
public class ExtendDemo2{
public static void main(String[] args){
B b1 = new B();
b1.show();
}
}
[/code]
實例3:
圖2018-08-22_222926.png
*E:\01\01 Java\day07\code*
[code]
/*
繼承特性:就近原則
方法內 > 本類中 > 繼承屬性
*/
class A{
int num = 1;
}
class B extends A{
int num = 2;
public void show(){
int num = 3;
System.out.println(num);
}
}
public class ExtendDemo3{
public static void main(String[] args){
B b1 = new B();
b1.show(); //3
}
}
[/code]
## super 關鍵字
- super和this的用法類似
- this代表本類對象的引用
- super代表父類對象的內存空間的標識
### super的使用場景
子父類出現同名成員時,用super進行區分:
- super.成員屬性
- super.成員方法()
子類使用super調用父類的構造方法
- super(...)
實例:
圖2018-08-23_001616.png
*E:\01\01 Java\day07\code\SuperDemo.java*
[code]
/*
super關鍵字
*/
class A{
int num=10;
}
class B extends A{
int num=20;
public void show(){
System.out.println(num); //20
System.out.println(super.num); //10
}
}
public class SuperDemo{
public static void main(String[] args){
B b1 = new B();
b1.show();
}
}
[/code]
代碼實例:
圖2018-08-23_002349.png
*E:\01\01 Java\day07\code\SuperDemo2.java*
[code]
/*
Super關鍵字特性
*/
class A{
int num=10;
public A(){
System.out.println("父類無參構造方法");
}
public A(String s){
System.out.println(s);
System.out.println("父類帶參構造方法");
}
}
class B extends A{
int num=20;
//程序會默認先執行B類的無參構造方法,然后執行父類的無參構造方法
public B(){
//必須在程序的第一行,顯示的調用父類的帶參的構造方法,使用Super關鍵字表示是父類
super("1000"); //不放在第一行,會報錯
System.out.println("子類無參構造方法重寫...");
}
public void show(){
System.out.println(num); //20
System.out.println(super.num); //10
}
}
public class SuperDemo2{
public static void main(String[] args){
B b1 = new B();
b1.show();
}
}
[/code]
## 方法重寫 Override|Overwrite
- 子類中出現與父類一模一樣的方法時,會出現覆蓋操作,也稱為重寫或者復寫
- 父類中的私有方法不可以被重寫
- 在子類重寫方法中,繼續使用被重寫的方法可以使用super.方法名(...)
- 覆蓋注意事項:覆蓋時,子類方法權限一定要大于等于父類的方法權限;除了訪問權限外,其他部分和父類保持一致;靜態只能覆蓋靜態;
- 覆蓋的應用:當子類需要父類的功能,而功能主體子類有自己的特有內容時,可以復寫父類中的方法,這樣,即沿襲了父類的功能,又定義了子類特有的內容
代碼實例:
2018-08-23_004820.png
*E:\01\01 Java\day07\code\OverrideDemo.java*
[code]
/*
方法重寫實例
*/
class Father{
public void test(){
System.out.println("Father test()...");
}
public static void test2(){
System.out.println("Father test2()...");
}
void test3(){
System.out.println("Father test3()...");
}
}
class Son extends Father{
//重寫父類方法,需要同名方法
public void test(){
super.test(); //在子類中調用父類的方法
System.out.println("Son test()...");
}
//重寫靜態方法,子類必須也是靜態方法
public static void test2(){
System.out.println("Son test2()...");
}
//子類的權限范圍必須大于父類的方法
public void test3(){
System.out.println("Son test3()...");
}
}
public class OverrideDemo{
public static void main(String[] args){
Son s = new Son();
s.test();
s.test2();
s.test3();
}
}
[/code]
### 子類的實例化過程
- 子類中所有的構造方法默認都會訪問父類中的空參構造方法,因為每一個構造方法的第一行都有一條默認的語句super(),除非第一行是用this或super顯示調用了其他的構造方法
- 子類會具備父類中的數據,所以要先明確父類是如何對這些數據初始化的,也就是父類對象必需在子類對象初始化前初始化ok
- 當父類中沒有空參構造方法時,子類的構造方法必須通過this或super語句指定要訪問的構造方法
代碼實例:
圖2018-08-23_010218.png
*E:\01\01 Java\day07\code\OverrideDemo2.java*
[code]
/*
方法重寫實例
*/
class Father{
public Father(){
System.out.println("Father構造方法");
}
}
class Son extends Father{
public Son(){
super(); //默認會添加父類的無參構造方法,也可以指定為其他的父類構造方法
System.out.println("Son構造方法");
}
}
public class OverrideDemo2{
public static void main(String[] args){
Son s = new Son();
}
}
[/code]
## final 關鍵字
final可以修飾類、方法、變量。
圖oop-10.jpg
final修飾的成員變量,必須在構造方法執行完成之前初始化:
1. 可以在定義的時候就賦值(最常見)
2. 可以在構造代碼塊中賦值,多個構造代碼塊中不能重復賦值
代碼實例:
圖2018-08-23_012422.png
*E:\01\01 Java\day07\code\FinalDemo.java*
[code]
/*
final關鍵字
*/
class A{
public final int num;
}
class B extends A{
int num=20;
public void show(){
System.out.println(num);
}
}
public class FinalDemo{
public static void main(String[] args){
B b1=new B();
b1.show();
}
}
[/code]
## 抽象類
### 1. 抽象類概述
抽象定義:抽象就是從多個事物中將共性的,本質的內容抽取出來
抽象類定義:Java中可以定義沒有方法體的方法,該方法的具體實現由子類來完成,該方法稱為抽象方法,包含抽象方法的類就是抽象類。
抽象方法的由來:多個對象都具備相同的功能,但是功能的具體實現有所不同,那么在抽取過程中,只抽取了功能定義,并未抽取功能主體,那么只有功能聲明,沒有功能主體的方法稱為抽象方法。
> 如果在父類中定義了一個各子類都有不同實現的方法,那么子類需要重寫這個方法,為什么父類還要定義這個方法?這是為多態做準備。
由于多態的要求:父類引用指向子類實例,但父類不能調用子類獨有的方法,為了使用多態,父類中必須定義這個方法,但是方法的實現又會被子類重寫。
為了既能使用多態,又能省去在父類中的麻煩,Java提供了抽象方法,在父類中只定義方法名,不實現方法體。
圖oop-10.jpg
### 2. 抽象類特點
抽象類和抽象方法必須用abstract關鍵字來修飾。
抽象方法只有方法聲明,沒有方法體,定義在抽象類中。
抽象類不可以被實例化,原因如下:
- 抽象類是具體事物抽象出來的,本身不是具體的,沒有對應的實例。
- 假設抽象類可以創建對象,那么調用其抽象方法,將無意義。
抽象類通過其子類實例化,而子類需要實現抽象類中所有的抽象方法后才能創建對象,否則該子類也是抽象類。
修飾符 abstract 返回值類型 方法名(參數列表);
圖oop-11.jpg
### 3. 抽象類舉例代碼
子類Dog, Cat分別實現Animal類的抽象方法eat()。
圖oop-12.jpg
2個代碼實例
### 4. 抽象類相關問題
- 抽象類是否可以有構造方法?
抽象類中可以有成員變量,而構造方法的作用就是對成員變量初始化的,所以可以有構造方法。
- 抽象關鍵字abstract不可以和哪些關鍵字共存?
static, final, private
- 抽象類中可不可以沒有抽象方法?
可以,比如可以不讓外界實例化。
## 接口
類可以繼承一個類的同時實現多個接口
class Dog extends Animal implements CanJump,CanWin{
...
}
接口與接口之間是繼承關系
public interface InterfaceA{void m1();}
public interface InterfaceB{void m2();}
public interface InterfaceC extends InterfaceA,InterfaceB{
//有兩個抽象方法繼承至父類接口;
}
接口是抽象的一種機制。
圖oop-13.jpg
現實事物的共性抽取成類:
將不同類中的同名方法抽象成抽象方法,形成抽象類。
對類的成員變量和方法繼續抽象的話,就形成接口,接口是類的最高級別的抽象機制。
接口中只有常量和抽象方法
接口是一種規范,實現一個接口,就需要實現其中所有的抽象方法。
格式:
[code]
[public] interface 接口名 [extends 父接口1,父接口2...]{
//成員常量: public static final
//抽象方法: public abstract
}
[/code]
- public: 可以在所有包中訪問,不加的話,表明只能在本包中訪問該接口
- 接口中的成員修飾符是固定的,寫與不寫都有
- 成員常量: public static final
- 抽象方法: public abstract
- 接口中的成員都是public修飾的。
- 接口的出現將"多繼承"通過另外一種形式體現出來,即"多實現"。
### 接口的特點
接口是程序的擴展功能:想給類A增加一個功能,只需要定義一個接口,然后自定義一個類,繼承自類A,并實現這個接口,即可完成把類A的功能擴展。
圖
圖oop-13.jpg
圖2018-08-24_110655.png
*E:\01\01 Java\day07\code\InterfaceDemo.java*
[code]
/*
接口:對功能的擴展
*/
class Dog{
public void eat(){
System.out.println("Dog eat()....");
}
}
interface Jump{
public abstract void jump();
}
class JumpDog extends Dog implements Jump{
public void jump(){
System.out.println("Dog jump()....");
}
}
public class InterfaceDemo {
public static void main(String[] args){
JumpDog jd = new JumpDog();
jd.eat();
jd.jump();
}
}
[/code]
- 接口的出現降低耦合性
接口只定義規范,不關心實現,這是設計和實現相分離的表現。
- 接口可以用來多實現
[code]
class SuperMan implements CanFly,CanSwin,CanFight{
//實現在所有接口中定義的抽象方法
}
[/code]