找工作的時(shí)候發(fā)現(xiàn)某公司在線編程題只支持JAVA和C家族唧龄,作為一個(gè)天天python的我簡(jiǎn)直是災(zāi)難,兩天速成一下煮嫌!
第一部分:Java基礎(chǔ)
封裝與接口
- 在一個(gè).java文件中情组,有且只能有一個(gè)類帶有public關(guān)鍵字。不帶關(guān)鍵字的也是可見的,后面會(huì)說(shuō)到。
Interface接口
interface Cup {
void addWater(int w);
void drinkWater(int w);
}
class MusicCup implements Cup
{
public void addWater(int w)
{
this.water = this.water + w;
}
public void drinkWater(int w)
{
this.water = this.water - w;
}
private int water = 0;
}
- 更易于管理
- 一個(gè)類可以使用多個(gè)interface
包
在.java文件的第一行寫上
package com.vamei.society
一個(gè)Java文件中只能有一個(gè)public的類,這個(gè)類要和文件同名!
一個(gè)Java類的完整路徑由它的包和類名共同構(gòu)成玫坛,比如com.vamei.society.Human。相應(yīng)的Human.java程序要放在com/vamei/society/下包晰。
一個(gè)類可以沒有public關(guān)鍵字湿镀,它實(shí)際上也表示一種權(quán)限: 該類在它所在的包中可見炕吸。
包的調(diào)用
我們只需要將Human.java編譯的Human.class放入相應(yīng)的文件夾就可以了。比如肠骆,我將Human.class放入com/vamei/society/中算途。實(shí)際上,你也可以把.java文件放入相應(yīng)路徑蚀腿,Java會(huì)在使用時(shí)自動(dòng)編譯嘴瓤。
如果整個(gè)包(也就是com文件夾)位于當(dāng)前的工作路徑中,那么不需要特別的設(shè)置莉钙,就可以使用包了廓脆。
可以這樣import
import com.vamei.society.*;
也可以直接提供完整路徑使用,則不需要import
如果包沒有放在當(dāng)前工作路徑下磁玉,我們?cè)谑褂冒鼤r(shí)停忿,需要通知Java。設(shè)置系統(tǒng)的CLASSPATH環(huán)境變量蚊伞。
繼承
class Woman extends Human
{
/**
* new method
*/
public Human giveBirth()
{
System.out.println("Give birth");
return (new Human(20));
}
}
基類和衍生類
衍生類不能訪問基類的私有對(duì)象席赂,public的是一樣的都可以訪問,衍生類可以訪問自己的private时迫,外部不能訪問衍生類的private颅停。
protected表示自己不能被外部訪問,但是可以被衍生類訪問掠拳。
super和this類似癞揉,但是super指父類,比如父類有個(gè)getHeight()方法溺欧,那么在子類定義新的getHeight()時(shí)可以在內(nèi)部先執(zhí)行super.getHeight()喊熟。當(dāng)子類和父類有同樣方法時(shí)(參數(shù)都一樣),那么對(duì)外呈現(xiàn)子類的姐刁,內(nèi)部可以用super或者this區(qū)分芥牌。
調(diào)用父類的構(gòu)造方法直接輸入super即可。
class Woman extends Human
{
/**
* constructor
*/
public Woman(int h)
{
super(h); // base class constructor
System.out.println("Hello, Pandora!");
}
}
static 類數(shù)據(jù)與類方法
帶static的成員變量是類成員變量龙填,被所有對(duì)象共享
如果一個(gè)方法聲明為static胳泉,那么它只能調(diào)用static的數(shù)據(jù)和方法,而不能調(diào)用非static的數(shù)據(jù)和方法岩遗。
調(diào)用類方法時(shí),我們可以通過class.method()的方式調(diào)用凤瘦,也可以通過object.method()的方式調(diào)用宿礁。
如果變量前加final,那么這個(gè)變量一旦賦值不能更改(當(dāng)然如果這時(shí)類的實(shí)例蔬芥,這個(gè)實(shí)例可以照常操作)
接口的繼承與抽象類
- 接口可以繼承接口梆靖,而且可以多重繼承控汉,但是類不行。
interface MusicCup extends Cup, Player
{
void display();
}
- 抽象類
abstract class Food {
public abstract void eat();
public void happyFood()
{
System.out.println("Good! Eat Me!");
}
}
- 抽象類中有抽象方法返吻,繼承的時(shí)候一定要覆蓋這些抽象方法姑子,抽象類與接口不同的是它也有具體方法以及具體變量。
對(duì)象引用
Human aPerson = new Human(160);
首先看等號(hào)的右側(cè)测僵。new是在內(nèi)存中為對(duì)象開辟空間街佑。具體來(lái)說(shuō),new是在內(nèi)存的堆(heap)上為對(duì)象開辟空間捍靠。這一空間中沐旨,保存有對(duì)象的數(shù)據(jù)和方法。
再看等號(hào)的左側(cè)榨婆。aPerson指代一個(gè)Human對(duì)象磁携,被稱為對(duì)象引用(reference)。實(shí)際上良风,aPerson并不是對(duì)象本身谊迄,而是類似于一個(gè)指向?qū)ο蟮闹羔槨Person存在于內(nèi)存的棧(stack)中烟央。
當(dāng)我們用等號(hào)賦值時(shí)统诺,是將右側(cè)new在堆中創(chuàng)建對(duì)象的地址賦予給對(duì)象引用。
這里的內(nèi)存吊档,指的是JVM (Java Virtual Machine)虛擬出來(lái)的Java進(jìn)程內(nèi)存空間篙议。
new關(guān)鍵字的完整含義是,在堆上創(chuàng)建對(duì)象怠硼。棧比較快鬼贱。
基本類型(primitive type)的對(duì)象,比如int, double香璃,保存在棧上这难。
一個(gè)對(duì)象可以有多個(gè)引用 (一個(gè)人可以放多個(gè)風(fēng)箏)。當(dāng)程序通過某個(gè)引用修改對(duì)象時(shí)葡秒,通過其他引用也可以看到該修改姻乓。
垃圾回收
隨著方法調(diào)用的結(jié)束,引用和基本類型變量會(huì)被清空眯牧。由于對(duì)象存活于堆蹋岩,所以對(duì)象所占據(jù)的內(nèi)存不會(huì)隨著方法調(diào)用的結(jié)束而清空。進(jìn)程空間可能很快被不斷創(chuàng)建的對(duì)象占滿学少。
Java內(nèi)建有垃圾回收(garbage collection)機(jī)制剪个,用于清空不再使用的對(duì)象,以回收內(nèi)存空間版确。
當(dāng)沒有任何引用指向某個(gè)對(duì)象時(shí)扣囊,該對(duì)象被清空乎折。
參數(shù)傳遞
基本類型變量的值傳遞,意味著變量本身被復(fù)制侵歇,并傳遞給Java方法骂澄。Java方法對(duì)變量的修改不會(huì)影響到原變量。
引用的值傳遞惕虑,意味著對(duì)象的地址被復(fù)制坟冲,并傳遞給Java方法。Java方法根據(jù)該引用的訪問將會(huì)影響對(duì)象枷遂。
就是new出來(lái)的是引用傳遞樱衷,普通的是值傳遞,普通的是存在棧中的酒唉。
類型轉(zhuǎn)換與多態(tài)
Java是一種強(qiáng)類型(strongly typing)語(yǔ)言矩桂,它會(huì)對(duì)類型進(jìn)行檢查。比如獎(jiǎng)Cup類的對(duì)象賦給Human類的引用就會(huì)報(bào)錯(cuò)痪伦。
為什么python也是強(qiáng)類型侄榴?
>>> 3+6
9
>>> "3"+6
error
- python看起來(lái)是弱類型因?yàn)樗囊貌挥弥付愋停。?/li>
基本類型變換
- 注意网沾,只是基本類型q稀!辉哥!
int a;
a = (int) 1.23; // narrowing conversion
int a = 3;
double b;
b = a; // widening conversion
- widening可以不加變量類型的
upcast與多態(tài)
public class Test
{
public static void main(String[] args)
{
Cup aCup;
BrokenCup aBrokenCup = new BrokenCup();
aCup = aBrokenCup; // upcast
aCup.addWater(10); // method binding
}
}
我們隨后調(diào)用了aCup(我們聲明它為Cup類型)的addWater()方法桦山。盡管aCup是Cup類型的引用,它實(shí)際上調(diào)用的是BrokenCup的addWater()方法醋旦!也就是說(shuō)恒水,即使我們經(jīng)過upcast,將引用的類型寬松為其基類饲齐,Java依然能正確的識(shí)別對(duì)象本身的類型钉凌,并調(diào)用正確的方法。Java可以根據(jù)當(dāng)前狀況捂人,識(shí)別對(duì)象的真實(shí)類型御雕,這叫做多態(tài)(polymorphism)。多態(tài)是面向?qū)ο蟮囊粋€(gè)重要方面滥搭。
Java告訴我們酸纲,一個(gè)衍生類對(duì)象可以當(dāng)做一個(gè)基類對(duì)象使用,而Java會(huì)正確的處理這種情況瑟匆。
downcast
- 我們可以將一個(gè)基類引用向下轉(zhuǎn)型(downcast)成為衍生類的引用福青,但要求該基類引用所指向的對(duì)象,已經(jīng)是所要downcast的衍生類對(duì)象脓诡。比如可以將上面的hisCup向上轉(zhuǎn)型為Cup類引用后无午,再向下轉(zhuǎn)型成為BrokenCup類引用。
object類
- Java中祝谚,所有的類實(shí)際上都有一個(gè)共同的繼承祖先宪迟,即Object類。
第二部分:JAVA進(jìn)階
String
String也是引用傳遞交惯,不過它不需要new
String是不可變對(duì)象次泽,即使用replace也只是返回一個(gè)新的String
常用String的方法
s.length() 返回s字符串長(zhǎng)度
s.charAt(2) 返回s字符串中下標(biāo)為2的字符
s.substring(0, 4) 返回s字符串中下標(biāo)0到4的子字符串
s.indexOf("Hello") 返回子字符串"Hello"的下標(biāo)
s.startsWith(" ") 判斷s是否以空格開始
s.endsWith("oo") 判斷s是否以"oo"結(jié)束
s.equals("Good World!") 判斷s是否等于"Good World!"
==只能判斷字符串是否保存在同一位置。需要使用equals()判斷字符串的內(nèi)容是否相同席爽。
s.compareTo("Hello Nerd!") 比較s字符串與"Hello Nerd!"在詞典中的順序意荤,
返回一個(gè)整數(shù),如果<0只锻,說(shuō)明s在"Hello Nerd!"之前玖像;
如果>0,說(shuō)明s在"Hello Nerd!"之后齐饮;
如果==0捐寥,說(shuō)明s與"Hello Nerd!"相等。
s.trim() 去掉s前后的空格字符串祖驱,并返回新的字符串
s.toUpperCase() 將s轉(zhuǎn)換為大寫字母握恳,并返回新的字符串
s.toLowerCase() 將s轉(zhuǎn)換為小寫,并返回新的字符串
s.replace("World", "Universe") 將"World"替換為"Universe"捺僻,并返回新的字符串
異常處理
try {
...;
}
catch(IOException e) {
e.printStackTrace();
System.out.println("IO problem");
}
catch() {
...;
}
finally {
...;
}
- 下圖中紅色的是unchecked錯(cuò)誤乡洼,應(yīng)該由程序員編程解決。藍(lán)色的是由于和編程環(huán)境互動(dòng)產(chǎn)生的錯(cuò)誤匕坯,應(yīng)該做異常處理束昵。
- 拋出異常
private void test(double p) throws Exception // 包含throws關(guān)鍵詞不一定會(huì)throw錯(cuò)誤,只是做檢查
{
if (p < 0) {
Exception e = new Exception("p must be positive");
throw e;
}
}
我們?cè)趗seBattery()中有異常處理器醒颖。由于test()方法不直接處理它產(chǎn)生的異常妻怎,而是將該異常拋給上層的useBattery(),所以在test()的定義中泞歉,我們需要throws Exception來(lái)說(shuō)明逼侦。
我們可以自定義異常類,只要繼承現(xiàn)有異常類就可以了腰耙。
IO基礎(chǔ)
- 基本操作,讀文件榛丢,文件要在project目錄下
public static void main(String[] args) {
try {
BufferedReader br =
new BufferedReader(new FileReader("file.txt"));
String line = br.readLine();
while (line != null) {
System.out.println(line);
line = br.readLine();
}
br.close();
} catch (IOException e) {
System.out.println("IO Problem");
}
}
BufferedReader()是一個(gè)裝飾器(decorator),它接收一個(gè)原始的對(duì)象挺庞,并返回一個(gè)經(jīng)過裝飾的晰赞、功能更復(fù)雜的對(duì)象。
基本操作,寫文件
try {
String content = "Thank you for your fish.";
File file = new File("new.txt");
// create the file if doesn't exists
if (!file.exists()) {
file.createNewFile();
}
FileWriter fw = new FileWriter(file.getAbsoluteFile());
BufferedWriter bw = new BufferedWriter(fw);
bw.write(content);
bw.close();
}
catch(IOException e) {
System.out.println("IO Problem");
}
}
內(nèi)存管理與垃圾回收
在Java中掖鱼,JVM中的棧記錄了線程的方法調(diào)用然走。每個(gè)線程擁有一個(gè)棧。在某個(gè)線程的運(yùn)行過程中戏挡,如果有新的方法調(diào)用芍瑞,那么該線程對(duì)應(yīng)的棧就會(huì)增加一個(gè)存儲(chǔ)單元,即幀(frame)褐墅。在frame中拆檬,保存有該方法調(diào)用的參數(shù)、局部變量和返回地址妥凳。
Java的參數(shù)和局部變量只能是基本類型的變量(比如int)竟贯,或者對(duì)象的引用(reference)。因此逝钥,在棧中屑那,只保存有基本類型的變量和對(duì)象引用。引用所指向的對(duì)象保存在堆中晌缘。(引用可能為Null值齐莲,即不指向任何對(duì)象)
當(dāng)被調(diào)用方法運(yùn)行結(jié)束時(shí),該方法對(duì)應(yīng)的幀將被刪除磷箕,參數(shù)和局部變量所占據(jù)的空間也隨之釋放选酗。線程回到原方法,繼續(xù)執(zhí)行岳枷。當(dāng)所有的棧都清空時(shí)芒填,程序也隨之運(yùn)行結(jié)束。
循環(huán)引用
- 我們以棧和static數(shù)據(jù)為根(root)空繁,從根出發(fā)殿衰,跟隨所有的引用,就可以找到所有的可到達(dá)對(duì)象盛泡。也就是說(shuō)闷祥,一個(gè)可到達(dá)對(duì)象,一定被根引用傲诵,或者被其他可到達(dá)對(duì)象引用凯砍。
JVM垃圾回收
JVM的垃圾回收是多種機(jī)制的混合。JVM會(huì)根據(jù)程序運(yùn)行狀況拴竹,自行決定采用哪種垃圾回收悟衩。
我們先來(lái)了解"mark and sweep"。這種機(jī)制下栓拜,每個(gè)對(duì)象將有標(biāo)記信息座泳,用于表示該對(duì)象是否可到達(dá)惠昔。當(dāng)垃圾回收啟動(dòng)時(shí),Java程序暫停運(yùn)行挑势。JVM從根出發(fā)镇防,找到所有的可到達(dá)對(duì)象,并標(biāo)記(mark)薛耻。隨后营罢,JVM需要掃描整個(gè)堆,找到剩余的對(duì)象饼齿,并清空這些對(duì)象所占據(jù)的內(nèi)存。
另一種是"copy and sweep"蝙搔。這種機(jī)制下缕溉,堆被分為兩個(gè)區(qū)域。對(duì)象總存活于兩個(gè)區(qū)域中的一個(gè)吃型。當(dāng)垃圾回收啟動(dòng)時(shí)证鸥,Java程序暫停運(yùn)行。JVM從根出發(fā)勤晚,找到可到達(dá)對(duì)象枉层,將可到達(dá)對(duì)象復(fù)制到空白區(qū)域中并緊密排列,修改由于對(duì)象移動(dòng)所造成的引用地址的變化赐写。最后鸟蜡,直接清空對(duì)象原先存活的整個(gè)區(qū)域,使其成為新的空白區(qū)域挺邀。
可以看到揉忘,"copy and sweep"需要更加復(fù)雜的操作,但也讓對(duì)象可以緊密排列端铛,避免"mark and sweep"中可能出現(xiàn)的空隙泣矛。在新建對(duì)象時(shí),"copy and sweep"可以提供大塊的連續(xù)空間禾蚕。因此您朽,如果對(duì)象都比較"長(zhǎng)壽",那么適用于"mark and sweep"换淆。如果對(duì)象的"新陳代謝"比較活躍哗总,那么適用于"copy and sweep"。
上面兩種機(jī)制是通過分代回收(generational collection)混合在一起的产舞。每個(gè)對(duì)象記錄有它的世代(generation)信息魂奥。所謂的世代,是指該對(duì)象所經(jīng)歷的垃圾回收的次數(shù)易猫。世代越久遠(yuǎn)的對(duì)象耻煤,在內(nèi)存中存活的時(shí)間越久。
容器
數(shù)組
Human[] persons = new Human[2]; // array size 2
persons[0] = new Human(160);
persons[1] = new Human(170);
int[] a = {1, 2, 3, 7, 9}; // array size 5
System.out.println(a[2]);
String[] names = {"Tom", "Jerry", "Luffy"}; // array size 3
System.out.println(names[0]);
List
import java.util.*;
public class Test
{
public static void main(String[] args)
{
List<String> l1 = new ArrayList<String>();
l1.add("good");
l1.add("bad");
l1.add("shit");
l1.remove(0);
System.out.println(l1.get(1));
System.out.println(l1.size());
Iterator i = l1.iterator();
while(i.hasNext()) {
System.out.println(i.next());
}
}
}
輸出可以用Iterator
List是接口,ArrayList是實(shí)現(xiàn)
集合Set
import java.util.*;
public class Test
{
public static void main(String[] args)
{
Set<Integer> s1 = new HashSet<Integer>();
s1.add(4);
s1.add(5);
s1.add(4);
s1.remove(5);
System.out.println(s1);
System.out.println(s1.size());
}
}
Map 如HashMap
import java.util.*;
public class Test
{
public static void main(String[] args)
{
Map<String, Integer> m1 = new HashMap<String, Integer>();
m1.put("Vamei", 12);
m1.put("Jerry", 5);
m1.put("Tom", 18);
System.out.println(m1.get("Vamei"));
}
}