Java基础知识、web开发用到的前端知识以及常用的各种框架和中间件,涵盖计算机基础、数据库、部署工具以及代码风格和规范的全栈知识体系
public class Hello{ //定义一个名为Hello的类(
public static void main(String[] args){ //main入口
System.out.println("Hello World"); //打印输出Hello World
}
}
这在正式开发中并不常用,适用于学习阶段或者调试程序。
import java.util.Scanner;
(需要写在class上面)Scanner sc = new Scanner(System.in);
int i = sc.nextInt();
import java.util.Scanner; //导包
public class input{ //创建input类
public static void main(String[] args){ //主入口
Scanner scan = new Scanner(System.in); //创建对象
int a = scan.nextInt(); //使用变量接收数据
System.out.println(a); //打印输出数据
}
}
除了
nextInt()
接收int类型数据,还可以使用nextLine()
、next()
等方法接收字符串等数据
就是给类、方法、变量等起名字的符号
定义规则
常见命名约定
name
约定2:标识符由多个单词组成的时候,第一个单词首字母小写,其他单词首字母大写 范例2:firstName
Student
约定2:标识符由多个单词组成的时候,每个单词首字母都大写 范例2:GoodStudent
隐式转换:将数据类型中,取值范围小的数据,给取值范围大的类型赋值,可以直接赋值
int a = 10; //int占4字节
double b = a; //double占8字节
小的给大的,可以直接给 小的数据和大的数据类型运算,小的会先提升为大的数据类型再进行运算
byte short char 这三种数据在运算的时候,无论是否有更高的数据类型,都会提升为int,然后再进行运算
强制转换:把一个表示数据范围大的数值或者变量赋值给另一个表示数据范围小的变量 格式:目标数据类型 变量名 = (目标数据类型)值或者变量;
int a = 10; //int 4字节
byte b = (byte)a; //byte 1字节
int c = (int)88.88;
强制类型转换,有可能会发生精度损失
精度损失:简单理解,将容积为8升的水倒入容积为4升的桶中,多出的水会洒掉
类型转换案例
public class Test{
public static void main(String[] args){
byte a = 3; //①
byte b = 4; //②
byte c = a + b; //③
byte d = 3 + 4; //④
}
}
③中错误,在byte short char运算时,会直接提升为int,然后再进行运算; ④正确:Java存在常量优化机制,3和4是两个常量,会在编译的时候让3和4进行相加,然后判断7是否在byte的取值范围内
对常量或者变量进行操作的符号
表达式:用运算符把常量或者变量连接起来符合Java语法的式子就可以称为表达式。 不同运算符连接的表达式体现的是不同类型的表达式。
int a = 10;
int b = 20;
int c = a + b;
算术运算符:加(+)、减(-)、乘(*)、除(/)、取余(%)
+
操作中,如果出现了字符串,就是连接运算符,否则就是算术运算符,当连续进行+
操作时,从左到右逐个执行int a = 1;
char b = 'a';
System.out.println(a + b); //输出98
System.out.println("java" + 666); //java666
System.out.println(1 + 99 +"java"); //100java
System.out.println("5+5=" + 5 + 5); //5+5=55
System.out.println("5+5=" + (5 + 5)); //5+5=10
自增自减运算符:自增(++)、自减(–)
++
和--
在前或者在后时结果都一样赋值运算符:赋值(=)、加后赋值(+=)、减后赋值(-=)、乘后赋值(*=)、除后赋值(/=)、取余后赋值(%=)
int a = 10;
a += 20; //a = a + 20
System.out.println(a); //30
注意:扩展运算符底层会自带强制类型转换的功能
关系(比较)运算符:等于(==)、不等(!=)、大于(>)、大于等于(>=)、小于(<)、小于等于(<=)
逻辑运算符
逻辑短路:
&&
遇到false直接为false,不执行后面代码;||
遇到true则直接为true,不执行后续代码
三元运算符
关系表达式 ? 表达式1 : 表达式2;
通过一些语句,来控制程序的执行流程
顺序结构语句:程序中最简单最基本的流程控制,没有特定的语法结构,按照代码的先后顺序依次执行,程序中大多数代码都是这样的
格式1
if(关系表达式){
语句体1;
}else{
语句体2;
}
执行流程
import java.util.Scanner;
public class a{
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
System.out.println("请输入您的年龄:");
int age = sc.nextInt();
if(age >= 18){
System.out.println("您已成年,可以进入");
}else{
System.out.println("对不起,您未成年,不能进入");
}
}
}
如果if语句中的语句体只有一条,那么大括号{}可以省略不写,但是不建议,容易混淆 if语句小括号后面不要写分号;
格式2(多条件判断)
if(判断条件){
语句体1;
}else if(判断条件2){
语句体2;
}
...
else{
语句体n+1;
}
import java.util.Scanner;
public class a{
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
System.out.println("请输入您的成绩:");
int score = sc.nextInt();
if(score >= 90 && score <= 100){
System.out.println("优秀");
}else if(score >= 80 && score < 90){
System.out.println("良好");
}else if(score >=60 && score < 80){
System.out.println("及格");
}else if(score <60 && score >= 0){
System.out.println("不及格");
}else{
System.out.println("请输入正确的成绩!");
}
}
}
格式
switch(表达式){
case 值1:
语句体1;
break;
case 值2;
语句体2;
break;
....
default:
语句体n+1;
break;
}
格式说明
case穿透
推荐在明确循环次数时使用
格式
for(初始化语句;条件判断语句;条件控制语句){
循环体语句;
}
执行流程
案例
//在控制台输出1-5
for(int i = 1;i <= 5;i++){
System.out.println(i);
}
//求1-5的数据和
int sum = 0;
for(int i = 1;i <= 5;i++){
sum += i;
}
System.out.println(sum);
//求1-100的偶数和
int sum = 0;
for(int i = 1;i <= 100;i++){
if(i % 2 == 0){
sum += i;
}
}
System.out.println(sum);
//输出所有的水仙花数
//水仙花数:是一个三位数,个位、十位、百位的数字立方和等于原数
for(int i = 100;i <= 999;i++){
int sum;
int a = i % 10;
int b = i / 10 % 10;
int c = i / 100;
sum = a * a * a + b * b * b + c * c * c;
if(sum == i){
System.out.println(i);
}
}
System.out.print()
为同行打印,不换行System.out.println()
自带换行效果,类似于html中的块级元素,独占一行。括号内无内容时可以当作换行符来使用
不明确循环次数时推荐while
格式
while(条件判断语句){
循环体语句;
条件控制语句;
}
int i = 1;
while(int i <= 100){
System.out.println(i);
i++;
}
使用较少
格式
do{
循环体语句;
条件控制语句;
}while(条件判断语句);
三种循环的区别:
//for
for(;;){
循环体语句;
}
//while
while(true){
循环体语句;
}
//do...while
do{
循环体语句;
}while(true);
例如:键盘录入一个1-100之间的整数(用户可能出现误操作现象)
while(true){
Scanner sc = new Scanner(System.in);
int a = sc.nextInt();
if(a >= 1 && a <= 100){
b
}
}
for循环中,条件语句可以省略,但是
;
不能省略
public class Test{
public static void main(String[] args){
int n = 1;
lo: //标号
while(true){
switch(n){
case 1:
System.out.println("1");
break lo; //通过标号,这里的break将结束外层while循环
}
}
}
}
语句前只允许加一个标号,标号后面不能跟大括号。通过用break后加标号对处于标号中的语句进行控制。往往标号后是for、while、do-while等循环
作用:用于产生一个随机数
使用步骤
import java.util.Random;
Random r = new Random();
int number = r.nextInt(10); //获取数据的范围:[0,10),包括0,不包括10 int number = r.nextInt(10) + 1; //获取数据的范围:[1,10],包括1,也包括10
猜数字案例
import java.util.Random;
import java.util.Scanner;
public class a{
public static void main(String[] args){
Random r = new Random();
int ran = r.nextInt(100) + 1;
while(true){
System.out.print("请输入您猜的数字:");
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
if(n > ran){
System.out.println("猜大了~~");
}else if(n < ran){
System.out.println("猜小了~~");
}else {
System.out.println("猜恭喜你,猜对了,答案就是" + ran);
break;
}
}
}
}
除了使用Random这个类,Math类中也有生成随机数的方法
数组(array):是一种容器,用来存储同种数据类型(或者比它所占字节小的)的多个值
格式
//1.数据类型[] 变量名 【最常用】
int[] array;
//2.数据类型 变量名[]
int array[];
在Java中,数组必须先初始化,才能使用 所谓初始化,就是在内存中,为数组容器开辟空间,并将数据存入容器的过程
动态初始化:初始化时只指定数组长度,由系统为数组分配初始值
数据类型[] 变量名 = new 数据类型[数组长度];
int[] arr = new int[3];
静态初始化:初始化时就可以指定数组要存储的元素,系统还会自动计算出该数组的长度
数据类型[] 变量名 = new 数据类型[]{数据1,数据2,数据3,....};
int[] arr = new int[]{1,2,3};
int[] arr = {1,2,3};
内存分配
Java程序在运行时,需要在内存中分配空间,为了提高效率,就对空间进行了不同区域的划分 每一片区域都有特定的处理数据的方式和内存管理方式
数组名
数组名[索引]
默认值
数组遍历:将数组中所有的元素取出来
数组名.length
int arr = {1,2,3,4,5,6,7,8,9};
for(int i = 0; i <= arr.length; i++){
System.out.println(arr[i]);
}
注意:遍历是指取出数据的过程,不要局限的理解为:遍历就是打印
获取最值
int[] arr = {1, 2, 3, 4, 5, 6, 7000, 8, 919};
int max = arr[0];
for(int i = 0; i < arr.length; i++){
if(arr[i] > max) max = arr[i];
}
System.out.println("最大值为:" + max);
数组元素求和
import java.util.Scanner;
public class test{
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
int[] arr = new int[];
int sum = 0;
for(int i = 0; i < arr.length; i++){
System.out.print("请输入第" + (i+1) + "个数值:");
int n = sc.nextInt();
sum += n;
}
System.out.println("数组内的元素的和为:" + sum);
}
}
数组基本查找
int[] arr = {19, 28, 37, 46, 50};
Scanner sc = new Scanner(System.in);
System.out.print("请输入您要查找的数据:");
int n = sc.nextInt();
for(int i = 0; i < arr.length; i++){
if(arr[i] == n){
System.out.println("您要查找的数据索引为:" + i);
break;
}
}
步骤
public class MyBinarySearchDemo{ public static void main(String[] args) { int[] arr = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; int number = 10; int index = binarySearchForIndex(arr, number); System.out.println(index); } private static int binarySearchForIndex(int[] arr, int number) { // 定义查找的范围 int min = 0; int max = arr.length - 1; // 循环查找 min <= max while (min <= max) { // 计算中间位置 int mid = (min + max) >> 1; // 右移一位,也是除以二的意思
// mid指向的元素 > number if (arr[mid] > number) { // 表示要查找的元素在左边 max = mid - 1; } // mid指向的元素 < number else if (arr[mid] < number) { // 表示要查找的元素在右边 min = mid + 1; } else { // mid指向的元素 == number return mid; } } // 如果min大于了max就表示元素不存在,返回-1 return -1; } }
排序:将一组数据按照固定的规则进行排列
冒泡排序:相邻的数据两两比较,小的放前面,大的放后面。
步骤
public class MyBubbleSortDemo{
public static void main(String[] args){
int[] arr = {3, 5, 2, 1, 4};
bubbleSort(arr);
printArr(arr);
}
private static void bubbleSort(int[] arr){
// 循环排序
// 外层循环控制次数,比数组的长度少一次
for(int i = 0; i < arr.length - 1; i++){
// 内存循环就是实际比较的次数
for(int j = 0; j < arr.length - 1 - i; j++){
// -1为了让数组不越界,-i 是每轮结束后都会减少比较
if(arr[j] > arr[j+1]){
int temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
}
private static void printArr(int[] arr){
// 循环遍历
for(int i = 0; i < arr.length; i++){
System.out.print(arr[i] + " ");
}
System.out.println();
}
}
以编程角度来看,递归指的是方法定义中调用方法本身的现象
解决问题的思路:把一个复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解,递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算
递归解决问题要有两个内容
案例
// 求1~100的和(递归实现)
public class MyFactorialDemo1{
public static void main(String[] args){
int sum = getSum(100);
System.out.println(sum);
}
private static int getSum(int i){
if(i == 1){
return 1;
}else{
return i + getSum(i - 1); // i + (i - 1)的和
}
}
}
// 需求:用递归求5的阶乘,并把结果在控制台输出
public class MyFactorialDemo2{
public static void main(String[] args){
int result = getJc(5);
System.out.println(result);
}
private static int getJc(int i){
// 出口
if(i == 1){
return 1;
}else{
// 规则(递归下一次调用的,一定更接近出口)
return i * getJc(i - 1);
}
}
}
public class MyQuiteSortDemo{ public static void main(String[] args) { int[] arr = {6, 1, 2, 7, 9, 3, 4, 5, 10, 8}; quiteSort(arr, 0, arr.length - 1); for (int i = 0; i < arr.length; i++) { System.out.print(arr[i] + " "); } } private static void quiteSort(int[] arr, int left, int right) { if (right < left) { return; } // 记录两个值 int left0 = left; int right0 = right; // 计算出基准数 int baseNumber = arr[left0]; while (left != right) { // 1.从右开始找比基准数小的 while (arr[right] >= baseNumber && right > left) { right--; } // 2.从左开始找比基准数大的 while (arr[left] <= baseNumber && right > left) { left++; } // 3.交换两个值的位置 int temp = arr[left]; arr[left] = arr[right]; arr[right] = temp; } // 4. 基准数归位 int temp = arr[left]; arr[left] = arr[left0]; arr[left0] = temp; // 再次递归调用方法 quiteSort(arr, left0, left - 1); quiteSort(arr, left + 1, right0); } }
方法就是一段具有独立功能 的代码块,不调用就不执行
方法定义
public void 方法名(){
//方法体
}
方法调用:方法名();
注意
形参和实参 形参:全称形式参数,是指方法定义中的参数 实参:全称实际参数,是指方法调用中的参数
定义
public void 方法名(参数){
//方法体
}
单个参数:数据类型 变量名
多个参数:数据类型 变量名1 , 数据类型 变量名2 , .....
调用
方法名(变量名/常量值);
方法名(变量名1/常量值1 , 变量名2/常量值2 , ...);
方法调用时,参数的数量与类型必须与方法定义中的设置相匹配,否则程序将会报错
带参数方法练习
// 需求:设计一个方法(print)用于打印n到m之间的所有的奇数
public class a{
public static void main(String[] args){
print(10, 20);
}
public static void print(int n, int m){
for(int i = n; i <= m; i++){
if(i % 2 != 0) {
System.out.println(i);
}
}
}
}
定义
public 返回值数据类型 方法名(参数){
return 数据;
}
return;
可以用于结束方法,也就是方法从栈内存中弹出去,该过程称为方法的弹栈调用:数据类型 变量名 = 方法名(参数);
方法通用格式
public 修饰符 返回值类型 方法名(参数){
方法体;
return 数据;
}
上面的案例中,方法都有static修饰符,现在只需要知道,在main中调用方法,对应的方法必须由static修饰即可
方法名相同,参数也完全相同,称为方法的重复定义,是一种冲突性的错误 在调用方法的时候,Java虚拟机会通过参数的不同来区分同名的方法
对于调用方法的人来说,方法的形参数据类型的重要程度要远远高于返回值,所以方法签名就由方法名+形参列表构成
方法重载练习
// 需求:使用方法重载思想,设计比较两个整数是否相同的方法,兼容全整数类型(byte,short,int,long)
public static void main(String[] args){
System.out.println(compare(20, 30));
}
public static boolean compare(byte a, byte b){
return a == b;
}
public static boolean compare(short a, short b){
return a == b;
}
public static boolean compare(int a, int b){
return a == b;
}
public static boolean compare(long a, long b){
return a == b;
}
案例
// 需求:设计一个方法用于数组遍历,要求遍历的结果是在一行上的。例如:[11,22,33,44,55]
public static void main(String[] args) {
int[] arr = {11, 22, 33, 44, 55};
printArray(arr);
}
public static void printArray(int[] arr) {
System.out.print("[");
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i]);
if (i == arr.length - 1) System.out.print("]");
else {
System.out.print(", ");
}
}
}
// 需求:设计一个方法用于获取数组元素中的最大值
public static void main(String[] args){
int[] arr = {11,33,44,88,22};
System.out.println("数组中的最大值为:" + max(arr));
}
public static int max(int[] arr){
int max = arr[0];
for(int i = 0; i < arr.length; i++){
if(arr[i] > max) max = arr[i];
}
return max;
}
// 需求:设计一个方法,该方法中能够同时获取最大值和最小值
public static void main(String[] args){
int[] arr = {11,22,33,44,2,2393,55};
int[] res = get(arr);
System.out.println("最大值为:" + res[0]);
System.out.println("最小值为:" + res[1]);
}
public static int[] get(int[] arr){
int max = arr[0];
int min = arr[0];
for(int i = 0; i < arr.length; i++){
if(arr[i] > max) max = arr[i];
if(arr[i] < min) min = arr[i];
}
int[] arrMaxAndMin = {max, min};
return arrMaxAndMin;
}
注意:return语句只能同时返回一个值,需要返回多个值的话可以使用数组
指进位制,是人们规定的一种进位方式
计算机数据在底层运算的时候,都是以二进制进行的,了解不同的进制,便于我们对数据的运算过程理解的更加深刻
进制表示
在Java中,数值默认都是十进制,不需要加任何修饰
0b
开头,b大小写都可0
开头0x
开头,x大小写都可注意:书写的时候,虽然加入了进制的标识,但打印在控制台展示的时候都是十进制数据
进制转换
计算机中的数据,都是以二进制补码的形式在运算。补码是通过反码和原码推算出来的
原码:(可直观的看出数据大小)就是二进制定点表示法,最高位为符号位,0正1负,其余位表示数值的大小 一个字节等于8个比特位,也就是8个二进制位
反码:(将原码转换为补码)正数的反码与其原码相同,负数的反码是对其原码逐位取反,但符号位除外 补码:(数据以该状态进行运算)正数的补码与其原码相同,负数的补码是在其反码的末位加1
正数的原反补都是相同的 负数的【反码】,是根据【原码】取反(0变1,1变0)得到的 (符号位不变) 负数的【补码】,是根据【反码】的末尾+1得到的
位运算指的是二进制位的运算,先将十进制数转换成二进制后再进行运算
在二进制位运算中,1表示true,0表示false
&
位与:遇false则false,遇0则0|
位或:遇true则true,遇1则1^
位异或:相同为false,不同为true (a = a ^ b ^ b)~
取反:全部取反,0变1,1变0(也包括符号位)位移运算符
<<
有符号左移运算,二进制位向左移动,左边符号位丢弃,右边补齐0
运算规律:向左移动几位,就是乘以2的几次幂
>>
有符号右移运算:二进制位向右移动,使用符号位进行补位
运算规律:向右移动几位,就是除以2的几次幂
>>>
无符号右移运算符,无论符号位是0还是1,都补0
案例
// 需求:在不使用第三方变量的情况下,实现两数据交换
public static void main(String[] args){
int a = 10;
int b = 20;
a = a ^ b;
b = a ^ b;
a = a ^ b;
System.out.println(a);
System.out.println(b);
}
// 需求:实现数组元素的反转(交换数组中元素的值)
int[] arr = {11, 22, 33, 44, 55, 66, 77};
for(int start = 0, end = arr.length - 1; start < end; start++, end--){
int temp = arr[start];
arr[start] = arr[end];
arr[end] = temp;
}
for(int i = 0 ; i < arr.length; i++){
System.out.println(arr[i]);
}
二维数组也是一种容器,不同于一维数组,该容器存储的都是一维数组容器
定义格式
数据类型[][] 变量名;
数据类型 变量名[];
数据类型[] 变量名[];
动态初始化:
数据类型[][] 变量名 = new 数据类型[m][n];
拓展:将一个提前创建好的一维数组存储到二维数组中
int[] arr = {11, 22, 33};
int[][] arr2 = new int[1][3];
arr2[0] = arr;
System.out.println(arr2[0][2]);
静态初始化:
数据类型[][] 变量名 = new 数据类型[][]{{元素1, 元素2,...}, {元素1, 元素2,...}...};int[][] arr = new int[][]{ {1, 2, 3}, {4, 5, 6} };
数据类型[][] 变量名 = {{元素1, 元素2,...}, {元素1, 元素2,...}, ...};int[][] arr = { {1, 2, 3}, {4, 5, 6} };
二维数组遍历
arr = {{11, 22, 33}, {33, 44, 55}};
int[][] arr = {{11, 22, 33}, {33, 44, 55}};
for(int i = 0; i < arr.length; i++){
for(int j = 0; j < arr[i].length; j++){
System.out.println(arr[i][j]);
}
}
案例
二维数组求和
int sum = 0;
int[][] arr = {{22, 66, 44}, {77, 33, 88}, {25, 45, 65}, {11, 66, 99}};
for(int i = 0; i < arr.length; i++){
for(int j = 0; j < arr[i].length; j++){
sum += arr[i][j];
}
}
System.out.println(sum);