文檔版本 | 開發工具 | 測試平臺 | 工程名字 | 日期 | 作者 | 備注 |
---|---|---|---|---|---|---|
V1.0 | 2016.02.29 | lutianfei | none |
[TOC]
工具類中使用靜態方法
-
當報錯無法從靜態上下文中引用非靜態 方法xxx:
- 表明在靜態方法中引用了非靜態方法
在工具類中當把
構造方法
私有后,外界就不能再創建對象了,此時將所有方法
設為靜態后。可以根據靜態方法
的特點:通過類名來調用。Eg:
/*
我想要對數組進行操作
在同一個文件夾下,類定義在兩個文件中和定義在一個文件中其實一樣的。
*/
class ArrayDemo {
public static void main(String[] args) {
//定義數組
int[] arr = {28,55,37,46,19};
//靜態方法
//printArray(arr);
//非靜態方法
//ArrayDemo ad = new ArrayDemo();
//ad.printArray(arr);
//方法改進為靜態后,就可以直接通過類名調用
ArrayTool.printArray(arr);
}
}
class ArrayTool {
//把構造方法私有,外界就不能在創建對象了
private ArrayTool(){}
public static void printArray(int[] arr) {
for(int x=0; x<arr.length; x++) {
if(x == arr.length-1) {
System.out.println(arr[x]);
}else {
System.out.print(arr[x]+", ");
}
}
}
}
幫助文檔的制作
-
制作工具類
- ArrayTools
-
制作幫助文檔(API)
-
javadoc -d 目錄 -author -version ArrayTool.java
- 目錄可以寫一個文件的路徑
-
javadoc -d 目錄 -author -version ArrayTool.java
制作幫助文檔出錯:
找不到可以文檔化的公共或受保護的類:告訴我們類的權限不夠。修改方法在類前面加
public
修飾。
如何使用幫助文檔
- 點擊
顯示
,找到索引
,出現輸入框
- 你應該知道你找誰?舉例:Scanner
- 看這個類的結構(需不需要
導包
) 注:java.lang
包下的類不需要導入,其他的全部需要導入。- 成員變量 說明書中對照為
字段摘要
- 構造方法 說明書中對照為
構造方法摘要
- 有構造方法 : 創建對象
- 沒有構造方法:成員可能都是靜態的,通過類名調用。
- 成員方法
方法摘要
- 看左邊
- 是否靜態:如果靜態,可以通過類名調用
- 返回值類型:定義返回的是說明,就用什么接收。
- 看右邊
- 方法名,不要打錯
- 參數列表:需要什么參數,就給什么,需要幾個給幾個
- 看左邊
- 看版本說明
- 成員變量 說明書中對照為
- 看這個類的說明
- 看構造方法
- 看成員方法
Math類學習
/*
Math:類包含用于執行基本數學運算的方法
由于Math類在java.lang包下,所以不需要導包。
特點:
沒有構造方法,因為它的成員全部是靜態的。
掌握一個方法:
獲取隨機數
public static double random():返回帶正號的 double 值,該值大于等于 0.0 且小于 1.0。
*/
class MathDemo {
public static void main(String[] args) {
//獲取一個隨機數
//double d = Math.random();
//System.out.println(d);
//需求:我要獲取一個1-100之間的隨機數,腫么辦?
for(int x=0; x<100; x++) {
int number = (int)(Math.random()*100)+1;
System.out.println(number);
}
}
}
代碼塊
在Java中,使用{}括起來的代碼被稱為代碼塊,根據其位置和聲明的不同,可以分為
局部代碼塊
,構造代碼塊
,靜態代碼塊
,同步代碼塊
(多線程講解)。-
局部代碼塊
- 在方法中出現;限定變量生命周期,及早釋放,提高內存利用率
-
構造代碼塊
- 在類中,方法外出現;
- 多個構造方法中相同的代碼存放到一起,每次調用構造都執行,并且在<font color = red>
構造方法
前</font>執行。- 作用:可以把多個構造方法中的共同代碼放到一起。
-
靜態代碼塊
- 在類中,方法外出現,加了
static
修飾;用于給類進行初始化,在加載的時候就執行,并且<font color = red>只執行一次</font>。
- 在類中,方法外出現,加了
eg1 :
class Code {
static { //靜態代碼塊
int a = 1000;
System.out.println(a);
}
//構造代碼塊
{
int x = 100;
System.out.println(x);
}
//構造方法
public Code(){
System.out.println("code");
}
//構造方法
public Code(int a){
System.out.println("code");
}
//構造代碼塊
{
int y = 200;
System.out.println(y);
}
//靜態代碼塊
static {
int b = 2000;
System.out.println(b);
}
}
class CodeDemo {
public static void main(String[] args) {
//局部代碼塊
{
int x = 10;
System.out.println(x);
}
//找不到符號
//System.out.println(x);
{
int y = 20;
System.out.println(y);
}
System.out.println("---------------");
Code c = new Code();
System.out.println("---------------");
Code c2 = new Code();
System.out.println("---------------");
Code c3 = new Code(1);
}
}
/*
* 程序運行結果:
10
20
---------------
1000
2000
100
200
code
---------------
100
200
code
---------------
100
200
code
*/
- Eg2 :
class Student {
static {
System.out.println("Student 靜態代碼塊");
}
{
System.out.println("Student 構造代碼塊");
}
public Student() {
System.out.println("Student 構造方法");
}
}
class StudentDemo {
static {
System.out.println("林青霞都60了,我很傷心");
}
public static void main(String[] args) {
System.out.println("我是main方法");
Student s1 = new Student();
Student s2 = new Student();
}
}
/*
寫程序的執行結果。
林青霞都60了,我很傷心
我是main方法
Student 靜態代碼塊
Student 構造代碼塊
Student 構造方法
Student 構造代碼塊
Student 構造方法
*/
繼承
繼承概述
- 多個類中存在相同屬性和行為時,將這些內容抽取到單獨一個類中,那么多個類無需再定義這些屬性和行為,只要繼承那個類即可。
- 通過
extends
關鍵字可以實現類與類的繼承-
class
子類名extends
父類名 {}
-
- 單獨的這個類稱為
父類
,基類
或者超類
;這多個類可以稱為子類
或者派生類
。 - 有了繼承以后,我們定義一個類的時候,可以在一個已經存在的類的基礎上,還可以定義自己的新成員。
class Dad(){}
class Son extends Dad {}
繼承的好處
-
提高了代碼的復用性
- 多個類相同的成員可以放到同一個類中
-
提高了代碼的維護性
- 如果功能的代碼需要修改,修改一處即可
-
讓類與類之間產生了關系,是多態的前提
- 其實這也是繼承的一個弊端:類的耦合性很強
-
開發的原則:低耦合,高內聚
-
耦合
:類與類的關系。 -
內聚
:就是自己完成某件事情的能力。
-
Java中繼承的特點
- Java只支持單繼承,不支持多繼承。
- 一個類只能有一個父類,不可以有多個父類。
- class SubDemo extends Demo{} //ok
- class SubDemo extends Demo1,Demo2...//error
- 一個類只能有一個父類,不可以有多個父類。
- Java支持多層繼承(繼承體系)
- class A{}
- class B extends A{}
- class C extends B{}
Java中繼承的注意事項
- 子類只能繼承父類所有非私有的成員(成員方法和成員變量)
- 其實這也體現了繼承的另一個弊端:打破了封裝性
- 子類不能繼承父類的構造方法,但是可以通過
super
關鍵字去訪問父類構造方法。 - 不要為了部分功能而去繼承
- Eg1:
class Father {
private int num = 10;
public int num2 = 20;
//私有方法,子類不能繼承
private void method() {
System.out.println(num);
System.out.println(num2);
}
public void show() {
System.out.println(num);
System.out.println(num2);
}
}
class Son extends Father {
public void function() {
//num可以在Father中訪問private
//System.out.println(num); //子類不能繼承父類的私有成員變量
System.out.println(num2);
}
}
class ExtendsDemo3 {
public static void main(String[] args) {
// 創建對象
Son s = new Son();
//s.method(); //子類不能繼承父類的私有成員方法
s.show();
s.function();
}
}
什么時候使用繼承呢?
- 繼承中類之間體現的是:”is a”的關系。
- 假設法:如果有兩個類A,B。只有他們符合A是B的一種,或者B是A的一種,就可以考慮使用繼承。
繼承中成員變量的關系
- 案例演示
- 子父類中同名和不同名的成員變量
- 結論:
- 在子類方法中訪問一個變量
- 首先在子類局部范圍找
- 然后在子類成員范圍找
- 最后在父類成員范圍找(肯定不能訪問到父類局部范圍)
- 如果還是沒有就報錯。(不考慮父親的父親…)
super關鍵字
- super的用法和this很像
-
this
代表本類對應的引用。 -
super
代表父類存儲空間的標識(可以理解為父類引用)
-
- 用法(this和super均可如下使用)
- 訪問
成員變量
- this.成員變量
- super.成員變量
- 訪問
構造方法
(子父類的構造方法問題講)- this(…) :調用本類的
構造方法
- super(…):調用父類的
構造方法
- this(…) :調用本類的
- 訪問
成員方法
(子父類的成員方法問題講)- this.成員方法()
- super.成員方法()
- 訪問
繼承中構造方法的關系
- 子類中所有的構造方法默認都會訪問父類中的<font color =red>無參</font>
構造方法
- 因為子類會繼承父類中的數據,可能還會使用父類的數據。所以,子類初始化之前,一定要先完成父類數據的初始化。
- 每一個構造方法的第一條語句默認都是:
super()
class Father {
int age;
public Father() {
System.out.println("Father的無參構造方法");
}
public Father(String name) {
System.out.println("Father的帶參構造方法");
}
}
class Son extends Father {
public Son() {
//super();//默認都會有的
System.out.println("Son的無參構造方法");
}
public Son(String name) {
//super();//默認都會有的
System.out.println("Son的帶參構造方法");
}
}
class ExtendsDemo6 {
public static void main(String[] args) {
//創建對象
Son s = new Son();
System.out.println("------------");
Son s2 = new Son("林青霞");
}
}
-
程序運行結果:
- 如果父類沒有無參構造方法,那么子類的構造方法會出現什么現象呢,如何解決?
- 會報錯
- 解決辦法:
- A:在父類中加一個無參構造方法
- B:通過使用
super
關鍵字去顯示的調用父類的帶參構造方法
。
- 子類中一定要有一個方法訪問了父類的構造方法,否則父類數據就沒有辦法初始化。
- 注:super(...)必須放在第一條語句上,否則就可能出現對父類的數據進行了多次初始化,所以必須放在第一條語句上面。
- 一個類的初始化過程
-
成員變量
進行初始化 -
默認
初始化 -
顯示
初始化 -
構造方法
初始化
-
- A:一個類的
靜態代碼塊
,構造代碼塊
,構造方法
的執行流程-
靜態代碼塊
>構造代碼塊
>構造方法
-
- B:靜態的內容是隨著類的加載而加載
- 靜態代碼塊的內容會優先執行
- C:子類初始化之前先會進行父類的初始化
- 練習1
/*
看程序寫結果:
A:成員變量 就近原則
B:this和super的問題
this訪問本類的成員
super訪問父類的成員
C:子類構造方法執行前默認先執行父類的無參構造方法
D:一個類的初始化過程
成員變量進行初始化
默認初始化
顯示初始化
構造方法初始化
結果:
fu
zi
30
20
10
*/
class Fu{
public int num = 10;
public Fu(){
System.out.println("fu");
}
}
class Zi extends Fu{
public int num = 20;
public Zi(){
System.out.println("zi");
}
public void show(){
int num = 30;
System.out.println(num); //30
System.out.println(this.num); //20
System.out.println(super.num); //10
}
}
class ExtendsTest {
public static void main(String[] args) {
Zi z = new Zi();
z.show();
}
}
- 練習2:
/*
看程序寫結果:
A:一個類的靜態代碼塊,構造代碼塊,構造方法的執行流程
靜態代碼塊 > 構造代碼塊 > 構造方法
B:靜態的內容是 隨著類的加載而加載
靜態代碼塊的內容會優先執行
C:子類初始化之前先會進行父類的初始化
結果是:
靜態代碼塊Fu
靜態代碼塊Zi
構造代碼塊Fu
構造方法Fu
構造代碼塊Zi
構造方法Zi
*/
class Fu {
static {
System.out.println("靜態代碼塊Fu");
}
{
System.out.println("構造代碼塊Fu");
}
public Fu() {
System.out.println("構造方法Fu");
}
}
class Zi extends Fu {
static {
System.out.println("靜態代碼塊Zi");
}
{
System.out.println("構造代碼塊Zi");
}
public Zi() {
System.out.println("構造方法Zi");
}
}
class ExtendsTest2 {
public static void main(String[] args) {
Zi z = new Zi();
}
}
- 練習3(<font color = red>有難度理解不深刻</font>)
/*
看程序寫結果:
A:成員變量的問題
int x = 10; //成員變量是基本類型
Student s = new Student(); //成員變量是引用類型
B:一個類的初始化過程
成員變量的初始化
默認初始化
顯示初始化
構造方法初始化
C:子父類的初始化(分層初始化)
先進行父類初始化,然后進行子類初始化。
結果:
YXYZ
問題:
雖然子類中構造方法默認有一個super()
初始化的時候,不是按照那個順序進行的。
而是按照分層初始化進行的。
它僅僅表示要先初始化父類數據,再初始化子類數據。
*/
class X {
Y b = new Y();
X() {
System.out.print("X");
}
}
class Y {
Y() {
System.out.print("Y");
}
}
public class Z extends X {
Y y = new Y();
Z() {
//super
System.out.print("Z");
}
public static void main(String[] args) {
new Z();
}
}
繼承中成員方法的關系
方法重寫
概述
- 子類中出現了和父類中一模一樣的方法聲明,也被稱為
方法覆蓋
,方法復寫
。 - 使用特點:
- 如果方法名不同,就調用對應的方法
- 如果方法名相同,最終使用的是子類自己的
- 方法重寫的應用:
- 當子類需要父類的功能,而功能主體子類有自己特有內容時,可以重寫父類中的方法,這樣,即沿襲了父類的功能,又定義了子類特有的內容。
方法重寫的注意事項
- 父類中
私有方法
不能被重寫 - 子類重寫父類方法時,訪問權限不能更低
- 父類靜態方法,子類也必須通過靜態方法進行重寫。(其實這個算不上方法重寫,但是現象確實如此,至于為什么算不上方法重寫,多態中會講解)
class Phone {
public void call(String name) {
System.out.println("給"+name+"打電話");
}
}
class NewPhone extends Phone {
public void call(String name) {
//System.out.println("給"+name+"打電話");
super.call(name);
System.out.println("可以聽天氣預報了");
}
}
class ExtendsDemo9 {
public static void main(String[] args) {
NewPhone np = new NewPhone();
np.call("林青霞");
}
}
練習題
-
Eg1:
方法重寫
和方法重載
的區別?方法重載
能改變返回值類型嗎?-
方法重寫(Override)
:- 在子類中,出現和父類中一模一樣的方法聲明的現象。
-
方法重載(Overload)
:- 同一個類中,出現的方法名相同,參數列表不同的現象。
- 方法重載能改變返回值類型,因為它和返回值類型無關。
-
-
Eg2: this關鍵字和super關鍵字分別代表什么?以及他們各自的使用場景和作用。
-
this
:代表當前類的對象引用 -
super
:代表父類存儲空間的標識。(可以理解為父類的引用,通過這個東西可以訪問父類的成員) - 場景:
- 成員變量:
- this.成員變量
- super.成員變量
- 構造方法:
- this(...)
- super(...)
- 成員方法:
- this.成員方法
- super.成員方法
- 成員變量:
-
Eg3:
//定義人類
class Person {
//姓名
private String name;
//年齡
private int age;
public Person() {
}
public Person(String name,int age) { //"林青霞",27
this.name = name;
this.age = 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;
}
}
//定義學生類
class Student extends Person {
public Student() {}
public Student(String name,int age) { //"林青霞",27
//this.name = name;
//this.age = age;
super(name,age);
}
}
//定義老師類
class Teacher extends Person {
}
class ExtendsTest4 {
public static void main(String[] args) {
//創建學生對象并測試
//方式1
Student s1 = new Student();
s1.setName("林青霞");
s1.setAge(27);
System.out.println(s1.getName()+"---"+s1.getAge());
//方式2
Student s2 = new Student("林青霞",27);
System.out.println(s2.getName()+"---"+s2.getAge());
//補齊老師類中的代碼并進行測試。
}
}