java
文章目录
数据类型
package test1;
/*
数据类型
基本数据类型:
整型:byte short int long
浮点型:float double
字符:char
布尔:boolean
注意:整型默认为int 浮点型默认double
字符串是String 特殊的引用数据类型通常做基本数据类型使用
变量:在程序相运行过程中可以发生改变的值
定义格式:
数据类型 变量名;
定义定初始化格式:
数据类型 变量名=初始化值(常量);
变量的操作
取值和修改
取值:就直接使用变量名称
修改:重新给值
格式:变量名=值;
注意:
1.使用之前必须初始化
2.等号左右数据类型一致
3.变量不能重新定义
4.整型默认int和浮点型默认double的问题
*/
public class DataType {
public static void main(String[] args) {
int a=1;
int b=2;
int c=a+b;
double d=a+b;
System.out.println(c); //3
System.out.println(d); //3.0
/*
类型转换:Java中不同的数据类型进行相互转换
分类:
自动类型转换(也叫隐式类型转换)
把一个范围小的数据类型或变量赋值给一个范围大的数据类型或变量
例如:double d=10;
强制类型转换(也叫显式类型转换)
把一个范围大的数据类型或变量赋值给一个范围小的数据类型或变量
例如:int i=(int)10.5;
注意:强制类型转换会造成精度丢失
*/
//隐士转换:小变大
double e=10;
System.out.println(e); //10.0
//强制转换:大变小
int i=(int)10.5;
System.out.println(i);//丢失精度 10
}
}
运算符
package test1;
/*
运算符:对常量和变量进行操作的符号
表达式:用运算符把常量和变量连接起来符合Java语法的式子,表达式中不同的运算符是不同类型的表达式
算术运算符:+,-,*,/,%,++,--,+另一种方式
注意:++和--只能使用在变量上
表达式中如果有多个加号,从左向右依次执行 (10+20+"你好")
如果加号两端出现了字符串,+做拼接使用,否者做算术运算符使用
包含类型自动提升,在算术表达式中如果有不同数据类型的值进行相加,结果的数据类型为范围大的
例如:10+15.5结果数据类型为double
赋值运算符:=,+=,-=...
简写的+=的方式:简写的是在某个变量基础之上进行相加的算术表达式
例如:int i=10;
i=i+15;可以简写为i+=15;
注意:简写的+=的方式包含了强制类型转换
例如:int i=15;
i+=10.5;结果为25
比较运算符:<,>,==,>=,<=...
注意:
如果使用==来进行判断两个String类型的数据是否相等,在某些情景之下会出现问题,所以不建议使用
String有专用于判断等于的方式equals,必须是两个字符串判断是否相等
例如:String str="admin";
str.equals(字符串)
逻辑运算符: &(and\与)
|(or\或)
!(非)
&&(短路and\短路与)
||(短路or\短路或)
为什么使用逻辑运算符:
因为20<x<50这种格式不符个java语法规范,所以需要逻辑运算符
一个符号和两个符号的区别:
一个符号:无论什么情况都会执行所有比较表达式
两个符号:在某些情况下只会执行第一个表达式
建议使用两个符号的逻辑运算符:
两个符号的逻辑运算符能减少计算时间和资源消耗
三元表达式:判断然后取值
格式:(比较表达式)?表达式1:表达式2;
*/
public class Operator {
public static void main(String[] args) {
int a=5;
a+=6.5; // a=a+6;
System.out.println(a);//包含强制类型转换 11
//出现字符串,+ 作拼接使用
System.out.println(5+5+"你好"); //10你好
System.out.println("你好"+5+5); //你好55
int x=10;
int y=20;
System.out.println(x++>5 || y++>10); //true
System.out.println(x); //11
System.out.println(y); //20
String str="admin";
boolean boo=str.equals("minad");
System.out.println(boo);
System.out.println(a>5 && a<12);//与或非,使用两个符号的
int b=(5>4)?5:4;
System.out.println(b); //5
String str1=(a>b)?"true":"false";
System.out.println(str1); //true
}
}
Scanner
package test1;
import java.util.Scanner;
/*
键盘录入:
三步
1.导包
import java.util.Scanner;
必须在类定义之外并且之上
2.创建对象
Scanner sacnner=new Scanner(System.in);
固定格式(除了sacnner是变量名可以手动更改)
3.1.接收int数据
int i=scanner.nextInt();
固定格式(除了i是变量名可以手动更改)
3.2.接收String数据
String str=scanner.next();
固定格式(除了str是变量名可以手动更改)
*/
public class Scan {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("请输入数字:");
int i= scanner.nextInt();
System.out.println("输出结果:"+i);
}
}
If
/*
程序流程控制
顺序:java程序默认从上到下依次执行
分支
单分支
格式:
if(比较表达式){
语句体;
}
执行流程:
1.首先执行比较表达式,结果为true或false
2.结果为true执行语句体
3.结果为false不执行语句体
4.向下依次执行
双分支
格式:
if(条件表达式){
语句体1;
}else{
语句体2;
}
执行流程
1.先计算关系表达式的值
2.如果关系表达式的值是true,执行语句体1。
3.如果关系表达式的值是false,执行语句体2,
4.继续执行后面的内容
多分支
格式:
if(条件表达式1){
语句体1;
}else if(条件表达式2){
语句体2;
}
……
else{
语句体n;
}
执行流程
1.先计算关系表达式1的值
2.如果关系表达式1的值是true,执行语句体1,如果为false计算关系表达式2的值。
3.如果关系表达式2的值是true,执行语句体2,如果为false计算关系表达式3的值
4.。。。。。
5.如果没有任何关系表达式的值为true,执行语句体n
注意:else加不加不会进行报错
多分支情况下通常把最后一种可能性写入到else之中
多个条件表达式1从上到下依次执行,如果成立当前if语句结束(之下的条件表达式不会执行)
*/
package test1;
import java.util.Scanner;
public class If {
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
System.out.println("请输入a,b值:");
int a = sc.nextInt();
int b = sc.nextInt();
if (a>b){
System.out.println("最大值为:" + a);
} else {
System.out.println("最大值为:" + b);
}
System.out.println("请输入成绩:");
int c = sc.nextInt();
if (c==100){
System.out.println("满分");
} else if (c>=80) {
System.out.println("优秀");
} else if (c>=60) {
System.out.println("及格");
}else {
System.out.println("补考");
}
}
}
/*
shell脚本中:
if
then
elif
then
else
fi
*/
循环(for,while)
/*
循环语句
while
格式1:
初始化语句
while(判断条件){
循环体;
条件控制语句;
}
格式2:
初始化语句;
do{
循环体;
条件控制语句;
}while(判断条件);
初始化语句(定义变量):循环结构什么时候开始,也用于记录循环次数(一条或多条)
条件判断语句:决定了循环什么时候结束(结果为boolean的表达式,为false时结束)
循环体:循环结构中反复执行的事情(任意语句)
条件控制语句:通过改变变量的值来控制循环次数(常见操作i++,i--等)
区别:格式1先判断再执行,格式2先执行再判断
for
格式
for(初始化变量;判断条件;条件控制语句){
循环体;
}
执行流程:
初始化变量->判断->循环体->条件控制语句
死循环
while(true)
do_while(true)
for(;;)
三种循环的区别:
while和for先判断在执行,do-while先执行再判断
for中初始化变量名称是for中独有的
break:
用在循环和选择语句中,基于条件控制,用于终止语句的执行
continue:
用在循环中,基于条件控制,用于跳过某次语句的执行,继续下一的执行
switch: 专门用于做等值判断
格式:
switch(表达式){
case 值1:
语句;
break;
case 值2:
语句;
break;
.
.
.
default:
语句;
break;
}
注意:
cae后的值不能重复
不注重顺序(等值判断只有一个结果为true)
default和break可加可不加(没有特殊的需求,都加上)
语句嵌套:
语句之中还有语句
每一个语句都有一个{}表示整体结构,每一个语句之中还有别的语句存在就是语句嵌套
*/
package test;
import java.util.Scanner;
public class Loop {
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
System.out.println("请输入:");
int a = sc.nextInt();
//switch : 专门用于做等值判断 (当没有break时,case判断不走了,但语句体还是会走)
//例如视频中讲解 输入2,输出周二周三
switch (a) {
case 2:
System.out.println("2");
break;
case 3:
System.out.println("3");
break;
default:
System.out.println("其他");
break;
}
System.out.println("===============");
//while:循环
//格式1:
while (a<=10){
System.out.println(a);
a++;
}
System.out.println("===============");
int i=1;
int so=0;
int sj=0;
int s=0;
while (i<=100) {
// i++;
if (i%2==0){
so=so+i;
}else {
sj=sj+i;
}
s=s+i;
i++;
}
System.out.println("偶数和:"+so);
System.out.println("奇数和:"+sj);
System.out.println("总和:"+s);
System.out.println("===============");
//格式2:
do {
System.out.println(a);
a++;
}while (a<=10);
System.out.println("===============");
//for循环
int b;
for (b=5;b<=10;b++){
System.out.println(b);
}
System.out.println("===============");
//死循环写法
// while(true){
// System.out.println(1);
// }
//
// for(;;){
// System.out.println(1);
// }
for (int i=1;i<=7;i++){
System.out.println(i);
if (i==5){
break;
}
}
System.out.println("======break========");
for (int i=1;i<=5;i++){
if (i==3){
continue;
}
System.out.println(i);
}
}
}
//continue; 跳过
数组
package test;
/*
动态初始化:指定长度
静态初始化:指定数组内容
内存分布:
栈:存储方法中的局部变量的,方法在这里面执行
堆:new 出来的东西都在堆里
方法区:存放类,main方法的,存放.class相关内容
数组:一种容器,可以保存多个值
用来存储任何类型的数据,包括原始数据类型和引用数据类型,
但是一旦指定了数组的类型之后,就只能用来存储指定类型的数据。
特点:数组一旦创建,长度不可改变
数组中的值,类型都一样
数组是引用类型
*/
public class Array {
public static void main(String[] args) {
//动态初始化(虽然没有直接给定元素,只给了长度,但是会有默认值)
//string:默认值为null
String [] a = new String[3];
System.out.println(a[0]);//null
System.out.println(a[1]);//null
System.out.println(a[2]);//null
System.out.println("=========int===========");
//int:默认值为0
int [] b = new int[2];
System.out.println(b[0]);
System.out.println(b[1]);
System.out.println("=========double===========");
//double:默认值为0.0
double [] c = new double[2];
System.out.println(c[0]);
System.out.println(c[1]);
System.out.println("===============");
//静态初始化1:
String [] d = new String[] {"张三","李四","王五","周六"};
System.out.println(d[0]);
System.out.println(d[3]);
//静态初始化2:简写
String [] e = {"张三","李四","王五","周六"};
System.out.println(e[0]);
//System.out.println(e[4]); //索引:从0开始,到数组长度减 1 为止。越界会报错
System.out.println("===================");
//修改数组的内容(可以这样给数组赋值)
int [] arrayA = new int[3];
arrayA[1]=20;
arrayA[2]=30;
System.out.println(arrayA); //内存地址
System.out.println(arrayA[0]);
System.out.println(arrayA[1]);
System.out.println(arrayA[2]);
System.out.println("====================");
//NullPointerException:空指针异常。原因:未对数组进行初始化
int [] arr = null;
//arr = new int[2];
System.out.println(arr[0]);
System.out.println("=========================遍历数组:");
//遍历数组
String [] f = new String[] {"张三","李四","王五","周六"};
for (int i = 0; i < f.length; i++) {
System.out.println(f[i]);
}
System.out.println("========练习======");
//求最值(最大,最小)
int [] g = {100,300,50,700,2000,5000};
int min = g[0]; // 就取第一个数用来比较大小,假设第一个数最小
for (int i = 0; i < g.length; i++) {
if (min > g[i]){
min = g[i];
}
}
System.out.println(min);
System.out.println("==========冒泡排序==========");
int[] h = {1, 3, 5, 9, 8, 6, 4, 7};
for (int i = 0; i < h.length - 1; i++) { //控制比较轮次,共 n-1 次
for (int j = 0; j < h.length - i -1; j++) { //-1防止数组越界
if (h[j] > h[j+1]){ //控制相邻的两个元素比较
int temp = h[j];
h[j] = h[j+1];
h[j+1] = temp;
}
}
}
//冒泡排序完成后,遍历一遍看看结果:
for (int i = 0; i < h.length; i++) {
System.out.println(h[i]);
}
System.out.println("==========选择排序==========");
int[] arrayA = {1, 3, 8, 5, 9, 4, 7, 6};
// 1, 3, 8, 5, 9, 4, 7, 6
// 1, 3, 8, 5, 6, 4, 7, 9 9和6交换位置
// 1, 3, 7, 5, 6, 4, 8, 9 8和7交换位置
// 1, 3, 4, 5, 6, 7, 8, 9 6和6交换位置
// 1, 3, 4, 5, 6, 7, 8, 9
// 1, 3, 4, 5, 6, 7, 8, 9
// 1, 3, 4, 5, 6, 7, 8, 9
// 1, 3, 4, 5, 6, 7, 8, 9
// 选择排序
for (int i = 0; i < arrayA.length - 1; i++) {
int maxIndex = 0;//默认最大索引位置先给0
for (int j = 0; j < arrayA.length - i; j++) {
if (arrayA[j] > arrayA[maxIndex]) {
maxIndex = j;
}
}
int temp = arrayA[maxIndex];
arrayA[maxIndex] = arrayA[arrayA.length - i - 1];
arrayA[arrayA.length - i - 1] = temp;
}
// 打印数组
for (int i = 0; i < arrayA.length; i++) {
System.out.print(arrayA[i]);
}
System.out.println("==========数组的倒转==========");
int[] arrayA = {1, 3, 5, 7, 9, 11}; //当左边索引=右边索引停止交换
for (int leftIndex = 0, rigthIndex = arrayA.length - 1; leftIndex < rigthIndex; leftIndex++, rigthIndex--) {
// 交换对称索引位置的元素
int temp = arrayA[leftIndex];
arrayA[leftIndex] = arrayA[rigthIndex];
arrayA[rigthIndex] = temp;
}
for (int i = 0; i < arrayA.length; i++) {
System.out.println(arrayA[i]);
}
}
}
//数组是引用数据类型,对引用数据类型的修改,是对堆内存地址的修改,所以打印原始数组也会发现改变了
//变量不会变,变量是基本数据类型
- 二维数组
package day04_Array;
/*
一维数组:里面的每一个元素都是基本数据类型 或者 String引用类型
动态初始化(需要指定长度):
格式: 数据类型[] 数组名称 = new 数据类型[长度];
数据类型 -> 引用类型 -> 数组类型: 数据类型 [长度]
定义:
数组里面可以包含引用类型,数组本身就是一个引用类型,
二维数组就是 数组里面包含数组
初始化:
动态初始化(需要指定长度):
格式: 数据类型 [][] 二维数组名称 = new 数据类型[长度1][长度2];
长度1:先初始化一个长度为 长度1 的数组A,该数组A里面可以存 长度1 个数组B
长度2:数组B的长度
注意:长度2可以省略,长度1无法省略
静态初始化(需要指定内容):
数据类型 [][] 二维数组名称 = new 数据类型[][]{数组1,数组2,数组3.....};
简写方式: 数据类型 [][] 二维数组名称 = {数组1,数组2,数组3.....}
数组1、2、3 的长度可以任意,但必须是一个数组,不能是基本数据类型
访问二维数组的元素a:
第一步:先访问元素a所在的数组C
第二步:再访问数组C中的元素a
格式:
二维数组名称[数组索引][数组里的元素索引]
思考:
如何遍历二维数组的所有元素?
*/
public class Demo17_ArrayTwoDimension {
public static void main(String[] args) {
// 动态初始化二维数组 指定两个长度
int[][] arrayAA = new int[2][3];
System.out.println(arrayAA); // 内存地址1
System.out.println(arrayAA[0]); // 内存地址2
System.out.println(arrayAA[1]); // 内存地址3
System.out.println("============");
System.out.println(arrayAA[0][0]);
System.out.println(arrayAA[0][1]);
System.out.println(arrayAA[0][2]);
System.out.println("============");
System.out.println(arrayAA[1][0]);
System.out.println(arrayAA[1][1]);
System.out.println(arrayAA[1][2]);
System.out.println("============");
// 数组索引越界
// System.out.println(arrayAA[2]);
// 动态初始化二维数组 指定一个长度
int[][] arrayAB = new int[2][];
arrayAB[0] = new int[3];
arrayAB[1] = new int[3]; // 3步合并 => int[][] arrayAA = new int[2][3];
// 静态初始化二维数组,直接指定内容
int[][] arrayBB = new int[][]{{1, 2, 3}, {2, 3, 4}, {5, 6}, {7}};
// 静态初始化二维数组的简写方式
int[][] arrayBC = {{1}, {1, 2, 3}, {2, 3, 4}, {5, 6}, {7}};
}
}
ArrayList
/*
为什么使用集合?
数组不能满足存储可变的多个相同数据
集合
ArrayList<E>
特点:
可变的存储模型
<E>表示泛型(指定存储的数据)
使用:如果想要通过ArrayList<E>存储String类型的数据
举例:ArrayList<String>
构造和添加
public ArrayList() 创建一个空白的对象
public boolean add(E e) 将指定的元素追加到集合末尾
public void add(int index,E element) 在集合中的指定位置插入指定的元素
注意:创建对象时,E被替换,方法上的E随着被替换
public boolean add(E e)不需要接受返回值并判断(只要参数对,返回值永远为true)
使用add时,只能连续添加
常用方法
public boolean remove(Object o) 删除指定元素,返回删除是否成功
public E remove(int index) 删除指定索引的元素,返回删除的元素
public E set(int index,E element) 修改指定索引的元素,返回被修改的元素
public E get(int index) 返回指定索引的元素
public int size() 返回集合中元素个数
public boolean contains(Object o) 如果此列表包含指定的元素,则返回 true 。
*/
package test1;
import java.util.ArrayList;
public class Demo_Arraylist {
public static void main(String[] args) {
//创建String类型的一个集合
ArrayList<String> list = new ArrayList<>();//创建一个空白的对象
System.out.println(list); //[]
list.add("10");
System.out.println(list); //[10]
list.add("20");
System.out.println(list); //[10, 20]
list.add(1,"30");
System.out.println(list); //[10, 30, 20]
System.out.println(list.size()); //3
System.out.println(list.get(2)); //20
System.out.println("========遍历集合=========");
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
}
}
- 集合存放学生类
package day7_Array;
public class Student {
private String name;
private int age;
private String clazz;
public void show(){
System.out.println(name+"----"+age+"-----"+clazz);
}
public Student() {
}
public Student(String name, int age, String clazz) {
this.name = name;
this.age = age;
this.clazz = clazz;
}
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 getClazz() {
return clazz;
}
public void setClazz(String clazz) {
this.clazz = clazz;
}
}
package day7_Array;
import java.util.ArrayList;
public class Demo08_ArrayList {
public static void main(String[] args) {
Student student1 = new Student("张三1",20,"一班");
Student student2 = new Student("张三2",18,"一班");
Student student3 = new Student("张三3",25,"一班");
ArrayList<Student> students = new ArrayList<>();
students.add(student1);
students.add(student2);
students.add(student3);
for (int i = 0; i <students.size() ; i++) {
students.get(i).show();
}
}
}
装箱和拆箱
为什么进行装箱和拆箱?
- ArrayList不支持存储基本数据类型
- 基本数据类型有些操作不能实现,通过包装器类型可以实现
- 装箱
package day7_Array;
//装箱就是将基本数据类型转换为包装器类型
//范例:
// 1.Integer a=Integer.valueOf(10);
// 2.Integer a=10;
public class Demo12_ZX {
public static void main(String[] args) {
//方式1:
Integer integer = Integer.valueOf(10);
System.out.println(integer);
//方式2:
Integer integer1=10;
System.out.println(integer1);
}
}
- 拆箱
package day7_Array;
//拆箱就是将包装器类型转换为基本数据类型
//范例:
// 1.int i=a.intValue();
public class Demo13_CX {
public static void main(String[] args) {
Integer a=10;//包装器类型
//拆箱
int i=a;
int i1 = a.intValue();
System.out.println(i);
System.out.println(i1);
}
}
- int <–> String
package day7_Array;
public class Demo13_IntToString {
public static void main(String[] args) {
//int转String
int i=10;
String str=String.valueOf(i);
System.out.println(str);
//String转int(String类型的int才能转换为int类型)
String str="10";
Integer integer = Integer.valueOf(str);
System.out.println(integer);
}
}
方法
package test1;
/*
方法:针对某一功能代码的集合
基础定义格式:
public static void 方法名(){
方法体;
}
1、方法不能嵌套。方法定义在类中,不能定义在方法中
2、方法需要手动调用:
方法名();
调用方式:
直接调用
打印调用
接收调用:int i=sum(1,2)
*/
public class Demo_fun {
public static void main(String[] args) {
job("工作");
System.out.println(sum(1, 2));
}
//没有返回值类型
public static void job(String string) {
System.out.println(string + ":");
System.out.println("大数据开发");
System.out.println("JAVA开发");
}
//有返回值类型
public static int sum(int a, int b) {
int sum_ab = a + b;
return sum_ab;
}
}
/*
完整的方法定义:
修饰符 返回值的类型 方法名(参数类型 参数名称,参数2类型 参数2名称......){
方法体;
return 返回值;
}
方法名:命名规则同变量的命名规则,小驼峰
return:1、停止程序;2、将返回值返回到调用方法的地方
*/
- 方法重载
package test;
//两个数相加,但类型未知
//方法的重载:方法名字相同,参数列表不同
//好处:只需记住一个函数名,就可以对 不同参数列表的数组 进行处理
public class FunctionOverLoad {
public static void main(String[] args) {
System.out.println(sum((byte) 1, (byte) 9));//byte
int sum = sum(1, 2); //int
System.out.println(sum);
double sum1 = sum(1.2, 2.3); //double
System.out.println(sum1);
//定义数组类型的方法,并遍历数组
int[] array = {1, 2, 3};
sum(array);
//递归函数求n的阶层
System.out.println(fun(5));
}
public static byte sum(byte a, byte b) {
System.out.println("调用byte类型加法");
return (byte) (a + b);
}
public static int sum(int a, int b) {
System.out.println("调用int类型相加");
int c = a + b;
return c;
}
public static double sum(double a, double b) {
System.out.println("调用double类型加法");
return a + b;
}
public static void sum(int[] array) { //数组类型为数组的方法
System.out.println("参数类型为数组");
for (int i = 0; i < array.length; i++) {
System.out.println(array[i]);
}
}
//递归函数:函数自己调用自己
//需要满足两个条件:
//1、自己调用自己
//2、停止条件
public static int fun(int n) { //使用递归函数求N 的阶层:n*(n-1)!
// 停止条件
if (n == 1) {
return 1;
} else {
return n * fun(n - 1);
}
}
}
/*
方法重载到底与什么条件有关呢(什么情况下可以构成重载呢)?
1、参数的类型不一样
2、参数的长度不一样
3、对于有多个”不同类型“的参数,只要顺序不一样,也可以实现重载
方法重载跟什么无关呢?
1、参数的名字无关
2、跟方法的返回值类型无关
*/
StringBuilder
package test1;
/*
为什么使用StringBuilder?
String发生修改时,会创建新的String对象,这种方式即耗时又浪费内存
StringBuilder
构造
StringBuilder() 创建一个空白的StringBuilder对象,不含有任何内容
StringBuilder(String str) 根据字符串的内容,创建StringBuilder对象
操作
append(任意类型) 添加数据并返回对象本身
reverse() 返回相反的字符序列
注意:在原数据上进行操作
为什么String和StringBuilder要进行相互转换?
String类型有些操作(需要反转)需要手写代码,但是StringBuilder可以直接调用方式进行实现(reverse()实现反转)
1.StringBuilder转为String
public String toString()
2.String转为StringBuilder
public StringBuilder(String str)
*/
public class Demo_StringBuilder {
public static void main(String[] args) {
StringBuilder stringBuilder = new StringBuilder("asdf");//创建空的StringBuilder,不会含有任何内容
System.out.println(stringBuilder);
stringBuilder.append("ghj"); //asdfghj
System.out.println(stringBuilder);
StringBuilder sb = new StringBuilder("123456");
sb.reverse(); //相反
System.out.println(sb);
System.out.println("========================");
//String和StringBuilder进行相互转换
//StringTOStringBuilder
String str="abcdef";
StringBuilder sb1 = new StringBuilder(str);
sb1.reverse();
System.out.println(sb1);
String s = sb1.toString();
System.out.println(s);
}
}
面向对象
面向对象:是一种编程思想
java中实现面向对象的流程
1.先创建类(包含属性和方法)
2.创建对象
3.赋值使用类:现实生过中拥有共同属性和行为事物的抽象(看不见摸不着)
对象:现实生过中具体的存在(看的见摸的着)
类是对象的抽象(集合),对象是类的实现(实体)
类可以看做是对象的数据类型
- 学生类
package test;
/*
类的定义:class所修饰的称之为类
1.public class 类名{}
2.通过成员变量(方法之外的变量)体现属性
格式:数据类型 变量名称;/public 数据类型 变量名称
使用第二个格式
3.通过成员方法 (没有static) 体现行为:
格式:public 返回值类型 方法名(参数){}
*/
public class Student {//学生类,表示所有学生
//属性
public String name;
public int age;
public String clazz;
//行为
public void play(){
System.out.println("学生爱玩");
}
public void study(){
System.out.println("学生要学习");
}
}
package test;
/*
对象的创建和使用
创建
格式:类名 对象名=new 类名();
使用成员变量
格式:对象名.成员属性
使用成员方法
格式:对象名.成员方法
*/
public class StudentTest {
public static void main(String[] args) {
//类是对象的数据类型
Student s = new Student();//s可以表示一个具体的学生(具体的对象)
s.name="张三";
s.age=22;
s.clazz="理科一班";
System.out.println(s.name + s.age + s.clazz);
s.play();
s.study();
}
}
- 学生类
package Lei.demo01;
/*
类的定义:(有class修饰)
1、public class 类名{}
2、定义成员属性
3、定义成员方法:不带static
*/
public class Student {
//属性
String name;
String sex;
int age;
//行为
public void study(){
System.out.println("学生在学习");
}
public void paly(){
System.out.println("学生打游戏");
}
}
package Lei.demo01;
//数组存储多个学生,然后获取年龄最大的学生
public class StudentTest {
public static void main(String[] args) {
Student student = new Student();
student.name = "张三";
student.sex = "男";
student.age = 23;
student.study();
System.out.println(student.name + "," + student.sex + "," + student.age);
System.out.println("========================");
Student stu1 = new Student();
stu1.name = "zs";
stu1.age = 25;
Student stu2 = new Student();
stu2.name = "ls";
stu2.age = 26;
Student stu3 = new Student();
stu3.name = "ww";
stu3.age = 22;
Student[] arr = {stu1, stu2, stu3}; //数组,类型是学生类
Student max = arr[0];
for (int i = 0; i < arr.length; i++) {
if (arr[i].age > max.age) {
max = arr[i];
}
}
System.out.println(max.name + max.age);
}
}
- this
package Lei.demo02;
// this:当前类的对象
/*
成员变量 和 局部变量 的区别
1.位置不同 类中方法外 方法内或者方法声明上(形参)
2.内存不同 堆内存 栈内存
3.生命周期 随着对象存在而存在,随着对象的消失而消失 随着方法的调用而存在,随着方法的调用完毕而消失
4.初始值不同 系统分配默认值(int是0,string是null) 没有默认的初始值,必须先定义,赋值,再使用
(想使用必须初始化)
变量的访问:遵循就近原则
*/
public class Student {
public String name = "成员变量";
public void test(){
String name="局部变量";
//想要在方法里面引用方法外的变量
System.out.println(this.name); //this 修饰成员变量
}
}
package Lei.demo02;
public class StudentTest {
public static void main(String[] args) {
Student student = new Student();
System.out.println(student.name); //成员变量
student.test(); //成员变量
}
}
- private
package Lei.demo03;
//private:修饰时,只能当前类调用
public class Student {
private int age;
public void setAge(int age){
System.out.println(this.age=age);
}
public int getAge(){
return age;
}
}
/*
private:权限访问修饰符
可以修饰成员变量和成员方法
private所修饰的只能在本类中会使用
为什么使用private?
别的类直接访问成员变量,可以直接赋值,无论这个值是否符合逻辑都能进行赋值,这种方式会导致数据的不安全,
所以使用private修饰成员变量,避免别的类直接访问成员变量进行随便赋值
被 private 修饰的成员变量,如果要被别的类使用,提供相应的操作
提供 get变量名() 方法,用于获取成员变量的值,用 public 修饰
提供 set变量名() 方法,用于设置成员变量的值,用 public 修饰
注意:每个私有化(private所修饰的)的成员变量,与之对应的有两个方法,一个set一个get
快捷键:alt+insert->Getter and Setter->所有私有化变量->回车
*/
package Lei.demo03;
public class StudentTest {
public static void main(String[] args) {
Student student = new Student();
student.setAge(200); //200
int age=student.getAge();
System.out.println(age); //200
}
}
- 封装
定义:
- 面向对象的三大特征之一(封装、继承、多态)
- 隐藏类中的内部细节,外界无法直接调用(因为有private修饰)
原则:
- 将类的某些信息隐藏在类内部,不允许外界直接调用,而是通过该类提供的方法(set、get)实现对隐藏信息的操作和访问。
- private私有化成员变量,提供了对应的set和get方法
优点:
- 通过方法控制成员变量,提高了代码的安全性
- 把代码进行封装,提高了代码的复用性
package Lei.demo05;
public class Student {
private String id;
private String name;
private int age;
private String sex;
//ctrl+shift+ +/-
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 int getAge() {
return age;
}
public void setAge(int age) {
if (age > 0 && age <= 120) {
this.age = age;
} else {
System.out.println("age有问题");
}
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
//自己手动定义一个方法,接收这几个值
public void show() {
System.out.println(id);
System.out.println(name);
System.out.println(age);
System.out.println(sex);
}
}
package Lei.demo05;
public class Test {
public static void main(String[] args) {
Student student = new Student();
student.setId("1001");
student.setName("张三");
student.setAge(18);
student.setSex("男");
student.show();
}
}
- 构造方法
package Lei.demo04;
/*
构造方法:是一个特殊的方法
作用:用于创建对象
功能:主要是完成对象的初始化
默认会有一个无参构造,无参构造中没有任何输出
如果手动书写了构造(无论有参还是无参)会把默认的无参构造覆盖掉
*/
public class Student {
public Student(){
System.out.println("这是无参构造");
}
public Student(int i){
System.out.println("这是有参构造");
}
}
package Lei.demo04;
public class StudentTest {
public static void main(String[] args) {
Student stu1 = new Student();
Student stu2 = new Student(10);
}
}
package day06.demo7;
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;
}
public void show (){
System.out.println(name+":"+age);
}
}
package day06_OOP.demo08_Construc;
public class Test {
public static void main(String[] args) {
//先创建对象 然后赋值
Student student1 = new Student();
student1.setName("张三");
student1.setAge(18);
student1.show();
System.out.println("------------------------");
//创建对象并赋值
Student student2 = new Student("张三",18);
student2.show();
//通过有参构造创建对象,然后获取年龄最大的学生
}
}
API
概述:
- 应用程序编程接口
- 编写一个机器人程序去控制机器人去踢球,程序需要向机器人发送前进,后退射门等命令。机器人厂商一定会提供一些用于控制机器人的接口类,这些类中定义了机器人的各种动作的方法,其实这些接口类就是机器人厂商提供给应用程序编程的接口,这些类称之为API
Java API:指的就是JDK中提供的各种功能的Java类
这些类底层的实现进行了封装,我们不需要关心这些类是如何实现的,之需要学习这些类如何使用即可
String类
String类表示字符串,Java中所有的字符串文字,都是String类的实例
就是说,Java程序中所有的双引号字符串都是String类的对象
特点:
String是特殊的引用数据类型(通常基本数据类型使用)
String的值,给定之后不可变(做基本数据类型使用时)
String的值,不可变但是可以被共享(做基本数据类型使用时)
String底层为char数组,更底层为byte数组
常见操作
遍历:String有长度有下标
通过charAt(int index)
切分:
通过split(String regex)
替换:
通过replace(char oldChar, char newChar)转义符:
作用:更改转义符之后第一个字符的默认含义
例如:n默认含义是字母
\n表示换行
\默认含义为转义符
\表示字符\
package day06_OOP.demo09_String;
/*
public String() 创建一个空白的字符串对象,不含有任何内容
public String(char[] c) 根据字符数组的内容,创建字符串对象
public String(byte[] b) 根据字节数组的内容,创建字符串对象
String(byte[] bytes, int offset, int length) 通过使用平台的默认字符集解码指定的字节子阵列来构造新的 String 。
String s=“abc” 直接赋值的方式创建对象
*/
public class Demo01_String {
public static void main(String[] args) {
String s = new String();
System.out.println(s);
char[] chars={'a','b','c','d'};
String s = new String(chars);
System.out.println(s); //abcd
byte[] bytes={97,98,99,100};
String s = new String(bytes);
System.out.println(s); //abcd
//String(byte[] bytes, int offset, int length)
byte[] bytes={97,98,99,100};
String s = new String(bytes,0,bytes.length);
System.out.println(s); //abcd
String s="abcd";//当前使用方式当做基本数据类型使用
System.out.println("===================")
String s1="abcd";
String s2="abcd";//都在常量池里,就比较值是否相同
String s3=new String("abcd");
String s4=new String("abcd");//引用类型,比较地址
System.out.println(s1==s2);//true
System.out.println(s3==s4);//false
System.out.println(s1==s3);//false
System.out.println("===================")
//String的值,给定之后不可变 (做基本数据类型使用时)
//String的值,不可变但是可以被共享 (做基本数据类型使用时)
//常量:在程序运行过程中不能发生改变的量
String s="Hello";
s+="World";
System.out.println(s);
}
}
package day06_OOP.demo10_String;
public class Demo01 {
public static void main(String[] args) {
String str="abcdefgasdbvadsa";
int count=0;
for (int i=0;i<str.length();i++){
if('a'==str.charAt(i)){ //charAt(int index):返回 char指定索引处的值。
count++;
}
}
System.out.println(count);//4
//字符串的切分 split(String regex)
String str="床前明月光,疑似地上霜。举头望明月,低头思故乡。";
String[] split = str.split(",|。");
for (int i = 0; i < split.length; i++) {
System.out.println(split[i]);
}
String str="HelloWorld.java.java";
String replace = str.replace("java", "txt");
System.out.println(replace); //"HelloWorld.txt.txt"
//转义符 \:更改含义(只能更改转义符之后第一个的含义)
System.out.println("Hello\nWorld");
System.out.println("Hello\\nWorld");//Hello\nWorld
System.out.println("Hello\"World");// Hello"World
}
}
继承
package Extends.demo2;
public class Person {
private String name;
private int age;
private String sex;
//写一个吃饭的方法
public void eat(){
System.out.println("吃饭");
}
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 getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
}
- Student
package Extends.demo2;
//格式:public class 子类名 extends 父类名{}
public class Student extends Person{
//子类中独有的方法
public void study(){
System.out.println("学习");
}
}
- Teacher
package Extends.demo2;
public class Teacher extends Person{
//子类中独有的属性和方法
private int money;
public void paly(){
System.out.println("上课");
}
public int getMoney() {
return money;
}
public void setMoney(int money) {
this.money = money;
}
}
- 创建对象
package Extends.demo2;
/*
继承:面向对三大特点之一
父类可以称之为基类或超类
子类可以称之为派生类
特点
子类可以继承父类中的所有成员(不包含构造,构造只能被使用,不能被继承)
子类可以拥有独有的属性和方法
好处
提高了代码的复用性
提高了代码的维护性
弊端
类与类之间提高了耦合性,当父类发生改变时,子类必须发生改变,降低了子类的独立性
*/
public class Test {
public static void main(String[] args) {
Student student = new Student();
student.setName("张三");
System.out.println(student.getName());
student.eat();
Teacher teacher = new Teacher();
teacher.setAge(22);
teacher.paly();
}
}
- super
package Extends.demo3;
public class Person {
public int age=20;
}
package Extends.demo3;
//super:表示当前类父类的对象
// this:表示当前类的对象
public class Student extends Person{
public int age=30;
public void test(){
int age =40;
System.out.println(super.age);
System.out.println(this.age);
System.out.println(age);
}
}
package Extends.demo3;
/*
成员变量访问顺序:
1.子类局部变量
2.子类成员变量
3.父类成员变量
4.没有就报错(不考虑父类还有父类)
成员方法访问
1.子类成员方法
2.父类成员方法
3.没有会报错
*/
public class Test {
public static void main(String[] args) {
Student student = new Student();
student.test(); // 20 30 40
}
}
- 父类的构造访问特点:super()
构造是用来创建对象的
package Extends.demo4;
public class Person {
public Person(){
System.out.println("父类的无参构造");
}
public Person(int i){
System.out.println("父类的有参构造");
}
}
package Extends.demo4;
public class Student extends Person{
public Student(){
//继承中,子类构造(无论无参还是有参)中默认包含父类的无参构造
//在子类构造中的第一行,默认有super();
super();
System.out.println("子类的无参构造");
}
public Student(int i){
super(i); //会覆盖默认的super();
System.out.println("子类有参构造");
}
}
package Extends.demo4;
public class Test {
public static void main(String[] args) {
Student student = new Student();
Student student1 = new Student(10);
//父类的无参构造
//子类的无参构造
//父类的有参构造
//子类有参构造
}
}
/*
构造的访问特点:
子类构造中默认第一行是父类的无参构造
为什么?
因为子类继承父类,子类可能会使用父类的中成员,使用之前父类中的成员必须存在(通过父类的构造进行初始化父类), 初始化子类之前先初始父类
注意:无参构造必须要有,没有无参构造可能会出错,有无参构造肯定不会出错
*/
- 方法重写
package Extends.demo5;
public class Animal {
public void jiao(){
System.out.println("动物在叫");
}
}
package Extends.demo5;
public class Cat extends Animal{
@Override //直接打方法名就出来了
public void jiao(){
System.out.println("喵喵喵");
}
public void eat(){
System.out.println("吃猫粮");
}
}
package Extends.demo5;
public class Dog extends Animal{
@Override
public void jiao(){
System.out.println("汪");
}
}
package Extends.demo5;
public class Pig extends Animal{
@Override
public void jiao() {
super.jiao();
}
}
package Extends.demo5;
public class Test {
public static void main(String[] args) {
Dog dog = new Dog();
dog.jiao(); //汪
Cat cat = new Cat();
cat.jiao(); //喵喵喵
}
}
/*
方法重写:
子类和父类中有一模一样的方法声明
为什么?
继承中,子类中共有的方法提到父类中,实现了父类功能但是子类有自有特定内容,需要子类重写父类中的方法,这样 即实现了父类的功能又实现了子类特有的内容
@Override:注解
作用:
用于区分子类是否实现了方法重写
子类重写父类方法时,可以直接打方法名(有提示)
注意:private所修饰的不能被重写
子类中重写的方法不能比父类中的权限访问修饰符更低(public>默认>private)
注意:
不能实现多继承(一个子类不能继承多个父类)
可以实现多层继承(a继承b,b继承c,a也就继承了c)
private所修饰的成员不能被继承
构造不能被继承只能被使用
*/
- 练习
package Extends.demo6;
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 study() {
System.out.println("人吃饭");
}
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;
}
}
package Extends.demo6;
public class Student extends Person {
public Student() {
}
public Student(String name, int age) {
super(name, age);
}
@Override
public void study() {
System.out.println("学生学习课堂上的内容");
}
}
package Extends.demo6;
public class Teacher extends Person {
private int salary;
public Teacher() {
}
public Teacher(String name, int age, int salary) {
super(name, age);
this.salary = salary;
}
@Override
public void study() {
System.out.println("老师备课学习新内容");
}
public int getSalary() {
return salary;
}
public void setSalary(int salary) {
this.salary = salary;
}
}
package Extends.demo6;
public class Test {
public static void main(String[] args) {
Student student = new Student("zs", 22);
System.out.println(student.getName() + "," + student.getAge());//zs,22
student.study();//学生学习课堂上的内容
Teacher teacher = new Teacher("ls", 33, 5800);
System.out.println(teacher.getName() + "," + teacher.getAge());//ls,33
teacher.study();//老师备课学习新内容
}
}
包
概述
本质就是文件夹
分类管理代码
使用格式
格式:package 包名;(多级包使用.分割)
范例:package com.shujia
注意:
在包下所打的代码,第一行都是表示当前代码的所在位置导包:
不同包下的java文件不能相互使用(不能直接使用),因为默认情况下只能在同一个包下才能相互使用; 不在同一个包下,可以通过给上类的全路径(从src开始的,不同的包之间使用.分割),但是这种方式路劲太长,使 用起来太繁琐
格式:
import 类的全路径;(多级包使用.分割)
例如:import java.util.Scanner;
import java.util.*;注意:只能在同一个项目下,因为java导包默认从当前项目下src开始
java自带的有很多的类,也是以包的形式进行区分,其中java.long这个包叫做java核心类库,使用java.long包下的类不需要导包
修饰符
- 权限访问修饰符
权限访问修饰符 同一个类中 同包 不同包,子类 不同包,非子类
public ------------------√------------√-----------√--------------√
protected--------------√------------√-----------√
default------------------√------------√
private------------------√
package demo09_modi.demo01_level;
public class Student {
public int age;
private int age1;
protected int age2;
int age3;
public void test(){
System.out.println(age);
System.out.println(age2);
System.out.println(age3);
}
}
package demo09_modi.demo01_level;
//同包下
public class Test {
public static void main(String[] args) {
Student student = new Student();
System.out.println(student.age);
// System.out.println(student.age1);//找不到
System.out.println(student.age2);
System.out.println(student.age3);
}
}
- 状态修饰符
final
(最终态):可以修饰成员变量,成员方法,类
特点
:
修饰变量:该变量的值,不能被修改,必须初始化
修饰方法:该方法,不能被重写
修饰类:该类,不能被继承
注意
:修饰引用数据类型时,是地址值不能改变,但地址所指的空间中的内容可以改变
总结
:final修饰不能被修改重写继承
注意:
final修饰变量,当前变量作为常量使用,为了区分,final修饰变量名称全部大写
package demo09_modi.demo02_final;
//final(最终态):可以修饰成员变量,成员方法,类
//final修饰成员变量 必须初始化,不能再发生更改
//final所修饰的成员变量作为常量使用,为了区分变量名全部大写
public class Student {
public int age;
public final int SUM=80;
public String name;
public final String SCHOOL="数加";
public void test(){
// sum=90;//sum不能再被修改
age=20;
age=30;
}
}
- static
static(静态):
可以修饰成员变量,成员方法
特点:
被类的所有对象共享
也是判断是否使用static的条件
修饰的成员变量,成员方法可以通过类名直接调用
注意:静态成员方法只能访问static修饰成员变量和成员方法,因为static修饰的成员是在类加载时加载,并且只加载一次
static所修饰的叫做静态变量或静态方法静态代码块
格式:static{}static变量 static方法 static代码块 执行流程
首先执行定义变量(不是定义并赋值),然后方法,赋值的操作谁在前谁先执行
package demo09_modi.demo06_static;
public class Student {
public String name;
public static String school;
}
package demo09_modi.demo06_static;
public class Test {
public static void main(String[] args) {
//static修饰成员变量 就是所有对象共享的一个值(值一样),用static所修饰
Student.school="数加";
Student zs = new Student();
//zs.school="数加" //通常通过类名.变量名 的方式赋值
zs.name="zs";
System.out.println(zs.school);//数加
Student ls = new Student();
ls.name="ls";
System.out.println(ls.school);//数加
Student ls1 = new Student();
ls1.name="ls1";
System.out.println(ls1.school);//数加
}
}
package demo09_modi.demo08_static;
public class Student {
public int sum;
public static int age;
public void test(){
}
public static void show(){
}
}
package demo09_modi.demo08_static;
//编写->编译->运行
public class Test {
public static void main(String[] args) {
//不用创建对象就可调用,直接通过类名.
//编译过程把static所修饰进行了加载
//static所修饰的成员随着类加载而加载,并且只加载一次
Student.show();
//普通:sum test() static:show(sum) age
Student.age=20;//age已经加载并赋值了
Student student = new Student();//还会不会加载age?不会,如果重新加载 age=0
System.out.println(student.age);//20
}
}
- 静态代码块
package demo09_modi.demo09_staic;
//首先执行定义变量(不是定义并赋值),然后方法,赋值的操作谁在前谁先执行
public class Student {
static {
System.out.println("hello");
age=50;
}
public static int age=20;
public static void show(){
age=30;
}
}
package demo09_modi.demo09_staic;
public class Test {
public static void main(String[] args) {
System.out.println(Student.age);//20
}
}
多态
概述:
同一个类,在不同的时候表现出不同的形态
举例:猫
可以说猫是猫:Cat c=new Cat();
也可以说猫是动物:Animal animal=new Cat();
这里猫在不同的时候 表现出了不同的形态就是多态
前提: 继承 方法重写 父类的引用指向子类的对象
好处:提高了程序的扩展性
弊端:不能使用子类特有的功能
package demo09_modi.demo10_Peptides;
public class Animal {
public void eat(){
System.out.println("动物吃东西");
}
}
package demo09_modi.demo10_Peptides;
public class Cat extends Animal {
@Override
public void eat() {
System.out.println("吃鱼");
}
}
package demo09_modi.demo10_Peptides;
public class Dog extends Animal {
@Override
public void eat() {
System.out.println("啃骨头");
}
}
package demo09_modi.demo10_Peptides;
public class Person {
//喂食的参数给父类的对象
public void feeding(Animal animal){
animal.eat();
}
// public void feeding(Cat cat){
// cat.eat();
// }
// public void feeding(Dog dog){
// dog.eat();
// }
//pig
//public void feeding(Pig pig){
}
package demo09_modi.demo10_Peptides;
public class Test {
public static void main(String[] args) {
Person person = new Person();
Cat cat = new Cat();
person.feeding(cat);
Dog dog = new Dog();
person.feeding(dog);
}
}
- 成员变量访问特点
package demo09_modi.demo11_Peptides;
public class Animal {
public int age=20;
}
package demo09_modi.demo11_Peptides;
public class Cat extends Animal {
public int age=30;
public int sum=50;
}
package demo09_modi.demo11_Peptides;
//父类的引用指向子类的对象
//本质还是父类对象,不能使用子类中的内容
public class Test {
public static void main(String[] args) {
Animal animal=new Cat();//等号左边是Animal的对象,是父类,父类不能用子类里面的东西
System.out.println(animal.age);//20
// System.out.println(animal.sum);找不到sum,父类里面没有变量sum
}
}
- 成员方法访问特点
package demo09_modi.demo12_Peptides;
public class Animal {
public void eat(){
System.out.println("动物吃东西");
}
}
package demo09_modi.demo12_Peptides;
public class Cat extends Animal {
@Override
public void eat() {
System.out.println("吃鱼");
}
public void show(){
System.out.println("猫");
}
}
package demo09_modi.demo12_Peptides;
public class Dog extends Animal {
@Override
public void eat() {
System.out.println("啃骨头");
}
}
package demo09_modi.demo12_Peptides;
// 方法重写:重写父类的方法,子类重写之后, 方法还是父类的(把父类中原本的方法覆盖了)
public class Test {
public static void main(String[] args) {
Animal animal=new Cat();
animal.eat();
// animal.show();//找不到
}
}
- 类型转换
类型转换:等同于之前的(数据类型之间)类型转换
向上转型:
父类的引用指向子类的对象(子类转化为父类)
例如:Animal animal=new Cat();向下转型:
父类的引用转为子类的对象(父类转化为子类)
例如:Cat cat=(Cat)animal;instanceof运算符:用于判断
使用格式:对象 instanceof 类或接口
例如:animal instanceof Cat(判断父类的引用animal是否指向的是子类Cat)
抽象类
抽象类和抽象方法
- 抽象方法格式:没有方法体的方法设置为抽象方法
访问修饰符 abstract 返回值 方法名();- 抽象类:
避免类直接实例化(new创建对象)
访问修饰符 abstract class 类名{}为什么使用抽象?
避免父类直接实例化(没有任何意义)
- 父类中方法的方法体不使用(子类必须重写父类方法)
- 子类必须重写父类中方法(可以不写,不写会出问题)
特点:
- 抽象方法必须在抽象类中,抽象类中可以有实体方法
- 抽象类不能直接实例化(抽象类没有具体实例,实例化没有意义)
- 抽象如何实例化?通过多态的方式,父类的引用指向子类的对象
- 抽象类的子类要么必须重写抽象类中所有抽象方法,要么子类是抽象类
抽象类中的成员特点:
成员变量:
可以有变量,可以有常量
构造方法:
有构造方法但是不能实例化
构造方法用于子类访问父类数据的初始化
成员方法:
可以有抽象方法:子类必须重写父类抽象方法
可以有非抽象(实体)方法:提高代码的复用性
package day10_poly.demo04_ploy;
/*
抽象方法:访问修饰符 abstract 返回值 方法名();
范例:public abstract void eat();
抽象类:访问修饰符 abstract class 类名{}
范例:public abstract class Animal{}
抽象方法必须在抽象类之中
没有方法体的方法,应该设置为抽象方法
*/
public abstract class Animal {
public abstract void eat();//1、解决了父类方法中的方法体从来不使用问题
}
package day10_poly.demo04_ploy;
//2、子类不重写父类方法会报错。必须重写
public class Cat extends Animal {
@Override
public void eat() {
System.out.println("猫吃东西");
}
}
package day10_poly.demo04_ploy;
public class Test {
public static void main(String[] args) {
//3、new出来一个动物(泛指),创建父类对象没有任何意义
// Animal animal = new Animal();再new会报错
}
}
接口
接口就是一种公共的规范标准
,只要符合标准,大家都可以使用
Java中的接口更多的体现在了对行为的抽象
。
格式:
访问修饰符 interface 接口名{}
范例:
public interface AnimalImpl{}
特点:
- 接口不能被实体类继承,只能被实现
- 接口之间可以继承,可以单继承和多继承
- 类实现接口通过implements实现
范例:public class 类名 implements 接口{}
- 接口不能直接实例化(因为接口没有构造,写上构造会报错)
通过多态的形式:接口 接口对象=new 实现类()
//接口没有构造,但是可以通过多态的形式创建接口的对象
AImpl a=new Z();
- 接口的实现类
要么重写接口中的所有抽象方法
要么是抽象类
- 类和接口产生联系
package day10_poly.demo07_poly;
//接口不能被实体类继承,只能被实现
//类实现接口通过implements实现
//范例:public class 类名 implements 接口{}
public abstract class Person implements PersonImpl{//在继承中通常用父类实现接口
private String name;
private int age;
private String sex;
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", sex='" + sex + '\'' +
'}';
}
public Person() {
}
public Person(String name, int age, String sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
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 getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
}
package day10_poly.demo07_poly;
//接口,里面放两个抽象方法
public interface PersonImpl {
public abstract void eat();
public abstract void sleep();
}
package day10_poly.demo07_poly;
//如果父类没有实现接口,这里重写方法会报错。子类也可实现接口
public class Student extends Person {//在继承中通常用父类实现接口
public Student() {
}
public Student(String name, int age, String sex) {
super(name, age, sex);
}
@Override
public void eat() {
System.out.println("学生吃饭");
}
@Override
public void sleep() {
System.out.println("学生睡觉");
}
}
package day10_poly.demo07_poly;
//如果父类没有实现接口,这里重写方法会报错。子类也可实现接口
public class Teacher extends Person {
public Teacher() {
}
public Teacher(String name, int age, String sex) {
super(name, age, sex);
}
@Override
public void eat() {
System.out.println("老师吃饭");
}
@Override
public void sleep() {
System.out.println("老师睡觉");
}
}
接口中的抽象方法写在抽象类中不是也可以吗?为什么要分开?
为了方便管理
属性在抽象父类中
方法(方法重写)在就接口中
- 接口与接口之间产生联系
package day10_poly.demo08_Poly;
//接口之间可以继承,可以单继承和多继承
public interface Cimpl extends BImpl,AImpl{
public abstract void eat02();
}
package day10_poly.demo08_Poly;
//接口中通常只输写抽象方法,访问修饰符和abstract可以省略不写
public interface BImpl {
//接口中没有构造,没有变量、常量
//接口中通常只写抽象方法。public abstract 可以省略不写
void eat02();
}
注意:
接口类中通常只写抽象方法
接口类中的抽象方法可以不用abstract修饰
接口中的方法(非静态方法)默认都是抽象方法
匿名对象/匿名类
package day10_poly.demo09_Poly;
/*
匿名对象格式:
new 构造(参数列表);
注意:只能使用一次
*/
import java.util.Scanner;
public class Test {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
//创建了对象,就可以多次使用
scanner.nextInt();
scanner.nextInt();
scanner.nextInt();
//如果需求只需要接收一次,以下方式就可以了,这就是匿名对象
new Scanner(System.in).nextInt();
}
}
- 匿名类
package day10_poly.demo09_Poly;
/*
格式:
new 接口或父类{
方法重写
}
注意:只能使用一次,匿名类的前提就是多态
*/
public class Animal {
public void eat(){
System.out.println("");
}
}
package day10_poly.demo09_Poly;
public class Cat extends Animal {
@Override
public void eat() {
System.out.println("猫吃东西");
}
}
package day10_poly.demo09_Poly;
public class Dog extends Animal {
@Override
public void eat() {
System.out.println("狗吃东西");
}
}
package day10_poly.demo09_Poly;
// 人去逛动物园,给动物园里的动物喂食
public class Person {
// public void eat(){
// Cat cat = new Cat();
// cat.eat();
// }//
public void eat00(){
Dog dog = new Dog();
dog.eat();
}
public void eat01(){
//匿名类:首要条件就是多态
Animal animal=new Animal(){
@Override
public void eat() {
System.out.println("不知道名字的动物吃东西");
}
};
}
}
异常
异常:程序出现的错误
- Throwable:
- Error:表示系统出现错误,不能及时处理
- Exception:程序出现错误,可以及时处理,并使程序恢复正常
- RunTimeException:运行错误
- 非RunTimeException:编译错误
异常处理:java默认出现问题,及时进行抛出并停止当前程序的运行。但是对于一个程序来说,某一块代码出现问题,不应该去影响其他代码的执行
- try catch
package day10_poly.demo10_Exception;
/*
格式:
try{
可能出现异常的代码
}catch(异常类 变量名){
处理异常的代码
}
执行流程:
程序从try开始执行,之后执行try中的代码
如果出现异常,会生成一个异常类,然后交给catch中去匹配,匹配成功执行处理异常的代码,
匹配失败程序报错
如果没有出现异常,catch不会执行
注意:
catch可以有多个
try当中的代码,只能捕获第一个错误
*/
public class Demo02 {
public static void main(String[] args) {
System.out.println("开始");
try{
System.out.println("String".charAt(20));//ArithmeticException
System.out.println(5/0);//ArithmeticException
}catch(Exception e){
System.out.println("出现了错误1");
}
System.out.println("结束");
}
}
- try-catch-finally
package day10_poly.demo10_Exception;
/*
try{
可能出现异常的代码
}catch(异常类 变量名){
处理异常的代码
}finally{
代码
}
执行流程:
程序从try开始执行,之后执行try中的代码
如果出现异常,会生成一个异常类,然后交给catch中去匹配,
匹配成功执行处理异常的代码再执行finally中代码;匹配失败程序报错,finally也会执行
如果没有出现异常,catch不会执行,finally中代码也会执行
注意:finally中的代码 无论是否出现异常都会执行
*/
public class Demo03 {
public static void main(String[] args) {
System.out.println("开始");
try{
System.out.println("String".charAt(20));
}catch (ArithmeticException e){
System.out.println("错误");
}finally {
System.out.println("finally");
}
System.out.println("结束");
}
}
- 捕获异常
package day10_poly.demo10_Exception;
/*
public String getMessage() 返回可输出的简短描述
public String toString() 返回异常的详细信息
public void printStackTrace() 把异常信息输出到控制台
*/
public class Demo04 {
public static void main(String[] args) {
System.out.println("开始");
try{
System.out.println(5/0);
}catch (Exception e){
// System.out.println(e.getMessage());
// System.out.println(e.toString());
e.printStackTrace();
}
System.out.println("结束");
// System.err.println("结束01");打印红色字体
}
}
- throws
package day10_poly.demo10_Exception;
/*
格式:
throws 异常类
注意:throws是写在方法之后的
范例:public void test() throws Exception{}
throws只是进行了抛出,抛出之后也需要进行处理
谁调用这个方法谁去处理
处理方式两种 1.try-catch 2.也抛出
注意:可以手动指定一个不存在的异常进行抛出
*/
//try-catch可能捕获异常也可能没有异常
//throws表示抛出一个异常
public class Demo05 {
public static void main(String[] args) throws Exception{
// jsq(2,"*",2);
jsq(5,"/",1);
}
public static void jsq(int a,String f,int b)throws Exception{
switch (f){
case "*":
System.out.println(a*b);
break;
case "/":
System.out.println(a/b);
break;
}
}
}
- 自定义异常
package day10_poly.demo11_Exception;
public class Student {
private int age;//1-120
public int getAge() {
return age;
}
//赋值范围超出1-120,逻辑上有错误
//自定义异常:java虽然提供了一些异常类,不能满足所有的需求
public void setAge(int age) {
if(age<1 ||age>120){
//控制台弹出StudentAgeException
throw new StudentAgeException("超出1-120");
}else {
this.age=age;
}
}
}
/*
throw:在当前位置输出一个异常
格式:在方法中
throw new 异常类(参数列表);
package day10_poly.demo11_Exception;
//定义一个异常类
/*
自定义异常:java虽然提供了一些异常类,不能满足所有的需求
格式:访问修饰符 class 类名 extends 异常的父类(Exception\RunntimeException...){
无参构造
有参构造
}
*/
public class StudentAgeException extends RuntimeException {
public StudentAgeException(){
super();
}
public StudentAgeException(String s){
super(s);
}
}
package day10_poly.demo11_Exception;
public class Test {
public static void main(String[] args) {
System.out.println("开始");
Student student = new Student();
student.setAge(200);
System.out.println("结束");
}
}
throws throw
用在方法声明后,跟的是异常类 用在方法内,跟的是异常对象
表示抛出异常,由调用的调用者处理 表示抛出异常,由当前方法处理
表示出现异常的可能性,不一定会出现 肯定抛出异常
Object
Object:是类层次的的顶级父类,每个类都可以将Object作为超类,所有的类都直接或间接继承该类。
它只有一个无参构造 public Object(){}。
在之前的面向对象中,子类继承父类时,子类构造中默认调用父类的无参构造,因为它们最顶级父类Object只有无参构造。
为什么打印ArrayList不是一个地址值?
ArrayList重写了父类Object中的toString方法。
equals只能用作判断String类型的内容是否相同
注意:使用equals时,对象值不能为null
集合
- 集合:一个长度的可变的存储模型
- Collection单列
- List可重复
- ArrayList
- LinkedList
- Set不可重复
- HashSet
- TreeSet
- List可重复
- Map双列
- HashMap
- Collection单列
Collection,Map,List,Set 都是接口
ArrayList,LenkedList,HashSet,TreeSet,HashMap都是实体类
- ArrayList
package day11_Coll.demo04_arrayList;
//ArrayList分组聚合
import java.util.ArrayList;
public class Demo {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("c");
list.add("d");
list.add("a");
list.add("a");
list.add("b");
list.add("c");
list.add("a");
list.add("b");
list.add("c");
list.add("a");
list.add("b");
list.add("c");
list.add("b");
list.add("c");
list.add("d");
list.add("b");
list.add("c");
list.add("d");
list.add("b");
list.add("c");
list.add("d");
System.out.println(list);
ArrayList<String> group = new ArrayList<>();//创建空集合存储分组
for (int i = 0; i < list.size(); i++) {
if(!group.contains(list.get(i))){//判断是否不存在
group.add(list.get(i));//不存在就添加
}
}
//聚合
for (int i = 0; i < group.size(); i++) {
int sum=0;
for (int j = 0; j < list.size(); j++) {//
if(group.get(i).equals(list.get(j))){//
sum++;
}
}
System.out.println(group.get(i)+":"+sum);
}
//a:5
//b:7
//c:7
//d:7
}
}
- Collection
package day11_Coll.demo05_Collection;
/*
Collection:单列最顶级的接口
使用方式:
多态
更具体的实现类ArrayList或LenkedList
常用方法:
boolean add(E e); 添加元素
boolean remove(Object o) 从集合中移除指定元素
void clear() 清空集合中的元素
boolean contains(Object o) 判断集合中是否存在指定元素
boolean isEmpty() 判断集合是否为空
int size() 集合的长度,集合中的元素个数
*/
import java.util.ArrayList;
import java.util.Collection;
public class Demo01_Collectiom {
public static void main(String[] args) {
Collection<String> collection = new ArrayList<>();
// System.out.println(collection);
collection.add("abc");
collection.add("def");
collection.add("ghr");
// System.out.println(collection);
//删除
// collection.remove("abc");
//清空集合中的元素
// collection.clear();
// System.out.println(collection.contains("abcqwe"));
// collection.clear();
// System.out.println(collection.isEmpty());
// System.out.println(collection);
// for (int i = 0; i <collection.size() ; i++) {
// collection.get();
// }
}
}
- Iterator
package day11_Coll.demo05_Collection;
/*
迭代器:集合专用的遍历方式
为什么使用迭代器?
因为有些集合使用for循环不能遍历。因为没有get方法
使用:
集合提供了itertaor()方法:获取集合中的元素
然后while()循环,判断条件为itertaor对象调用hasNext()
获取元素itertaor对象调用next()
注意:next()表示取出一个元素,取一个少一个
*/
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
/*
Iterator:迭代器,集合的专用遍历方式
Iterator<E> iterator():返回此集合中的元素,通过集合中的iterator()方法得到
Iterator中的常用方法:
E next():返回迭代器中下一个元素
boolean hasNext():如果迭代器中具有更多的元素,返回true
*/
public class Demo02_Iterator {
public static void main(String[] args) {
Collection<Integer> coll = new ArrayList<>();
coll.add(1);
coll.add(2);
coll.add(3);
coll.add(4);
coll.add(5);
Iterator<Integer> iterator = coll.iterator();
// System.out.println(iterator.hasNext());
// System.out.println(iterator.next());
// System.out.println(iterator.hasNext());
// System.out.println(iterator.next());
// System.out.println(iterator.hasNext());
// System.out.println(iterator.next());
// System.out.println(iterator.hasNext());
// System.out.println(iterator.next());
// System.out.println(iterator.hasNext());
// System.out.println(iterator.next());
// System.out.println(iterator.hasNext());
// System.out.println(iterator.next());
while (iterator.hasNext()){
System.out.println(iterator.next());
}
}
}
- List
package day11_Coll.demo06_List;
/*
List:有序集合(序列):可以精准的控制元素的插入位置,可以通过索引来访问元素
特点:
有序:存储和取出的元素顺序一样
可重复:存储的元素可以重复
独有方法:
boolean add(int index,E element); 在集合中指定位置插入元素
E remove(int index) 删除指定元素,并返回删除元素
E get(int index) 返回指定位置的元素
E set(int index,E element) 修改指定元素,并返回被修改元素
*/
import java.util.ArrayList;
import java.util.List;
/*
boolean add(int index,E element); 在集合中指定位置插入元素
E remove(int index) 删除指定元素,并返回删除元素
E get(int index) 返回指定位置的元素
E set(int index,E element) 修改指定元素,并返回被修改元素
*/
public class Demo01_List {
public static void main(String[] args) {
List<Integer> list=new ArrayList<>();
System.out.println(list);
list.add(1);
list.add(2);
list.add(3);
System.out.println(list);
//最大下标为原始下标最大值加1
list.add(3,4);
//下标范围为原始下标范围之内
list.remove(3);
System.out.println(list);
System.out.println(list.get(1));
System.out.println(list.set(1,20));
System.out.println(list);
}
}
- 增强for
package day11_Coll.demo06_List;
/*
增强for:内部封装了一个迭代器
格式:
for(元素数据类型 变量名称:对象){
操作
}
*/
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/*
for(Integer i:list){
//代码体直接使用变量即可
}
*/
public class Demo02_List {
public static void main(String[] args) {
List<Integer> list=new ArrayList<>();
list.add(1);
list.add(2);
list.add(2);
list.add(2);
list.add(2);
list.add(2);
list.add(3);
list.add(2);
list.add(2);
list.add(3);
list.add(2);
// Iterator<Integer> iterator = list.iterator();
// while (iterator.hasNext()){
// Integer next = iterator.next();
// if(next==2){
// list.set();
// }
// }
//将2 改为 20
for (int i = 0; i < list.size(); i++) {
Integer integer = list.get(i);
if(integer==2){
list.set(i,20);
}
}
System.out.println(list);
System.out.println("=================");
//增强for
for(Integer i:list){
System.out.println(i);
}
for (Integer integer : list) {
System.out.println(integer);
}
}
}
- LinkedList:结构为双链表的存储模型
package day11_Coll.demo06_List;
import java.util.LinkedList;
import java.util.List;
/*
LinkedList: 结构为双链表的存储模型
独有方法:
void addFirst(E e) 在列表开头插入指定元素
void addLast(E e) 在列表末尾追加指定元素
E getFirst() 返回列表第一个元素
E getLast() 返回列表末尾元素
E removeFirst() 移除第一个元素并返回
E removeLast() 移除末尾元并返回
*/
public class Demo03_LinkedList {
public static void main(String[] args) {
LinkedList<Integer> list=new LinkedList<>();
list.add(1);
list.add(2);
list.add(3);
System.out.println(list);
list.addFirst(0);
list.addLast(4);
System.out.println(list);
System.out.println(list.getFirst());
System.out.println(list.getLast());
list.removeFirst();
list.removeLast();
System.out.println(list);
}
}
ArrayList 和 LinkeList 的优缺点:
- ArrayList 数组结构:
数组
是一种查询快,增删慢
的模型
查询快:查询数据通过索引定位,查询任意数据耗时相同
删除慢:删除元素时,要将原始数据删除,同时元素进行前移
添加慢:添加元素时,要在添加位置的每一个数据进行后移,再添加元素 - LinkedList 链表结构:
链表
是一种增删快,查询慢
的模型
增删快:增加和删除时,只需要修改下一个地址指向,耗时相同
查询慢:查询数据时,都需要从头开始查询
/*
Set 概述:
1、不包含重复元素
2、Set集合没有索引方法,不能使用for循环遍历
3、不能保证存储和取出的顺序一致
*/
package demo;
import java.util.HashSet;
public class Demo2 {
public static void main(String[] args) {
HashSet<String> hs = new HashSet<>();
hs.add("hello");
hs.add("world");
hs.add("java");
hs.add("python");
hs.add("python");
System.out.println(hs); //[python, world, java, hello]
}
}
哈希值:
- 根据对象的
地址值
或字符串
或数字
计算得到的 int 类型的数值 - 通过 public void hashCode() :返回对象的哈希值
package day11_Coll.demo06_Set;
/*
HashSet
概述:
由哈希表(实际为HashMap实例)支持。 对集合的迭代次序不作任何保证
特点:
底层数据结构是哈希表(元素为链表的数组)
对集合的迭代顺序不进行任何保证,就是存储和取出的顺序不一定相同
没有带索引的方法,不能使用for循环遍历
继承Set集合,元素不能重复
*/
//public void hasCode():返回对象的哈希值
public class Demo02_HashCode {
public static void main(String[] args) {
String s1="hello";
String s2="world";
String s3="通话";
String s4="重地";
String s5="hello";
//同一个对象多次调用hasCode()方法返回的哈希值是相同的
//默认情况下,不同对象的的哈希值是不同的,通过重写hasCode(),可以实现让不同对象的哈希值相同
System.out.println(s5.hashCode());//99162322
System.out.println(s1.hashCode());//99162322
System.out.println(s2.hashCode());//113318802
System.out.println(s3.hashCode());//1179395
System.out.println(s4.hashCode());//1179395
System.out.println(99162322%16);//2
System.out.println(113318802%16);//2
System.out.println(1179395%16);//3
}
}
package day11_Coll.demo06_Set;
//分组聚合
import java.util.ArrayList;
import java.util.HashSet;
public class Demo03_Test {
public static void main(String[] args) {
ArrayList<Integer> integers = new ArrayList<>();
integers.add(1);
integers.add(2);
integers.add(2);
integers.add(3);
integers.add(1);
integers.add(2);
integers.add(2);
integers.add(2);
integers.add(2);
integers.add(3);
//分组 HashSet不重复
HashSet<Integer> hashSet = new HashSet<>();
for (Integer integer : integers) {
hashSet.add(integer); //ArrayList里的数据添加到hashset里自动去重
}
for (Integer integer : hashSet) {//遍历HashSet
int sum=0;
for (Integer integer1 : integers) {//原始数据
if(integer==integer1){
sum++;
}
}
System.out.println(integer+":"+sum);
}
}
}
- TreeSet
package demo;
/*
TreeSet:元素有序,不是存储或取出有序,而是按照一定的规则进行排序,排序方式取决于构造方法
TreeSet():根据元素的自然排序进行排序
TreeSet(Comparator comparator):根据指定的比较器比较
特点:
元素有序
没有索引,不能进行for循环遍历
不能重复
*/
public class Demo4 {
public static void main(String[] args) {
//自然排序:无什么样的数据都是转化为数字进行排序
//1-10 a-z(98-104)
//张z 李l
char c='四';
int i=c;
System.out.println(i);//22235
char c1='三';
int i1=c1;
System.out.println(i1);//19977
int lim = Math.min("李四".length(), "张三".length());
System.out.println(lim);
TreeSet treeSet = new TreeSet();
treeSet.add("a");
treeSet.add("z");
treeSet.add("d");
treeSet.add("c");
System.out.println(treeSet);//[a,c,d,z]
}
}
- Comparable
package day12_Coll.Demo02;
/*
自然排序:按照数字进行从小到大的排序方式
TreeSet中默认包含自然排序,自定义的类需要实现Comparable接口(自然排序接口),然后重写ComareTo()自然排序方法
ComareTo()返回值:
1:0 表示数据相同(不添加)
2:正数 表示新添加的数据大于已存在的数据,升序
3:负数 表示新添加的数据小于已存在的数据,降序
*/
public class Student implements Comparable{
@Override
public int compareTo(Object o) {
return -1;
//返回值为0 表示相同
//返回值为整数 表示插入的大于原本的数据,正序
//返回值为负数 表示倒序
}
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;
}
}
package day12_Coll.Demo02;
import java.util.TreeSet;
/*
day12_Coll.Demo02.Student cannot be cast to java.lang.Comparable
*/
public class Test {
public static void main(String[] args) {
Student zs = new Student("张三", 28);
Student ls = new Student("李四", 30);
Student ww = new Student("王五", 32);
TreeSet<Student> treeSet = new TreeSet<>();
treeSet.add(zs);
treeSet.add(ls);
treeSet.add(ww);
for (Student student : treeSet) {
System.out.println(student.getName());
}
}
}
- 按照年龄从小到大排序
package day12_Coll.Demo03_Comparable;
/*
注意: 当一个实现Comparable接口之后,参与比较的对象有this和参数o
this表示插入的数据
o表示已存在的数据
String中已存在自然排序,可以直接调用
*/
public class Student implements Comparable<Student>{
@Override
public int compareTo(Student o) {
// int age = this.age;//插入数据
// int age1 = o.age;//已插入的数据
// System.out.println(age);//30 新插入的李四
// System.out.println(age1);
int sum=this.age-o.age;//2
System.out.println(sum);
return sum;
}
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;
}
}
package day12_Coll.Demo03_Comparable;
import java.util.TreeSet;
/*
day12_Coll.Demo02.Student cannot be cast to java.lang.Comparable
*/
public class Test {
public static void main(String[] args) {
Student zs = new Student("张三", 28);
Student ls = new Student("李四", 30);
Student ww = new Student("王五", 29);
TreeSet<Student> treeSet = new TreeSet<>();
treeSet.add(zs);
treeSet.add(ls);
treeSet.add(ww);
for (Student student : treeSet) {
System.out.println(student.getName()+":"+student.getAge());
}
}
}
- 比较器Comparator
package day12_Coll.Demo07_COmparator;
/*
比较器Comparator:其实就是自然排序,只是写法不同称呼不同
使用:需要在TreeSet有参构造中,创建匿名的Comparator的实现类,然后重写compare方法
注意:
compare方法中参数有两个o1和o2
o1表示插入的数据
o2表示已存在的数据
*/
import java.util.Comparator;
import java.util.TreeSet;
//TreeSet(Comparator comparator):根据指定的比较器比较
public class Demo01 {
public static void main(String[] args) {
//当前包下没有实体类实现Comparator接口
//但是TreeSet还需要Comparator接口的实现类
TreeSet<String> strings = new TreeSet<>(new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
// System.out.println(o1);//插入的数据
// System.out.println(o2);//以插入的数据
int sum=o1.compareTo(o2);
return sum;
}
});
strings.add("a");
strings.add("b");
strings.add("z");
strings.add("d");
for (String s : strings) {
System.out.println(s);
}
}
}
- map
map:Interface Map<K,V> K:键的类型 V:值的类型
将键映射到值的对象,不能包含重复的键,每个键可以映射最多一个值
package day12_Coll.Demo11_Map;
import java.util.HashMap;
import java.util.Map;
/*
V put(K key,V value) 添加元素
V remove(Object key) 根据key移除元素
void clear() 清空集合
boolean containsKey(Object key) 判断集合中是否包含指定key
boolean containsValue(Object value) 判断集合中是否包含指定value
boolean isEmpty() 判断集合是否为空
int size() 集合的长度
*/
public class Demo01 {
public static void main(String[] args) {
//创建对象:
//1、通过多态的形式
//2、通过具体的实现类HashMap
Map<String,String> map=new HashMap<String,String>();
map.put("1001","张三");
map.put("1002","李四");
map.put("1003","王五");
// map.put("1001","zs"); //k重复覆盖原有数据。put可以做添加,也可以做修改
map.put("1004","李四");
System.out.println(map);
//remove移除并返回移除的元素
// String remove = map.remove("1004");
// System.out.println(remove);
System.out.println(map.containsKey("1009"));
System.out.println(map.containsValue("李四"));
System.out.println(map);
}
}
package day12_Coll.Demo11_Map;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/* map的获取方法:
V get(Object key) 根据key获取value
Set<K> keySet() 获取所有key的集合
Collection<V> values() 获取所有value的集合
Set<Map.Entry<K,V>> entrySet() 获取所有KV的集合
*/
public class Demo02 {
public static void main(String[] args) {
Map<String,String> map=new HashMap<String,String>();
map.put("1001","张三");
map.put("1002","李四");
map.put("1003","王五");
map.put("1004","李四");
//get不存在返回null
// System.out.println(map.get("1005"));
// System.out.println(map.keySet());
// System.out.println(map.values());
Set<Map.Entry<String, String>> entries = map.entrySet();
System.out.println(map);//大括号括住{}
System.out.println(entries);//中括号括住[]
}
}
package day12_Coll.Demo11_Map;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/*
map的两种遍历方式:
1.首先获取key的集合,然后遍历通过key获取value
例如:Set<String> set=map.keySet();
for(String s:set){
sout(s+":"+map.get(s));
}
2.直接获取KV集合然后遍历获取
例如:
Set<Map.Entry<String, String>> entries = map.entrySet();
for (Map.Entry<String, String> entry : entries) {
System.out.println(entry.getKey()+":"+entry.getValue());
}
*/
public class Demo03 {
public static void main(String[] args) {
Map<String,String> map=new HashMap<String,String>();
map.put("1001","张三");
map.put("1002","李四");
map.put("1003","王五");
map.put("1004","李四");
//方式1:
// Set<String> strings = map.keySet();
// for (String s : strings) {
// System.out.println(s+":"+map.get(s));
// }
// Collection<String> values = map.values();
// for (String s : values) {
// System.out.println(s);
// }
//方式2:
Set<Map.Entry<String, String>> entries = map.entrySet();
for (Map.Entry<String, String> entry : entries) {
System.out.println(entry.getKey()+":"+entry.getValue());
}
}
}
- 分组聚合
package day12_Coll.Demo11_Map;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
public class Demo04 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("c");
list.add("d");
list.add("a");
list.add("a");
list.add("a");
list.add("b");
list.add("b");
list.add("c");
list.add("d");
list.add("a");
list.add("a");
list.add("a");
list.add("b");
list.add("b");
list.add("c");
list.add("d");
list.add("a");
list.add("a");
list.add("a");
list.add("b");
list.add("b");
list.add("c");
list.add("d");
list.add("a");
list.add("a");
list.add("a");
list.add("b");
list.add("b");
list.add("c");
list.add("d");
list.add("a");
list.add("a");
list.add("a");
list.add("b");
list.add("b");
list.add("c");
list.add("d");
HashMap<String, Integer> map = new HashMap<>();//接受最终结果
HashSet<String> group = new HashSet<>();//分组
for (String s : list) {
group.add(s);
}
for (String s : group) {//循环分组
int sum=0;
for (String s1 : list) {//循环数据
if(s==s1){
sum++;
}
}
map.put(s,sum);
}
System.out.println(map);
}
}
package day12_Coll.Demo11_Map;
//不使用HashSet分组,直接用 hashmap
import java.util.ArrayList;
import java.util.HashMap;
public class Demo05 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("c");
list.add("d");
list.add("a");
list.add("a");
list.add("a");
list.add("b");
list.add("b");
list.add("c");
list.add("d");
list.add("a");
list.add("a");
list.add("a");
list.add("b");
list.add("b");
list.add("c");
list.add("d");
list.add("a");
list.add("a");
list.add("a");
list.add("b");
list.add("b");
list.add("c");
list.add("d");
list.add("a");
list.add("a");
list.add("a");
list.add("b");
list.add("b");
list.add("c");
list.add("d");
list.add("a");
list.add("a");
list.add("a");
list.add("b");
list.add("b");
list.add("c");
list.add("d");
HashMap<String, Integer> map = new HashMap<>();//接受最终结果
// 方式1
// //分组 KV
// for (String s : list) {
// map.put(s,0);
// }
// //聚合
// for (String s : list) {
// if(map.containsKey(s)){//d
// map.put(s,map.get(s)+1);
// }
// }
//更简单的方式2
//分组和聚合写到一个循环之中
//
for (String s : list) {
//以数据作为k来判断在map是否存在key
if(map.containsKey(s)){
//如果存在进行累加,在原本的V上进行加1
map.put(s,map.get(s)+1);
}else {//如果不存在,出现第一个,添加的map中s作为k,1作为v
map.put(s,1);
}
}
System.out.println(map);
}
}
泛型
泛型:提供了编译时的类型安全监测机制
也可以叫参数类型化,由具体使用/调用时决定具体的数据类型
可以使用在类,接口,方法,变量;成为泛型类,泛型接口,泛型方法
package day12_Coll.Demo09_Coll;
import java.util.ArrayList;
public class Demo01 {
public static void main(String[] args) {
//提供了编译时类型安全监测机制,允许在编译时检测到非法类型
//存储String类型的数据
ArrayList<String> list = new ArrayList<>();
list.add("string");
// list.add(20);
}
}
- 泛型方法
package day12_Coll.Demo09_Coll;
/*
泛型方法格式:
访问修饰符 <泛型> 返回值 方法名称(泛型 变量名)
范例:
public <T> void show(T t)
注意:这里的T是一个标识,可以为任意标识,常见的如K V T E等用于表示泛型
*/
public class Demo02 {
public static void main(String[] args) {
show(10.5);
show(true);
}
//权限访问修饰符 static <泛型标识> void 方法名(泛型标识 变量){}
public static <V> void show(V v){
System.out.println(v);
}
// public static void show(String s){//输出字符串
// System.out.println(s);
// }
// public static void show(int i){//输出int
// System.out.println(i);
// }
// public static void show(boolean bool){//输出boolean
// System.out.println(bool);
// }
// public static void show(double d){//需求又增加了一个
// System.out.println(d);
// }
}
- 泛型类
package day12_Coll.Demo09_Coll;
/*
格式:
访问修饰符 class 类名<类型>{}
范例:
public class Student<T>
注意:这里的T是一个标识,可以为任意标识,常见的如K V T E等用于表示泛型
泛型类中的 成员变量或者成员方法 也加上了泛型(前提条件:使用的是类上的泛型)
成员变量或者成员方法上的泛型和泛型类保持一致
*/
public class Demo03<T> {
public void show(){
System.out.println("show");
}
public <E> void test(E e){
}
}
package day12_Coll.Demo09_Coll;
public class Demo03_Test {
public static void main(String[] args) {
Demo03<String> stringDemo03 = new Demo03<>();
stringDemo03.test("abc");
// stringDemo03.test(10);也不会报错,因为就近原则,泛型方法上也定义了一个泛型
}
}
- 泛型接口
package day12_Coll.Demo09_Coll;
/*泛型接口格式:
权限访问修饰符 interface 类名<泛型标识>{}
*/
public interface Demo04_Impl<T> {
void show(T t);
<E> void test(E e);
}
- 泛型变量
package day12_Coll.Demo09_Coll;
/*
格式:
权限访问修饰符 泛型表示 变量名;
*/
public class Demo05<T> {
public T name;
}
//注意:泛型修饰变量需在泛型类之下
使用泛型方法,需要注意泛型方法上的泛型标识是否和泛型类上的泛型标识保持一致
泛型标识T,只是一个标识符,可以是任意字母,常用K,V,T,E标识泛型
- 可变参数
package day12_Coll.Demo10_Coll;
import java.util.ArrayList;
//可变参数
public class Demo {
public static void main(String[] args) {
show(10,20);
show(10,20,30);
show(10,20,30,40);
ArrayList<Integer> integers = new ArrayList<>();
integers.add(10);
integers.add(20);
integers.add(30);
show(integers);
}
public static void show(int a,int b){//两个值的和
System.out.println(a+b);
}
public static void show(int a,int b,int c){//三个值的和
System.out.println(a+b+c);
}
public static void show(int a,int b,int c,int d){//四个值的和
System.out.println(a+b+c+d);
}
public static void show(ArrayList<Integer> list){
int sum=0;
for (Integer integer : list) {
sum+=integer;
}
System.out.println(sum);
}
}
package day12_Coll.Demo10_Coll;
/*
概述:
可变参数就是方法的参数个数可以发生变化
格式:修饰符 返回值类型 方法名(数据类型...变量名){}
范例:public static void sum(int...i)
*/
//可变参数本质就是数组
//可变参数只能放在参数列表中的最后
//可变参数只能有一个
public class Test {
public static void main(String[] args) {
show(10,20);
show(10,20,30);
//一个变量ints=七个int类型的数据
show(10,20,30,40,50,60,70);
}
public static void show(int...ints){
int sum=0;
for (int i : ints) {//数组遍历,增强for
sum+=i;
}
System.out.println(sum);
}
}
IO(File)
IO:Input OutPut 流
File:文件和目录的抽象
- 文件和目录可以通过File封装成对象;
- 对于File,其封装的并不是一个真正的文件,只是文件的路径,
可存在可不存在
,之后通过具体的操作把这个路径转化为具体的存在
package day13_IO.demo01_File;
import java.io.File;
/*构造:
File(String pathname) 通过将给定的路径名字符串转换为抽象路径名来创建新的 File实例。
File(String parent, String child) 从父路径名字符串和子路径名字符串创建新的 File实例。
File(File parent, String child) 从父抽象路径名和子路径名字符串创建新的 File实例。
*/
public class Demo01 {
public static void main(String[] args) {
// File file = new File("E:\\IdeaFile\\BigData\\score\\Test01.txt");
// System.out.println(file);
//E:\\IdeaFile\\BigData\\score +Test.txt
// File file = new File("E:\\IdeaFile\\BigData", "score\\Test.txt");
// System.out.println(file);
File file = new File("E:\\IdeaFile\\BigData");
File file1 = new File(file, "score\\Test.txt");
System.out.println(file1);
//E:\IdeaFile\BigData\score\next.txt
// System.out.println("E:\IdeaFile\BigData\score\next.txt");
}
}
//抽象路径:不从盘符开始,从当前项目开始
//绝对路径:从盘符开始
package day13_IO.demo01_File;
import java.io.File;
import java.io.IOException;
/* 操作
public boolean createNewFile() 当且仅当具有该名称的文件尚不存在时,原子地创建一个由该抽象路径名命名的新的空文件。
public boolean mkdir() 创建由此抽象路径名命名的目录
public boolean mkdirs() 创建由此抽象路径名命名的目录,包括任何必需但不存在的父目录。
*/
public class Demo02 {
public static void main(String[] args) throws IOException {
//创建文件 创建的都是空白,存在不创建
File file = new File("E:\\IdeaFile\\BigData\\score\\Test01.txt");
//file常见操作
boolean newFile = file.createNewFile();这个方法有异常抛出
System.out.println(newFile);
//创建目录
File file = new File("E:\\IdeaFile\\BigData\\score\\score01");
boolean mkdir = file.mkdir();
System.out.println(mkdir);
// File file = new File("E:\\IdeaFile\\BigData\\score\\score03");
// System.out.println(file.mkdirs());
File file = new File("E:\\IdeaFile\\BigData\\score\\demo");
boolean newFile = file.createNewFile();
System.out.println(newFile);
}
}
package day13_IO.demo01_File;
import java.io.File;
import java.io.IOException;
/*
public boolean isDirectory() 判断抽象路径是否为目录
public boolean isFile() 判断抽象路径是否为文件
public boolean exists() 判断抽象路径是否存在
public String getAbsolutePath() 返回抽象路径的绝对路径字符串
public String getPath() 返回抽象路径的路径字符串
public String getName() 返回抽象路径表示路径或文件的名称
publci String[] list() 返回抽象路径(路径只能是目录)表示目录下的目录和文件的名称
public File[] listFile() 返回抽象路径(路径只能是目录)表示目录下的目录和文件的对象
(返回结果带路径了)
public boolean delete() 删除抽象路径表示的文件或目录
注意:删除只能删除空目录
*/
public class Demo03 {
public static void main(String[] args) throws IOException {
// File file = new File("E:\\IdeaFile\\BigData\\score");
// System.out.println(file.isDirectory());
// File file = new File("E:\\IdeaFile\\BigData\\score","Test0.txt");
// System.out.println(file.isFile());
// System.out.println(file.exists());
//public String getAbsolutePath() 返回抽象路径的绝对路径字符串
//public String getPath() 返回抽象路径的路径字符串(从当前项目下开始查找)
// File file = new File("E:\\IdeaFile\\BigData\\score\\Test02.txt");
// System.out.println(file.getAbsolutePath());
// System.out.println(file.getPath());
// File file1 = new File("score\\Test03.txt");
// System.out.println(file1.getAbsolutePath());
// System.out.println(file1.getPath());
//publci String[] list() 返回抽象路径表示目录下的目录和文件的名称
// public File[] listFile() 返回抽象路径表示目录下的目录和文件的对象
// File file = new File("E:\\IdeaFile\\BigData\\score\\next.txt");
// String[] list = file.list();
// for (String s : list) {
// System.out.println(s);
// }
File file = new File("E:\\IdeaFile\\BigData\\score");
File[] files = file.listFiles();
for (File file1 : files) {
System.out.println(file1.getName());
}
File file = new File("E:\\IdeaFile\\BigData\\data\\demo");
System.out.println(file.delete());
}
}
- 找出文件后缀是 .java 的文件
package day13_IO.demo01_File;
import java.io.File;
public class Demo04 {
public static void main(String[] args) {
File file = new File("E:\\IdeaFile\\BigData\\score\\test.java");
String name = file.getName();
boolean b = name.endsWith(".java");//自动识别字符串内容
System.out.println(b);//true
System.out.println("=================");
//score目录下全是文件
File file = new File("E:\\IdeaFile\\BigData\\score");
String[] files = file.list();
for (String s : files) {
boolean b = s.endsWith(".java");
if(b){
System.out.println(s);
}
}
}
}
package day13_IO.demo01_File;
//score目录下有目录有文件
import java.io.File;
public class Demo05 {
public static void main(String[] args) {
File file = new File("E:\\IdeaFile\\BigData\\score");
File[] files = file.listFiles();
for (File file1 : files) {
if(file1.isFile()){
if(file1.getName().endsWith(".java")){
System.out.println(file1.getName());
}
}else {//如果是目录。就再判断目录里面的内容
File[] files1 = file1.listFiles();
for (File file2 : files1) {
if(file2.getName().endsWith(".java")){
System.out.println(file2.getName());
}
}
}
}
}
}
- 获取data目录下所有文件
package day13_IO.demo01_File;
import java.io.File;
//获取data目录下所有文件
public class Demo06 {
public static void main(String[] args) {
File file = new File("E:\\IdeaFile\\BigData\\data");//把data目录封装成file对象
/*
获取当前data下所有对象,对象中
有文件:输出
有目录:进入目录中,然后获取对象
*/
File[] files = file.listFiles();//获取当前data下所有对象(data下有目录)
for (File file1 : files) {
if(file1.isFile()){//判断是否是文件
System.out.println(file1.getName());
}else {//否则就是目录
File[] files1 = file1.listFiles();//获取当前demo下所有对象(demo下有目录)
for (File file2 : files1) {
if(file2.isFile()){
System.out.println(file2.getName());
}else {
File[] files2 = file2.listFiles();//获取当前demo1下所有对象(只有文件)
for (File file3 : files2) {
System.out.println(file3.getName());
}
}
}
}
}
}
}
- 递归:用于解决多层次的类似问题
本质:方法调用方法本身
package day13_IO.demo01_File;
//使用递归
import java.io.File;
public class Demo07 {
public static void main(String[] args) {
File file = new File("E:\\IdeaFile\\BigData\\data");
show(file);
}
public static void show(File file){//从data开始
File[] files = file.listFiles();
for (File file1 : files) {
if(file1.isFile()){
System.out.println(file1.getName());
}else {
show(file1);//参数是file1
}
}
}
}
package day13_IO.demo01_File;
//获取目录下的对象,然后查找出文件后缀是 .java 的文件
import java.io.File;
public class Demo08 {
public static void main(String[] args) {
File file = new File("E:\\IdeaFile\\BigData\\data");
show(file);
}
public static void show(File file){
//获取当前file对象下的所有对象
File[] files = file.listFiles();
//循环获取一个一个对象
for (File file1 : files) {
//然后判断是文件还是目录
if(file1.isFile()){
String name = file1.getName();
if(name.endsWith(".java")){
System.out.println(name);
}
}else {//否则就是目录,开始下一次递归(从新调用方法)
show(file1);
}
}
}
}
- 递归删除
package day13_IO.demo01_File;
import java.io.File;
public class Demo11 {
public static void main(String[] args) {
File file = new File("E:\\IdeaFile\\BigData\\data\\demo");
show(file);
}
public static void show(File file){
//获取当前file下所有对象
//遍历
//是文件:删除
//是目录:进入
File[] files = file.listFiles();
for (File file1 : files) {
if(file1.isFile()){
file1.delete();
}else {
show(file1);
}
}
file.delete();//for循环是为了删除文件,删除文件后删除目录
}
}
- copy
package day13_IO.demo01_File;
import java.io.File;
import java.io.IOException;
public class Demo12 {
public static void main(String[] args) throws IOException {
File file = new File("E:\\IdeaFile\\BigData\\data");
File newFile = new File("E:\\IdeaFile\\BigData\\copy");
String[] list = file.list();
for (String s : list) {
File file1 = new File(newFile, s);//父路径和子路径
file1.createNewFile();
}
}
}
package day13_IO.demo01_File;
import java.io.File;
import java.io.IOException;
public class Demo13 {
public static void main(String[] args) throws IOException {
File file = new File("E:\\IdeaFile\\BigData\\data");
File newFile = new File("E:\\IdeaFile\\BigData\\copy");
show(file,newFile);
}
//第一次 file=data newFile=copy
//第二次 file=data/demo newFIle=copy/demo
public static void show(File file,File newFile) throws IOException {//复制一个原路径 一个新路径
//循环获取原路径下的对象
File[] files = file.listFiles();
for (File file1 : files) {
if(file1.isFile()){//如果是文件,使用newFIle+文件名 创建新的File 然后调用createNewFile
File file2 = new File(newFile, file1.getName());
file2.createNewFile();
}else {//先复制目录名称
File file2 = new File(newFile, file1.getName());
file2.mkdirs();
show(file1,file2);
}
}
}
}
- 剪切
package day13_IO.demo01_File;
import java.io.File;
import java.io.IOException;
//剪切
public class Demo14 {
public static void main(String[] args) throws IOException {
File file = new File("E:\\IdeaFile\\BigData\\data");
File newFile = new File("E:\\IdeaFile\\BigData\\copy");
show(file,newFile);
}
public static void show(File file,File newFIle) throws IOException {
File[] files = file.listFiles();
for (File file1 : files) {
if(file1.isFile()){
File file2 = new File(newFIle, file1.getName());
file2.createNewFile();
//复制之后就删除
file1.delete();
}else {//如果是目录 先复制目录,然后递归复制内容
File file2 = new File(newFIle, file1.getName());
file2.mkdirs();
show(file1,file2);
}
}
file.delete();
}
}
IO流
IO:输入/输出(input/output)
流:抽象的概念,数据传输的总称
IO流:用来处理设备之间数据传输问题。如文件上传,下载,复制…
硬盘—输入流(读数据)---->内存 内存—输出流(写数据)—>硬盘
分类:
- 通过流向分类:输入流(读数据) 和 输出流(写数据)
- 通过数据类型分类:
- 字节流:字节输入流,字节输出流
- 字符流:字符输入流,字符输出流
- 注意:这两种流该如何使用:通过记事本打开,内容能读懂使用字符流:
读不懂使用字节流。如果不知道使用什么流就只用字节流
字节流抽象父类:
InputStrem
:这个抽象类表示字节输入流
的所有类的父类
OutputStrem
:这个抽象类表示字节输出流
的所有类的父类
FileOutPutStream
:文件字节输出流
(具体的字节输出流实现类)
package day13_IO.demo02_IO;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
/*
//文件输出流是用于将数据写入到输出流File
FileOutPutStream(String name)创建文件字节输出流写入文件
使用步骤:
1.创建对象(1.调用系统创建空文件 2.创建字节输出流对象 3.让对象指向文件)
3.调用写数据的方法(writer())
2.释放资源(关闭文件流并释放与此相关的资源)
*/
//无论是否存在都会创建空白文件
public class Demo01_FileOutPutStream {
public static void main(String[] args) throws Exception {
FileOutputStream fos = new FileOutputStream("E:\\IdeaFile\\BigData\\data\\text.txt");
fos.write(97);//会转化为a写入
fos.close();
}
}
package day13_IO.demo02_IO;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
/*
write(int b) 将指定的字节写入文件,一次写一个字节
write(byte[] b) 将指定的字节数组写入文件,一次写一个字节数组
write(byte[] b,int off,int len) 将指定的字节数组,从偏移量off开始写入文件,一次写len个字节,一次写数组的一部分
*/
public class Demo02_FileOutputStream {
public static void main(String[] args) throws Exception {
//1.创建对象
FileOutputStream fos = new FileOutputStream("E:\\IdeaFile\\BigData\\data\\text.txt");
//写数据方式1 int数据会转化成char写入到文件中
fos.write(98);
fos.write('\n');
fos.write(99);
fos.write('\r');
fos.write(100);
//写数据方式2
byte[] b={97,98,99};
fos.write(b);
//写数据的方式3
//偏移量理解为下标或索引
byte[] b={97,98,99,100,101,102};
fos.write(b,0,5);
//2.关闭资源
fos.close();
}
}
- FileOutputStream(File file)
package day13_IO.demo02_IO;
import java.io.File;
import java.io.FileOutputStream;
/*
FileOutputStream(String name, boolean append)
创建文件输出流以指定的名称写入文件
FileOutputStream(File file)
创建文件输出流以写入由指定的 File对象表示的文件。
FileOutputStream(File file, boolean append)
创建文件输出流以写入由指定的 File对象表示的文件。
//FileOutputStream如果append参数为true表示追加
//FileOutputStream如果append参数没有默认为false表示覆盖
//
*/
public class Demo04_FileOutputStream {
public static void main(String[] args) throws Exception{
FileOutputStream fos = new FileOutputStream(
"E:\\IdeaFile\\BigData\\data\\text.txt");
fos.write(98);
fos.close();
sout("=======================")
//简写:使用了匿名类
// File file = new File("E:\\IdeaFile\\BigData\\data\\text.txt");
FileOutputStream fos = new FileOutputStream(new File("E:\\IdeaFile\\BigData\\data\\text.txt"));
fos.write(100);
fos.close();
}
}
- 输入流 FileInputStream
package day13_IO.demo02_IO;
import java.io.FileInputStream;
/*
FileInputStream(String name)创建文件字节输入流读取文件
使用步骤:
1.创建对象(1.调用系统创建文件2.创建字节输入流对象3.让对象指向文件)
2.调用读数据的方法(read())
3.释放资源(关闭文件流并释放与此相关的资源)
read() 读取一个字节
read(byte[] b) 按照指定的数组读取数据,一地刺那个读取一个字节数组,返回值为读取的数据个数
read(byte[] b,int off,int len) 按照指定的数组读取数据,从偏移量开始进行存储,一次读取len个数据,一次读取数组的一部分
*/
public class Demo05_FileinputStream {
public static void main(String[] args) throws Exception{
FileInputStream fis = new FileInputStream("E:\\IdeaFile\\BigData\\data\\text.txt");
int read = fis.read();
System.out.println(read);
//read(byte[] b) 按照数组长度读取,读取的数据存储在数组中
byte[] b=new byte[5];
int read = fis.read(b);
System.out.println(read);
for (byte b1 : b) {
System.out.println(b1);
}
//read(byte[] b,int off ,int len)
byte[] b=new byte[5];
int read = fis.read(b, 1, 2);
System.out.println(read);
for (byte b1 : b) {
System.out.println(b1);
}
fis.close();
}
}
- 把文件里的数据完整的读出来
package day13_IO.demo02_IO;
import java.io.FileInputStream;
public class Demo06_FileInputStream {
public static void main(String[] args) throws Exception{
FileInputStream fis = new FileInputStream("E:\\IdeaFile\\BigData\\data\\text.txt");//abc
// int read = fis.read();
// System.out.println(read); 97
// int read1 = fis.read();
// System.out.println(read1); 98
// int read2 = fis.read();
// System.out.println(read2); 99
// int read3 = fis.read();
// System.out.println(read3); -1
int i;
while ((i=fis.read())!=-1){
System.out.println(i); // i确保每次循环只读取一次
}
fis.close();
}
}
package day13_IO.demo02_IO;
import java.io.FileInputStream;
public class Demo07_FileInputStream {
public static void main(String[] args) throws Exception{
FileInputStream fis = new FileInputStream("E:\\IdeaFile\\BigData\\data\\text.txt");//abcdefghj12
// byte[] b=new byte[3];
// int read = fis.read(b);
// System.out.println(read); 3
// int read1 = fis.read(b);
// System.out.println(read1); 3
// int read2 = fis.read(b);
// System.out.println(read2); 3
// int read3 = fis.read(b);
// System.out.println(read3); -1
byte[] b=new byte[3];
int i;
while ((i=fis.read(b))!=-1){
//String(byte[] bytes, int offset, int length) :把数组的一部分转String
//防止多次读取数据,下一次的数据会覆盖上一次,下一次读取的数据比上一次少会导致覆盖不全
// 12j
System.out.println(i);
System.out.print(new String(b,0,i)); // i就是数组长度
}
fis.close();
}
}
- 判断文件中有多少行
package day13_IO.demo02_IO;
import java.io.FileInputStream;
public class Demo09_FileInputStream {
public static void main(String[] args) throws Exception{
FileInputStream fis = new FileInputStream("E:\\IdeaFile\\BigData\\data\\text.txt");
int i;
int sum=0;
while ((i=fis.read())!=-1){
// System.out.print((char)i); 将所有数据读出来
char i1 = (char) i;
if(i1=='\n'){
sum++;
}
}
fis.close();
System.out.println(sum);
}
}
- 判断总共打了多少行
package day13_IO.demo02_IO;
import java.io.File;
import java.io.FileInputStream;
//方式1:
public class Demo10_Row {
static int sum=0;
public static void main(String[] args) throws Exception{
File file = new File("E:\\IdeaFile\\BigData\\src");
show(file);
System.out.println(sum);
}
public static void show(File file)throws Exception{
File[] files = file.listFiles();//获取所有对象
//循环判断是文件还是目录
for (File file1 : files) {
if(file1.isFile()){
String name = file1.getName();
if(name.endsWith(".java")){//后缀为.java统计行数
FileInputStream fis = new FileInputStream(file1.getAbsolutePath());
int i;
while ((i=fis.read())!=-1){
if((char)i=='\n'){
sum++;
}
}
fis.close();
}
}else {
show(file1);
}
}
}
}
package day13_IO.demo02_IO;
import java.io.FileInputStream;
//方式2:
public class Demo11_FileInputStream {
public static void main(String[] args) throws Exception{
FileInputStream fis = new FileInputStream("E:\\IdeaFile\\BigData\\data\\text.txt");
byte[] b=new byte[1024]; //给基本大小1024
int sum;
int i=0;
while ((sum=fis.read(b))!=-1){
// System.out.print(new String(b,0,sum));
for (byte b1 : b) {
if((char)b1=='\n'){
i++;
}
}
}
System.out.println(i);
fis.close();
}
}
- 复制文件内容
package day14_IO.demo01_Copy;
import java.io.FileInputStream;
import java.io.FileOutputStream;
//把text.txt复制到copytext.txt
public class Demo01_Copy {
public static void main(String[] args) throws Exception{
FileInputStream fis = new FileInputStream("E:\\IdeaFile\\BigData\\data\\text.txt");
FileOutputStream fos = new FileOutputStream("E:\\IdeaFile\\BigData\\data\\copyText.txt");
byte[] b=new byte[1024];
int i;
while ((i=fis.read(b))!=-1){//循环读写100次
fos.write(b,0,i);
}
fis.close();
fos.close();
}
}
package day14_IO.demo01_Copy;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
//复制目录
//把目录data复制为copyData
public class Demo02_copy {
public static void main(String[] args) throws Exception {
File file = new File("E:\\IdeaFile\\BigData\\data");//原本的路径
File newFile = new File("E:\\IdeaFile\\BigData\\copyData");//复制的路径
show(file,newFile);
}
public static void show(File file,File newFile)throws Exception{
File[] files = file.listFiles();
for (File file1 : files) {
if(file1.isFile()){
String s = newFile.getAbsolutePath() +"\\"+ file1.getName();//获取复制的路径
System.out.println(s);
FileInputStream fis = new FileInputStream(file1.getAbsolutePath());
FileOutputStream fos = new FileOutputStream(s);
byte[] b=new byte[1024];
int i;
while ((i=fis.read(b))!=-1){
fos.write(b,0,i);
}
fis.close();
fos.close();
}else {//目录 首先在复制的路径下创建新的目录
File file2 = new File(newFile, file1.getName());
file2.mkdirs();
show(file1,file2);
}
}
}
}
- 字节缓冲流
字节缓冲流:避免多次读写过程中,㡳层系统的多次调用
- BufferedOutputStream:该类实现缓冲输出流。 通过设置这样的输出流,应用程序可以向底层输出流写入字节,而不必为写入的每个字节导致底层系统的调用。
- BufferedInputStream:创建一个内部缓冲区数组。 当从流中读取或跳过字节时,内部缓冲区将根据需要从所包含的输入流中重新填充,一次有多个字节。
构造方法:
BufferedOutputStream(OutputStream out)
BufferedInputStream(InputStream input)
注意:
- 字节缓冲流仅仅提供缓冲区,真正的读写数据还是依靠基本的字节流对象进行操作
- 使用字节缓冲输入流BufferedOutputStream时,数据首先写入到缓冲区之中(数组),然后通过关闭流或者flush()把数据写入到文件之中
package day14_IO.demo02_Buffered;
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
//BufferedOutputStream(OutputStream out)
public class Demo01 {
public static void main(String[] args) throws Exception{
BufferedOutputStream bos = new BufferedOutputStream(
new FileOutputStream("E:\\IdeaFile\\BigData\\data\\text.txt"));
bos.write(97);
bos.write(98);
bos.flush();
}
}
package day14_IO.demo02_Buffered;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
//BufferedInputStream(InputStream input)
public class Demo02 {
public static void main(String[] args) throws Exception{
BufferedInputStream bis = new BufferedInputStream(
new FileInputStream("E:\\IdeaFile\\BigData\\data\\text.txt"));
int read = bis.read();
System.out.println(read);
bis.close();
}
}
- 编码表
常用编码表:ASCII,GBK,Unicode
Unicode统一编码表,标准万国码,使用最多4个字节的数字表达字母,有三种编码格式,UTF-8、UTF-16和UTF32常用UTF-8
编码:
byte[] getBytes():使用平台的默认字符编码集将String存储字节数组
byte[] getBytes(String chareName):使用指定的编码集String存储字节数组
解码:
String(byte[] bytes):通过默认字符集解码指定的数组来构造新的String
String(byte[] bytes,String chareName):通过指定字符集解码指定的数组来构造新的String
注意:编码和解码所随用的编码集要保持一直,不然会出现乱码问题(解析字节的个数不同)
package day14_IO.demo03;
import java.io.UnsupportedEncodingException;
/*
编码:
byte[] getBytes():使用平台的默认字符编码集将String存储字节数组
byte[] getBytes(String chareName):使用指定的编码集String存储字节数组
解码:
String(byte[] bytes):通过默认字符集解码指定的数组来构造新的String
String(byte[] bytes,String chareName):通过指定字符集解码指定的数组来构造新的String
*/
public class Demo02 {
public static void main(String[] args) throws Exception {
// String s="中";
//编码
byte[] bytes = s.getBytes();//默认UTF-8
for (byte b : bytes) {
System.out.println((char)b);
}
//解码
String string = new String(bytes);
System.out.println(string);
sout("==========================")
String s="中国";
byte[] gbks = s.getBytes("UTF-8");
System.out.println(gbks.length);
//UTF-8格式编码三个字节 BGK2个字节
String gbk = new String(gbks, "GBK");
System.out.println(gbk);
}
}
package day14_IO.demo03;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
public class Demo03 {
public static void main(String[] args) throws Exception{
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("E:\\IdeaFile\\BigData\\data\\text.txt"));//中国12你好
byte[] bytes = new byte[3];//三个字节长度
int i;
while ((i=bis.read(bytes))!=-1){
String s = new String(bytes);//解码
System.out.println(s);//读出来的结果会乱码
}
bis.close();
}
}
- 字符流
Read:这个抽象类表示字符输入流的所有类的父类
Write:这个抽象类表示字符输出流的所有类的父类
package day14_IO.demo04_OutputStream;
// 写数据
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
/*
OutputStreamWrite:文件字符输出流(具体的字符输出流实现类)
OutputStreamWrite(OutputStream out)创建文件字节输出流写入文件
注意:字符流构造中的参数不是具体的文件路径 而是字节流对象
说明了字符流才具体的操作文件内容时,本质上还是通过字节流操作
*/
public class Demo01_OutputStreamWrite {
public static void main(String[] args) throws Exception{
OutputStreamWriter osw = new OutputStreamWriter(
new FileOutputStream("E:\\IdeaFile\\BigData\\data\\text.txt"));
//write方式:
// osw.write(97);
// char[] c={'a','b','c'};//String底层就是char数组 更底层是字节数组
// osw.write(c,1,2);
// osw.write("abc中国");
String abc = "abc中国";//charAt
osw.write(abc,1,3);
osw.close();
}
}
package day14_IO.demo04_OutputStream;
//读数据
import java.io.FileInputStream;
import java.io.InputStreamReader;
/*
IntputStreamWrite:文件字符输入流(具体的字符输入流实现类)
IntputStreamWrite(IntputStream input)创建文件字节输入流读取文件
*/
public class Demo02_InputStreamRead {
public static void main(String[] args) throws Exception{
InputStreamReader isr = new InputStreamReader(
new FileInputStream("E:\\IdeaFile\\BigData\\data\\text.txt"));//bc中
// int read = isr.read();
// System.out.println((char) read);
// int read1 = isr.read();
// System.out.println((char)read1);
// int read2 = isr.read();
// System.out.println((char)read2);
// char[] c=new char[1024];
// int read = isr.read(c);
// System.out.println(read);
char[] c=new char[1024];
int read = isr.read(c,2,4);
System.out.println(read);
isr.close();
}
}
package day14_IO.demo04_OutputStream;
import java.io.FileInputStream;
import java.io.InputStreamReader;
public class Demo02_String {
public static void main(String[] args) throws Exception{
InputStreamReader isr = new InputStreamReader(
new FileInputStream("E:\\IdeaFile\\BigData\\data\\text.txt"));
char[] c=new char[1024];
int i;
int sum=0;
while ((i=isr.read(c))!=-1){
for (char c1 : c) {
if(c1=='\n'){
sum++;
}
}
}//判断有多少行数
System.out.println(sum);
isr.close();
}
}
/*
写入
void write(int c) 写一个字符
void write(char[] cbuf) 写一个字符数组
void write(char[] cbuf,int off,int len) 写一个字符数组的一部分
void write(String str) 写一个字符串
void write(String str,int off,in len) 写一个字符串的一部分
读取
void read() 读一个字符
void read(char[] cbuf,int offset,int len) 将字符读入数组的一部分
- 字符流简单写法
package day14_IO.demo04_OutputStream;
/*
字符输出流:
FileWrite(OutputStream)
*/
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.OutputStreamWriter;
public class Demo05_FileWrite {
public static void main(String[] args) throws Exception{
FileWriter fw = new FileWriter("E:\\IdeaFile\\BigData\\data\\text.txt",true);
fw.write("你好");
fw.write("世界");
fw.close();
}
}
package day14_IO.demo04_OutputStream;
/*
字符输入流:
FileRead(InputStream)
*/
import java.io.FileReader;
public class Demo06_FileReader {
public static void main(String[] args) throws Exception{
FileReader fr = new FileReader("E:\\IdeaFile\\BigData\\data\\text.txt");//你好中国
int read = fr.read();
System.out.println((char)read);//你
fr.close();
}
}
- 字符缓冲流
-
BufferedReader:从字符输入流读取文本,缓冲字节,以提供字符,数组和行的高效读取。可以指定缓冲区大小,或者可以使用默认大小。默认大小足够大,可用于大多数用途。
-
BufferedWrite:将文本写入字符输出流,缓冲字节,以提供字符,数组和行的高效写入。可以指定缓冲区大小,或者可以使用默认大小。默认大小足够大,可用于大多数用途。
构造方法:
BufferedReader(Read in)
BufferedWrite(write out)
package day14_IO.Demo05_Buffered;
import java.io.BufferedWriter;
import java.io.FileWriter;
//字符缓冲输出流
//BufferedWrite(Write out);
public class Demo01_BuffreedWrite {
public static void main(String[] args) throws Exception{
//缓冲区默认数组大小为8192,可以手动指定
BufferedWriter bw = new BufferedWriter(
new FileWriter("E:\\IdeaFile\\BigData\\data\\text.txt"));
//\n \r \r\n java支持夸形态
bw.write("你好");
bw.newLine();//保证书写代码时,不需要关心换行符的问题,由字符缓冲流自动匹配
bw.write("世界");
bw.close();
}
}
package day14_IO.Demo05_Buffered;
import java.io.BufferedReader;
import java.io.FileReader;
//字符缓冲输入流
//BufferedReader(InputStream)
public class Demo02_BufferedRead {
public static void main(String[] args) throws Exception{
BufferedReader br = new BufferedReader(new FileReader("E:\\IdeaFile\\BigData\\data\\text.txt")); //你好
// String s = br.readLine(); 世界
// System.out.println(s);
// String s1 = br.readLine();
// System.out.println(s1);
// String s2 = br.readLine();
// System.out.println(s2); null
String s;
int sum=0;
while ((s=br.readLine())!=null){
sum++;
}
br.close();
System.out.println(sum);
}
}
package day14_IO.Demo05_Buffered;
//统计总共多少行代码
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
public class Demo03_Line {
static int sum=0;
public static void main(String[] args) throws Exception{
File file = new File("E:\\IdeaFile\\BigData\\src");
show(file);
System.out.println(sum);
}
public static void show(File file)throws Exception{
File[] files = file.listFiles();
for (File file1 : files) {
if(file1.isFile()){
BufferedReader br = new BufferedReader(
new FileReader(file1.getAbsolutePath()));
String s;
while ((s=br.readLine())!=null){
sum++;
}
br.close();
}else {
show(file1);
}
}
}
}
// 统计行号 复制 剪切
// 分类聚合:
// 目录下之有文件,每个文件中一行有一个单词
// 统计所有文件中,每个单词出现次数,并把结果保存到文件中,每一行是一个结果例如
// hello,10换行 world,5
package day14_IO.Demo05_Buffered;
import java.io.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
//读取所有数据,并存储ArrayList<String>
//分类聚合
public class Demo04 {
public static void main(String[] args) throws Exception{
ArrayList<String> list = new ArrayList<>();//用于存储所有数据
//读取所有数据
File file = new File("E:\\IdeaFile\\BigData\\data");
File[] files = file.listFiles();//获取所有文件的对象
for (File file1 : files) {
BufferedReader br = new BufferedReader(
new FileReader(file1.getAbsolutePath()));
String s;
while ((s=br.readLine())!=null){
list.add(s);
}
br.close();
}
//分类聚合
HashMap<String, Integer> hashMap = new HashMap<>();
//遍历所有数据,如果存在累加,不存在添加1
for (String s : list) {
if(hashMap.containsKey(s)){
hashMap.put(s,hashMap.get(s)+1);//通过k获取v,然后加1
}else {
hashMap.put(s,1);
}
}
// System.out.println(list.size());
// System.out.println(hashMap);
//把结果进行存储
BufferedWriter bw = new BufferedWriter(
new FileWriter("E:\\IdeaFile\\BigData\\copyData\\out.txt"));
Set<Map.Entry<String, Integer>> entries = hashMap.entrySet();//获取map中KV集合
for (Map.Entry<String, Integer> entry : entries) {
String key = entry.getKey();
Integer value = entry.getValue();
bw.write(key+","+value);
bw.newLine();
}
bw.close();
}
}
对象流
对象序列化
:就是将对象保存到磁盘中,或者在网络中传输对象
- 这种机制就是使用一个字节序列表示一个对象,该字节序列包含:对象的类型,对象中存储的对象详细信息
- 字节序列写入到文件之后,相当于文件持久保存了一个对象的信息;
反之,改该字节序列也可以从文件中读取对象信息,称之为反序列化
对象序列化流:ObjectOutputStream(OutputStream)
使用writeObject序列化对象
对象反序列化流:ObjectInputSTream(InputSTream)
使用readObject反序列化对象
package day14_IO.Demo06_Object;
//将学生对象的信息保存到文件中
import java.io.Serializable;
//Serializable接口没有任何方法
//只起到标识的作用,标识当前类可以进行序列化或反序列化
public class Student implements Serializable {
public static final long serialVersionUID = 10001;
private String name;
//如果类中的成员不想参与序列化,可以给该成员加上一个transient关键字修饰,标识了该成员不参与序列化
private transient int age;
// private int sum=100;
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;
}
}
package day14_IO.Demo06_Object;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
//对象序列化流:ObjectOutputStream
public class Test {
public static void main(String[] args) throws Exception{
Student ls = new Student("ls", 25);
ObjectOutputStream oos = new ObjectOutputStream(
new FileOutputStream("E:\\IdeaFile\\BigData\\copyData\\data.txt"));
oos.writeObject(ls);
oos.close();
sout("====================")
//反序列化
ObjectInputStream ois = new ObjectInputStream(
new FileInputStream("E:\\IdeaFile\\BigData\\copyData\\data.txt"));
Object o = ois.readObject(); //多态
Student student=(Student)o; //父类强制转为子类
System.out.println(student.getName());
System.out.println(student.getAge());
ois.close();
}
}
package day14_IO.Demo06_Object;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
//序列化和反序列化,执行过程中类发生改变
/*
Exception in thread "main" java.io.InvalidClassException:
day14_IO.Demo06_Object.Student;
local class incompatible: stream classdesc serialVersionUID = 181723052826308620,
local class serialVersionUID = 7913971369935982464
//每个类中实现了Serializable接口,当前类默认隐藏一个serialVersionUID,
当类发生改变时,serialVersionUID会发生变化
序列化和反序列化是通过serialVersionUID识别当前类是否相同
当序列化运行时检测到类中的以下问题之一时抛出。
类的串行版本与 从流中读取的类描述符的类型不匹配
该类包含未知的数据类型
该类没有可访问的无参数构造函数
*/
public class TestObject {
public static void main(String[] args) throws Exception{
Student student = new Student("ls", 25);
write(student);
read();
}
public static void write(Student student)throws Exception{
ObjectOutputStream oos = new ObjectOutputStream(
new FileOutputStream("E:\\IdeaFile\\BigData\\copyData\\data.txt"));
oos.writeObject(student);
oos.close();
}
public static void read()throws Exception{
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("E:\\IdeaFile\\BigData\\copyData\\data.txt"));
Object o = ois.readObject();
Student student=(Student)o;
System.out.println(student.getName());
System.out.println(student.getAge());
ois.close();
}
}
/*
常见问题
序列化一个对象之后,如果当前类发生改变,反序列化会出现异常
实现Serializable接口的类,默认异常一个UID版本号,当类发生改变时,UID会发生改变
而序列化和反序列化,是通过识别UID版本号,验证当前类是否属于同一个类
序列化一个对象之后,类文件发生更改,会出现InvalidClassException:
因为当序列化运行时检测到类中的以下问题之一时抛出。
类的串行版本与从流中读取的类描述符的类型不匹配
该类包含未知的数据类型
该类没有可访问的无参数构造函数
解决方案:
在类中增加一个版本标识信息(序列化对象时,会由系统分配的版本标识)
protected static final long serialVersionUID = 42L;
进程和线程
进程:正在运行的程序
- 是系统进行资源分配和调用的独立单位
- 每一个进程都有自己独有的内容空间和系统资源
- 正在执行的应用程序,表示程序在内存中的执行区域
线程:是进程中单个顺序控制流,是一条执行路径
- 是进程中的一个执行控制单元或执行路径
- 单线程:程序只有一条执行路径
- 多线程:程序有多个执行路径
注意:进程只负责开辟内存空间,线程负责执行逻辑代码
Java实现多线程的方式1:继承Thread
步骤:
1.创建类继承Thread
2.重写run方法
3.创建对象
4.调用start
start和run的区别
run:负责封装被线程执行的代码
start:启动线程,有java虚拟机调用此线程的run方法线程随机性
每个程序都有cpu进行执行,但是cpu同一时刻只能执行一个程序,多线程的同时执行,对于开发人员来说属于同时执行,对cpu来说属于交叉执行(同一时刻只能执行一个),多线程的随机性就是交叉执行执行的顺序不能保证比如一秒可能执行1000次
package day15_Thread.demo01_Thread;
/*
方式一:继承Thread类
定义一个类继承Thread类
在类中重写run方法
创建类的对象
启动线程
*/
public class MyThread extends Thread{
@Override
public void run() {
for (int i = 1; i <=100 ; i++) {
System.out.println(i);
}
}
}
package day15_Thread.demo01_Thread;
/*
方式一:继承Thread类
定义一个类继承Thread类
在类中重写run方法
创建类的对象
启动线程
*/
public class Test {
public static void main(String[] args) {
//创建两个线程对象
MyThread myThread = new MyThread();
MyThread myThread1 = new MyThread();//两个线程会交叉执行
//多个执行路径,交叉执行(交叉显示)
myThread.start();
myThread1.start();
// myThread.run(); run方法执行还是单线程
// myThread1.run();
}
}//打印结果:1 2 3 4 5 6 7 8 1 2 3 4 9 10 11 12 5 6 7
package day15_Thread.demo02_Thread;
public class MyThread extends Thread {
@Override
public void run() {
for (int i = 1; i <=100 ; i++) {
System.out.println(getName()+":"+i);
}
}
}
package day15_Thread.demo02_Thread;
/*
Thread中设置和获取线程名称的方法
void SetName(String name):将线程的名称设置为name
String getName():返回次线程的名称
*/
public class Test {
public static void main(String[] args) {
//创建线程对象
MyThread thread = new MyThread();
MyThread thread1 = new MyThread();
MyThread thread2 = new MyThread();
thread.setName("张三");
thread1.setName("李四");
thread2.setName("王五");
String name = thread.getName();//默认thread-0
String name1 = thread1.getName();//默认thread-1
String name2 = thread2.getName();
System.out.println(name);
System.out.println(name1);
System.out.println(name2);
thread.start();
thread1.start();
}
}
package day15_Thread.demo02_Thread;
// Thread(String name):构造函数,线程对象一建立就可以指定名称
// static Thread currentThread():获取当前线程对象
public class MyThread01 extends Thread {
public MyThread01() {
}
public MyThread01(String name) {
super(name);
}
@Override
public void run() {
for (int i = 1; i <=100; i++) {//获取线程名称
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
package day15_Thread.demo02_Thread;
//注意:在main方法中通过currentThread()获取的对象,
//无论使用什么去调用currentThread(),都为main这个线程的线程对象
public class Test01 {
public static void main(String[] args) {
MyThread01 zs = new MyThread01("张三");
MyThread01 ls = new MyThread01("李四");
zs.start();
ls.start();
sout("=============================")
//static Thread currentThread():获取当前线程对象
//静态方法的调用:类名.方法
System.out.println(Thread.currentThread().getName());//这个获取main方法的名称,可以理解为main里面有两个线程。会先调用main
System.out.println(zs.currentThread().getName());//这个获取main方法的名称(zs继承了Thread)
zs.start();
System.out.println(zs.currentThread().getName());
ls.start();
}
}
- 线程优先级
package day15_Thread.demo03_Thread;
/*
CPU调度模式
分时调度:多个线程平均分配CPU的使用时间
抢占调度:优先级较高的抢占CPU的改路较高,优先级只是提供了一个可能性。(不保证一定先执行)
Thread优先级
默认为5
最小为1
最大为10
Thread设置获取线程优先级的方法:
int getPriority():返回此线程的优先级
void setPriority():更改此线程的优先级
注意:
线程默认优先级为5,最大优先级为10,最小优先级为1
优先级高仅仅表示了抢占CPU的概率大,在次数多的时候效果明显
*/
public class MyThread extends Thread{
public MyThread() {
}
public MyThread(String name) {
super(name);
}
@Override
public void run() {
for (int i = 1; i <=100 ; i++) {
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
package day15_Thread.demo03_Thread;
/*
Thread设置获取线程优先级的方法
int getPriority():返回此线程的优先级
void setPriority():更改此线程的优先级
*/
public class Test {
public static void main(String[] args) {
MyThread zs = new MyThread("zs");
MyThread ls = new MyThread("ls");
//原本执行概率都是55开(默认优先级相同)
//大概率让zs先执行完(zs的优先级调高)
// System.out.println(zs.getPriority());
// System.out.println(ls.getPriority());
zs.setPriority(10);
zs.start();
ls.start();
}
}
- sleep
/*
void sleep(long millis) 使当前正在执行的线程暂停指定的毫秒数
void join() 等待这个线程的死亡
void setDaemon(boolean on) 将此线程标记为守护线程,当运行的线程都是守护线程时,Java虚拟机将退出
注意:守护线程会随着其余的线程而死亡,如果其余线程有多个以上,会等待最后一个线程死亡而死亡
*/
package day15_Thread.demo04_Thread;
//兔子
public class MyThread extends Thread {
public MyThread() {
}
public MyThread(String name) {
super(name);
}
@Override
public void run() {
for (int i = 1; i <=100 ; i++) {
if(i==20){
try {
sleep(2500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName()+"----"+i);
}
}
}
package day15_Thread.demo04_Thread;
//乌龟
public class MyThread1 extends Thread{
public MyThread1() {
}
public MyThread1(String name) {
super(name);
}
@Override
public void run() {
for (int i = 1; i <=100 ; i++) {
System.out.println(Thread.currentThread().getName()+"----"+i);
}
}
}
package day15_Thread.demo04_Thread;
/*
void sleep(long millis) 使当前正在执行的线程暂停指定的毫秒数
void join() 等待这个线程的死亡
void setDaemon(boolean on) 将此线程标记为守护线程,当运行的线程都是守护线程时,Java虚拟机将退出
*/
//龟兔赛跑
public class Test {
public static void main(String[] args) throws Exception{
MyThread1 wg = new MyThread1("乌龟");
MyThread tz = new MyThread("兔子");
tz.setPriority(10);
wg.setPriority(1);
wg.start();
tz.start();
}
}
- join
package day15_Thread.demo05_Thread;
public class MyThread extends Thread {
public MyThread() {
}
public MyThread(String name) {
super(name);
}
@Override
public void run() {
for (int i = 1; i <=100 ; i++) {
System.out.println(Thread.currentThread().getName()+"----"+i);
}
}
}
package day15_Thread.demo05_Thread;
public class MyThread1 extends Thread {
public MyThread1() {
}
public MyThread1(String name) {
super(name);
}
@Override
public void run() {
for (int i = 1; i <=100 ; i++) {
System.out.println(Thread.currentThread().getName()+"----"+i);
}
}
}
package day15_Thread.demo05_Thread;
//join() 等待当前线程的死亡
public class Test {
public static void main(String[] args) throws Exception{
MyThread zs = new MyThread("zs");
MyThread1 ls = new MyThread1("ls");
zs.start();
ls.start();
//等ls执行结束 zs在执行
zs.join();
}
}
- setDaemon :守护线程(辅助)
package day15_Thread.demo06_Thread;
public class MyThread extends Thread {
public MyThread() {
}
public MyThread(String name) {
super(name);
}
@Override
public void run() {
for (int i = 1; i <=100 ; i++) {
System.out.println(Thread.currentThread().getName()+"----"+i);
}
}
}
package day15_Thread.demo06_Thread;
public class MyThread01 extends Thread {
public MyThread01() {
}
public MyThread01(String name) {
super(name);
}
@Override
public void run() {
for (int i = 1; i <=100 ; i++) {
System.out.println(Thread.currentThread().getName()+"----"+i);
if(i==55){//关羽挂掉的年龄
stop();
}
}
}
}
package day15_Thread.demo06_Thread;
public class MyThread02 extends Thread {
public MyThread02() {
}
public MyThread02(String name) {
super(name);
}
@Override
public void run() {
for (int i = 1; i <=100 ; i++) {
System.out.println(Thread.currentThread().getName()+"----"+i);
}
}
}
package day15_Thread.demo06_Thread;
/*
void setDaemon(boolean on)
将此线程标记为守护线程,当运行的线程都是守护线程时,Java虚拟机将退出
*/
public class Test {
public static void main(String[] args) {
MyThread zs = new MyThread("zs");
MyThread01 ls = new MyThread01("ls");
zs.setDaemon(true);//把zs标记为了守护线程
//zs守护ls,ls挂了zs存在的意思就没了
//zs在ls挂了之后 紧接着就挂了
zs.start();
ls.start();
}
}
package day15_Thread.demo06_Thread;
//刘 关 张
//但求同年同月同日死
public class Test01 {
public static void main(String[] args) {
MyThread l = new MyThread("刘备");
MyThread01 g = new MyThread01("关羽");
MyThread02 z = new MyThread02("张飞");
l.setDaemon(true);
// z.setDaemon(true);
l.start();
g.start();
z.start();
}
}
多线程的生命周期:
新建 就绪 运行 阻塞 死亡
- 实现多线程的方式2
实现多线程的方式2:实现Runnable接口
步骤:
1.创建一个类实现Runnable接口
2.重写run方法
3.创建对象
4.创建Thread对象,把对象当做参数放入构造中
5.调用strat方法启动线程区别:
Runnable避免了java单继承
Runnable可以进行资源共享
package day16_Runnable.demo01;
/*
方式二:实现Runnable接口
定义一个类实现Runnable类
在类中重写run方法
创建类的对象
创建Thread对象(就是创建类对象),把类的对象作为构造方法的参数
启动线程
*/
public class MyRunnable implements Runnable{
int i;//保证for循环中用同一个变量,两个线程共同输出1-100,实现了资源共享
@Override
public void run() {
for (i=1; i <=100 ; i++) {
System.out.println(Thread.currentThread().getName()+"----"+i);
}
}
}
package day16_Runnable.demo01;
/*
创建类的对象
创建Thread对象,把类的对象作为构造方法的参数
启动线程
*/
public class Test {
public static void main(String[] args) {
//多个线程使用同一个类,实现了资源共享
MyRunnable myRunnable = new MyRunnable();
Thread thread = new Thread(myRunnable);
Thread thread1 = new Thread(myRunnable);
thread.start();//启动线程
thread1.start();
}
}
- 买票(相当于两个线程共同输出1-100)
package day16_Runnable.demo02;
//100-1 为0时程序不停止(循环继续,不输出)
public class MyRunnable implements Runnable{
static int i=100;
@Override
public void run() {
while (true){
if(i>=1){
System.out.println(Thread.currentThread().getName()+"----"+i);
i--;
}
}
}
}
package day16_Runnable.demo02;
//买票 三个窗口,总共有100张票,但是票卖完了之后,窗口还在不买票了
public class Test {
public static void main(String[] args) {
MyRunnable myRunnable = new MyRunnable();
Thread thread = new Thread(myRunnable,"张三");
Thread thread1 = new Thread(myRunnable,"李四");
thread.start();
thread1.start();
}
}
//数字顺序会乱
package day16_Runnable.demo03;
public class Tick implements Runnable {
int sum=100;//总票数
@Override
public void run() {
while (true){//循环买票
// t1 sum=1 sleep(100) t2抢走了
// t2 sum=1 sleep(100) t3抢走了
// t3 sum=1 sleep(100) t1抢走了
// t1 输出1 sum-- sum=0 t2抢走了
// t2 输出0 sum-- sum-1 t3抢走了
// t3 输出-1 sum-- sum-2
if(sum>0){
//模拟网络延迟,可以让顺序一致,但会出现一张票卖了多次
// t1---sum=100 sleep(100) 线程被t2抢走了
// t2---sum=100 sleep(100) 线程被t3抢走了
// t3---sum=100 sleep(100) 线程被t1抢走了
// t1 输出100 线程被t2抢走了sum-- sum=99 线程被t2抢走了
// t2 输出100 线程被t3抢走了sum-- sum=98 线程被t3抢走了
// t3 输出100 线程被t1抢走了sum-- sum=97
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"买出了第"+sum+"张票");
sum--;
}
}
}
}
package day16_Runnable.demo03;
public class Test {
public static void main(String[] args) {
Tick tick = new Tick();
Thread t1 = new Thread(tick, "窗口1");
Thread t2 = new Thread(tick, "窗口2");
Thread t3 = new Thread(tick, "窗口3");
t1.start();
t2.start();
t3.start();
}
}
数据安全问题
本质:资源共享中,每个线程执行操作资源的代码,操作不完整
解决:
让每个线程操作执行完整
通过锁把操作资源的代码锁起来,让线程执行完整同步代码块:任意对象,通常使用当前对象this
格式:
synchronized(任意对象){
代码
}synchronized(任意对象):给代码加上锁,任意对象就可以看做锁
好处:解决数据安全问题;
弊端:线程很多时,每个线程都会执行synchronized,消耗资源,会降低执行效率
package day16_Runnable.demo04_synchronized;
/*
synchronized(任意对象){//通常给当前对象this
多条语句操作共享数据的代码
}
*/
public class Tick implements Runnable {
int sum=100;
@Override
public void run() {
while (true){
synchronized(this){//放在循环里面
if(sum>0){
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"买出了第"+sum+"张票");
sum--;
}
}
}
}
}
package day16_Runnable.demo04_synchronized;
public class Test {
public static void main(String[] args) {
Tick tick = new Tick();
Thread t1 = new Thread(tick, "窗口1");
Thread t2 = new Thread(tick, "窗口2");
Thread t3 = new Thread(tick, "窗口3");
t1.start();
t2.start();
t3.start();
}
}
同步方法:this
格式:
修饰符 synchronized 返回值类型 方法名(){}
静态同步方法:类名.class
格式:
修饰符 static synchronized 返回值类型 方法名(){}
package day16_Runnable.demo05_synchronized;
/*
格式:
修饰符 synchronized 返回值类型 方法名(参数){}
同步代码块锁任意对象 通常锁当前对象this
同步方法锁当前对象this
*/
public class Tick implements Runnable {
int sum=100;//总票数
@Override
public void run() {
while (true){//循环买票
if(sum%2==0){
show();
}else {
synchronized(this){
if(sum>0){
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"买出了第"+sum+"张票");
sum--;
}
}
}
}
}
public synchronized void show(){
if(sum>0){
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"买出了第"+sum+"张票");
sum--;
}
}
}
package day16_Runnable.demo05_synchronized;
public class Test {
public static void main(String[] args) {
Tick tick = new Tick();
Thread t1 = new Thread(tick, "窗口1");
Thread t2 = new Thread(tick, "窗口2");
Thread t3 = new Thread(tick, "窗口3");
t1.start();
t2.start();
t3.start();
}
}
package day16_Runnable.demo06_synchronized;
/*
格式:
修饰符 synchronized 返回值类型 方法名(参数){}
同步代码块锁任意对象 通常锁当前对象this
同步方法锁当前对象this
*/
public class Tick implements Runnable {
static int sum=100;//总票数
@Override
public void run() {
while (true){//循环买票
if(sum%2==0){
show();
}else {
synchronized(Tick.class){
if(sum>0){
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"买出了第"+sum+"张票");
sum--;
}
}
}
}
}
public static synchronized void show(){
if(sum>0){
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"买出了第"+sum+"张票");
sum--;
}
}
}
package day16_Runnable.demo06_synchronized;
public class Test {
public static void main(String[] args) {
Tick tick = new Tick();
Thread t1 = new Thread(tick, "窗口1");
Thread t2 = new Thread(tick, "窗口2");
Thread t3 = new Thread(tick, "窗口3");
t1.start();
t2.start();
t3.start();
}
}
线程池:
写法:创建多个线程
ExecutorService threadPool = Executors.newFixedThreadPool(8);
启动线程
threadPool.submit(Runnable对象)
关闭线程池
threadPool.shutdown();
package day16_Runnable.demo9;
import day16_Runnable.demo06_synchronized.Tick;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
//一次性创建多个线程:线程池
//格式
public class Test {
public static void main(String[] args) {
ExecutorService threadPool = Executors.newFixedThreadPool(8);
Tick tick = new Tick();
threadPool.submit(tick);
threadPool.submit(tick);//可以调用8次,就8个线程了
}
}
网络编程
网络编程:多同设备之间进行数据交换
网络编程三要素
IP地址:设备在网络中的唯一标识
IPv4:32位的二进制,分成4组
IPv6:128位的16进制,分为8组
java提供了InetAddress操作IP地址
方法:
static InetAddress getByName(String host) 确定主机名称的IP地址,主机名称可以是机器名称,也可以是Ip地址
String getHostName() 获取此IP地址的主机名
String getHostAddress() 返回IP地址的字符串端口号:程序在设备中的唯一标识
0-65536之间,但是0-1023被知名的陈谷和服务占用
通讯协议:数据传输时,遵循的规则,常见UDP和TCP
UDP:无连接通讯协议,不能保证数据的完整性
TCP:面向连接刑讯协议,可以保证数据的完整性UDP发送数据
步骤:
1.创建DatagramSocket对象
2.准备数据
3.把数据转换成DatagramPacket对象,通过DatagramPacket(byte[],byte.lenght,ip,port)
4.调用DatagramSocket对象中send方法发送数据
5.关闭
UDP接收数据
步骤:
1.创建DatagramSocket对象,并指定端口号
2.创建byte数组
3.把数组传到DatagramPacket对中用于接收数据,通过DatagramPacket(byte[],byte.lenght)
4.调用DatagramSocket对象中receive方法接收数据
5.解析数据,通过调用DatagramPacket中的方法来解析
6.关闭TCP发送数据
步骤:
1.创建Socket对象,并制定IP地址和端口号
2.通过getOutputStream()获取流写数据
3.关闭
TCP接收数据
步骤:
1.创建ServerSocket对象,并绑定端口号
2.通过accpet()监听端口,并获取Socket对象
3.通过geInputStream()获取流读数据
4.关闭注意:
三次握手建立连接
如果使用循环读取数据,read()不能判断是否还有数据进行传输(不能判断输入流是否结束),read()会进入阻塞状态,等待数据的输入
通过shutdownOutput()可以解决阻塞状态,但是循环接收和发送时,不能使用shutdownOutput()
如何解决通讯两端的阻塞问题,不使用循环,并且通讯两端约定传输数据的最大值
反射
反射:一个类在运行状态中获取另一个类的class文件(Class对象,编译状态)
注意:java准动态的语言类加载:当程序要使用某个类时,如果该类还没有加载到内存中,系统会通过类的加载,类的连接,类的初始化三个步骤来对类进行初始化
类的加载:
将class文件(源文件)读取内存,并创建对应的Class对象
任何类被使用时,系统都会创建一个java.lang.Class对象
类的连接
验证阶段:检验被加载的类和相关类(父类/接口)内部结构是否合法
准备阶段:负责为类中的变量分配内存,并设置默认值
解析阶段:将类的二进制数据中字符(方法)引用改为直接引用
注意:方法实际上是在方法区中
类的初始化:
对类变量进行初始化(赋值)类加载注意事项
1.当类还未被加载和连接时,程序先加载并连接该类
2.该类的直接父类未被初始化,先初始化直接父类
3.假如类中有初始化语句(非static修饰),依次执行初始化语句
执行步骤2时,同样遵循1-3类加载器:负责将class文件加载到内存中,并生成对应的Class对象
机制:
全盘负责:
当类加载器负责加载某一个class文件时,与之相关的class文件也由该类 加载器负责,除非显示由另一个加载器负责
父类委托:
加载某一个class文件时,先让父类的加载器试图加载该class文件,只有在父类无法加载该class文件时,才尝试从自己的类路径加载
缓存机制:
会把所有加载的class文件生成的Class对象进行缓存,当程序需要使用某一个Class对象时,类加载器首先去缓存中搜索,缓存中不存在时,才会将class文件加载到内存中,并生成对应的Class对象通过反射获取类
1.通过类的class属性
格式:
类名.class
2.通过对象名调用getClass()方法
3.通过Class中静态方法forName(String name),当前的抽象路径(src下开始)
注意:所获取的Class对象默认可以使用newInstance()调用默认构造创建对象获取构造并使用
Constructor<?>[] getConstructors():获取所有公共构造对象的数组 Constructor<?>[] getDeclaredConstructors():获取所有构造对象的数组
Constructor[] getConstructors(Class<?>... parameterTypes):返回单个公共构造方法对象 Constructor[] getDeclaredConstructor(Class<?>… parameterTypes):返回单个构造方法对象
Class类中用与使用构造的方法
T newInstance(Object… initargs);根据指定的构造方法创建对象
注意:通过反射私有化构造不能直接创建对象需要通过setAccessible方法获取属性和使用
Field[] getFields();获取所有公共成员变量的数组
Field[] getDeclaredFields();获取所有成员变量的数组
Field[] getFields(String name);返回单个公共成员变量的对象
Field[] getDeclaredFields(String name);返回单个成员变量的对象
Class类中用与成员变量赋值的方法
void set(Object obj,Object value):给obj对象的成员赋值value
注意:通过反射私有化成员不能直接赋值需要通过setAccessible方法获取方法和使用
Method[] getMethods();获取所有公共成员方法(包括继承)的数组
Method[] getDeclaredMethods();获取所有成员方法(不包括继承)的数组
Method[] getMethods(String name,Class<?>... parameterTypes);返回单个公共成员方法的对象 Method[] getDeclaredMethods(String name,Class<?>… parameterTypes);返回单个成员方法的对象Method类中用与调用成员方法的方法
Object invoke(Object obj,Object…args):调用obj对象的成员方法参数为args,返回值为Object
注意:通过反射私有化成员方法不能直接调用需要通过setAccessible方法
正则表达式
正则表达式:通过简单的代码验证文本框的输入内容
/…/ 代表一个模式的开始和结束
^ 匹配字符串的开始
$ 匹配字符串的结束
\s 任何空白字符
\S 任何非空白字符
\d 匹配一个数字字符,等价于[0-9]
\D 除了数字之外的任何字符,等价于[^0-9]
\w 匹配一个数字、下划线或字母字符,等价于[A-Za-z0-9_]
\W 任何非单字字符,等价于[^a-zA-z0-9_]
. 除了换行符之外的任意字符
{n} 匹配前一项n次
{n,} 匹配前一项n次,或者多次
{n,m} 匹配前一项至少n次,但是不能超过m次
- 匹配前一项0次或多次,等价于{0,}
- 匹配前一项1次或多次,等价于{1,}
? 匹配前一项0次或1次,也就是说前一项是可选的,等价于{0,1}
(x|y) 匹配x获取匹配y,例如:(abc|123)java,所匹配的结果为abcjava或者123java
步骤:
1.创建格式
例如:String reg=“^\d[1-11]$”;
2.把String转化为正则表达式
例如:Pattern compile = Pattern.compile(reg);
3.匹配内容
例如:Matcher matcher = compile.matcher(内容);
4.获取匹配的结果对还是错
例如:System.out.println(matcher.matches());