包
包是組織類的一種方式. 使用包的主要目的是保證類的唯一性.
例如, 你在代碼中寫了一個 Test 類. 然后你的舍友也可能寫一個 Test 類. 如果出現兩個同名的類, 就會沖突, 導致 代碼不能編譯通過.
導入包中的類
Java 中已經提供了很多現成的類供我們使用. 例如
public class Test {public static void main(String[] args) {java.util.Date date = new java.util.Date();// 得到一個毫秒級別的時間戳System.out.println(date.getTime());}
}
以使用 java.util.Date 這種方式引入 java.util 這個包中的 Date 類. ?
但是這種寫法比較麻煩一些, 可以使用 import 語句導入包.
import java.util.Date;
public class Test {public static void main(String[] args) {Date date = new Date();// 得到一個毫秒級別的時間戳System.out.println(date.getTime());}
}
如果需要使用 java.util 中的其他類, 可以使用 import java.util.*
import java.util.*;
public class Test {public static void main(String[] args) {Date date = new Date();// 得到一個毫秒級別的時間戳System.out.println(date.getTime());}
}
但是我們更建議顯式的指定要導入的類名. 否則還是容易出現沖突的情況.
import java.util.*;
import java.sql.*;
public class Test {public static void main(String[] args) {// util 和 sql 中都存在一個 Date 這樣的類, 此時就會出現歧義, 編譯出錯Date date = new Date();System.out.println(date.getTime());}
}
// 編譯出錯
Error:(5, 9) java: 對Date的引用不明確java.sql 中的類 java.sql.Date 和 java.util 中的類 java.util.Date 都匹配
在這種情況下需要使用完整的類名
import java.util.*;
import java.sql.*;
public class Test {public static void main(String[] args) {java.util.Date date = new java.util.Date();System.out.println(date.getTime());}
}
靜態導入
使用 import static 可以導入包中的靜態的方法和字段.
import static java.lang.System.*;
public class Test {public static void main(String[] args) {out.println("hello");}
}
使用這種方式可以更方便的寫一些代碼, 例如
import static java.lang.Math.*;
public class Test {public static void main(String[] args) {double x = 30;double y = 40;// 靜態導入的方式寫起來更方便一些. // double result = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));double result = sqrt(pow(x, 2) + pow(y, 2));System.out.println(result);}
}
將類放到包中
基本規則
- 在文件的最上方加上一個 package 語句指定該代碼在哪個包中.
- 包名需要盡量指定成唯一的名字, 通常會用公司的域名的顛倒形式(例如 com.csdn.demo1 ).
- 包名要和代碼路徑相匹配. 例如創建 com.csdn.demo1 的包, 那么會存在一個對應的路徑 com/csdn/demo1 來存儲代碼.
- 如果一個類沒有 package 語句, 則該類被放到一個默認包中.
操作步驟
1) 在 IDEA 中先新建一個包: 右鍵 src -> 新建 -> 包
2) 在彈出的對話框中輸入包名, 例如 com.csdn.demo1
3) 在包中創建類, 右鍵包名 -> 新建 -> 類, 然后輸入類名即可.
4) 此時可以看到我們的磁盤上的目錄結構已經被 IDEA 自動創建出來了
5) 同時我們也看到了, 在新創建的 Test.java 文件的最上方, 就出現了一個 package 語句
包的訪問權限控制
我們已經了解了類中的 public 和 private.
private 中的成員只能被類的內部使用. 如果某個成員不包含 public 和 private 關鍵字, 此時這個成員可以在包內部的其他類使用, 但是不能在包外部的類使 用.
下面的代碼給了一個示例. Demo1 和 Demo2 是同一個包中, Test 是其他包中.
Demo1.java
package com.csdn.demo;
public class Demo1 {int value = 0;
}
Demo2.java
package com.csdn.demo; public class Demo2 { public static void Main(String[] args) { Demo1 demo = new Demo1(); System.out.println(demo.value); }
}
// 執行結果, 能夠訪問到 value 變量
Test.java
import com.csdn.demo.Demo1; public class Test { public static void main(String[] args) { Demo1 demo = new Demo1(); System.out.println(demo.value); }
} // 編譯出錯
Error:(6, 32) java: value在com.csdn.demo.Demo1中不是公共的; 無法從外部程序包中對其進行訪問
常見的系統包
1. java.lang:系統常用基礎類(String、Object),此包從JDK1.1后自動導入。
2. java.lang.re?ect:java 反射編程包;
3. java.net:進行網絡編程開發包。
4. java.sql:進行數據庫開發的支持包。
5. java.util:是java提供的工具程序包。(集合類等) 非常重要
6. java.io:I/O編程開發包。
?繼承
語法規則
基本語法
class 子類 extends 父類 { }
- 使用 extends 指定父類.
- Java 中一個子類只能繼承一個父類 (而C++/Python等語言支持多繼承).
- 子類會繼承父類的所有 public 的字段和方法.
- 對于父類的 private 的字段和方法, 子類中是無法訪問的.
- 子類的實例中, 也包含著父類的實例.
- 可以使用 super 關鍵字得到父類實例的引用.
class Animal { public String name; public Animal(String name) { this.name = name; } public void eat(String food) { System.out.println(this.name + "正在吃" + food); }
} class Cat extends Animal { public Cat(String name) { // 使用 super 調用父類的構造方法. super(name); }
} class Bird extends Animal { public Bird(String name) { super(name); } public void fly() { System.out.println(this.name + "正在飛 ︿( ̄︶ ̄)︿"); }
} public class Test { public static void main(String[] args) { Cat cat = new Cat("小黑"); cat.eat("貓糧"); Bird bird = new Bird("圓圓"); bird.fly(); }
}
extends 英文原意指 "擴展". 而我們所寫的類的繼承, 也可以理解成基于父類進行代碼上的 "擴展". 例如我們寫的 Bird 類, 就是在 Animal 的基礎上擴展出了 ?y 方法.
如果我們把 name 改成 private, 那么此時子類就不能訪問了.
// 編譯出錯
Error:(19, 32) java: name 在 Animal 中是 private 訪問控制
protected 關鍵字
剛才我們發現, 如果把字段設為 private, 子類不能訪問. 但是設成 public, 又違背了我們 "封裝" 的初衷. 兩全其美的辦法就是 protected 關鍵字.
- 對于類的調用者來說, protected 修飾的字段和方法是不能訪問的
- 對于類的 子類 和 同一個包的其他類 來說, protected 修飾的字段和方法是可以訪問的
小結: Java 中對于字段和方法共有四種訪問權限
- private: 類內部能訪問, 類外部不能訪問
- 默認(也叫包訪問權限): 類內部能訪問, 同一個包中的類可以訪問, 其他類不能訪問.
- protected: 類內部能訪問, 子類和同一個包中的類可以訪問, 其他類不能訪問.
- public : 類內部和類的調用者都能訪問
更復雜的繼承關系
剛才我們的例子中, 只涉及到 Animal, Cat 和 Bird 三種類. 但是如果情況更復雜一些呢?
針對 Cat 這種情況, 我們可能還需要表示更多種類的貓~
這個時候使用繼承方式來表示, 就會涉及到更復雜的體系.
// Animal.java
public Animal { ...
} // Cat.java
public Cat extends Animal { ...
} // ChineseGardenCat.java
public ChineseGardenCat extends Cat { ...
} // OrangeCat.java
public Orange extends ChineseGardenCat { ...
}
......
如剛才這樣的繼承方式稱為多層繼承, 即子類還可以進一步的再派生出新的子類.
時刻牢記, 我們寫的類是現實事物的抽象.
而我們真正在公司中所遇到的項目往往業務比較復雜, 可能會涉及到一 系列復雜的概念, 都需要我們使用代碼來表示, 所以我們真實項目中所寫的類也會有很多. 類之間的關系也會更加 復雜.
但是即使如此, 我們并不希望類之間的繼承層次太復雜. 一般我們不希望出現超過三層的繼承關系. 如果繼承層 次太多, 就需要考慮對代碼進行重構了.
如果想從語法上進行限制繼承, 就可以使用 ?nal 關鍵字
?nal 關鍵字
曾經我們學習過 ?nal 關鍵字, 修飾一個變量或者字段的時候, 表示 常量 (不能修改).
final int a = 10;
a = 20; // 編譯出錯
?nal 關鍵字也能修飾類, 此時表示被修飾的類就不能被繼承.
final public class Animal { ...
} public class Bird extends Animal { ...
} // 編譯出錯
Error:(3, 27) java: 無法從最終com.csdn.Animal進行繼承
?nal 關鍵字的功能是 限制 類被繼承 "限制" 這件事情意味著 "不靈活".
在編程中, 靈活往往不見得是一件好事. 靈活可能意味著更容易出錯.
是用 ?nal 修飾的類被繼承的時候, 就會編譯報錯, 此時就可以提示我們這樣的繼承是有悖這個類設計的初衷的.