一、面向?qū)ο蟾拍?/h2>
OOP:Object Oriented Programming class和instance是“模版”和“實例”的關(guān)系:
類:class,對象模版
實例:instance,具體對象 class用字段(field)封裝了數(shù)據(jù),不同的instance擁有各自獨立的字段(field)
通過變量.字段名訪問某個字段(field)
指向instance的變量都是引用變量
二、數(shù)據(jù)封裝
一個 class 可以包含多個 field,直接把 field 用public暴露給外部可能破壞了封裝,我們可以用 private關(guān)鍵字 修飾 field 進(jìn)而拒絕外部訪問。
外部代碼通過定義 public方法可以間接的修改 private關(guān)鍵字 修飾的 field。
通過 變量.方法名() 來調(diào)用實例方法。
通過 方法 訪問實例字段更安全。
public class Person{
private String name;
private int age;
public String address;
public void setName(String name){
this.name = name;
}
public String getName() {
return this.name;
}
}
Person ming = new Person();
ming.address = "北京"; // 可以賦值
ming.name = "小明"; // 編譯錯誤
ming.age = 12; // 編譯錯誤
ming.setName(" 小明 ");
System.out.println(ming.getName()); // "小明"
(一)方法定義
1、修飾符:public、private、
2、方法返回值:有返回值的方法要寫上返回值類型,沒有返回值的方法 用void 來表示,void 表示不返回任何值(注意和返回null不同)
3、方法名稱:首字母小寫,后面的單詞首字母大寫;
4、方法參數(shù):方法名稱后的 () 內(nèi)寫入?yún)?shù)及參數(shù)類型列表,如果沒有參數(shù)則空著,如果有多個參數(shù)則需要用逗號隔開每一個參數(shù)的類型及變量,方法參數(shù)可以是基本類型參數(shù),也可以是引用類型參數(shù)。
public class Person{
private String name;
private int age;
public String address;
public String getName() {
return this.name;
}
public void setName(String name){
if (name == null){
throw new NullPointException();
}
this.name = name.trim();
return; // 可以省略,因為 void
}
public void retName(String name_1, String name_2){
// Todo
}
}
5、方法內(nèi)部可以使用隱式變量 this,this指向當(dāng)前實例,this.field 可以訪問當(dāng)前實例的字段。
6、調(diào)用方法:實例變量.方法名(參數(shù)),可以忽略方法返回值。
Person ming = new Person();
ming.setName(" 小明"); // 沒有返回值
String s = ming.getName(); // 返回值為 String
7、可以定義 private 方法,外部代碼不可以訪問 private 方法,內(nèi)部代碼可以調(diào)用自己的 private 方法,外部代碼可以通過 public 方法間接調(diào)用 private 方法。
public class Person{
private String name;
private int age;
public String getBirth() {
retrun calcBirth(2016);
}
private int calcBirth (int currentYear){
return currentYear - this.age;
}
}
(二)構(gòu)造方法
1、構(gòu)造方法可以在創(chuàng)建對象實例時初始化對象實例
2、構(gòu)造方法名就是類名
3、構(gòu)造方法的參數(shù)沒有限制
4、構(gòu)造方法沒有返回值,也沒有 void
5、必須使用 new操作符 調(diào)用構(gòu)造方法
public class Person{
private String name;
private int age;
public Person(String name, int age) { // 構(gòu)造方法 Person
this.name = name;
this.age = age;
}
}
6、如果一個類沒有定義構(gòu)造方法,編譯器會自動生成一個默認(rèn)的構(gòu)造方法(無參數(shù),無執(zhí)行語句)
public class Person{
private String name; // = null
private int age; // = 0
private String address = "北京";
public Person() { // 編譯器生成的默認(rèn)構(gòu)造方法
}
}
7、如果自定義了構(gòu)造方法,編譯器就不再自動創(chuàng)建默認(rèn)構(gòu)造方法
8、 構(gòu)造方法參數(shù)的初始化順序:先初始化字段,沒有賦值的字段初始化為默認(rèn)值(基本類型=0;引用類型=null),再執(zhí)行構(gòu)造方法的代碼
public class Person{
private String name; // = null
private int age; // = 0
private String address = "北京";
public Person(String name, int age, Sting address) { // 三個參數(shù),創(chuàng)建實例時傳入
this.name = name;
this.age = age;
this.address = address;
}
}
9、一個類的構(gòu)造方法可以有多個,通過創(chuàng)建實例s時傳入的參數(shù)個數(shù)、參數(shù)類型來判斷具體調(diào)用了哪個構(gòu)造方法
public class Person{
private String name; // = null
private int age; // = 0
private String address = "北京";
public Person(String name, int age, Sting address) { // 構(gòu)造方法一
this.name = name;
this.age = age;
this.address = address;
}
public Person(String name){ // 構(gòu)造方法二
this.name = name;
System.out.println("hello world")
}
public Person(){ // 構(gòu)造方法三
System.out.println("hello")
}
}
10、一個構(gòu)造方法可以調(diào)用其他構(gòu)造方法,便于代碼復(fù)用,調(diào)用其他構(gòu)造方法的語法是 this(..)
public class Person{
private String name; // = null
private int age; // = 0
private String address = "北京";
public Person(String name, int age, Sting address) { // 構(gòu)造方法一
this.name = name;
this.age = age;
this.address = address;
}
public Person(String name){ // 構(gòu)造方法二
this(name,10,"北京")
}
public Person(){ // 構(gòu)造方法三
this("Andy")
}
}
(三)方法重載
1、方法重載入是指多個方法的方法名相同,但是各自的參數(shù)不同(參數(shù)個數(shù),參數(shù)類型,參數(shù)位置),方法返回值類型通常是相同的。
2、方法重載的目的是使相同功能的方法使用同一方法名,以便于調(diào)用
public class Hello {
public void indexOf (String name){
}
public void indexOf (int age){
}
public void indexOf (int age, String name){
}
public void indexOf (String name, int age){
}
}
public class Main{
public static void main(String[] agers){
Hello s = new Hello();
int n1 = s. indexOf('t');
int n2 = s. indexOf('st', 20);
}
}
三、繼承多態(tài)
(一)繼承
1、繼承使用關(guān)鍵字 extends,子類 Student 獲得了父類 Person 的所有功能,Student 只需要編寫新增的功能。
2、如果定義的類沒有寫 extends 關(guān)鍵字,則該類繼承自 object 類。
3、Java 只允許 class 繼承自一個類,不與許同時繼承自多個類,即一個類有且僅有一個父類。
public class Person{
private String name;
private int age;
publicString getName(){
return name
}
public void setName(String name){
this.name = name;
}
public int getAge() {
return age;
}
public void run(){
System.out.println(name + " is running!");
}
}
public class Student extends Person {
private int score;
public void setScore(int score){
return score;
}
public int getScore(){
this.score = score;
}
}
public class Main{
public static void main(String[] args){
Person p = new Person();
Student s = new Student();
p.setName("Xiao Ming");
s.setName("Xiao Hong");
p.run(); // Xiao Ming is running!
s.run(); // Xiao Hong is running!
}
}
4、Person 類定義的 private 字段無法被子類訪問
5、Person 類定義的 protected 修飾的字段可以被子類訪問。即 protected關(guān)鍵字 把字段和方法的訪問權(quán)限控制在了繼承樹內(nèi)部。
public class Person {
private String name;
private int age;
protected String hight;
public void run() {
}
}
public class Student extends Person{
public String hello(){
return "Hello," + this. name; // ERROR!
}
public String hello(){
return "Hello," + this. hight; // ok
}
}
6、java 語言規(guī)定編寫子類的構(gòu)造方法時,必須在第一行調(diào)用父類的構(gòu)造方法(使用 super() 語句調(diào)用),如果沒有調(diào)用 super() 方法,編譯器會默認(rèn)的幫助我們調(diào)用 super() ; 但是如果父類沒有默認(rèn)的構(gòu)造方法,即父類顯式的實現(xiàn)了構(gòu)造方法,則子類需要在自身的構(gòu)造方法中顯式(手動)調(diào)用 super() 方法,并傳入父類需要的參數(shù)。實例如下:
public class Person {
public String name;
public int age;
public Person(String name){ // 顯式的實現(xiàn)帶一個參數(shù)的構(gòu)造方法
System.out.println("create Person");
}
}
public class Student extends Person{
public Student(){
super("小紅"); // 父類 Person 是顯式構(gòu)造的構(gòu)造方法,所以子類 Student 需要顯式調(diào)用 super(),并傳入?yún)?shù)
System.out.println(" create student");
}
}
7、向上轉(zhuǎn)型:可以對實例變量進(jìn)行向上轉(zhuǎn)型(upcasting),向上轉(zhuǎn)型把子類型安全地變?yōu)楦映橄蟮念愋?。例?Student 類實例對象 轉(zhuǎn)型為 Person 類實例對象。
Person p = new Person();
Student s = new Student();
Person ps = new Student(); // upcasting ps 是 Person 類型
Object o1 = p; // upcasting
Object o2 = s; // upcasting
8、向下轉(zhuǎn)型:可以對實例變量進(jìn)行向下轉(zhuǎn)型(downcasting), 向下轉(zhuǎn)型把抽象的類型變成一個具體的子類型。
Person p = new Student()
Student s = (Student) p; // downcasting
向下轉(zhuǎn)型很可能報錯:ClassCastException
Person p = new Person()
Student s = (Student) p; // ClassCastException
9、instanceof 操作符:判斷實例對象的類型
Person p = new Person();
System.out.println(p instanceof Person); // true
System.out.println(p instanceof Student); // false
(二)多態(tài)
1、子類覆寫父類的方法是覆寫(Override),覆寫的方法使用 @Override 修飾,該修飾非必須,但是可以讓編譯器幫助檢查是否進(jìn)行正確的覆寫,如下:
public class Person{
public void run(){
}
}
public class Student extends Person{
@Override // 可省略
public void run(){
}
@Override // Compile error! 因為沒有進(jìn)行正確覆寫
public void run( String name){
}
}
Person p = new Student();
p.run();
2、方法簽名如果不同就不是 Override,而是創(chuàng)建了一個新方法,如下:
public class Person {
public void run(){
}
}
public class Student extends Person {
public void run(String s){ // 方法簽名不同(有參數(shù)),所以不是覆寫,而是創(chuàng)建了一個新的方法,此處省略了 @Override 關(guān)鍵字
}
}
3、java 中引用變量的聲明類型可能與其實際類型不符
4、多態(tài)概念:實例對象的方法調(diào)用總是對應(yīng)實際類型,即Java 的實例方法調(diào)用是基于運行時實際類型的動態(tài)調(diào)用
5、多態(tài)定義:指針對某個類型的方法調(diào)用,其真正執(zhí)行的方法取決于運行時實際類型的方法。所以我們對某個類型調(diào)用某個方法,執(zhí)行的方法可能是某個子類的覆寫方法。利用多態(tài)的允許添加更多類型的子類的特性,實現(xiàn)功能的擴展。
public class Person{
public void run(String name){
System.out.println(name + " is running")
}
}
public class Student extends Person{
@Override // 可省略
public void run(String name){
System.out.println("Student " + name + " is running")
}
}
public class Main{
public static void main(String[] args){
Person p = new Person("Xiao Ming");
Person s = new Student(("Xiao Hang");
p.run(); // 調(diào)用的是 Person 類型的 run() 方法
s.run(); // 調(diào)用的是實際類型 Student 的 run() 方法
}
}
6、所有的類都是從 Object 類繼承下來的,是在 Object 類的基礎(chǔ)上使用多態(tài)實現(xiàn)了功能的擴展。例如:toString() 方法、equals() 方法、hashCode() 方法。
public class Person{ // 在子類 Person 中對父類 Object 的各個方法進(jìn)行覆寫
@Override
public String toString(){ // toString() 方法:把接口 instance 輸出為 String
}
@Override
public boolean equals(Object o){ // equals() 方法: 判斷兩個接口 instance 是否邏輯相等
}
@Override
public int hashCode(){ // hashCode() 方法:計算一個接口 instance 的哈希值
}
}
7、super 方法可以調(diào)用父類的被覆寫 Override 的方法,如下:
public class Person{
private String name;
public String hello(){
return "Hello, " + name;
}
}
public Student extends Person{
@Override
public String hello(){
return super.hello() + "!"; // 此處使用 super.hello() 調(diào)用父類的 hello() 方法,返回 “Hello,” + name 的執(zhí)行結(jié)果
}
}
8、 final 關(guān)鍵字:當(dāng)我們定義一個類的方法時如果不希望該方法被子類覆寫,可以使用 final 關(guān)鍵字修飾。
9、使用 final 關(guān)鍵字修飾的類不能被繼承;使用 final 關(guān)鍵字修飾的方法不能被Override;使用 final 關(guān)鍵字修飾的字段 field 在初始化后不能被修改;
public class Person{
public final void setName(String name){
}
}
public final class Student extends Person{
private final int score;
}
四、抽象類和接口
(一) 抽象類
1、抽象方法:如果一個class 定義了方法,但沒有具體執(zhí)行代碼,這個方法就是抽象方法;
(1)抽象方法使用 abstract 關(guān)鍵字修飾;
(2)抽象方法沒有任何執(zhí)行語句;
(3)因為無法執(zhí)行抽象方法,因此實現(xiàn)抽象方法的類必須使用 abstract 關(guān)鍵字修飾為抽象類;
(4)抽象類無法實例化,但可以被繼承;
(5)抽象類強迫其子類實現(xiàn)其定義的抽象方法,否則編譯錯誤;
public abstract class Person{
public abstract void run(); // 定義一個抽象方法 run(),和一個抽象類 Person()
}
Person p = new Person(); // 編譯錯誤, 因為抽象類無法實例化
Person s = new Student(); // OK Student類 繼承了 Person類
Person t = new Teacher(); // OK Teacher類 繼承了 Person類
// 調(diào)用抽象方法實現(xiàn)多態(tài):
s.run();
t.run();
2、面向抽象編程:
(1)不關(guān)心父類 Person類型 對象的具體類型
(2)不關(guān)心新的子類是如何實現(xiàn)抽象方法 (run方法)的
public abstract class Person{
public abstract void run();
}
public class Student extends Person{
@Override
public voide run() {
}
}
public class Teacher extends Person{
@Override
public void run() {
}
}
Person s = new Student();
Person t = new Teacher();
s.run()
t.run()
3、總結(jié):
抽象方法定義了子類必須實現(xiàn)的接口規(guī)范
定義了抽象方法的類就是抽象類
從抽象類繼承的子類必須實現(xiàn)抽象方法
如果不實現(xiàn)抽象方法,則該子類仍是一個抽象類
(二) 接口 --- Interface
1、如果一個抽象類沒有字段,所有方法全部是抽象方法,就可以把該抽象類改寫為接口(interface),可以使用關(guān)鍵字 interface 來聲明一個接口。
public interface Person{
// public abstract void run(); // 接口定義的方法默認(rèn)是 public abstract (不需要寫)
void run();
}
2、interface 是 Java 內(nèi)置的純抽象接口,實現(xiàn) interface 使用 implements。
public class Student implements Person{
@Override
public void run(){}
}
3、一個類可以同時實現(xiàn)多個 interface。
public class Robot implements Hello, Comparable{
}
4、一個類如果想實現(xiàn)某個接口,子類必須實現(xiàn)該接口中所定義的全部方法,如果接口中方法是使用 default 關(guān)鍵字定義的,則該方法默認(rèn)被子類實現(xiàn)了
// 接口
public interface Shape{
double area(); // 繼承時 area方法 需要顯式實現(xiàn)
default double perimeter(){ // default 關(guān)鍵字修飾的方法,繼承時默認(rèn)實現(xiàn)
return 0;
}
}
// 實現(xiàn)接口的子類
public class Rect implements Shape{
private final double width;
private final double height;
public Rect(double width, double height){
this.width = width;
this.height = height;
}
@Override
public double area(){
return width * height
}
}
public class Main{
public static void main(String[] args){
Shape s1 = new Rect(200, 100);
System.out.println(s1.area());
}
}
5、一個 interface 可以繼承自另一個 interface,interface 之間的繼承使用 extends 關(guān)鍵字
public interface Person {
String getName();
}
public interface Student extends Person{
String getSchool();
}
public class PrimaryStudent implements Student{
@Override
public String getName(){
}
@Override
public String getSchool(){
}
}
6、interface 的繼承相當(dāng)于擴展了 interface(接口)的方法
(三) 抽象類 vs 接口
1、合理設(shè)計 interface 和 abstract class 的繼承關(guān)系:公共邏輯放在 abstract class 中。
2、類可以實現(xiàn)多個接口。
3、接口也是數(shù)據(jù)類型,適用于向上轉(zhuǎn)型和向下轉(zhuǎn)型。
4、接口不能定義實例字段。
5、接口可以定義 default 方法(JDK >= 1.8)
五、包和classpath
(一) 靜態(tài)字段和靜態(tài)方法
1、用 static 修飾的字段稱為靜態(tài)字段,普通的字段在每個實例中都有自己的一個獨立"空間",靜態(tài)字段只有一個共享"空間"。
2、對于一個類的所有實例,都共享一個靜態(tài)字段。
3、不推薦用實例變量訪問靜態(tài)字段。
4、推薦用類名訪問靜態(tài)字段。
5、可以把靜態(tài)字段理解為描述 class 本身的字段(非實例字段)。
public class Person{
public String name;
public int age;
public static int number = 100; // 定義一個靜態(tài)字段 number
}
Person ming = new Person();
Person hong = new Person();
ming.number = 99; // 通過 實例變量 訪問靜態(tài)字段,不推薦
System.out.println(hong.number); // 99
Person.number = 88; // 使用 類名 調(diào)用靜態(tài)變量
System.out.println(Person.number); // 88
6、用 static 修飾的方法稱為靜態(tài)方法,調(diào)用實例方法必須通過實例變量,調(diào)用靜態(tài)方法不需要實例變量,可直接使用類名調(diào)用(靜態(tài)方法類似于其他編程語言中的函數(shù))。
public class Person{
private String name;
private static int number = 100;
pulic static viod setNumber(int num){
number = num;
}
}
Person.setNumber(99);
7、靜態(tài)方法不能訪問 this 變量。
8、靜態(tài)方法不能訪問實例字段。
9、靜態(tài)方法可以訪問靜態(tài)字段、及其他靜態(tài)方法。
10、Java程序的入口 main() 也是靜態(tài)方法。
(二) 包
1、Java 定義了名字空間:包,包名 + 類名 = 完整類名。
2、包(package) 可以是多層結(jié)構(gòu):java.util.Arrays。
3、包沒有父類 / 子類關(guān)系:java.util 和 java.util.zip 是不同的包,兩者沒有任何關(guān)系。
4、包作用域:不用 public、protected、private修飾的字段和方法就是包作用域。
5、位于同一個包的類,可以訪問包作用域的字段和方法。
package hello;
public class World{
static int findMax(int[] ns){
}
}
package hello;
public class Map{
int price;
void setPrice(int price)
}
6、包的引用:
package hello;
import java.util.Arrays;
public class World{
public int findMin(int[] ns){
Arrays sort(ns);
return ns[0];
}
}
(三) 作用域
1、訪問權(quán)限是指在一個類的內(nèi)部,能否引用另一個類以及訪問它的字段和方法。
2、訪問權(quán)限有 public、protected、private 和 package 四種。
(1)定義為 public 的 field、method 可以被其他類訪問;
(2)定義為 private 的 field、method 無法被其他類訪問,但是在類的內(nèi)部可以訪問(即 private 訪問權(quán)限限定在了 class 的內(nèi)部);
(3)private 還可以修飾 class,定義為 private 的 class 無法被其他類訪問
(4)訪問 private class 被限定在外層 class 的內(nèi)部,定義在一個 class 內(nèi)部的 class 稱為 內(nèi)部類(inner class)。
package abc;
public class Hello{
public void hello(){
Inner inner = null;
}
private class Inner{ // 定義一個內(nèi)部類 Inner
}
}
(5)protected 作用于繼承關(guān)系,定義為 protected 的字段和方法可以被子類訪問
package abc;
public class Hello{
protected void hi(){
}
}
package xyz;
class World extends Hello {
void foo(){
Hello h = new Hello();
h.hi();
}
}
(6)包作用域(package) 是指一個類允許訪問同一個 package 的沒有 public、private 修飾的 class,以及沒有 public、protected、private 修飾的 字段和方法。注意:包名必須完全一致
package abc;
class Hello {
void hi() {
}
}
package abc;
class Main {
void foo()[
Hello h = new Hello();
h.hi()
}
}
3、最佳實踐:最小化暴露對外方法,即盡量少使用 public 。
4、局部變量:在方法內(nèi)部定義的變量稱為局部變量,局部變量作用域由所在語句塊{...}決定。
package abc;
public class Hello{
void hi(String name){
String s = name.toLowerCase();
int len = s.length();
if (len < 10){
int p = 10 - len;
for (int i = 0; i < 10; i++){
System.out.println(i);
}
}
}
}
5、final 關(guān)鍵字:
(1)final 與訪問權(quán)限不沖突;
(2)用 final 修飾 class 可以阻止被繼承;
(3)用 final 修飾 method 可以阻止被覆寫;
(4)用 final 修飾 field 可以阻止被重新賦值;
(5)用 final 修飾局部變量可以阻止被重新賦值;
package abc;
public class Hello{
private int n = 0;
protected void hi(final int t){
final long i = t;
}
}
6、一個.java 文件只能包含一個 public class, 但是可以包含多個非 public class。
(四) classpath 和 jar
1、jar 包是 zip 格式的壓縮文件,包含若干 .class 文件。
2、jar 包相當(dāng)于目錄,classpath 可以包含 jar 文件,例如:C:\work\bin\all.jar。
3、查找 com.fiya.Hello 類會在 C:\work\bin\all.jar 文件中搜索 com/fiya/Hello.class。
4、jar 包的其他功能:
(1)jar 包可以包含一個特殊的 /META-INF/MANIFEST.MF 文件,該文件是純文本,可以指定 Main-Class 和其他信息。
(2)jar 包還可以包含其他 jar 包。
5、JVM運行時會自動加載 JDK 自帶的 class。JDK自帶的 class 被打包在 rt.jar 中。
六、Java核心類
(一) 字符串和編碼
1、String 可以使用 "" 來直接創(chuàng)建,創(chuàng)建后內(nèi)容不可變。
String s1 = "hello"; // 創(chuàng)建 String 方法一
String s2 = new String("world"); // 創(chuàng)建 String 方法二
2、字符串常用操作:
(1)使用 equals() 判斷字符串是否相等,忽略大小寫 equalsIgnoreCase(String)
String s = "hello";
s.equals("Hello"); // false
s.equalsIgnoreCase("Hello") // true
(2)是否包含字符串:boolean contains(CharSequence)
String s = "hello world";
s.contains("ll"); // true
(3)查找字符串位置:int indexof(String) 和 int lastIndexof(String)
String s = "hello world";
s.indexof("ll"); // 從前向后查找 2
s.lastIndexof("l") // 從后向前查找 9
(4)是否以指定字符串開頭:boolean startsWith(String)
String s = "hello world";
s.startsWith("he"); // true
(5)是否以指定字符串結(jié)尾:boolean endsWith(String)
String s = "hello";
s.endsWith("lo"); // true
(6)移除字符串首尾空白字符:trim(),注意 trim() 不改變字符串內(nèi)容,而是返回新的字符串。
String s = " \t hello \r\n ";
String s2 = s.trim(); // "hello"
s = s.trim();
(7)提取字符串子串:substring()
String s = "hello,world";
s.substring(7); // "world"
s.substring(1, 5); // "ello"
(8)大小寫轉(zhuǎn)換:toUpperCase()、toLowerCase()
String s = "heLLo";
s.toUpperCase(); // "HELLO"
s.toLowerCase(); // "hello"
(9)替換子串普通替換:replace(char, char)
String s = "hello";
s.replace('l', 'w'); // "hewwo"
s.replace('l', 'w~'); // "hew~w~o"
(10)替換子串正則表達(dá)式替換:replaceAll(String,String)
String s = "A,,B;C ,D";
s.replaceAll("[\\,\\;\\s]+", ", "); // "A, B, C, D"
(11)分割字符串:String[] split(String)
String s = "A,,B;C ,D";
String[] ss = s.split("[\\,\\;\\s]+"); // {"A", "B", "C", "D"}
(12)拼接字符串:static String join()
String[] arr = {"A", "B", "C"};
String s = String.join("~~", arr); // "A~~B~~C"
3、String 類型和 其他任意類型 的轉(zhuǎn)換
(1)把任意數(shù)據(jù)轉(zhuǎn)換為 String 類型:static String valuOf(int)、static String valuOf(boolean)、static String valuOf(Object)
String.valueOf(123); // "123"
String.valueOf(true); // "true"
String.valueOf(new Object()); // "java.lang.Object@7852e922"
(2)把 String 類型轉(zhuǎn)換為其它類型:
static int Interger.parseInt(String)
int i = Integer.parseInt("123"); //123
static Interger Interger.valueOf(String)
Integer I = Interger.valueOf("123");
4、String 與 char[] 互相轉(zhuǎn)換:
(1)String 轉(zhuǎn)換為 char[]:char[] toCharArray();
String s = "hello";
char[] cs = s.toCharArray(); // {'h', 'e', 'l', 'l', 'o'}
(2)char[] 轉(zhuǎn)換為 String :new String(char[]);
char[] cs = {'h', 'e', 'l', 'l', 'o'};
String s2 = new String(cs); // "hello"
5、String和byte[]互相轉(zhuǎn)換(需要指定編碼)
(1)String 轉(zhuǎn)換為 byte[]: byte[] getBytes(String)、byte[] getBytes(Charset)
String s = "hello";
byte[] bs1 = s.getBytes("UTF-8");
byte[] bs2 = s.getBytes(StandardCharsets.UTF_8);
(2)byte[] 轉(zhuǎn)換為 String: new String(byte[], String)、new String(byte[], Charset)
new String(bs1, "UTF-8");
new String(bs2, StandardCharsets.UTF_8);
6、一個中文字符占用2個字節(jié),中文編碼:GB31、GBK、GB8030.
7、全球統(tǒng)一編碼:Unicode。Java使用的就是 Unicode 編碼。
(二) StringBuidler
1、StringBuilder 是可變對象,可以預(yù)分配緩沖區(qū),進(jìn)而實現(xiàn)高效的拼接字符串。
StringBuilder sb = new StringBuilder(1024);
for (int i = 0; i < 1000; i++){
sb.append(String.valueOf(i));
}
String s = sb.toString();
2、StringBuilder 可以進(jìn)行鏈?zhǔn)讲僮鳌?/p>
StringBuilder sb = new Stringbuilder(1024);
String s = sb.append("Ms ").append("name").append("!").insert(0, "Hello, ").toString();
3、編譯器在內(nèi)部自動把多個連續(xù)的 + 號操作優(yōu)化為 StringBuilder 操作。
String s = "Hello, " + "nemw" + "!";
4、Java 還提供了一個和 StringBuilder 接口完全相同的接口 StringBuffer,StringBuffer 是線程安全的,一般沒必要使用。
(三) 包裝類型
1、Java 的屬性包括 基本數(shù)據(jù)類型 和 引用數(shù)據(jù)類型,基本類型不能視為對象,如果我們把一個基本類型賦值為null ,程序會報錯。
int n = null; // ERROR!
2、可以對基本類型進(jìn)行包裝,變成一個引用類型(即包裝類型實際上是一個引用類型,只不過其內(nèi)部包含一個基本類型的變量)。
// 定義一個 Integer 類,包含一個實例字段 int
public class Integer {
private int value;
public Integer(int value) {
this.value = value;
}
}
Integer n = null;
Integer n2 = new Integer(99);
以上是我們手動實現(xiàn)的包裝類型,其實 JDK 已經(jīng)為每種基本類型都創(chuàng)建了對應(yīng)的包裝類型,無需我們手動實現(xiàn):
基本類型 對應(yīng)的引用類型
boolean Boolean
byte Byte
short Short
int Integer
long Long
float Float
double Double
char Character
3、基本類型int 和 對應(yīng)的引用類型Integer 可以相互轉(zhuǎn)化:
Integer n = new Integer(99); // 基本類型 轉(zhuǎn)換為 引用類型
int i = n.intValue(); // 引用類型 轉(zhuǎn)換為 基本類型
Integer n1 = Interger.valueOf("88"); // String類型 轉(zhuǎn)換為 引用類型Interger
String s = n.toString(); // 引用類型Interger 轉(zhuǎn)換為 String類型
特別注意 Integer.getInteger(String) 是從系統(tǒng)環(huán)境中讀取系統(tǒng)變量。
4、編譯器可以自動在 int 和 Integer 之間轉(zhuǎn)型:自動裝箱、自動拆箱
Integer n = 99; // Integer.valueOf(99) 自動裝箱 int -> Integer
int i = n; // n.intValue() 自動拆箱 Integer -> int
注意:自動裝箱和自動拆箱只發(fā)生在編譯階段;
裝箱和拆箱會影響執(zhí)行效率;
編譯后的class代碼是嚴(yán)格區(qū)分基本類型和引用類型的;
自動拆箱時:Integer -> int 執(zhí)行時可能會報錯(null 時),即 Integer x = null; int y = x; // NullPointerException
5、Java 的包裝類型定義了一些有用的靜態(tài)變量
Boolean t = Boolean.TRUE;
Boolean f = Boolean.FALSE;
int max = Integer.MAX_VALUE; // 2147483647
int min = Integer.MIN_VALUE; // -2147483647
int sizeOfLong = Long.SIZE; // 64 (bite)
int bytesOfLong = Long.BYTES; // 8(bytes)
6、整數(shù)和浮點數(shù)包裝類型繼承自 Number,所以我們可以對這些包裝類型進(jìn)行向上轉(zhuǎn)型(變?yōu)?Number 類型),然后使用 Number 類型的一些方法將其轉(zhuǎn)化為任意基本類型:

Number num = new Integer(999) // 將包裝類型 Integer 向上轉(zhuǎn)型為 Number 類型
byte b = num.byteValue();
int n = num.intValue();
long ln = num.longValue();
float f = num.floatValue();
double d = num.doubleValue();
(四) JavaBean
1、許多 class 的定義都符合:a.若干 private 實例字段、b.通過 public 方法讀寫實例字段。符合以上兩種命名規(guī)范的 class 被稱為 JavaBean,即:
(1)private Type field
(2)public Type getField()
(3)public void setField(Type value)
注意:以上三點中方法名稱大小寫不能改變。
public class Person{
private String name;
private int age;
public String getName(){
}
public void setName(String name){
}
public int getAge(){
}
public void setAge(int age){
}
}
boolean 字段的讀方法命名為 isXxx():
private boolean child
public boolean isChild() {} // 讀方法
public void setChild(boolean value){}
2、通常把一組對應(yīng)的 getter 和 setter 方法稱為屬性(Property):
(1) 讀寫屬性都具備:
name 屬性:
有對應(yīng)讀方法 getName()
有對應(yīng)寫方法 setName()
(2) 只有 setter 的屬性稱為只寫屬性(Write-only):
age 屬性:
無對應(yīng)讀方法 getAge()
有對應(yīng)寫方法 setAge()
(3) 只有 getter 的屬性稱為只讀屬性(Read-only):
age 屬性:
有對應(yīng)讀方法 getAge()
無對應(yīng)寫方法 setAge()
(五) 枚舉類型
1、常量的定義
(1)可以使用 enum 關(guān)鍵字定義常量, 使用 enum 關(guān)鍵字定義的常量本身帶有類型,使用 == 比較常量是否相等。
(2)enum 可以定義常量類型,它被編譯器編譯為:final class Xxx extends Enum{...}
public enum Weekday{ // 定義了一些 Weekday 類型的常量
SUN, MON, TUE, WED;
}
public enum Color { // 定義了一些 Color 類的常量
RED, GREEN, BLUE;
}
if (day == Weekday.FRI){
}
enum 定義的類型實際上是 class,繼承自 java.lang.Enum(如下),不能通過 new 創(chuàng)建實例,所有常量都是唯一實例,可以用于 switch 語句
public enum Color{
RED, GREEN, BLUE;
}
// 編譯器編譯出來的 class:
import java.lang.Enum
public final class Color extends Enum{
public static final Color RED = new Color();
public static final Color GREEN = new Color();
public static final Color BLUE = new Color();
private Color(){}
}
2、常量的一些使用:
(1)name() 獲取常量定義的字符串,注意不要使用 toString()
(2)ordinal() 返回常量定義的順序(無實質(zhì)意義)
package com.test;
public enum Weekday {
SUN, MON, TUE, WED, THU, FRI, SAT;
}
package com.test;
public class Main{
public static void main(String[] args){
for (Weekday day : Weekday.values()){
System.out.println(day.name());
}
Weekday fri = Weekday.FRI; // 將常量 FRI 賦值給 fri
System.out.println(fri.name()); // enum類型 -> String類型
System.out.println(fri.ordinal()); // 返回常量定義的順序
System.out.println(Weekday.valueOf("FRI").name()); // String類型 —> enum類型
Weekday.valueOf("ABC"); // 不存在的常量,會拋出 IllegalArgumentException
}
}
(3)構(gòu)造方法申明為 private
(4)可以為enum枚舉類編寫構(gòu)造方法、字段和方法,例如為每個枚舉類型添加一個中文名稱:
package com.test;
public enum Weekday {
// b. 傳入構(gòu)造方法的參數(shù),繼而調(diào)用構(gòu)造方法
SUN("星期日"), MON("星期一"), TUE("星期二"), WED("星期三"), THU("星期四"), FRI("星期五"), SAT("星期六");
private String chinese;
private Weekday(String chin){ // a. 使用構(gòu)造方法 初始化 chinese
this.chinese = chin;
}
public String toChinese() { // c. 定義 toChinese 方法返回 chinese
return chinese
}
}
public class Main{
public static void main(String[] args){
Weekday fri = Weekday.FRI;
System.out.println(fri.toChinese()); // 星期五
}
}
(六) 常用工具類
1、Math 類:提供類數(shù)學(xué)計算的靜態(tài)方法:
(1)abc / min / max
(2)pow / sqrt / exp / log / log10
(3)sin / cos / tan / asin / acos
(4)常量:PI = 3.14159;E = 2.71828
(5)Math.random() 生成一個隨機數(shù),范圍 0 <= 隨機數(shù) < 1
double x1 = Math.random();
long MIN = 1000;
long MAX = 9000;
double x2 = Math.random() * (MAX - MIN) + MIN;
double r = (long) x2;
(6)Random 對象:Random 對象用來創(chuàng)建偽隨機數(shù)
Random r = new Random();
r.nextInt(); // 生成下一個隨機 int
r.nextLong(); // 生成下一個隨機 long
r.nextFloat(); // 生成下一個隨機 float,介于 0~1
r.nextDouble(); // 生成下一個隨機 double,介于 0~1
r.nextInt(10); // 生成 0~10 之間的隨機數(shù),不包括 10
(7)為隨機數(shù):給定種子后偽隨機數(shù)算法會生成完全相同的序列,不給定種子時 Random 使用系統(tǒng)當(dāng)前時間戳作為種子。
Random r = new Random(12345);
for (int i = 0; i < 10; i ++){
System.out.println(r.nextInt(100))
}
2、SecureRandom:生成安全的隨機數(shù)。
3、BigInteger:表示任意大小的整數(shù)。
4、BigDecimal:表示任意精度的浮點數(shù)。
5、BigInteger 和 BigDecimal 都繼承自 Number。