狂神说Java(基础版)
Java基础01:注释
创建项目
首先创建一个空项目
命名注意不能有中文

但是一个空项目里面我们右键连新的类都不能创建

于是我们就要新建一个模块(Moudle)

选中java然后一路next,记得命名

创建完成之后就可以看到我们熟悉的src文件夹

解释一下为什么要这么创建项目
IDEA 项目架构解析
核心概念:Project vs Module
Code
Project (项目)
├── Module 1 (模块1)
│ ├── src/
│ ├── pom.xml / build.gradle
│ └── Module 1.iml
├── Module 2 (模块2)
│ ├── src/
│ └── Module 2.iml
└── .idea/
└── 项目配置文件
一、为什么需要 Module?
IDEA 的设计理念
IntelliJ IDEA 采用的是 "Project → Module" 两级结构:
- Project(项目):
- 最顶层的容器
- 相当于一个"工作空间"
- 包含全局配置(JDK、代码风格、版本控制等)
- 本身不直接包含代码
- Module(模块):
- 实际的代码单元
- 每个模块可以有独立的:
- 源代码目录(src)
- 依赖管理(pom.xml / build.gradle)
- 输出目录(out / target)
- JDK 版本
- 框架支持
二、为什么这样设计?
1. 支持大型项目的模块化开发
真实场景示例:
Code
电商系统项目(Project)
├── user-service(用户服务模块)
├── order-service(订单服务模块)
├── payment-service(支付服务模块)
├── common(公共模块)
└── admin(后台管理模块)
优势:
- 每个模块独立开发、测试、部署
- 模块间可以相互依赖
- 便于团队协作(不同人负责不同模块)
2. 与其他 IDE 的对比
| IDE | 架构模式 |
|---|---|
| Eclipse | Workspace → Project(工作空间 → 项目) |
| IntelliJ IDEA | Project → Module(项目 → 模块) |
| VS Code | Workspace / Folder(工作空间 / 文件夹) |
IDEA 的特点:
- Eclipse 的 Project = IDEA 的 Module
- Eclipse 的 Workspace = IDEA 的 Project
- IDEA 更适合大型、多模块项目
从这里继续学习
在这里查看项目结构

正常情况下这里sdk的设置会爆红因为你没有设置java环境,本机配置好了java环境直接选环境就好

在src里面新建一个类

在里面输入Hello World然后运行,成功代表环境搭建完毕

接下来正式讲注释

单行注释,两个斜杠"//"

多行注释 /注释内容/

文档注释 /** / 文档注释里面每一行的最前面都有一个,这个*符号可以加参数,@后面加的参数是有作用的,可以标示出一些内容,这些注释结合JavaDoc来使用

在设置里面改注释的颜色

Java基础02:标识符和关键字
注意:命名的时候不可以用关键字

在这个里面,HelloWorld是类名,main指的是方法名


以下是代码示例

特别提醒java中标识符是大小写敏感的

Java中是可以用中文给标识符命名的


Java基础03:数据类型讲解
强类型语言要求变量的使用要严格符合规定,所有变量都必须先定义后才能使用,安全性高,但是速度就会比较慢
弱类型语言对于变量的要求就没有那么严格,比如说'12'+3,这个运算可以有两种结果,可以是123,也可以是"123",但是其实这两者有很大区别,会存在漏洞。

Java中的基本数据类型按容量大小(精度)从高到低排序如下:
double > float > long > int > short > byte
需要注意的是,char 类型在运算时可以被转换为 int 类型。在进行混合运算时,容量小的数据类型会自动转换为容量大的数据类型
1. 自动类型转换(隐式转换)
当容量小的数据类型与容量大的数据类型进行运算时,容量小的数据类型会自动转换为容量大的数据类型。这称为自动类型转换。
数据类型容量大小排序为: byte, short, char -> int -> long -> float -> double
特别注意: 当 byte, short, char 这三种类型进行运算时,无论操作数是什么类型,它们都会首先被提升为 int 类型。
System.out.println(a+b+c+d); 因为 a 是 long 类型,是所有变量中容量最大的,所以其他变量 (b, c, d) 都会被转换为 long 类型进行计算,最终结果也是 long 类型。
System.out.println(b+c+d); 因为 b 是 int 类型,是这三个变量中容量最大的,所以 c 和 d 会被转换为 int 类型进行计算,最终结果是 int 类型。
System.out.println(c+d); 根据特殊规则,short 类型的 c 和 byte 类型的 d 在运算时都会被提升为 int 类型,所以结果是 int 类型
long a = 123312321313123L;
int b = 123;
short c = 10;
byte d = 8;
System.out.println(a+b+c+d);//Long
System.out.println(b+c+d);//Int
System.out.println(c+d);//Int
.2.强制类型转换(显式转换)
当需要将容量大的数据类型转换为容量小的数据类型时,必须使用强制类型转换。
语法: (目标类型)变量名;
强制类型转换可能会导致精度降低或数据溢出,需要谨慎使用
代码示例,如果a没有初始化的话输出不了,必须要赋值。

数据类型又错了,我用String定义的a变量但是赋值int类型的10报错了

整数类型包括byte short int long 浮点类型(小数)float double 字符类型 char 布尔类型true false

代码示例 byte最大只能到128,如果赋值200就会报错,

long类型要在数字后面加上L

float类型要在小数后面加上F,不然会报错识别成double

char类型的变量只能容下一个字符

要想在idea里面查看int类型的大小范围,输入Integer,将鼠标光标放在上面以后Ctrl+鼠标左键就可以进入源码

进入源码Integer.java就可以查看范围了

科普一下字节是什么

32位的操作系统只能用32位的cpu,但是64位的操作系统既可以用32位的又可以用64位的cpu,两者区别在于寻址能力,64位操作系统可以带128GB内存,32位操作系统可以带4GB内存。
Java基础04:数据类型扩展及面试题讲解
整数拓展就讲了点十进制和八进制和十六进制转换没什么意思


浮点数拓展这里,我们经过调试发现f和d都是0.1

但是运行代码输出f==d(强等于表示数值和类型都要一样)是false

很神奇,为什么d2是d1+1但是电脑判断两者是相同的


原因就是float类型是有限的,离散的,较大的数字会存在舍入误差,大约接近但不等于,所以以后最好完全不要使用浮点数进行比较,会存在误差,后面会有有个叫BigDecimal数学工具类使用

字符拓展:强制转换char类型为int类型,发现输出为数字,引出概念所有的字符本质都是数字


Unicode编码表,可以处理各种语言的文字,占两个字节,最多可以表示65536字符。最早的excel表格只有2的16次方长也就是65536,所以说其实本质上来说我们定义的"a"和"中"都是数字,不过是通过char类型变成了字符而已,unicode表上a对于97 中对应20013
下图中输出转义字符\u也就是unicode编码,后面接的是十六进制0061也就是十进制97,对应就是字母"a"


转义字符 \t制表符 \n换行符


布尔值拓展,因为if(flag==true)和if(flag)等价但是后者更加简洁一点所以熟练了一般写后面那种

Java基础05:类型转换
long64位但是在float32位的后面是因为小数的优先级大一些

赋值也属于运算,由于byte和int类型不同所以赋值前也需要先进行类型转换

转换完以后再输出两者的值,发现b的值为-128,这是因为byte的最大值为127,赋值128就会造成内存溢出,溢出后为多少值这个是不清楚的


以上就是强制转换 (类型)变量名 --高到低


自动转换 --低到高



将高容量的double和float转换成int,看看是否存在精度问题
注:强制转换直接舍弃小数部分,不会四舍五入


char类型转int类型属于自动转换(低转高)


先计算后赋值原则,total1也溢出的原因就是money和years变量为int,计算后已经出错,再赋值的话哪怕total为long类型也是错误结果,total2不溢出是因为事先将years或者money类型转换为long,将计算中的任一变量类型转换即可。


提一嘴:L和l都能表示long类型
Java基础06:变量、常量、作用域

变量可以看做内存里面的一个空间,只是里面要放什么东西我们还不知道。
我们可以将内存比作衣柜,但是我们指定内存分了三个部分分为衣服、鞋子、内衣,就像定义变量的数据类型一样,衣服里面有不同的衣服,我们命名为衣服1、衣服2、衣服3,
就像定义变量名一样。

类变量就是写在类里面的,实例变量就是可以写在方法的外面类的里面,局部变量就是写在方法里面的。
类变量需要加个关键词static,静态的。

局部变量
局部变量的寿命就在这方法的花括号里

你看,在其他方法里面就无法识别main方法里面的i。

局部变量必须声明和初始化值

实例变量
接下来讲解实例变量,实例变量是从属于类的,我们利用类新建对象,对象的属性即实例变量(这里可能理解有点误差,学完对象再来看)。我们输出实例变量即对象属性的时候如果不进行初始化的话就会自动使用这个变量类型的初始值
常见初始值:整数型0,小数型0.0 字符串\u0000也就是0 布尔值默认是false
除了基本类型,其余的默认值都是null;



类变量
和实例变量差不多,也是从属于类,而且定义用static,且与类同生共死,类消失了他也就消失了
常量

static作为修饰符不存在先后顺序,这里是定义了一个类常量

变量命名规范
类成员变量:除了第一个单词首字母小写,后面的单词首字母都要大写,比如姓 lastName
局部变量:首字母小写加驼峰原则
常量:大写字母以及下划线
类名:首字母大写加驼峰原则
方法名:首字母小写加驼峰原则

Java基础07:运算符

&& - 逻辑与运算符(AND)
- 含义:两个条件都为 true 时,结果才为 true;否则为 false。
- 特点:短路求值。如果左边为 false,右边不再计算。
boolean result = (5 > 3) && (10 > 8); // true && true = true
boolean result2 = (5 > 3) && (10 < 8); // true && false = false
|| - 逻辑或运算符(OR)
- 含义:两个条件至少有一个为 true 时,结果为 true;只有都为 false 时才为 false。
- 特点:短路求值。如果左边为 true,右边不再计算。
boolean result = (5 > 3) || (10 < 8); // true || false = true
boolean result2 = (5 < 3) || (10 < 8); // false || false = false
! - 非黑即白
我们写了这么多java文件,看着好乱啊,接下来学习怎么用包

随意创建一个名字

将java文件全部拖到这个base包里面(其实就是个文件夹)

再新建一个包命名为operator(也就是运算符的意思)
可以看到在operator包里面新建的java文件有个代码代表此时在operator包里面

四个不同类型的变量进行运算,变量运算中如果有long类型结果自动为long。如果有double类型就自动转变为double类型,没有long类型或者其他高于int类型自动转换为int

想改变结果就将输出结果强制转为double

但是String类型转换不了,从这个报错也能看的出byte和short运算结果确实为int

接下来讲一下关系运算符号,如图所示,关系运算符返回结果只有true和false

模运算,信息安全数学基础里面讲烂了的东西,这里不过多赘述

Java基础08:自增自减运算符、初识Math类
这一节主要讲的就是自增运算符比如说++和--,观察下图中的代码,猜测其运行结果

为什么是这个结果呢。

先别急,我们改一下输出a的语句的位置


这里面的代码注释很好的讲解了a++和++a的区别,++a的意思就是a先加1再赋值给其他变量,a++就是先赋值给其他变量再a加1

接下来讲幂运算,虽然在平常我们写2的三次方可以写成2^3,但是在java中并不存在这种写法,那怎么办呢

我们可以输入Math.,在后面我们可以看到出现很多数学方法,pow就是乘方运算



综上可知,很多数学运算我们都会使用一些工具类来操作
Java基础09:逻辑运算符、位运算符
逻辑运算符
&&的意思就是两者同时为真才为真,||的意思就是有一方为真就为真,!的意思就是如果是真,则变为假,如果是假则变为真


还有个短路运算,b&&a刚开始运算就发现b为false,那么后面的&&a都不用运算了,直接输出false就可以了,这就是短路运算

不信的话我们可以做一个实验,如果没有短路运算的话理论上&&后面的c++就会执行,那么输出的c的值肯定就是6,但实际上输出的却是5,所以这里是存在短路运算的


位运算
常见位运算符如下

与:同时为真才为真
或:同时为假才为假
异或:相同为假,不同为真

还有个<<和>>没有讲,这里通过一个面试题来讲,面试官问如果要实现2^3=8怎么样才是最快的。毫无疑问就是位运算
<<代表左移一位也就是乘以2
>>代表右移一位也就是除以2


3左移两位也就是乘以4

Java基础10:三元运算符及小结
扩展赋值运算符
这个没什么意思,就是偷个懒,一般也不建议这么写

接下来还讲个字符串连接符号,+号两边只要有一方出现String类型,就会将另一方也转换为String类型再进行连接

30
1020
引进一个面试题
System.out.println(""+a+b);
System.out.println(a+b+"");
这两者有什么区别,结果如下
1020
30
原因就是,如果字符串在前面,后面的数字会依次被当成字符串拼接。
如果字符串在后面,前面的数字会先进行数学运算,最后再变成字符串。
条件运算符
//条件运算符
//x ? y : z
//如果x==true,则结果为y,否则结果为z
int score = 80;
String type = score<60?"不及格":"及格";
及格
优先级
反正()的优先级是最高的,拿不准就直接现价括号试一下比如说
a+b*c
我拿不准先+还是先*,那我就先加个()括起来,然后再跑
a+(b*c)
其实加括号代码可读性也更好
Java基础11:包机制
其实简单来说,包就和我们常说的"文件夹"一样

包的命名也是有讲究的,一般使用公司域名倒置作为包名,比如说百度公司的域名为www.baidu.com,那么包命名就是com.baidu.www

举个例子,我们新建了一个com的包,然后在这个里面我们还新建了baike、wenku、www这些包,就是分别拿来写百度百科 、百度文库、百度主界面这些代码的

我们在com包下面再新建一个kuang包,然后将base和operator包都丢进去,然后我们再看看base或者operator包下的任意java文件,

可以发现包名变了

同时我们也可以用import语句导入java中的其他包,比如说我想写个时间,就可以用Date包
import java.util.Date;
需要特别说明的是package的语句必须放在最上面,不然就报错

同时尽量不要让包里面的名字重复,比如下图,本来这个java文件的名字就是Demo01.java,我再导入其他包中的Demon01.java就会出现已经定义的错误

当然如果在某个包下需要导入的类非常多,且一个个导进去实在是麻烦的话。我们也可以使用通配符 *来直接导入某个包下所有的类
import com.kuang.base.* //导入base包下的所有类
Java基础12:JavaDoc生成文档

举例子
package com.kuang.base;
/**
* @author Kuangshen
* @since 1.8
* @version 1.0
*/
public class Doc {
String name;
/**
*
* @param name
* @return
* @throws Exception
*/
public String test(String name) throws Exception{
return name;
}
}
这段代码中的注释是 Javadoc 文档注释,通常写在类、方法或属性的前面,用来生成标准的 API 帮助文档。
具体每一行的含义如下:
/** ... */:这是文档注释的格式。
@author Kuangshen:作者。表示这个类是由 Kuangshen 编写的。
@since 1.8:最早使用的 JDK 版本。表示这个类或功能最早是在 JDK 1.8 版本开始支持或创建的。
@version 1.0:版本号。表示当前这个类的版本是 1.0。
如何生成文档?
你可以通过命令行生成网页版的说明文档:
javadoc -encoding UTF-8 -charset UTF-8 Doc.java
运行后会生成一堆 HTML 文件,打开 index.html 就能看到类似官方文档的页面,里面会包含你写的这些信息。
这个注释加在类前面就是对类的注释,加在方法前面就是对方法的注释
在命令行运行上面命令后生成下面这些网页版文档


生成的很详细,但是可惜我看不懂(雾)

Java流程控制01:用户交互Scanner
Scanner类用于获取用户的输入

package com.kuang.scanner;
import java.util.Scanner;
public class 用户交互Scanner {
public static void main(String[] args) {
//创建一个扫描器对象,用于接收键盘数据
Scanner scanner = new Scanner(System.in);
System.out.println("用next方式接收:");
if(scanner.hasNext())
{
String str = scanner.next();
System.out.println("输入的内容为:"+str);
}
scanner.close();//凡是属于IO流的类如果不关闭会一直占用资源,要养成好习惯用完就关掉
}
}
用next方式接收:
2
输入的内容为:2
scanner.close()作用:关闭扫描器。
scanner.hasNext():
这是一个判断语句。它会检测输入流中是否还有下一个标记(token)。在控制台交互中,程序运行到这里会阻塞(暂停),等待用户输入并按下回车。一旦有输入,它就返回 true,进入 if 内部。
scanner.next():
这是真正读取数据的方法。
重要特性:next() 方法读取到有效字符后才可以结束输入。
对空格的处理:它会自动去掉输入前的空白(空格、Tab、回车),并且以空白作为结束符。
举例:如果你输入 Hello World,str 只会接收到 Hello,因为中间的空格被当作结束符了。后面的 World 会被留在缓冲区里。
但是如果我们将输入内容改为Hello World会发生什么
用next方式接收:
Hello World
输入的内容为:Hello
我们会发现只输出了空格前的内容,原因就是next()无法读取带有空格的完整句子,如果我们使其全部输出就得使用nextLine()方法
Scanner scanner1 = new Scanner(System.in);
System.out.println("用nextLine方式接收:");
//判断用户有没有输入
if(scanner.hasNextLine())
{
//使用next方式接收
String str = scanner.nextLine();//程序会等待用户输入完毕
System.out.println("输入的内容为:"+str);
}
scanner.close();

我写代码的时候踩了坑,看完这两种接收方式的性质才反应过来
package com.kuang.scanner;
import java.util.Scanner;
public class 用户交互Scanner {
public static void main(String[] args) {
//创建一个扫描器对象,用于接收键盘数据
Scanner scanner = new Scanner(System.in);
System.out.println("用next方式接收:");
//判断用户有没有输入
if(scanner.hasNext())
{
//使用next方式接收
String str = scanner.next();//程序会等待用户输入完毕
System.out.println("输入的内容为:"+str);
}
System.out.println("用nextLine方式接收:");
//判断用户有没有输入
if(scanner.hasNextLine())
{
//使用next方式接收
String str1 = scanner.nextLine();//程序会等待用户输入完毕
System.out.println("输入的内容为:"+str1);
}
scanner.close();
}
}
code
输出内容为
用next方式接收:
1
输入的内容为:1
用nextLine方式接收:
输入的内容为:
code
可以看到我只输入了一个1然后按了回车键,nextLine方式就直接跳过输出为空了,这里就是一个经典的Scanner坑
当你输入 1 并按下 回车键 时,输入缓冲区里实际上是 1 加上一个换行符(\n)。
scanner.next() 读取了字符 1,但它不会读取后面的换行符。此时,换行符还留在缓冲区里。
接下来代码执行到 scanner.nextLine()。nextLine() 的特性是读取直到遇到换行符为止。
因为它一上来就看到了刚才剩下的那个换行符,所以它认为“这一行已经结束了”,直接读取了一个空字符串并结束,导致你感觉它“跳过”了输入。
想要解决这个问题也很简单,修改成下面这样就好
package com.kuang.scanner;
import java.util.Scanner;
public class 用户交互Scanner {
public static void main(String[] args) {
//创建一个扫描器对象,用于接收键盘数据
Scanner scanner = new Scanner(System.in);
System.out.println("用next方式接收:");
//判断用户有没有输入
if(scanner.hasNext())
{
//使用next方式接收
String str = scanner.next();//程序会等待用户输入完毕
System.out.println("输入的内容为:"+str);
}
// 修复:吃掉 next() 留下的回车符
scanner.nextLine();
System.out.println("用nextLine方式接收:");
//判断用户有没有输入
if(scanner.hasNextLine())
{
//使用next方式接收
String str1 = scanner.nextLine();//程序会等待用户输入完毕
System.out.println("输入的内容为:"+str1);
}
scanner.close();
}
}
Java流程控制02:Scanner进阶使用
package com.kuang.scanner;
import java.util.Scanner;
public class Scanner进阶使用
{
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
//从键盘接收数据
int i = 0 ;
float f = 0.0f;
System.out.println("请输入整数:");
//判断一下是不是整数
if(scanner.hasNextInt())//hasNextInt 判断接收进来的是不是整数
{
i = scanner.nextInt();
System.out.println("整数数据:" + i);
}
else {
System.out.println("输入的不是整数数据!");
}
System.out.println("请输入小数:");
//判断一下是不是小数
if(scanner.hasNextFloat())//hasNextInt 判断接收进来的是不是整数
{
f = scanner.nextFloat();
System.out.println("小数数据:" + f);
}
else {
System.out.println("输入的不是小数数据!");
}
scanner.close();
//
}
}
code
上面的代码,用户通过终端输入数字,然后代码自动判断是整数还是小数,不过有点小问题的是在判断float类型时,由于程序会自动将整数类型转换为浮点型再判断所以这里哪怕输入整数(因为整数其实也就是特殊形式的小数)也会通过判断。
不过java确实方便,如果是c语言的话我要判断整数和小数还得手搓一个小算法来实现,java有现成的类和方法比如说hasNextInt()和hasNextFloat()直接使用。
还有个小问题,输入的是整数就得用nextInt()方法接收,nextLine()方法使用来接收字符串的,不然就会报下图的错误

接下来我们就用java来写一个计算总和和平均数的程序
package com.kuang.scanner;
import java.util.Scanner;
public class 求和与平均数 {
//我们可以输入多个数字并求其总和与平均数,
// 每输入一个数字用回车确认,通过输入非数字来结束输入并执行输出结果
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
double sum = 0 ;
int m = 0 ;
System.out.println("请输入:");
while(scanner.hasNextDouble()){
double x = scanner.nextDouble();
m = m + 1;
sum = sum + x;
System.out.println("你输入了第"+m+"个数据,然后当前结果为sum="+sum);
}
System.out.println(sum);
System.out.println(m+"个数的平均值是"+(sum/m));
scanner.close();
}
}
想要循环结束的话只要输入一个非double类型的数据就行
请输入:
1
你输入了第1个数据,然后当前结果为sum=1.0
2
你输入了第2个数据,然后当前结果为sum=3.0
3
你输入了第3个数据,然后当前结果为sum=6.0
x
6.0
3个数的平均值是2.0
Java流程控制03:顺序结构

package com.kuang.base.struct;
public class 顺序结构{
public static void main(String[] args) {
System.out.println(1);
System.out.println(2);
System.out.println(3);
System.out.println(4);
System.out.println(5);
System.out.println(6);
System.out.println(7);
}
}
1
2
3
4
5
6
7
Java流程控制04:if选择结构

if单选择结构
package com.kuang.base.struct;
import java.util.Scanner;
public class if单选择结构 {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("请输入内容:");
String s = scanner.nextLine();
//equal方法用于判断字符串是否相等
if (s.equals("Hello"))
{
System.out.println(s);
}
System.out.println("End");
scanner.close();
}
}
//不相等的情况
请输入内容:
123
End
//相等的情况
请输入内容:
Hello
Hello
End
if双选择结构

package com.kuang.base.struct;
import java.util.Scanner;
public class if双选择结构 {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("请输入成绩:");
int score = scanner.nextInt();
if(score>60)
{
System.out.println("你及格了");
}
else
{
System.out.println("你不及格");
}
scanner.close();
}
}
请输入成绩:
60
你不及格
if多选择结构

package com.kuang.base.struct;
import java.util.Scanner;
public class if多选择结构 {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
/*
if语句至多有1个else语句,else语句在所有的elseif语句之后.
if语句可以有若干个elseif语句,它们必须在else语句之前.
一旦其中一个elseif语句检测为true,其他的elsef以及else语句都将跳过执行
*/
System.out.println("请输入成绩");
int score = scanner.nextInt();
if (score==100){
System.out.println("恭喜满分");
}else if (score<100 && score>=90)
{
System.out.println("A级");
}
else if (score<90 && score>=80){
System.out.println("B级");
}
else if (score<80 && score>=70)
{
System.out.println("c级");
}else if (score<70 &&score>=60)
{
System.out.println("D级");
}else if (score<60 && score>=0)
{
System.out.println("不及格");
}
else{
System.out.println("成绩不合法");
}
scanner.close();
}
}
请输入成绩
100
恭喜满分
请输入成绩
98
A级
请输入成绩
87
B级
f语句至多有1个else语句,else语句在所有的elseif语句之后.
if语句可以有若干个elseif语句,它们必须在else语句之前.
一旦其中一个elseif语句检测为true,其他的elsef以及else语句都将跳过执行
嵌套的if结构

package com.kuang.base.struct;
import java.util.Scanner;
public class if嵌套结构 {
public static void main(String[] args) {
//要在1-100之间找一个数字
Scanner scanner = new Scanner(System.in);
System.out.println("请输入一个1-100之间的数字:");
if(scanner.hasNextInt())
{
int score = scanner.nextInt();
// 第一层判断:是否在合法范围内
if(score >= 1 && score <= 100) {
// 第二层判断:具体的区间
if(score < 60) {
System.out.println("这个数字小于60,属于不及格区间");
} else if (score < 80) {
System.out.println("这个数字在60-80之间,属于中等区间");
} else {
System.out.println("这个数字大于等于80,属于优秀区间");
// 第三层判断(嵌套演示):是否是满分
if(score == 100) {
System.out.println("哇!是满分100!");
}
}
} else {
System.out.println("输入的数字不在1-100之间!");
}
} else {
System.out.println("请输入合法的整数!");
}
scanner.close();
}
}
请输入一个1-100之间的数字:
89
这个数字大于等于80,属于优秀区间
请输入一个1-100之间的数字:
76
这个数字在60-80之间,属于中等区间
请输入一个1-100之间的数字:
12
这个数字小于60,属于不及格区间
Java流程控制05:Switch选择结构

package com.kuang.base.struct;
public class Switch结构 {
public static void main(String[] args) {
char grade = 'C';
// switch 匹配一个具体的值
switch (grade) {
case 'A':
System.out.println("优秀");
break;
case 'B':
System.out.println("良好");
case 'C':
System.out.println("及格");
case 'D':
System.out.println("再接再厉");
case 'E':
System.out.println("挂科");
default:
System.out.println("未知等级");
}
}
}
switch(expression),括号里面一定是已经定义了的变量
输出结果如下
及格
再接再厉
挂科
未知等级
这时就有人会问了,这明明是switch语句啊而且明明定义了grade为c的,为什么一下子输出这么多结果。
case 穿透现象:如果 case 后面不写 break,程序会继续向下执行,直到遇到 break 或 switch 结束
仔细观察代码就会发现,除了case 'A'以外的其他case语句其实都没有写break语句,那么执行完一个case语句后后面就会继续后面的case语句。
那我们加上break语句试一下
package com.kuang.base.struct;
public class Switch结构 {
public static void main(String[] args) {
// case 穿透现象:如果 case 后面不写 break,程序会继续向下执行,直到遇到 break 或 switch 结束
// 这种现象称为 "case 穿透"
char grade = 'C';
switch (grade) {
case 'A':
System.out.println("优秀");
break;
case 'B':
System.out.println("良好");
break;
case 'C':
System.out.println("及格");
break;
case 'D':
System.out.println("再接再厉");
break;
case 'E':
System.out.println("挂科");
break;
default:
System.out.println("未知等级");
}
}
}
及格
自从jdk7开始switch支持字符串string类型

为什么支持string类型,我们看下反编译文件就知道了
.class 文件(字节码文件)通常位于项目的输出目录中

狂神视频里的字节码文件反编译后的样子如下图,因为版本较老所以看起来代码很多

新版本IDE内置的反编译器非常智能它们能识别出这种特定的代码模式,基本上直接给你反编译还原成源码的样子了

对于switch语句反编译代码的讲解
- 先算字符串的哈希值:
switch(name.hashCode())。 - 根据哈希值找到对应的分支。
- 为了防止哈希冲突(不同字符串可能有相同的哈希值),再用
if (name.equals("..."))进行二次确认。 - 最后根据确认结果,给一个临时变量
var3赋值(0, 1, 2...),再用第二个switch(var3)去执行真正的逻辑。
Java流程控制06:While流程详解


输出1-100
package com.kuang.base.struct;
public class while循环 {
public static void main(String[] args) {
//输出1-100
int i = 0;
while(i<100)
{
i = i+1;
System.out.println(i);
}
}
}
计算1加到100
package com.kuang.base.struct;
public class while循环计算1加到100{
public static void main(String[] args) {
int i = 0;
int sum = 0;
while(i<100)
{
i = i+1;
sum = sum+i;
}
System.out.println(sum);
}
}
Java流程控制07:DoWhile循环

dowhile循环与 while循环的区别就在于 先执行后判断,比如下面这个代码,不管是否满足while中 i<=100的条件,首先都会先改变sum和i的值。注意看最后while语句有个分号 ;因为一直都是在do语句里面循环,while只是起一个判断循环条件的作用,一旦不满足就直接跳出循环了
package com.kuang.base.struct;
public class DoWhile循环 {
public static void main(String[] args) {
int i =0;
int sum = 0;
do{
sum = sum + i ;
i = i + 1;
}while(i<=100);
System.out.println(sum);
}
}
关于这两种循环的区别我们可以写一个代码,可以看到因为a=0 while循环判断条件无法满足根本都不会进入循环, dowhile循环因为会先执行 a++所以满足a>0的条件。
package com.kuang.base.struct;
public class dowhile和while的区别 {
public static void main(String[] args) {
int a = 0;
while(a>0)
{
System.out.println(a);
}
System.out.println("======================================");
do
{
System.out.println(a);
a = a + 1;
}while(a>0 && a<=100);
}
}
Java流程控制08:For循环详解

package com.kuang.base.struct;
public class For循环 {
public static void main(String[] args) {
int a = 1;
while (a<=100)
{
System.out.println(a);
a+=2;
}
System.out.println("While循环结束!");
for(int i =1;i<=100;i++)
{
System.out.println(i);
}
System.out.println("for循环结束!");
}
}

由于第一个和第二个可以为空,我们就可以写一个死循环
for(; ; ){}

练习1(不算上100)
package com.kuang.base.struct;
public class for循环1到100奇数和偶数的和 {
public static void main(String[] args) {
int i = 0;
int sum1 = 0;
int sum2 = 0;
for(i=0;i<100;i++)
{
if(i%2==0)//偶数
{
sum1=sum1+i;
}
if(i%2!=0)
{
sum2=sum2+i;
}
}
System.out.println("奇数的和"+sum2);
System.out.println("偶数的和"+sum1);
}
}
练习2
package com.kuang.base.struct;
public class 用while或for循环输出1到1000之间能被5整除的数且每行输出三个 {
public static void main(String[] args) {
int i = 1;
for(i=1;i<1000;i++)
{
if(i%5==0)
{
System.out.print(i+"\t");
}
if(i%5==0&&i%3==0)
{
System.out.println();
}
}
}
}
package com.kuang.base.struct;
public class 打印九九乘法表 {
public static void main(String[] args) {
for(int i=1;i<=9;i++)
{
for(int j=1;j<=i;j++)
{
System.out.print(i + "*" + j + "=" +(j*i) + "\t");
}
System.out.println();
}
}
}
Java流程控制09:打印九九乘法
package com.kuang.base.struct;
public class 打印九九乘法表 {
public static void main(String[] args) {
for(int i=1;i<=9;i++)
{
for(int j=1;j<=i;j++)
{
System.out.print(i + "*" + j + "=" +(j*i) + "\t");
}
System.out.println();
}
}
}
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
这里我们用到了嵌套循环,这里的 i对应的是列元素,j对应的是行元素,外面的for循环是用来循环每一行的,里面的循环是用来循环每一列的,外面的循环限制了只有9行,而内循环设置条件为 j<=i就是保证不出现重复项比如说 2*3 和3*2。
下面这个代码就是为了保证能够输出类似 1*2=2这种样式,当然也不是说一定要输出成这样。\t是为了让每一个式子中间用空格隔开
i + "*" + j + "=" +(j*i) + "\t"
外循环的这个语句是为了换行
System.out.println();//或者System.out.println("\n");
Java流程控制10:增强for循环

package com.kuang.base.struct;
public class 增强for循环 {
public static void main(String[] args) {
int [] numbers = {10,20,30,40,50};
for(int i=0;i<5;i++)
{
System.out.println(numbers[i]);
}
System.out.println("====================");
for(int x:numbers)
{
System.out.println(x);
}
}
}
10
20
30
40
50
====================
10
20
30
40
50
上面这个代码很好的显示出普通for循环和增强for循环的区别以及优缺点
int x : numbers
增强型for循环:Java 会自动把 numbers 数组里的每一个元素,依次赋值给变量 x。你不需要关心索引是多少,也不用担心数组越界。
普通型for循环:可以控制索引,比如可以跳着遍历(i+=2),或者倒序遍历,非常灵活。
总的来说就是普通for循环你可以控制其循环次数以及循环方式,但是增强型for循环你就只能让其一次性将数组元素全部遍历完。两种循环各有各的优缺点
Java流程控制11:break、continue、goto

package com.kuang.base.struct;
public class break_continue_goto{
public static void main(String[] args) {
//break,只输出到30
int i = 1;
for(i=1;i<=100;i++)
{
System.out.println(i);
if(i==30)
{
break;
}
}
System.out.println("=======================");
//continue 10的倍数不输出
for(i=1;i<=100;i++)
{
if(i%10==0)
{
System.out.println();
continue;
}
System.out.print(i+"\t");
}
}
}
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
=======================
1 2 3 4 5 6 7 8 9
11 12 13 14 15 16 17 18 19
21 22 23 24 25 26 27 28 29
31 32 33 34 35 36 37 38 39
41 42 43 44 45 46 47 48 49
51 52 53 54 55 56 57 58 59
61 62 63 64 65 66 67 68 69
71 72 73 74 75 76 77 78 79
81 82 83 84 85 86 87 88 89
91 92 93 94 95 96 97 98 99
可以看到 continue语句只要碰到10的倍数就跳过不执行了,continue会直接跳过后面的语句直接进入到下一个循环的开始,而break语句会直接跳出循环

Java方法01:什么是方法?

System是系统的一个类,out是system下的一个输出对象,println()就是一个方法

对于main方法来说 public static就是一个修饰符,void表示返回值类型,这里代表无返回值

用实际代码看看,可以看到现在我们虽然定义了一个add方法但是在main方法中引用不了,

原因如下:add是实例方法也就是 非静态方法,而main方法是 静态方法也就是 类方法,在类中静态方法无法直接调用实例方法,只有当类创建了实例也就是对象后静态方法才能通过 类名.实例方法名才能调用该实例方法。或者说你将该实例方法加个 static修饰符使其变为静态方法后,其他的静态方法也可以直接调用该加了修饰符的实例方法(此时已经变成了静态方法力(悲))
Java方法02:方法的定义和调用


形参 实参
形参就是方法被调用的时候用于接收外界输入的数据

实参就是调用方法时实际传给方法的数据

这里我们可以看看println方法的源码,可以看到传入了一个x形参,没有返回值而是直接输出

Java方法03:方法的重载

比如说在上一节课中我们写了一个用来比较大小的方法,但是返回值类型是int类型。如果我们输入小数的话就会报错,针对这个情况,我们就还需要再写一个方法,名字一样但是返回值类型不同且形参类型也要不同。当遇到用户输入浮点数类型数据的时候
package com.kuang.base.merthod;
import java.util.Scanner;
public class 比大小 {
public static void main(String[] args) {
System.out.println("请输入数字");
Scanner scanner = new Scanner(System.in);
double num1 = 0;
double num2 = 0;
if(scanner.hasNextDouble())
{
num1=scanner.nextDouble();
num2=scanner.nextDouble();
}
double num3 = max(num1,num2);
System.out.println(num3);
scanner.close();
}
//比大小(int类型)
public static int max(int a,int b)
{
int result;
if (a==b)
{
System.out.println("a==b");
}
if(a>b)
{
result = a;
}
else
{
result =b;
}
return result;
}
public static double max(double a,double b)
{
double result;
if (a==b)
{
System.out.println("a==b");
}
if(a>b)
{
result = a;
}
else
{
result =b;
}
return result;
}
}
Java方法04:命令行传参参数

package com.kuang.base.merthod;
public class 命令行传递参数 {
public static void main(String[] args) {
for (int i = 0; i < args.length; i++) {
System.out.println("args["+i+"]:"+args[i]);
}
}
}
i这段代码演示了 Java 如何接收和处理命令行参数。
代码解读
- String[] args:
- 这是 main 方法的参数,它是一个字符串数组。
- 它的作用是接收你在运行程序时,从命令行(终端)传递给程序的额外信息。
- args[0]是第一个参数,args[1]是第二个,以此类推。
for循环:- i < args.length:遍历这个数组,看看你到底传了多少个参数进来。
- System.out.println(...):把每一个参数的索引(下标)和具体内容打印出来。
如何运行并看到效果?
如果你直接点击 IDE(如 VS Code)的“运行”按钮,控制台可能什么都不会输出(或者只输出程序结束的信息),因为默认情况下你没有传递任何参数,args数组是空的,长度为 0,循环根本不会执行。
要看到效果,你需要通过命令行手动传递参数
首先在该代码所在的文件夹下编译该代码文件

可以看到生成了编译后的文件

但是我们在该目录下直接用java命令执行该class文件会报错

原因就是
Java 规定,带有包名的类,必须在包的根目录(也就是 src 目录)下运行,并且要写全名。是在 method 目录下运行的,Java 找不到 com 这个包结构,所以报错 ClassNotFoundException。
所以命令行的命令要这么修改
java com.kuang.base.merthod.命令行传递参数

没有回显是因为还需要我们通过命令行传递参数给main方法的参数args[]数组

Java方法05:可变参数

上上节课我们说到方法重载,对于不同的需求我们可以重载不同的方法,但是,就比大小这一方法而言,如果比较的两个数字类型不同我们就可能就需要重载非常多的方法,非常繁琐。所以这节课我们就引进了可变参数这一概念

可变参数允许我在调用方法的时候传入任意数量的参数(0个、1个或多个),当你不确定调用者会传递多少个参数时非常有用。
语法
在指定参数类型后加上省略号 ...,例如
public void method(int... numbers) {
// 方法体
}
核心特点
-
本质是数组:在方法内部,可变参数 numbers 实际上就是一个数组(例如
int[])。 可以像操作数组一样操作它(使用 .length,下标访问等)。 -
位置限制
:一个方法中只能指定
一个
可变参数,而且它必须是方法的
最后一个参数
。
- 正确:public void test(int a, String... b)
- 错误:public void test(String... b, int a)(可变参数必须在最后)
- 错误:public void test(int... a, String... b)只能有一个可变参数)
package com.kuang.base.merthod;
public class 可变参数 {
public static void main(String[] args) {
// 调用可变参数的方法
可变参数 a = new 可变参数();
a.test(1,2,3,4);
}
public void test(int ...i)
{
System.out.println(i[0]);
}
}
1
最开始敲这个代码的时候我忘记给i加上索引了,直接打印了i,输出结果如下
[I@28a418fc
输出 [I@28a418fc 是因为直接打印了一个数组对象。
在 Java 中:
[I表示这是一个 int 类型的数组([代表数组,I代表 int)。@是分隔符。28a418fc是这个对象在内存中的哈希码(十六进制)
可变参数int ...i本质上还是一个数组。

可以看到我想输出1.3,直接报错了,说明可变参数中的每一个元素都得保证类型一样
Java方法06:递归讲解

利用递归实现阶乘的代码如下
package com.kuang.base.merthod;
public class 递归讲解 {
public static void main(String[] args) {
System.out.println(f(5));
}
public static int f(int n)
{
if(n==1)
{
return 1;
}else
{
return n*f(n-1);
}
}
}
用大白话讲解一下流程,当然如果自己能够利用debug(调试)去理解代码当然是最好的了。
首先main方法会调用f(5),n不等于1,进入else,再调用f(4)。
f(4)中n不等于1,进入else,再调用f(3)。
f(3)中n不等于1,进入else,再调用f(2)。
f(2)中n不等于1,进入else,再调用f(1)。
f(1)中n等于1,返回1到f(2)中,此时n变为2,执行n*f(n-1),即1x2。
f(2)返回2到f(3)中,此时n变为3,执行n*f(n-1),即3x2x1。
依次类推,一直到f(5),返回5x4x3x2x1到main方法中,再由println方法将结果打印出来


边界条件的意思就是递归的出口,也就是停止调用自己的条件。如果没有它,程序就会无限循环下去,直到内存溢出(栈溢出)。
前阶段的意思就是“递”的过程。程序不断地调用自身,每一次调用参数都在变化(通常是规模变小),一步步逼近边界条件。在这个阶段,计算还没有真正完成,只是在不断地“压栈”(把任务存起来)。
返回阶段的意思就是“归”的过程。当触碰到边界条件后,程序开始一层层往回走。拿着子任务的结果,计算当前任务的结果,并返回给上一层。

package com.kuang.base.merthod;
import java.util.Scanner;
public class 计算器 {
public static void main(String[] args) {
计算器 test = new 计算器();
Scanner num = new Scanner(System.in);
double num1 = 0;
double num2 = 0;
double result = 0;
String operator = "0";
System.out.println("请输入两个数字");
if(num.hasNextLine())
{
num1 = num.nextDouble();
num2 = num.nextDouble();
}
System.out.println("请输入运算符");
if(num.hasNext())
{
operator=num.next();
}
switch(operator)
{
case "+":
result = test.add(num1,num2);
System.out.println(result);
break;
case "-":
result = test.subtract(num1,num2);
System.out.println(result);
break;
case "*":
result = test.multiply(num1,num2);
System.out.println(result);
break;
case "/":
result = test.divide(num1, num2);
System.out.println(result);
break;
}
}
public double add(double a,double b)
{
return a+b;
}
public double subtract(double a,double b)
{
if(a==b){
return 0;
}
if(a>b)
{
return a-b;
}else
{
return b-a;
}
}
public double multiply(double a,double b)
{
return a*b;
}
public double divide(double a,double b)
{
if(b==0)
{
System.out.println("除数为0,无法操作");
}
return a/b;
}
}
Java数组02:数组的声明和创建

声明数组
package com.kuang.base.Array;
public class 数组的声明和创建 {
public static void main(String[] args) {
//变量类型 变量名称 = 值
int num[];//声明数组
// int[] num;//声明数组。建议使用这种
}
}
定义数组,分配空间
int num = new int[10];//数组的定义,表示能存放是个元素
给数组元素赋值
//给数组元素赋值
num[0]=1;
num[1]=1;
num[2]=2;
num[3]=3;
num[4]=4;
num[5]=5;
num[6]=6;
num[7]=7;
num[8]=8;
num[9]=9;
计算数组元素的值
int sum = 0;
获取数组的长度 array.length
for (int i = 0; i < num.length; i++) {
sum = sum + i;
}
System.out.println(sum);

Java数组03:三种初始化及内存分析

Java 的内存主要分为两块区域来处理数组:(注意:这里的sum其实对应的就是图中的array)
- 栈内存 (Stack):存放基本变量类型(int, double等)和引用变量(对象的地址)。
- 堆内存 (Heap):存放
new出来的对象和数组(数组在 Java 中也是对象)。 - 声明数组 int[] sum = NULL:在 栈内存 (Stack) 中,开辟了一个小空间,名字叫
num。此时它只是一个变量名,里面是空的(或者说null),还没有指向任何实际的数据。

2.创建数组 array=new int[10]:
new int[10]:在 堆内存 (Heap) 中,开辟了一块连续的内存空间,大小足以存放 10 个int数据。- 初始化:这 10 个格子会被默认初始化为
0。 - 赋值:将这块堆内存的内存地址(比如
0x1234)赋值给栈里的num

3.给数组中赋值:不赋值的话数组中每个元素就是默认元素

这时候有人问了,数组里只有十个元素,那如果我访问第十一个元素会发生什么
会报如下的错误 ArrayIndexOutOfBoundsException数组下标越界错误
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 10 out of bounds for length 10
at com.kuang.base.Array.数组的声明和创建.main(数组的声明和创建.java:23)
三种初始化

静态初始化:开始数组里的所有元素就都已经初始化且赋值了,创建数组的同时,直接指定数组中每个元素的具体值。
//静态初始化
int[] a = {1,2,3,4,5,6,7,8,9,10};
System.out.println(a[0]);
动态初始化:先只指定数组的长度,不指定具体的值。
//动态初始化,包含默认初始化
int[] b = new int[10];
b[0]=10;
System.out.println(b[0]);
System.out.println(b[1]);
System.out.println(b[2]);
System.out.println(b[3]);
默认初始化:这是动态初始化的一部分。当你 new 了一个数组但还没赋值时,Java 绝不会让内存空着,而是会填入默认值。
Java数组04:下标越界及小结


int[] a = {1,2,3,4,5,6,7,8,9,10};
System.out.println(a[0]);
for (int i = 0; i <= a.length; i++) {
System.out.println(a[i]);
}
关于越界,如上面代码所示,数字虽然有10个,但是下标其实是 0~9,第10个下标其实不存在,如果还要输出的话就会报下面这样的错误
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 10 out of bounds for length 10
at com.kuang.base.Array.三种初始化.main(三种初始化.java:9)
对于数组的小结J

Java数组05:数组的使用
打印数组的全部元素
int[] arrays = {1,2,3,4,5};
//打印数组的全部元素
for (int i = 0; i < arrays.length; i++) {
System.out.print(arrays[i]+" ");
}
System.out.println("\n"+"===================");
计算数组里面所有元素的和
//计算数组里面所有元素的和
int sum = 0;
for (int i = 0; i < arrays.length; i++) {
sum = sum + arrays[i];
}
System.out.println("sum"+sum);
System.out.println("======================");
查找数组里面的最大元素
//查找数组中最大的元素
int max = arrays[0];
for (int i = 1; i < arrays.length; i++) {
if(arrays[i]>max)
{
max = arrays[i];
}
}
System.out.println("max="+max);
增强型for循环打印数组元素
//增强型for循环,自从jdk1.5开始的
for (int array:arrays) {
System.out.println(array);
}
自写方法打印数组元素
public static void printArray(int[] arrays)
{
for (int i = 0; i < arrays.length; i++) {
System.out.println(arrays[i]);
}
}
反转数组
package com.kuang.base.Array;
public class 数组的使用 {
public static void main(String[] args) {
int[] arrays = {1,2,3,4,5};
int[] reverse = reverse(arrays);//定义一个新数组接收reverse返回值
printArray(reverse);
System.out.println("\n"+"===================");
}
public static int[] reverse(int[] arrays)
{
int[] result = new int[arrays.length];
for(int i=0,j=arrays.length-1;i<arrays.length;i++,j--)
{
result[j]=arrays[i];
}
return result;
}
}
Java数组06:二维数组


打印第0行第1列
package com.kuang.base.Array;
public class 二维数组 {
public static void main(String[] args) {
//[4][2]
//1 2
//2 3
//3 4
//4 5
int[][] array = {{1,2},{2,3},{3,4},{4,5}};
System.out.println(array[0][1]);
}
}
2
打印第0行
System.out.println(array[0]);
[I@28a418fc
嗯?怎么是这个结果。仔细观察,奥,原来在java中,二维数组的每一行其实就是一个一维数组对象
那就修改一下代码
for(int j=0;j<array[0].length;j++)
{
System.out.println(array[0][j]);
}
1
2
输出数组长度
System.out.println(array.length);
4
输出二维数组第1行的长度
System.out.println(array[0].length);
2
将二维数组打印出来(嵌套循环)
for(int i=0;i<array.length;i++)
{
System.out.println("\n");
for(int j=0;j<array[i].length;j++)
{
System.out.print(array[i][j]+" ");
}
}
Java数组07:Arrays类讲解

首先注意,如果你在代码开头不导入包的话 import java.util.Arrays;的话,在后面你每次想引用这个 Arrays 类的方法的时候都要写全名,例如我想用Arrays类里面的 toString方法,我就得写 java.util.Arrays.toString。这个问题虽然很基础但是新手经常容易忘记导入包导致代码爆红但是不知道为什么爆红()。
先进入这个类看一下

要想查看这个类里面的所有方法,就可以在vscode中使用”大纲“识图
- 位置:通常在左侧资源管理器(Explorer)的底部,有一个名为 “大纲” (Outline) 的折叠栏。
- 操作:点击展开它,你会看到当前类中所有的字段(变量)和方法列表。
- 功能:你可以直接点击列表中的方法名,编辑器会自动跳转到该方法的定义处。你还可以直接在里面输入字符进行筛选。

例:打印数组元素 toString
package com.kuang.base.Array;
import java.util.Arrays;
public class Arrays类 {
public static void main(String[] args) {
int[] a = {1,2,5,3232,54363,52412411};
System.out.println(Arrays.toString(a));
}
}
Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF-8
[1, 2, 5, 3232, 54363, 52412411]
例:排序数组元素
package com.kuang.base.Array;
import java.util.Arrays;
public class Arrays类 {
public static void main(String[] args) {
int[] a = {1,2,5,123312312,3232,52412411};
Arrays.sort(a);//数组进行排序,升序
System.out.println(Arrays.toString(a));
}
}
Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF-8
[1, 2, 5, 3232, 52412411, 123312312]
例:给数组元素赋值
package com.kuang.base.Array;
import java.util.Arrays;
public class Arrays类 {
public static void main(String[] args) {
int[] a = {1,2,5,123312312,3232,52412411};
Arrays.fill(a, 1);//给数组里面每个元素都赋值为1
System.out.println(Arrays.toString(a));
}
}
Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF-8
[1, 1, 1, 1, 1, 1]
例:比较两个数组
package com.kuang.base.Array;
import java.util.Arrays;
public class Arrays类 {
public static void main(String[] args) {
int[] a = {1,2,5,123312312,3232,52412411};
int[] b = {1,3,5,123312312,3232,52412411};
boolean c = true;
c=Arrays.equals(a, b);
System.out.println(c);
}
}
Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF-8
false
例:通过二分查找操作在排序好恶毒数组里面查找某个元素并返回位置
package com.kuang.base.Array;
import java.util.Arrays;
public class Arrays类 {
public static void main(String[] args) {
int[] a = {1,2,5,123312312,3232,52412411};
int[] b = {1,3,5,123312312,3232,52412411};
int c =Arrays.binarySearch(a, 1);
System.out.println(c);
}
}
Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF-8
0
Java数组08:冒泡排序

package com.kuang.base.Array;
import java.util.Arrays;
public class 冒泡排序 {
public static void main(String[] args) {
int a[] = {1,2,3,4,5,8,7,9,10};
// 外层循环:决定我们要走多少轮
for (int i = 0; i < a.length - 1; i++) {
// 内层循环:比较判断两个数,如果第一个数比第二个数大,则交换位置
// -1 是为了防止溢出 (j+1)
// -i 是因为每一轮结束后,最大的数已经冒泡到了最后,不用再比了
for (int j = 0; j < a.length - 1 - i; j++) {
if (a[j] > a[j + 1]) {
// 正确的交换逻辑(三步走)
int temp = a[j];
a[j] = a[j + 1];
a[j + 1] = temp;
}
}
}
System.out.println(Arrays.toString(a));
}
}
每循环一轮就会把当前循环中最大的数字放到最后面。
优化:加个标志位,如果循环一轮发现本来就是有序的,就可以直接退出循环了降低时间成本减少无用功
package com.kuang.base.Array;
import java.util.Arrays;
public class 冒泡排序 {
public static void main(String[] args) {
int a[] = {1,2,3,4,5,8,7,9,10};
// 外层循环:决定我们要走多少轮
for (int i = 0; i < a.length - 1; i++) {
boolean flag = false; // 通过flag标识位减少没有意义的比较
// 内层循环:比较判断两个数,如果第一个数比第二个数大,则交换位置
// -1 是为了防止溢出 (j+1)
// -i 是因为每一轮结束后,最大的数已经冒泡到了最后,不用再比了
for (int j = 0; j < a.length - 1 - i; j++) {
if (a[j] > a[j + 1]) {
// 正确的交换逻辑(三步走)
int temp = a[j];
a[j] = a[j + 1];
a[j + 1] = temp;
flag = true;
}
}
if (flag == false) {
break;
}
}
System.out.println(Arrays.toString(a));
}
}
面向对象01:什么是面向对象

属性加方法就是一个类
1. 面向过程 (Procedural Programming)
核心思想:步骤化。分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个一个依次调用。
- 场景:做蛋炒饭
- 买菜(定义买菜函数)
- 洗菜(定义洗菜函数)
- 切菜(定义切菜函数)
- 打蛋(定义打蛋函数)
- 起锅烧油(定义炒菜函数)
- 出锅装盘(定义装盘函数)
- 吃
- 特点:
- 需要亲力亲为,关注每一个细节。
- 代码是线性的,从上到下执行。
- 适合:简单、不需要协作的小任务(比如刚才写的冒泡排序,逻辑简单,一步步走完就行)。
2. 面向对象 (Object-Oriented Programming, OOP)
核心思想:模块化/分类。把构成问题事务分解成各个对象,建立对象的目的不是为了完成一个步骤,而是为了描述某个事物在整个解决问题的步骤中的行为。
- 场景:饭店点蛋炒饭
- 你(对象A):负责下达命令“我要吃蛋炒饭”。
- 服务员(对象B):负责接收命令,传给厨房。
- 厨师(对象C):负责具体的买菜、洗菜、炒菜(这些细节封装在厨师内部,你不需要知道他先放盐还是先放蛋)。
- 结果:饭端上来,你吃。
- 特点:
- 你不需要知道饭怎么炒的,你只需要找到“厨师”这个对象,调用他的功能。
- 适合:复杂、庞大、需要多人协作的系统(比如开发一个淘宝,不可能把所有逻辑写在一个 main 方法里)。

封装
简单来说就是把对象属性隐藏起来,只留一个口允许外部操作接口访问
示例代码
public class Student {
// 1. 封装:把属性藏起来,防止别人乱改(比如把年龄改成 -100 岁)
private int age;
// 2. 提供公开的入口,可以在这里加关卡(逻辑判断)
public void setAge(int age) {
if (age < 0 || age > 120) {
System.out.println("年龄不合法!");
} else {
this.age = age;
}
}
}
继承
子类可以继承父类的属性和方法,不需要重新写一遍
// 父类:动物
class Animal {
public void eat() {
System.out.println("吃东西");
}
}
// 子类:猫(自动拥有了 eat 方法,不用自己写)
class Cat extends Animal {
public void meow() {
System.out.println("喵喵叫");
}
}
多态
同一个方法调用,由于对象不同,可能会有不同的行为。
拿学习举例子,学习这个方法是人类共有的,但是小红和小丽这两个对象对于学习掌握的程度不同就会造成差异
// 父类
class Animal {
void shout() { System.out.println("动物叫"); }
}
// 子类狗
class Dog extends Animal {
@Override
void shout() { System.out.println("汪汪汪"); }
}
// 子类猫
class Cat extends Animal {
@Override
void shout() { System.out.println("喵喵喵"); }
}
public class Test {
public static void main(String[] args) {
// 多态的魅力:虽然类型都是 Animal,但行为不同
Animal a1 = new Dog();
Animal a2 = new Cat();
a1.shout(); // 输出:汪汪汪
a2.shout(); // 输出:喵喵喵
}
}
为什么说从认识论角度考虑是现有对象后有类,比如说我们是有很多人去承担教书的责任我们才抽象出了“教师”这个概念,这就是为什么现有对象后有类
从代码运行角度来看,我们是先写好了类,再用类去声明对象,所以说先有类后有的对象

面向对象02:回顾方法的定义

package com.oop;
//回顾方法 类
public class 回顾方法 {
//main方法
public static void main(String[] args) {
// 1. 先实例化这个类(new 一个对象出来)
// 类名 对象名 = new 类名();
回顾方法 demo = new 回顾方法();
// 2. 通过对象调用非静态方法
// 对象名.方法名();
String result = demo.sayHello();
System.out.println(result);
}
/*
修饰符 返回值类型 方法名(...)
{
方法体
返回值;
}
*/
public String sayHello()
{
return "Hello,World";
}
public void print() {
System.out.println("我是打印方法");
}
}
修饰符和返回类型这两个在命名方法的时候较为常见,不再赘述
break和return的区别
接下来讲break和return的区别,
beak:跳出switch,结束整个循环
return:代表方法结束,只要执行了这个关键字,方法就结束了。return的值也可以为空


方法名
方法名要注意驼峰原则,第一个单词首字母小写,后面的单词首字母要大写。方法的命名要做到见名知意
面向对象03:回顾方法的调用
静态方法的调用
首先先看静态方法的调用,static修饰,在同一个包不同文件中,可以通过 类名.方法名直接调用该方法;不在同一个包的话就需要先导入包,然后再通过 类名.方法名来调用该方法。

非静态方法
要想调用非静态方法的话,就得先创建一个对象,再通过 对象.方法名来调用这个方法。

方法之间的调用
可以看到两个静态方法之间互相调用没有报错

两个非静态方法之间调用也没报错

但是静态和非静态方法之间相互调用就报错了,这是因为静态方法在类加载的时候就已经存在了,而非静态方法要一直到对象创建成功之后才会存在
静态可以调用非静态,但是非静态不能调用静态

形参和实参
1. 概念对比
| 概念 | 全称 | 英文 | 含义 | 比喻 |
|---|---|---|---|---|
| 形参 | 形式参数 | Formal Parameter | 定义方法时使用的参数。它只是一个占位符,用来接收外面传进来的值。 | 剧本里的角色名(如“男主角”),谁来演都可以。 |
| 实参 | 实际参数 | Actual Parameter | 调用方法时实际传递给方法的数据。 | 实际演戏的演员(如“胡歌”),他去演那个角色。 |
2. 代码演示
请看 回顾方法的调用.java中的代码:
public static void main(String[] args) {
int m = 10;
// 【实参】:调用的时候,m(也就是10) 和 20 是实实在在的数据
// 我们把 10 和 20 传给了 add 方法
int result = add(m, 20);
}
// 【形参】:定义的时候,a 和 b 只是两个变量名
// 它们等着接收外面传进来的值
public static int add(int a, int b) {
return a + b;
}
3. 传递过程(值传递)
当你调用 add(m, 20)时,Java 发生了一次赋值操作:
- 把实参 m的值(10)复制一份,赋给形参 a。
- 把实参
20的值(20)复制一份,赋给形参 b。 - 方法内部计算 a + b,其实就是计算
10 + 20。
注意:形参和实参在内存中是两个不同的变量,只是值被复制过去了而已。
值传递和引用传递
先讲一下值传递,运行下面的代码,你会发现,main方法中 a=1,在 changePrimitive方法中明明把a的值修改为10 a=10,但是最后输出的a的值却为1
原因就是java中值传递,是将实参a的值复制了一份复印件然后传给形参的,形参用复印件去方法中执行操作的,所以你将复印件的值改了是不会影响作为原件的 实参的值的。
再来讲一下引用传递,你可以看到我将person对象属性 name的值设为 小明,写了个 changeReference方法将
package com.oop;
// 值传递
public class 值传递 {
public static void main(String[] args) {
// 1. 基本数据类型(int)
int a = 1;
System.out.println("调用前 a = " + a);
changePrimitive(a);
System.out.println("调用后 a = " + a); // 结果会是多少?
// 2. 引用数据类型(对象)
Person person = new Person();
person.name = "小明";
System.out.println("调用前 name = " + person.name);
changeReference(person);
System.out.println("调用后 name = " + person.name);
change(person);
System.out.println("再次调用后 name = "+ person.name);
// 结果会是多少?
}
// 尝试修改基本类型
public static void changePrimitive(int num) {
num = 10; // 修改形参
}
// 尝试修改引用类型
public static void changeReference(Person p) {
// p 是 person 的一个拷贝(拷贝的是地址)
// 但是它们指向同一个“人”
p.name = "小红";
}
public static void change(Person p) {
p = new Person(); // p 指向了“北京路2号”
p.name = "旺财";
}
}
// 定义一个简单的类
class Person {
String name;
}

记录下java基础的学习
浙公网安备 33010602011771号