java基础学习

helloworldad1mv-ybgu0

开始学习Java安全,先从基础学起

学习网站:

JAVA 基础 |Java全栈工程师 | 以实例驱动学习 | how2j.cn

Java学习路线(学+测) - 阿里云开发者社区 (aliyun.com)

https://www.bilibili.com/video/BV1YT4y1H7YM/

工具环境配置

idea网上搜的破解版教程

IntelliJ IDEA中配置Tomcat(超详细)_idea怎么配置tomcat服务器-CSDN博客

Java简介

可以实现任何功能,java不擅长的部分会被其他的语言所顶替。

网景(第一家浏览器技术的启发,推出了一个HotJava的浏览器。)后来1995年5月23日正式推出JDK1

SUN(Standord University NetWork)公司是一家从事于硬件开发的公司。小型机(被广泛应用在amazon上)

最初的电子商务IBM提出来的。(任何经济模式都会有瓶颈)但是对于90到00年初的互联网低潮而言,这就是一个严重的伤害。

从最初到现在也出现了一些技术的不同发展:

  • java(J2SE,JAVA SE):提供底层,单机开发。
  • Java嵌入式开发(J2ME,JAVA ME)基本上被Android代替。
  • Java企业开发(J2EE,JAVA EE)。主要进行企业平台的搭建。

2021062209440261

Java主要特点

完全取决于Java的自身的技术特征。

  1. 是一个行业内通用的技术实现标准,半开源,使得厂商得以接触到Java的底层,使得Java开发更加透明;
  2. 是一门面向对象编程语言,使得Java语言语法结构更加方便开发,正在不断扩充(不同的JDK版本);
  3. 提供有方便的内存回收处理机制:Java提供自动的内存回收操作(优化);
  4. 避免了复杂的指针问题,而使用更加简单的引用来代替指针,通过引用来简化指针。
  5. Java是为数不多支持多线程的开发,使得单位时间内,处理的性能得到提升(性能的提升不是绝对的)。
  6. Java提供有高效的网络处理能力。
  7. Java具有良好的可移植性。
  8. Java语言足够简单。

Java可移植性

同一个程序可以在任意的操作环境部署。在Java里面如果向实现可移植性的控制。JAVAVM虚拟机是由软件和硬件模拟出来的计算机,所有的

程序只要有Java虚拟机的支持,系统上会有不同版本的JVM存在,这样就可以实现移植性

Java应用程序运行机制

计算机高级编程语言类型

  • 编译型
  • 解释型

Java是两种语言的结合:

编译命令:javac.exe

解释命令:Java.exe

image-20240105191346191

Java程序组成: Java源文件、字节码文件、机器码指令

image-20240105191500303

但是依然会存在有VM调优问题。

JDK

java的开发

Java数据类型划分

浮点型数据

1
2
3
4
5
6
7
public class JavaDemo {
public static void main(String args[]) {
double x = 10.2;
int y = 2;
System.out.println(x * y);
}
}

所有的数据类型进行自动转型的时候都是由小类型向大类型进行自动转化处理。默认类型为double,但是也可以定义位数相对较少的float变量,此时重新赋值的时候就必须要采用强制类型转换。

浮点型数据描述的是小数,而在Java里面任意一个数常量其对应的类型为double,所以在以后描述小数的时候都建议使用double来进行定义。

定义float

1
2
3
4
5
6
7
public class JavaDemo {
public static void main(String args[]) {
float x = (float)10.2;
float y = 10.3F;
System.out.println(x * y);
}
}

通过一系列的代码分析发现,整形是不包含有小数点的,而浮点型是包含有小数点的。

1
2
3
4
5
6
7
public class JavaDemo {
public static void main(String args[]) {
int x =10;
int y =4;
System.out.println(x / y);
}
}

计算结果为2整型不保存小数点。想要得到正确结果,需要强制类型转换。

1
2
3
4
5
6
7
public class JavaDemo {
public static void main(String args[]) {
int x =10;
int y =4;
System.out.println((double)x / y);
}
}

字符型数据

1.定义一个字符型变量

字符型使用的是char进行定义的,在Java之中使用单引号定义的内容就是一个字符。于是以下将研究如何去使用字符,例如定义一个字符型变量。

范例:定义一个字符型变量

1
2
3
4
5
6
7
8
9
10
11
public class JavaDemo {

public static void main(String args[]){

char c='B';/∥一个字符变量.

System.out.println(c);

}

}

现在程序直接输出一定是正常的字符B。

2.观察Char与int的关系

首先要明确在任何的编程语言之中,字符都可以与int进行互相转换,字符中所描述的内容可以通过int获取其内容对应的系统编码。最早的计算机搭造的只是010101,但是如果用01的数字(例如110 101 数字等)来描述,尽管简化了一些过程,但却很难理解的。

范例:观察char与int的关系

1
2
3
4
5
6
7
8
9
10
11
12
13
public class JavaDemo {

public static void main(String args[]) {

char c = 'A';//一个字符变量.

int num = c; //可以获得字符的编码

System.out.println(num);

}

}

代码编译执行之后,答案是65。

3.将小写字母变为大写字母

对于以上的程序获得了编码,这里面有几个范围需要注意:

1:“大写字母范围”:’A’(65)~’Z’(90);A编译执行的结果是65,Z编译执行的结果是90。

2:“小写字母范围”:’a’(97)~’z’(122);在程序中输入a编译执行的结果是97,z编译执行的结果是122。

3:“数字范围”:’0’(48)~’9’(57);在程序中要注意0跟’0’不是一个概念,前者是整数字,后者是字符,而字符是有编码的。在以上程序中输入0,编译执行结果是48。输入9,编译执行的结果是57。所以字符零和零完全是两个概念,单引号括起来的内容就是字符的数据

通过编码范围可以发现大小写字母之间差了32个数字的长度,于是就可以实现大小写的转换处理。程序如下:

范例:将小写字母变为大写字母

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class JavaDemo {

public static void main(String args[]) {

char c = 'x';//一个字符变量

int num = c;//可以获得字符的编码

num = num - 32;//让自己的内容减少32

System.out.println((char) num);

}

}

例如现在有小写字母x,想让他变成大写字母。就需要进行强制转型,将int变成字符。然后就做到了小写字母变成大写字母的转型。

4.保存中文数据

到此为止,所有的操作都与传统的c语言的方式是一样的,但是需要注意的是在java里面存在char的处理,char主要是进行中文的处理,所以Java中的char类型可以保存中文数据。

范例:保存中文数据

1
2
3
4
5
6
7
8
9
10
11
12
13
public class JavaDemo {

public static void main(String args[]) {

char c = '仁';//一个字符变量

int num = c; //可以获得字符的编码

System.out.println(num);

}

}

例如在程序中输入仁(字符就只有一个字),观察是否能够运行且是否能够保存。编译执行到结果为20161。20161这个值已经很大了。所以Java中是允许保存有中文的,char最大的优势也就在于中文处理。之所以在java语言里面可以使用char进行中文数据的保存,是因为java使用的是unicode这种十六进制的编码,这种编码的主要特点是可以包括任意的文字内容,所以使得程序开发更加的简单。

最初的时候,如果看到一篇文章非常的长,那么一般需要通过切来换行,但是切文字的时候就比较繁琐。一个字母占一个字节,一个字符占两个字节,如果按照字节的概念,字母的切跟中文的切是不一样的。字母会切得非常完整,但如果是中文,就可能把非常的非切成两半,于是造成了断码。还要去判断是否是正常值,如果是正常值就可以切,不是正常值就要往前找。所以如果有了java这种字符描述16进制的方式,存放中文的时候就会更加方便,这就是unicode的主要作用。

所有的操作方法适合于各种数据操作,就因为它的编码是统一的,所以在描述中文的时候,要使用cha r来描述。

布尔数据

布尔类型只有true和false

定义布尔型数据

1
2
3
4
5
6
7
8
9
10
11
public class JavaDemo {

public static void main(String args[]) {
boolean flag =true;
if(flag){
System.out.println("nb");
}

}

}

String字符串

一、String字符串简介

在任何语言里面都没有提供所谓的字符串这种数据,但是从实际的使用上来讲各个编程语言为了方便程序的开发,也都会提供有字符串的相应描述。在Java里面使用的是String作为字符串的定义。

由于String类的存在较为特殊,所以其可以像普通变量那样采用直接赋值的方式进行字符串的定义,并且要求使用“""”进行字符串描述。

定义字符串:

1
2
3
4
5
6
7
8
public class JavaDemo {

public static void main(String args[]) {
String str = "Hello World";
System.out.println(str);

}
}

但是需要考虑另外一点,此时对于“+”就有了两种描述:字符串的连接、数字的加法计算。

1
2
3
4
5
6
7
8
9
10
public class JavaDemo {

public static void main(String args[]) {
String str = "Hello";
str = str + "World";
str = str + "!!";
System.out.println(str);

}
}

在Java语言里面,数据范围大的数据类型与数据范围小的数据类型进行计算的时候,所有范围小的数据类型自动转型为范围大的数据类型,但是如果此时有String字符串了,则所有的类型无条件先变为String,如果有“+”表示的就是字符串连接。

在描述字符串的时候也可以使用转义字符进行一些处理,例如:TAB ( t)、”(")、’(')、换行、( \n)、(\)。

观察转义字符

1

Java运算符

简介

首先对于程序开发而言,里面会提供有大量的基础运算符,那么这些运算符也都会提供有各自的优先顺序,可是从正常的角度来讲,个人强烈不建议去记这些运算符优先级。

优先级 运算符 结合性
1 ()、[]、{} 从左向右
2 !、+、-、~、++、– 从右向左
3 *、/、% 从左向右
4 +、- 从左向右
5 «、»、>>> 从左向右
6 <、<=、>、>=、instanceof 从左向右
7 ==、!= 从左向右
8 & 从左向右
9 ^ 从左向右
10 | 从左向右
11 && 从左向右
12 || 从左向右
13 ?: 从右向左
14 =、+=、-=、*=、/=、&=、|=、^=、~=、«=、»=、>>>= 从右向左

数学运算符

在Java数学运算提供了标准的支持,包括四则运算都是支持的。

四则运算

简化运算符

求模

关系运算

进行大小的比较处理。

包括:(>)、小于(<)、大于等于(>=)、小于等于(<=)、不等(!=)、相等(==)。所有的关系运算返回的判断结果都是布尔类型的数据;

范例:做一个大小关系的判断。

三目运算符

关系运算?关系满足时的内容:关系不满足时的值

三目嵌套的可读性差。

位运算符

位运算指的是可以直接进行二进制的计算处理,主要有:与(&)、或(|)、异或(^)、反码(~)、移位处理。

控制流程

scanner键盘录入

1
2
3
4
5
6
7
8
9
10
11
12
13
1.概述:是java定义好的一个类
2.作用:将数据通过键盘录入的形式放到代码中参与运行
3.位置:java.util
4.使用:
a.导包:通过导包找到要使用的类 -> 导包位置:类上
import java.util.Scanner -> 导入的是哪个包下的哪个类

b.创建对象
Scanner 变量名 = new Scanner(System.in);

c.调用方法,实现键盘录入
变量名.nextInt() 输入整数int型的
变量名.next() 输入字符串 String型的

代码

1
2
3
4
5
6
7
8
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner a = new Scanner(System.in);
int Data1 = a.nextInt();
System.out.println(Data1);
}
}

next() nextLine

1
2
变量名.next():录入字符串 -> 遇到空格和回车就结束录入了
变量名.nextLine():录入字符串 -> 遇到回车就结束录入了

Random随机数

1
2
3
4
5
6
7
8
9
1.概述:java自带的一个类
2.作用:可以在指定的范围内随机一个整数
3.位置:java.util
4.使用:
a.导包:import java.util.Random
b.创建对象:
Random 变量名 = new Random()
c.调用方法,生成随机数:
变量名.nextInt() -> 在int的取值范围内随机一个整数
1
2
3
4
5
6
7
8
import java.util.Random;
public class Main {
public static void main(String[] args) {
Random rd = new Random();
int Data1 = rd.nextInt();
System.out.println(Data1);
}
}

在指定范围内随机一个数:
nextInt(int bound) -> 在0-(bound-1)

流程控制语句

switch

必须要先掌握定义格式,然后掌握执行流程(带一个数进去,根据执行流程观察值的变化)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
1.格式:
switch(变量){
case 常量值1:
执行语句1;
break;

case 常量值2:
执行语句2;
break;

case 常量值3:
执行语句3;
break;

case 常量值4:
执行语句4;
break;
...
default:
执行语句n;
break;
}

2.执行流程:
用变量接收的值和下面case后面的常量值匹配,匹配上哪个case就执行哪个case对应的执行语句
如果以上所有case都没有匹配上,就走default对应的执行语句n
3.break关键字:代表的是结束switch语句
4.注意:switch能匹配什么类型的数据:
byte short int char 枚举类型 String类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package xz;
import java.util.Scanner;

public class Demo {
public static void main(String args[]){
Scanner sc = new Scanner(System.in);
System.out.println("输入整数");
int data = sc.nextInt();
switch(data){
case 1:
break;
case 3:
System.out.println("nb");
break;
default:
System.out.println("6");
break;


}

}
}
case的穿透性

如果没有break,就会出现case的穿透性,程序就一直往下穿透执行,直到遇到了break或者switch代码执行完毕了,就停止了

if语句

第一种

1.格式:

1
2
3
if(boolean表达式){
执行语句;
}

2.执行流程:
先走if后面的boolean表达式,如果是true,就走if后面大括号中的执行语句,否则就不走
3.注意:
if后面跟的是boolean表达式,只要是结果为boolean型的,都可以放在小括号中,哪怕直接写一个true或者false

第二种

1.格式:

1
2
3
4
5
if(boolean表达式){
执行语句1;
}else{
执行语句2;
}

2.执行流程:
a.先走if后面的boolean表达式,如果是true,就走if后面的执行语句1
b.否则就走else后面的执行语句2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package xz;
import java.util.Scanner;
public class rg {
public static void main(String args[]){
System.out.println("输入一个整数");
Scanner sc = new Scanner(System.in);
int Data1 = sc.nextInt();
if (Data1%2==0){
System.out.println("偶数");
}
else{
System.out.println("奇数");
}
}
}

while循环

1
2
3
4
5
6
7
8
9
10
11
12
1.格式:
初始化变量;
while(比较){
循环语句;
步进表达式
}

2.执行流程:
a.初始化变量
b.比较,如果是true,就走循环语句,走步进表达式
c.再比较,如果还是true,继续走循环语句,继续走步进表达式
d.再比较,直到比较为false,循环结束
1
2
3
4
5
6
7
8
9
public  class Demo {
public static void main(String args[]){
int i = 0;
while(i<5){
System.out.println("Atlant1c");
i++;
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
public  class Demo {
public static void main(String args[]){
double mountain = 88444430;
double paper = 0.1;
int count = 0;
while(mountain > paper){
paper = paper*2;
count++;
}
System.out.println(count);
}
}

循环控制关键字

1
2
3
4
5
6
1.break:
a.在switch中代表结束switch语句
b.在循环中代表结束循环

2.continue:
结束当前本次循环,直接进入下一次循环,直到条件为false为止

数组

定义

1.问题:想将一个数据保存起来,我们可以使用变量,但是变量一次只能存储一个数据,所以我们想能不能一次存多个数据
2.数组概述:是一个容器,数组本身属于引用数据类型
3.作用:一次存储多个数据
4.特点:
a.既可以存储基本类型的数据,还能存储引用类型的数据
5.定义:
a.动态初始化:

1
2
数据类型[] 数组名 = new 数据类型[长度]
数据类型 数组名[] = new 数据类型[长度]
各部分解释:
  等号左边的数据类型:规定了数组中只能存储什么类型的元素
  []:代表的是数组,一个[]代表一维数组,两个[][]代表二维数组    
  数组名:自己取的名字,遵循小驼峰
  new:代表的是创建数组
  等号右边的数据类型:要和等号左边的数据类型一致
  [长度]:指定数组长度,规定了数组最多能存多少个数据    

b.静态初始化

image-20240203133159665

c.简化的静态初始化:

1
数据类型[] 数组名 = {元素1,元素2...}-> 推荐使用

6.区别:
a.动态初始化:定义的时候只指定了长度,没有存具体的数据
当只知道长度,但不知道具体存啥数据时可以使用动态初始化

b.静态初始化:定义的时候就直接知道存啥了

操作

获取长度

1.格式:
数组名.length
2.注意:
length后面不要带小括号,因为length不是一个方法,而是数组中的一个属性

1
2
3
4
5
6
7
8
9
package xz;

public class Array {
public static void main(String args[]){
int[] arr1 = {1,2,3,4,5};
int len = arr1.length;
System.out.println(len);
}
}

索引

1.概述:元素在数组中存储的位置
2.特点:
a.索引唯一
b.索引都是从0开始的,最大索引是数组长度-1
3.注意:
我们将来操作元素,必须通过索引来操作
存数据,要指定索引
取数据,要指定索引
查数据,要指定索引

存储元素

1.格式:
数组名[索引值] = 值 -> 将等号右边的值放到数组指定的索引位置上

获取元素

1.地址值:
数组在内存中的身份证号,唯一标识,我们可以通过这个唯一标识到内存中准确找到这个数,从而操作这个数组中的数据

2.注意:
a.直接输出数组名,会直接输出数组在内存中的地址值
b.如果数组中没有存元素,那么直接获取索引上对应的元素也是有值的,只不过不是我们存储的数据,而是数组中的元素默认值
整数: 0
小数: 0.0
字符: ‘\u0000’ -> 空白字符 -> 对应的int值是0
布尔: false
引用: null

遍历数组

1.遍历:将元素从数组中一个一个的获取出来

操作数组时两个常见的问题

1.数组索引越界异常_ArrayIndexOutOfBoundsException

1
2
1.原因:
操作的索引超出了数组索引范围了
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class Demo09Array {
public static void main(String[] args) {
int[] arr = new int[3];
arr[0] = 100;
arr[1] = 200;
arr[2] = 300;
//arr[3] = 400;//索引3超出了arr的索引范围

//arr[-1] = 1000;//索引3超出了arr的索引范围

for (int i = 0; i <= arr.length; i++) {
System.out.println(arr[i]);//索引3超出了arr的索引范围
}
}
}
2.空指针异常_NullPointerException
1
2
1.原因:
当一个对象为null时,再调用此对象中的其他成员
1
2
3
4
5
6
7
8
9
10
public class Array {
public static void main(String[] args) {

int[] arr = new int[3];
System.out.println(arr.length);//3
arr = null;
System.out.println(arr.length);//NullPointerException
}
}

内存图

1.内存:可以理解”内存条”,任何程序,软件运行起来都会在内存中运行,占用内存,在java的世界中,将内存分为了5大块
2.分为哪5大块
栈(重点)(Stack)
主要运行方法,方法的运行都会去栈内存中运行,运行完毕之后,需要”弹栈”,腾空间
堆(重点):(Heap)
每new一次,都会在堆内存中开辟空间,并为此空间自动分配一个地址值
堆中的数据都是有默认值的
整数:0
小数:0.0
字符: ‘\u0000’
布尔:false
引用:null
方法区(重点)(Method Area)
代码的”预备区”,记录了类的信息以及方法的信息

本地方法栈(了解):专门运行native方法(本地方法)
本地方法可以理解为对java功能的扩充
有很多功能java语言实现不了,所以就需要依靠本地方法完成

寄存器(了解) -> 跟CPU有关

image-20240118185242999

一个数组的内存图

image-20240118185310264

两个数组的内存图

我们创建了两个数组,在堆内存中开辟了两个不同的空间,此时修改一个数组中的元素不会影响到另外一个数组中的数据

image-20240118185335340

两个数组指向同一片内存空间

1
2
arr2不是new出来的,是arr1直接赋值的,arr1在内存中保存的是地址值,给了arr2,那么arr2的地址值和arr1就是一样的
所以此时arr1和arr2指向了堆内存中的同一片空间(同一个地址值,同一个数组),此时改变一个数组中的元素会影响到另外一个数组

image-20240118185940996

二维数组

1.概述:数组中的套多个数组
2.定义格式
a.动态初始化

1
2
3
数据类型[][] 数组名 = new 数据类型[m][n]
数据类型 数组名[][] = new 数据类型[m][n]
数据类型[] 数组名[] = new 数据类型[m][n]

m:代表的是二维数组的长度
n:代表的是二维数组中每一个一维数组的长度

数据类型[][] 数组名 = new 数据类型[m][] -> 二维数组中的一维数组没有被创建

b.静态初始化

1
2
3
数据类型[][] 数组名 = new 数据类型[][]{{元素1,元素2...},{元素1,元素2...},{元素1,元素2...}}
数据类型 数组名[][] = new 数据类型[][]{{元素1,元素2...},{元素1,元素2...},{元素1,元素2...}}
数据类型[] 数组名[] = new 数据类型[][]{{元素1,元素2...},{元素1,元素2...},{元素1,元素2...}}

c.简化静态初始化:

1
2
3
数据类型[][] 数组名 = {{元素1,元素2...},{元素1,元素2...},{元素1,元素2...}}
数据类型 数组名[][] = {{元素1,元素2...},{元素1,元素2...},{元素1,元素2...}}
数据类型[] 数组名[] = {{元素1,元素2...},{元素1,元素2...},{元素1,元素2...}}

数组常见算法

数组翻转

数组对称索引位置上的元素互换

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package packaging;

public class Test01 {
public static void main(String[] args){
int[] arr = {1,2,3,4,5,6,7};
for(int min=0,max=arr.length-1;min<max;min++,max--){
int temp = arr[min];
arr[min] = arr[max];
arr[max] = temp;
}
for(int i=0;i<arr.length;i++){
System.out.print(arr[i]);
}
}

}

冒泡排序

比较相邻的元素。如果第一个比第二个大,就交换他们两个。

对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数。

针对所有的元素重复以上的步骤,除了最后一个,即需要进行length-1次。

第一次是对n个数进行n-1次比较,进行到最后第n个的一个是最大的;

第二次是对n-1个数进行n-2次比较,进行到最后第n-1个的一个是最大的;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package Aarithmetic;

public class bubble {
public static void main(String args[]){
int arr[]= {3,2,6,4,5,8};
//冒泡算法
for(int i=0;i<arr.length-1;i++){
for(int j=0;j<arr.length-1-i;j++){
if(arr[i]>arr[i+1]){
int temp =arr[i];
arr[i] = arr[i+1];
arr[i+1] = temp;
}
}
}
for(int i=0;i<arr.length;i++){
System.out.print(arr[i]);
}
}
}

二分查找

前提:数组中的数据必须是有序的
查询思想:
a.老式查询:遍历数组,一个一个比较 -> 查询效率慢
b.二分查找:每次找中间索引对应的元素进行比较查询(每一次查询少一半数据)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package Aarithmetic;

public class Binary {
public static void main(String[] args) {
int[] arr = {1,2,3,4,5,6,7,18,9};
int index = binary(arr, 18);
System.out.println(index+1);
}

public static int binary(int[] arr,int data){
//定义三个变量,分别代表最大索引,最小索引,中间索引
int min = 0;
int max = arr.length-1;
int mid = 0;
//查找
while(min<=max){
mid = (min+max)/2;
if (data>arr[mid]){
min = mid+1;
}else if(data<arr[mid]){
max = mid-1;
}else{
return mid;
}
}

return -1;
}
}

方法的使用

之前所有的代码都在main方法中写,如果我们将来将所有功能的代码都放到main方法中,会显得main方法代码太多,太乱,太臃肿不好维护
解决:将不同功能的代码放到不同的方法中,想执行某个功能,直接调用方法名就行了,对应的代码就自动执行起来了
将来维护的时候,直接找到对应的方法,就可以对其直接修改维护

方法:

拥有功能性代码的代码块
将不同的功能放在不同的方法中,给每个方法取个名字,直接调用方法名,对应的方法就执行起来了,好维护
3.通用定义格式:

1
2
3
4
修饰符 返回值类型 方法名(参数){
方法体
return 结果
}

4.通过通用格式,分成四种方法来学习:
a.无参无返回值方法
b.有参无返回值方法
c.无参有返回值方法
d.有参有返回值方法

无参无返回值方法:

定义

1
2
3
4
public static void 方法名(){
方法体 -> 实现此方法的具体代码

}

调用:直接调用。在其他方法中: 方法名()

注意事项:

  • void关键字代表无返回值,写了void,就不要在方法中写return结果
  • 方法不调用不执行, main方法是jvm调用的
  • 方法之间不能互相嵌套,方法之间是平级关系
  • 方法的执行顺序只和调用顺序有关

有参数无返回值的方法

格式:

1
2
3
public static void 方法名(数据类型 变量名){
方法体
}

调用:
直接调用:方法名(具体的值) -> 调用的时候要给参数赋值

无参数有返回值

格式:

1
2
3
4
public static 返回值类型 方法名(){
方法体
return 结果
}

调用: 返回值返回给了谁? 哪里调用返回给哪里
a.打印调用:sout(方法名()) -> 不推荐使用
b.赋值调用:调用完之后用一个变量接收返回值结果 -> 极力推荐
数据类型 变量名 = 方法名()

有参数有返回值

格式:
public static 返回值类型 方法名(参数){
方法体
return 结果
}

调用:
a.打印调用:
sout(方法名(具体的值))
b.赋值调用(极力推荐)
数据类型 变量名 = 方法名(具体的值)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package Method;
import java.util.Scanner;
public class Method {
public static void main(String args[]) {
Scanner a =new Scanner(System.in);
Scanner b =new Scanner(System.in);
int result = sum(a,b);
System.out.println(result);
}
public static int sum(Scanner a, Scanner b){
int A=a.nextInt();
int B=b.nextInt();
int sum = A+B;
return sum;
}
}

形式参数和实际参数区别

1.形式参数(形参):在定义方法的时候形式上定义的参数,此参数还没有值
2.实际参数(实参):在调用方法的时候给形参赋予的具体的值

参数和返回值使用的时机

1.参数:
当想将方法A的数据传递到方法B时,那么定义方法B时就需要带个参数,在方法A中调用方法B时,可以将方法A中的数据通过参数传递到方法B中
2.返回值:
调用方法A时,想要方法A的结果,去参与其他的操作,那么方法A就需要将自己的结果返回

方法注意事项

  1. 方法不调用不执行
  2. 方法的执行顺序只和调用顺序有关
  3. 方法之间不能互相嵌套
  4. void不能和[return 结果]共存,但是void能和[return]共存
    a.void:代表没有返回值
    b.return 结果:就代表有返回值了
    先将结果返回,然后结束方法
    c.return:仅仅代表结束方法,不代表有返回值
  5. 一个方法中不能连续写多个return(也就是说一个方法不能都多个返回值)
  6. 调用方法的时候要看看下面有没有这个方法,没有的方法直接调用会报错

方法的重载

方法名相同,参数列表不同的方法

参数列表不同:
a.参数个数不同
b.参数类型不同
c.参数类型顺序不同

多个不同但功能相似的方法所以同一个方法名,根据传递的参数来确定调用了哪个方法。

注意

判断两个方法是否为重载方法,和什么无关:
a.和参数名无关
b.和返回值无关

面向对象

面向对象的介绍

我们只需要直接拿过来使用即可,简化了我们自己的编写过程,减少了我们的代码量

什么时候使用面向对象思想编程:

  • 调用别人的功能时
  • 在一个类中想使用别的类中的成员时,就使用面向对象思想编程
  • 至于我们使用的功能人家怎么实现的,我们不需要关心,我们只需要知道怎么使用即可
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package Object;

import xz.Array;

import java.util.Arrays;
import java.util.Random;
import java.util.Scanner;

public class Test {
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
String Data = sc.next();
System.out.println(Data);

Random rd = new Random();
int mb = rd.nextInt(10);
System.out.print(mb);

int ar[]={4,5,7,8};
System.out.print(Arrays.toString(ar));
}

}

类和对象

1.测试类:带main方法的类,主要是运行代码的
2.实体类:是一类事物的抽象表示形式
世间万物的分类:比如: 人类 狗类 猫类 鼠标类

组成部分:
1.属性(成员变量):这一类事物有啥
a.定义位置:类中方法外
b.作用范围:作用于当前类
c.定义格式: 数据类型 变量名
d.默认值:
整数:0
小数:0.0
字符:’\u0000’
布尔:false
引用:null
2.行为(成员方法):这一类事物都能干啥
只需要将模块六所学的方法中的static干掉,其他的都一样

对象

Java创建对象的方法(5种)_创建一个对象java-CSDN博客

1.概述:一类事物的具体体现
2.使用:
a.导包: import 包名.类名
如果两个类在同一个包下,想要使用对方的成员不需要导包
如果两个类不在同一个包下,想要使用对方的成员需要导包

特殊包:java.lang -> 使用lang包下的类不需要导包 -> String
    
友情提示:在学四种权限修饰符之前,尽量让两个类在同一个包下

b.创建对象:想要使用哪个类中的成员,就new哪个类的对象
类名 对象名 = new 类名() -> 比如: Person person = new Person()
c.调用成员(成员变量,成员方法) -> 想要使用哪个类中的成员,就用哪个类的对象去点哪个成员
对象名.成员变量名 = 值
对象名.方法名() -> 调用的是无参无返回值方法
对象名.方法名(实参) -> 调用的是有参无返回值方法
数据类型 变量名 = 对象名.方法名() -> 调用的是无参有返回值方法
数据类型 变量名 = 对象名.方法名(实参) -> 调用的是有参有返回值方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package Object;

public class volant {
public static void main(String[] args){
sage sage = new sage();
sage.kind = "ak";
sage.price = 2900;

System.out.println(sage.kind);
System.out.println(sage.price);

sage.rl("omen");
String hf = sage.zl();
System.out.println(hf);
}


}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
package Object;

public class sage {
String kind;
int price;

public void rl(String name) {
System.out.println("给" + name + "复活");
}

public String zl() {
return "恢复到100exp";
}
}
匿名对象的使用

1.所谓的匿名对象:其实就是没有等号左边的部分,只有等号右边的部分(对象)
2.使用:

1
new 对象().成员

3.注意:
a.如果我们只想单纯的调用一个方法,让方法执行,我们可以考虑使用匿名对象
b.但是如果涉及到赋值,千万不要用匿名对象

image-20240122142704839

1
2
3
4
5
6
7
8
9
10
11
12
13
package Object;

public class volant {
public static void main(String[] args){
new sage().kind = "ak";
new sage().price = 2900;

System.out.println(new sage().kind);
System.out.println(new sage().price);
}


}

成员变量和局部变量的区别

1.定义位置不同(重点)
a.成员变量:类中方法外
b.局部变量:定义在方法之中或者参数位置
2.初始化值不同(重点)
a.成员变量:有默认值的,所以不用先手动赋值,就可以直接使用
b.局部变量:是没有默认值的,所以需要先手动赋值,再使用
3.作用范围不同(重点)
a.成员变量:作用于整个类
b.局部变量:只作用于自己所在的方法,其他方法使用不了
4.内存位置不同(了解)
a.成员变量:在堆中,跟着对象走
b.局部变量:在栈中,跟着方法走

5.生命周期不同(了解)
a.成员变量:随着对象的创建而产生,随着对象的消失而消失
b.局部变量:随着方法的调用而产生,随着方法的调用完毕而消失

封装

将一个物品封装起来,外界不能直接使用了,提高了物品的安全性

介绍

1.面向对象三大特征: [封装] 继承 多态

隐藏对象内部的复杂性,只对外提供公开,公共的接口,便于外界调用,从而提高了系统的可扩展性,可维护性,安全性,通俗来说,把该隐藏的隐藏起来(细节),把该暴露的暴露出来(对外提供的供别人使用的接口),这就是封装思想

a.关键字:private(私有化的) -> 被private修饰的成员只能在本类中使用,在别的类中使用不了
b.注意:
将代码放到一个方法中,也是封装的体现
一个成员被private修饰也是封装的体现,只不过private最具代表性
c.private的使用:
修饰成员变量:private 数据类型 变量名
修饰方法:将public改成private,其他的都一样
2.问题:属性被私有化了,外界直接调用不了了,那么此时属性就不能直接赋值取值了,所以需要提供公共的接口
get/set方法

  set方法:为属性赋值
  get方法:获取属性值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package packaging;

public class Test01 {
public static void main(String[] args) {
Person person = new Person();
//person.name = "涛哥";
//person.age = -18;

//System.out.println(person.name);
//System.out.println(person.age);

person.setName("涛哥");
person.setAge(18);

String name = person.getName();
int age = person.getAge();
System.out.println(name+"..."+age);
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package packaging;

public class Person {
private String name;
private int age;
//为name提供get/set方法
public void setName(String xingMing){
name = xingMing;
}
public String getName(){
return name;
}
//为age提供get/set方法
public void setAge(int nianLing){
if(nianLing<0 || nianLing>150){
System.out.println("hmp?");
}
else{
age =nianLing;}
}
public int getAge(){
return age;
}
}

由这个例子可以看出来内部的xingMing和nianLing不会在调用时被知道,类内部进行操作的变量。

用private将属性封装起来,外界不能直接调用,保护了属性。对外提供一套公共的接口(set/get方法),让外界通过公共的接口间接使用封装起来的属性

this

介绍

1.如果成员变量和局部变量重名时,我们遵循”就近原则”,先访问局部变量
2.this概述:代表的是当前对象
3.作用:this可以区分重名的成员变量和局部变量
this点出来的一定是成员的变量
4.this代表当前对象,那么具体代表哪个对象呢?
哪个对象调用的this所在的方法,this就代表哪个对象

无参构造与有参构造

1.概述:方法名和类名一致并且能初始化对象的方法
2.分类:
a.无参构造:没有参数
b.有参构造:有参数,参数是为指定的属性赋值
c.满参构造:给所有属性赋值
以上构造咱们不用记那么详细,我们就记有参和无参构造就可以了
3.特点:
a.方法名和类名一致
b.没有返回值,连void都没有

空参构造

1.格式:
public 类名(){

}
2.作用:
new对象使用
3.特点:
每个类中默认都有一个无参构造,不写也有,jvm会自动提供
4.使用:一new对象就是在调用构造方法

有参构造

1.格式:
public 类名(形参){
为属性赋值
}

2.作用:
a.new对象
b.为属性赋值
3.特点:
jvm不会自动提供有参构造,但是将有参构造手写出来,jvm将不再提供无参构造,所以建议有参,无参的构造都手写上去

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package packaging;

public class Person {
private String name;
private int age;
public Person(){
System.out.println("无参构造");
}
public Person(String name,int age){
this.name=name;
this.age=age;
}
public void setName(String name){
this.name=name;
}
public String getName(){
return name;
}
public void setAge(int age){
this.age=age;
}
public int getAge(){
return age;
}
}
1
2
3
4
5
6
7
8
9
10
package packaging;

public class Test01 {
public static void main(String[] args) {
Person person = new Person();
Person person2 = new Person("atlantic",19);
System.out.println(person2.getName()+person2.getAge());
}
}

标准JavaBean

JavaBean 是 Java语言编写类的一种标准规范。符合JavaBean` 的类,要求:

(1)类必须是具体的(非抽象 abstract)和公共的,public class 类名

(2)并且具有无参数的构造方法,有参构造

(3)成员变量私有化,并提供用来操作成员变量的setget 方法。

1
2
3
4
5
com.atguigu.controller -> 专门放和页面打交道的类(表现层)
com.atguigu.service -> 专门放业务处理的类 (业务层)
com.atguigu.dao -> 专门放和数据库打交道的类(持久层)
com.atguigu.pojo -> 专门放javabean类
com.atguigu.utils -> 专门放工具类

将来的javabean都是和数据库的表相关联
a.类名 -> 表名
b.属性名 -> 列名
c.对象 -> 表中每一行数据
d.属性值 -> 表中单元格中的数据

static关键字

introduce

概述:static是一个静态关键字

使用:

1.修饰一个成员变量

1
static 数据类型 变量名

2.修饰一个方法

1
2
3
4
修饰符 static 返回值类型 方法名(形参){
方法体;
return 结果;
}

调用静态成员:类名直接调用

静态成员的特点:

  • 静态成员属于类成员,不属于对象成员
  • 静态成员会随着类的加载而加载
  • 静态成员优先于非静态成员在内存中
  • 凡是根据静态成员所在的类创建出来的对象,都可以共享这个静态成员
static修饰成员的访问特点
  • 在静态方法中不能直接访问非静态成员,想要调用需要new对象调用。
  • 在静态/非静态方法访问静态成员。同类直接调用,类名调用;不同类需要使用类名调用。
  • 在非静态方法调用非静态成员,只有在同类才能直接调用,同类也可以new调用。但是不同类只能new调用。

可变参数

1.需求:
定义一个方法,实现n个整数相加
2.分析:
方法参数位置,只明确了参数的类型,但是不明确参数个数,此时就可以定义成可变参数

递归

在方法内再调用本方法

对象数组

将对象的标签存放到数组里

方法参数

基本数据类型:整型,浮点型,字符型,布尔型。

基本数据类型当作实参传递,传递的是数值而不是变量本身。

引用数据类型做方法参数传递时,传递的是地址值。

命令行参数

在执行java的.class文件是在cmd添加参数。

继承

保姆级教程,彻底搞懂Java继承的五种用法-阿里云开发者社区 (aliyun.com)

继承是java面向对象编程技术的一块基石,因为它允许创建分等级层次的类。
继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为。

继承关键字

关键字extends

表示对父类的继承,可以实现父类,也可以调用父类初始化。而且会覆盖父类定义的变量或者函数。在 Java 中,类的继承是单一继承,也就是说,一个子类只能拥有一个父类,所以 extends 只能继承一个类。
类的继承格式

1
2
3
4
5
class 父类 {
}

class 子类 extends 父类 {
}

继承可以使用 extends 和 implements 这两个关键字来实现继承,而且所有的类都是继承于 java.lang.Object,当一个类没有继承的两个关键字,则默认继承 Object(这个类在 java.lang 包中,所以不需要 import)祖先类。

关键字implements

是一个类,实现一个接口用的关键字,它是用来实现接口中定义的抽象方法。实现一个接口,必须实现接口中的所有方法。使用 implements 关键字可以变相的使java具有多继承的特性,使用范围为类继承接口的情况,可以同时继承多个接口(接口跟接口之间采用逗号分隔)
还有几点需要注意:
(1)接口可以被多重实现(implements),抽象类只能被单一继承(extends)
(2)接口只有定义,抽象类可以有定义和实现
(3)接口的字段定义默认为:public static final, 抽象类字段默认是”friendly”(本包可见)

1
2
3
4
5
6
7
8
9
10
11
public interface A {
public void eat();
public void sleep();
}

public interface B {
public void show();
}

public class C implements A,B {
}
super 与 this 关键字

super关键字:我们可以通过super关键字来实现对父类成员的访问,用来引用当前对象的父类。

this关键字:指向自己的引用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package Inherit;


class Animal {
void eat() {
System.out.println("animal : eat");
}
}

class Dog extends Animal {
void eat() {
System.out.println("dog : eat");
}
void eatTest() {
this.eat(); // this 调用自己的方法
super.eat(); // super 调用父类方法
}
}

public class superAndThis {
public static void main(String[] args) {
Animal a = new Animal();
a.eat();
Dog d = new Dog();
d.eatTest();
}
}


image-20240203173116025

final 关键字

final 可以用来修饰变量(包括类属性、对象属性、局部变量和形参)、方法(包括类方法和对象方法)和类。

final 含义为 “最终的”。

使用 final 关键字声明类,就是把类定义定义为最终类,不能被继承,或者用于修饰方法,该方法不能被子类重写:

  • 声明类:

    1
    final class 类名 {//类体}
  • 声明方法:

    1
    修饰符(public/private/default/protected) final 返回值类型 方法名(){//方法体}

注: final 定义的类,其中的属性、方法不是 final 的。

继承的特性

  • 子类拥有父类非 private 的属性、方法。

  • 子类可以拥有自己的属性和方法,即子类可以对父类进行扩展。

  • 子类可以用自己的方式实现父类的方法。

  • Java 的继承是单继承,但是可以多重继承,单继承就是一个子类只能继承一个父类,多重继承就是,例如 B 类继承 A 类,C 类继承 B类,所以按照关系就是 B 类是 C 类的父类,A 类是 B 类的父类,这是 Java 继承区别于 C++ 继承的一个特性。

  • 提高了类之间的耦合性(继承的缺点,耦合度高就会造成代码之间的联系越紧密,代码独立性越差)。

构造器

继承结构中,父类的构造器只能够被调用,而不能被子类继承。 调用父类的构造方法要在子类的构造器中使用super()。

“对于子类,其构造器的正确初始化是非常重要的,而且当且仅当只有一个方法可以保证这点:在构造器中调用父类构造器来完成初始化,而父类构造器具有执行父类初始化所需要的所有知识和能力。”

正常情况下,子类会默认自动调用父类的构造器(无参的,不管是自己手动写的的还是系统自动新建的),但是如果父类没有无参构造器,子类必须要显式地调用父类的带参构造器,而且必须是在子类构造器中做的第一件事(第一行代码)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
class SuperClass {
private int n;
SuperClass(){
System.out.println("SuperClass()");
}
SuperClass(int n) {
System.out.println("SuperClass(int n)");
this.n = n;
}
}
// SubClass 类继承
class SubClass extends SuperClass{
private int n;

SubClass(){ // 自动调用父类的无参数构造器
System.out.println("SubClass");
}

public SubClass(int n){
super(300); // 调用父类中带有参数的构造器
System.out.println("SubClass(int n):"+n);
this.n = n;
}
}
// SubClass2 类继承
class SubClass2 extends SuperClass{
private int n;

SubClass2(){
super(300); // 调用父类中带有参数的构造器
System.out.println("SubClass2");
}

public SubClass2(int n){ // 自动调用父类的无参数构造器
System.out.println("SubClass2(int n):"+n);
this.n = n;
}
}
public class TestSuperSub{
public static void main (String args[]){
System.out.println("------SubClass 类继承------");
SubClass sc1 = new SubClass();
SubClass sc2 = new SubClass(100);
System.out.println("------SubClass2 类继承------");
SubClass2 sc3 = new SubClass2();
SubClass2 sc4 = new SubClass2(200);
}
}

多态

多态是同一个行为具有多个不同表现形式或形态的能力。

多态的优点

  • 消除类型之间的耦合关系
  • 可替换性
  • 可扩充性
  • 接口性
  • 灵活性
  • 简化性

多态存在的三个必要条件

  • 继承
  • 重写
  • 父类引用指向子类对象:**Parent p = new Child();**
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package polymorphism;


class Animal {
void makeSound() {
System.out.println("Animal makes a sound.");
}
}

class Dog extends Animal {
@Override
void makeSound() {
System.out.println("Dog barks.");
}
}

class Cat extends Animal {
@Override
void makeSound() {
System.out.println("Cat meows.");
}
}
public class Test{
public static void main(String[] args) {
Animal animal1 = new Dog();
Animal animal2 = new Cat();
animal1.makeSound(); // 输出 "Dog barks."
animal2.makeSound(); // 输出 "Cat meows."
}
}

instanceof 运算符

在某些情况下,我们需要在运行时检查对象的类型,以便根据对象的类型采取不同的行动。这时可以使用 instanceof 运算符。

instanceof 运算符用于检查一个对象是否是特定类的实例,或者是否是其子类的实例。它的语法如下:

1
object instanceof Class

如果 objectClass 类的一个实例,或者是 Class 类的子类的一个实例,instanceof 运算符返回 true,否则返回 false

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
class Animal {
void makeSound() {
System.out.println("Animal makes a sound.");
}
}

class Dog extends Animal {
@Override
void makeSound() {
System.out.println("Dog barks.");
}
}

class Cat extends Animal {
@Override
void makeSound() {
System.out.println("Cat meows.");
}
}

public class Main {
public static void main(String[] args) {
Animal animal1 = new Dog();
Animal animal2 = new Cat();

if (animal1 instanceof Dog) {
System.out.println("animal1 is a Dog.");
}

if (animal2 instanceof Cat) {
System.out.println("animal2 is a Cat.");
}
}
}

接口

JAVA基础——接口(全网最详细教程)_java接口怎么写-CSDN博客

接口(英文:Interface),在JAVA编程语言中是一个抽象类型,是抽象方法的集合,接口通常以interface来声明。一个类通过继承接口的方式,从而来继承接口的抽象方法。

接口并不是类,编写接口的方式和类很相似,但是它们属于不同的概念。类描述对象的属性和方法。接口则包含类要实现的方法。

除非实现接口的类是抽象类,否则该类要定义接口中的所有方法。

接口无法被实例化,但是可以被实现。一个实现接口的类,必须实现接口内所描述的所有方法,否则就必须声明为抽象类。另外,在 Java 中,接口类型可用来声明一个变量,他们可以成为一个空指针,或是被绑定在一个以此接口实现的对象。

为什么要用接口
  • 接口被用来描述一种抽象。
  • 因为Java不像C++一样支持多继承,所以Java可以通过实现接口来弥补这个局限。
  • 接口也被用来实现解耦。
  • 接口被用来实现抽象,而抽象类也被用来实现抽象,为什么一定要用接口呢?接口和抽象类之间又有什么区别呢?原因是抽象类内部可能包含非final的变量,但是在接口中存在的变量一定是final,public,static的。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package Interface;

interface in1{
final int a =10;
void display();
}
class testClass implements in1{
public void display(){
System.out.println("hello");
}
}
public class Test {
public static void main(String[] args){
testClass test1 = new testClass();
test1.display();
System.out.println(test1.a);
}
}

image-20240204122042026

接口的标识用法

​ 虽然接口内部定义了一些抽象方法,但是并不是所有的接口内部都必须要有方法,比如Seriallizable接口,Seriallizable接口的作用是使对象能够“序列化”,但是Seriallizable接口中却没有任何内容,也就是说,如果有一个类需要实现“序列化”的功能,则这个类必须去实现Seriallizable接口,但是却并不用实现方法(因为接口中没有方法),此时,这个Serilizable接口就仅仅是一个“标识”接口,是用来标志一个类的,标志这个类具有这个“序列化”功能。