优秀是一种习惯
大数据基础:JavaSE
- Java 语言背景
- Java语言跨平台的原理
- JVM,JRE,JDK关系
- DOS命令
- HelloWorld案例详解
- 编程中可能会出现的问题
- 注释
- 关键字
- 常量
- 变量
- 数据类型
- 数据类型转化
- 基础面试题
- 键盘录入
- 标识符
- 运算符
- 流程控制语句
- 循环语句
- 三种循环之间区别
- 死循环
- 循环跳出
- 随机数
- 数组
- 数组遍历
- 方法
- 方法的重载
- 方法练习题
- 进制
- 快速进制转换 8421码
- 原码反码补码
- 位算符
- 二维数组
- 二维数组遍历案例
- 面向对象
- 类与对象的关系
- 封装
- 关键字private
- 关键字 this
- 构造方法
- 一个标准的JavaBean类
- API
- Scanner
- String
- == 和equals
- 时间戳
- StringBuilder
- 集合
- ArrayList
- 案例
- 综合案例-学生管理系统(初级版)
- 集合 字符串 数组 遍历区别
- 继承
- 多态
- final
- static
- abstract
- interface
- 接口与类之间的关系
- 普通类,抽象类,接口类区别
- 包
- 权限修饰符
- Object
- 冒泡排序
- Arrays工具类
- Arrays类的构造方法问题
- 包装类
- Date日期
- SimpleDateFormat类
- 匿名对象
- 内部类
- 集合
- Lambda表达式
- Lambda和匿名内部类区别:
- 集合遍历
- 数据结构
- 异常
- final finally finalize这是三个关键字的区别
- IO
- 序列化和反序列化
- 进程 线程 并发 并行
Java 语言背景
- JavaSE 其他两个版本的基础 用来做桌面的开发 主要为今后从事大数据开发 打基础
- JavaME 嵌入式消费类型的电子设备
- JavaEE web开发 做web页面和后台功能实现
Java语言跨平台的原理
-
Java语言 一次编译到处运行
-
Java开发
-
编写Java
- JRE Java运行环境 包括JVM和核心类库
- JVM 虚拟机 本身不可以跨平台 允许跨平台的是Java程序
-
编译Java
- .java文件 属于 源文件 ,无法被JVM所识别执行的
- 使用Java提供的JDK中的翻译工具
-
运行Java
JDK 是Java语言你的软件开发工具包,包含代码的编译工具和运行工具
-
JVM,JRE,JDK关系
JDK =JRE +开发工具
JRE=JVM+核心类库
DOS命令
为了使用Javac和Java命令
- 盘符: 切换到某盘
- cd 进入
- dir 显示当前目录下所有文件
- cd / 进入根目录
- exit 退出
HelloWorld案例详解
public class HelloWrold{
public static void main(String[] args){
System.out.println("helloworld");
}
}
- public 限定类名和文件名保持一致 记
- class 定义一个类
- hellowrld 类型
- main 主方法 JVM 只会调用main方法 Java程序的入口
- System.out.println(""); 输出语句
编程中可能会出现的问题
- bug 程序中的缺陷问题
- 单词写错 没区分大小写
- 使用中文字符
- 类名和文件名不一致
注释
给程序员看的 并不会给JVM看
- 单行注释 //
- 多行注释 /* */
- 文档注释 /** */
关键字
Java赋予了特殊含义的单词
- 全小写 字母
- 在一些代码编辑工具中会有颜色标记
常量
作用:在代码运行期间 其值不会发生变化的数据
-
整数常量
例如:1,2,3,11,33,212
-
小数常量
例如:1.22,12.13
-
字符常量
例如:‘A’,‘a’,‘1’
-
字符串常量
例如:“黑马”,“abc”
-
布尔常量
例如:true,false
-
空常量
只有一个:null
不能单独打印
变量
作用:使用变量记录一些经常发生变化的数据
变量是什么:内存中一小块存储区域 这个区域中的值经常发生变化
变量的定义格式: 数据类型 变量名=初始化值;
变量的使用:拿变量名使用 拿变量名获取这个变量对应的值
注意事项:
-
变量名不可以重名
-
一行上可以定义同类型的数据
例如:int a,b,c;
int a=11,b=22,c=33;
-
变量使用前,必须要有一个初始化
-
定义float与long 对应初始化值后面加上F/f和L/l;
-
变量的作用范围 变量所在的大括号中
数据类型
分为基本数据类型和引用数据类型。
基本数据类型 四类八种:
- 整数类型: byte short int long
- 浮点类型: float doublee
- 布尔类型: boolean
- 字符类型: char
引用数据类型:
- 数组
- String
- 接口interface
- 类
整数类型:
字节Byte 范围
byte 1B -128~127
short 2B -2^15~2^15-1
int 4B -2^31~2^31-1 默认
long 8B
浮点类型
float 4B
double 8B 默认
字符
char 2B
布尔类型
boolean 1B
定义float类型变量时 后面必须加上F或f;
定义double类型变量时 后面可以不加D或d;
定义long类型变量时 后面必须加上L或l;
int类型和float类型所占都是4个字符,那种数据类型所储存的数据大呢?
float在数据结构中存在的方式是用指数表示的 采用科学技术法
所以float表示的数据范围要比int大
数据类型转化
自动转换/隐式转换
要求:
-
将数据范围小的 赋予一个数据范围大的
-
一个小的和一个大的计算时 小的提升为大的 然后计算 记
byte–>short–>int–>long–>float–>double
char–>int–>long–>float–>double
byte、short、char 参与计算时 会提升为int 记
例如:将数据范围小的 赋予一个数据范围大的
int a=222;
long b=a;
例如:一个小的和一个大的计算时 小的提升为大的 然后计算
int a=222;
double b=10.2;
double c=a+b; //a int自动提升为double
例如:byte、short、char计算时 会提升为int
byte a=10;
short b=20;
int c=a+b; //byte、short、char计算时提升为int
byte d=(byte)(a+b) //强转
byte f=10+20; //常量的优化机制 在编译时(javac),就将10和20计算出一个30的结果,并i且自动判断该结果是否在byte范围内,在编译通过,不在编译失败。
强制转换
要求:
- 将数据范围大的 赋予一个数据范围小的
- 小数转为整数 只保留整数位
例如: 将数据范围大的 赋予一个数据范围小的
int a=222;
byte b=(byte)a;
例如:小数转为整数 只保留整数位
double a=10.95;
int b=(int)a;
sout(b); //10
基础面试题
键盘录入一个小数,输出一个四舍五入的整数
方法1:键盘录入一个小数,输出一个四舍五入的整数
Scanner sc= new Scanner(System.in);
double num=sc.nextDouble();
int result=(int)(num+0.5);
sout(result);
方法2:键盘录入一个小数,输出一个四舍五入的整数
Scanner sc= new Scanner(System.in);
double num=sc.nextDouble();
sout(Math.round(num));
拓展:
向下取整
Math.floor(num);
例如:
Math.floor(11.7)=11;
Math.floor(-11.2)=-12;
向上取整
Math.ceil(num)
例如:
Math.ceil(11.4)=12;
Math.ceil(-11.6)=-11;
键盘录入
用键盘录入数据 为了让我们的数据更加灵活
- 导包
- 位于类上方
- import java.util.Scanner;
- 创建对象
- Scanner sc=new Scanner(System.in);
- 接收数据
- int i=sc.nextInt();
案例:例如:
import java.util.Scanner;
public class Demo{
public static void main(String[] args){
Scanner sc=new Scanner(System.in);
int i=sc.nextInt();
Sysyem.out.println(i);
}
}
标识符
用来给变量 类 方法取名的符号
硬性规范
- 数字,下划线,字母,美元符号$
- 不能以数字开头
- 不可以使用关键字
- 严格区分大小写
江湖规矩
- 小驼峰
- 作用在 变量 方法 上
- 一个单词时 首字母小写
- 多个单词时 第一个单词首字母小写,其他单词首字母大写
- 大驼峰
- 作用在 类 上
- 一个单词时 首字母大写
- 多个单词时 每个单词首字母都要大写
运算符
-
运算符 用来连接常量或者变量的符号
-
表达式 使用运算符连接常量或者变量的一种符合Java语法的式子
分类
-
算术运算符
-
赋值运算符
-
比较(关系)运算符
-
逻辑运算符
-
三元运算符
算数运算符
算数运算符包括: | 作用 |
---|---|
+ | 加法运算,字符串连接运算 |
- | 减法运算 |
* | 乘法运算 |
/ | 除法运算 |
% | 取模运算,两个数字相除取余数 |
案例:例如:求三位数的各位数字,十位数字,百位数字是多少?
public class Demo {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("请输入一个三位的整数");
int num = sc.nextInt();
int ge=num%10;
int shi=num/10%10;
int bai=num/100%10;
// int qian = num / 1000 % 10;
// int wan = num / 10000 % 10;
System.out.println(ge+" "+shi+" "+bai);
}
}
字符参与运算:ASCII
作用:字符和byte对应关系 为了让我们方便使用字符
byte、short、char 参与计算时 会提升为int
字符 | 数值 |
---|---|
0 | 48 |
9 | 57 |
A | 65 |
Z | 90 |
a | 97 |
z | 122 |
例如:
int a=1;
char b='a';
sout(a+b); //b默认提升为int类型 1+97=98
自增自减运算符
符号 | 作用 | 说明 |
---|---|---|
++ | 自增 | 变量的值加1 |
– | 自减 | 变量的值减1 |
单独使用时,a++,++a,a–,--a相同。
参与运算时,a++ 先拿值在++,++a先++再拿值。
a-- 先拿值在–,--a先–再拿值。
例如:
int a=5;
int b=a++ + ++a +5; // 5 7 5
// 6
sout(b); //17
字符串参与加法运算
字符串参与加法运算得到的结果 也是一个字符串 也叫字符串拼接
从左往右执行 如果有括号先算括号内的
加号两边只要有字符串 结果就是字符串 例如:“你好” + 3 + 4 要考虑到 “你好” + 3结果是一个字符串 所以第二个加号两边存在字符串
sout(2+"你好"); //2你好
sout("你好"+3); //你好3
sout(2+3+"你好"); //5你好
sout(2+"你好"+3); //2你好3
sout("你好"+2+3); //你好23
sout("你好"+(2+3); //你好5
赋值运算符
符号 | 作用 | 说明 |
---|---|---|
= | 赋值 | a=10,将10赋值给变量a |
+= | 加后赋值 | a+=b,将a+b的值给a |
-= | 减后赋值 | a-=b,将a-b的值给a |
*= | 乘后赋值 | a*=b,将a×b的值给a |
/= | 除后赋值 | a/=b,将a÷b的商给a |
%= | 取余后赋值 | a%=b,将a÷b的余数给a |
扩展的赋值运算隐含了强制类型转换 记
例如:
short s = 1;
s+=1; //一次运算 相当于 s=(short)(s+1)
sout(s);
比较(关系)运算符
关系运算符就是用来描述两个变量或者常量之间的关系的。
符号 | 说明 |
---|---|
== | a==b,判断a和b的值是否相等,成立为true,不成立为false |
!= | a!=b,判断a和b的值是否不相等,成立为true,不成立为false |
> | a>b,判断a是否大于b,成立为true,不成立为false |
>= | a>=b,判断a是否大于等于b,成立为true,不成立为false |
< | a<b,判断a是否小于b,成立为true,不成立为false |
<= | a<=b,判断a是否小于等于b,成立为true,不成立为false |
逻辑运算符
注意: 假设下表中的a和b, 都是boolean类型的值。
符号 | 作用 | 说明 |
---|---|---|
& | 逻辑与 | a&b,并且的意思. 有false则整体为false, 都为true, 则整体为true. |
| | 逻辑或 | a|b,或者的意思, 有true则整体为true, 都为false, 则整体为false. |
! | 逻辑非 | !a,取反的意思, 以前为true, 取反后为false, 以前为false, 取反后为true. |
^ | 逻辑异或 | a^b,异同的意思, 相同为false, 不同为true. |
短路逻辑运算符
在实际开发中, 并且, 或者这样的操作是非常多的, 但是上述的&(逻辑与), !(逻辑或)运算符没有短路效应, 所以效率相对较低, 针对这种情况, 我们可以使用&&(短路与), ||(短路或)来优化.
符号 | 作用 | 说明 |
---|---|---|
&& | 短路与 | 作用和&相同,但是有短路效果, 前边出现false, 后边不执行. |
|| | 短路或 | 作用和|相同,但是有短路效果, 前边出现true, 后边不执行. |
解释
-
在短路与运算中,只要有一个表达式的值为false,那么结果就可以判定为false了,没有必要将所有表达式的值都计算出来,短路与运算符就有这样的效果,可以提高效率。
-
同理在短路或运算中,一旦发现值为true,右边的表达式将不再参与运算。
短路和非短路之间的区别
- 逻辑与 和 短路与之间的区别
– 逻辑与&(也叫单与): 无论左边真假,右边都要执行。
– 短路与&&(也叫双与): 如果左边为真,右边执行;如果左边为假,右边不执行。
- 逻辑或 和 短路或之间的区别
– 逻辑或|(也叫单或): 无论左边真假,右边都要执行。
– 短路或||(也叫双或): 如果左边为假,右边执行;如果左边为真,右边不执行。
记忆: 在实际开发中, 我们用的最多的逻辑运算符就是: &&, ||, ! 记
例如:
public class Demo {
public static void main(String[] args) {
boolean x = true;
boolean y = false;
short z = 42; //真 假 42
if ((z++ == 42) && (y = true)) //真 真 43
z++; //真 真 44
if ((x = false) || (++z == 45)) //假 真 45
z++; //假 真 46
System.out.println("z=" + z);
}
}
三元运算符
三元运算符也叫三目运算符,即由三部分组成,格式如下:
(关系表达式) ? 表达式1:表达式2;
执行流程:
先执行关系表达式, 看其结果是true还是false.
如果是true, 则执行表达式1
如果是false, 则执行表达式2
例如:三个数字找出最大值
int num1=100;
int num2=111;
int num3=222;
int temp=num1>num2?num1:num2;
int max= temp?num3?temp:num3;
sout(max);
或://可嵌套 不推荐
int max= (num1>num2?num1:num2)?num3?(num1>num2?num1:num2):num3;
流程控制语句
分类:
• 顺序结构
• 选择结构(if语句, switch.case语句)
• 循环结构(for循环, while循环, do.while循环)
顺序结构
顺序结构指的是代码是按照从上往下,从左往右的顺序,,依次逐行执行的,,且顺序结构也是Java程序的默认结构。
例如:
public class Demo {
public static void main(String[] args) {
sout("a");
sout("b");
sout("c");
sout("d");
sout("e"); // abcde
}
}
选择结构(if语句, switch.case语句)
主要分为以下三种:
if语句(也叫: 单分支)
if…else语句(也叫: 双分支)
if…else if语句(也叫: 多分支)
单分支
结构一般用来判断一种情况, 格式如下:
格式
if(关系表达式) {
//语句体;
}
执行流程:
先执行关系表达式,看其结果是true还是false。
如果是true,则执行大括号中的语句体。
如果是false, 则大括号中的语句体不执行。
例如:
public class Demo {
public static void main(String[] args) {
sout("开始了");
int time = 5;
if(time >= 0 && time <= 8) {
sout("早上好");
}
sout("其他语句");
}
}
双分支
双分支结构指的是if. else语句, 一般用来判断两种情况, 格式如下:
if(关系表达式) { //if的意思: 如果
//语句体1;
} else { //否则…
//语句体2;
}
执行流程:
先执行关系表达式, 看其结果是true还是false。
如果是true,则执行语句体1。
如果是false,则执行语句体2。
例如:
public class Demo {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("请录入一个整数: ");
int num = sc.nextInt();
if (num % 2 == 0) {
System.out.println(num + "是偶数");
} else {
System.out.println(num + "是奇数");
}
}
}
多分支
多分支结构指的是if. else if语句, 一般用来判断多种情况, 格式如下:
if(关系表达式1) {
//语句体1;
} else if(关系表达式2){
//语句体2;
} else if(关系表达式3){ //这里可以根据需求, 有多个else if语句
//语句体3;
} else {
//语句体n;
}
执行流程
先执行关系表达式1,看其结果是true还是false。
如果是true, 则执行语句体1, 整个if语句结束。
如果是false,则判断关系表达式2, 看其结果是true还是false。
如果是true, 则执行语句体2, 整个if语句结束。
如果是false, 则判断关系表达式3, …以此类推。
如果所有的关系表达式都不成立,,则执行else语句的语句体n,整个if语句结束。
例如:键盘输入小明考试成绩,
如果小明考试成绩为95~100奖励山地自行车一辆。
如果小明考试成绩为90~94奖励去游乐园一次。
如果小明考试成绩为80~89奖励变形金刚玩具一个。
如果小明考试成绩为0~79男女混合双打。
import java.util.Scanner;
public class Demo {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("请录入小明的考试成绩: ");
int score = sc.nextInt();
if (score >= 95 && score <= 100) {
System.out.println("奖励小明: 山地自行车一辆");
} else if(score >= 90 && score < 95) {
System.out.println("奖励小明: 游乐场玩儿一次");
} else if(score >= 80 && score < 90) {
System.out.println("奖励小明: 变形金刚玩具一个");
} else if(score >= 0 && score < 80){
System.out.println("奖励小明: 男女双混组合拳 + 扫帚棒法");
} else {
System.out.println("考试成绩录入有误.");
}
}
}
例如:键盘输入狗子年龄,狗子前两年每年相当于人类10.5年,之后每增加一年就增加四岁,那么狗子五岁相当于人类多少年龄?
import java.util.Scanner;
public class Demo1 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("请输入狗狗的年龄:");
int dogAge = sc.nextInt();
if (dogAge==1){
System.out.println("相当于人类10.5岁");
}else if (dogAge==2){
System.out.println("相当于人类"+(int)(10.5*2)+"岁");
}else if (dogAge>2){
int temp=dogAge-2;
double age=temp*4+(int)(10.5*2);
System.out.println("相当于人类"+age+"岁");
}else {
System.out.println("输入有误,请重新上输入");
}
}
}
switch(byte,short,char,int,枚举,String)…case 值:…
格式:
switch(表达式) {
case 值1:
语句体1;
break;
case 值2:
语句体2;
break;
…
default:
语句体n+1;
[break;]
}
执行流程:
首先计算表达式的值。
依次和case后面的值进行比较,如果有对应的值,就会执行相应的语句,在执行的过程中,遇到break就会结束。
如果所有的case后面的值和表达式的值都不匹配,就会执行default里面的语句体,然后程序结束掉。
例如:键盘录入星期数,显示今天的减肥活动。
周一:跑步
周二:游泳
周三:慢走
周四:动感单车
周五:拳击
周六:爬山
周日:好好吃一顿
import java.util.Scanner;
public class Demo {
public static void main(String[] args) {
System.out.println("请输入星期数,显示今天的减肥活动");
Scanner sc = new Scanner(System.in);
int day = sc.nextInt();
switch (day) {
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;
case 6:
System.out.println("爬山");
break;
case 7:
System.out.println("好好吃一顿");
break;
default:
System.out.println("输入有误,请重新输入");
}
}
}
循环语句
for循环
解决什么问题: 当一些需要重复执行的代码 可以循环
格式:
for(①初始化语句;②条件语句,③循环控制语句){
④循环语句体;
}
执行顺序:
1. 初始化语句①
2. 条件语句② 为true 继续往下执行,false循环结束
3. 循环语句体④
4. 循环控制语句③
5. 条件语句② 返回顺序第2步执行
例如:打印输出所有水仙花数。
public class Demo {
public static void main(String[] args) {
for (int i = 100; i <= 999; i++) {
int ge = i % 10;
int shi = i / 10 % 10;
int bai = i / 100 % 10;
//int qian = num / 1000 % 10;
//int wan = num / 10000 % 10;
if (i == ge * ge * ge + shi * shi * shi + bai * bai * bai) {
System.out.println(i);
}
}
}
}
需求:在控制台输出所有的“水仙花数”,要求每行打印2个
public class Demo1 {
public static void main(String[] args) {
int count=0;
for (int i = 100; i <= 999; i++) {
int ge = i % 10;
int shi = i / 10 % 10;
int bai = i / 100 % 10;
//int qian = num / 1000 % 10;
//int wan = num / 10000 % 10;
if (i == ge * ge * ge + shi * shi * shi + bai * bai * bai) {
System.out.print(i+" "); //print 不换行输出
count++;
if (count%2==0){
System.out.println(); //printlin 不换行输出
}
}
}
}
}
需求:求1-5之间的数据和,并把求和结果在控制台输出
public class Demo {
public static void main(String[] args) {
int sum=0;
for (int i = 1; i <= 5; i++) {
sum+=i;
}
System.out.println(sum);
}
}
需求:求1-100之间的偶数和,并把求和结果在控制台输出
public class Demo1 {
public static void main(String[] args) {
int sum=0;
for (int i = 1; i <= 100; i++) {
if (i%2==0){
sum+=i;
}
}
System.out.println(sum);
}
}
while循环
完整格式:
初始化语句①;
while (条件判断语句②) {
循环体语句③;
条件控制语句④;
}
执行流程:
1. 执行初始化语句①
2. 执行条件判断语句②,看其结果是true还是false
如果是false,循环结束
如果是true,继续执行
3. 执行循环体语句③
4. 执行条件控制语句思
5. 回到2继续
例如:需求:世界最高山峰是珠穆朗玛峰(8844.43米=8844430毫米),假如我有一张足够大的纸,它的厚度是0.1毫米。请问,我折叠多少次,可以折成珠穆朗玛峰的高度?
public class Demo {
public static void main(String[] args) {
int zf = 8844430;
double paper = 0.1;
int count = 0;
while (paper < zf) {
paper *= 2;
count++;
}
System.out.println(count);
}
}
在控制台打印10次HelloWorld
public class Demo {
public static void main(String[] args) {
int i = 0;
while(i < 10) {
System.out.println("Hello World!");
i++;
}
}
}
do…while循环
完整格式:
初始化语句①;
do {
循环体语句②;
条件控制语句③;
}while(条件判断语句④);
执行流程:
1. 执行初始化语句①
2. 执行循环体语句②
3. 执行条件控制语句③
4. 执行条件判断语句④,看其结果是true还是false
如果是false,循环结束
如果是true,继续执行
5. 回到2继续
例如:需求 通过do.while循环, 在控制台打印10次Hello World!
public class Demo {
public static void main(String[] args) {
int i = 1;
do{
System.out.println("Hello World! " + i);
i++;
}while(i <= 10);
}
}
三种循环之间区别
-
do…while循环和其他两个循环之间的区别
-
do…while循环是先执行一次, 后判断。
-
而其他两个循环都是先执行判断条件, 然后决定是否执行循环体。
-
-
for循环和其他两个循环之间的区别
- for循环执行结束后, 初始化条件就不能继续使用了。
- 而其他两个循环执行结束后, 初始化条件还可以继续使用.
死循环
在Java中, 死循环的写法格式主要有以下3种:
-
for( ; ; ) { 循环体代码 }
-
while(true){ 循环体代码 }
-
do { 循环体代码 } while(true);
循环跳出
-
break: 是用来终止循环的,循环不再继续执行。
-
continue: 用来结束本次循环,进行下一次循环的, 循环还会继续执行。
例如: 打印10次`HelloWorld`, 当打印第五次的时候, 结束循环.
public class BreakDemo {
public static void main(String[] args) {
System.out.println("start");
for (int i = 1; i <= 10 ; i++) {
if (i == 5)
break;
System.out.println("Hello World! " + i);
}
System.out.println("end");
}
}
需求 打印1~10之间, 所有不是3倍数的整数.
public class ContinueDemo {
public static void main(String[] args) {
System.out.println("start");
for (int i = 1; i <= 10; i++) {
if (i % 3 == 0){
continue;
}
System.out.println(i);
}
System.out.println("end");
}
}
逢七过
public class ContinueDemo {
public static void main(String[] args) {
for (int i = 1; i <= 100; i++) {
if (i%10==7||i/10%10==7||i%7==0){
continue;
}
System.out.print(i+" ");
}
}
}
随机数
Random 随机生成[0,值);
步骤
- 导包
- 创建对象
- 获取随机数
1. import java.util.Random;
2. Random r=new Random();
3. int num=r.nextInt(值);
例如:生成5个1~10之间的随机整数, 并将结果打印到控制台
import java.util.Random;
public class Demo1 {
public static void main(String[] args) {
Random r = new Random();
int num;
for (int i = 1; i <= 5; i++) {
num = r.nextInt(10) + 1;
System.out.println(num);
}
}
}
猜数字
需求
1. 生成一个1~100(70~80)之间的随机数, 让用户来猜
2. 如果猜的数字比生成的随机数大,提示你猜的数据大了
3. 如果猜的数字比生成的随机数小,提示你猜的数据小了
4. 如果猜的数字与生成的随机数相等,提示恭喜你猜中了
import java.util.Random;
import java.util.Scanner;
public class Demo {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
Random r=new Random();
int temp=r.nextInt(100)+1;
while (true) {
System.out.println("用户键盘录入猜的数字:");
int num = sc.nextInt();
if (num == temp) {
System.out.println("猜中了");
break;
}
if (num < temp) {
System.out.println("小了");
}
if(num > temp) {
System.out.println("大了");
}
}
}
}
import java.util.Scanner;
public class Demo {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int temp = (int) (70 + Math.random() * (80 - 70 + 1));
while (true) {
System.out.println("用户键盘录入猜的数字:");
int num = sc.nextInt();
if (num == temp) {
System.out.println("猜中了");
break;
}
if (num < temp) {
System.out.println("小了");
}
if(num > temp) {
System.out.println("大了");
}
}
}
}
数组
数组是一种容器,用来存储同数据类型的多个值。
容器的类型和 存储的数据类型要保持一致。
Java中的数组必须先初始化,然后才能使用。
所谓初始化:就是在内存中,为数组容器开辟空间,并将数据存入容器中的过程。
动态初始化
数据类型[] 数组名=new 数据类型[长度];
数据类型 数组名[]=new 数据类型[长度];
int[] arr=new arr[3];
int arr[]=new arr[3];
静态初始化
数据类型[] 数组名=new 数据类型[]{值1,值2,值3…};
数据类型[] 数组名={值1,值2,值3…};
int[] arr=new int[]{1,2,3,4};
int[] arr={1,2,3,4};
动态初始化和静态初始化
动态初始化:手动指定数组长度,由系统给出默认初始化值。
静态初始化:手动指定数组元素,系统会根据元素个数,计算出数组的长度
数组元素的访问
数组名[索引]
索引是数组容器中空间的编号
- 索引从0开始的
- 索引是连续的
- 索引逐一增加,每次加1
索引的作用:访问数组容器中的空间位置
内存分配
栈内存:方法运行时,进入的内存,局部变量都存放于这块内存当中
堆内存:new出来的内容都会进入堆内存,并且会存在地址值
方法区:字节码文件(.class文件)加载时进入的内存
数据类型 | 默认值 |
---|---|
整数 | 0 |
浮点数 | 00 |
布尔 | false |
字符 | 空字符 |
引用数据类型 | null |
注意:
多个数组时,每new一次,在堆内存中,都是一块新的空间,堆内存中的空间地址不会出现重复。
数组操作常见的两个小问题
- 索引越界
int[] arr=new int[3];
arr[3].sout;
- 空指针异常
int[] arr=new int[3];
arr=null;
arr[0].sout;
数组遍历
数组长度:arr.length
例如:遍历数组
public class Demo {
public static void main(String[] args) {
//1. 定义int类型的数组arr, 存储元素11, 22, 33, 44, 55.
int[] arr = {11, 22, 33, 44, 55};
//2. 通过for循环, 遍历数组.
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
}
}
求最大值
public class Demo {
public static void main(String[] args) {
int[] arr = {5, 15, 2000, 10000, 100, 4000};
int max = arr[0];
for (int i = 0; i < arr.length; i++) {
if (max < arr[i])
max = arr[i];
}
System.out.println("最大值为: " + max);
}
}
求最小值
public class Demo {
public static void main(String[] args) {
int[] arr = {152, 150, 163, 171, 128};
int min = arr[0];
for (int i = 1; i < arr.length; i++) {
if (arr[i] < min) {
min = arr[i];
}
}
System.out.println("最大值为: " + min);
}
}
定义功能,遍历数组中的所有元素,打印并以逗号( , )隔开每个元素。
有数组: int[] arr = {1,2,3,4,5,6,7,8,9};
public class Demo {
public static void main(String[] args) {
int[] arr = {1, 2, 3, 4, 5, 6, 7, 8, 9};
System.out.print("[");
for (int i = 0; i < arr.length; i++) {
if (arr.length-1==i){
System.out.print(arr[i]+"]");
}else {
System.out.print(arr[i]+",");
}
}
}
}
求出数组中索引与索引对应的元素都是奇数的元素
public class Demo {
public static void main(String[] args) {
int[] arr = {152, 150, 163, 171, 128};
for (int i = 0; i < arr.length; i++) {
if (i%2!=0&&arr[i]%2!=0){
System.out.println("下标"+i+"元素"+arr[i]);
}
}
}
}
按要求在main方法中完成以下功能:
1. 定义一个长度为5的int型数组arr,提示用户输入5个1-60之间的数字作为数组元素
2. 生成2-10(范围包含2和10)之间的随机数num
3. 遍历数组arr,筛选出数组中不是num倍数的元素并输出
public class Demo {
public static void main(String[] args) {
System.out.println("输入5个1-60之间的数字:");
Scanner sc = new Scanner(System.in);
int []arr =new int[5];
for (int i = 0; i < 5; i++) {
arr[i]= sc.nextInt();
}
System.out.println("--------");
int temp= (int)(2+Math.random()*(10-2+1));
System.out.println("2-10(范围包含2和10)之间的随机数为"+temp);
System.out.println("筛选出数组中不是num倍数的元素并输出");
for (int i = 0; i < arr.length; i++) {
if (arr[i]%temp!=0){
System.out.println(arr[i]);
}
}
}
}
有一个数组int[] arr = {9,1,3,4,54,56,23,22,20,43,45,78};,要求打印数组中能被6整除的元素。
public class Demo {
public static void main(String[] args) {
int[] arr = {9, 1, 3, 4, 54, 56, 23, 22, 20, 43, 45, 78};
for (int i = 0; i < arr.length; i++) {
if (arr[i]%6==0){
System.out.println(arr[i]);
}
}
}
}
定义一个长度为20的数组,元素为20-40的随机数,要求判断指定元素在数组中出现的次
public class Demo {
public static void main(String[] args) {
System.out.println("键盘录入范围为20-40之间:");
Scanner sc = new Scanner(System.in);
int num = sc.nextInt();
int [] arr=new int[20];
for (int i = 0; i < arr.length; i++) {
arr[i]=(int)(20*Math.random()*(40-20+1));
}
int count=0;
for (int i = 0; i < arr.length; i++) {
if (arr[i]==num){
count++;
}
}
System.out.println(count);
}
}
定义功能完成数组的求和。一个功能求偶数和,一个功能求奇数和。一个功能求总和。
数组: int[] arr = {1,2,3,4,5,6,7,8,9};
public class Demo {
public static void main(String[] args) {
int[] arr = {1,2,3,4,5,6,7,8,9};
int ou=0;
int ji=0;
int num=0;
for (int i = 0; i < arr.length; i++) {
if (arr[i]%2==0){
ou+=arr[i];
}else if (arr[i]%2!=0){
ji+=arr[i];
}
num+=arr[i];
}
System.out.println("偶数:"+ou);
System.out.println("奇数:"+ji);
System.out.println("总和:"+num);
}
}
定义功能,计算出数组中的最小值。
数组: int[] arr = {1,43,43,5,4,6,6,7,7,88,9,9,9,0,0,9};
public class Demo {
public static void main(String[] args) {
int[] arr = {1,43,43,5,4,6,6,7,7,88,9,9,9,0,0,9};
int min=0;
for (int i = 0; i < arr.length; i++) {
if (arr[i]<=min){
min=arr[i];
}
}
System.out.println(min);
}
}
定义功能,计算出数组中指定元素出现的次数。
数组: int[] arr = {1,43,43,5,4,6,6,7,7,88,9,9,9,0,0,9};
指定元素: int x = 9;
public class Demo {
public static void main(String[] args) {
int[] arr = {1,43,43,5,4,6,6,7,7,88,9,9,9,0,0,9};
int x=9;
int count=0;
for (int i = 0; i < arr.length; i++) {
if (arr[i]==x){
count++;
}
}
System.out.println(count);
}
}
定义功能,将数组中的0元素,使用1-10之间的随机数替换掉。
数组: int[] arr = {1,43,43,5,4,6,6,7,7,88,9,9,9,0,0,9};
public class Demo {
public static void main(String[] args) {
int[] arr = {1,43,43,5,4,6,6,7,7,88,9,9,9,0,0,9};
int x=0;
for (int i = 0; i < arr.length; i++) {
if (arr[i]==x){
arr[i]=(int)(Math.random()*10+1);
}
}
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i]+" " );
}
}
}
方法
方法(method)也叫函数,是将具有独立功能的代码块组织成为一个整体,使其成为具有特殊功能的代码集。
格式:
修饰符 返回值的数据类型 方法名(参数类型 参数名1, 参数类型 参数名2){ //这里可以写多个参数
//方法体;
return 具体的返回值;
}
格式解释:
• 修饰符: 目前记住这里是固定格式public static
• 返回值的数据类型: 用于限定返回值的数据类型的
注意:
-
返回值的数据类型是int类型, 则说明该方法只能返回int类型的整数
-
如果方法没有具体的返回值, 则返回值的数据类型要用void来修饰
• 方法名: 方便我们调用方法
• 参数类型: 用于限定调用方法时传入的数据的数据类型
例如: 参数类型是String类型, 说明我们调用方法时,只能传入字符串
• 参数名: 用于接收调用方法时传入的数据的变量
• 方法体: 完成特定功能的代码
• return 返回值: 用来结束方法的, 并把返回值返回给调用者
解释: 如果方法没有明确的返回值, 则return关键字可以省略不写
注意事项:
方法与方法之间是平级关系, 不能嵌套定义。
方法必须先创建才可以使用,,该过程称为: 方法定义。
方法自身不会直接运行, 而是需要我们手动调用方法后, 它才会执行, 该过程称为方法调用。
方法的功能越单一越好。
定义方法的时候写在参数列表中的参数, 都是: 形参.
形参: 形容调用方法的时候, 需要传入什么类型的参数。
调用方法的时候, 传入的具体的值(变量或者常量都可以),叫实参。
实参: 调用方法时,实际参与运算的数据。
方法的调用
格式 : 方法名();
解释: 通过方法名();的形式, 可以直接根据方法名调用指定的方法.
无参无返回值的方法
定义方法时,要做到三个明确, 这样定义方法就会变得非常简单了:
明确方法名, 即: 方法名要符合小驼峰命名法, 且要见名知意, 方便我们调用。
明确方法的参数列表。即: 调用方法时, 我们需要给它(方法)什么数据。
明确方法的返回值类型。 即: 调用方法完毕后,方法会返回给我们一个什么类型的数据。
格式:
public static void 方法名() {
//方法体;
}
有参无返回值的方法
有参无返回值的方法的意思是: 调用方法时, 我们需要传入具体的参数,但是方法执行完毕后, 并不会给我们返回具体的结果。
格式
public static void 方法名(参数类型 参数名1, 参数类型 参数名2) { //这里可以写多个参数
//方法体;
}
具体调用格式
方法名(参数值1, 参数值2); //注意: 参数的个数, 以及对应的参数类型都要和定义方法的参数列表保持一致.
例如:
需求
1.定义方法isEvenNumber(), 该方法接收一个int类型的整数num。
2.判断num是奇数还是偶数,并打印结果。
public class Demo2 {
public static void main(String[] args) {
//调用方法
isEvenNumber(20);
}
//方法: 判断数值奇偶数,并打印
public static void isEvenNumber(int num){
//判断传递过来数值,是奇数还是偶数
if(num%2==0){
System.out.println("是偶数");
}else{
System.out.println("是奇数");
}
}
}
无参有返回值的方法
无参有返回值的方法的意思是: 调用方法时,我们不需要传入具体的参数, 但是方法执行完毕后, 会给我们返回具体的结果。
格式
public static 返回值的数据类型 方法名() {
//方法体;
return 具体的返回值;
}
有参有返回值的方法
有参有返回值的方法的意思是: 调用方法时, 我们不仅需要传入具体的参数,方法执行完毕后, 还会给我们返回具体的结果。
格式
public static 返回值的数据类型 方法名(参数类型 参数1, 参数类型 参数2) {
//方法体;
return 具体的返回值;
}
例如
需求
1. 定义方法getMax(), 接收一个int类型的数组
2. 通过该方法, 获取数组元素中的最大值
3. 在main方法中, 调用方法, 打印对应的结果
参考代码
public class Demo {
public static void main(String[] args) {
int[] array = {12, 20, 21, 24, 33};
//调用getMax方法,并传递int类型数组到方法中
int max = getMax(array);
System.out.println("最大值:" + max);
}
//方法:遍历数组并获取最大值
public static int getMax(int[] array) {
//假设最大值为:array[0]元素
int max = array[0];
//遍历数组(从索引1开始,因为array[0]已设定为最大值)
for (int i = 1; i < array.length; i++) {
//比较max和数组中元素大小
if (max < array[i]) {
//如果数组中的元素大,则把元素值赋给max
max = array[i];
}
}
//数组遍历后,就拿到了最大值
return max;//返回最大值
}
}
方法的重载
方法(method)就是一段具有独立功能的代码块,不调用就不执行。
特点:
- 在同一个类中
- 方法名相同
- 参数列表不同(个数,类型,顺序)
- 与返回值的数据类型无关
例如:
public static void open(){}
public static void open(int a){}//是重载。 参数个数
static void open(int a,int b){}//是重载 参数个数
public static void open(double a,int b){}//是重载 参数顺序
public static void open(int a,double b){}//是重载 参数顺序
public void open(int i,double d){} //不是重载 参数个数顺序类型
public static void OPEN(){} //不是重载 (java区分大小写)
public static void open(int i,int j){} //不是重载 参数个数顺序类型
方法练习题
例如:
定义 getNewArr()静态方法:要求传入一个int类型的数组arr,遍历数组,将数组中小于10**的元素替换成0,然后返回修改之后的数组
在main方法中完成:
1. 定义一个长度为5的int类型的数组
2. 随机生成5个随机数存入数组(随机数的范围为5到50,包括5和50),并把数组中的元素打印在控制台
3. 调用getNewArr方法,在控制台打印返回后的数组中的元素
public class Demo {
public static void main(String[] args) {
int []arr =new int[5];
for (int i = 0; i < 5; i++) {
arr[i]=(int)(5+Math.random()*(50-5+1));
}
getNewArr(arr);
}
public static void getNewArr(int[] arr){
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
}
}
系统产生一个70-80之间的随机数,请猜出这个数字是多少。
(猜中之后程序就结束,没有猜中则继续猜)
详细步骤:
1.利用Random产生一个随机数,范围70-80(包括70和80)。
2.提示用户键盘录入猜的数字
3.比较这两个数字(用if语句)
大了:给出提示大了,并且继续猜
小了:给出提示小了,并且继续猜
猜中了:给出提示,恭喜你,猜中了,并且结束循环
public class Demo {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int temp = (int) (70 + Math.random() * (80 - 70 + 1));
while (true) {
System.out.println("用户键盘录入猜的数字:");
int num = sc.nextInt();
if (num == temp) {
System.out.println("猜中了");
break;
}
if (num < temp) {
System.out.println("小了");
}
if(num > temp) {
System.out.println("大了");
}
}
}
}
在主方法中定义一个长度为10的数组,数组中元素使用随机数赋值,随机数范围为23-57(包括23与57)判断偶数的个数,并输出
public class Demo {
public static void main(String[] args) {
int[] arr=new int[10];
for (int i = 0; i < arr.length; i++) {
arr[i]=(int)(23+Math.random()*(57-23+1));
}
int count=0;
for (int i = 0; i < arr.length; i++) {
if (arr[i]%2==0){
count++;
}
}
System.out.println(count);
}
}
定义方法,参数为整数数组与指定元素,判断数组中有多少个能整除指定元素的,在主方法中输出。
数组int[] arr = {12,43,45,76,78,98,23,21,34,56};指定元素为2;
public class Demo {
public static void main(String[] args) {
int[] arr = {12,43,45,76,78,98,23,21,34,56};
int num=2;
demo1(arr,num);
}
public static void demo1(int[] arr,int num){
for (int i = 0; i < arr.length; i++) {
if (arr[i]%2==0){
System.out.print(arr[i]+" ");
}
}
}
}
定义一个长度为5的数组arr1,用于存放5个1~9的随机整数(范围包含1和9),再定义一个长度为2的数组arr2,统计arr1中的元素对2求余等于0的个数,保存到arr2[0], 统计arr1中的元素对3求余等于0的个数,保存到arr2[1],在控制台打印输出arr2的所有元素
public class Demo {
public static void main(String[] args) {
int[] arr1=new int[5];
for (int i = 0; i < 5; i++) {
arr1[i]=(int) (1+Math.random()*(9-1+1));
}
int count=0;
for (int i = 0; i < arr1.length; i++) {
if (arr1[i]%2==0){
count++;
}
}
int[] arr2=new int[2];
arr2[0]=count;
int count1=0;
for (int i = 0; i < arr1.length; i++) {
if (arr1[i]%3==0){
count1++;
}
}
arr2[1]=count1;
for (int i = 0; i < arr2.length; i++) {
System.out.print(arr2[i]+" ");
}
}
}
进制
进制:指进位制,是人们规定的一种进位方式
表示某一位置上的数,运算时是逢X进一位。
十进制是逢十进一,二进制就是逢二进一,八进制是逢八进一…
为什么要学进制?
原因:计算机数据在底层运算的时候,都是以二进制形式。
也有数据是以八进制、十进制、或者十六进制进行存储或运算,了解不同的进制,便于我们对数据的运算过程理
解的更加深刻。
二进制
介绍:二进制数据是用0和1两个数码来表示。例如:0101000
进位规则是“逢二进一”,借位规则是“借一当二”。
八进制
采用0,1,2,3,4,5,6,7八个数字,逢八进一;
十六进制
用数字0到9和字母A到F(或af)表示,其中:AF表示10~15,这些称作十六进制。
【0】【1】【2】【3】【4】【5】【6】【7】【8】【9】【a】【b】【c】【d】【e】【f】
不同进制的书写格式:
十进制:Java中,数值默认都是10进制,不需要加任何修饰。
二进制:数值前面以0b开头,b大小写都可以。
八进制:数值前面以0开头。
十六进制:数值前面以0x开头,x大小写都可以。
二进制转十进制
例如: 1 0 0
1*2`2 +0*2`1 +0*2`0
十六进制转十进制
例如: 1 0 0
1*16`2 0*16`1 0*16`0
十进制转二进制
例如 11 --》1001 从下往上 7--》111
11/2 1 7/2 1
5/2 1 3/2 1
1/2 0 1/2 1
1
快速进制转换 8421码
8421码又称BCD码,是BCD代码中最常用的一种。
BCD: (Binary-Coded Decimal) 二进制码十进制数。
在这种编码方式中,每一位二进制值的1都是代表一个固定数值,把每一位的1代表的十进制数加起来得到的结果
就是它所代表的十进制数。
二进制快速转八进制
八进制:将三个二进制位看为一组,再进行转换
原因:八进制逢八进一,三个二进制位最多可以表示111,也就是数值7,如果出现第四位,就超范围了
将60的二进制0b111100转换为八进制
4 2 1 4 2 1
1 1 1 1 1 1
1 1 1 1 0 0
4+2+1=7 4
74
二进制快速转十六进制
十六进制:将四个二进制位看为一组,再进行转换
原因:十六进制逢十六进一,四个二进制位最多可以表示1111,也就是数值15,如果出现第五位,就超范围了
将60的二进制0b111100转换为三十六进制
8 4 2 1 8 4 2 1
1 1 1 1 1 1 1 1
0 0 1 1 1 1 0 0
2+1=3 8+4=12
原码反码补码
注意:计算机中的数据,都是以二进制补码的形式在运算,而补码则是通过反码和原码推算出来的。
原码(可直观看出数据大小)
就是二进制定点表示法,即最高位为符号位,【0】表示正,【1】表示负,其余位表示数值的大小。
通过一个字节表示+7和-7,代码:byte b1 = 7; byte b2 = -7;
一个字节等于8个比特位,也就是8个二进制位
0(符号位) 0000111
1(符号位) 0000111
反码
正数的反码与其原码相同;负数的反码是对其原码逐位取反,但符号位除外。
补码(数据以该状态进行运算)
正数的补码与其原码相同;负数的补码是在其反码的末位加1。
位算符
符号 | 计算方式 |
---|---|
& | 遇到0(false)则0(false),两边同时为1(true),结果才是1(true) |
| | 遇到1(true)则1(true),两边都是0(false),结果才是0(false) |
^ | 相同为false,不同为true |
~ | 取反,二进制位全部取反,0变1,1变0,包括符号位 |
<< | 有符号左移运算,左边符号位丢弃,右边补齐0 |
>> | 有符号右移运算,根据符号位,补齐左边 |
>>> | 无符号右移,无论最符号位是0还是1,都补0 |
异或运算的特点
一个数,被另外一个数,异或两次,该数本身不变。
数据交换
需求:已知两个整数变量a = 10,b = 20,使用程序时间这两个变量的数据交换
最终输出a = 20,b = 10;
public static void main(String[] args) {
int a = 10;
int b = 20;
a = a ^ b;
b = a ^ b;
a = a ^ b;
System.out.println(a);
System.out.println(b);
}
解释:
a = a ^ b; // a = 10 ^ 20;
b = a ^ b; // b = 10 ^ 20 ^ 20;
a = a ^ b; // a = 10 ^ 20 ^ 10;
反转
需求:数组数据反转
for(int start=0,end=arr.length-1;start<end;start++,end--){
int temp = arr[start];
arr[start] =arr[end];
arr[end] = temp;
}
二维数组
二维数组也是一种容器,不同于一维数组,该容器存储的都是一维数组容器。
动态初始化
数据类型[][]变量名=new 数据类型[长度][长度];
数据类型[][]变量名=new 数据类型[长度][];
静态初始化
数据类型[][]变量名={{值1,值2,值3..},{值1,值2...},{值1}};
二维数组遍历案例
for(int i<0;i<arr.length;i++){
for(int j=0;j<arr[i].length;j++){
sout(arr[i][j]);
}
}
例如:
输出100以内被6整除的数字,每5个换一行,
如:
1 2 3 4 5
6 7 8 9 10
。。。。。
public class Demo {
public static void main(String[] args) {
int num=0;
for (int i = 1; i <= 100; i++) {
if (i%6==0){
num++;
System.out.print(i+" ");
if (num%5==0){
System.out.println("");
}
}
}
}
}
有一个输出语句System.out.print("@")。使用这个语句,在控制台打印出一个四行五列的长方形,效果如下:
@@@@@
@@@@@
@@@@@
@@@@@
分析:
A) 已知条件中只有一个@,如何在一行打印出多个?
B) 如何把一行@变成多行?
解决方案:使用嵌套循环完成
步骤:1、定义循环执行4次代表一共4行
2、定义内层循环执行5次代表每行5个符号
3、在内层循环中输出符号
4、每行结束之后执行换行操作
public class Demo {
public static void main(String[] args) {
for (int i = 0; i < 4; i++) {
for (int i1 = 0; i1 < 5; i1++) {
System.out.print("@");
}
System.out.println("@");
}
}
}
使用for循环打印出九九乘法表。打印效果如下:
分析:
乘法表有9行,9列,怎么完成?需要使用循环嵌套
步骤:
1、 使用for循环代表9行数据
2、 在for循环中嵌套for循环代表每行要打印的列数
3、 在内部for循环中打印每一个等式,等式和等式之间用制表符隔开(System.out.print(j + "*" + i + "=" + j*i + "\t"); 其中”\t”是制表符)
4、 没打印完一行等式之后执行换行操作
public class Demo {
public static void main(String[] args) {
for (int i = 1; i <= 9; i++) {
for (int i1 = 1; i1 < i; i1++) {
System.out.print(i1+"*"+i+"="+(i*i1)+" ");
}
System.out.println();
}
}
}
面向对象
是一种思想,将生活中所见到的事物 抽象,看作为程序中的一个对象,将我们从一个执行者变成一个指挥者,将复杂的问题简单化。
类与对象的关系
对象是类的是实例。
类是对象的抽象定义。
类是对具有一组同属性,行为的事物的一种抽象。
对象是具体存在的某一事物。
类负责描述共同的属性和行为,对象根据我们的属性行为创造出来的具体存在。
public class Student{
//成员变量 属性
String name;
int age;
double gender;
String phone;
String addr;
//成员方法 行为
public void eat(){
sout("吃面");
}
public void sleep(){
sout("睡觉");
}
}
封装
将具体的实现进行隐藏,只对外暴露公共的访问方法。
使用封装的好处:
- 提高代码的安全性
- 提高代码的复用性
常见的封装:
- 将代码封装在方法中,提高代码的复用性
- 将属性私有化,提供get/set方法 ,提高代码的安全性和复用性
关键字private
- 权限修饰符
- 修饰成员变量以及成员方法
- 特点:只能在本类中使用
- 提高代码安全性
关键字 this
作用:哪一个的对象调用成员方法,在方法中this 就代表谁。
通过关键字来区分调用的是哪一个内存空间中属性/行为。
给成员变量赋值 区分参数列表
public class Student{
private String name;
private int age;
private boolean gender;
private String phone;
private String addr;
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;
}
...
}
构造方法
用来创建对象时调用方法。
本质作用是初始化对象。
执行时机:
- 每次创建对象(new)时
- 每创建一个对象就会调用一次
- 可以利用执行时机,完成初始化。
注意事项:
如果你没有无参构造,系统默认提供一个无参构造
如果定义了一个构造方法,系统将不默认提供无参构造
建议:
两个都写
一个标准的JavaBean类
public class Student{
//成员变量
private String name;
private int age;
//构造方法
public Student{
}
public Student(String name,int age){
this.name=name;
this.age=age;
}
//getter and setter 方法
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;
}
}
例如:编写一个Student类,包含name、gender、age、id、score属性,分别为String、String、int、int、double类型。设置get/set方法,有参无参构造方法,创建三个对象并且完成初始化,存入数组中,遍历输出。
public class Stu {
private String name;
private String gender;
private int age;
private int id;
private double score;
public Stu() {
}
public Stu(String name, String gender, int age, int id, double score) {
this.name = name;
this.gender = gender;
this.age = age;
this.id = id;
this.score = score;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public double getScore() {
return score;
}
public void setScore(double score) {
this.score = score;
}
@Override
public String toString() {
return "Stu{" +
"name='" + name + '\'' +
", gender='" + gender + '\'' +
", age=" + age +
", id=" + id +
", score=" + score +
'}';
}
}
public class StuTest {
public static void main(String[] args) {
Stu stu1 = new Stu("张三", "男", 18, 1, 90.2);
Stu stu2 = new Stu("李四", "nan", 12, 2, 98.5);
Stu stu3 = new Stu("王五", "nan", 12, 3, 99.2);
Stu[] arr = new Stu[3];
arr[0] = stu1;
arr[1] = stu2;
arr[2] = stu3;
for (Stu stu : arr) {
System.out.println(stu);
}
}
}
API
Application programming interface 应用程序编程接口
Java API
指的是JDK中提供的各种功能的JAVA类
这些类将底层的实现封装了起来,我们不需要这些类是如何实现的,只需要学习这些类如何使用即可。
Scanner
键盘输入
注意事项:
- next 结束符 空格 制表符
- nextLine 结束符 回车
- 当nextLine和nextInt配合使用的时候 有可能会导致字符串无法录入
public class Demo {
public static void main(String[] args) {
System.out.println("输入一个数字:");
Scanner sc = new Scanner(System.in);
int num = sc.nextInt();
System.out.println(num);
System.out.println("输入一个字符串:");
String str = sc.nextLine(); //不可达
System.out.println(str);
}
}
解决方法
1. 换位置;
2. nextLine()换为next()接收;
String
字符串,开发中经常对字符串进行处理 比较 切割等等
大数据开发,日志服务器中日志 他们都是一些字符串 我们需要对日志中的字符串进行处理(ETL处理)
注意事项:
-
String类在Java.lang包下,所有使用时候不需要导包。
-
Java程序中,所有的双引号字符串都是String类的对象。
-
字符串不可变,是一个常量,他们的值在创建后不能被改变。
-
直接采用字符串创建对象的方式 会在常量池中创建一个字符串 如果这个字符串存在 会复用常量池中的字符串 记
-
常量池
2. JDK1.7之前在方法区中
3. JDK1.7开始在堆内存中 -
new的方式创建字符串的对象会产生两个对象
- 两个对象
- 字符串本身
- 字符串对象
- 两个对象
-
当字符串的变量和字符串相加的时候 每一次相加都会产生一个StringBuilder的对象进行append()拼接的操作每相加一次 都会产生这个对象 记
第一种:创建的字符串放在了串池中 共享
//第一种方式
String string1 = "hello";
//hello放在了串池中共享
String string2 = "hello";
System.out.println(string1==string2);//true
第二种:
//第二种 通过构造方法创建字符串
String string = new String("hello");
注意:这行代码创建了两个对象 一个对象 hello字符串 放在了串池中用于共享 一个通过new创建 放到了堆里
面试题
public class DemoString1 {
public static void main(String[] args) {
String s1="abc";
String s2="abc";
sout(s1==s2); //true
}
}
public class DemoString2 {
public static void main(String[] args) {
String s1="abc";
String s2=new String("abc");
sout(s1==s2); //false
}
}
public class DemoString3{
public static void main(String[] args) {
String s1="abc";
String s2="ab";
String s3=s2+"c";
sout(s1==s3); //false
}
}
DemoString3 ,先在方法区test3.class main ,s1的abc s2的ab在常量池中 ,s3会在堆中创建StringBuider对象使用append拼接 c(c常量池中), 然后toString()转化为string类型在堆中
常见的构造方法
方法名 | 说明 |
---|---|
public String() | 创建一个空白字符串对象,不含有任何内容 |
public String(char[] chs) | 根据字符数组的内容,来创建字符串对象 |
public String(String original) | 根据传入的字符串内容,来创建字符串对象 |
String中的方法
方法名 | 说明 |
---|---|
public boolean equals(Object anObject) | 比较字符串的内容,严格区分大小写 |
public boolean equalsIgnoreCase(String anotherString) | 比较字符串的内容,忽略大小写 |
public int length() | 返回此字符串的长度 |
public char charAt(int index) | 返回指定索引处的 char 值 |
public char[] toCharArray() | 将字符串拆分为字符数组后返回 |
public String substring(int beginIndex, int endIndex) | 根据开始和结束索引进行截取,得到新的字符串(包含头,不包含尾) |
public String substring(int beginIndex) | 从传入的索引处截取,截取到末尾,得到新的字符串 |
public String replace(CharSequence target, CharSequence replacement) | 使用新值,将字符串中的旧值替换,得到新的字符串 |
public String[] split(String regex) | 根据传入的规则切割字符串,得到字符串数组 |
案例
案例:
public class DemoString {
public static void main(String[] args) {
//第二种 通过构造方法创建字符串
//string1 堆里
String string1 = new String("hello");
//string2 串池中
String string2 = "hello";
System.out.println(string1==string2);//false
System.out.println(string1.equals(string2));//true
}
}
案例: 设置字符串为"woaiheima,buguanheimahaishibaima,zhaodaogongzuojiushihaoma" 计算里面有出现几次"heima"。
public class Demo {
public static void main(String[] args) {
String str = "woaiheima,buguanheimahaishibaima,zhaodaogongzuojiushihaoma";
// int count=0;
// String str1="heima";
// for (int i = 0; i <str.length()-5; i++) {
// String sub = str.substring(i, i + 5);
// if (sub.equals(str1)){
// count++;
// }
// }
// System.out.println(count);
String newStr = str.replace("heima", "");
int count = (str.length() - newStr.length()) / "heima".length();
System.out.println("count = " + count);
}
}
/*
* 已知数字1, 2, 3, 4, 问其能组合成的4位数字有多少种形式, 并将结果打印到控制台上.
需求1: 该四位数必须包含1, 2, 3, 4. 例如: 1234, 1243, 1432...
需求2: 在需求1的基础上加入数字4不能开头.
需求3: 在需求2的基础上加入数字1和3不能挨着, 即: 1324, 3124都不行.
//以上3个需求, 分开进行输出.
* */
public class Demo {
public static void main(String[] args) {
getCount();
System.out.println(" ---------------------------------------------- ");
getCountNot4();
System.out.println(" ---------------------------------------------- ");
getCountNot4And13();
}
public static void getCount() {
for (int i = 1234; i <= 4321; i++) {
String strNum = i + "";
if (strNum.contains("1") && strNum.contains("2") && strNum.contains("3") && strNum.contains("4")) {
System.out.println(strNum);
}
}
}
public static void getCountNot4() {
for (int i = 1234; i <= 4321; i++) {
String strNum = i + "";
if(strNum.contains("1") && strNum.contains("2") && strNum.contains("3") && strNum.contains("4")
&& !strNum.startsWith("4")){
System.out.println(strNum);
}
}
}
public static void getCountNot4And13 () {
for (int i = 1234; i <= 4321; i++) {
String strNum = i + "";
if(strNum.contains("1") && strNum.contains("2") && strNum.contains("3") && strNum.contains("4")
&& !strNum.startsWith("4") && !strNum.contains("13") && !strNum.contains("31")){
System.out.println(strNum);
}
}
}
}
案例:用户登录
需求:已知用户名和密码,请用程序实现模拟用户登录。总共给三次机会,登录之后,给出相应的提示
import java.util.Scanner;
public class Demo {
public static void main(String[] args) {
String name = "xfz";
String passwd = "123";
Scanner sc = new Scanner(System.in);
for (int i = 1; i <= 3; i++) {
System.out.println("请输入账号:");
String uname = sc.nextLine();
System.out.println("请输入密码:");
String upasswd = sc.nextLine();
if (uname.equals(name) && upasswd.equals(passwd)) {
System.out.println("登录成功");
break;
} else {
if (i == 3) {
System.out.println("三次机会已用完,请稍后再试");
} else {
System.out.println("您还有" + (3 - i) + "次");
}
}
}
}
}
案例:遍历字符串
需求:键盘录入一个字符串,使用程序实现在控制台遍历该字符串
import java.util.Scanner;
public class Demo {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("请输入一个字符串:");
String str = sc.nextLine();
for (int i = 0; i <str.length() ; i++) {
System.out.print(str.charAt(i)); //charAt()
}
}
}
import java.util.Scanner;
public class Demo {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("请输入一个字符串:");
String str = sc.nextLine();
char[] chars = str.toCharArray(); //toCharArray()
for (int i = 0; i < chars.length; i++) {
System.out.print(chars[i]);
}
}
}
案例:统计一个字符串中大写字母字符,小写字母字符,数字字符出现的次数。(不考虑其他字符)
分析:
A:键盘录入一个字符串数据
B:定义三个统计变量,初始化值都是0
C:遍历字符串,得到每一个字符
D:拿字符进行判断
假如ch是一个字符。
大写:ch>='A' && ch<='Z'
小写:ch>='a' && ch<='z'
数字:ch>='0' && ch<='9'
E:输出结果
public class Demo {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String str = sc.next();
int max=0;
int min=0;
int num=0;
for(int i=0;i<str.length();i++){
char temp= str.charAt(i);
if (temp>='A'&& temp<='Z'){
max++;
}
if (temp>='a'&&temp<='z'){
min++;
}
if (temp>='0'&&temp<='9'){
num++;
}
}
System.out.println(max+" "+min+" "+num);
}
}
案例:手机号屏蔽
需求:以字符串的形式从键盘接受一个手机号,将中间四位号码屏蔽
最终效果为:156****1234
import java.util.Scanner;
public class Demo {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("请输入手机号:");
String str = sc.nextLine();
String start = str.substring(0, 3);
String end=str.substring(7);
System.out.println(start+"****"+end);
}
}
案例:敏感词替换
需求:键盘录入一个 字符串,如果字符串中包含(TMD),则使用***替换
public class Demo {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("请输入手机号:");
String str = sc.nextLine();
String newStr=str.replace("TMD","***");
System.out.println(newStr);
}
}
案例 :切割字符串
需求:以字符串的形式从键盘录入学生信息,例如:“张三 , 23”从该字符串中切割出有效数据
封装为Student学生对象
import java.util.Scanner;
public class Demo {
public static void main(String[] args) {
Student stu = new Student();
Scanner sc = new Scanner(System.in);
System.out.println("请输入学生信息:");
String str = sc.nextLine();
String[] splits = str.split(",");
stu.setName(splits[0]);
stu.setAge(splits[1]);
System.out.println(stu.getName());
System.out.println(stu.getAge());
}
}
案例:获取一个字符在一个字符串中出现的次数
比如:String st = "adfdfsfksdfsdjfhsjdfhsfkdfgjdfkgljlds";
字符‘f’在字符串st中出现的次数
public class Demo {
public static void main(String[] args) {
String st = "adfdfsfksdfsdjfhsjdfhsfkdfgjdfkgljlds";
int count=0;
for (int i=0;i<st.length();i++){
if (st.charAt(i)=='f'){
count++;
}
}
System.out.println(count);
}
}
案例:编写一个Java程序,提示用户输入一串字符串,要求字符串中必须存在字母(需要代码判断)**
1. 若不符合要求,则提示用户重新输入直至符合要求为止
2. 若符合要求,则判断字符串中大写字母出现次数并打印。
import java.util.Scanner;
public class Demo {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
while (true) {
System.out.println("请输入一串字符串,要求字符串必须存在字母:");
String str = sc.nextLine();
int maxCount = 0;
for (int i = 0; i < str.length(); i++) {
if (str.charAt(i) >= 'A' && str.charAt(i) <= 'Z') {
maxCount++;
break;
}else if (str.charAt(i) >= '0' && str.charAt(i) <= '9') {
System.out.println("输入有误请重新输入!");
}
}
System.out.println("大写个数有:" + maxCount + "个");
}
}
}
== 和equals
- ==的应用
- 如果==两端是基本数据类型的变量,则比较的是数值是否相同
- 如果==两端是引用类型的变量,则比较的是地址是否相同
- equals方法开发是用于比较对象的内容是否相同
时间戳
System.currentTimeMillis()在java中是最常用的获取系统时间的方法,它返回的是1970年1月1日0点到现在经过
的毫秒数。
System.currentTimeMillis();
案例:比较String拼接和StringBuilder拼接的速度
//String
public class Demo {
public static void main(String[] args) throws Exception {
long start = System.currentTimeMillis();
String str = "";
for (int i = 0; i < 50000; i++) {
str += " ";
}
long end = System.currentTimeMillis();
System.out.println(end - start); //1609
}
}
//StringBuilder
public class Demo {
public static void main(String[] args) throws Exception {
long start = System.currentTimeMillis();
StringBuffer sb=new StringBuffer();
for (int i = 0; i < 50000; i++) {
sb.append(" ");
}
long end = System.currentTimeMillis();
System.out.println(end - start); //6
}
}
StringBuilder
可变的字符串 字符串容器
好处:提高字符串拼接的效率。
StringBuilder sb=new StringBuilder("a");
sb.append("b").append("c");
//在堆内存中创建一个对象进行拼接 返回一个StringBuilder对象 可以链式调用
构造方法
方法名 | 说明 |
---|---|
public StringBuilder() | 创建一个空白可变字符串对象,不含有任何内容 |
public StringBuilder(String str) | 根据字符串的内容,来创建可变字符串对象 |
常用方法
方法名 | 说明 |
---|---|
public StringBuilder append (任意类型) | 添加数据,并返回对象本身 |
public StringBuilder reverse() | 返回相反的字符序列 |
public int length() | 返回长度 ( 字符出现的个数) |
public String toString() | 通过toString()就可以实现把StringBuilder转换为String |
案例
案例:对称字符串
需求:键盘接受一个字符串,程序判断出该字符串是否是对称字符串,并在控制台打印是或不是
对称字符串:123321、111
非对称字符串:123123
public class Demo{
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
String str= sc.nextLine();
StringBuilder sb=new StringBuilder(str);
String newStr= sb.reverse().toString();
sout(newStr);
}
}
案例:拼接字符串
需求:定义一个方法,把 int 数组中的数据按照指定的格式拼接成一个字符串返回,调用该方法,并在控制台输出结果。例如,数组为int[] arr = {1,2,3}; ,执行方法后的输出结果为:[1, 2, 3]
import java.util.Scanner;
public class Demo {
public static void main(String[] args) {
int[] arr={1,2,3};
String str = strReverse(arr);
System.out.println(str);
}
public static String strReverse(int[] arr){
StringBuilder sb=new StringBuilder();
sb.append("[");
for (int i = 0; i < arr.length; i++) {
if (i==arr.length-1){
sb.append(arr[i]).append("]");
}else {
sb.append(arr[i]).append(",");
}
}
return sb.toString();
}
}
集合
集合类的特点:提供一种存储空间可变的存储模型,存储数据容量可以发生改变。
集合和数组之间的区别:
共同点:存储数据的容器
不同点:数组的容量是固定的,集合的容量是可以变的,且ArrayList底层都是用的就是数组
ArrayList
List集合中存放的数据都为Object类型
特点:
1)有序
2)可以重复
3)可以索引(通过下标可以访问元素)
基本方法
方法名 | 说明 |
---|---|
public ArrayList() | 创建一个空的集合对象 |
public int size() | 返回集合中的元素的个数 |
增
方法名 | 说明 |
---|---|
public boolean add(E e) | 将指定的元素追加到此集合的末尾 |
public void add(int index,E element) | 在此集合中的指定位置插入指定的元素 |
删
方法名 | 说明 |
---|---|
public boolean remove(Object o) | 删除指定的元素,返回删除是否boolean |
public E remove(int index) | 删除指定索引处的元素,返回值被删除的元素 |
改
方法名 | 说明 |
---|---|
public E set(int index,E element) | 修改指定索引处的元素,返回是被替换掉的元素 |
查
方法名 | 说明 |
---|---|
public E get(int index) | 返回指定索引处的元素 |
案例
集合删除元素
需求:创建一个存储String的集合,内部存储(test,张三,李四,test,test)字符串
删除所有的test字符串,删除后,将集合剩余元素打印在控制台
思路:
创建集合对象
调用add方法,添加字符串
遍历集合,取出每一个字符串元素
加入if判断,如果是test字符串,调用remove方法删除
打印集合元素
public class Demo {
public static void main(String[] args) {
ArrayList<String> strings = new ArrayList<>();
strings.add("test");
strings.add("张三");
strings.add("李四");
strings.add("test");
strings.add("test");
for (int i = 0; i < strings.size(); i++) {
if (strings.get(i).equals("test")) {
strings.remove(i);
i--;
}
}
System.out.println(strings);
}
}
集合元素筛选
需求:定义一个方法,方法接收一个集合对象(泛型为Student),方法内部将年龄低于18的学生对象找出
并存入新集合对象,方法返回新集合。
思路:
定义方法,方法的形参定义为ArrayList<Student> list
方法内部定义新集合,准备存储筛选出的学生对象 ArrayList<Student> newList
遍历原集合,获取每一个学生对象
通过学生对象调用getAge方法获取年龄,并判断年龄是否低于18
将年龄低于18的学生对象存入新集合
返回新集合
main方法中测试该方法
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;
}
}
import java.util.ArrayList;
public class Demo {
public static void main(String[] args) {
ArrayList<Student> list = new ArrayList<>();
list.add(new Student("张三", 18));
list.add(new Student("李四", 19));
list.add(new Student("王五", 17));
ArrayList<Student> stus = getStus(list);
for (int i = 0; i < stus.size(); i++) {
System.out.println(stus.get(i).getName() + "---" + stus.get(i).getAge());
}
}
public static ArrayList<Student> getStus(ArrayList<Student> list) {
ArrayList<Student> stus = new ArrayList<>();
for (int i = 0; i < list.size(); i++) {
if (list.get(i).getAge() < 18) {
stus.add(list.get(i));
}
}
return stus;
}
}
请按以下要求编写代码:
1. 定义一个只能存储字符串的集合对象;
2. 向集合内添加以下数据:
“孙悟空”
“猪八戒”
“沙和尚”
“铁扇公主”
3.不用遍历,直接打印集合;
4.获取第4个元素(注意,是--第4个元素,它的索引是?)
5.打印一下集合大小;
6.删除元素“铁扇公主”
7.删除第3个元素(注意:是--第3个元素)
8.将元素“猪八戒”改为“猪悟能”
9. 再次打印集合;
public class Demo {
public static void main(String[] args) {
ArrayList list = new ArrayList<>();
list.add("孙悟空");
list.add("猪八戒");
list.add("沙和尚");
list.add("铁扇公主");
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
System.out.println("获取第四个元素: " + list.get(3));
System.out.println("打印集合大小: " + list.size());
list.remove("铁扇公主");
list.remove(2);
list.set(1, "猪悟能");
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
}
}
定义ArrayList集合,存入多个字符串
1. 如:"ab1" "123ad" "bca" "dadfadf" "dddaaa" "你好啊" "我来啦" "别跑啊"
2.遍历集合,删除长度大于5的字符串,打印删除后的集合对象
3.基于上一步,删除集合中元素包含0-9数字的字符串(只要字符串中包含0-9中的任意一个数字就需要删除此整个字符串)
import java.util.ArrayList;
public class ArrListTest {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<String>();
list.add("ab1");
list.add("bca");
list.add("dadfadf");
list.add("dddaaa");
list.add("你好啊");
list.add("我来啦");
list.add("别跑啊");
for (int i = 0; i < list.size(); i++) {
String temp = list.get(i);
if (temp.length() > 5) {
list.remove(i);
i--;
}
}
System.out.println(list);
for (int i = 0; i < list.size(); i++) {
for (int j = 0; j <= 9; j++) {
if ( list.get(i).contains(""+j)){
list.remove(i);
}
}
}
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
}
}
定义“手机类”Phone包含空参构造、满参构造和以下成员变量:
名称name(String类型) 价格price(double类型) 类型type(String类型)
生成以上成员变量的set/get方法
定义测试类Test,完成以下要求:
①定义public static ArrayList<Phone> filter(ArrayList<Phone> list,double price) {...}方法: 要求:遍历list集合,将list中价格大于参数price的元素存入到另一个ArrayList 中并返回
②在main方法内完成以下要求: a.根据以下内容创建并初始化3个Phone对象
{"小米MIX2",2999,"新机皇"}
{"Iphone8", 5888,"火爆新机"} {"VIVO X9s",1998,"火爆新机"}
b.创建一个ArrayList list_phone,将上面的3个Phone对象添加到list_phone中,调用 filter方法传入list_phone和2000,根据返回的list集合输出所有元素信息
public class Phone {
private String name;
private double price;
private String type;
public Phone() {
}
public Phone(String name, double price, String type) {
this.name = name;
this.price = price;
this.type = type;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
@Override
public String toString() {
return "Phone{" +
"name='" + name + '\'' +
", price=" + price +
", type='" + type + '\'' +
'}';
}
}
public class PhoneTest {
public static void main(String[] args) {
ArrayList<Phone> list = new ArrayList<Phone>();
list.add(new Phone("小米MIX2", 2999, "新机皇"));
list.add(new Phone("Iphone8", 5888, "火爆新机"));
list.add(new Phone("VIVO X9s", 1998, "火爆新机"));
ArrayList<Phone> list1 = filter(list, 2000);
for (int i = 0; i < list1.size(); i++) {
System.out.println(list1.get(i));
}
}
public static ArrayList<Phone> filter(ArrayList<Phone> list, double price) {
ArrayList<Phone> list1 = new ArrayList<Phone>();
for (int i = 0; i < list.size(); i++) {
if (list.get(i).getPrice() > price) {
list1.add(list.get(i));
}
}
return list1;
}
}
定义个学生类Student,包含空参构造、满参构造和以下成员变量:
姓名name(String类型) 成绩 score(ing 类型)
生成以上成员变量的set、get方法
定义测试类,创建三个对象,存入集合中,之后遍历集合list,求出三个学生的平均成绩
public class Student {
private String name;
private int score;
public Student() {
}
public Student(String name, int score) {
this.name = name;
this.score = score;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getScore() {
return score;
}
public void setScore(int score) {
this.score = score;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", score=" + score +
'}';
}
}
public class StudentTest {
public static void main(String[] args) {
List<Student> list=new ArrayList<Student>();
list.add(new Student("张三",110));
list.add(new Student("李四",112));
list.add(new Student("王二",114));
int num=0;
for (int i = 0; i <list.size() ; i++) {
num+=list.get(i).getScore();
}
int avg= num/list.size();
System.out.println(avg);
}
}
1. 定义一个Avengers类
1)属性: 编号id ( int类型 ) ,姓名name(String类型),性别sex (String类型)
2)方法:空参满参构造 set、get方法
2. 在测试类中创建6个对象(对象数据如下),依次将Avengers对象存入集合。
1,"钢铁侠","男"
2,"美国队长","男"
3,"黑寡妇","女"
4,"绿巨人","男"
5,"雷神","男"
6,"星云","女"
3. 遍历集合删除其中性别为男且姓名长度大于等于3的元素,将剩余的元素数据打印在控制台。
public class Avengers {
private int id;
private String name;
private String sex;
public Avengers() {
}
public Avengers(int id, String name, String sex) {
this.id = id;
this.name = name;
this.sex = sex;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
@Override
public String toString() {
return "Avengers{" +
"id=" + id +
", name='" + name + '\'' +
", sex='" + sex + '\'' +
'}';
}
}
public class AvengersTest {
public static void main(String[] args) {
List<Avengers> list=new ArrayList<Avengers>();
list.add(new Avengers(1,"钢铁侠","男"));
list.add(new Avengers(2,"美国队长","男"));
list.add(new Avengers(3,"黑寡妇","女"));
list.add(new Avengers(4,"路巨人","男"));
list.add(new Avengers(5,"雷神","男"));
list.add(new Avengers(6,"星云","女"));
for (int i = 0; i < list.size(); i++) {
if (list.get(i).getName().length()>=3&&list.get(i).getSex()=="男"){
list.remove(i);
}
System.out.println(list.get(i));
}
}
}
综合案例-学生管理系统(初级版)
项目演示:
--------欢迎来到学生管理系统--------");
1 添加学生
2 删除学生
3 修改学生
4 查看学生
5 退出
请输入您的选择:
public class Student {
private String sid;
private String name;
private int age;
private String birthday;
public Student() {
}
public Student(String sid, String name, int age, String birthday) {
this.sid = sid;
this.name = name;
this.age = age;
this.birthday = birthday;
}
public String getSid() {
return sid;
}
public void setSid(String sid) {
this.sid = sid;
}
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 String getBirthday() {
return birthday;
}
public void setBirthday(String birthday) {
this.birthday = birthday;
}
}
public class StudentManager {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
//001
ArrayList<Student> stus = new ArrayList<>();
lo:
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("请输入您的选择:");
//使用键盘录入
int choose = sc.nextInt();
switch (choose) {
case 1:
//System.out.println("添加学生");
//添加学生的方法
addStudent(stus);
break;
case 2:
//System.out.println("删除学生");
removeStudent(stus);
break;
case 3:
//System.out.println("修改学生");
updateStudent(stus);
break;
case 4:
//System.out.println("查看学生");
showStudent(stus);
break;
case 5:
System.out.println("退出");
break lo;
default:
System.out.println("您输入的选项不存在,请重新输入!");
break;
}
}
}
//修改学生
public static void updateStudent(ArrayList<Student> stus) {
//1.键盘录入学生id
Scanner sc = new Scanner(System.in);
System.out.println("请您输入要修改的学生id:");
String sid = sc.next();
//2.判断学生id是否存在
int index = getIndex(stus, sid);
if(index == -1){
//4.不存在 添加/提示
//System.out.println("您要修改的信息不存在,请您重新选择:");
System.out.println("你要修改的信息不存在,请添加这个学生信息:");
addStudent(stus);
}else{
//index 索引值
//3.存在 修改操作
Student student = stus.get(index);
student.setSid(sid);
System.out.println("请您输入要修改的学生姓名:");
String name = sc.next();
student.setName(name);
System.out.println("请您输入要修改的学生年龄:");
int age = sc.nextInt();
student.setAge(age);
System.out.println("请您输入要修改的学生生日:");
String birthday = sc.next();
student.setBirthday(birthday);
//Studnet是一个引用数据类型 直接修改之后 内存空间中数据已经发生了改变
//stus.set(index,student); 写上也没问题 将001地址值 替换成了 001地址值
System.out.println("修改完成1");
}
}
//删除学生
public static void removeStudent(ArrayList<Student> stus) {
Scanner sc = new Scanner(System.in);
System.out.println("请您输入要删除的学号:");
String sid = sc.nextLine();
//判断sid时候存在
int index = getIndex(stus, sid);
if(index == -1){
//不存在 给用户一个提示
System.out.println("您要删除的学生不存在,请您重新选择!");
}else{
//存在 删除
stus.remove(index);
System.out.println("学生删除成功!");
}
}
//展示学生信息
public static void showStudent(ArrayList<Student> stus) {
if(stus == null || stus.size() <= 0){
System.out.println("学生不存在,请重新选择");
return;
}
System.out.println("学号\t\t姓名\t年龄\t生日");
for (int i = 0; i < stus.size(); i++) {
Student stu = stus.get(i);
System.out.println(stu.getSid() + "\t" + stu.getName() + "\t" + stu.getAge() + "岁\t" + stu.getBirthday());
}
}
//添加学生信息
public static void addStudent(ArrayList<Student> stus) {//001
//1.使用键盘录入
Scanner sc = new Scanner(System.in);
//2.给用户提示信息
String sid;
while(true) {
System.out.println("请您输入学生id");
sid = sc.next();
int index = getIndex(stus, sid);
if (index > -1) {
//已经存在对应学生对象
System.out.println("学生对象已经存在,请重新输入!");
}else{
break;
}
}
System.out.println("请您输入学生姓名");
String name = sc.next();
System.out.println("请您输入学生年龄");
int age = sc.nextInt();
System.out.println("请您输入学生生日");
String birthday = sc.next();
//3.将用户输入的内容封装到学生对象中
Student stu = new Student(sid, name, age, birthday);
//4.将学生对象存储到集合中
stus.add(stu);
System.out.println("学生添加成功!");
}
//根据id获取学生索引
public static int getIndex(ArrayList<Student> stus,String sid){
//1.定义一个变量用来接收索引值
int index = -1;
//2.遍历查询有没有对应的sid
for (int i = 0; i < stus.size(); i++) {
Student stu = stus.get(i);
if(sid.equals(stu.getSid())){
index = i;
break;
}
}
//3.如果有 则返回索引号
//4.如果没有 则返回 -1
return index;
}
}
集合 字符串 数组 遍历区别
length属性数组
**length() 字符串 **
size()集合
继承
概念:在我们开发中,会发现有一些类,代码重复率比较高,我们可以讲这些代码冲去出来 放到一个类中,然后我们将这个类和这些类之间建立关系,从而这些类就具备了这些重复的的代码而这个关系就是一个继承关系。
格式
public class A extends B{}
A 称为子类
B 称为父类
继承的优缺点
优点:
- 提高了代码的复用性
- 提高了代码的可维护性
- 让类与类之间产生关系
缺点:
- 提高了代码的耦合性
开发代码原则是:高内聚 低耦合 记
内聚:指的是类自己独立完成某些事情的能力
耦合:指的是类与类之间的关系
继承构造方法的特点:
当我们使用子类对象的时候,会优先完成父类的初始化操作;
this: 调用本类的成员
this():调用本类的无参构造方法
this(参数):调用本类的有参构造
super:在子类中指向父类空间的一个引用
super:调用父类的成员
super():调用父类的无参构造
super():调用父类的有参构造
new子类的是时候,之创建了子类对象,new谁创建就是子类的对象 跟继承无关。
继承中访问成员属性的特点:
就近原则:
方法中有 先使用方法中的变量,方法中没有就去 本类中找,本类中没有就去去类中找。
继承中访问成员方法的特点:
就近原则:
本类中有先访问,本类中没有,就访问父类。
Java中继承的特点:
- 单继承
- 多层继承
方法的重写:
子类中存在于父类中一摸一样的方法 返回值类型也一样
作用:扩展父类中方法的功能
使用:在重写的方法中可以使用super.父类中的方法();
注意:
- 在重写的方法中可以i使用@Override防止我们误写错方法名
- 被private修饰的方法 无法被重写
- 重写方法的权限修饰符 不能小于父类中的权限修饰
package homework01;
public class People {
private String name;
private int age;
public People() {
}
public People(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("吃");
}
}
package homework01;
public class Student extends People {
public Student() {
}
public Student(String name, int age) {
super(name, age);
}
@Override
public void eat() {
System.out.println("学生吃牛肉");
}
public void study(){
System.out.println("学生学习");
}
}
package homework01;
public class Teacher extends People {
public Teacher() {
}
public Teacher(String name, int age) {
super(name, age);
}
@Override
public void eat() {
System.out.println("老师喝牛肉汤");
}
public void teach() {
System.out.println("老师讲课");
}
}
package homework01;
public class StuTeaTest {
public static void main(String[] args) {
Student stu = new Student();
stu.setName("张三");
stu.setAge(18);
stu.eat();
stu.study();
System.out.println(stu.getName()+"---"+stu.getAge());
Student stu1 = new Student("李四",19);
System.out.println(stu1.getName()+"---"+stu1.getAge());
Teacher tea = new Teacher("王二", 20);
tea.eat();
tea.teach();
System.out.println(tea.getName()+"---"+tea.getAge());
}
}
多态
概述:
同一个事物在不同时间下的不同状态
多态的前提:
- 继承
- 重写方法
- 父类引用指向子类对象
多态访问成员的特点:
结论: 记忆
1. 成员变量: 编译看左, 运行看左.
编译的时候, 看左边的数据类型有没有这个变量, 有不报错, 没有就报错.
运行的时候, 具体运行的是左边的数据类型里边的: 此变量.
2. 成员方法: 编译看左, 运行看右.
编译的时候, 看左边的数据类型有没有这个方法, 有不报错, 没有就报错.
运行的时候, 具体运行的是右边的数据类型里边的: 此方法.
原因是因为: 方法有重写, 而变量没有.
多态转型问题:
向上转型:子类对象赋值给父类引用
Animal an=new Cat();
此时通过父类的变量就只能调用父类中有的方法,不能调用子类特有的方法了
向下转型:父类引用赋值给子类引用
Cat cat=(Cat)animail;
父类类型向子类类型向下转换的过程,这个过程是强制的。
当使用多态方式调用方法时,首先检查父类中是否有该方法,如果没有,则编译错误。也就是说,不能调用子类拥有,而父类没有的方法。编译都错误,更别说运行了。这也是多态给我们带来的一点"小麻烦"。所以,想要调用子类特有的方法,必须做向下转型。
注意:千万记住一点,他原先是什么 ,就可以向下转型为什么。
扩展类instanceof
多态正确使用:
-
方法中形参可以是 父类引用 调用方法的的时候传递子类对象作为实参
-
同一个方法 接收的参数 可以是不同的对象
父类应用 instanceof 子类:
判断这个引用本质上是谁的对象
package homework03;
public class Animail {
private String name;
private int age;
public Animail() {
}
public Animail(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 void run() {
System.out.println("跑步");
}
}
package homework03;
public class Cat extends Animail {
public Cat() {
}
public Cat(String name, int age) {
super(name, age);
}
@Override
public void eat() {
System.out.println("猫吃鱼");
}
public void catchMouse() {
System.out.println("猫抓老鼠");
}
}
package homework03;
public class Dog extends Animail {
public Dog() {
}
public Dog(String name, int age) {
super(name, age);
}
@Override
public void eat() {
System.out.println("狗吃肉");
}
public void lookHome(){
System.out.println("狗看门");
}
}
package homework03;
public class Demo {
public static void main(String[] args) {
//第一种
Cat cat = new Cat("猫1", 10);
cat.eat();
cat.catchMouse();
cat.run();
System.out.println(cat.getName() + "--" + cat.getAge());
Dog dog = new Dog("狗1", 10);
dog.eat();
dog.run();
dog.lookHome();
System.out.println(dog.getName() + "--" + dog.getAge());
System.out.println("-------------------------------------------------");
//第二种
Animail an = new Cat(); //向上转型
if (an instanceof Cat) {
Cat cat1 =(Cat)an; //向下转型
cat1.catchMouse();
cat1.run();
cat1.eat();
}else if (an instanceof Dog){
Dog dog1=(Dog)an;
dog1.run();
dog1.lookHome();
dog1.eat();
}
System.out.println("-----------------------------------");
//第三种
Dog dog1=new Dog();
getRe(dog1);
}
public static void getRe(Animail animail){
if (animail instanceof Cat) {
Cat cat1 =(Cat)animail;
cat1.catchMouse();
cat1.run();
cat1.eat();
}else if (animail instanceof Dog){
Dog dog1=(Dog)animail;
dog1.run();
dog1.lookHome();
dog1.eat();
}
}
}
final
最终的意思:可以用来修饰类 修饰变量 修饰方法
修饰类:类不能被继承
修饰变量:变量就成了常量
- 必须要保证常量可以被赋值成功
- 定义常量时可以进行赋值
- 在构造方法中进行赋值操作
- 在静态代码块中给静态的常量进行赋值操作
修饰方法:方法不能被重写
static
静态的意思
静态方法:只能访问静态的成员和静态的成员方法
注意事项:
- 在静态方法中,是没有super,this
- 因为静态的内容随着类的加载而加载 而this和super是随着对象的创建而存在的。
特点:
- 随着类的加载而加载
- 优先于对象存在
- 被static修饰的属性可以被所有的对象所共享
- 使用类名调用
- 使用类名.成员 调用
- 被static修饰的成员 存放在静态区中,随着类的加载而加载 随着类的消失而消失 生命周期非常长,对内存造成了浪费
- 什么时候使用静态
- 对属性的复用
- 将频繁使用的成员方法进行封装成工具类
abstract
抽象:使用继承/多态的时候发生一些问题
- 对于父类来讲,他是一个抽象的类, 比如说animal 不应该创建他的对象 因为他是抽象的
- 对于重写的方法 方法具体是什么应该有重写这说了算 需要抽象方法
抽象类的特点:
- 不能创建对象
- 构造方法有什么用?
- 初始化父类中的成员
- 可以有抽象方法
- 当继承一个抽象类时 要重写抽象方法
- 当继承一个抽象类时,不重写抽象方法,就要变成抽象类
- 剩下跟普通类没什么区别
interface
接口:当一些成员没有办法进行抽取到父类中 也没办法直接存放在子类中时,需要一些扩展的功能,有时需要,有时不需要这个功能,就需要使用到 接口。
接口的特点:
- 被interface修饰
- 无法创建接口的对象 如果要创建使用接口多态
- 接口中只有常量和抽象方法
- JDK8以后又添加了静态方法和默认方法
接口与类之间的关系
类与类 : 继承关系 ,单继承 多层继承
类与接口:实现关系 ,多实现 也可以单实现
接口与接口:继承关系,可以单继承 耶尔可以多继承
普通类,抽象类,接口类区别
普通类:属性:成员变量 常量。 构造方法:初始化 创建对象。 方法:普通方法 静态的方法
抽象类:属性:成员变量 常量。 构造方法:初始化。 方法:普通方法 静态的方法 抽象方法
接口: 属性:常量。 方法:默认方法 静态的方法 抽象方法
包
本质:就是一个多级文件夹
规范:域名反写.项目名称.分包名称
作用:帮助我们对类进行管理
权限修饰符
从大到小:
- public 公共的 :在任何位置都可以被访问
- protected 子父关系 : 子类访问父类的成员 任何位置都没有权限
- 默认 一个包中 :只要在一个包中 都可以访问
- private 私有的 : 只能在本类中访问
Object
toString
- 打印对象中内容。
- 默认打印的是对象的地址值,地址值由该类的全类名和@和哈希码 组成 无意义
- 一般重写该方法 输出语句直接打印对象,默认调用对象的toString()方法;
equals
- 比较两个对象的内容是否相同
- 不重写比较的是地址
- 重写equals方法 比较对象的各个属性值
- 开发中:如果对象中内容一样的 我们将它看作同一个对象
hashcode 提高效率
- hashcode不同 两个对象绝对不同。
- hashcode相同 调用equals方法比较。
冒泡排序
相邻两位 两两比较 大的放后面 依次比较
import java.util.*;
public class Demo {
public static void main(String[] args) {
//定义数组,记录要排序的元素
int [] arr={1,3,4,0,10,42,1,4,212};
//通过外层循环,控制比较的轮数
for (int i = 0; i < arr.length-1; i++) {
//通过内层循环,控制每轮比较的次数
for (int j = 0; j < arr.length-i-1; j++) {
//将前一个元素比后一个元素大的 进行换位
if (arr[j]>arr[j+1]){
int temp=arr[j];
arr[j]=arr[j+1];
arr[j+1]=temp;
}
}
}
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i]+" ");
}
}
}
Arrays工具类
特点:
- 构造方法私有化
- 成员方法都是静态的
• public static String toString(int[] arr)
解释: 把int类型的数组转成其对应的字符串形式.。
• public static void sort(int[] arr)
解释: 对给定的int数组, 按照元素升序的顺序进行排序。
Arrays类的构造方法问题
我们知道, 如果一个类中没有构造方法, 那么系统将提供一个空参构造方法。而我们在帮助文档中没有看到Arrays类的构造方法。 这是为什么呢?难道Arrays类真的没有构造方法吗?
答案是:
Arrays类中有一个私有的空参构造方法,这样做的目的是:不让用户通过构造方法来创建Arrays类的对象。
因为Arrays类的成员都是静态的, 可以通过类名点的形式直接调用。
FOR循环遍历和冒泡排序:
public class Demo1 {
public static void main(String[] args) {
int[] arr = {25, 69, 80, 57, 13};
arrSort(arr);
arrSort2(arr);
}
public static void arrSort(int[] arr) {
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + " ");
}
}
public static void arrSort2(int[] arr) {
for (int i = 0; i < arr.length - 1; i++) {
for (int j = 0; j < arr.length - 1 - i; j++) {
if (arr[j] > arr[j + 1]) {
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + " ");
}
}
}
包装类
为了对基本类型进行更多更方便的操作,Java就针对每一种基本类型提供了一个对应的引用类型,这就是包装类。
例如:获取int的取值范围:我们就可以通过Integer类的MAX_VALUE和MIN_VALUE两个常量来实现
• public static final int MIN_VALUE
解释: 获取int类型所能表示的最小值
• public static final int MAX_VALUE
解释: 获取int类型所能表示的最大值
它们的对应关系如下:
基本类型 | 对应的包装类 |
---|---|
byte | Byte |
short | Short |
char | Character |
int | Integer |
long | Long |
float | Float |
double | Double |
boolean | Boolean |
常用包装类Integer
构造方法:
• public Integer(int value)
解释: 把int类型的数据封装成其对应的Integer对象。
• public Integer(String s)
解释: 把字符串类型的整数封装成其对应的Integer对象。
注意: 这里传入的必须是纯数字类型的字符串。
int转String
1. String str=10+"";
2. String str=String.valueOf(10); ==常用==
String转int
1. String str="10";
Integer num=Integer.parseInt(str); ==常用==
2. String str="10";
Integer l=new Integer(str);
int num=l.intValue();
自动拆装箱
• 把基本类型的数据封装成其对应的包装类型, 则称之为自动装箱。
//示例代码
Integer ii = 100; //自动装箱。
• 把包装类型的对象拆解成其对应的基本类型, 则称之为自动拆箱。
Integer ii = 100;
i1 += 200; //自动拆箱。
注意: 自动拆装箱都是JDK5的新特性。
将91 27 45 38 50字符串进行升序排序输出
public class Demo {
public static void main(String[] args) {
String s = "91 27 45 38 50";
String[] arr = s.split(" ");
int[] iarr = new int[arr.length];
for (int i = 0; i < arr.length; i++) {
iarr[i] = Integer.parseInt(arr[i]);
}
Arrays.sort(iarr);
for (int i = 0; i < iarr.length; i++) {
if (iarr.length - 1 == i) {
System.out.print(iarr[i]);
} else {
System.out.print(iarr[i] + ",");
}
}
}
}
键盘录入纯数字形式的字符串,中间用逗号隔开 输出数字总和
public class Demo {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("键盘录入一个纯数字形式的字符串, 中间用, 隔开");
String str = sc.next();
String[] split = str.split(",");
int sum=0;
for (int i = 0; i < split.length; i++) {
sum+=Integer.parseInt(split[i]);
}
System.out.println(sum);
}
}
Date日期
构造方法:
• public Date();
解释: 根据当前系统时间,获取其对应的Date对象。
• public Date(long date);
解释: 根据给定的整数,获取其对应的Date对象。
方法:
• public long getTime()
解释: 获取毫秒值。
• public void setTime(long time)
解释: 设置时间, 单位是毫秒值。
SimpleDateFormat类
SimpleDateFormat类, 叫日期格式化类, 专门用来格式化和解析日期的.
• 格式化(日期 -> 文本), 即: Date -> String
• 解析(文本 -> 日期), 即: String -> Date
构造方法
• public SimpleDateFormat()
解释: 根据空参构造, 创建SimpleDateFormat类的对象。
• public SimpleDateFormat(String pattern)
解释: 根据给定的模板, 创建其对应的SimpleDateFormat类的对象。
成员方法
• public final String format(Date date)
解释: 用来格式化日期的。
• public Date parse(String source)
解释: 用来解析字符串形式的日期的。
public class Demo {
public static void main(String[] args) throws ParseException {
Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String format = sdf.format(date);
System.out.println("日期按照样式字符串输出显示: "+format);
String str="2021-03-31 15:21:21";
SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date parse = sdf1.parse(str);
System.out.println("字符串按照日期样式输出: "+parse);
}
}
//封装成方法
public class DateUtils {
private DateUtils() {
}
public static String date2String(Date data, String pattern) {
SimpleDateFormat sdf = new SimpleDateFormat(pattern);
return sdf.format(data);
}
public static Date string2Date(String str, String pattern) throws ParseException {
SimpleDateFormat sdf = new SimpleDateFormat(pattern);
return sdf.parse(str);
}
}
public class Demo {
public static void main(String[] args) throws ParseException {
Date date = new Date();
String str = DateUtils.date2String(date, "yyyy-MM-dd HH:mm:ss");
System.out.println(str);
String str1="2021-03-31 20:45:21";
Date date1 = DateUtils.string2Date(str1, "yyyy-MM-dd");
System.out.println(date1);
}
}
键盘录入年份 输出该年2月总共天数
import java.util.Calendar;
import java.util.Scanner;
public class Demo {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("键盘录入年份");
int year = sc.nextInt();
Calendar calendar = Calendar.getInstance();
calendar.set(year, 2, 1);
calendar.add(Calendar.DAY_OF_MONTH, -1);
int day = calendar.get(Calendar.DAY_OF_MONTH);
System.out.println(day);
}
}
输入出生年月日 得出出生到目前活了多少天
import java.text.ParseException;
import java.util.Calendar;
import java.util.Scanner;
public class Demo {
public static void main(String[] args) throws ParseException {
Calendar calendar = Calendar.getInstance(); // 设置日历对象
Scanner sc = new Scanner(System.in);
System.out.println("请输入您的生日年份:");
int year = sc.nextInt();
System.out.println("请输入您的生日月份:");
int month = sc.nextInt();
System.out.println("请输入您的生日天数:");
int day = sc.nextInt();
calendar.set(year, month-1, day); // 将输入年、月、日放到日历中
long olddate = calendar.getTimeInMillis(); //获得日历时间的毫秒值
long nowdate = System.currentTimeMillis(); //获得当前时间的毫秒值
long l = (nowdate - olddate) / 1000 / 60 / 60 / 24; //将两值相减,再转换为天数
System.out.println("您目前活了" + l + "天!");
}
}
提示用户录入他的出生年月日, 计算这个用户一共活了多少天, 并将结果打印到控制台上
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Scanner;
public class Test01 {
public static void main(String[] args) throws ParseException {
//提示用户录入他的出生年月日, 计算这个用户一共活了多少天, 并将结果打印到控制台上
//键盘录入一个日期
Scanner sc = new Scanner(System.in);
System.out.println("请输入您的的生日 格式如下:xxxx年xx月xx日");
String birthday = sc.nextLine();
//将字符串的时间转为毫秒值
//Date-->getTime()-->毫秒值
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日");
Date date = sdf.parse(birthday);
long startTime = date.getTime();
//Date date = new Date();
//long nowTime =date.getTime();
long nowTime = System.currentTimeMillis();
//现在这个时间的毫秒值 - 生日所在毫秒值 / 1000 /60 /60 /24
int day = (int) ((nowTime - startTime) / 1000 / 60 / 60 / 24);
System.out.println("您总共活了" + day + "天");
}
}
匿名对象
没有名字的对象
我们可以直接new 类()执行某一些功能
做什么?
调用方法 只能调用一次
可以座位参数传递 传递之前不能做其他操作
内部类
类种类
成员内部类
成员的位置定义一个类
new 外部类().new 内部类()
局部内部类
在局部位置定义一个类
先定义类 在创建对象
为什么在内部类中引用局部变量 局部变量需要加final
原因:生命周期的问题,由于局部变量生命周期是在方法内 对象是在堆中 在堆中的数据 生命周期药厂与方法中的变量 导致正在引用这个局部变量而局部变量没有了
如何解决:为局部变量使用final修饰 让他变成一个常量 常量的生命周期 从定义开始 直达JVM结束 保证我们爱引用期间 这个常量是一直存在的
匿名内部类
我们可以将它理解为一个没有名字的局部内部类
-
new谁创建的就是谁的子类/实现类的对象
-
格式 new 类/接口(){
//类中内容和正常的类是没有区别的
//重写方法
}
-
应用
- 匿名内部类整体可以看作一个匿名对象
- 可以调用方法 的但是只能调用一次
- 可以作为参数传递,但传递之前不能做其他操作(调用有参构造可以)
集合
Collection 单列集合
1. list 有序 可重复 有索引 不能为空
1. Arraylist 底层用==**数组**==实现 查询快 增删慢(数据是连续存储的,当插入删除是势必导致部分数据的的位置便宜)
2. Linkedlist 底层使用双向==**链表**==实现 链表的机构在内存中是分散的 查询慢 增删快 查找一个元素是,会进行一个加速操作 要查找的下表和集合的size的一般进行对比 如果小于Size/2 从头查找 反之从尾查找
2. set 无序 不可重复 无索引
1. HashSet 哈希表:底层是一个数组的链表结构
去重:
原理:1.添加元素调用add方法,
2.方法内部会调用map的put方法,
3.将值存入map.put的key中,value是系统自动创建并填充的, 进map.put方法
4.再调用putVal方法将key的hash值,key,存入进行判断
5.先判断哈希值是否相等
6.再判断地址是否相等
7.再判断添加的元素是否为空
8.再比较对象的各个属性值是否相等。
问题: 为什么要设计的这么复杂呢? 直接通过equals()比较两个属性的属性值不就好了吗?
答案: 确实可以这样设计, 但是效率比较低, 程序之所以写的这么繁琐, 就是为了降低调用equals()方法的次数, 从而实现 节约资源, 提高效率!
结论:HashSet保证元素的唯一性, 依赖hashCode()和equals()方法
实现的原理:底层是一个数组的链表结构
原理: 重写hashCode方法是为了让相同的对象返回相同的hash值 放到相同下标位置从而去调用equals方法比较内容,如果结果为true说明是两个相同的对象 那么后者就不会再添加到集合中实现去重
哈希表:原理2:1.一个长度为16大的数组+链表组成
2.首先计算元素的hash值
3.将这些hash值对16取余
4.根据取余的结构将内容存储到数组中
5.需要对内容进行判断 是否重复 不重复使用链表添加 重复不添加
1. LinkedHashSet 有序 无索引 不可重复 hash+链表
hash保证数据唯一性
链表保证有序性
3. Map 双列集合 key--value 键值对存储 key无序 键不可以重复 key的数据类型可以是任意对象类型 value 值可以重复 value的数据类型可以是任意对象类型
1. HashMap 采用哈希表结构,顺序不能保持一致,由于要保证键的唯一 不可重复需要重写equals 和hashcode 方法
2. LinkedHashMap : HashMap下有个子类LinkedHashMap,存储数据采用的哈希表结构+链表结构。通过链表结构可以保证元素的存取顺序一致;通过哈希表结构可以保证的键的唯一、不重复,需要重写键的hashCode()方法、equals()方法。
Hashtable与HashMap区别:
1. Hashtable 线程安全集合,运行速度慢
HashMap 线程不安全的集合,运行速度快
2. HashMap 允许存储null值,null键
Hashtable 不允许存储null值,null键
Hashtable他的孩子,子类 Properties 依然活跃在开发舞台
Lambda表达式
对匿名内部类 进行简化,函数式思想的体现
前提:有一个叫接口,且接口中有且仅有一个抽象方法
格式:
(参数列表)-> {方法体}
解释:
- 形式参数:如果多个参数,参数之间用逗号隔开,如果没有参申诉,留空
- -> :固定形式
- 方法块:具体要做的事
- 组成Lambda表达式的三个要素:形式参数,箭头,代码块
表达式的省略模式:
- 参数类型可以省略,但是有多个参数的情况下不能只省略一个
- 如果参数有且只有一个,小括号可以省略
- 如果代码块的语句只有一条,可以直接省略大括号和分号,和return关键字
Lambda和匿名内部类区别:
-
所需类型不同
- 匿名内部类:可以是接口,也可以是抽象类,还可以是具体类
- Lambda表达式:只能是**接口**
-
使用限制不同
- 如果==接口中有且仅有一个抽象方法==,可以使用Lambda表达式,也可以使用匿名内部类
- 如果接口中多于一个抽象方法,只能使用匿名内部类,而不能使用Lambda表达式
-
实现原理不同
- 匿名内部类:编译之后,产生一个单独的.class字节码文件
- Lambda表达式:编译之后,没有一个单独的.class字节码文件。对应的字节码会在运行的时候动态生成
集合遍历
迭代器
iterater() 获取一个迭代器
hasNext()判断是否包含下一个元素
next() 获取下一元素
for循环
size()获取集合长度
get(int index)配合索引获取元素
增强for循环
for(元素数据类型 变量名:数组){}
增强for循环底层使用的是迭代器 所以也会出现并发修改异常
/*通过代码, 完成如下需求:
1. 自定义一个人类,给出成员变量name和age.
2. 使用ArrayList集合存储人类对象并遍历.
3. 最后在控制台输出人类对象的成员变量值。
//格式为: 姓名: 张三, 年龄: 23
4. 通过四种方式遍历.
//提示: 普通迭代器, 增强for, 列表迭代器, 普通for*/
package day13.HomeWork4;
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 +
'}';
}
}
public class Demo1 {
public static void main(String[] args) {
List<Student> list = new ArrayList<>();
list.add(new Student("张三", 23));
list.add(new Student("王二", 22));
list.add(new Student("李四", 21));
for (Student student : list) {
System.out.println("student = " + student);
}
Iterator it = list.iterator();
while (it.hasNext()) {
System.out.println("it.next() = " + it.next());
}
ListIterator lt = list.listIterator();
while (lt.hasNext()) {
System.out.println("lt.next() = " + lt.next());
}
for (int i = 0; i < list.size(); i++) {
System.out.println("list = " + list.get(i));
}
}
}
/*
* 通过代码, 完成如下需求:
1. 自定义一个学生类,给出成员变量name和age.
2. 定义ArrayList集合, 用来存储学生对象.
3. 键盘录入3个学生的信息, 将他们封装成学生对象后, 添加到ArrayList集合中.
4. 判断集合中是否有姓名叫 刘亦菲 的学生, 如果有, 就往集合中添加学生对象: 糖糖, 18
5. 遍历集合. //用任意一种方式遍历即可.*/
public class Demo1 {
public static void main(String[] args) {
List<Student> list = new ArrayList<>();
Scanner sc = new Scanner(System.in);
for (int i = 0; i < 3; i++) {
System.out.println("请输入第"+(i+1)+"个学生姓名:");
String name = sc.next();
System.out.println("请输入第"+(i+1)+"个学生年龄:");
int age = sc.nextInt();
list.add(new Student(name,age));
}
ListIterator<Student> it=list.listIterator();
while (it.hasNext()){
Student next = it.next();
if (next.getName().equals("刘亦菲")){
it.add(new Student("糖糖",18));
}
}
for (Student student : list) {
System.out.println(student);
}
}
}
数据结构
- 栈 先进后出
- 队列 先进先出
- 数组 查询修改快 增删慢
- 链表 查询修改慢 增删快
异常
异常:就是不正常的现象;
程序中的异常:就是在程序运行中,会出现一些不正常的情况,对于这些情况必须做出处理。否则会导致程序停止。
父类:Throwable
|---Error 错误 虚拟机内存用完了 无法通过程序去避免解决
|---Exception 异常 可以通过程序解决 我们可以给出解决方案
---RuntimeException 运行时异常 编译器是不检查的 未检查异常
---非RuntimeException 编译器要检查 已检查异常
运行时异常
- 数组下标越界异常 ArrayIndexOutOfBoundsException
- 空指针异常 NullPointerException
- 类型转化异常 ClassCastException
- 数字格式转化异常 NumberFormatException
- 算数除0异常 ArithmeticException
- 没有集合元素的错误 NoSuchElementException
- 没有实现序列化接口NotSerializableException
- 类无效异常(序列化号不一致,没无参)InvalidClassException
1.数组下标越界异常
案例:
package cn.baizhi.day17;
public class Demo {
public static void main(String[] args) {
//定义一个数组
int[] a = new int[5];
System.out.println(a[5]);
}
}
异常信息:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 5
at cn.baizhi.day17.Demo.main(Demo.java:12)
=========================================================================================
2.空指针异常
案例:
package cn.baizhi.day17;
public class Demo {
public static void main(String[] args) {
//空指针异常
int[] a = null;
System.out.println(a[3]);
}
}
异常信息:
Exception in thread "main" java.lang.NullPointerException
at cn.baizhi.day17.Demo.main(Demo.java:11)
=========================================================================================
3.类型转换异常
案例:
package cn.baizhi.day17;
public class Demo {
public static void main(String[] args) {
//类型转换异常
Animal animal = new Dog();
Cat cat = (Cat)animal;
}
}
class Animal{
}
class Dog extends Animal{
}
class Cat extends Animal{
}
异常信息:
Exception in thread "main" java.lang.ClassCastException: cn.baizhi.day17.Dog cannot be cast to cn.baizhi.day17.Cat
at cn.baizhi.day17.Demo.main(Demo.java:7)
=========================================================================================
4.数字格式转换异常
案例:
package cn.baizhi.day17;
public class Demo {
public static void main(String[] args) {
String string = "刘洋";
int a = Integer.parseInt(string);
System.out.println(a);
}
}
异常信息:
Exception in thread "main" java.lang.NumberFormatException: For input string: "刘洋"
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
at java.lang.Integer.parseInt(Integer.java:492)
at java.lang.Integer.parseInt(Integer.java:527)
at cn.baizhi.day17.Demo.main(Demo.java:6)
==================================================================
5.算数除0异常
案例:
package cn.baizhi.day17;
public class Demo {
public static void main(String[] args) {
int a = 3;
int b = 0;
System.out.println(a/b);
}
}
异常信息:
Exception in thread "main" java.lang.ArithmeticException: / by zero
at cn.baizhi.day17.Demo.main(Demo.java:7)
- JVM处理异常的时候,将异常的错误原因 ,异常的位置打印在控制台。
- throws写在方法上 将异常抛给调用者处理 现在main方法的的调用者是JVM throws后面可以写多个异常,一般我们开发不会这样写,可以直接抛出一个Exception
- 父类中的方法有异常,子类重写方法之后也需要抛出异常,且子类抛出的异常不能比父类宽
- catch可以写多个,但顺序上 前面只可以放小的子类异常信息。
finally
- 是关键字 finally正常情况下 都会执行 finally中的代码块 一般做资源内存的释放
- 不执行finally的情况有 断电。System.exit(0);正常退出jvm。
格式:try{
} catch(Exception e){
e.print…
}finally{
}
final finally finalize这是三个关键字的区别
-
final 和finally是关键字,finalize是垃圾回收机制里的方法
-
final修饰类:类不能被继承
final 修饰变量:变量就成了常量
final 修饰方法:方法不能被重写
-
finally 是try{}catch{}finally{} 语句的关键字 ,特点就是正常情况下 代码都会执行finally括号内的代码块
-
finalize 垃圾回收机制 父类object 其中的一个finalize方法,做内存释放
IO
体系结构:
字节流: 可以拷贝任何文件
1. 字节输入流的所有类的超类 InputStream
1. BufferedInputStream 高效输入流
2. FileInputStream 普通输入流
2. 字节输出流的所有类的超类 OutputStream
1. BufferedOutputStream 高效输出流
2. FileOutputStream 普通输入流
字符流: 只能拷贝文本文件
1. 字符输入流的所有类的超类 Reader
1. BufferedReader 高效输入流
2. FileReader普通输入流
2. 字符输出流的所有类的超类 Writer
1. BufferedWriterr 高效输出流
2. FileWriter 普通输入流
交换流
1. InputStreamReader:是从字节流到字符流的桥梁
它读取字节,并使用指定的编码将其解码为字符
它使用的字符集可以由名称指定,也可以被明确指定,或者可以接受平台的默认字符集
1. OutputStreamWriter:是从字符流到字节流的桥梁
是从字符流到字节流的桥梁,使用指定的编码将写入的字符编码为字节
它使用的字符集可以由名称指定,也可以被明确指定,或者可以接受平台的默认字符集
案例:字节流
public class FileBufferedInputOutputStream {
public static void main(String[] args) throws IOException {
getCopy1();//普通字节流 一个字节
getCopy2();//普通字节流 一个字节数组
getCopy3();//高效字节流 一个字节
getCopy4();//高效字节流 一个字节数组
getRead5();//高效字节流 一个字节数组控制台打印输出
}
public static void getCopy1() throws IOException {
FileInputStream fis = new FileInputStream("1.txt");
FileOutputStream fos = new FileOutputStream("2.txt");
int len;
while ((len = fis.read()) != -1) {
fos.write(len);
}
fos.close();
fis.close();
}
public static void getCopy2() throws IOException {
FileInputStream fis = new FileInputStream("1.txt");
FileOutputStream fos = new FileOutputStream("2.txt");
int len;
byte[] buf = new byte[1024 * 8];
while ((len = fis.read(buf)) != -1) {
fos.write(buf, 0, len);
}
fos.close();
fis.close();
}
public static void getCopy3() throws IOException {
FileInputStream fis = new FileInputStream("1.txt");
FileOutputStream fos = new FileOutputStream("2.txt");
BufferedInputStream bis = new BufferedInputStream(fis);
BufferedOutputStream bos = new BufferedOutputStream(fos);
int len;
while ((len = bis.read()) != -1) {
bos.write(len);
}
bos.close();
bis.close();
fos.close();
fis.close();
}
public static void getCopy4() throws IOException {
FileInputStream fis = new FileInputStream("1.txt");
FileOutputStream fos = new FileOutputStream("2.txt");
BufferedInputStream bis = new BufferedInputStream(fis);
BufferedOutputStream bos = new BufferedOutputStream(fos);
int len;
byte[] buf = new byte[1024 * 8];
while ((len = bis.read(buf)) != -1) {
bos.write(buf, 0, len);
}
bos.close();
bis.close();
fos.close();
fis.close();
}
public static void getRead5() throws IOException {
FileInputStream fis = new FileInputStream("1.txt");
BufferedInputStream bis = new BufferedInputStream(fis);
byte[] buf = new byte[1024 * 8];
int len = bis.read(buf);
System.out.println(new String(buf, 0, len));
bis.close();
fis.close();
}
}
案例:字符流
public class InputOutputReaderWriter {
public static void main(String[] args) throws IOException {
copyFile1(); //fr fw 普通一个字符
copyFile2(); //fr fw 普通一个字符数组
copyFile3(); //br bw 高效一个字符
copyFile4(); //br bw 高效一个字符数组
copyFile5(); //br bw 高效 一行一行的读 ==**不解析换行 需要手动调用方法换行**==
copyFile6(); //isr osr转换流一个字符
copyFile7(); //isr osr转换流一个字符数组
}
public static void copyFile1() throws IOException {
FileReader fr = new FileReader("a.txt");
FileWriter fw = new FileWriter("b.txt");
int len;
while ((len = fr.read()) != -1) {
fw.write(len);
}
fw.close();
fr.close();
}
public static void copyFile2() throws IOException {
FileReader fr = new FileReader("a.txt");
FileWriter fw = new FileWriter("b.txt");
int len;
char[] buf = new char[1024];
while ((len = fr.read(buf)) != -1) {
fw.write(buf, 0, len);
}
fw.close();
fr.close();
}
public static void copyFile3() throws IOException {
BufferedReader br = new BufferedReader(new FileReader("a.txt"));
BufferedWriter bw = new BufferedWriter(new FileWriter("b.txt"));
int len;
while ((len = br.read()) != -1) {
bw.write(len);
}
bw.close();
br.close();
}
public static void copyFile4() throws IOException {
BufferedReader br = new BufferedReader(new FileReader("a.txt"));
BufferedWriter bw = new BufferedWriter(new FileWriter("b.txt"));
int len;
char[] buf = new char[1024];
while ((len = br.read(buf)) != -1) {
bw.write(buf, 0, len);
}
bw.close();
br.close();
}
public static void copyFile5() throws IOException {
BufferedReader br = new BufferedReader(new FileReader("a.txt"));
BufferedWriter bw = new BufferedWriter(new FileWriter("b.txt"));
String len;
while ((len = br.readLine()) != null) {
bw.write(len);
bw.newLine();
}
bw.close();
br.close();
}
public static void copyFile6() throws IOException {
FileInputStream fis = new FileInputStream("a.txt");
InputStreamReader isr = new InputStreamReader(fis, "UTF-8");
FileOutputStream fos = new FileOutputStream("b.txt");
OutputStreamWriter osw = new OutputStreamWriter(fos, "UTF-8");
int len;
while ((len = isr.read()) != -1) {
osw.write(len);
}
osw.close();
isr.close();
}
public static void copyFile7() throws IOException {
FileInputStream fis = new FileInputStream("a.txt");
InputStreamReader isr = new InputStreamReader(fis, "UTF-8");
FileOutputStream fos = new FileOutputStream("b.txt");
OutputStreamWriter osw = new OutputStreamWriter(fos, "UTF-8");
int len;
char[] buf = new char[1024];
while ((len = isr.read(buf)) != -1) {
osw.write(buf, 0, len);
}
osw.close();
isr.close();
}
}
• File类的构造方法
方法名 | 说明 |
---|---|
File(String pathname) | 通过将给定的路径名字符串转换为抽象路径名来创建新的 File实例 |
File(String parent, String child) | 从父路径名字符串和子路径名字符串创建新的 File实例 |
File(File parent, String child) | 从父抽象路径名和子路径名字符串创建新的 File实例 |
• 方法分类
方法名 | 说明 |
---|---|
public boolean createNewFile() | 当具有该名称的文件不存在时,创建一个由该抽象路径名命名的新空文件 |
public boolean mkdir() | 创建由此抽象路径名命名的目录 |
public boolean mkdirs() | 创建由此抽象路径名命名的目录,包括任何必需但不存在的父目录 |
• 判断功能
方法名 | 说明 |
---|---|
public boolean isDirectory() | 测试此抽象路径名表示的File是否为目录 |
public boolean isFile() | 测试此抽象路径名表示的File是否为文件 |
public boolean exists() | 测试此抽象路径名表示的File是否存在 |
• 获取功能
方法名 | 说明 |
---|---|
public String getAbsolutePath() | 返回此抽象路径名的绝对路径名字符串 |
public String getPath() | 将此抽象路径名转换为路径名字符串 |
public String getName() | 返回由此抽象路径名表示的文件或目录的名称 |
public String[] list() | 返回此抽象路径名表示的目录中的文件和目录的名称字符串数组 |
public File[] listFiles() | 返回此抽象路径名表示的目录中的文件和目录的File对象数组 |
序列化和反序列化
一个类实现Seralizable接口, 这个接口是标记型接口,
仅仅是作为一个标记,实现了子接口的类标识可以进行序列化操作。
1. 当反序列化对象时,如果对象所属的class文件在序列化之后进行的修改,那么进行反序列化也会发生异常InvalidClassException。例如:Student.class被修改删除,也会抛出此异常。
发生常InvalidClassException异常的原因如下:
该类(此例为Person类)的序列版本号与从流中读取的类描述符的版本号不匹配(即序列号冲突问题,后面详细讲)
该类包含未知数据类型
该类没有可访问的无参数构造方法
没有方法的接口,被称为标记型接口。
2.Serializable为标记接口。该接口给需要序列化的类,提供了一个序列版本号。serialVersionUID. 该版本号的目的在于验证序列化的对象和对应类是否版本匹配。
//序列化的这个类 都有一个序列化版本号 serialVersionUID
//序列化的时候 会根据类中的成员信息 会生成一个 serialVersionUID
//反序列化的时候 会根据类中的成员信息 会生成一个 serialVersionUID
//序列化之后 删除了一个属性 导致反序列化时生成的 serialVersionUID 与 序列化时的版本号不一致
//要保证序列化与反序列化使用的类是同一个类才可以
//如何解决这个问题:
//1.删除属性之后 重新序列化一次
//2.将 serialVersionUID 写死 不要让他自动生成
//格式:private static final long serialVersionUID = 1L;
//保证前后ID是一致的 反序列化的时候 存在属性就赋值 不存在属性就不赋值
3.transient 瞬态修饰符 被这个修饰符修饰的成员 不能被序列化的
案例:
1.一个类实现序列化接口
public class Student implements Serializable {
private String name;
private int 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 Student(String name, int age) {
this.name = name;
this.age = age;
}
public Student(){
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
2.进行序列化
public class Demo {
public static void main(String[] args) throws IOException {
Student stu = new Student("张三", 19);
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("a.txt"));
oos.writeObject(stu);
oos.close();
}
}
3.进行反序列化
public class Ser {
public static void main(String[] args) throws IOException, ClassNotFoundException {
// Student stu=new Student("张三",18);
// ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("aaa.txt"));
// oos.writeObject(stu);
// oos.close();
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("aaa.txt"));
Student stu= (Student) ois.readObject();
System.out.println("stu = " + stu);
ois.close();
}
}
4.对类进行修改 并再次反序列化,报错:解决方式1.添加serialVersionUID,少的属性给默认值。
public class Student implements Serializable {
//该类的序列版本号与从流中读取的类描述符的版本号不匹配
//序列化的这个类 都有一个序列化版本号 serialVersionUID
//序列化的时候 会根据类中的成员信息 会生成一个 serialVersionUID
//反序列化的时候 会根据类中的成员信息 会生成一个 serialVersionUID
//序列化之后 增加/删除了一个属性 导致反序列化时生成的 serialVersionUID 与 序列化时的版本号不一致
//要保证序列化与反序列化使用的类是同一个类才可以
//如何解决这个问题:
//1.删除属性之后 重新序列化一次
//2.将 serialVersionUID 写死 不要让他自动生成
//格式:private static final long serialVersionUID = 1L;
//保证前后ID是一致的 反序列化的时候 存在属性就赋值 不存在属性就不赋值
private static final long serialVersionUID = 5716919894699259371L;
private String name;
private int age;
//地址是保密的 不想对他进行序列化
//transient 瞬态修饰符 被这个修饰符修饰的成员 不能被序列化的
private transient String address;
public String getAddr() {
return addr;
}
public void setAddr(String addr) {
this.addr = addr;
}
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 Student(){
}
public Student(String name, int age, String addr) {
this.name = name;
this.age = age;
this.addr = addr;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", addr='" + addr + '\'' +
'}';
}
}
进程 线程 并发 并行
一进程多线程
进程:是系统运行程序的基本单位
线程:是进程中的一个执行单位
并发:在同一时间段发生
并行:在同一时刻发生
创建线程的第一种方法:继承
1.创建一个类继承Thread接口
2.重写run方法
3.创建线程对象
4.开启线程 开启后,这个线程就有机会被CPU执行的机会
public class ExtendsDemo extends Thread{
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(getName() +"继承:"+i);
}
}
}
public class Demo {
public static void main(String[] args) {
Thread thread = new Thread();
thread.start();
for (int i = 0; i < 100; i++) {
System.out.println("主线程: " + i);
}
}
}
创建线程的第二种方法:实现
public class ExtendsDemo implements Runnable{
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() +"实现:"+i);
}
}
}
//getName() 是属于 Thread类中的方法
//之前是继承了Thread类 所以可以用getName
//当前类跟Thread一毛钱关系都没有 肯定无法使用getName()
//static Thread currentThread()
// 返回对当前正在执行的线程对象的引用
//线程任务类 将他丢在哪一个线程中 他就属于哪一个线程
public class Demo {
public static void main(String[] args) {
Thread thread = new Thread();
thread.start();
for (int i = 0; i < 100; i++) {
System.out.println("主线程: " + i);
}
}
}
匿名实现
public class Demo {
public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("实现:"+i);
}
}
}).start();
}
}
匿名继承
public class Demo {
public static void main(String[] args) {
new Thread("线程名"){
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("i = " + i);
}
}
}.start();
}
}