1.數(shù)據(jù)結(jié)構(gòu)
-
枚舉(Enumeration)
枚舉接口雖然它本身不屬于數(shù)據(jù)結(jié)構(gòu),但它在其他數(shù)據(jù)結(jié)構(gòu)的范疇里應用很廣。
枚舉接口定義了一種從數(shù)據(jù)結(jié)構(gòu)中取回連續(xù)元素的方式绰咽。
Enumeration接口中定義了一些方法菇肃,通過這些方法可以枚舉(一次獲得一個)對象集合中的元素。
現(xiàn)已比較少使用取募,一般會出現(xiàn)在Vector和Properties這些傳統(tǒng)類所定義的方法中
import java.util.Vector;
import java.util.Enumeration;
public class CodeExercise {
public static void main(String[] args) {
Enumeration<String> days;
Vector<String> dayNames = new Vector<String>();
dayNames.add("Sunday");
dayNames.add("Monday");
dayNames.add("Tuesday");
dayNames.add("Wednesday");
dayNames.add("Thursday");
dayNames.add("Friday");
dayNames.add("Saturday");
//將Vector元素給到枚舉
days = dayNames.elements();
// 測試枚舉是否包含更多的元素
while(days.hasMoreElements()){
// 返回下一個元素
System.out.println(days.nextElement());
}
}
}
-
位集合(BitSet)
一個Bitset類創(chuàng)建一種特殊類型的數(shù)組來保存位值琐谤。
public class CodeExercise {
public static void main(String[] args) {
BitSet bits1 = new BitSet(16);
BitSet bits2 = new BitSet(16);
for(int i=0;i<16;i++){
if((i%2) == 0) bits1.set(i);
if((i%2) != 0) bits2.set(i);
}
// bits1:{0, 2, 4, 6, 8, 10, 12, 14}
System.out.println("bits1:"+bits1);
// bits2:{1, 3, 5, 7, 9, 11, 13, 15}
System.out.println("bits2:"+bits2);
// 取交
bits2.and(bits1);
System.out.println("bits2 and bits1:"+bits2);
// 取并
bits2.or(bits1);
System.out.println("bits2 or bits1:"+bits2);
// 取異或
bits2.xor(bits1);
System.out.println("bits2 xor bits1:"+bits2);
}
}
-
向量(Vector)
Vector類實現(xiàn)了一個動態(tài)數(shù)組。和ArrayList很相似玩敏,但兩者是不同的:- Vector是同步訪問的
- Vector包含了許多傳統(tǒng)的方法斗忌,這些方法不屬于集合框架
Vector主要用在事先不知道數(shù)組大小,或者只是需要一個可以改變大小的數(shù)組的情況
import java.util.Vector;
import java.util.Enumeration;
public class CodeExercise {
public static void main(String[] args) {
// capacity只會以2位單位增加
Vector v = new Vector(3,2);
// size = 0
System.out.println("the initial size of v:" + v.size());
// capacity = 3
System.out.println("the initial capacity of v:" + v.capacity());
// 將指定的組件添加到此向量的末尾旺聚,將其大小增加 1织阳。
v.addElement(new Integer(3));
v.addElement("string");
v.addElement(new Double(5.0));
v.addElement(new Float(6.6));
// size 4
System.out.println("the size of v:" + v.size());
// capacity 5
System.out.println("the capacity of v:" + v.capacity());
Enumeration vEnum = v.elements();
System.out.println("elements in vector");
while(vEnum.hasMoreElements()){
System.out.print(vEnum.nextElement()+" ");
}
}
}
-
棧(Stack)
棧是Vector的一個子類,棧內(nèi)元素后進先出砰粹。
import java.util.*;
public class CodeExercise {
public static void main(String[] args) {
Stack<Integer> st = new Stack<Integer>();
// stack.empty() 判斷棧是否為空
while(st.empty() == true){
System.out.println("st is empty.");
break;
}
st.push(1);
st.push(2);
st.push(3);
st.push(4);
st.push(5);
System.out.println(st);
// a = 5
int a = st.pop();
System.out.println("Pop element is: " + a);
}
}
-
字典(Dictionary)
Dictionary是一個抽象類唧躲,用來存儲key/value對,作用和Map類相似碱璃。
給出key和value的值弄痹,就可以將value存儲在Dictionary的對象中。一旦被存儲嵌器,就可以通過key來獲取它肛真。
Dictionary類已經(jīng)過時,實際開發(fā)中爽航,往往通過實現(xiàn)Map接口來獲取Key/Value的存儲功能蚓让。
Map代碼:
import java.util.*;
public class CodeExercise {
public static void main(String[] args) {
Map m1 = new HashMap();
m1.put("Zara",8);
m1.put("Mahnaz","31");
m1.put("Ayan","12");
m1.put("Daisy","12");
System.out.println(m1);
}
}
-
哈希表(Hashtable)
Hashtable和HashMap類很相似,但它支持同步讥珍。注:Hashtable已經(jīng)被淘汰了历极,簡單來說就是,如果不需要線程安全串述,那么使用HashMap,如果需要線程安全寞肖,那么使用ConcurrentHashMap纲酗。
-
屬性(Properties)
Properties繼承于Hashtable。表示一個持久的屬性集新蟆。
屬性列表中每個鍵及其對應值都是一個字符串觅赊。
import java.util.*;
public class CodeExercise {
public static void main(String[] args) {
Properties capitals = new Properties();
Set states;
String str;
capitals.put("Illinois","Springfield");
capitals.put("Missouri","Jefferson City");
capitals.put("Washington","Olympia");
capitals.put("California","Sacramento");
capitals.put("Indiana","Indianapolis");
states = capitals.keySet();
// 迭代器一種用于訪問集合的方法
Iterator itr = states.iterator();
while(itr.hasNext()){
str = (String)itr.next();
System.out.println("The capital of " + str + " is " + capitals.getProperty(str));
}
}
}
2.控制語句
Java控制語句大致可分為三大類:
- 選擇語句
- if 語句
- if...else 語句
- if...else if...else 語句
- 嵌套的if...else 語句
- switch語句
default
在沒有case
語句的值和變量值相等的時候執(zhí)行。default
分支不需要break
語句琼稻。
- 循環(huán)語句
- while 循環(huán)
- do while 循環(huán)
- for 循環(huán)
- for each 循環(huán)
- 中斷語句
- break關(guān)鍵字
- continue關(guān)鍵字
- return關(guān)鍵字吮螺,跳出函數(shù)整體
public class CodeExercise {
public static void main(String[] args) {
int[] numbers = { 10, 20, 30, 40, 50 };
for (int x : numbers) {
if (x == 30) {
// 直接跳出main函數(shù)
return;
}
System.out.print(x);
System.out.print("\n");
}
System.out.println("return 示例結(jié)束");
}
}
輸出:
10
20
Process finished with exit code 0
實踐參考
- 選擇分支特別多的情況下,
switch
語句優(yōu)于if...else if... else
語句 -
switch
語句盡量考慮default
,并且將其放在最后 -
for each
循環(huán)優(yōu)先于傳統(tǒng)的for
循環(huán) - 不要循環(huán)遍歷容器元素,然后刪除特定元素鸠补。正確的做法是遍歷容器的迭代器(
Iterator
)萝风,刪除元素。
3.面向?qū)ο缶幊?/h3>
面向?qū)ο缶幊痰娜笾饕卣鳎?/p>
- 封裝性
- 繼承性
- 多態(tài)性
封裝性:在面向?qū)ο蟪淌皆O計方法中紫岩,封裝是指一種將抽象性函式接口的實現(xiàn)細節(jié)部分包裝规惰、隱藏起來的方法。
封裝可以被認為是一個保護屏障泉蝌,防止該類的代碼和數(shù)據(jù)被外部類定義的代碼隨機訪問歇万。
封裝最主要的功能在于我們能修改自己實現(xiàn)的代碼,而不用修改那些調(diào)用我們代碼的程序片段勋陪。
封裝的簡單實現(xiàn):
- 修改屬性的可見性(一般限制為private)
public class Person {
private String name;
private int age;
}
- 對每個值屬性提供對外的公共方法訪問贪磺,也就是創(chuàng)建一對賦取值方法,用于對私有屬性的訪問诅愚。
public class Person{
private String name;
private int age;
public int getAge(){
return age;
}
public String getName(){
return name;
}
public void setAge(int age){
this.age = age;
}
public void setName(String name){
this.name = name;
}
}
注:以上實例中寒锚,public方法是外部類訪問該類成員變量的入口,這些方法被稱為getter和setter方法呻粹。
為什么需要setter和getter?
繼承性:
參考
多個類中存在相同屬性和行為時壕曼,將這些內(nèi)容抽取到單獨一個類中,那么多個類無需再定義這些屬性和行為等浊,只要繼承那個類即可腮郊。
子類可以直接訪問父類中的非私有的屬性和行為。通過extends
讓類與類之間產(chǎn)生繼承關(guān)系筹燕。
class Succlass extends Class{}
繼承的特點
1.Java只支持單繼承轧飞,不支持多繼承
class Demo extends Demo1, Demo2... //error
2.Java支持多重繼承(繼承體系)
class B extends A { }
class C extends A { }
多態(tài)性:
對象在不同時刻表現(xiàn)出來的不同狀態(tài)。換句話可以理解為撒踪,同一個事件發(fā)生在不同的對象上會產(chǎn)生不同的結(jié)果过咬。
多態(tài)的前提:
- 繼承
- 重寫
- 父類引用指向子類對象:
Parent p = new Child();
多態(tài)的實現(xiàn)方式:
1.重寫
2.接口
3.抽象類和抽象方法
Overloading 的條件 以及與Overriding的區(qū)別:
重寫(Overriding)是子類對父類中允許訪問的方法進行重新編寫,返回值和形參都不能改變制妄。
重寫的好處在于掸绞,子類可以根據(jù)需要實現(xiàn)父類的方法。
重寫方法不能跑出新的檢查異掣蹋或者比被重寫方法申明更加寬泛的異常衔掸。例如:父類的一個方法申明了一個檢查異常IOException,但是在重寫這個方法的時候不能拋出Exception異常俺抽,因為Exception是IOException的父類敞映。
public class CodeExercise {
public static void main(String[] args) {
Test a = new Test();
ChildTest b = new ChildTest();
a.f(3);
b.f(4);
b.f1();
}
}
class Test{
public void f(int a){
System.out.println("Parent class " + a);
}
}
class ChildTest extends Test{
public void f(int b){
// 子類調(diào)用父類的被重寫的方法時,用super關(guān)鍵字
super.f(b);
System.out.println("Child class " + b);
}
public void f1(){
System.out.println("Child class f1");
}
}
output:
Parent class 3
Parent class 4
Child class 4
Child class f1
重載(Overloading)是在一個類里面磷斧,方法名字相同振愿,而參數(shù)不同捷犹,返回類型不限制。
每個重載的方法都必須有一個獨一無二的參數(shù)類型列表冕末。最常用的地方就是構(gòu)造器的重載萍歉。
public class CodeExercise {
public void test(){
System.out.println(1);
}
public int test(int a){
return a;
}
public String test(String a){
return a;
}
public String test(String a,String b){
return a+b;
}
public static void main(String[] args) {
CodeExercise oj = new CodeExercise();
oj.test();
System.out.println(oj.test(2));
System.out.println(oj.test("test"));
System.out.println(oj.test("test","test1"));
}
}
output:
1
2
test
testtest1
總結(jié):
方法的重寫和重載時Java多態(tài)性的不同表現(xiàn),重寫是父類與子類之間多態(tài)性的一種表現(xiàn)栓霜,重載可以理解成多態(tài)的具體表現(xiàn)形式翠桦。
- 重載時一個類中定義了多個方法名相同,但參數(shù)數(shù)量不同或類型不同或次序不同胳蛮。
- 重寫是在子類方法與父類方法的名字相同销凑,并且參數(shù)個數(shù)與類型一樣,唯一不同的則是實現(xiàn)的內(nèi)核仅炊。
4.數(shù)組斗幼、對象和類
數(shù)組:數(shù)組是用于存儲固定大小的同類型元素。
對象:在java中抚垄,對象主要包括屬性和方法蜕窿。
類:是抽象的概念集合,表示的是一個共性的產(chǎn)物呆馁,類之中定義的是屬性和方法桐经。
抽象類:如果一個類中沒有包含足夠的信息來描繪一個具體的對象,這樣的類就是抽象類浙滤。由于抽象類不能實例化對象阴挣,所以抽象類必須被繼承
5.接口、繼承關(guān)系纺腊、多態(tài)畔咧、內(nèi)部類
接口:接口是抽象方法和常量值的集合。從本質(zhì)上講揖膜,接口是一種特殊的抽象類誓沸,這種抽象類只包含常量和方法的定義,而沒有變量和方法的實現(xiàn)壹粟。
一個類通過繼承接口的方式拜隧,從而繼承接口的抽象方法。
接口并不是類趁仙,編寫接口的方式和類很相似洪添,但他們屬于不同的概念。類描述對象的屬性和方法幸撕。接口則包含類要實現(xiàn)的方法薇组。
接口的聲明:
public interface Animal {
public void eat();
public void travel();
}
接口的實現(xiàn):
public class MammalInt implements Animal{
public void eat(){
System.out.println("Mammal eats");
}
public void travel(){
System.out.println("Mammal travels");
}
public int noOfLegs(){
return 0;
}
public static void main(String args[]){
MammalInt m = new MammalInt();
m.eat();
m.travel();
}
}
接口的繼承:
public interface Sports
{
public void setHomeTeam(String name);
public void setVisitingTeam(String name);
}
// 文件名: Football.java
public interface Football extends Sports
{
public void homeTeamScored(int points);
public void visitingTeamScored(int points);
public void endOfQuarter(int quarter);
}
// 文件名: Hockey.java
public interface Hockey extends Sports
{
public void homeGoalScored();
public void visitingGoalScored();
public void endOfPeriod(int period);
public void overtimePeriod(int ot);
}
Hockey接口自己聲明了四個方法外臂,從Sports接口繼承了兩個方法坐儿,故實現(xiàn)Hockey接口的類需要實現(xiàn)6個方法。
同理,實現(xiàn)Football接口的類需要實現(xiàn)5個方法貌矿。
抽象類:由于抽象類不能實例化對象炭菌,所以抽象類必須被繼承,才能被使用逛漫。通常在設計階段決定要不要設計抽象類黑低。
例如一個圖形類Shape
,它有一個方法draw()
,Shape
其實是一個抽象的概念酌毡,具體的draw()
方法并不知道如何去實現(xiàn)克握,只有子類才知道如何實現(xiàn)的方法,這種方法一般被定義為抽象方法枷踏。
一個類在繼承抽象類之后菩暗,必須實現(xiàn)抽象類中定義的所有抽象方法,除非它自己也聲明為抽象類旭蠕。
public abstract class Shape{
// .... 其他代碼
public abstract void draw();
}
public class Circle extends Shape{
// ...其他代碼
@Override
public void draw(){
}
}
為什么需要抽象類停团?
引入抽象類和抽象方法,是Java提供的一種語法工具掏熬。
使用抽象方法佑稠,而非空的方法體,子類就知道必須要實現(xiàn)該方法旗芬,而不可能忽略舌胶。
使用抽象類,類的使用者創(chuàng)建對象的時候岗屏,就知道他必須要使用某個具體的子類辆琅,而不可能無用不完整的父類。
抽象類和接口
- 抽象類中的方法可以有實現(xiàn)方法的具體功能这刷,但是接口中的方法不行婉烟。
- 抽象類中的成員變量可以使各種類型,接口中的成員變量只能是
public static final
類型的暇屋。 - 接口中不能含有靜態(tài)代碼塊以及靜態(tài)方法似袁,而抽象類可以有。
- 一個類只能繼承一個抽象類咐刨,而一個類卻可以實現(xiàn)多個接口
內(nèi)部類:
將一個類定義在另一個類里面昙衅,里面的那個類就被稱為內(nèi)部類。
為什么要使用內(nèi)部類
是因為定鸟,每個內(nèi)部類都能獨立地繼承一個接口的實現(xiàn)而涉,所以無論外部類是否已經(jīng)繼承了某個接口的實現(xiàn),對于內(nèi)部類都沒有影響联予。
內(nèi)部類比較好的解決了多重繼承的問題啼县。
附:Java的多重繼承問題:
多重繼承主要指的是一個類可以同時繼承多個類材原。例如A類繼承自B類和C類。
若B,C繼承A類季眷,即A -> B,A -> C余蟹,并且D繼承B,C。若B,C都改寫了A中的一個方法void a()
成void a1()
和void a2()
子刮,D類不知道該用a1還是a2威酒。
但在接口中并不會出現(xiàn)這樣的問題是因為,接口是抽象類挺峡,它只規(guī)定了a方法并沒有實現(xiàn)葵孤,所以不會出現(xiàn)a方法有兩種實現(xiàn)版本的問題。
內(nèi)部類的主要分類:
成員內(nèi)部類橱赠、局部內(nèi)部類佛呻、匿名內(nèi)部類和靜態(tài)內(nèi)部類。
- 成員內(nèi)部類
是最普通的內(nèi)部類病线,他是外部類的一個成員吓著,所以他是可以無限制訪問外部類所有成員屬性和方法,但是外部類則需要通過內(nèi)部類實例來訪問內(nèi)部類的成員屬性和方法送挑。
public class CodeExercise {
private String sex = "Male";
public static String name = "OutterMatthew";
//外部類的方法
public void outterdisplay(){
System.out.println("OutterClass" );
}
//推薦使用 getter來獲取成員內(nèi)部類绑莺,尤其是該內(nèi)部類的構(gòu)造參數(shù)無參數(shù)時
public InnerClass getterInner(){
return new InnerClass();
}
//成員內(nèi)部類
public class InnerClass{
public void display(){
// 非靜態(tài)內(nèi)部類中可以調(diào)用外部類的任何成員,無論靜態(tài)還是非靜態(tài)
System.out.println("InnerClass call Outter name: " + name);
System.out.println("InnerClass call Outter sex: " + sex);
outterdisplay();
}
}
public static void main(String[] args) {
// new CodeExercise().getterInner()是通過外部類的object調(diào)用getterInner惕耕,從而獲取成員內(nèi)部類
CodeExercise.InnerClass inner = new CodeExercise().getterInner();
inner.display();
}
}
- 局部內(nèi)部類
局部內(nèi)部類是嵌套在方法和作用于內(nèi)的纺裁。
局部內(nèi)部類即在方法中定義的內(nèi)部類,與局部變量類似司澎,在局部內(nèi)部類前不加修飾符public或private欺缘,其范圍為定義它的代碼塊。
注意:局部內(nèi)部類中不可定義static變量挤安,可以訪問外部類的局部變量(即方法內(nèi)的變量)谚殊,但變量必須是final
的。
public class CodeExercise {
private int a = 1;
private int out_n = 2;
//外部類的方法
public void outterdisplay(final int k){
final int a = 100;
final int b = 200;
// 局部內(nèi)部類
class InnerClass{
int a = 101;
// static int m = 10; 在非靜態(tài)內(nèi)部類中不能存在靜態(tài)成員
InnerClass(){
display();
}
public void display(){
// 沒有與外部類同名的變量蛤铜,可直接調(diào)用
System.out.println("局部內(nèi)部類訪問外部類非同名實例變量: " + out_n);
// 調(diào)用局部變量(方法內(nèi)的變量)嫩絮,必須final修飾!
System.out.println("局部內(nèi)部類訪問方法內(nèi)的變量: " + k);
// 若內(nèi)部類和外部類同名围肥,則訪問的是內(nèi)部類的變量
System.out.println("變量同名剿干,則訪問內(nèi)部類的: " + a);
// this.同名變量 訪問的也是內(nèi)部類變量
System.out.println("加 this.變量名,訪問的也是內(nèi)部類變量: " + this.a);
// 外部類類名.this.同名變量名 訪問的是外部類變量
System.out.println("外部類類名.this.變量名穆刻,訪問的是外部類變量: " + CodeExercise.this.a);
}
}
// 創(chuàng)建新的內(nèi)部類對象
new InnerClass();
}
public static void main(String[] args) {
CodeExercise outer = new CodeExercise();
outer.outterdisplay(300);
}
}
匿名內(nèi)部類
匿名內(nèi)部類往往是沒有名字的靜態(tài)內(nèi)部類
使用static修飾的內(nèi)部類稱之為靜態(tài)內(nèi)部類置尔,也被稱為嵌套內(nèi)部類。
靜態(tài)內(nèi)部類和非靜態(tài)內(nèi)部類之間的最大區(qū)別:非靜態(tài)內(nèi)部類在編譯完成之后會隱含地保存著一個引用氢伟,該引用是指向創(chuàng)建它的外部類榜轿,但是靜態(tài)內(nèi)部類卻沒有篮愉。這就意味著:
- 靜態(tài)內(nèi)部類的創(chuàng)建時不需要依賴外部類的。
- 靜態(tài)內(nèi)部類不能使用任何外部類的非static成員變量和方法差导。
public class CodeExercise {
private String sex = "Male";
public static String name = "OutterMatthew";
//外部類的方法
public void display(){
// 外部類訪問靜態(tài)內(nèi)部類
System.out.println("OutterClass call static InnerClass1"+ InnerClass1.name1);
// 靜態(tài)內(nèi)部類可以直接創(chuàng)建實例,不需要依賴外部類
new InnerClass1().display();
CodeExercise.InnerClass2 inner2 = new CodeExercise().new InnerClass2();
System.out.println("OutterClass call static InnerClass2" + inner2.name2);
inner2.display();
}
//靜態(tài)內(nèi)部類
public static class InnerClass1{
// 在靜態(tài)內(nèi)部類中可以存在靜態(tài)成員
public static String name1 = "InnerMatthew1";
public void display(){
// 靜態(tài)內(nèi)部類只能訪問外部類的靜態(tài)成員變量和方法
// 不能訪問外部類的非靜態(tài)成員變量和方法
System.out.println("OutterClass1 name: " + name);
}
}
//非靜態(tài)內(nèi)部類
public class InnerClass2{
// 在非靜態(tài)內(nèi)部類中不能存在靜態(tài)成員
public String name2 = "InnerMatthew2";
public void display(){
// 非靜態(tài)內(nèi)部類中可以調(diào)用外部類的任何成員猪勇,無論靜態(tài)還是非靜態(tài)
System.out.println("OutterClass2 name: " + name);
System.out.println("OutterClass2 sex: " + sex);
}
}
public static void main(String[] args) {
CodeExercise outer = new CodeExercise();
outer.display();
}
}