java基础

JAVA基础

注释

1).单行注释 //

2).多行注释

/*

*/

3).文档注释 (在生成文档时会保留下)

/**

*/

第一个java文件

public class HelloWorld{
public static void main(String[] args){
System.out.print("hello world");
}
}

输出语句

System.out.print

System.out.println

System.out.printf

区别:

1、print 将它的参数显示在命令窗口,并将输出光标定位在所显示的最后一个字符之后。

System.out.print(参数) 参数不能为空.必须有

2、println 将它的参数显示在命令窗口,并在结尾加上换行符,将输出光标定位在下一行的开始。

System.out.println() 可以不写参数

3、printf 是格式化输出的形式(即可以控制输出的格式)。

  • %d的意思是一个int值的占位符

  • %f为一个double 或float值的占位符

  • %s为一个string值的占位符

  • %.2f:输出两位小数点

  • %.3f:输出三位小数点

例:

public class a {

public static void main(String args[]) {

int i=9;

double j=10.4;

System.out.print("i,j的值分别为:"+i+","+j);

System.out.print("\n");//换行

System.out.println("i,j的值分别为:"+i+","+j);

System.out.printf("i的值为%d,j的值为%f",i,j);

System.out.println();//换行

System.out.printf("i的值为%d,j的值为%.2f",i,j);

}

}

image-20240311085719107

变量

1)定义:

计算机内存中的一块存储空间,是存储数据的基本单元

2)声明:

​ 数据类型 变量名;

​ 赋值:

​ 变量名=值;

​ 使用:

​ System.out.print(变量名);

可以声明时一起赋值

3)标识符

由字母,货币符号(英文状态下的),下划线(-),数字组成

不能以数字开头

不能与关键字、保留字重名

不能与字面常量重名(true false null)

命名方法:

a.帕斯卡法(pascal)每个单词首字母大写

b.驼峰命名法(camel)首单词首字母小写,后续单词首字母大写

数据类型

java中的变量有严格的数据类型区分(强类型语言)

java中任意一个值都有其对应的类型的变量。

image-20240304232122039

基本数据类型共8种

整数

image-20240304232204722

整数默认为int(运算时) 但在具体赋值时会窄化成具体类型

如果为long类型(超过int的极限时),需要在值的后面加“L”(不加就会转换成int)

小数(浮点型)

image-20240304233038730

浮点型数值采用科学计数法表示

double为浮点数的默认类型,要切换成float类型时,要在后面的值加“f”

布尔型

image-20240304233712045

可直接赋值true/false

也可以赋值一个结果为true/false的表达式

boolean不能参与算数运算

字符

ascii码:
0:48 A:65 a:97

image-20240304234149810

赋值方式:

image-20240304234309189

转义字符:

image-20240304234358568

字符串

image-20240304234553646

image-20240304234622463

例题

image-20240304234858505

类型转换

1.自动类型转换

两种类型相互兼容

目标类型大于原类型

short->int

2.强制类型转换

两种类型相互兼容

目标类型小于原类型

int->short

image-20240304235407561

强制转换规则:

image-20240304235613018

自动类型提升

image-20240304235718465

运算符

算数运算符

image-20240305001102597

a=10 b=8

System.out.print("a+b="+a+b);

此时会输出108 因为字符串拼接会转换成字符串 所以”a+b=”+a拼接了(10)

+(拼接符)b(8)成字符串拼接在一起(108)

要想输出正确结果,就要加括号,改变其运算顺序

System.out.print("a+b="+(a+b));

这样就是18

同理:

System.out.print("a+b="+a-b);

报错 因为字符串不能与整数相减

要改成

System.out.print("a+b="+(a-b));

特殊:

除数不能为0

5/0 报错->by zero

5.0/0 报错->infinity(无限大)

-5.0/0 报错->-infinity(无限小)

0.0/0 ——>NaN(not a number)

++–

++在前,先自增再使用自增后的结果

++在后,先使用自增前的结果再自增

–同理

赋值运算符

赋值运算符:等号右边赋值给等号左边

image-20240311083157302

例:

image-20240311084157980

image-20240311084638663

因为+是一个二元运算符 会将s1+s2的结果转换为int 此时要强制转换才行

image-20240311084349974

而+=是一个复合赋值运算符 是一元运算符 会将结果窄化,窄化为short 所以不影响

其他运算符

关系运算符

两个操作数进行比较

image-20240311085834056

比较结果都是布尔值

逻辑运算符

两个boolean类型的操作数或表达式进行逻辑比较

image-20240311090141834

短路与:

image-20240311090950018

正常 此时b=11

image-20240311091012052

短路 此时b=10 因为在判断a>9为false后 因为后面式&& 程序认为不用判断后续程序即可得到结果false,所以没有执行b++==10 ,所以b=10

但若是前面为a>b 则仍要执行后续代码

同理有短路或

三元运算符

将判断后的结果赋值给变量

image-20240311091830570

运算符的优先级

  • 括号优先
  • 算数>关系>赋值
  • */%>+-
  • !>&&>||

image-20240311092159826

控制台输入

image-20240311092504993

理解:

import java.util.Scanner;  //导包

public class Main {
public static void main(String[] args) {
Scanner scanner /*这里的scanner相当于定义扫描仪*/= new Scanner(System.in);
double width = scanner.nextDouble(); //小数用nextDouble
double height = scanner.nextDouble();
double area = width * height;
double perimeter = (width + height) * 2;
System.out.println("The area is " + area);
System.out.println("The perimeter is " + perimeter);

scanner.close();
}
}
import java.util.Scanner;//导包
public class TestS{
public static void main (String[] args){
Scanner input = new Scanner(System.in);//所以扫描仪的名字可以自定义(这里的input 上面的scanner)
//这里可以来一些提示输入
String name = input.next();//next()是接收字符串
int age = input.nextInt();//接收整数用nextInt()
char gender=input.next().charAt(0);//charAt(0)表示提取接收字符串的第一个字符 截断 所以这里是接收字符
System.out.println(”姓名: “+name);
System.out.println(”年龄: “+age);
System.out.println(”性别: “+gender);
}
}

选择结构

简单if

image-20240313101950939

import java.util.Scanner;
public class Main{
public static void main(String[] args){
Scanner.scanner=new Scanner(System.in);
System.out.println("成绩:");
int a=scanner.nextInt();
if(a>=90){
System.out.println("周末放假");
}
}
}

image-20240313102859465

if-else

image-20240313103024331

import java.util.Scanner;
public class Main{
public static void main(String[] args){
Scanner scanner=new Scanner(System.in);
System.out.println("成绩:");
int a=scanner.nextInt();
if(a>=90){
System.out.println("周末放假");
}eles{
System.out.println("滚去学习")
}
}
}

image-20240313103354178

多重if

image-20240313103533397

import java.util.Scannr;
public class Main{
public static void main(String[] args){
Scanner scanner=new Scanner(System.in);
System.out.println(钱:);
int a=scanner.nextInt();
if (a>=500){
System.out.println("法拉利");
}else if(a>=100){
System.out.println("保时捷");
}else if(a>=50){
System.out.println("奔驰");
}else if(a>=10){
System.out.println("大众");
}else{
System.out.println("五菱宏光,都有能买的车了,你还要什么自行车");
}
}
}

从大到小排或从小到大排

要连续区间

image-20240313110232793

嵌套if

image-20240313110347076

import java.util.Scanner;
public class Main{
public static void main(String[] args){
Scanner scanner=new Scanner(System.in);
System.out.println("预赛成绩");
int a=scanner.nextInt();
if(a<=10){
System.out.println("性别");
char gender=scanner.next().charAt(0);
if(gander=='男'){
System.out.println("男子决赛");
}else{
System.out.println("女子决赛");
}
}else{
System.out.println("很遗憾");
}
}
}

image-20240313111734290

分支结构

image-20240313112041530

image-20240313112544753

只要是Int即可判断

byte short char 都可以转换成Int

string本质上是int(hashCode)

long不行Long不能转成32位的int

case的值不能相同

当执行成功一个case会继续向下执行直到遇到break

import java.util.Scanner;
public class Main{
public static void main(String[] args){
Scanner scanner=new Scanner(System.in);
System.out.println("银行简写");
String bank=scanner.next();
switch(bank){
case"icbc":
case"ICBC":
System.out.println("工商银行");
break;
case"bc":
System.out.println("中国银行");
break;
case"cbc":
System.out.println("建设银行");
break;
default
System.out.println("输入有误");
break;
}
}
}

使用toLowerCase()可以把大写转成小写

switch(bank.toLowerCase())

image-20240313115019616

循环结构

概念:通过某个条件,重复执行一段逻辑代码

image-20240318083142151

while循环

image-20240318083315614

public class Main{
public static void main(String[] args){
int i=1;
while(i<=100){
System.out.println("第"+i+"次输出HelloWorld");
i++
}
}
}

image-20240318084223134

while是先判断后执行

//求和 1-100总和 奇数和 偶数和
public class Main{
public static void main(String[] args){
int sum=0,odd=0,even=0;
int i=1;
while(i<=100){
sum=sum+i;
if(i%2==1){
odd+=i;
}else{
even+=i;
}
i++;
}
System.out.println("sum="+sum);
System.out.println("odd="+odd);
System.out.println("even="+even);
}
}

do-whlie

image-20240318085719545

image-20240318085754781

import java.util.Scanner;
public class Main{
public static void main(String[] args){
Scanner scanner=new Scanner(System.in);
int score;
do{
System.out.println("第一阶段成绩为:");
score=scanner.nextInt();
}while(score<60);
System.out.println("本阶段考试成功");
}
}
public class Main{
public static void main(String[] args){
int i=1;
do{
System.out.println("第"+i+"次输出HelloWorld");
i++
} while(i<=100);
System.out.println("结束");
}
}

image-20240318091044774

for循环

image-20240318091239565

for循环是从while循环演变过来的,所以他们之间可以互相转换

//累乘
import java.util.Scanner;
public class Main{
public static void main(String[] args){
Scanner scanner=new Scanner(System.in);
System,out,println("输入一个数");
int mul=1;
int n=scanner.nextInt();
for(i=1;i<=n;i++){
mul=mul*i;
}
System.out.println(mul);
}
}
//求平均分
import java.util.Scanner;
public class Main{
public static void main(String[] args){
Scanner scanner=new Scanner(System.in);
int sum=0;
for(i=1;i<=5;i++){
System.out.println("第"+i+"名同学分数:");
int score =scanner.nextInt();
sum+=score;
}
System.out.println("平均分为"+sum/5);
}
}

流程控制

break

image-20240318092620473

public class Main{
public static void main(String[] args){
int i=1;
for(;i<=10;i++){
System.out.println("第"+i+"个数字");
if(i==5){
break;
}
}
System.out.println("完成,此时i为:"+i);
}
}

Break后会直接跳过后续代码,且for中不会I++

//求平均分
import java.util.Scanner;
public class Main{
public static void main(String[] args){
Scanner scanner=new Scanner(System.in);
int sum=0;
int count=0;
for(i=1;i<=5;i++){
System.out.println("第"+i+"名同学分数:");
int score =scanner.nextInt();
if(score<0){
System.out.println("输入异常,终止输入");
break;
}
sum+=score;
count++;
}
if(count==0){
System.out.println("本次录入无效");
}else{
System.out.println("当前人数为:"+count+"平均分为"+sum/count);
}
}
}

continue

image-20240318094033665

public class Main{
public static void main(String[] args){
int i=1;
for(;i<=10;i++){
if(i==5){
continue;
}
System.out.println("第"+i+"个数字");

}
System.out.println("完成,此时i为:"+i);
}
}

会跳过后续代码,但会继续执行循环,执行i++

//求平均分
import java.util.Scanner;
public class Main{
public static void main(String[] args){
Scanner scanner=new Scanner(System.in);
int sum=0;
for(i=1;i<=5;i++){
System.out.println("第"+i+"名同学分数:");
int score =scanner.nextInt();
if(score<0){
System.out.println("输入异常,重新输入");

i--; continue;
}
sum+=score;
}

System.out.println("平均分为"+sum/5);

}
}

嵌套循环

概念:在一个完整的循环结构中,嵌套另一个完整的循环

外层循环循环一次,内存循环循环一轮

//三行五列*
public class Main{
public static void main(String[] args){
//外层循环控制行数,内层循环控制列数
for(int i=1;i<=3;i++){
for(int j=1;j<=5;j++){
System.out.print("*");
}
System.out.println();
}
}
}

外层循环控制行数,内层循环控制列数

//计算三个班,每个班5名同学的平均成绩
import java.util.Scanner;
public class Main{
public static void main(String[] args){
Scanner scanner=new Scanner(System.in);
for(int i;i<=3;i++){
int sum=0;
for(int j;j<=5;j++){
System.out.println("第"+i+"个班,第"+j+"个同学的成绩是:");
sum+=scanner.nextInt();
}
System.out.println("第"+i+"个班的平均分是:"+sum/5);
}
}
}
//打印图型
public class Main{
public static void main(String[] args){
//打印正直角三角形
for(int i;i<=5;i++){
for(int j;j<=i,j++){//通过i来控制j
System.out.print("*");
}
System.out.println();
}

//打印反的直角三角形
for(int i;i<=5;i++){
//用一个循环来打印空格
for(int j=1;j<=5-i;j++){
System.out.print("");
}
for(int j;j<=i,j++){//通过i来控制j 打印*
System.out.print("*");
}
System.out.println();
}

//打印等腰三角形
for(int i;i<=5;i++){
//用一个循环来打印空格
for(int j=1;j<=5-i;j++){
System.out.print("");
}
for(int j;j<=2*i-1,j++){//通过i来控制j 打印* 1,3,5,7,9找规律
System.out.print("*");
}
System.out.println();
}

//打印菱形
//打印菱形上半部分
for(int i;i<=5;i++){
//用一个循环来打印空格
for(int j=1;j<=5-i;j++){
System.out.print("");
}
for(int j;j<=2*i-1,j++){//通过i来控制j 打印* 1,3,5,7,9找规律
System.out.print("*");
}
System.out.println();
}
//打印菱形下半部分
for(int i;i<=5;i++){
//用一个循环来打印空格
for(int j=1;j<=i;j++){
System.out.print("");
}
for(int j;j<=2*(5-i)-1,j++){//通过i来控制j 打印* 7,5,3,1找规律
System.out.print("*");
}
System.out.println();
}
}
}

方法与函数

实际上方法就是函数,只是在面向对象编程中,将函数称为方法

语法

image-20240320113041653

在java中不允许在方法中定义方法

image-20240320113240845

所以只有2和4能定义方法

main方法是程序的入口,一开始程序就会执行,而普通方法必须在main方法中进行调用才能执行

public class Main{
public static void main(String[] args){
System.out.println("窗前明月光,");
printSign();
System.out.println("疑是地上霜。");
printSign();
System.out.println("举头望明月,");
printSign();
System.out.println("低头思故乡。");
printSign();
}
public static void printSign(){
System.out.println("---------");
}
}

在需要执行代码的地方,通过方法名称进行调用方法

调用方法时,会优先执行方法内部代码,结束后,返回到方法调用处,继续向下执行

参数

形参与实参

image-20240325085238714

public class Main{
public static void main(String[] args){
System.out.println("窗前明月光,");
printSign(10,#);
System.out.println("疑是地上霜。");
printSign(10,$);
System.out.println("举头望明月,");
printSign(10,%);
System.out.println("低头思故乡。");
printSign(10,^);
}
public static void printSign(int count,char sign){
for (int i=1;i<=count;i++){
System.out.println(sign);
}
System.out.println();
}
}

返回值

参数是调用者给方法的输入,返回值是方法给调用者的反馈

image-20240325090312312

image-20240325090450620

public class Main{
public static void main(String[] args){
int a;
int b;
int c = add(a,b);
System.out.println(c);
}
public static int add (int a,int b){
return a+b;
}
}

返回值只能有一个,也就是说返回过来的值只能有一个

即:不能有

public static int add (int a,int b){
return a+b;
return a-b;
}

//这种要写成两个方法

但是这种可以:

public class Main{
public static void main(String[] args){
int a;
int b;
if(num%2==0){
return "偶数"
}else{
return "奇数"
}
}
}

同时这种不行:

public class Main{
public static void main(String[] args){
int num;
if(num%2==0){
return "偶数"
}else if(num%==1){
return "奇数"
}
//至少要加这个 return "xx";
}
}

因为编译器认为你else if后面可能还有if 而if后没有返回值 报错,所以至少要在后面再加一个返回值

image-20240325093005531

image-20240325093124926

如果此时是break,是指跳到for循环外,继续执行后续代码,这里是到}外

而return,在无返回值时可写可不写,写了就表示结束方法,这里时回到{

调用与递归

多级调用:

public class Main{
public static void main(String[] args){
m1();
}
public static void m1(){
System.out.println("m1-start");
m2();
System.out.println("m1-end");
}
public static void m2(){
System.out.println("m2-start");
System.out.println("m2-end");
}
}

先执行m1,再执行m2,然后执行m1后续

无穷递归

public class Main{
public static void main(String[] args){
m1();
}
public static void m1(){
System.out.println("m1-start");
m1();
System.out.println("m1-end");
}
}

此时会无限调用m1,导致方法栈溢出,报错

递归

image-20240325094945449

递归阶乘

image-20240325095147430

public class Main{
public static void main(String[] args){
int num = f(5);
System.out.println(num);
}
public static int f(int n){
return n==1?1:n*f(n-1);
}
}

if同理

递归:斐波那契数列

后面的数是前两个数之和:1 1 2 3 5 8 13 21 34 55

public class Main{
public static void main(String[] args){
int num=getRabit(20);
System.out,println(num);
}
public static int getRabit(int n){
return n==1||n==2?1:getRabit(n-1)+getRabit(n-2);
}
}

数组

概念

一组连续的存储空间,存储多个相同数值类型的值

创建:

先声明 再分配空间:
数据类型[] 数组名;
数组名=new 数据类型[长度];
int[] a;
a=new int[5]//5表示内存大小为5

声明并分配空间:
数据类型[] 数组名=new 数据类型[长度];
int[] a= new int[5];

声明并赋值1
数据类型[] 数组名=new 数据类型[]{1,2,3};//此时[]内不写
int[] a=new int[]{1,2,3};

声明并赋值2
数据类型[] 数组名={1,2,3};//显示初始化 但不能换行
int[] a={1,2,3};

image-20240327113352733

遍历

遍历:从头至尾,逐一对数组的每个元素进行访问

public class Main{
public static void main(String[] args){
int[] nums={1,2,3,4,5,6};
for(int i=0;i<nums.length;i++)
System.out.println(nums[i]);
}
}

image-20240327114047818

默认值:

默认值会根据数据类型的不同而改变

int–>0

double–>0.0

boolean–>false

char–>-\u000

其他(引用类型)–>null

//求平均值
public class Main{
public static void main(String[] args){
int[] nums={8,7,9,3,5};
int sum=0;
for(int i=0;i<nums.length;i++)
sum += nums[i];
System.out.println(sum/nums.length);
}
}
//输入一个数 判断是否在数组中
import java.util.Scanner
public class Main{
public static void main(String[] args){
int[] nums={8,7,9,3,5,6,10};
Scanner scanner=new Scanner(System.in);
int num = input.nextInt;
boolean flag=false//先默认这个值不存在
for(int i=0;i<nums.length;i++)
if(nums[i]==num);{
System.out.println(i);
flag=true;
break;
}
}
if(flag=false){
System.out.println(666);
}
}
}

扩容

length属性是只读权限 不能赋值

image-20240403105542687

所以扩容就是创建一个新数组然后把旧数组的值重新传进来

//数组的扩容
public class Main{
public static void main(String[] args){
int[] nums={11,22,33,44,55};
int[] newNums=new int[nums.length*2];
for(int i=0;i<nums.length;i++)
newNums[i]=nums[i];//将nums中的值赋给newNums
}
nums=newNums;
System.out.println(Arrays.toString(nums))
}
}

nums=newNums;

因为数组是引用类型,所以在声明数组时会在堆中开辟一段空间 将nums的地址指向这个堆空间

而将nums=newNums;此时是进行栈操作,将nums的地址指向newNums的堆空间 进而实现数组的拓展

image-20240403110950666

image-20240403111435499

复制的方法:
image-20240403111043343

//数组的扩容
public class Main{
public static void main(String[] args){
nums=Array.copyof(nums,nums.length*2);
//要调用这个拓展了的数组 因为它是以返回值的形式返回
System.out.println(Arrays.toString(nums))
}
}

数组型参数与返回值

public class Main{
public static void main(String[] args){
int[] nums={1,2,3,4,5,6};
add(nums);
System.out.println(Arrays.toString(nums))

}
public static void add(int[] nums){
for(int i=0;i<nums.length;i++){
nums[i]+=1;
}
}
}

//输出2,3,4,5,6,7

因为这里当数组作为一个参数时,方法会获取他堆地址进行操作

public class Main{
public static void main(String[] args){
int[] nums={1,2,3,4,5,6};
//add(nums);
//System.out.println(Arrays.toString(nums))
expand(nums);
}
public static void expand(int[] nums){
nums=Arrays.copyof(nums,nums.Lenth*2);
System.out.println(Array.toString(nums));
}

public static void add(int[] nums){
for(int i=0;i<nums.length;i++){
nums[i]+=1;
}
}
}
//此时会输出已扩展的nums


public class Main{
public static void main(String[] args){
int[] nums={1,2,3,4,5,6};
//add(nums);
//System.out.println(Arrays.toString(nums))
expand(nums);
System.out.println(Array.toString(nums));
}
public static void expand(int[] nums){
nums=Arrays.copyof(nums,nums.Lenth*2);
//System.out.println(Array.toString(nums));
}

public static void add(int[] nums){
for(int i=0;i<nums.length;i++){
nums[i]+=1;
}
}
}
//此时会输出为扩展的nums

//因为expand方法中有一个形参->nums 但这其实不是nums数组,形参是互补影响的,所以这里其实是在调用expand方法时,会在堆中重新开辟一段空间,此时形参nums(叫其他的也是一样的)的地址会指向nums数组的堆地址,赋值到形参的地址,扩容,但在调用完成后会销毁这个地址(因为没用),所以如果查看nums数组时,会仍指向原地址,就没扩容




//解决
public class Main{
public static void main(String[] args){
int[] nums={1,2,3,4,5,6};
//add(nums);
//System.out.println(Arrays.toString(nums))
nums=expand(nums);//接收
System.out.println(Array.toString(nums));
}
public static int[] expand(int[] nums){//将返回值类型改为数组
nums=Arrays.copyof(nums,nums.Lenth*2);
return nums;//返回地址
//System.out.println(Array.toString(nums));
}

public static void add(int[] nums){
for(int i=0;i<nums.length;i++){
nums[i]+=1;
}
}
}

可变长参数

public class Main{
public static void main(String[] args){
add(1,2,3,4);
}
public static void add(int...nums){
int sum=0;
for(int i=0;i<nums.length;i++){
nums[i]+=1;
}
System.out.println(sum);
}
}

可变长参数其实就是未封装的数组

但可变长参数只能在最后一个形参处调用

image-20240403114621699

排序

排序的目的是为了方便数据的查找

有10种排序方法

冒泡排序 选择排序 插入排序 n*n

快速排序 堆排序 希尔排序 归并排序 n*log2n

桶排序 计数排序 计数排序

//冒泡排序:相邻的两个数值比较大小 互换位置
public class Main{
public static void main(String[] args){
int[] nums = {3,5,9,56,84,24,12,8};
bubbleSort(nums);
System.out.println(Array.toString(nums));
}
public static void bubbleSort(int[] nums){
for(int i=0;i<nums.length-1;i++){//外层循环控制轮数
for(int j=0;j<nums.length-1-i;j++){//内层循环控制每轮比较次数 比过的就不用再比了
//相邻比较 交换顺序
if(nums[j]<nums[j+1]){
int temp = nums[j];
nums[j]= nums[j+1];
nums[j+1]=temp;
}
}
}
}
}


//选择排序:固定值与其他值依次比大小,互换位置

//jdk排序
public class Main{
public static void main(String[] args){
int[] nums = {3,5,9,56,84,24,12,8};
Arrays.sort(nums);//默认升序排序
System.out.println(Array.toString(nums));
}
}


//计数排序 用于特定环境 连续区间
public class Main{
public static void main(String[] args){
int[] nums = {1243241342};
//{2,3,2,3}描述数组 2个1 3个2 2个3 3个4
//{1,1,2,2,2,3,3,4,4,4}排序

int[] counts=new int[4];//{0,0,0,0}
for(int i=0;i<nums.length;i++){//描述数组构建
counts[nums[i]-1]++;//映射赋值
}
int[] newNums=new int[nums.length];
int index=0;
for(int i=0;i<counts.length;i++){
for(int j=0;j<counts[i];j++){
//还原数组
newNums[index++]=i+1;
}
}
nums=newNums;
System.out.println(Arrays.toString(nums));
}
}

查找

public class Main{
public static void main(String[] args){
int[] nums = {1,6,2,35,48,5};
int num = 5;
int index=getNum(nums,num);
System.out.println(index);

Array.sort(nums);
int index=binarySearch(nums,num);
//也可以直接 int index=Array.binarySearch(nums,num);
System.out.println(index);
}

//顺序查找 一个一个找
public static int getNum(int[] nums,int num){
for(int i=0;i<nums.length;i++){
if(nums[i]==num){
return i;
}
}
return -1;
}

//二分查找 一半一半找 前提是数据有序的
public static int binarySearch(int[] nums,int num){
int begin=0;
int end=nums.length-1;
int mid;
while(begin<=end){
mid=(begin+end)/2 //取中点下标
if(nums[mid]==num){
return mid;
}else if(nums[mid]==num){//说明查找元素再前半部分
//end 前移
}else{
//begin 后移
begin=mid+1;
}
}
return -1;
}
}

二维数组

概念:

image-20240408094100540

赋值:

image-20240408094336997

内存分配

image-20240408094458848

访问:

image-20240408094607893

声明:

image-20240408094741389

高维长度是必要的 低维长度可要可不要

public class Main{
public static void main(String[] args){
int[][]nums={{1,2,3},{4,5,6},{7,8,9}};
for(int i=0;i<nums,length;i++){
for(int j=0;j<nums[i].length;j++){
System.out.println(nums[i][j]+" ");
}
System.out.println();
}
}
}
//杨辉三角
public class Main{
public static void main(String[] args){
int[][]nums=new int[10][];
for(int i=0;i<nums.length;i++){
nums[i]=new int[i+1];
nums[i][0]=1;
nums[i][i]=1;
for(int j=1;j<nums[i].length-1;j++){
nums[i][j]=nums[i-1][j-1]+nums[i-1][j];
}
}
for(int i=0;i<nums,length;i++){
for(int j=0;j<nums[i].length;j++){
System.out.println(nums[i][j]+" ");
}
System.out.println();
}
}
}

面向对象

对象

image-20240410102648801

image-20240410103759344

//创建类
public class Dog{
//属性
String brand;//品种
String name;
int age;
String color;

//方法
public void eat(){
System.out.println(name+"eating");
}

public void sleep(){
System.out.println(name+"sleeping");
}
}


//另一个包实例化对象
public class Main{
public static void main(String[] args){
Dog dog=new Dog();
dog.brand="1";
dog.name="2";
dog.age="3";
dog.color="4";

dog.eat();
dog.sleep();
}
}

image-20240410104643287

类(类型)是一种模板(1个) 根据类可以创建出多个对象(实例)

image-20240410104902803

方法与属性

属性

属性是有默认值的 所有在类的定义中可以不赋值 直接调用

image-20240410105246809

就近原则:谁离我近 谁对我起作用(作 用域更小的起作用)

方法

image-20240410105657665

//创建类
public class Student{
//属性
String name;
int age;
String sex;
int score;

//方法
public void sayHi(){
System.out.println(name+"---"+age+"---"+sex+"---"+score);
}

}


//另一个包实例化对象
public class Main{
public static void main(String[] args){
Student s1=new Student();
s1.name="2";
s1.age="3";
s1.sex="4";
s1.score="5";
s1.sayHi();


Student s2=new Student();
s2.name="a";
s2.age="b";
s2.sex="c";
s2.score="d";
s2.sayHi();
}
}

方法重载

有些情况下,对象的同一种行为可能存在多种实现过程(吃饭与吃药 都是吃 但过程存在差异)

这样直接写的话会出现一个问题就是:方法名太多。而重载存在的意义就是解决方法名的问题 他允许一个方法名执行多个方法 根据传来的参数不同 执行不同的方法

image-20240410111013681

注:参数要不同 与返回值类型无关 与形参名字无关

构造方法

image-20240410111327769

image-20240410111606491

构造方法也可以重载,遵循重载规则

image-20240410111937961

//创建类
public class Student{
//属性
String name;
int age;
String sex;
int score;

//构造方法
public Student(String n,int a,String s,int sc){
name=n;
age=a;
sex=s;
score=sc;
}

public Student(){//如果自己写了带参数的构造方法 要再写一个无参数的构造方法(习惯) 因为框架会调用

}

//方法
public void sayHi(){
System.out.println(name+"---"+age+"---"+sex+"---"+score);
}

}


//另一个包实例化对象
public class Main{
public static void main(String[] args){
Student s1=new Student("2",3,"4",5);
s1.sayHi();


Student s2=new Student();
s2.name="a";
s2.age="b";
s2.sex="c";
s2.score="d";
s2.sayHi();
}
}

this关键字

image-20240410112918317

用法1:

image-20240410113039744

用法2:

当两个构造方法当中,包含多条冗余代码时

image-20240410113359968

public Student(String name,int age,String sex){
this.name=name;
this.age=age;
this.sex=sex;
}

public Student(String name,int age,String sex,int score){
this(name,age,sex);//只能在第一行
this.score=score;
}

在对象创建时 一旦分配空间 就已经存在this了 指向这个空间

封装

image-20240413142319994

本来这样是直接给age赋值 可能无意或恶意输入错误值

所以用set get 方法

image-20240413142545434

这样将接受和赋值分开 可以让是否赋值的主动权在我们手中(可以判断)

public class character {
public static void main(String[] args) {
Student s1=new Student();
s1.setAge(22000);
System.out.println(s1.getAge());
}
}
public class Student{
String name;
private int age;
String gender;
double score;

public void setAge{
if(age>=0&&age<=120) {
this.age = age;
}else{
this.age=18;
}
}
public void getAge{
return age;
}
}

image-20240413154220187

封装的好处:

  • 更安全
  • 对外提供一个接口 更方便

继承

概念

程序中的继承,是类与类之间特征和行为的一种赠与或获得

两个类之间的继承关系,必须满足”is a”的关系

父类的选择:

一个对象其实是有很多的父类

image-20240413155258258

public class Pet{
String name;
int health;
int love;//亲密度

public void eat(){
System.out.println(name+" is eating");
}
public void show(){
System.out.println(name+"-"+health+"-"+love);
}

public String getName(){
return name;
}
public void setName(String name){
this.name=name;
}
public int getHealth(){
return health;
}
public void setHealth(int health){
this.health=health;
}
public int getLove(){
return love;
}
public void setLove(int love){
this.love=love;
}
}

public class Dog extends Pet{
String strain;//品种

public void catchDisk(){
System.out.println("在玩飞盘");
}

public String getStrain(){
return strain;
}
public void setStrain(String strain){
this.strain=strain;
}
}

public class Penguin extends Pet{
String gender;

public void swim(){
System.out.println("在游泳");
}

public String getGender(){
return gender;
}
public void setGender(String gender){
this.gender=gender;
}
}

public class exercise {
public static void main(String[] args) {
Dog d = new Dog();
d.name="汪汪";
System.out.println(d.name);
d.show();
Penguin p = new Penguin();
p.name="QQ";
System.out.println(p.name);
p.show();
}
}

在一组相同或类似的类中,抽取出共性的特征和行为,定义在父类中,实现重用

子类通过extends来继承

image-20240417104444383

特点

单根性:一个类只能有一个直接的父类

传递性:类之间可以多级继承,属性和方法逐级叠加

public class Person{
String name;
int age;

public void display(){
System.out.println(name +"-"+ age);
}

public String getName(){
return name;
}
public int getAge(){
return age;
}
public void setName(String name){
this.name = name;
}
public void setAge(int age){
this.age = age;
}
}

public class SE extends Person{
public void code(){
System.out.println(name+"coding");
}
}

public class Student extends SE{
int score;
public void dowork(){
System.out.println(name +"studying");
}
}

public static void main(String[] args) {
Student s=new Student;
s.name="Ozero";
s.age=19;
s.score =150;
s.dowork();//Student
s.show();//Person
s.code();//SE
}

可以通过接口与内部类来实现多继承

属性的继承

父类的所以属性都可以被继承

但是父类的私有属性不能被访问

当子类和父类有同名属性的时候可以通过super关键字区分

image-20240417111831356

sub继承sup

不加super–>当前对象的属性

加super–>父类被继承道子类的属性

public class Sup {
private int a=1;
public int b=2;
}

public class Sub extends Sup{
public char c='c';
public int b=3;
public class show(){
System.out.println(super.b)
}
}

public static void main(String[] args) {
Sub sub=new Sub();
sub.show();
}

image-20240417113146760

默认是default

方法的重写与覆盖

如果父类提供的方法无法满足子类需求时,可在子类中定义和父类相同的方法进行重写(Override)

public class Pet{
String name;
int health;
int love;//亲密度

public void eat(){
System.out.println(name+" is eating");
}
public void show(){
System.out.println(name+"-"+health+"-"+love);
}

public String getName(){
return name;
}
public void setName(String name){
this.name=name;
}
public int getHealth(){
return health;
}
public void setHealth(int health){
this.health=health;
}
public int getLove(){
return love;
}
public void setLove(int love){
this.love=love;
}
}

public class Dog extends Pet{
String strain;//品种

public void catchDisk(){
System.out.println("在玩飞盘");
}

public void show(){
super.show();
System.out.println(strain);
}

public String getStrain(){
return strain;
}
public void setStrain(String strain){
this.strain=strain;
}
}

public class exercise {
public static void main(String[] args) {
Dog d = new Dog();
d.name="汪汪";
d.health=10;
d.love=5;
d.strain="修狗"
d.show();
}
}

当然 也可以不用 super.show(); 直接完全重写也行 但这时是默认default 所以可以直接访问

System.out.println(name+"-"+health+"-"+love+"-"+strain);

但如果这时是private呢

肯定不能这样访问

System.out.println(getName()+"-"+getHealth()+"-"+getLove()+"-"+strain);

他把门关了,我们调用这个窗户就行

当然 这里也要改

public  class exercise {
public static void main(String[] args) {
Dog d = new Dog();
d.setName(汪汪);
d.setHealth(10);
d.setLove(5);
d.strain="修狗"
d.show();
}
}

如果父类里strain也是private 也需要setStrain()

方法重写的时候 访问权限可以放大 不能减小

返回值类型可以和父类一样,也可以是父类返回值类型的子类

方法名要一样

参数列表也必须相同

父类的私有的东西是不能被重写的

image-20240417161050813

继承中的对象创建

在具有继承关系的对象创建中,构建子类对象会先调用父类构造

由父类的共性类容,叠加子类的独有内容,组合成完整的子类对象

image-20240417162049626

只会调用父类的构造方法 而不会去创建父类

public class exercise {
public static void main(String[] args) {
C c=new C(7,8,9);
System.out.println(c.a+"--"+c.b+"--"+c.c);
}
}
class A{
int a=4;
public A(int a){//带参构造
this.a=a;
System.out.println("A(int)");
}
}
class B extends A{
int b=3;
public B(int b,int a){
super(a);
this.b=b;
System.out.println("B(int,int)");
}
}
class C extends B{
int c=5;
public C(int c,int b,int a){
super(a,b);
this.c=c;
System.out.println("C(int,int,int)");
}
}

super() 表示调用父类无参构造

super(实参) 表示调用父类带参构造

image-20240417163817844

多态

概念

多态=继承+重写

image-20240417165136599

多态表现形式:调用父类的方法,执行子类的方法

这里是向上转型

多态的应用

1.使用父类作为方法形参实现多态,使方法参数的类型更为宽泛

代码与前面的相结合一下 这里只写重点代码了

public class character {
public void feed(Pet){
pet.eat();
}

public static void main(String[] args) {
character m = new character();
m.feed(new Dog());
}
}

2.使用父类作为方法返回值实现多态,使方法可以返回不同子类对象

public class character {
public void feed(pet){
pet.eat();
}

public Pet getPet(String type){
if(type.equals("cat")){
return new Dog();
}else {
return new Penguin();
}
}

public static void main(String[] args) {
character m = new character();
Pet pet = m.getPet("Dog");
m.feed(new Dog());
}
}

向下转型(拆箱)

一个对象在调用方法的时候,能调用到哪些方法取决于对象的类型

执行方法的时候,执行哪个方法取决于实际类型

public class character {
public void feed(pet){
pet.eat();
}

public void play(Pet pet){
Dog dog=(Dog)pet;
dog.catchDisk();
}

public Pet getPet(String type){
if(type.equals("cat")){
return new Dog();
}else {
return new Penguin();
}
}

public static void main(String[] args) {
character m = new character();
Pet pet = m.getPet("Dog");
m.feed(new Dog());
m.play(Pet);
}
}

Dog dog=(Dog)pet;

将父类引用中的子类对象,强制转回子类本身类型,称为向下转型

只要转回子类真实类型,才可调用子类独有的属性和方法

向下转型时,如果父类引用中的子类对象类型和目标类型不匹配,则会发生类型转换异常(classCastException)

解决:

判断传来的是什么

instanceof关键字

public class character {
public void feed(pet){
pet.eat();
}

public void play(Pet pet){
if(pet instanceof Dog){
Dog dog=(Dog)pet;
dog.catchDisk();
}else {
Penguin p =(Penguin) pet;
p.swim();
}
}

public Pet getPet(String type){
if(type.equals("cat")){
return new Dog();
}else {
return new Penguin();
}
}

public static void main(String[] args) {
character m = new character();
Pet pet = m.getPet("Dog");
m.feed(new Dog());
m.play(Pet);
}
}

向下转型前,应先判断引用中对象真实类型,保证类型转换的正确性

抽象

abstract

介绍

abstract 抽象

这是上面写的Pet类 并加上了abstract

public abstract class Pet{
String name;
int health;
int love;//亲密度

public void eat(){
System.out.println(name+" is eating");
}
public void show(){
System.out.println(name+"-"+health+"-"+love);
}

public String getName(){
return name;
}
public void setName(String name){
this.name=name;
}
public int getHealth(){
return health;
}
public void setHealth(int health){
this.health=health;
}
public int getLove(){
return love;
}
public void setLove(int love){
this.love=love;
}
}

因为这个Pet是一个抽象出来的类 所以它不能被实例化

Pet pet=new Pet();  //这样不行 只能new Dog()这种

image-20240421195056419

作用

那抽象类的作用是什么呢

1.可被子类继承

2.可声明为引用

image-20240421195716373

抽象方法

在抽象类中 只用声明这个方法就行 具体实现在子类中(必须 若这个子类不是抽象的化 抽象的化就会让子类的子类来实现)

public abstract class Pet{
String name;
int health;
int love;//亲密度

public abstract void eat()//将eat方法抽象

public void show(){
System.out.println(name+"-"+health+"-"+love);
}

public String getName(){
return name;
}
public void setName(String name){
this.name=name;
}
public int getHealth(){
return health;
}
public void setHealth(int health){
this.health=health;
}
public int getLove(){
return love;
}
public void setLove(int love){
this.love=love;
}
}

抽象方法必须放在抽象类中(或接口中)

image-20240421200629629

static

介绍

静态

实例属性:

public class Myclass {
int a;
}

public class Text {
public static void main(String[] args) {
Myclass mc1 = new Myclass();
mc1.a = 10;
Myclass mc2 = new Myclass();
mc2.a = 20;
System.out.println(mc1.a+"---"+mc2.a);
}
}
//10---20

image-20240421201723788

静态属性:

public class Myclass {
static int a;//这里将a变为静态属性
}

public class Text {
public static void main(String[] args) {
Myclass mc1 = new Myclass();
mc1.a = 100;
Myclass mc2 = new Myclass();
mc2.a = 200;
System.out.println(mc1.a+"---"+mc2.a);
}
}
//20---20

image-20240421202112564

注意 这里用mc1.b来调用实际上警告了的(java中) 因为b实际上是在类中 该用Myclass.b来调用

image-20240421202445371

这里可以通过静态变量来统计类对象被创建了多少词

静态方法

public class Myclass {
int a;

public static void m1() {
System.out.println("M1");
m2();//静态方法之间可以直接调用
new Myclass().m3();//非静态方法要实例化对象调用
}

public static void m2() {
System.out.println("M2");
}

public void m3() {
System.out.println("M2");
}
}

public class Text {
public static void main(String[] args) {
// Myclass mc1 = new Myclass();
// mc1.a = 10;
// Myclass mc2 = new Myclass();
// mc2.a = 20;
// System.out.println(mc1.a+"---"+mc2.a);
Myclass.m1();
}
}
//m1 m2 m3

在静态方法中不能用this super

image-20240421203443385

image-20240421203603070

public class Myclass {
int a;

public static void m1() {
System.out.println("M1");
m2();
}

public static void m2() {
System.out.println("M2");
}

public void m3() {
System.out.println("M2");
}
}

public class Text {
public static void main(String[] args) {
// Myclass mc1 = new Myclass();
// mc1.a = 10;
// Myclass mc2 = new Myclass();
// mc2.a = 20;
// System.out.println(mc1.a+"---"+mc2.a);
// Myclass.m1();
Myclass mc = new SubClass();
mc.m1();
/*
如果这里是
SubClass mc = new SubClass();
mc.m1();
结果:sub-m1 隐藏 不重写
*/
SubClass.m1();
}
}

class SubClass extends Myclass{
public static void m1() {
System.out.println("sub-m1");
}
/*
没有这里方法的时候会输出:
m1 m2 m3
*/
}
//sub-m1(SubClass.m1();)
//m1 m2 m3(mc.m1();)

类加载

image-20240421204829368

反射时会主动加载

静态代码块

静态代码块会优先于类 构造方法之类的先执行 一般用于初始化

public class Myclass {
int a=888;

static {
System.out.println(a);
System.out.println("static block");
}

}

public class Text {
public static void main(String[] args) {
new Myclass();
}
}
//888
//static block
//先加载静态属性 再加载静态代码块 new多次也只会执行一次(已经加载了)

image-20240421205735924

final

介绍

image-20240421210000010

final修饰类:此类不能被继承

final修饰方法:此方法不能被覆盖

final修饰变量:此变量不能被改变(常量)

image-20240421210720496

普通常量:

image-20240421210752719

静态常量:

image-20240421210904529

对象常量:

常量是一个对象

image-20240421211244107

image-20240421211307746

接口

语法

接口相当于特殊的抽象类,定义方法、组成部分与抽象类类似

interface

public interface MyInterface{
public static final String FIELD="value";
public abstract void m1();
void m2();//默认public abstract
double VERSION=1.0;//默认public static final
}

jdk8以前:

接口中只能写:

1.公开静态常量

2.公开抽象方法

接口的使用:

接口相当于一个抽象父类

public interface MyInterface{
public static final String FIELD="value";
public abstract void m1();
void m2();//默认public abstract
double VERSION=1.0;//默认public static final
}

public class SubTest implements MyInterface{
public void m1(){
System.out.println("sub-M1");
}
}

public class Test{
public static void main(String[] args){
SubTest sub = new SubTest();
sub.m1();

MyInterface sub = new SubTest();
sub.m1();
}
}
//sub-M1 sub-M1

与抽象类的异同:

image-20240421212931162

介绍

image-20240421213834570

public interface ICode{
void code();
}

public interface IPlay{
void play();
}

public class Student implements IPlay,ICode{

public void code(){
System.out.println("会编码");
}

public void play(){
System.out.println("弹钢琴");
}
}

public static void main(String[] args){
Student s = new Student();
s.code();
s.play();
}

接口的规范

  • 任何类在实现接口时,必须实现接口中所有的抽象方法,否则此类为抽象类
  • 实现接口中的抽象方法时,访问修饰符必须时public

接口引用

同父类一样,接口也可以声明为引用,并指向实现类对象

注:

  • 仅可调用接口中声明的方法,不可调用实现类中独有的方法
  • 可强回转实现类本身类型,进行独有方法调用

接口的多态

image-20240421214510628

image-20240421214617722

不同引用类型,仅可调用自身类型中所什么的方法

常见关系

image-20240421214803253

常量接口

将多个常用于表示状态或固定值的变量,以静态常量的形式定义在接口中统一管理,提高代码可读性

接口表示标准

接口从宏观上来讲是一种标准

public interface IUsb {
void service();
}

public class character {
IUsb usb;//成员变量

}

public class UsbDisk implements IUsb{
public void service() {
System.out.println("Usb service started1");
}
}

public class UsbFan implements IUsb{
public void service() {
System.out.println("Usb service started2");
}
}

public class Test{
public static void main(String[] args) {
UsbDisk disk = new UsbDisk();
UsbFan fan = new UsbFan();
character c=new character();
c.usb=disk;
c.usb.service();

}
}
//Usb service started1

接口除了表示约束 表示规范 接口还表示一种标记

接口回调

先有接口的使用,后有接口的实现

public interface ICallback {
void call();//抽象方法--以后要实现的功能--留给实现类去实现

default void doCall(){//jdk8以后 接口中可以调用默认方法(用default修饰)与静态方法
call();
}
}

public class Test{
public static void main(String[] args) {
ICallback call =new CallBack();//反射+注解自动寻找用户类来完成对这个类的实例化
call.doCall();
}
}

public class CallBack implements ICallback {
public void call(){
System.out.println("call!");
}
}
//call!

总结

接口优势:

  • 程序的耦合度降低
  • 更自然的使用多态
  • 设计与实现完全分离
  • 更容易搭建程序框架
  • 更容易更换具体实现

image-20240421221459493