線上工具
java https://c.runoob.com/compile/10
線上編寫執行 Java 8 https://www.tutorialspoint.co...
SQL 線上執行 https://www.bejson.com/runcod...
Java牛客題庫 https://www.nowcoder.com/inte...
JDK, JRE, JVM
- JDK : Java Development Kit
- JRE : Java Runtime Enviroment
- JVM : Java Virtual Machine
輸出Hello Wolrd
vim Hello.java
public class Hello{
public static void main(String[] args){
System.out.print("Hello World!");
}
}
編譯
javac Hello.java
執行
java Hello
輸出
Hello World!
Java程式執行機制
- 編譯型:
- 解釋型:
程式執行機制:
原始檔(*.java) => Java編譯器 => 位元組碼(.class)
=> JVM ( 類裝載器 =>位元組碼校驗器 => 直譯器 )
=> 作業系統平臺
IDEA
新建工程
File => New => Project… => Empty Project
File => Project Structure => Project => Project SDK (1.8.0) => Project language level (8) => OK
基礎語法
1.註釋,識別符號,關鍵字
註釋
//單行註釋
/* 多行註釋 */
/**
* 文件註釋
* @Author itxiaoma
*/
識別符號
類名,變數名,方法名都稱為識別符號
- 識別符號以字母,美元($),下劃線(_)開始
- 首字母后可以是字母,美元($),下劃線(_),數字的組合
- 不能使用關鍵字作為變數名,方法名
- 大小寫敏感
關鍵字(50+)
2.資料型別
強型別語言:變數使用必須嚴格符合規定,所有變數都必須先定義後才能使用
Java資料型別
基本型別:(8大基本型別)
數值
整數
- byte:1個位元組(-128~127)
- short:2個位元組(-32768~32767)
- int:4個位元組(-2147483648~2147483647)21億+
- long:8個位元組(例:long num=40L;)
浮點
- float:4個位元組(例:float num=40F;)
- double:8個位元組
- 字串char:2個位元組
- boolean:1位,true/false
- 引用型別:類,介面,陣列
注1:String不是資料型別,是類
注2:1bit表示1位;(bit是計算機內部資料儲存的最小單位)
1Byte表示1個位元組,1B=8b;
1KB = 1024B;
1MB = 1024KB;
1GB = 1024MB;
1TB = 1024GB;
Java資料型別的常見問題
整數擴充套件
int a = 10; int b = 010;//八進位制 int c = 0x10;//十六進位制
浮點型擴充套件
float f = 0.1f; double d = 1.0/10; System.out.println(f==d);//false float d1 = 123123123123f; float d2 = d1 + 1; System.out.println(d1==d2);//true //float 有限 離散 舍入誤差 接近但不等於 //不要用浮點數進行比較 //數學工具類BigDecimal
字元類擴充套件
char a = 'a'; System.out.println((int)a);//97 char a1 = '\u0061'; System.out.println(a1);//a //所有的字元本質還是數字 轉義字元: \t 製表符 \n 換行 ...
3.型別轉換
運算中,不同型別的資料會先轉換位同一型別,再進行計算
優先順序:低 ==> 高
byte,short,char => int => long => float => double
自動轉化:低 => 高
強制轉換: 高 => 低 (型別)變數名
注1:
- 不能對布林值進行轉換
- 不能把物件型別轉為不相干的型別
- 高容量轉低容量,會有記憶體溢位或精度問題
注2:JDK7的新特性,數字間可以用下劃線分割(1000 = 1_000)
4.變數、常量、作用域
變數
int a = 1;
常量 - final
常量:初始化後不能改變,一般為大寫
static final double PI = 3.14;
作用域
- 類變數
- 例項變數
- 區域性變數
public class Hello {
//類變數:static
static int a = 1;
//例項變數:屬於物件,不需要初始化(會自動初始化為型別預設值)
//布林值預設false,除基本型別以外其他變數都是null
String b;
public static void main(String[] args) {
System.out.println(a);
int c = 3;//區域性變數:必須宣告和初始化
System.out.println(c);
Hello obj = new Hello();
System.out.println(obj.b);//null
}
}
命名規則:
- 類變數,區域性變數,方法名:駝峰(首字母小寫)
- 常量:大寫 + 下劃線
- 型別:駝峰(首字母大寫)
5.基本運算子
- 算術運算子:+, -, *, /, %, ++, --
- 賦值運算子:=
- 關係運算子:>, <, >=, <=, ==, !=, instanceof
- 邏輯運算子:&&,||,!
- 位運算子:&, |, ^, ~, >>, << , >>>
- 條件運算子:? :
- 擴充套件賦值運算子:+=, -=, *= ,/=
例:
long a = 123L;
int b = 123;
short c = 10;
byte d = 8;
System.out.println(a+d);//long
System.out.println(b+c);//int
System.out.println(c+d);//int
//結論:有long型別時轉long,否則轉int
冪運算:2^3
double pow = Math.pow(2, 3);
System.out.println(pow);//8.0
位運算
<< 乘2
>> 除2
6.包機制
包的本質就是資料夾
- 包機制是為了更好地組織類,用於區別類名的名稱空間
- 一般用公司名倒置作為報名 pakage com.baidu.www;
- 使用import匯入包(import 包名.* 表示匯入包下所有類)
7.JavaDoc生成文件
註釋引數
/**
* @author 作者
* @version 版本
* @since 需要最早使用的jdk版本
* @param 引數
* @return 返回值
* @throws 異常丟擲
*/
中文編碼
javadoc -encoding UTF-8 -charset UTF-8 Demo.java
流程控制
1.使用者互動Scanner (Java5新特性)
基礎使用
import java.util.Scanner;
public class Demo {
public static void main(String[] args) {
//建立掃描器物件,用於接收鍵盤資料
Scanner s = new Scanner(System.in);
//判斷使用者輸入
if(s.hasNextLine()){
String str = s.nextLine();
System.out.println(str);
}
//IO流的類會一直佔用記憶體,用完需要關閉
s.close();
}
}
//next()以空格為結束符,nextLine()以回車為結束符
使用進階
計算多個數字的總和與平均數,非數字結束
Scanner s = new Scanner(System.in);
double sum = 0;
int num = 0;
while(s.hasNextDouble()){
double x = s.nextDouble();
sum += x;
num++;
}
System.out.println("和是:" + sum);
System.out.println("平均值是" + (sum/num));
s.close();
2.九九乘法表
/*
1*1=1
2*1=2 2*2=4
3*1=3 3*2=6 3*3=9
4*1=4 4*2=8 4*3=12 4*4=16
5*1=5 5*2=10 5*3=15 5*4=20 5*5=25
6*1=6 6*2=12 6*3=18 6*4=24 6*5=30 6*6=36
7*1=7 7*2=14 7*3=21 7*4=28 7*5=35 7*6=42 7*7=49
8*1=8 8*2=16 8*3=24 8*4=32 8*5=40 8*6=48 8*7=56 8*8=64
9*1=9 9*2=18 9*3=27 9*4=36 9*5=45 9*6=54 9*7=63 9*8=72 9*9=81
*/
for (int m = 1; m <= 9; m++) {
for (int n = 1; n <= m; n++) {
System.out.print(m + "*" + n + "=" + (m * n) + "\t");
}
System.out.println();
}
//System.out.print 不換行輸出
3.增強for迴圈(JDK1.5新特性)
int[] numbers = {1, 2, 3, 4, 5};
for (int x : numbers) {
System.out.println(x);
}
4.label
列印101 - 150間的所有質數
outer:for (int i = 101; i <= 150; i++) {
for (int j = 2; j < i / 2; j++) {
if (i % j == 0) {
continue outer;
}
}
System.out.println(i);
}
Java方法
方法是用來完成特定功能的程式碼片段,由方法名和方法體組成
方法名:修飾符 返回值型別 方法名 (引數型別 引數名){}
方法體:return 返回值;
引數型別:實參,形參
注:java都是值傳遞,沒有引用傳遞
1.方法的過載
過載就是在一個類中,有相同的函式名稱,但形參不同的函式
方法過載規則:
- 方法名稱必須相同
- 引數列表必須不同(個數,型別,引數順序不同)
- 返回型別可相同可不同
2.命令列傳參
程式執行時傳遞引數,可以通過main方法傳遞
public static void main(String[] args) {
for (int i = 0; i < args.length; i++) {
System.out.println(args[i]);
}
}
3.可變引數(JDK1.5新特性)
public static void main(String[] args) {
test(1,2,3);
}
public static void test(int... i){
System.out.println(i[0]);
System.out.println(i[1]);
System.out.println(i[2]);
}
4.遞迴
遞迴頭:什麼時候不呼叫自身方法。如果沒有頭,將陷入死迴圈。
遞迴體:什麼時候需要呼叫自身方法。
Java陣列
陣列是相同型別資料的有序集合
dataType[] arrayRefVar = new dataType[size];
int nums[] = new int[10];
//二維陣列
int[][] n = new int[2][2];
int[][] n = {{1,2},{3,4}}
基本特點
- 長度是確定的,一旦建立,長度不可變
- 元素型別必須相同
- 陣列物件本身在堆中(陣列是引用型別,可看做物件,陣列元素相當於物件的成員變數,Java的物件在堆中)
記憶體分析
graph LR
A(java記憶體)
A --> B(堆)
B -->B1[存放new的物件和陣列]
B -->B2[可以被所有執行緒共享,不會存放別的物件引用]
A --> C(棧)
C -->C1[存放基本變數型別,包含具體數值]
C -->C2[引用物件的變數,存放引用在堆中的地址]
A --> D(方法區)
D -->D1[可以被所有執行緒共享]
D -->D2[包含所有calss和static變數]
//1.宣告陣列
int[] nums;//在棧中
//2.建立陣列
nums = new int[10];//在堆中
三種初始化狀態
//靜態初始化
int[] a = {1, 2, 3};
Man[] mans = {new Man(1),new Man(2)}
//動態初始化(包含預設初始化)
int[] b = new int[10];//預設分配10個0
b[0] = 10;
注:陣列是引用型別,陣列元素相當於類的例項變數,陣列建立時分配空間,陣列元素也會按預設值初始化。
陣列工具類java.util.Arrays
列印陣列元素 | Arrays.toString(a); | |
---|---|---|
陣列填充 | Arrays.fill(a, 0 , 1, 0); | 陣列下標0-1的元素用0填充 |
陣列排序 | Arrays.sort(a); | |
比較陣列 | equals | |
查詢陣列元素 | binarySearch | 對排序好的陣列進行二分法查詢 |
氣泡排序
- 共有八大排序
- 時間複雜度為O(n2)
稀疏陣列
當一個陣列中大部分元素為0或值相同時,可以使用稀疏陣列儲存
處理方式:
1.記錄陣列行列數,不同值數
2.把不同值的元素行列資訊,元素值記錄在小規模陣列中
/*
稀疏陣列
1 2 1
2 3 2
還原陣列
0 0 0 0 0 0 0 0 0 0 0
0 0 1 0 0 0 0 0 0 0 0
0 0 0 2 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
*/
public class Demo {
public static void main(String[] args) {
int[][] array1 = new int[11][11];
array1[1][2] = 1;
array1[2][3] = 2;
int sum = 0;
for (int i = 0; i < 11; i++) {
for (int j = 0; j < 11; j++) {
if (array1[i][j] != 0) {
sum++;
}
}
}
int[][] array2 = new int[sum + 1][3];
array2[0][0] = 11;
array2[0][1] = 11;
array2[0][2] = sum;
int count = 0;
for (int i = 0; i < array1.length; i++) {
for (int j = 0; j < array1[i].length; j++) {
if (array1[i][j] != 0) {
count++;
array2[count][0] = i;
array2[count][1] = j;
array2[count][2] = array1[i][j];
}
}
}
System.out.println("稀疏陣列");
for (int j = 1; j < array2.length; j++) {
System.out.println(array2[j][0] + "\t" + array2[j][1] + "\t" + array2[j][2]);
}
System.out.println("還原陣列");
int[][] array3 = new int[array2[0][0]][array2[0][1]];
for (int j = 1; j < array2.length; j++) {
array3[array2[j][0]][array2[j][1]] = array2[j][2];
}
for (int[] ints : array3) {
for (int num : ints) {
System.out.print(num + "\t");
}
System.out.println();
}
}
}
物件導向
以類的方式組織程式碼。以物件組織(封裝)資料
三大特性:封裝,繼承,多型
1.建立類與物件
一個專案應該只存在一個main方法
建立物件
使用new建立物件時,除了分配記憶體空間,還會給建立好的物件進行預設初始化,及呼叫類中的構造器。
com/oop/demo/Application.java
package com.oop.demo;
public class Application {
public static void main(String[] args) {
//類:抽象的,例項化後會返回一個自己的物件
Student xiaoming = new Student();
Student xiaohong = new Student();
xiaoming.name = "小明";
xiaoming.age = 20;
xiaohong.name = "小紅";
xiaohong.age = 21;
System.out.println("姓名:" + xiaoming.name + "\t年齡:" + xiaoming.age);
xiaoming.study();
System.out.println("姓名:" + xiaohong.name + "\t年齡:" + xiaohong.age);
xiaohong.study();
}
}
com/oop/demo/Student.java
package com.oop.demo;
public class Student {
//屬性
String name;
int age;
//方法
public void study() {
System.out.println(this.name + "在學習");
}
}
構造器(構造方法)
- 必須和類名相同
- 必須沒有返回型別(不能寫void)
- 一旦定義了有引數的構造器,new物件時想不傳引數,就必須寫一個無引數構造器
public class Student {
//屬性
String name;
int age;
//無參(預設)構造器
public Student(){
}
//有參
public Student(String name){
this.name = name;
}
public Student(String name,int age){
this.name = name;
this.age = age;
}
}
建立物件記憶體分析
public class Application {
public static void main(String[] args) {
//類:抽象的,例項化後會返回一個自己的物件
Student xiaoming = new Student();
Student xiaohong = new Student();
xiaoming.name = "小明";
xiaoming.age = 20;
xiaohong.name = "小紅";
xiaohong.age = 21;
System.out.println("姓名:" + xiaoming.name + "\t年齡:" + xiaoming.age);
xiaoming.study();
System.out.println("姓名:" + xiaohong.name + "\t年齡:" + xiaohong.age);
xiaohong.study();
}
}
方法區也在堆中;
靜態方法區和類一起載入,所以靜態方法可以直接呼叫,不需要例項化
- 載入Application和Student類資訊到方法區
- 載入main()方法到棧中
- 載入xiaoming和xiaohong引用變數名到棧中
- 載入Student xiaoming = new Student();和Student xiaohong = new Student();例項到堆中
- xiaoming和xiaohong呼叫方法區的study方法
注:基本型別外的變數都是引用型別,是通過引用來操作的;引用名在棧中,指向物件實體在堆中的地址。
封裝
禁止直接訪問一個物件中資料的實際表示,應通過介面操作來訪問。
屬性私有(private),get/set
public class Student {
private String name;
private int age;
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
public int getAge() {
return age;
}
}
繼承extends
繼承的本質是對某一批類的抽象,從而實現更好的建模;
繼承是類之間的關係,子類繼承(extends)父類的全部public方法;
私有的屬性和方法無法被繼承
注:
- Java中只有單繼承,沒有多繼承 (一個子類只能有一個父類)
- Java中所有類,都預設直接或間接繼承Object類
Super
注意點
- super呼叫父類的構造方法,必須在構造方法的第一行
- super只能出現在子類的方法或構造方法中
- super和this不能同時在構造方法中呼叫(都需要在第一行)
super和this的區別
this | super | |
---|---|---|
代表物件不同 | 呼叫者本身的物件 | 父類物件的引用 |
使用前提不同 | 沒有繼承也能使用 | 只能在有繼承時使用 |
呼叫構造方法不同 | 呼叫本類的構造方法 | 呼叫父類的構造方法 |
com/oop/demo/Application.java
package com.oop.demo;
public class Application {
public static void main(String[] args) {
Student xiaoming = new Student();
xiaoming.test1();
//Person無參構造
//Student無參構造
//Student
//Student
//Person
}
}
com/oop/demo/Person.java
package com.oop.demo;
public class Person {
public Person() {
System.out.println("Person無參構造");
}
public void print(){
System.out.println("Person");
}
}
com/oop/demo/Student.java
package com.oop.demo;
public class Student extends Person{
public Student() {
//隱藏程式碼:呼叫了父類的無參構造super();
//super();
System.out.println("Student無參構造");
}
public void print(){
System.out.println("Student");
}
public void test1(){
print();
this.print();
super.print();
}
}
方法重寫@Override
子類的方法和父類必須要一致,方法體不同
重寫都是方法的重寫,和屬性無關
靜態方法不能被重寫 !
注意點
- 方法名,引數列表必須相同
- 修飾符範圍可以擴大不能縮小
- 丟擲異常範圍可以縮小不能擴大
程式碼示例
靜態方法
public class B {
public static void test(){
System.out.println("B=>test()");
}
}
public class A extends B{
public static void test(){
System.out.println("A=>test()");
}
}
public class Application {
public static void main(String[] args) {
//靜態方法:方法呼叫只和左邊定義的資料型別有關
A a = new A();
a.test();//A=>test()
//父類的引用指向了子類
B b = new A();
b.test();//B=>test()
}
}
方法重寫
public class B {
public void test(){
System.out.println("B=>test()");
}
}
public class A extends B{
@Override
public void test() {
System.out.println("A=>test()");
}
}
public class Application {
public static void main(String[] args) {
A a = new A();
a.test();//A=>test()
B b = new A();
b.test();//A=>test()
}
}
多型
同一方法根據傳送物件不同,採用多種不同的行為方式;
一個物件的型別是確定的,但可以指向物件的引用型別有很多(可以是子類,父類,Object)
多型存在的條件:
- 有繼承關係
- 子類重寫父類方法
- 父類引用指向子類物件
注:多型是方法的多型,屬性沒有多型。
無法重寫的方法
- static方法,屬於類,不屬於例項
- final 常量 (final修飾的類不能被繼承)
- private方法
//子類能呼叫的方法都是自己的或繼承父類的
A a = new A();
B b = new B();
//物件能執行哪些方法看左邊的引用型別
//父類引用可以指向子類,但不能呼叫子類獨有的方法
B c = new A();
a.test();//A=>test()
b.test();//B=>test()
//子類重寫了父類方法,會執行子類的方法
c.test();//A=>test()
instanceof和型別轉化
- 父類引用可以指向子類的物件,反過來不行
- 子類轉換為父類稱為向上轉型,可能丟失自己本來的一些方法
- 父類轉換為子類稱為向下轉型,需要強制轉換
public class Application {
public static void main(String[] args) {
//子類特有方法go
Student s = new Student();
s.go();
//向上轉型,轉型後無法再呼叫go方法
Person p = s;
//向下轉型
((Student) p).go();
}
}
static關鍵字
靜態變數
private static int age;
靜態方法
public class Application {
private static void test(){
System.out.println("Static Function");
}
public static void main(String[] args) {
test();
}
}
靜態程式碼塊
public class Person {
{
System.out.println("匿名程式碼塊");
}
static {
System.out.println("靜態程式碼塊");//只會在類載入時執行一次
}
public Person() {
System.out.println("構造方法");
}
public static void main(String[] args) {
Person p = new Person();
//靜態程式碼塊
//匿名程式碼塊
//構造方法
}
}
靜態匯入包
import static java.lang.Math.random;
public class Person {
public static void main(String[] args) {
System.out.println(random());
}
}
抽象類 abstract
//抽象類 (介面可以多繼承)
abstract class Person {
public abstract void doSomething();//抽象方法:只有方法名,沒有方法體
}
注:
- 抽象類不能new,只能靠子類實現
- 抽象方法必須在抽象類中,但抽象類可以包含普通方法
介面 interface
對物件的抽象,約束和實現分離:面向介面程式設計
注:
- 介面不能被例項化,介面中沒有構造方法
- 介面中所有方法都是抽象的(public abstract)
- 介面中只有常量(public static final)
- 類通過implements實現介面,一個類可以實現多個介面,實現多繼承
- 實現介面的類,必須重寫介面中所有方法
public interface UserService {
void userTest1();
void userTest2();
}
public interface TimeService {
void time1();
void time2();
}
public class UserTime implements UserService,TimeService{
@Override
public void userTest1() {
}
@Override
public void userTest2() {
}
@Override
public void time1() {
}
@Override
public void time2() {
}
}
內部類
匿名物件:不將例項儲存到變數(棧)中,只在堆記憶體中使用物件
public class Application {
public static void main(String[] args) {
new Apple().eat();
}
}
class Apple{
public void eat(){
System.out.println("吃蘋果");
}
}
匿名內部類
public interface UserService {
void userTest1();
void userTest2();
}
public class Application {
UserService u = new UserService() {
@Override
public void userTest1() {
}
@Override
public void userTest2() {
}
};
}
異常Error Exception
Error
Error類物件由JVM生成並丟擲,大多數錯誤與操作無關,發生錯誤時JVM一般會終止執行緒;
如記憶體溢位(OutOfMemeryError),棧溢位,類定義錯誤(NoClassDefFoundError),連結錯誤(LinkageError)
Exception
異常通常由邏輯錯誤引起,應儘量避免
- 非執行時異常(IO異常...)
- 執行時異常(RuntimeException)
注:Error通常是致命性錯誤,程式無法處理;Exception通常可以且應該儘可能的處理。
異常處理機制
- try 監控區域 (必要)
- catch 捕獲異常 (必要)
- finally 最終處理 (釋放佔用資源)
- throw 丟擲異常(一般在方法中使用 )
- throws
注:捕獲多個異常需要從小到大XXXException < XXXException < Throwable
public class Application {
public static void main(String[] args) {
int a = 1;
int b = 0;
try{
if(b == 0){
throw new ArithmeticException();
}
System.out.println(a/b);
}catch (ArithmeticException e){
e.printStackTrace();//列印錯誤的棧資訊
}catch (Exception e){
}catch (Throwable e){
}finally {
}
}
}
自定義異常
使用者自定義異常類,只需要繼承Exception類即可
public class MyException extends Exception {
String msg;
public MyException(String msg) {
this.msg = msg;
}
@Override
public String toString() {
return "MyException{" + msg + "}";
}
}
public class Application {
static void test(String msg) throws MyException{
throw new MyException(msg);
}
public static void main(String[] args) {
try{
test("test");
}catch (MyException e){
System.out.println(e);//MyException{test}
}
}
}