阅读前请看一下:我是一个热衷于记录的人,每次写博客会反复研读,尽量不断提升博客质量。文章设置为仅粉丝可见,是因为写博客确实花了不少精力。希望互相进步谢谢!!
文章目录
- 阅读前请看一下:我是一个热衷于记录的人,每次写博客会反复研读,尽量不断提升博客质量。文章设置为仅粉丝可见,是因为写博客确实花了不少精力。希望互相进步谢谢!!
- 前言
- 1、简介
- 2、运算符
- 3、if、switch、for、while语句
- 4、IDEA
- 5、数组
- 6、方法
- 7、Debug
- 8、基础案例
- 9、类和对象
- 10、API
- 11、String
- 12、StringBuilder
- 13、ArrayList集合
- 14、学生管理系统
- 15、继承
- 16、修饰符
- 17、多态
- 18、抽象类
- 19、接口
- 20、形参和返回值
- 21、内部类
- 22、常用API
- 23、异常
- 24、集合进阶
- 25、IO流
- 、总结
前言
学的黑马java,记录笔记如下,视频链接地址 《https://www.bilibili.com/video/BV18J411W7cE?p=1&vd_source=763a5e93fb502e71e42ff76a6fe1ae7c》
提示:以下是本篇文章正文内容
1、简介
1.1、JDK、JRE、JVM
visio 2016
JDK:开发环境;
JRE:运行环境;
JVM:相当于一个翻译,保证了JAVA程序能够跨平台使用。
开发工具:编译工具(javac.exe)和运行工具(java.exe)
1.2、JDK的安装目录
1.3 DOS常用命令
1.4 第一个程序的编写
1、记事本编写个 .java 文件;
2、进到所在的目录,执行 javac HelloWorld.java 进行编译,得到一个 HelloWorld.class 的java字节码文件;
3、执行 java HelloWorld ,即运行编译好的 java 程序。
1.5 HelloWorld常见小问题
1.6 关键字
关键字:被java语言赋予了特定含义的单词
1.7 常量
注意:NULL常量是不能直接被输出的,其他常量则可以被直接输出。
___________________________时间分隔符:2023/3.20__2h
1.8 变量使用注意事项
-
long类型的变量定义的时候,为了防止数过大,要在后面加L。
后面加“L”的原因:不加默认为int,相当于把int类型的数据赋值给long类型,而本身10000000000是超过int的数据范围了,因此不加就会报错”超过范围“!!!
- float类型的变量定义时,为了防止类型不兼容,后面要加F。因为默认小数默认double,而double是无法直接转换为float的(什么都不加的情况下)。
1.9 标识符
-
标识符定义规则
-
标识符命名约定
1.10 类型转换
- 自动类型转换
- 强制类型转换
1.11 Scanner,从控制台输入数据
步骤:
1、导包
2、创建对象
3、接收数据
//1、导包
import java.util.Scanner;
pubilc class MethodTest_02 {
public static void main(String[] args) {
//2、创建对象
Scanner sc = new Scanner(System.in);
//3、接收数据
int week = sc.nextInt();
}
}
2、运算符
2.1 算术运算符
整数操作只能得到整数,要想得到小数,必须要有浮点数参与运算
System.out.println(3 / 2);
System.out.println(3.0 / 2);
2.2 字符的’+'操作
其实就是在讲ASCII码,不过多讲了个类型是如何自动提升的
int k = 1 + 1.0; 报错
double k = 1 + 1.0; 不报错
2.3 字符串的’+'操作
System.out.println("黑马" + 6 + 66); 输出:黑马666
System.out.println(1 + 99 + "黑马"); 输出:100黑马
2.4 赋值运算符=、+=等操作
只用注意一个点:+=、-=等等扩展的赋值运算符,自动包含了强制类型转换
short s = 10;
s += 20; //不会报错,因为自动包含了强制类型转换
System.out.println("s: " + s);
short x = 10;
x = x + 20; //报错,int无法转换为short,解决办法是强类型转换,不过复杂了
System.out.println("x: " + x);
2.5 ++、-- 操作
- 单独使用时,放前后都一样!!!
- 参与使用时,放前后不一样!!!
2.6 关系运算符
关系运算符的结果都是True or False,千万不要把 “==” 成 “=” 。
2.7 逻辑运算符
注意各个逻辑运算符的规则,尤其是“异或”容易忘。
2.8 短路逻辑运算符
注意 “短路逻辑运算符” 和 “逻辑运算符” 的区别,自己之前没接触过此类运算符。
2.8 三元运算符
跟C++差不多。
2.9 具体案例
具体案例可以看“两只老虎”、“三个和尚”。其实分析的过程基本都是如下:
1、首先分析需要几个变量去表示;
2、想想用什么数据结构去实现(例如最简单的比大小,复杂点的就是排序咯)
3、输出结果。
3、if、switch、for、while语句
3.1 switch语句
要注意case穿透现象是什么,如何利用case穿透现象进行程序的编写。
当不利用case穿透时程序会很复杂:
使用case穿透改进如下
3.2 水仙花数,for语句的案例
关键点是记住,给一个指定数字,如何获取指定位置上的数字。
3.3 珠穆朗玛峰,while循环的案例
这里要注意,什么时候用for,什么时候用while。
若知道循环次数,for更好;若不知循环次数,则用while更好。
3.4 三种循环对比
do while:先执行后判断;
while:先判断后执行;
for:先判断后执行。
for、while的区别就是i的作用域不同,即结束后该变量能否再被使用。
死循环格式了解即可。
3.5 跳转控制语句continue、break
两者对比
continue:用于循环中,跳过某次循环的内容,执行下一次循环;
break:用于循环中,终止循环体内容的执行,即终止当前整个循环体的执行。
3.6 循环嵌套
注意两层循环是怎么分析出来的
3.7 Random
注意random的使用规则:
3.7 Random案例:猜数字
注意分析过程,很巧妙,要能回答如下三个问题:
如何生成1——100的随机数?
循环究竟选取for还是while?
如何结束循环?视频里用break。但是自己想的是定义一个是否猜对的标志变量。
4、IDEA
4.1 IDEA安装
公众号:软件安装管家目录安装专业版的破解版。
注意,别安装社区版,虽然免费,但是例如Spring功能没法一键配置。
4.2 IDEA编程HelloWorld
六步如下:
其次还需要知道,.java 文件编译后生成的 .class 文件,是在该目录下的 out 文件夹下。例如下图中 idea_test 是模块目录有 .java 文件,而 .class 文件是在 out 目录里。
4.3 IDEA项目结构
项目、模块、包、类(即 .java 文件):
4.4 IDEA中快捷键
4.5 IDEA中模块的分类
新建模块;
删除模块;
导入模块。
5、数组
5.1 数组的定义格式
推荐使用方法一。
5.2 数组的初始化
动态初始化 + 静态初始化。
5.2.1 数组动态初始化
定义:初始化时只指定数组长度,由系统为数组分配随机初始值。
格式如下: (其中new代表向内存申请空间)
5.2.2 数组访问
数组名[索引] 等同于 变量名,是一种特殊的变量名。
5.2.3 内存分配
一定要深刻理解第一行代码的过程;同时理解栈区与堆区;同时还要理解堆内存初始默认值。
5.2.4 多个数组内存图(指向不同)
5.2.5 多个数组内存图(指向相同)
1、
2、
5.2.6 数组静态初始化
注意:
1、即便知道数组长度,[ ]里面也不能写长度;
2、推荐简化格式,且简化格式里没有new关键字,但是要做到清楚这个过程是有new的。
5.2.7 数组操作中常见的问题:数组越界、空指针异常
索引越界:访问了数组中不存在的索引对应的元素,造成索引越界问题。
ArrayIndexOutOfBoundsException。看到这个错误一般反应过来大概率是索引越界。
空指针异常:访问的数据不再指向堆内存的数据,造成空指针异常。
NullPointerException。看到这个错误一般反应过来大概率是指向的为空。
package itheima_04;
//数组操作常见的两个小问题
/*
索引越界:访问了数组中不存在的索引对应的元素,造成索引越界问题。
ArrayIndexOutOfBoundsException。看到这个错误一般反应过来大概率是索引越界。
空指针异常:访问的数据不再指向堆内存的数据,造成空指针异常。
NullPointerException。看到这个错误一般反应过来大概率是指向的为空。
*/
public class ArrayDemo {
public static void main(String[] args) {
int[] arr = new int[3];
//System.out.println(arr[3]);
arr = null;
System.out.println(arr[0]);
}
}
5.2.8 数组常见操作:遍历and获取数组长度
遍历好说,for循环完事。但若不知道数组长度,就需要获取数组长度,要明白如何获取数组长度,以及遍历数组统一的格式。
遍历通用格式:
6、方法
6.1 定义
方法就是一个代码集,其实就是函数,需要先定义,再调用。
分为 带返回值的方法(int、boolean、float等等) 和 不带返回值的放法(void)。具体每一种又分是否带参数。
6.2 形参、实参
6.3 带返回值方法的定义和调用
1、定义
2、调用
推荐格式2,且要注意方法的返回值通常会使用变量接收,否则该返回值将毫无意义。
6.4 方法注意事项
1、方法不能嵌套定义
2、void 表示无返回值,可以省略return,也可以单独的写return,后面不加数据
6.5 方法的通用格式!!!
做到两个明确:
1、明确返回值类型:主要是明确方法操作完毕之后是否有数据返回,如果没有写void;如果有,则写对应的数据类型;
2、明确参数:主要是明确参数的类型和数量。
调用方法时:
1、void类型的方法,直接调用;
2、非void类型的方法,推荐用变量接收调用。
6.6 方法的重载!!!
方法重载通常用于创建完成一组任务相似但参数的类型或参数的个数不同的方法。
如何判断(注意是同时成立):
1、多个方法在一个类中;
2、多个方法具有相同的方法名;
3、多个方法的参数不相同,具体指:类型不同 或 数量不同 或 两者都不同。
4、重载仅针对同一个类中方法的名称与参数进行识别,与返回值无关。换句话说,不能通过返回值是否相同来判断两个方法是否构成重载。
注意下图中第四个,都不在同一个类中,自然不是方法的重载。
再比如下列代码,方法一、二、三为方法的重载,但是四、五却不是,代码放在IDEA里也会报错。
public class MethodDemo {
public static void main(String[] args) {
}
// 方法一
public static int sum(int a, int b) {
return a + b;
}
// 方法二
public static double sum(double a, double b) {
return a + b;
}
// 方法三
public static int sum(int a, int b, int c) {
return a + b + c;
}
// 方法四
public static boolean sum(int a, int b) {
return false;
}
// 方法五
public static int sum(int c, int d) {
return c + d;
}
}
6.7 方法的重载的练习
需求:使用方法重载的思想,设计比较两个整数是否相同的方法,兼容全整数类型(byte,short,int,long)。
注意每个方法中 System.out.println("数据类型");
,如果没有,实际判断不出来究竟是对应执行的那个方法,而加了这句,相当于不同重载方法有了不同的方法。
package itheima_05;
// 方法重载的练习
public class MethodTest {
public static void main(String[] args) {
System.out.println(comapre(10,20));
System.out.println(comapre((byte)10,(byte)20));
System.out.println(comapre((short)10,(short) 20));
System.out.println(comapre((long)10,(long)20));
System.out.println(comapre(10L,20L));
}
public static boolean comapre(int a, int b) {
System.out.println("int");
return a == b;
}
public static boolean comapre(byte a, byte b) {
System.out.println("byte");
return a == b;
}
public static boolean comapre(short a, short b) {
System.out.println("short");
return a == b;
}
public static boolean comapre(long a, long b) {
System.out.println("long");
return a == b;
}
}
6.8 方法的参数传递(基本类型)
一定深刻理解在内存里是如何进行的。形参的改变,并不会影响实际参数的值。
6.9 方法的参数传递(引用类型)
一定深刻理解在内存里是如何进行的。对于引用类型的参数,形参的改变,会影响实际参数的值。
7、Debug
7.1 Debug简述
如何加断点?
如何运行加了断点的程序?
看哪里?
点哪里?
如何删除断点?
7.2 Idea使用debug
关于具体的怎么使用,看如下文章即可(看1、2两篇基本就够,觉得想系统务必看第3篇,第四篇可以用到时候再看):
1、《Intellij IDEA调试功能使用总结(step over / step into / force step into/step out等)》
2、《IDEA调试程序按钮初探 (Step Over/Step Into/Force Step Into/Step Out/Evaluate Expression/Resume Program/条件断点)》
3、《史上最全的 IDEA Debug 调试技巧(超详细案例)》
4、《后悔没能早知道的IDEA调试功能之变量操作》
8、基础案例
8.1 导包三种方式
以Scanner为例,有三种方式:
1、手动导包;
2、快捷键导包:Alt + Enter;
3、自动导包
8.2 百钱百鸡(利用循环解带约束的三元一次方程组)
题目:
分析:
package itheima;
// 百钱买百鸡,如何利用循环解带约束的三元一次方程组
public class Test_05 {
public static void main(String[] args) {
for(int i=0; i<=20; i++) {
for(int j=0; j<=33; j++){
int z = 100 - i - j;
if(z%3==0 && 5*i+3*j+z/3==100){
System.out.println(i + "," + j + "," + z);
}
}
}
}
}
8.3 数组反转
需求:
分析:
1、定义一个数组,静态初始化;
2、循环遍历数组,这一次初始化语句定义两个循环变量,start、end,判断条件是start < end;
3、变量交换(定义临时空间);
4、遍历打印新的数组。
--------------------------------分割线:2023/4/4-----------------------------------
9、类和对象
9.1、类与对象的阐述
要知道:
1、什么是对象?
2、什么是面向对象?
3、什么是类?
4、什么是对象的属性、属性值?
5、什么是对象的行为?
6、类与对象的关系?
9.2、类的定义
要明确:
1、类的定义和组成;
2、如何定义一个类; 需要注意成员方法无static关键字。
package itheima_01;
/*
视频100: 类的定义
类的定义:
定义类;
编写类的成员变量;
编写类的方法
手机类:
类名:
Phone
成员变量:
品牌(brand)
价格(price)
方法:
打电话
发短信
*/
public class Phone {
// 成员变量
String brand;
int price;
// 成员方法
public void call(){
System.out.println("打电话");
}
public void sendMessage(){
System.out.println("发短信");
}
}
9.3、对象的使用
要掌握:如何创建对象;如何使用对象。
代码实例:注意如果不给成员变量赋初值的话,new在堆内存开辟初值时就会赋默认初值,所以刚开始是null、0。
public class PhoneDemo {
public static void main(String[] args) {
Phone p = new Phone();
System.out.println(p.brand);
System.out.println(p.price);
p.brand = "小米";
p.price = 3000;
System.out.println(p.brand);
System.out.println(p.price);
p.call();
p.sendMessage();
}
}
9.4、对象的使用之具体案例,学生
/*
学生类
*/
public class Student {
// 成员变量
String name;
int age;
// 成员方法
public void study(){
System.out.println("好好学习,天天向上");
}
public void doHomework(){
System.out.println("多写点作业吧");
}
}
/*
学生测试类
*/
public class StudentDemo {
public static void main(String[] args) {
Student s = new Student();
s.name = "zct";
s.age = 25;
System.out.println(s.name);
System.out.println(s.age);
s.study();
s.doHomework();
}
}
9.5、对象内存图
需要理解创建对象和使用对象在内存中的一个流程。分单个对象、多个对象。
9.5.1 单个对象内存图
1、
2、
3、
4、
5、
6、
7、注意这里study()方法执行到}后,就完了,就从栈内存释放了
8、
9、同样,如果main()方法执行完毕后,也会从栈内存释放。
9.5.2 多个对象内存图,指向不同
9.5.3 多个对象内存图,指向相同
9.6、成员变量和局部变量
要理解两者的定义和区别:
注意在方法声明上指的是形参:
9.7、封装
9.7.1、private关键字
通过对象名直接访问数据,会存在安全隐患。例如 s.age = -30 ,而年龄不可能为负。因此不让外界直接访问成员变量的值,才引出private关键字。
下图非常非常非常重要:
注意 get函数中,一般最好写个判断错误数据 ,如下
public class Student {
// 成员变量
String name;
//int age;
private int age;
// 成员方法
public void setAge(int a) {
if (a < 0 | a > 100) {
System.out.println("您输入的信息有误");
} else {
age = a;
}
}
public int getAge() {
return age;
}
public void show() {
System.out.println(name + "," + age); //注意这里age如果赋值失败,输出的是默认值0
}
}
public class StudentDemo {
public static void main(String[] args) {
Student s = new Student();
s.name = "zct";
//s.age = -30;
s.setAge(-30);
s.getAge();
s.show();
}
}
9.7.2、private关键字的使用
注意这里有两种不同的方法,获得其属性值。show的话格式就是固定,get的话就是可以更随意拼接。
--------------------------------分割线:2023/4/12-----------------------------------
9.7.3、this关键字的使用
1、为何要使用this关键字? 取名时为了直观,可能成员变量名和局部变量名重合。
改进: 用this来指代成员变量。
2.this关键字的用途:注意下图中三个箭头!!!
9.7.4、this内存原理
2.
3.
4.
9.7.5、封装总结
9.8、构造方法
构造方法的作用?
在最初定义成员变量时为成员赋初始值,防止一些出错。即new的时候直接初始化,不用调用get赋值了。
构造方法与一般方法的区别?
1、构造方法是一种特殊的方法。其会在创建对象时由java平台自动调用,不像一般方法,需要的时候才调用;
2、构造函数的函数名要与类名一样,而普通的函数只要符合标识符的命名规则即可 ;
3、构造函数没有返回值类型,但是可以加return,只不过idea会警告。
4、不能被static、final、synchronized、abstract和native修饰。构造方法不能被子类继承,所以用final和abstract修饰没有意义
构造方法的注意事项?
构造方法格式?
public class 类名{
修饰符 类名( 参数 ) { }
}
构造方法快捷键?
Alt+insert or Alt+Fn+insert
可以直接生成无参构造、有参构造、set、get等
代码实操:
Student类:
public class Student {
private String name;
private int age;
// 无参构造方法1
public Student() {}
// 无参构造方法2
// public Student() {
// this.name = "zct";
// this.age = 18;
// }
// 有参构造方法1
public Student(String name) {
this.name = name;
}
// 有参构造方法2
public Student(int age) {
this.age = age;
}
// 有参构造方法3
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public void show() {
System.out.println(name + "," + age);
}
}
StudentDemo类
public class StudentDemo {
public static void main(String[] args) {
// 创建对象
Student s1 = new Student();
s1.show(); // output: null,0。这里默认初值
Student s2 = new Student("zct");
s2.show(); // output: zct,0
Student s3 = new Student(18);
s3.show(); // output: null,18
Student s4 = new Student("zct", 18);
s4.show(); // output: zct,18
}
}
9.9、标准类即测试类的制作格式(非常重要)
代码:
Student类
public class Student {
// 成员变量
String name;
int age;
// 构造方法,包含无参和有参
public Student() {
}
public Student(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;
}
public void show() {
System.out.println(name + "," + age);
}
}
StudentDemo类
public class StudentDemo {
public static void main(String[] args) {
// 使用无参构成方法创建对象,并使用setXXX进行赋值,并用show打印
Student s1 = new Student();
s1.setName("zct");
s1.setAge(18);
s1.show(); // output: zct,18
// 使用有参构造方法直接创建带用户设定初值的对象,并用show打印
Student s2 = new Student("zct", 18);
s2.show(); // output: zct,18
}
}
10、API
10.1、API概述
如何查看java的API,官网地址: https://docs.oracle.com/javase/8/docs/api/。当然,也可以下载官方API中文文档。
1、查看类属于哪个包; 注意,java.lang包是不需要要导入的
2、查看类的功能信息描述;
3、查看构造方法(包含无参和有参);
4、看成员方法(着重看返回值,方法名,返回值)。
10.2、API练习
需求:
注意:
代码:
推荐先写右边,完事用一个变量去接收一个返回值,推荐快捷键
import java.util.Scanner;
public class API {
public static void main(String[] args) {
// 创建对象
Scanner sc = new Scanner(System.in);
// 接收数据
System.out.println("请输入要输入的字符串:");
String line = sc.nextLine(); // 推荐先写右边,完事用一个变量去接收一个返回值,推荐快捷键 Ctrl+Alt+v
// 打印数据
System.out.println("你所输入的字符串是:" + line);
}
}
11、String
11.1、String概述
11.2、String类常见的构造方法
推荐使用第四种 String s = "abc";
11.3、String对象的特点
要明白new建立的字符串
和 ""建立的字符串
两者在内存中的执行流程以及区别
11.4、String的比较
11.4.1 例子一
String不是基本类型,直接使用==
进行对象的比较,其实是引用类型的比较,即地址值的比较。而要比较包含的值,应该用equals()
函数。
所有对象的equals方法继承自Object类的方法,而String重写了equals方法的比较算法,它比较的是字符串的内容,即在堆中的了符序列。
字符串是一种比较特殊的对象,这里的特殊指的是在运行期间,它的赋值直接改变引用(当然,任何对象的赋值都是直接改变的引用,只不过字符串这种东西往往让人容易理解为它是在原来的基础上操作的,尤其是+=这类操作),而不是在原来所引用的内存块中做修改(因此有了StringBuilder类的出现,因为StringBuilder支持原本内容的改变,具体可见12.1)。
public class StringDemo2 {
public static void main(String[] args) {
// String类的构造方法得到字符串
char[] chs = {'a', 'b', 'c'};
String s1 = new String(chs);
String s2 = new String(chs);
// String类的直接赋值得到字符串
String s3 = "abc";
String s4 = "abc";
// 比较字符串对象地址值是否相同
System.out.println(s1 == s2); // output: false
System.out.println(s1 == s3); // output: false
System.out.println(s3 == s4); // output: true
// 比较字符串内容是否相同
System.out.println(s1.equals(s2)); // output: true
System.out.println(s1.equals(s3)); // output: true
System.out.println(s4.equals(s4)); // output: true
}
}
为什么s3 == s4
结果为true,可以看11.3图片说明,因为对于字符串常量的赋值,是依照“常量池”机制。
11.4.2 例子二
String s1 = "hello";
String s2 = "hello";
System.out.println(s1.equals(s2)); //true
System.out.println(s1 == s2); //true
按照上面的说法,第一个true不难理解。
而第2个之所以也为true是因为,java编译器用的类似于C语言中的"常量池机制",即在源代码中所有的字符串常量声明全部放在一块内存区域,因此当一个字符串声明时赋值的是一个字符串常量,那么如果"文字池"中有这个字符串常量,编译器将直接把它的引用赋值给这个变量。(可以看11.3,图片有堆、栈的图说明)
因此在用==
来比较s1和s2时,将会得到true。
String s1 = "hello";
String s2 = "hello";
s1 = s1 + "a";
s2 = s2 + "a";
System.out.println(s1.equals(s2)); //true
System.out.println(s1 == s2); //false
第3,4行的赋值操作在运行期间执行,根据上面的知识点3:两个变量的引用将会发生改变,即新开辟内存空间进行最终结果的存储。因此这时用==相比时将会得到false;
(在运行期间所得到的字符串内容,将不会放到所谓的"文字池"之中,然后如果有相同内容的变量引用相同内容,这样作的话需要每次字符串改变时需要检查它的内容,并再在文字池中查找看是否有相同内容的常量,太过浪费效率.)
("文字池机制"也许也是为什么字符串对象在作更改时,直接改变引用的一个原因,因为如果直接对引用的内存块作操作的话,另一个指向相同引用的字符串变量将也会发什么改变,发生逻辑混淆)
11.5、String案例之用户登录
需求:
代码:一定要先写单次实现,再用循环去实现。
public class 用户登录 {
public static void main(String[] args) {
// 1、定义已知的用户名和密码
String username = "zct";
String password = "18";
// 2、从键盘录入用户的用户名和密码
Scanner sc = new Scanner(System.in);
// System.out.println("请输入用户名:");
// String name = sc.nextLine();
// System.out.println("请输入密码:");
// String pwd = sc.nextLine();
// 3、使用equals()函数进行比较,成功则结束并给出提示信息,失败给出提示信息
// if (name.equals(username) && pwd.equals(password)) {
// System.out.println("登陆成功");
// } else {
// System.out.println("登陆失败,你还有几次机会");
// }
// 4、循环实现3次录入,由于已知,使用for循环
for (int i = 0; i < 3; i++) {
System.out.println("请输入用户名:");
String name = sc.nextLine();
System.out.println("请输入密码:");
String pwd = sc.nextLine();
if (name.equals(username) && pwd.equals(password)) {
System.out.println("登陆成功");
break;
} else {
if ((2-i)==0){
System.out.println("三次机会已用光,你的帐户已被锁定,请联系管理员");
} else{
System.out.println("登陆失败,你还有" + (2 - i) + "机会");
}
}
}
}
}
11.6、String案例之遍历
需求:
两个新知识点:
1、字符串的长度和数组的长度如何表示,
XXX.length()
;
2、XXX.charAT(int index),字符串的成员函数,获取字符串指定索引对应的元素。
3、遍历字符串的通用格式:
for (int i=0; i<s.length(); i++){s.charAT(i);
}
import java.util.Scanner;
// 遍历字符串
public class bianlizifuchuan {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("请输入你要遍历的字符串:");
String line = sc.nextLine();
for (int i = 0; i < line.length(); i++) {
System.out.println(line.charAt(i));
}
}
}
--------------------------------------2023/4/24,更新---------------------------------------------
11.7、String案例之统计字符次数
需求:
代码:
import java.util.Scanner;
public class tongjizifugeshu {
public static void main(String[] args) {
// 1、从键盘录入字符串
Scanner sc = new Scanner(System.in);
System.out.println("请输入字符串: ");
String line = sc.nextLine();
// 2、定义三个变量分别存储大写、小写、数字字符的个数
int daxie = 0;
int xiaoxie = 0;
int shuzi = 0;
// 3、遍历字符串,得到每一个字符
for (int i = 0; i < line.length(); i++) {
char ch = line.charAt(i);
// 4、对于得到的每个字符进行判断
if (ch >= 'A' && ch <= 'Z') {
daxie++;
} else if (ch >= 'a' && ch <= 'z') {
xiaoxie++;
} else if (ch >= '0' && ch <= '9') { //注意这里是'0',而不是0
shuzi++;
}
}
System.out.println("大写字母有" + daxie + "个");
System.out.println("小写字母有" + xiaoxie + "个");
System.out.println("数字有" + shuzi + "个");
}
}
11.8、String案例之数组转字符串
需求:
代码:
/*
步骤:
1、定义一个数组,静态初始化
2、定义一个方法,参数int[] arr,返回值String
3、在方法中:遍历数组,按照要求进行拼接
4、调用该方法,并定义一个变量接收其返回值
5、输出该返回值
*/
public class ArrayToString {
public static void main(String[] args) {
int[] arr = new int[]{1, 2, 3};
String s = arrayToString(arr);
System.out.println("转换的结果是: " + s);
}
// 定义一个方法,参数int[] arr,返回值String
public static String arrayToString(int[] arr) {
String s = "";
s += '[';
for (int i = 0; i < arr.length; i++) {
if (i == arr.length - 1) {
s += arr[i];
} else {
s += arr[i];
s += ", ";
}
}
s += ']';
return s;
}
}
11.9、String案例之字符串反转
需求(这里关键点是倒着遍历):
代码:
import java.util.Scanner;
public class ZiFuChuanFanZhuan {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("请输入要反转的字符串:");
String line = sc.nextLine();
String reverse_string = reverse(line);
System.out.println("反转后的字符串是:"+reverse_string);
}
// 定义一个方法,参数String,返回值String,倒着遍历
public static String reverse(String line) {
String s = "";
for(int i = line.length()-1; i >= 0; i--){
s += line.charAt(i);
}
return s;
}
}
12、StringBuilder
12.1 StringBuilder概述
1:
2:
3:
4(注意String和StringBuilder的区别):
12.2 StringBuilder之构造方法(即初始化)
具体查看官网文档《https://docs.oracle.com/javase/8/docs/api/》
这里主要讲两个:
代码:
/*
这里对于StringBuilder的构造方法进行说明
*/
public class StringBuilderConstructor {
public static void main(String[] args) {
//public StringBuilder():创建一个空白的字符串对象,不含有任何内容
StringBuilder sb = new StringBuilder();
System.out.println("sb: "+sb);
System.out.println("sb.length: "+sb.length());
//public StringBuilder():根据字符串内容,创建一个可变的字符串对象
StringBuilder sb2 = new StringBuilder("hello");
System.out.println("sb2: "+sb);
System.out.println("sb2.length: "+sb2.length());
}
}
12.3 StringBuilder之append和reverse方法
方法讲解:
代码(这里注意新的链式编程):
/*
这里对StringBuilder的append和reverse方法进行说明
*/
public class StringBuilderAppendReverse {
public static void main(String[] args) {
// 创建对象
StringBuilder sb = new StringBuilder();
// 1、public StringBuilder append() 添加一个字符串,返回的是一个StringBuilder对象
// 写法1,不推荐
// System.out.println("sb: "+sb);
// StringBuilder sb2 = sb.append("hello");
// System.out.println("sb2: "+sb2);
// System.out.println(sb == sb2);
// 写法2,推荐新手
// sb.append("hello");
// sb.append("world.");
// sb.append(100);
// System.out.println("sb: "+sb);
// 链式编程,推荐老手
//因为sb.append("hello")返回的是一个对象,所以可以再调用append方法
sb.append("hello").append("world.").append(100);
System.out.println("sb: "+sb);
// 2、public StringBuilder reverse() 反转一个字符串并将反转的字符串返回
sb.reverse();
System.out.println("sb: "+sb);
}
}
12.4 java的链式编程
参考12.3和12.7的具体代码即可
/*
这里对StringBuilder的append和reverse方法进行说明
*/
public class StringBuilderAppendReverse {
public static void main(String[] args) {
// 创建对象
StringBuilder sb = new StringBuilder();
// public StringBuilder append 添加一个字符串,返回的是一个StringBuilder对象
// 推荐新手
// sb.append("hello");
// sb.append("world.");
// sb.append(100);
// System.out.println("sb: "+sb);
// 链式编程,推荐老手
//因为sb.append("hello")返回的是一个对象,所以可以再调用append方法
sb.append("hello").append("world.").append(100);
System.out.println("sb: "+sb);
}
}
// 定义一个方法,该方法能够反转字符串,参数String s,返回值String
public static String myReverse(String s) {
// StringBuilder sb = new StringBuilder(s);
// sb.reverse();
// String ss = sb.toString();
// return ss;
// 等价简便写法
return new StringBuilder(s).reverse().toString();
}
12.5 StringBuilder和String的互换
1、为什么要互换?
因为StringBuilder有两个很好用的方法,append和reverse,但String却不能直接用。
因此可以先转化为StringBuilder调用那两个方法,再转化回来成String即可。
2、如何转化?
3、代码:
public class StringBuilder2String {
public static void main(String[] args) {
/*
1、StringBuilder转换为String:
public String toString()
*/
StringBuilder sb = new StringBuilder();
sb.append("hello");
// String s = sb; // 错误写法
String s = sb.toString();
System.out.println("s: " + s);
// 2、String转化为StringBuilder
String s2 = "hello";
// StringBuilder sb2 = s2; // 错误写法
StringBuilder sb2 = new StringBuilder(s2);
System.out.println("sb2: " + sb2);
}
}
12.6 字符串拼接使用StringBuilder改造版
1、需求和思路:
2、why:
此题之前String那里做过一模一样的,但是那样会很浪费时间和存储空间,因此这里使用StringBuilder进行改造升级。
3、代码:
/*
1、定义一个int类型的数组,并使用静态初始化
2、定义一个方法,该方法能将字符串进行拼接,参数int[] arr,返回值Srting
3、在该方法中使用StringBuilder按要求进行拼接
4、调用该方法,并使用一个变量接收
5、打印该变量
*/
public class ZiFuChuanPinJie {
public static void main(String[] args) {
// 定义一个int类型的数组,并使用静态初始化
int[] arr = new int[]{1, 2, 3};
// 调用该方法,并使用一个变量接收
String s = arrayToString(arr);
// 打印该变量
System.out.println("拼接后的结果:" + s);
}
// 定义一个方法,该方法能将字符串进行拼接,参数int[] arr,返回值Srting
public static String arrayToString(int[] arr) {
StringBuilder sb = new StringBuilder();
//在该方法中使用StringBuilder按要求进行拼接
sb.append("[");
for (int i = 0; i < arr.length; i++) {
if (i == arr.length-1) {
sb.append(arr[i]);
} else {
sb.append(arr[i]).append(",");
}
}
sb.append("]");
String s = sb.toString();
return s;
}
}
12.7 字符串反转使用StringBuilder改造版
1、需求和思路:
2、why:
此题之前String那里做过一模一样的,但是那样会很浪费时间和存储空间,因此这里使用StringBuilder进行改造升级。
3、代码(注意这里的链式编程)
import java.util.Scanner;
/*
字符串反转
*/
public class StringReverse {
public static void main(String[] args) {
// 创建一个对象,从键盘录入字符串
Scanner sc = new Scanner(System.in);
System.out.println("请输入要反转的字符串: ");
String s = sc.nextLine();
// 调用该方法,并用一个变量接收
String ss = myReverse(s);
// 打印该变量
System.out.println("反转后的结果为:" + ss);
}
// 定义一个方法,该方法能够反转字符串,参数String s,返回值String
public static String myReverse(String s) {
// StringBuilder sb = new StringBuilder(s);
// sb.reverse();
// String ss = sb.toString();
// return ss;
// 等价简便写法
return new StringBuilder(s).reverse().toString();
}
}
12.8 StringBuilder帮助文档
黑马主要讲了两个构造方法和三个常用方法:
官方文档:
《https://docs.oracle.com/javase/8/docs/api/》
13、ArrayList集合
13.1 ArrayList概述
1、Why?
因为数组长度是固定的,万一要变怎么办?因此要ArrayList。
ArrayList本质就是一个可变长的数组。
2、总结:
13.2 ArrayList构造方法、添加方法
1、具体介绍:
2、代码:
/*
ArrayList的构造方法和添加方法
*/
import java.util.ArrayList;
public class AraayListDemo_01 {
public static void main(String[] args) {
// 创建一个对象
// ArrayList<String> array = new ArrayList<>(); // 仅支持JDK7.0以后的版本
ArrayList<String> array = new ArrayList<String>();
System.out.println("array:" + array); // output: array:[]
array.add("hello");
array.add("world");
array.add("sb");
System.out.println("array: " + array); // output: array: [hello, world, sb]
array.add(2,"xxx");
System.out.println("array: " + array); // output: array: [hello, world, xxx, sb]
}
}
13.3 ArrayList之常用方法
1、总览:
2、代码:
/*
对于ArrayList常见的方法进行说明
*/
import java.util.ArrayList;
public class ArrayListDemo_02 {
public static void main(String[] args) {
// 创建对象
ArrayList<String> array = new ArrayList<String> ();
array.add("hello");
array.add("world");
array.add("java");
// System.out.println(array.remove("world"));
// System.out.println(array.remove("javase"));
// System.out.println(array.remove(2));
// System.out.println(array.remove(4)); // IndexOutOfBoundsException
// System.out.println(array.set(1,"javase"));
// System.out.println(array.set(2,"javaee"));
// System.out.println(array.get(2));
System.out.println(array.size());
System.out.println("array: " + array);
}
}
13.4 ArrayList之遍历
1、需求:
2、代码:
/*
遍历ArrayList
*/
import java.util.ArrayList;
public class ArrayListDemo_03 {
public static void main(String[] args) {
// 创建对象
ArrayList<String> array = new ArrayList<String> ();
// 添加内容
array.add("aaa");
array.add("bbb");
array.add("ccc");
// 遍历
for(int index=0; index < array.size(); index++) {
String s = array.get(index);
System.out.println(s);
}
}
}
13.5 ArrayList之存储学生对象并遍历
1、需求和思路:
2、代码(注意这里用到了之前标准类的格式,不要忘记啦):
/*
标准类:
1、成员变量:使用private修饰
2、构造方法
一个无参,一个有参
3、成员方法
每个成员变量均对应一个getXXX()/setXXX()
show()
4、创建对象并使用两种方法创建对象
*/
public class Student {
// 成员变量
private String name;
private int age;
// 构造方法
public Student() {};
public Student(String name, int age) {
this.name = name;
this.age = age;
}
// 成员方法
public void setName(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
public void setAge(int age) {
this.age = age;
}
public int getAge() {
return this.age;
}
public void show() {
System.out.println("name: " + this.name);
System.out.println("age: " + this.age);
}
}
import java.util.ArrayList;
public class ArrarListDemo_01 {
public static void main(String[] args) {
// 创建ArrayList对象
ArrayList<Student> arrayStuent = new ArrayList<Student>();
// 创建学生对象,这里使用带参构造创建
Student stu1 = new Student("aaa", 18);
Student stu2 = new Student("bbb", 20);
Student stu3 = new Student("ccc", 22);
// 添加学生对象至集合中
arrayStuent.add(stu1);
arrayStuent.add(stu2);
arrayStuent.add(stu3);
// 遍历集合
for (int index=0; index < arrayStuent.size(); index++) {
Student s = arrayStuent.get(index);
System.out.println(s.getName()+","+s.getAge());
}
}
}
13.6 ArrayList之存储学生对象并遍历升级版
1、需求和思路:
2、代码:
/*
标准类:
1、成员变量:使用private修饰
2、构造方法
一个无参,一个有参
3、成员方法
每个成员变量均对应一个getXXX()/setXXX()
show()
4、创建对象并使用两种方法创建对象
*/
public class Student {
// 成员变量
private String name;
private String age;
// 构造方法
public Student() {};
public Student(String name, String age) {
this.name = name;
this.age = age;
}
// 成员方法
public void setName(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
public void setAge(String age) {
this.age = age;
}
public String getAge() {
return this.age;
}
public void show() {
System.out.println("name: " + this.name);
System.out.println("age: " + this.age);
}
}
import java.util.ArrayList;
import java.util.Scanner;
public class ArrarListDemo_01 {
public static void main(String[] args) {
// 创建ArrayList对象
ArrayList<Student> arrayStuent = new ArrayList<Student>();
// // 从键盘录入学生姓名
// Scanner sc = new Scanner(System.in);
//
// System.out.println("请输入学生的姓名:");
// String name = sc.nextLine();
// System.out.println("请输入学生的年龄:");
// String age = sc.nextLine();
// // 创建学生对象,这里使用无参构造并调用set方法创建
// Student stu = new Student();
// stu.setName(name);
// stu.setAge(age);
//
// // 添加学生对象至集合中
// arrayStuent.add(stu);
// 添加
System.out.println("您以共要输入3位学生的信息:");
for (int num=0; num < 3; num++) {
createStudentAndAdd(arrayStuent, num+1);
}
// 遍历集合
System.out.println("您所遍历的学生信息为:");
for (int index=0; index < arrayStuent.size(); index++) {
Student s = arrayStuent.get(index);
System.out.println(s.getName()+","+s.getAge());
}
}
// 由于要添加3个学生,因此为了代码复用性,定义一个方法更合适
/*
三个明确:
参数类型:ArrayList<Student> arrayStuent, int i(代表第几位)
返回值类型:void
*/
public static void createStudentAndAdd(ArrayList<Student> arrayStuent, int i) {
// 从键盘录入学生姓名
Scanner sc = new Scanner(System.in);
System.out.println("请输入第"+ i +"位学生的姓名:");
String name = sc.nextLine();
System.out.println("请输入第"+ i +"位学生的年龄:");
String age = sc.nextLine();
// 创建学生对象,这里使用无参构造并调用set方法创建
Student stu = new Student();
stu.setName(name);
stu.setAge(age);
// 添加学生对象至集合中
arrayStuent.add(stu);
}
}
14、学生管理系统
14.1 需求和思路分析
1、需求:
2、实现思路:
14.2 定义学生类
1、思路:
2、注意:
1、标准类是如何定义的。
2、有参的构造方法,有几个成员变量,它参数就有几个。
3、注意这里面的方法都没有statistic的修饰。
4、注意快捷键的使用,fn+alt+insert,可以快速插入构造方法和set/get方法。
3、代码:
/*
注意,fn+alt+insert键可快速生成构造方法和set/get方法
*/
public class Student {
// 定义成员变量: 学号、姓名、年龄、地址
private String id;
private String name;
private String age;
private String address;
// 定义构造方法:无参+有参
public Student() {
}
public Student(String id, String name, String age, String address) {
this.id = id;
this.name = name;
this.age = age;
this.address = address;
}
// 每个成员变量给出对应的set/get方法
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
14.3 主界面的编写
1、思路
2、注意新知识
System.exit(0); // JVM退出,可以理解为让程序结束
自己则是定义的flag变量,去结束死循环
3、代码
public static void main(String[] args) {
while (true) {
// 显示主界面信息
System.out.println("--------" + "欢迎来到学生管理系统" + "--------");
System.out.println("1 添加学生");
System.out.println("2 删除学生");
System.out.println("3 修改学生");
System.out.println("4 查看所有学生");
System.out.println("5 退出");
System.out.println("请输入你的选择:");
// 从键盘录入数据
Scanner sc = new Scanner(System.in);
int option = sc.nextInt();
// Switch语句完成操作的选择
switch (option) {
case 1:
System.out.println("添加学生");
break;
case 2:
System.out.println("删除学生");
break;
case 3:
System.out.println("修改学生");
break;
case 4:
System.out.println("查看所有学生");
break;
case 5:
System.out.println("退出");
// break;
System.exit(0); // JVM退出
default:
System.out.println("您输入的信息有误,回到主界面请重新输入:");
break;
}
// if (option==5) {
// break;
// }
}
}
14.4 添加学生的编写
1、需求
2、代码
// 添加学生 参数:arrayList 返回值:空
public static void addStudent(ArrayList<Student> array) {
// 打印提示信息并从键盘录入学生信息
Scanner sc = new Scanner(System.in);
System.out.println("请输入学生学号:");
String id = sc.nextLine();
System.out.println("请输入学生姓名:");
String name = sc.nextLine();
System.out.println("请输入学生年龄:");
String age = sc.nextLine();
System.out.println("请输入学生住址:");
String address = sc.next();
// 将录入的信息赋值给创建好的学生对象
Student stu = new Student();
stu.setId(id);
stu.setName(name);
stu.setAge(age);
stu.setAddress(address);
// 将学生对象添加到集合中
array.add(stu);
// 给出提示信息”添加成功“
System.out.println("添加成功");
}
14.5 查看所有学生的编写
1、思路:
2、升级版
3、代码
注意
1、这里黑马里讲了关于如何使用\t控制输出信息的格式控制。
2、自己用的是if else。但else里内容太多,不如黑马的直观。不要else,而是在if里加一个return即可,即告诉程序如果满足if,则不用再执行后面的代码了。
// 查看所有学生 参数:arrayList 返回值:空
public static void viewStudent(ArrayList<Student> array) {
// // 先判断集合中是否有学生信息
// if (array.size() == 0) {
// System.out.println("还未添加任何学生信息,请返回主界面添加学生信息");
// } else {
// // 显示表头信息
// /*
// 注意,\t要放在""里面,一个\t相当于按了一个Tab键进行缩进
// \t是补全当前字符串长度到8的整数倍,最少1个最多8个空格,补多少要看你\t前字符串长度。
// 比如当前字符串长度10,那么\t后长度是16,也就是补6个空格。
// 如果当前字符串长度12,此时\t后长度是16,补4个空格。
// */
// System.out.println("0123456701234567012345670123456701234567"); // 自己加的技巧
// System.out.println("学号" + "\t\t" + "姓名" + "\t\t" + "年龄" + "\t\t" + "居住地");
// // 从集合中依次取出学生信息,并按照格式显示,年龄补充岁
// for (int i = 0; i < array.size(); i++) {
// // 打印学生的信息
// Student s = array.get(i);
// System.out.println(s.getId() + "\t" + s.getName() + "\t" + s.getAge() + "岁\t" + s.getAddress());
// }
// }
// 先判断集合中是否有学生信息
if (array.size() == 0) {
System.out.println("还未添加任何学生信息,请返回主界面添加学生信息");
return; // 告诉程序不再往下执行了
}
// 显示表头信息
/*
注意,\t要放在""里面,一个\t相当于按了一个Tab键进行缩进
\t是补全当前字符串长度到8的整数倍,最少1个最多8个空格,补多少要看你\t前字符串长度。
比如当前字符串长度10,那么\t后长度是16,也就是补6个空格。
如果当前字符串长度12,此时\t后长度是16,补4个空格。
*/
System.out.println("0123456701234567012345670123456701234567"); // 自己加的技巧
System.out.println("学号" + "\t\t" + "姓名" + "\t\t" + "年龄" + "\t\t" + "居住地");
// 从集合中依次取出学生信息,并按照格式显示,年龄补充岁
for (int i = 0; i < array.size(); i++) {
// 打印学生的信息
Student s = array.get(i);
System.out.println(s.getId() + "\t" + s.getName() + "\t" + s.getAge() + "岁\t" + s.getAddress());
}
}
14.6 删除学生的编写
1、思路:
2、升级版:
3、代码:
注意
1、判断id和s.getId()一定要用equals。因为是执行过程中的String,用==比较,比较的是引用即地址,会永远不等。不懂的看此篇文章11.4
2、这里的技巧就是定义index去保存查询到的索引。黑马里没有定义isExitStudent,因为index==-1也可以判断不存在学生信息。但我这里定义了感觉更清晰!!!
// 删除学生 参数:arrayList 返回值:空
// 为了简单,这里仅实现了根据学号删除学生信息的功能
public static void deleteStudent(ArrayList<Student> array) {
if (array.size() == 0) {
System.out.println("没有任何学生信息,返回主界面");
} else {
// 从键盘录入待删除的学生的学号
Scanner sc = new Scanner(System.in);
System.out.println("请输入要删除学生的学号:");
String id = sc.nextLine();
// 根据学号查出该生在集合中的索引
boolean isExitStudent = false; //标志
int index = -1; //保存查询到的学生在集合中的索引
for (int i = 0; i < array.size(); i++) {
Student s = array.get(i);
// if (id == s.getId()) //错误写法,因为是执行过程中的String,用==比较,比较的是引用即地址,会永远不等。
if (id.equals(s.getId())) {
System.out.println("查到该学生,信息如下:");
System.out.println("该生学号为:" + s.getId());
System.out.println("该生姓名为:" + s.getName());
System.out.println("该生年龄为:" + s.getAge());
System.out.println("该生地址为:" + s.getAddress());
index = i; //保存索引,方便修改
isExitStudent = true;
break;
}
}
if (isExitStudent == true) {
// 删除学生信息
array.remove(index);
System.out.println("删除成功");
} else {
System.out.println("无该生信息,返回主界面");
}
}
}
14.7 修改学生的编写
1、思路:
2、升级版
3、代码
注意:
替换的是集合中Student实例,因此需要创建新的临时Student实例,去整体替换。而非去替换Student的学号、姓名、年龄、住址。
// 修改学生 参数:arrayList 返回值:空
public static void modifyStudent(ArrayList<Student> array) {
if (array.size() == 0) {
System.out.println("没有任何学生信息,返回主界面");
} else {
// 从键盘录入待修改的学生的学号
Scanner sc = new Scanner(System.in);
System.out.println("请输入要修改学生的学号:");
String id = sc.nextLine();
// 根据学号查出该生在集合中的索引
boolean isExitStudent = false; //标志
int index = -1; //保存查询到的学生在集合中的索引
// for(int i=0; i<array.size(); i++) //错误写法
for (int i = 0; i < array.size(); i++) {
if (id.equals(array.get(i).getId())) {
Student s = array.get(i);
System.out.println("查到该学生,信息如下:");
System.out.println("该生学号为:" + s.getId());
System.out.println("该生姓名为:" + s.getName());
System.out.println("该生年龄为:" + s.getAge());
System.out.println("该生地址为:" + s.getAddress());
index = i; //保存索引,方便修改
isExitStudent = true;
break;
}
}
if (isExitStudent == true) {
// 从键盘录入修改的信息
System.out.println("请输入要修改后学生的学号:");
String newId = sc.nextLine();
System.out.println("请输入学生的新姓名:");
String newName = sc.nextLine();
System.out.println("请输入学生的新年龄:");
String newAge = sc.nextLine();
System.out.println("请输入学生的新住址:");
String newAddress = sc.nextLine();
// 将信息赋值给临时创建的Student对象,并修改集合中的指定Student对象
Student stuTemp = new Student();
stuTemp.setId(newId);
stuTemp.setName(newName);
stuTemp.setAge(newAge);
stuTemp.setAddress(newAddress);
// 修改学生信息
array.set(index, stuTemp);
System.out.println("修改成功");
} else {
System.out.println("无该生信息,返回主界面");
}
}
}
14.8 解决添加学生学号重复的问题
1、思路:
2、全部代码:
import java.util.ArrayList;
import java.util.Scanner;
public class StudentManagerByHeiMa {
public static void main(String[] args) {
// 创捷一个集合,用于存储学生对象
ArrayList<Student> stuArray = new ArrayList<Student>();
while (true) {
// 显示主界面信息
System.out.println("--------" + "欢迎来到学生管理系统" + "--------");
System.out.println("1 添加学生");
System.out.println("2 删除学生");
System.out.println("3 修改学生");
System.out.println("4 查看所有学生");
System.out.println("5 退出");
System.out.println("请输入你的选择:");
// 从键盘录入数据
Scanner sc = new Scanner(System.in);
int option = sc.nextInt();
// Switch语句完成操作的选择
switch (option) {
case 1:
// System.out.println("添加学生");
addStudent(stuArray);
break;
case 2:
// System.out.println("删除学生");
deleteStudent(stuArray);
break;
case 3:
// System.out.println("修改学生");
modifyStudent(stuArray);
break;
case 4:
// System.out.println("查看所有学生");
viewStudent(stuArray);
break;
case 5:
System.out.println("退出");
// break;
System.exit(0); // JVM退出
default:
System.out.println("您输入的信息有误,回到主界面请重新输入:");
break;
}
// if (option==5) {
// break; // 结束循环
// }
}
}
// 添加学生 参数:arrayList 返回值:空
public static void addStudent(ArrayList<Student> array) {
// 打印提示信息并从键盘录入学生信息
Scanner sc = new Scanner(System.in);
String id;
// 为了能够回到这里,这里使用循环实现
while (true) {
System.out.println("请输入学生学号:");
id = sc.nextLine();
boolean flag = isExitSameId(array, id);
if (flag) {
System.out.println("你输入的学号已被占用,请重新输入学号");
} else {
break;
}
}
System.out.println("请输入学生姓名:");
String name = sc.nextLine();
System.out.println("请输入学生年龄:");
String age = sc.nextLine();
System.out.println("请输入学生住址:");
String address = sc.next();
// 将录入的信息赋值给创建好的学生对象
Student stu = new Student();
stu.setId(id);
stu.setName(name);
stu.setAge(age);
stu.setAddress(address);
// 将学生对象添加到集合中
array.add(stu);
// 给出提示信息”添加成功“
System.out.println("添加成功");
}
// 删除学生 参数:arrayList 返回值:空 为了简单,这里仅实现了根据学号删除学生信息的功能
public static void deleteStudent(ArrayList<Student> array) {
if (array.size() == 0) {
System.out.println("没有任何学生信息,返回主界面");
} else {
// 从键盘录入待删除的学生的学号
Scanner sc = new Scanner(System.in);
System.out.println("请输入要删除学生的学号:");
String id = sc.nextLine();
// 根据学号查出该生在集合中的索引
boolean isExitStudent = false; //标志
int index = -1; //保存查询到的学生在集合中的索引
for (int i = 0; i < array.size(); i++) {
Student s = array.get(i);
// if (id == s.getId()) //错误写法,因为是执行过程中的String,用==比较,比较的是引用即地址,会永远不等。
if (id.equals(s.getId())) {
System.out.println("查到该学生,信息如下:");
System.out.println("该生学号为:" + s.getId());
System.out.println("该生姓名为:" + s.getName());
System.out.println("该生年龄为:" + s.getAge());
System.out.println("该生地址为:" + s.getAddress());
index = i; //保存索引,方便修改
isExitStudent = true;
break;
}
}
if (isExitStudent == true) {
// 删除学生信息
array.remove(index);
System.out.println("删除成功");
} else {
System.out.println("无该生信息,返回主界面");
}
}
}
// 修改学生 参数:arrayList 返回值:空
public static void modifyStudent(ArrayList<Student> array) {
if (array.size() == 0) {
System.out.println("没有任何学生信息,返回主界面");
} else {
// 从键盘录入待修改的学生的学号
Scanner sc = new Scanner(System.in);
System.out.println("请输入要修改学生的学号:");
String id = sc.nextLine();
// 根据学号查出该生在集合中的索引
boolean isExitStudent = false; //标志
int index = -1; //保存查询到的学生在集合中的索引
// for(int i=0; i<array.size(); i++) //错误写法
for (int i = 0; i < array.size(); i++) {
if (id.equals(array.get(i).getId())) {
Student s = array.get(i);
System.out.println("查到该学生,信息如下:");
System.out.println("该生学号为:" + s.getId());
System.out.println("该生姓名为:" + s.getName());
System.out.println("该生年龄为:" + s.getAge());
System.out.println("该生地址为:" + s.getAddress());
index = i; //保存索引,方便修改
isExitStudent = true;
break;
}
}
if (isExitStudent == true) {
// 从键盘录入修改的信息
System.out.println("请输入要修改后学生的学号:");
String newId = sc.nextLine();
System.out.println("请输入学生的新姓名:");
String newName = sc.nextLine();
System.out.println("请输入学生的新年龄:");
String newAge = sc.nextLine();
System.out.println("请输入学生的新住址:");
String newAddress = sc.nextLine();
// 将信息赋值给临时创建的Student对象,并修改集合中的指定Student对象
Student stuTemp = new Student();
stuTemp.setId(newId);
stuTemp.setName(newName);
stuTemp.setAge(newAge);
stuTemp.setAddress(newAddress);
// 修改学生信息
array.set(index, stuTemp);
System.out.println("修改成功");
} else {
System.out.println("无该生信息,返回主界面");
}
}
}
// 查看所有学生 参数:arrayList 返回值:空
public static void viewStudent(ArrayList<Student> array) {
// // 先判断集合中是否有学生信息
// if (array.size() == 0) {
// System.out.println("还未添加任何学生信息,请返回主界面添加学生信息");
// } else {
// // 显示表头信息
// /*
// 注意,\t要放在""里面,一个\t相当于按了一个Tab键进行缩进
// \t是补全当前字符串长度到8的整数倍,最少1个最多8个空格,补多少要看你\t前字符串长度。
// 比如当前字符串长度10,那么\t后长度是16,也就是补6个空格。
// 如果当前字符串长度12,此时\t后长度是16,补4个空格。
// */
// System.out.println("0123456701234567012345670123456701234567"); // 自己加的技巧
// System.out.println("学号" + "\t\t" + "姓名" + "\t\t" + "年龄" + "\t\t" + "居住地");
// // 从集合中依次取出学生信息,并按照格式显示,年龄补充岁
// for (int i = 0; i < array.size(); i++) {
// // 打印学生的信息
// Student s = array.get(i);
// System.out.println(s.getId() + "\t" + s.getName() + "\t" + s.getAge() + "岁\t" + s.getAddress());
// }
// }
// 先判断集合中是否有学生信息
if (array.size() == 0) {
System.out.println("还未添加任何学生信息,请返回主界面添加学生信息");
return; // 告诉程序不再往下执行了
}
// 显示表头信息
/*
注意,\t要放在""里面,一个\t相当于按了一个Tab键进行缩进
\t是补全当前字符串长度到8的整数倍,最少1个最多8个空格,补多少要看你\t前字符串长度。
比如当前字符串长度10,那么\t后长度是16,也就是补6个空格。
如果当前字符串长度12,此时\t后长度是16,补4个空格。
*/
System.out.println("0123456701234567012345670123456701234567"); // 自己加的技巧
System.out.println("学号" + "\t\t" + "姓名" + "\t\t" + "年龄" + "\t\t" + "居住地");
// 从集合中依次取出学生信息,并按照格式显示,年龄补充岁
for (int i = 0; i < array.size(); i++) {
// 打印学生的信息
Student s = array.get(i);
System.out.println(s.getId() + "\t" + s.getName() + "\t" + s.getAge() + "岁\t" + s.getAddress());
}
}
// 判断是否纯在相同学号 参数:arrayList、id 返回值:boolean
public static boolean isExitSameId(ArrayList<Student> array, String id) {
for (int i = 0; i < array.size(); i++) {
Student s = array.get(i);
if (id.equals(s.getId())) {
return true; // 该学号已被占用
}
}
return false; // 该学号未被占用
}
}
15、继承
15.1、继承概述
继承是面向对象三大特征之一,可以使得子类具有父类的属性和方法,还可以在子类中重新定义、追加属性和方法。
继承中子类的特点:
- 子类可以有父类的内容;
- 子类还可以有自己的内容。
15.2、继承格式
格式:
代码:
public class Fu {
public void show() {
System.out.println("调用一个show方法");
}
}
public class Zi extends Fu{
public void myMethod() {
System.out.println("调用一个myMethod方法");
}
}
/*
测试类
*/
public class Demo {
public static void main(String[] args) {
Fu f = new Fu();
f.show();
Zi z = new Zi();
z.myMethod();
z.show();
}
}
15.3、继承好坏、什么时候使用
15.4、继承中变量访问的特点
1、结论(其实就是就近原则):
那如果就要访问本类成员变量、父类成员变量呢?this和super关键字即可。
2、代码:
15.5、super关键字
1、总结:
2、代码:
public class Fu {
public int age = 40;
}
public class Zi extends Fu{
public int age = 20;
public void show() {
int age = 30;
// 访问方法中的局部变量age
System.out.println(age);
// 访问本类中的成员变量age
System.out.println(this.age);
// 访问父类中的成员变量age
System.out.println(super.age);
}
}
/*
测试类
*/
public class Demo {
public static void main(String[] args) {
// 创建对象,调用方法
Zi z = new Zi();
z.show();
}
}
15.6、继承中构造方法的访问特点
1、子类中所有的构造方法默认都会访问父类中无参的构造方法
为什么?
每一个子类的无参构造方法的第一条默认语句都是
super()
,推荐不写此句,因为系统已经默认了。由15.5的知识点,super()就代表访问父类的无参构造方法。
问题又来了,为什么要这样设计?
因为子类会继承父类的数据,甚至可能使用父类的数据。因此子类初始化前,父类一定要初始化完成,而构造方法作用就是初始化,故要先访问父类的构造方法。
2、如果父类中没有无参构造方法,只有含参构造方法,那么子类初始化时会报错。
为什么呢?
一个类中,如果不含带参构造方法,系统会默认创建一个无参构造方法;但如果已经含有一个带参构造方法,系统则不会主动创建无参构造方法。
而每一个子类的无参构造方法的第一条默认语句都是super()
,想要先访问父类无参构造方法,但是却找不到父类的无参构造方法,因此自然报错。
怎么办呢?
- 通过
super(参数)
去显示地访问父类中的含参构造方法;- 在父类中自己提供一个无参构造方法。
3、
15.7、继承中成员方法的访问特点
15.8、super在内存图中的过程
局部变量存栈区,全局、成员变量存堆区
自己再看一遍!!!
https://www.bilibili.com/video/BV18J411W7cE?p=156&vd_source=763a5e93fb502e71e42ff76a6fe1ae7c
15.9、方法重写
收获:
1、@Override 帮助检查方法重写时是否会出现拼写错误 ;
2、调用父类方法时最好通过super关键字访问,而不是出现和父类一样的代码;
3、方法重写快捷方式:直接写父类的函数名,一回车后会自动生成。
code:
public class Phone {
public void call(String name) {
System.out.println("给" + name + "打电话");
}
}
public class NewPhone extends Phone{
/*
public void call(String name) {
System.out.println("给" + name + "开视频");
// System.out.println("给" + name + "打电话");
super.call(name);
}
*/
@Override
public void call(String name){
System.out.println("给" + name + "打电话");
super.call(name);
}
}
public class PhoneDemo {
public static void main(String[] args) {
Phone p = new Phone();
p.call("林青霞");
System.out.println("-------");
NewPhone np = new NewPhone();
np.call("林青霞");
}
}
15.10、方法重写注意事项
- 私有方法不能被重写(父类的私有成员子类是无法继承的);
- 子类方法访问权限不能低于父类(public > 默认 > private)。
15.11、继承中注意事项
15.12、继承案例之老师与学生
注意事项:
1、定义Teacher类时,忘了写默认无参构造,在PersonDemo时无参初始化也能成功,因为系统会默认出一个Teacher() {} 的无参构造方法。但是想有参初始化时就要报错,因为Teacher类里都没有有参构造方法,因此需要在Teacher类里再定义有参构造方法,且加上无参构造(一旦给了有参,系统就不自动加无参,那么无参初始化时必然报错)。故:即便Teacher继承Person,也应该去定义自己的无参 + 有参构造方法,且有参构造方法既然是继承Person的有参构造方法,那就应该通过super(name,age)关键字去实现,如果按照this去访问就会报错,因为本身都没有name和age。
2、定义类的标准流程(成员变量、无参构造、有参构造、set、get、成员方法)
3、快捷键 Alt+Fn+insert
4、自己老爱忘写 extends
5、如何利用super访问父类的成员变量、构造方法、成员方法,要记得。
6、子类中无参构造方法默认执行super(),只是推荐不写而已。
public class Person {
private String name;
private int age;
public Person() {
}
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;
}
}
public class Teacher extends Person{
public Teacher() {
}
public Teacher(String name, int age) {
/* 报错写法
this.name = name;
this.age = age
*/
/* 错误写法
super.name = name;
super.age = age;
*/
super(name,age);
}
public void teach(){
System.out.println("用爱成就每一位学员");
}
}
public class PersonDemo {
public static void main(String[] args) {
// 1、无参构造初始化
Teacher t1 = new Teacher();
t1.setName("林青霞");
t1.setAge(30);
System.out.println(t1.getName() + "," + t1.getAge());
t1.teach();
// 2、有参构造初始化
Teacher t2 = new Teacher("风清扬", 33);
System.out.println(t2.getName() + "," + t2.getAge());
t2.teach();
Student s1 = new Student();
s1.setName("张三");
s1.setAge(22);
System.out.println(s1.getName() + "," + s1.getAge());
s1.study();
Student s2 = new Student("李四", 21);
System.out.println(s2.getName() + "," + s2.getAge());
s2.study();
}
}
public class Student extends Person {
public Student() {
}
public Student(String name, int age){
super(name, age);
}
public void study(){
System.out.println("好好学习,天天向上");
}
}
15.13、继承案例之猫与狗
注意事项:
- 生成无参、带参构造方法、set、get方法的快捷键的使用(Alt+Fn+insert),父类和子类都能用
分析如下:
思路如下:
code:
public class Animal {
private String name;
private int age;
public Animal() {
}
public Animal(String name, int age) {
this.name = name;
this.age = age;
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
}
public class Cat extends Animal{
public Cat() {
}
public Cat(String name, int age) {
super(name, age);
}
public void catchMouse(){
System.out.println("猫抓老鼠");
}
}
public class Dog extends Animal{
public Dog() {
}
public Dog(String name, int age) {
super(name, age);
}
public void eatShit(){
System.out.println("狗爱吃屎");
}
}
public class AnimalDemo {
public static void main(String[] args) {
// 1、无参初始化
Cat c1 = new Cat();
c1.setName("加菲猫");
c1.setAge(5);
System.out.println(c1.getName() + "," + c1.getAge());
c1.catchMouse();
// 2、有参初始化
Cat c2 = new Cat("田园猫", 3);
System.out.println(c2.getName() + "," + c2.getAge());
c2.catchMouse();
Dog d1 = new Dog();
d1.setName("牧羊犬");
d1.setAge(5);
System.out.println(d1.getName() + "," + d1.getAge());
d1.eatShit();
Dog d2 = new Dog("哈士奇", 3);
System.out.println(d2.getName() + "," + d2.getAge());
d2.eatShit();
}
}
16、修饰符
16.1、包
- 命令行运行不带包的程序
- 命令行运行带包的程序(如何手动建包、自动建包)
16.2、导包
code:
16.3、权限修饰符
16.4、状态修饰符
16.4.1、final
注意:为什么没有构造函数?因为构造函数不能被这些修饰,这一点学构造函数就讲过了。
Final用于修饰类、成员变量和成员方法。final修饰的类,不能被继承(String、StringBuilder、StringBuffer、Math,不可变类),其中所有的方法都不能被重写(这里需要注意的是不能被重写,但是可以被重载,这里很多人会弄混)(关于重载和重写可参考《Java中重载和重写的区别》),所以不能同时用abstract和final修饰类(abstract修饰的类是抽象类,抽象类是用于被子类继承的,和final起相反的作用);Final修饰的方法不能被重写,但是子类可以用父类中final修饰的方法;Final修饰的成员变量是不可变的,如果成员变量是基本数据类型,初始化之后成员变量的值不能被改变,如果成员变量是引用类型,那么它只能指向初始化时指向的那个对象,不能再指向别的对象(即地址值不能变),但是对象当中的内容是允许改变的。参考《final、finally、finalize区别》
具体见下(final 那里修饰的是引用s,s是一个引用,即地址不能变,但里面的内容可以变):
16.4.2、static
例如所有学生都来自于同一所大学,则期望大学名称被共享。
再举个例子,饮水机被学生共享,但是水杯却是学生独有。
static的访问特点如下:
17、多态
17.1、概览
注意:
方法重写时直接写父类函数名,回车后会自动生成,很方便
17.2、多态中访问的特点
17.3、多态的好处和弊端
每次需要新建一个类,同时修改方法,然后调用方法。多态的好处在于不用去修改方法,提升可扩展性。
17.4、多态的转型
17.5、多态内存图解
17.6、多态案例之猫与狗
需求:
code:
public class Animal {
private String name;
private int age;
public Animal() {
}
public Animal(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public void eat() {
System.out.println("动物吃东西");
}
}
public class Cat extends Animal{
public Cat() {
}
public Cat(String name, int age) {
super(name, age);
}
@Override
public void eat() {
System.out.println("猫吃鱼");
}
}
public class Dog extends Animal{
public Dog() {
}
public Dog(String name, int age) {
super(name, age);
}
@Override
public void eat() {
System.out.println("狗吃肉");
}
}
/*
测试类
*/
public class Demo {
public static void main(String[] args) {
// 1、无参初始化
Animal a = new Cat();
a.setName("加菲猫");
a.setAge(5);
System.out.println(a.getName() + "," + a.getAge());
a.eat();
// 2、有参初始化
a = new Cat("加菲猫", 5);
System.out.println(a.getName() + "," + a.getAge());
a.eat();
}
}
18、抽象类
18.1、概述
Animal不应该new一个具体的,尤其是里面的eat函数,不应该有“吃东西”,不然猫也吃东西,狗也吃东西。
在java中,没有方法体的方法应该定义为抽象方法,而类中有抽象方法,必须定义为抽象方法。一个类中有抽象方法,必须定义为抽象类;而一个抽象类中可以没有抽象方法。
18.2、抽象类的特点
这里针对第3、4点进行说明如下:
Animal类:
测试类(不能原来那样实例化,会报错,应该用多态性质实例化,即创建一个子类实利用多态实例化。注意子类创建时,子类要么重写父类的全部抽象方法,要么就定义为抽象子类):
Cat类:
测试类(多态针对于成员方法时,编译看左边,执行看右边。a.eat(),Animal有,编译通过,执行时Cat有,执行Cat的“猫吃鱼”。a.sleep(),Animal有,编译通过,执行时Cat虽然没有,但是继承了Animal的,因此输出“睡觉”):
18.3、抽象类的成员(变量、方法)特点
18.4、抽象类案例之猫与狗
需求:
code:
public abstract class Animal {
private String name;
private int age;
public Animal() {
}
public Animal(String name, int age) {
this.name = name;
this.age = age;
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age){
this.age = age;
}
public String getName(){
return name;
}
public int getAge() {
return age;
}
// 抽象类
public abstract void eat();
}
public class Cat extends Animal{
public Cat() {
}
public Cat(String name, int age) {
super(name, age);
}
@Override
public void eat() {
System.out.println("猫吃鱼");
}
}
/*
测试类
*/
public class Demo {
public static void main(String[] args) {
// 多态实例化,无参初始化
Animal a = new Cat();
a.setName("加菲");
a.setAge(5);
System.out.println(a.getName() + "," + a.getAge());
a.eat();
// 带参初始化
a = new Cat("加菲", 5);
System.out.println(a.getName() + "," + a.getAge());
a.eat();
}
}
19、接口
19.1、接口概述
注意接口更多的是对行为的抽象!!!
19.2、接口的特点
注意如何新建接口:
接口:
Cat类(这里关键字是implements):
Dog类(但子类继承Dog时还需要重写接口中的抽象方法):
测试类
19.3、接口类中成员的特点
关于1:
关于2:
关于3:
19.4、接口案例之猫与狗
需求:
使用的一定是子类,因为里面有最多的方法:
code:
/*
测试类
*/
public class Demo {
public static void main(String[] args) {
// 多态创建对象初始化,无参初始化
Animal a = new Cat();
a.setName("加菲");
a.setAge(5);
System.out.println(a.getName() + "," + a.getAge());
a.eat();
// a.jump; //报错,不能调,因为这个属于接口的方法
// 有参初始化
a = new Cat("加菲", 5);
System.out.println(a.getName() + "," + a.getAge());
a.eat();
Jumpping j = new Cat();
j.jump();
System.out.println("---------------");
/*
不推荐上面这种多态创建对象,因为Cat包含了最多的方法,故使用Cat直接创建对象!!!
*/
Cat c = new Cat();
c.setName("加菲");
c.setAge(5);
// Cat c = new Cat("加菲", 5); // 也可以有参初始化
System.out.println(c.getName() + "," + c.getAge());
c.eat();
c.jump();
}
}
public interface Jumpping {
public abstract void jump();
}
public abstract class Animal {
private String name;
private int age;
public Animal() {
}
public Animal(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public abstract void eat();
}
public class Cat extends Animal implements Jumpping{
public Cat() {
}
public Cat(String name, int age) {
super(name, age);
}
@Override
public void jump() {
System.out.println("猫可以跳高了");
}
@Override
public void eat() {
System.out.println("猫吃鱼");
}
}
19.5、接口与类的关系
19.6、抽象类与接口的关系
下面以门和警报的例子说明。门都具有“开”、“关”的功能,可以都放抽象类或者接口中:
但随着时代进步,有的门升级了,还可以进行“警报”。因此想法是要么把“警报”功能加进抽象类中,要么加入接口中:
但是并非所有的门都能“警报”,也并非所有的都能“开关门”,如火灾报警器,因此应该是“开关门”放入抽象类,“警报”放入接口。
19.7、综合案例之教练和运动员
code:
/*
接口
*/
public interface SpeakEnglish {
public abstract void speak();
}
/*
抽象人类
*/
public abstract class Person {
private String name;
private int age;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public abstract void eat();
}
/*
抽象教练类
*/
public abstract class Coach extends Person{
public Coach() {
}
public Coach(String name, int age) {
super(name, age);
}
public abstract void teach();
}
/*
抽象运动员类
*/
public abstract class Player extends Person {
public Player() {
}
public Player(String name, int age) {
super(name, age);
}
public abstract void study();
}
/*
篮球教练类
*/
public class BasketballCoach extends Coach{
public BasketballCoach() {
}
public BasketballCoach(String name, int age) {
super(name, age);
}
@Override
public void teach() {
System.out.println("篮球教练教如何运球和投篮");
}
@Override
public void eat() {
System.out.println("篮球教练吃羊肉,喝羊奶");
}
}
/*
乒乓球教练类
*/
public class PingpongCoach extends Coach implements SpeakEnglish{
public PingpongCoach() {
}
public PingpongCoach(String name, int age) {
super(name, age);
}
@Override
public void teach() {
System.out.println("乒乓球教练教如何发球和接球");
}
@Override
public void eat() {
System.out.println("乒乓球教练吃小白菜,喝大米粥");
}
@Override
public void speak() {
System.out.println("乒乓球教练说英语");
}
}
/*
篮球运动员类
*/
public class BasketballPlayer extends Player{
public BasketballPlayer() {
}
public BasketballPlayer(String name, int age) {
super(name, age);
}
@Override
public void study() {
System.out.println("篮球运动员学习如何运球和投篮");
}
@Override
public void eat() {
System.out.println("篮球运动员吃牛肉,喝牛奶");
}
}
/*
乒乓球运动员类
*/
public class PingpongPlayer extends Player implements SpeakEnglish{
public PingpongPlayer() {
}
public PingpongPlayer(String name, int age) {
super(name, age);
}
@Override
public void study() {
System.out.println("乒乓球运动员学习如何发球和接球");
}
@Override
public void eat() {
System.out.println("乒乓球运动员吃大白菜,喝小米粥");
}
@Override
public void speak() {
System.out.println("乒乓球运动员说英语");
}
}
20、形参和返回值
基本类型作为形参和返回值比较简单,这里不予讨论,重点讨论引用(类名、抽象类、接口)作为形参和返回值。
20.1、类名作为形参和返回值
- 方法的形参是类名,其实需要的是该类的对象
- 方法的返回值是接口名,其实返回的是该类的对象
形参:
猫类:
测试类:
CatOperator类:
返回值:
测试类:
操作类:
20.2、抽象类名作为形参和返回值
- 方法的形参是接口名,其实需要的是该抽象类的子类对象
- 方法的返回值是接口名,其实返回的是该抽象类的子类对象
形参:
Animal类:
AnimalOperate类:
测试类:
返回值:
测试类:
操作类:
20.3、接口名作为形参和返回值
- 方法的形参是接口名,其实需要的是该接口的实现类对象
- 方法的返回值是接口名,其实返回的是该接口的实现类对象
测试类:
操作类:
接口:
猫类:
21、内部类
21.1、内部类概述
代码示例:
21.2、成员内部类
收获:
- 如何创建内部类对象并调用?
- 如何隐藏内部类,外部又如何访问呢?
1、如何创建内部类对象并调用?但这里前提是内部类呗定义为了public,这样外部才能访问。
2、如何隐藏内部类,外部又如何访问呢?目标内部类定义为private,同时再定义一个public的方法去访问private内部类。测试类则通过外部类的对象间接实现对内部类的访问(具体为通过外部类的对象访问其成员方法,而在成员方法内部,创建局部内部类的对象去访问内部类)。
不难发现,要想封装,都是在同一个类中,封装目标(可能是类、成员变量、成员方法)定义为private,同时再定义个public的方法去访问封装目标(例如创建内部类对象并调用其方法),例如之前的set/get方法、现在的内部类封装。
这样通过外部类的对象间接实现对内部类的访问(具体为通过外部类的对象访问其成员方法,而在成员方法内部,创建局部内部类的对象去访问内部类。
)
21.3、局部内部类
局部内部类是在方法中定义的类,所以外界是无法直接访问的,需要在方法内部中创建对象使用。
该类可以直接访问外部类的成员,也可以访问方法内的局部变量。
这里其实就是把成员内部类的method包了所有。
这样通过外部类的对象间接实现对内部类的访问(具体为通过外部类的对象访问其成员方法,而在成员方法内部,创建局部内部类的对象去访问内部类。
)
21.4、匿名内部类
匿名内部类是局部内部类的一种特殊形式。
收获:
- 格式如何写?
- 本质是什么?
- 如何调用?
- 如何多次调用?
本质是一个匿名的子类对象,该对象继承了一个类或实现了一个接口。
格式:
测试类:
Outer类(注意这里,匿名内部类是局部内部类的特殊形式,因此应该写在方法method()内部):
推荐下面这种写法(多态实现,编译看左边,实现看右边):
21.4、匿名内部类在开发中的使用
需求:
按照以前讲的方法,正常测试类,要调用method()方法,应该先实例化Jumpping接口(因为接口作为形参,其实是想要接口实例化的对象),但是Jummping接口没法直接实例化,应该先定义个子类,通过多态方式实现实例化。这样坏处在于,来一个Cat就要定义一个Cat子类,来一个Dog就要定义一个Dog子类,这样就会很麻烦。因此可以用匿名内部类,不必多定义Cat类或Dog类。因为匿名内部类本质是一个对象,自然可以作为method()方法的参数传递。
测试类:
22、常用API
之前已经学了 String、StringBuilder、Scanner、Random 的常用API,为何学习?使用其提高开发效率。
Math、System、Array在帮助文档里都没有找到构造方法,要想访问成员方法,需要用类名进行访问。
真的没有构造方法么?看源码其实是有的,只不过该构造方法被private修饰了,并不想让外界直接访问来创建一个对象。具体见22.4中Array那里具体的设计思想。
22.1、Math
简介:
要使用Math,就需要去new一个Math对象,因此去帮助文档查看构造方法,但是一查,发现没有构造方法。
那如何访问呢?发现Math的成员变量、成员方法均用static修饰,用static修饰的内容可以直接通过类名直接访问,所以没有构造方法也不奇怪。
所以以后一个API即便没有构造方法也不可怕,只要是其成员是static修饰的,自然可以通过类名去访问。
Math类中常用的方法:
22.2、System
System是不能被实例化的,如何访问其成员呢?那从上一节可知,自然其成员是被static修饰的,自然通过类名去访问其成员变量or方法。
而且之前Scanner那里遇到过System.in,后面还遇到过System.out。
常用方法:
code:
22.3、Object类
概述:
22.3.1、toString方法
注意:Object类中的toString() 和 StringBuilder中的toString() 不一样
收获:
-
1、看方法的源码?
选中方法,Ctrl+B。
-
2、toString最好重写,这样方便阅读,对于对象进行赋值时,不用get,直接输出对象时,得到的是能够看得懂的字符串。如何重写?
还是Fn+Alt+insert,选中toString()方法,再选中两个成员变量,ok即可。
22.3.2、equals方法
注意:Object类中的equals() 和 String中的equals() 不一样
收获:
-
1、Object类中的equals() 默认比较地址值
-
2、重写equals() 自动生成
-
3、谁调的谁就是this
22.3.3、总结
22.4、冒泡排序
其实是n-1趟,第一趟:n-1次,第二趟:n-1-1次,第三趟:n-1-2次…
注意为何代码是这样优化的。
22.5、Array
Math、System、Array在帮助文档里都没有找到构造方法,要想访问成员方法,需要用类名进行访问。
真的没有构造方法么?看源码其实是有的,只不过该构造方法被private修饰了,并不想让外界直接访问来创建一个对象。
22.6、基本类型包装类
22.6.1、概述
22.6.2、Integer
构造方法:
22.6.3、int和String的转换
22.6.3、字符串中数据排序
import java.util.Arrays;
public class IntegerDemo {
public static void main(String[] args) {
String str = "91 35 23 57 19 45";
// 1、拆分字符串,存到字符数组中
String[] strArr = str.split(" ");
/*
for(int i = 0; i < strArr.length; i++) {
System.out.println(strArr[i]);
}
*/
// 2、将字符数组存到int类型数组中
int[] intArr = new int[strArr.length];
for (int i = 0; i < strArr.length; i++) {
intArr[i] = Integer.parseInt(strArr[i]);
}
// 3、对int数组进行排序
Arrays.sort(intArr);
// 4、将int数组进行拼接,采用StringBuilder进行
StringBuilder sb = new StringBuilder();
for(int i =0; i< intArr.length;i++) {
if(i == (intArr.length-1)){
sb.append(intArr[i]);
} else {
sb.append(intArr[i]).append(" ");
}
}
String result = sb.toString();
System.out.println("排序前:" + str);
System.out.println("排序后:" + result);
}
}
22.6.4、自动装箱和拆箱
22.7、Date
22.7.1、Date构造方法
注意这里,util和sql两个包下都有,课上讲的是util包。
22.7.2、Date类的常用方法
突然发现,这里不就是“无参构造+get/set” or “有参构造+get么”
22.8、SimpleDateFormat类
收获:
-
1、为何要学习此类?
Date类的输出是一串数字,不好看。人们更想看到“年、月、日”,因此学SimpleDateFormat类。
-
2、概述?
-
3、构造方法?
-
4、成员方法?
22.8、案例之日期工具类
工具类的思想:
构造方法定义为private(防止外界直接访问);成员方法用static修饰(便可以通过类名去调用成员方法)
22.9、Calendar类
22.9.1、概述
22.9.2、常用方法
22.9.3、案例之二月天(二月有多少天)
正常思路是去判断是否为闰年即可,但是有了Calendar类,就不必如此了。
import java.util.Calendar;
import java.util.Scanner;
/*
心得:
Calendar有点像一个后端数据库,这里其实就是在查找数据库而已。
那具体流程,无非就是首先定义Calendar的对象(注意这里的不同),然后通过对象访问成员方法。
而成员字段(变量)可以通过类名直接访问
*/
public class CalendarDemo {
public static void main(String[] args) {
Scanner s = new Scanner(System.in);
System.out.println("请输入年份:");
int year = s.nextInt();
Calendar c = Calendar.getInstance(); // 获取一个对象
c.set(year, 2, 1); // 这一年的3月1日
c.add(Calendar.DATE, -1); // 往前推一天
int dates = c.get(Calendar.DATE);
System.out.println(year + "年的二月有" + dates + "天");
}
}
23、异常
23.1、异常概述
其实返回的异常本质就是一个类
Throwtable是所有异常、错误的超类
23.2、JVM的默认处理方案
如果程序出现了问题,我们没有做任何处理,最终JVM会做默认的处理:
- 把程序异常的名称、原因、出现位置等信息输出在控制台
- 程序停止执行
23.3、异常处理之try…catch
-
1、为何要自定义异常处理?
JVM默认处理会停止执行,而我们并不想这样,想把异常后面的代码也执行。
-
2、格式?
-
3、代码
-
4、补充,详见25.3.5
23.4、Throwable的成员变量
23.1节就讲了,Throwable是所有错误、异常的超类。
23.5、编译时异常 VS. 运行时异常
- 1、编程时的最大区别就在于是否要手动捕获异常
- 2、如何区分?帮助文档中搜寻是否继承自RuntimeException
- 3、编译时异常,只是有可能出现异常,并非一定会异常
23.6、异常处理之 throws
23.7、自定义异常
-
1、为何要自定义异常
因为java虽然提供了很多异常,但是并不能满足全部需要,例如学生成绩只能在1-150之间。
-
2、定义格式
-
3、如何使用自定义异常
在方法体内部要用“throw new 异常”。
23.8、throws 和 throw 的区别
24、集合进阶
24.1、集合概述
- 1、集合类的特点:
- 2、集合的体系结构:
24.2、Collection
24.2.1、Collection 集合概述和使用
注意,所有集合里的<E>必须为引用。
/*
所有基本类型必须要用其基本包装类,具体见24.7.7小节
*/
Collection<int> c = new ArrayList<int>(); // 这里会报错
Collection<Integer> c = new ArrayList<Integ>(); // 正确写法
- 1、帮助文档:
- 2、概述
- 3、使用
24.2.2、Collection 集合常用方法
-
1、Alt+7,快捷键,打开一个窗口,能够看到该类的所有信息(各种构造方法、成员方法、成员变量),方便查找源码中某个方法。或者:
-
2、boolean add(E e)
24.2.3、Collection 遍历
-
1、概述
-
2、Iterator:迭代器,集合的专用遍历方式
查看ArrarList中重写iterator()方法的对应源码: -
3、具体使用
public class CollectionDemo { public static void main(String[] args) { Collection<String> c = new ArrayList<String>(); // 添加元素 c.add("hello"); c.add("world"); c.add("java"); Iterator<String> it = c.iterator(); while (it.hasNext()) { String s = it.next(); System.out.println(s); } } }
24.2.4、Collection 案例之存储学生对象并遍历
/*
测试类
*/
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class CollectionDemo {
public static void main(String[] args) {
// 创建集合对象
Collection<Student> c = new ArrayList<Student>();
// 创建学生对象
Student s1 = new Student("林青霞", 35);
Student s2 = new Student("张曼玉", 35);
Student s3 = new Student("王祖贤", 35);
// 把学生添加到集合
c.add(s1);
c.add(s2);
c.add(s3);
// 遍历集合
Iterator<Student> it = c.iterator();
while(it.hasNext()) {
Student s = it.next();
System.out.println(s);
}
}
}
/*
Student类
*/
public class Student {
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
24.3、List
24.3.1、List概述
- 1、概述
- 2、code
24.3.2、List特有方法
这些方法,List的父类Collection没有,但是子类ArrayList有。
24.3.3、List遍历
-
1、Iterator遍历
-
2、通过get()方法、size()方法遍历(因为List带索引,所以可以利用索引去遍历)
24.3.4、List案例之存储学生对象
24.3.5、List 并发修改异常
-
1、概述
-
2、code
-
3、源码分析,建议再此观看视频 《https://www.bilibili.com/video/BV18J411W7cE?p=229&spm_id_from=pageDriver&vd_source=763a5e93fb502e71e42ff76a6fe1ae7c》
因为代码中调用了list对象的add、iterator两个方法,故拿过来。又因为这是个接口,是利用多态形式创建,故要从ArrayList中拿重写后的add、iterator两个方法。而iterator中又有Itr方法,也得拿过来。
24.3.6、列表迭代器ListIterator
- 1、概述
- 2、code
24.3.7、增强for循环
- 1、概述
- 2、code
- 3、注意
最好在增强for前判空,增加程序健壮性
24.3.8、List案例 存储学生对象用三种方式遍历
24.4、数据结构
-
1、概述
-
2、栈
-
3、队列
-
4、数组
-
5、链表
24.5、List的子类的特点
24.5.1、ArrayList、LinkedList概述
-
1、概述
-
2、code
24.5.2、ArrayList案例之存储学生对象并三种方式遍历
24.5.3、ArrayList特有功能
看之前按的即可
24.5.4、LinkedList特有功能
-
1、概述
-
2、code
24.6、Set集合
- 1、概述
-
2、code
这里应通过多态方式创建对象,因为set是一个接口。
24.7、Set子类
24.7.1、哈希值
-
1、概述
-
2、 code
24.7.2、hashset集合的特点
-
1、概述
-
2、code
24.7.3、hashset集合保证元素唯一性的源码分析
源码看得不是特别懂,建议重听 《https://www.bilibili.com/video/BV18J411W7cE/?p=241&spm_id_from=pageDriver&vd_source=763a5e93fb502e71e42ff76a6fe1ae7c》
看不懂就看下一节的图(讲了哈希表如何保证存储元素的唯一性,而hashset底层又是哈希表),就能明白了。
24.7.4、常见数据结构之哈希表
- 1、概述
-
2、如何保证唯一性的?
24.7.5、hashset之存储学生并遍历(与之前不一样)
- 1、需求与分析
- 2、code
24.7.6、LinkedHashSet集合概述和特点
-
1、概述
-
2、code
24.7.7、TreeSet集合概述和特点
-
1、概述
-
2、code
24.7.8、自然排序Comparable的使用
-
1、需求
-
2 、ClassCastException(类转换异常),Student类无法转化为Comparable类。
通过帮助文档,可以知道,要想让Student类有自动排序的功能,就必须实现Comparable这个接口。
上一节Integer没有报这个错,自己去帮助文档搜,Integer已经实现了Comparable这个接口。
-
3、Student类实现Comparable接口,并重写compareto()方法。
-
4、测试类
24.7.9、比较器排序Comparator的使用
-
1、需求
-
2、TreeSet的有参构造方法
-
3、code
-
4、比较
- Comparable是要让类实现Comparable接口,并在该类的内部重写compareTo(T o)方法,注意参数个数。重写时的访问可以通过成员变量访问。
- Comparator是要让结合构造方法接收实现Comparator接口的对象(这里推荐匿名内部类),并在构造方法中重写compareTo(T o1, T o2)方法,注意参数个数。重写时的访问不能通过成员变量访问(成员变量往往私有),需要通过成员方法访问。
- 重写规则的逻辑其实都一样
24.7.10、TreeSet案例之成绩排序(非常重要)
- 1、需求
- 2、Student类
- 3、测试类
24.7.10、Set案例之不重复的随机数
- 1、需求及分析
- 2、code
24.8、泛型
24.8.1、概述
-
1、概述
-
2、code。不用泛型,默认为Object类型,传字符串自然会向上转型,但是一旦有了向下转型又转成Srting,运行期间就报错,Integer无法转化成String类型。
24.8.2、泛型类
- 1、why?格式?
24.8.3、泛型方法
-
1、概述。改进类中方法重载的。
-
2、code
package itheima_2; /* Generic类 */ /* 1、方法的重载 */ public class Generic { public void show(String s) { System.out.println(s); } public void show(Integer i) { System.out.println(i); } public void show(Boolean b) { System.out.println(b); } } /* 2、泛型类去改进 */ public class Generic<T> { public void show (T t) { System.out.println(t); } } /* 3、泛型方法去改进 */ public class Generic { public <T> void show(T t) { System.out.println(t); } }
package itheima_2; /* 测试类 */ public class GenericDemo { public static void main(String[] args) { Generic g = new Generic(); g.show("林青霞"); g.show(35); g.show(true); g.show(3.14); // 报错 } // 坏处是每次new均需要说明类型,那可不可以new的时候还是泛型,只有调方法时才明确具体类型呢? public static void main(String[] args) { Generic<String> g1 = new Generic<String>(); g1.show("林青霞"); Generic<Integer> g2 = new Generic<Integer>(); g2.show(35); Generic<Boolean> g3 = new Generic<Boolean>(); g3.show(true); Generic<Float> g4 = new Generic<Float>(); g4.show(3.14f); // 不加f报错 } public static void main(String[] args) { Generic g = new Generic(); g.show("林青霞"); g.show(35); g.show(true); g.show(3.14); } }
24.8.4、泛型接口
要掌握泛型接口、泛型接口实现类、方法重写该怎么些
-
1、泛型接口
-
2、泛型接口实现子类
-
3、测试类
24.8.5、类型通配符
-
1、概述
-
2、code
24.8.6、可变参数
-
1、概述
-
2、code
24.8.7、可变参数的使用
- 1、概述
- 2、code
24.9、Map
24.9.1、Map概述
- 1、概述
- 2、code
24.9.2、Map的常用方法
-
1、概述
-
2、code
24.9.3、Map集合的获取功能
- 1、概述
- 2、code
24.9.4、Map集合的遍历方式1
-
1、概述
-
2、code
24.9.5、Map集合的遍历方式2
- 1、概述
- 2、code
24.9.6、HashMap存储学生对象并遍历
- 1、需求
- 2、code
24.9.6、HashMap存储学生对象并遍历升级
- 1、 需求
- 2、code
24.9.7、集合嵌套之ArrayList嵌套HashMap
-
1、需求
-
2、code
24.9.8、集合嵌套之HashMap嵌套ArrayList
- 1、需求
- 2、code
/*
1、创建HashMap集合
2、创建ArrayList集合
3、添加ArrayList元素到HashMap集合
4、遍历HashMap集合
*/
public class Demo {
public static void main(String[] args) {
HashMap<String, ArrayList> hm = new HashMap<String, ArrayList>();
ArrayList<String> arr1 = new ArrayList<String>();
arr1.add("赵云");
arr1.add("张飞");
hm.put("三国演义", arr1);
ArrayList<String> arr2 = new ArrayList<String>();
arr2.add("唐僧");
arr2.add("孙悟空");
hm.put("西游记", arr2);
ArrayList<String> arr3 = new ArrayList<String>();
arr3.add("宋江");
arr3.add("晁盖");
hm.put("水浒传", arr3);
Set<String> keySet = hm.keySet();
for (String key: keySet) {
ArrayList<String> value = hm.get(key);
for(String s: value) {
System.out.println(key + "," + s);
}
}
System.out.println("-------------");
Set<Map.Entry<String, ArrayList>> entrySet = hm.entrySet();
for(Map.Entry<String, ArrayList> entry: entrySet) {
String key = entry.getKey();
ArrayList<String> value = entry.getValue();
for(String s: value) {
System.out.println(key + "," + s);
}
}
}
}
24.9.9、统计字符串中每个元素出现的次数
-
1、需求与分析(注意这里是怎么分析得到的)
-
2、code
/* 1、键盘录入一个字符串 2、创建一个HashMap集合/TreeMap集合 3、遍历该字符串,拿到每一个字符 4、将拿到的字符,作为键去HashMap中找对应的值 5、遍历HashMap集合,得到键和值,按要求进行拼接 */ import java.util.HashMap; import java.util.Scanner; import java.util.Set; import java.util.TreeMap; public class Demo { public static void main(String[] args) { Scanner sc = new Scanner(System.in); System.out.println("请输入要遍历的字符串:"); String s = sc.nextLine(); // 这样不会自动排序 // HashMap<Character, Integer> hm = new HashMap<Character, Integer>(); // 会按照字母排序 TreeMap<Character, Integer> hm = new TreeMap<Character, Integer>(); for(int i = 0; i < s.length(); i++) { char c = s.charAt(i); Integer value = hm.get(c); if (value==null){ hm.put(c, 1); } else { value += 1; hm.put(c, value); } } StringBuilder sb = new StringBuilder(); Set<Character> keySet = hm.keySet(); for(Character key: keySet) { Integer value = hm.get(key); sb.append(key).append("(").append(value).append(")"); } String s1 = sb.toString(); System.out.println(s1); } }
24.10、Collections
24.10.1、概述
- 1、概述
- 2、code
24.10.2、ArrayList存储学生并排序
-
1、需求及分析
-
2、code
跟之前也很像,第一个方法必须Student实现Comparable这个接口。第二个方法其实就是匿名内部类。
24.10.3、模拟斗地主
由于看牌是共同操作,故抽象成函数。
24.10.4、模拟斗地主升级版(牌有排序)
/*
1、创建HashMap对象,键是Integer类型,值是String类型;
2、创建ArrayList对象,元素是Integer类型;
3、创建花色数组、点数数组;
4、往HashMap中存储索引+牌,往ArrayList中存储索引;
5、洗牌(洗的是编号),用Collections中的shuffle()实现;
6、发牌,往三个玩家手里发牌,也要发底牌,遍历ArrayList实现,TreeSet存储;
7、定义看牌的方法,遍历TreeSet集合,根据索引去HashMap中寻找对应的牌;
8、看牌
*/
import java.util.*;
public class Demo {
public static void main(String[] args) {
// 1、创建HashMap对象;
HashMap<Integer, String> hm = new HashMap<>();
// 2、创建ArrayList对象,元素是Integer类型;
ArrayList<Integer> array = new ArrayList<>();
// 3、创建花色数组、点数数组;
String[] colors = {"♣", "♦", "♠", "♥"};
String[] numbers = {"3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A", "2"};
// 4、往HashMap中存储索引+牌,往ArrayList中存储索引;
int index = 0;
// for (String c : colors) {
// for (String n : numbers) {
// hm.put(index, c + n);
// array.add(index);
// index++;
// }
// } // 与上一节不一样
for (String n : numbers) {
for (String c : colors) {
hm.put(index, c + n);
array.add(index);
index++;
}
}
hm.put(index, "小王");
array.add(index);
index++;
hm.put(index, "大王");
array.add(index);
// Set<Integer> keySet = hm.keySet();
// for (Integer key : keySet) {
// String value = hm.get(key);
// System.out.println(key + ": " + value);
// }
// 5、洗牌(洗的是编号),用Collections中的shuffle()实现;
Collections.shuffle(array);
// 6、发牌,往三个玩家手里发牌,也要发底牌,遍历ArrayList实现,TreeSet存储;
TreeSet<Integer> lqxSet = new TreeSet<>();
TreeSet<Integer> fqySet = new TreeSet<>();
TreeSet<Integer> wzxSet = new TreeSet<>();
TreeSet<Integer> dpSet = new TreeSet<>();
for (int i = 0; i < array.size(); i++) {
Integer x = array.get(i);
if (i >= array.size() - 3) {
dpSet.add(x);
} else if (i % 3 == 0) {
lqxSet.add(x);
} else if (i % 3 == 1) {
fqySet.add(x);
} else if (i % 3 == 2) {
wzxSet.add(x);
}
}
// 7、定义看牌的方法,遍历TreeSet集合,根据索引去HashMap中寻找对应的牌;
// 8、看牌
showPokers("Linqingxia", hm, lqxSet);
showPokers("Fengqingyang", hm, fqySet);
showPokers("Wangzuxian", hm, wzxSet);
showPokers("dipai", hm, dpSet);
}
// 7、定义看牌的方法,遍历TreeSet集合,根据索引去HashMap中寻找对应的牌;
public static void showPokers(String name, HashMap<Integer, String> hm, TreeSet<Integer> ts) {
System.out.print(name + "的牌是:");
for (Integer key: ts) {
String poker = hm.get(key);
System.out.print(poker + " ");
}
System.out.println();
}
}
25、IO流
25.1、File
25.1.1、File类概述和构造方法
-
1、概述
-
2、构造方法
-
3、code
25.1.2、File类创建功能
-
1、概述
-
2、code
25.1.3、File类判断和获取功能
- 1、概述
-
2、code
25.1.4、File类删除功能
-
1、概述
-
2、绝对路径和相对路径
-
3、注意事项
-
4、code
25.2 、递归
25.2.1 、概述
-
1、故事
-
2、概述
-
3、code
25.2.2 、递归求阶乘
-
1、分析
-
2、思路
-
3、code
-
4、内存讲解
25.2.3、递归遍历目录
- 1、分析
- 2、code
为了健壮性,以后增强for最好判空。
25.3、字节流
25.3.1、IO流的概述和分类
-
1、概述
-
2、分类及使用
25.3.2、字节流写数据
-
1、概述
-
2、code
25.3.3、字节流写数据的3种方式
-
1、两种构造方法。其实是等价,第一种会自动将路径封装为一个File对象,自己跟进一下源码就知道了。推荐第一种,更简单。
public class Demo { public static void main(String[] args) throws FileNotFoundException { // 1、构造方法1 FileOutputStream fos = new FileOutputStream("myByteStream\\fos.txt"); /* 跟进的源码: public FileOutputStream(String name) throws FileNotFoundException { this(name != null ? new File(name) : null, false); } */ // 2、构造方法2 File file = new File("myByteStream\\fos.txt"); FileOutputStream fos = new FileOutputStream("myByteStream\\fos.txt"); FileOutputStream fos = new FileOutputStream(new File("myByteStream\\fos.txt")); } }
-
2、code
25.3.4、字节流写数据如何实现换行
25.3.5、字节流写数据如何实现追加写入
25.3.6、字节流写数据加异常处理Finally
-
1、先看一段代码,这段代码报错,之前操作是通过throws解决的。
现在通过try catch来解决。
但现在问题来了,如果上面异常了,那么fos.close()则会无法被执行,因此有了下面的Finally。
-
2、Finally解决
故fos.close()要放到Finally中进行操作。
无论是基础类型还是引用类型,最好都初始化。
所以要判空。最终格式为:
25.3.7、字节流读数据(一次读一个字节数据)
-
1、概述
-
2、code
第一次优化后代码:
第二次优化后代码(即标准代码):
25.3.8、字节流案例之复制文本文件
-
1、需求与分析
-
2、思路
-
3、code
25.3.9、字节流读数据(一次读一个字节数组数据)
-
1、思路
-
2、标准格式
-
3、分析
循环优化
25.3.10 字节流案例之复制图片
-
1、需求
-
2、code
25.3.11、字节缓冲流
- 1、why?好处就是减少访问底层的次数,一次性从缓冲区读/写很多字节。
- 2、code
25.3.12、字节流案例之复制视频(4种方式对比)
-
1、需求
-
2、code
方式一
方式二
方式三
方式四
25.4、字符流
25.4.1、为什么出现字符流
-
1、
-
2、
25.4.2、编码表
-
1、基础知识
-
2、字符集(即分类)
-
3、Ascii(美国和欧洲)
-
4、GB(中国)
-
5、UTF(万能,国际统一)
25.4.3、字符串中的编码解码问题
- 1、概述
- 2、code
25.4.4、字符流中的编码解码问题
-
1、概括
-
2、code
25.4.5、字符流写数据的五种方式
-
1、概括
-
2、code
25.4.6、字符流读数据的两种方式
-
1、概括
-
2、code
25.4.7、字符流案例之复制Java文件
-
1、需求及分析
-
2、code
25.4.8、字符流案例之复制Java文件改进版
- 1、需求与分析
- 2、code
25.4.9、字符缓冲流
- 1、概括
- 2、code
写数据
读数据
25.4.10、字符缓冲流之复制Java文件
-
1、需求
-
2、code
25.4.11、字符缓冲流特有功能
-
1、概括
-
2、code
BufferWriter:
BufferReader :
25.4.12、字符缓冲流特有功能之复制Java文件(最常用,掌握!!!)
- 1、需求及分析
- 2、code
25.5、IO总结
25.5.1、字节流
25.5.2、字符流
、总结
码字不易,谢谢点赞!!!
码字不易,谢谢点赞!!!
码字不易,谢谢点赞!!!