java语法

1:使用的是java11.0。java.8公司使用的最多的

java跨windows等操作平台操作。java有jam(翻译)java虚拟机从而进行跨平台操作。

JRE:java的运行环境包含JVM要运行java安装JRE就可以了

JDK:包含JRE和开发环境

bin:JDK的各种工具命令。java和javac就在。

conf:JDK的相关配置文件

jmods:JDK的各种模块

include:一些头文件

legal:模块的授权文档

lib:补充JAR包。

2:DOS命令,运行cmd

盘符:回车(切换盘)。dir(查看现路径下的内容。cd目录(进入目录)。cd..(退回上级目录)。cd目录\目录。cd\ 。cls(清屏)。exit(退出)。

这是因为IDEA运行Junit或者运行main方法时候会默认先编译整个项目。

基础语法

基础

1注释:

说明。单行注释// .多行注释/* /.文本注释/* */.

java中最基本的组成单位是类。类的定义格式: public class 类名{}。mian方法是入口

关键字

字母全部小写。有特殊颜色标记。

常量

固定不变的。

字符串,整数,小数,字符,布尔,空(null)

数据类型

字节B位(比特位)b

byte 1.short 2.int 4(默认).long 8.float 4.double 8(默认).char 2. boolean 1(布尔).

变量

暂存位置。int a=19;a=10;

一定要给值。不是默认类型要加L(long),F(float).

标识符

由数字,字母,下划线()和美元符()组成

不以数字开头,不是关键字,区分大小写。

小驼峰命名法(方法,变量):一个单词首字母小写,多个单词的时候第一单词首小写其他首大写

大驼峰命名法(类):一个单词首字母大写,多个单词的时候每个首字母大写

类型转换

自动类型转换:表示数据范围小的变成数据表示范围大的 从大到小类型不兼容int k=(int)88.8。

运算符

算术运算符

+-*/% (byte,short,char->int->long->float->double)

字符加操作:会用字母的ASKNA值('A'=65,'a'=97,'0'=48) 会自动提升类型

字符串的加操作:将两个拼接,1+99+“王”=100王;王+1+99=王199;

赋值运算符

在赋值时要转换类型 扩装的赋值预算符隐含强制类型转换

自增自减运算符

i++ ;++i; --i;i--;单独使用和参与操作使用;

关系运算符

值只为为ture或false;

逻辑运算符

&:有false则为false(和)全运行;

|:有true则true(或);

^:同为false,不同为true;

!:相反;

短路运算符

&&:有false则为false(和)若第一个为false则右边不执行;

||:有true则true(或)若第一个为false则右边不执行;

三元运算符

a>b?a:b:对为a错为b;

两只老虎

判断其体重是否相同

有三元运算符

三个和尚

求三个身高的最高值

也用三元运算符

数据输入Scanner:

import java.util.Scanner;(导包的动作必须在类定义的上边)

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

int i=sc.nextInt();(i是变量名可变,sc与上面对应);接收数据

三个和尚

录入三个身高再求最大值

控制语句

分支语句

流程控制

顺序结构

if语句

1if(关系表达式){

语句体;}关系表达式为true就执行语句;

2 if(){

语句体1}else{

语句体2}

3 if(){

语句1;}else if(){

语句体2;}else if(){

语句体3;}---else if(){

语句体n-1;}

判断是奇偶数

用if语句

考试奖励

不同的分有不同的奖励95100山地自行车;9094游乐场80~89变形金刚;80以下竹笋炒肉一顿

数据测试:正确数据,边界数据,错误数据

switch语句

switch(表达式){

case值1:语句体1;

​ break;

case值2:

​ 语句体2;

​ break;......

default:语句体n+1;

break;

}把表达式的值与case比较相同运行其语句遇到break退出

case穿透:无break会向下走直到遇到break退出

春夏秋冬

输入一个月份输出季节;

循环语句

for循环语句

for(初始化语句;条件判断语句;条件控制语句){

循环体语句}

先初始化再判断语句之后循环语句最后控制语句

输出数据

输出9*9乘法表;

求和 sum;
求偶数和
输出水仙花数三位数(水仙花数的个位十位百位的立方和等于原数字)

对任意数字的指定位置上的值:先整除到个位再求余取出

统计水仙花数输出其数量

while循环语句

基本语法

初始化;

while(条件判断语句)

{

循环语句;

条件控制语句;}

珠穆朗玛峰8844.43米用一张厚度为0.1毫米。问折叠几次可折成珠峰高度

do while语句

do {

循环体语句;

条件控制语句;}while(条件判断语句);

三个循环区别:1do while至少一次

2for可直接在初始化时定义但不能带出循环

死循环格式:for(;;){}

while(true){}

do{}while(true);

跳转控制语句

continue跳过这次循环进行下一次循环

break退出循环不再循环

循环嵌套

循环语句中包含循环语句

输出一天的小时和分钟

Random

作用:获得一个随机数;

步骤:导包:import java.util.Random:

创建对象:Random r=new Random();(r可以变,其他不能变。)

获得随机数:int number=r.nextInt(10);(获取数据范围为[0~10)number是变量名,可变,数字10可变。)

猜数字

大了小了中了都会提示;

idea


  • src中有java文件

  • out中有class文件

项目结构

项目(project)——>模块(modern)——>包——>类

内容辅助键和快捷键

  • 生成main()方法:psvm回车。

  • 生成输出语句:sout回车。

  • Ctrl+Alt+space(内容提示,代码补全等).

单行注释 多行注释 格式化
ctrl+/,再来就是取消 ctrl+shift+/再来就是取消 ctrl+alt+L

模块操作

数组

同类型,大量的数据的数据模型。

  1. 数据类型[] 变量名 int[] arr定义了一个int类型的数组,名为arr。

  2. 数据类型 变量名[]int arr[]定义了一个int类型的变量,名为arr数组。

初始化

定义

分配内存空间,并赋值。

方式

只指定数组长度,由系统为数组分配初始值

数据类型[] 变量名=new 数据类型[数组长度];

int [] arr = new int[3];

int [ ] arr new int [ ] 3
数组中的元素类型 说明这是数组 数组名 为数组申请空间 数组中的元素类型 说明这是一个数字 数组长度

数组元素访问

  • 数组变量访问

​ 格式:数组名

  • 数组元素

​ 格式:数组名[索引]

内存分配

int [] arr = new int[3];

会分配两个空间分别储存地址和元素

栈内存:是局部变量使用完后会消失

堆内存:new出来的内容(实体,对象)数组在初始化时会为存储空间添加默认值(new出来的东西会在垃圾回收器空闲时被回收)。

  • 整数:0;
  • 浮点数:0.0;
  • 布尔:false;
  • 字符:空字符;
  • 引用数据类型:null;

int[ ] arr = new int[2];

int[] arr2=new int[3];

System.out.println(arr);(地址)

System.out.println(arr[0]);

System.out.println(arr[1]);

System.out.println(arr2);

System.out.println(arr[0]);

System.out.println(arr[2]);

数组内存多个数组指向一个

int[] arr=new int[3];

int[] arr2=arr;

数组的静态初始化

初始化时指定数组元素初始值,由系统决定数组长度。

格式:数据类型[] 变量名=new 数据类型[]{数据1,数据2......};

int [] arr= new int[]{1,2,3};

简化:

int[] arr={1,2,3};

常见问题

索引越界:访问了数组中不存在的元素。

空指针异常:访问的数组不再指向堆内存。null(空指针)。

遍历

数组元素个数:arr.lengh

最值

定义变量取数组第一个数再一次比较

方法

方法概述

方法是将独立的代码块组织成一个整体,使其成为代码集(类似c语言中的函数)

  • 方法定义:方法先创建再使用
  • 方法调用:创建后不直接运行,需手动使用。

定义

public static void 方法名(数据类型 变量名1...)

{

方法体;}

方法调用

格式:方法名(参数);

一个方法打印最大值

形参:方法定义中的参数;

实参:方法调用中的参数;

通用

public static 返回值类型 变量名(){

...

return 参数;}

调用

数据类型 变量名=方法名(参数);

注意

  • 不能嵌套定义

  • void表示无返回值

方法重载

  • 多个方法在同类中
  • 相同的方法名
  • 参数不同,类型不同或数量不同(与返回值无关)

public static int sun(int a,int b){

return a+b;}

``public ststic doublie sun(doublie a,double b){`

return a+b;}

public ststic int sun(int a,int b int c){

return a+b+c;}

当用public ststic int sun(20,30)时为第一个方法;

通过参数的不同来区别不同方法;

比较两个数使用全整数(byte short int long)并确定是哪个方法。

方法参数传递

基本类型

形参的改变不影响实参的值

引用类型

对引用类型的形参影响实参(用地址改变实参)

其类型为:类,接口,数组,String(字符串)

ln有换行的作用

System.out.print()——不换行

用方法求数组遍历
用方法求数组最大值

Debug

概述:查看程序执行流程 ,追踪程序来调试程序

断点调试

加断点,运行Debug,按F7继续运行。

练习

减肥计划星期1,2,3,4,5,6,7分别去跑步,游泳,慢走,单车,拳击,爬山,好吃一次。(测试)

导包

  • 手动导包
  • 快捷键:ail+回车
  • 自动导包
逢七过包含7或7的倍数
不死神兔一对兔子从出生的第三个月开始都生一对兔子,问第二十个月有多少对兔子。
百钱白鸡一鸡翁五钱一鸡母三钱三鸡雏一钱问百钱买百鸡其鸡各几个。
数组元素求和求和的数字个位和十位都不能是七并只能是偶数arr[]=
数组内容是否相同
查找找数在数组中的位置

返回值为索引

反转:把数组反转(借助一个空间)
评委打分去掉最高分和最低分再算平均分

面向对象基础

类和对象

定义

类是对现实生活中一类具有共同属性和行为的事物的抽象。

  • 类是对象的数据类型
  • 类是具有相同属性和行为的集合

属性:对象具有的各种特征,每个对象的每个属性都有特定的值

行为:对象能干什么

对象:是能看到的真实的实体

类是对象的抽象。

类是java的基本组成单位

类的组成:属性和行为

属性和行为在类中的体现:

属性 行为
成员变量 成员方法

javabean类不写main方法(不写main方法的类)。

定义步骤:

  • 定义类
  • 编写类的成员变量
  • 编写类的成员方法

public class Phone{

//成员变量

String brand;

int price;

//成员方法

public void call(){

System.out.println("打电话")

public void sendMessage(){

System.out.println("发短信");}

对象的使用

创建

  • 格式:类名 对象名=new 类名();
  • 范例:Phone p=new Phone();

使用

1:使用成员变量

  • 格式:对象名.变量名
  • 范例:p.brond

2:使用成员方法

  • 格式:对象名.方法名()
  • 范例:p.call()
案例:学生定义学生类,再定义一个学生测试类,在学生测试类中通过对象完成成员变量和成员方法。

对象内存图

能创建多个对象

使用对象在内存中的流程:

  • 在栈内存中创建main方法给对象一个地址
  • 在堆内存中创建成员变量(地址一样),在栈内存中使用成员方法。
  • 若有多个对象,重复上述流程(不同的对象的地址不同)

多个对象指向相同(其地址相同)

成员变量和局部变量

  • 成员变量:类中方法外的变量

  • 局部变量:方法中的变量

区别 成员变量 局部变量
类位置不同 类中方法外 方法内或方法声明上
内存中位置不同 堆内存 栈内存
生命周期不同 随着对象的存在而存在,随着对象的消失而消失 随着方法的调用而存在,随着方法的完毕而消失
初始值不同 有默认的初始值 没有默认的初始值,必须定义,赋值

封装

private关键字

  • 是一个权限权限修饰符

  • 可以修饰成员(成员方法和成员变量)

  • 作用是保护成员不被别的类使用,被private修饰的成员旨在本类中才能访问

    针对private修饰的成员变量,如果需要被其他类使用,则需要提供相应的操作(在本类中设置方法)

    • 提供“get变量名()”方法,用于获取成员变量的值,方法用public修饰
    • 提供“set变量名(参数)“方法,用于设置成员变量的值,方法用public修饰
    • 方法可以加判断

使用

在方法中加上get/set方法

  • set方法是改变值
  • get方法是获取值

public void setName(String n){

name=n;}

public int getName(){

return name;}

public void showName(){

System out.println(name);}

this关键字

  1. this修饰的变量指成员变量
  • 方法的形参如果与成员变量同名,不带this修饰的变量指的是形参,不是成员变量
  • 方法的形参没有与成员变量同名,不在this的变量也值成员变量
  1. 作用:解决局部变量隐藏成员变量

  2. this:代表所在类的对象引用

this的内存原理

封装概述

  • 面向对象的三大特征(封装,继承,多态)

  • 是面向对象语言对客观世界的模拟,客观世界里成员变量都是隐藏在对象内部的,外界是无法直接操作的

封装原则

将类的某些信息隐藏在类内部,不允许外部程序直接访问,而是通过该类提供的方法来实现对隐藏信息的操作和访问成员变量private,提供对应的getXxx()/setXxx()方法

好处

  • 提高了代码的安全性
  • 提高了代码的复用性

构造方法。

一种特殊的方法

格式:

public class 类名{

修饰符 类名(参数){

}}

注意

  • 如无构造方法会默认为无参构造方法
  • 若已定义则不再提供默认的构造方法
  • 构造方法可以重载(推荐书写(无参)构造方法不论是否使用)

标准类制作

  • 成员变量都使用private修饰
  • 构造方法提供一个无参构造方法和一个带参构造方法
  • 成员方法提供每一个成员对应的setXxx()/getXxx()和显示信息的show()

API

定义:应用程序编程接口(接口类)(类似c语言中的库函数)

java API:JDK中提供的各种功能的java类

  • 导包:导入附带的软件包(可以使用其中的方法)

  • 创建对象:创建一个具体的事物来接收类

  • 接收数据:用具体的变量来接收对象(具体事物)其中的成员变量

对象调用方法若有返回值用变量接收可用快捷键Ctrl+Alt+v

String(字符串)

概述

String在java.lang包下不需要导包

String在java中是所有“”的字符串文字

特点

  • 字符串不可变,它们的值在创建后不能被更改
  • String的值是不可变的,但可以被共享
  • 字符串效果相当于字符数组(char[]),但底层原理是字节数组(byte[])

构造方法

方法名 说明
public String() 创建一个空白字符串对象
public String(char[] chs) 根据字符串的内容,来创建字符串对象
public String(byte[] bys) 根据字节数组内容来创建字符串对象
String s="abc" 直接赋值的方式来创建字符串对象

String对象的特点

  1. 通过new来创建的字符串对象,每次创建的对象都会创建一个存储空间(地址不同)
  2. 直接赋值来创建,只要字符串的大小顺序相同它指的都是同一个存储空间(地址相同)

比较equals

使用==作比较

  • 基本类型:比较的是数据值是否相同
  • 引用类型:比较的是地址是否相同

方法:equals()

  • public boolean equals(object anobject)
  • 示例:boolean a=s1.equals(s2)s1,s2为比较的字符串
用户登录:已知用户名和密码,请用程序模拟用户登录。总共三次机会登录之后会有提示。

常见方法:

int indexOf(int ch):返回指定字符串中第一次出现位置的索引

int IastIndexOf(int ch):

int indexOf(String str)

int IastIndexOf(String str):

遍历字符串
  • 录入字符串
  • 遍历字符串public char charAt(int index);
  • for(int i=0;i<line.length();i++){
  • System.out.print(line.charAt(i));}
统计字符次数
  1. 录入一个字符串。
  2. 统计三个字符个数,定义三个统计变量初始值都为0
  3. 遍历每一个字符
  4. 判断该字符是哪种类型对应其统计变量加1;
  5. 大写字母:ch>='A'&&ch<='z'
拼接字符串
  1. 定义一个int类型的数组,用静态初始化
  2. 定义一个方法用于把int数组中的数据按照格式拼成一个字符串返回String s="";s+=arr[0];arr[0]会强制转换为字符串类型
  3. 用变量接收结果(s为形参)
字符串反转
  1. 录入一个字符串
  2. 定义一个方法实现反转返回值类型为S听,参数为String s
  3. 在方法中倒着遍历再把字符拼接字符串并返回

StringBuilder概述

原因

String s="hellow";

s+="world";

System.out.println(s);

在堆内存中进行:

  1. 创建一个空间,s存储其地址,其值为hellow
  2. 因为没有world的空间所以创建一个空间存储world
  3. 最后在创建一个空间存储两个字符串拼接在一起的值,s存储最后空间的地址

因为字符串每次拼接都会创造空间,故使用StringBuilder

StringBuilder是可变的字符串类,在其申请的空间中改变值

构造

方法名 说明 格式
public StringBuilder() 创建一个空白可变字符串 StringBuilder sb=new StringBuilder();
public StringBuilder(Srting str) 根据字符串的内容来创建可变字符串对象 StringBuilder sb2=new StringBuilder("hellow");

添加和反转

方法名 说明
public StringBuiler append() 添加数据,并返回对象本身
public StringBuiler reverse() 返回相反的字符序列

append:

  • StringBuiler sb2=sb.append("hellow")
  • sb.append("hellow")
  • sb.append("hellow").append("world").apppend("java").append(100)

reverse:

sb.reverse()

String与StringBuiler的相互转化

StringBuiler转换String通过toString();

String s=toString(sb);

String转换为StringBuiler通过构造方法

String s;StringBuiler sb=new StrngBuiler(s)

定义一个方法把int数组用字符串返回
  • 定义一个int类型的数组并初始化
  • 定义一个方法用于把数字中的数据按指定格式拼接成一个字符串返回(用StringBuiler节省空间)
字符串反转(用StringBuiler)
  • 录入字符串,用Scanner实现
  • 定义一个方法,实现字符串反转。返回值类型为String,参数为String类型
  • 在方法中用StringBuiler实现字符串反转并把结果转成String返回
  • 调用方法,用变量接受并输出。

集合

概述

特点:存储空间可变的存储模型

ArrayList

  • ArrayList array = new ArrayList<>();

  • array.add(e)

  • array.add(1,E)

  • array.remove( Object E)

  • array.remove(int 2)

  • array.set(0,A)

  • array.get(0)

  • array.size()

存储字符串并遍历
  1. 创建一个集合对象
  2. 在集合中添加字符串对象
  3. 遍历集合,首先要获得集合中的每一个元素用get(i)
  4. 遍历要获取集合长度用size()
  5. 通用格式

for(int i;i<array.size();i++){

String s=array.get(i);

System.out.println(s);}

存储学生对象并遍历
  1. 定义学生类,成员变量用String

  2. 创建集合对象

  3. 录入学生数据

  4. 创建学生对象并添加学生数据

  5. 添加学生对象到集合中

  6. 遍历集合

学生管理系统
要求:

1.添加学生
2.删除学生
3.修改学生
4.查看所有学生
5.退出系统

思路:

1.定义学生类{

  • 学号
  • 姓名
  • 年龄
  • 居住地
    标准方法(快捷键alt+insert)
    }
    2.用输出语句完成主界面的编写
    3.用Scanner实现录入数据
    4.用switch语句选择,使用方法实现
    5.用循环再会回到主界面(System.exit()退出Java虚拟机)
添加学生方法编写:

1.定义一个方法
2.提示信息
3.创建学生对象并把数据赋值给学生对象
4.把学生添加到集合中

查看学生方法
  1. 先判断是否有数据
  2. 显示表头信息
  3. 调出数据
删除学生的方法
  1. 提示信息
  2. 录入要删除的学生的信息
  3. 遍历集合删除对象
修改学生的方法
  1. 录入要修改的学生的信息
  2. 创建学生对象
  3. 遍历修改对应的学生信息

解决删除修改时要判断数据不存在问题

解决添加学生学号重复问题

继承

概述

两个类有相同的的特征(变量和方法)

可以使子类继承父类的成员和方法

格式:public class 子类 extends 父类{}

好处:提高了代码的复用性,维护性。

弊端:父类变化子类也变化

继承中的变量访问

在子类中访问一个变量

  • 子类局部范围找
  • 子类成员
  • 父类成员
  • 都不有就报错(不考虑父亲的父亲...)

super关键字

当变量名相同时:

  • this关键字是访问本类的成员变量也可访问其方法

  • super关键字是访问父类的成员变量也可访问其方法

访问子类方法的特点

子类构造方法

子类中的构造方法都会默认访问父类的无参构造方法

每个子类的构造方法会默认有supre()(访问父类的无参构造方法)

父类中无无参构造方法:

  • 用super访问带参构造方法!
  • 手写一个
子类方法
  • 子类有方法调子类的方法
  • 子类没有父类有再调用父类的方法
super的内存执行
方法重写
  • 子类出现与父类一样的方法声明

  • 在子类中加上super.方法(参数)来继承父类的方法

  • @Override是一个注解可以帮我看看方法重写是否相同

  • 父类中的私有方法子类不能重写(父类私有成员是不能被继承的)

  • 子类方法的访问权限不能比父类低(public>默认>私有)

继承的注意

  • 在java中一个类只能继承一个类,只支持单个继承
  • 类支持多层继承
老师和学生;定义老师和学生类,写代码测试,找到其两者的共性内容抽取雏一个父类,用继承的方式改写代码
  1. 定义老师类(姓名,年龄,教书())
  2. 定义学生类(姓名,年龄,学习())
  3. 定义测试类,测试
  4. 抽取共性父类,定义人类(姓名,年龄)
  5. 用继承改写老师类和学生类并给出各自的特有方法
  6. 在测试
猫和狗:直接使用继承实现

就是文件夹,对类进行分类管理

定义

package 包名;

package com.ithema;

手动建包和自动建包

导包

使用不同包:

  • 需要写全路径
  • 导包(简化带包操作)
  • import 包名.类名;
  • improt java.util.Scanner;

修饰符

权限修饰符

修饰符 同一个类中 同包不同类中子类无关类 不同包的子类 不同包的无关类
private
默认
protected
public

final修饰符

  • 修饰变量:表示该变量为常量,不能再次被赋值
  • 修饰方法:表示该方法为最终方法,不能再次被重写
  • 修饰类:表明该类为最终类,不能被继承

修饰局部变量

final修饰基本类型变量为常数,数据值不能变

修饰引用类型变量,地址值不能变,但其内容可以改变。

static修饰符

static关键字是静态的意思
无需创建实例就可以被调动
  • 被类的所有对象共享
  • 可以使用类名调用也可用对象调用

静态成员方法只能访问静态成员

静态方法和静态成员属于类本身,在类加载时就存在

多态

同一个对象,在不同时刻表现出来的不同形态

前提
  1. 继承或实现

  2. 方法重写

  3. 有父类引用指向子类对象

    fu f=new zi();

    当用a调用成员时

    • 成员对象:编译看左边,执行看左边
    • 成员方法:编译看左边,执行看右边
    • 因为成员方法有重写

好处:定义方法的时候,使用父类型作为参数,将来在使用的时候使用具体的子类型参与操作

弊端:不能使用子类特有功能

实际操作

在操作类中用:public void 方法名(fu a){

重写的方法(必须是重写的方法别的方法不行)

}在操作中就是使用子类重写之后的方法,都会跳转到子类方法。

当多子类继承父类的时候可以少写代码到达复用性

转型

向上转型:(上面的那个实例

  • 从子类到父类
  • 父类引用指向子类对象

向下转型:(调用子类特殊方法)

  • 从父类到子类
  • 父类引用转为子类对象
  • zi z=(zi)f;把父类引用强转为子类

当运行到Cat cc=(Cat) a;时会报错cat类型不能强转为dog类型(父类可以强转为子类但cat和dog不为子父类关系)

猫和狗案例(变量姓名,年龄,方法:标准类,构造方法有无参,eat方法)多态

抽象类概述

  • 没有方法体的方法被称为抽象方法,有抽象方法的类被称为抽象类

  • 用abstract来修饰

    public abstract class 类名{}

    public abstract void 方法名();

  • 抽象方法一定是抽象类,抽象类中可以有非抽象方法,抽象类中可以没有抽象方法

  • 抽象类中无法创建对象(不能实体化),可以参照多态的使用,通过建立子类对象实例化,这叫抽象类多态

  • 抽象类的子类

    要么重写抽象类中的所有抽象对象

    要么是抽象类

抽象类中的成员特点

  • 抽象类中是包含成员方法,构造方法成员方法
  • 成员变量:可以是变量,也可以是常量
  • 构造方法:不能实体化,用于子类访问父类数据的初始化
  • 成员方法: 可以是抽象方法,必须限定子类完成某些动作,也可是非抽象方法,来提高代码的复用性
猫和狗案例(变量姓名,年龄,方法:标准类,构造方法有无参,eat方法)抽象思想

接口

接口是一种公共行为规范,在java中体现在对行为的抽象

特点
  • 接口是抽象的,用interface修饰,public interface 接口名{}

  • 类实现接口,public class 类名 implements 接口名

  • 接口不能实例化,故参照多态

    多态形式:具体类多态,抽象类多态,接口多态

    前提:有继承或实现关系,有方法重写,有父类\接口指向子类\实现类对象

  • 实现和抽象类一样

成员特点
  • 接口中的变量只能是常量默认修饰符,public static final
  • 构造方法:没有构造方法,默认继承Object类
  • 成员方法:只能是抽象方法,默认修饰符,public abstract
猫和狗,对猫和狗训练就可以跳高了用接口和抽象来完成

类和接口的关系

  • 类和类是继承关系,只能单继承,但可以多层继承

  • 类和接口是实现关系,也可以多实现,还可以在继承一个类的同时实现多个接口

  • 接口和接口是继承关系可以多继承

运动员和教练

现在有乒乓球运动员和篮球运动员,乒乓球,篮球教练,乒乓球的相关人员要出国需要英语要用具体类,抽象类,和接口

思路:

  1. 定义说英语的接口
  2. 定义抽象人类(吃饭)
  3. 定义抽象教练类,继承人类(教)
  4. 定义运动员类继承人类(学)
  5. 定义具体的篮球运动员,乒乓球运动员,篮球教练,乒乓球教练分别重写吃饭学习教说英语

形参和返回值的问题

  • 方法的形参作为类名是需要该类的对象

  • 方法的返回值为是类名,返回的是该类的对象

  • 方法的形参是抽象类名需要的是该抽象类的子类对象

  • 方法返回值是抽象类名,需要的是该抽象类的子类对象

  • 方法的形参是接口名,需要的是该接口的实现类对象

  • 方法的返回值是接口名,返回的是该接口的实现类

内部类

在类中再定义一个类

public class 类名{

修饰符 class 类名{}}

内部类可以直接访问外部类的成员包括私有

外部类要想访问内部类需要创建对象

特点
  1. 成员内部类:在类的成员位置
  • 外部类名.内部类名 对象名=外部类对象.内部类对象
  • Outerus.inner an=new Outer().inner();
  • 一般使用定义方法来调用内部类
  1. 局部内部类:直接写class 类名

    在类的局部位置(在成员方法内)

  • 需要在方法内部创建对象并使用

  • 该类可以直接访问外部类成员,也可访问方法内部的局部变量

    1. 匿名内部类:存在一个接口或类
  • new 类名或接口(){

  • 重写方法;}

  • 本质:是一个继承了该类或实现了该接口的子类匿名对象(可以当对象使用)

  • 接口名 i=new 接口名(){重写方法} 这就是一个接口子类对象

API

若类没有构造方法,看是否是静态的,若是就可以通过类名直接调用

看方法的源码,选中,ctrl b

Math类

概述

无构造方法是静态

直接调用

包含基本数学运算

方法

实例:int b=Math.abs(a);

Math.abs(a);int

Math.ceil(a);double

Math.floor(a);double

Math.round(a);flaot

Math.max(a,b);int

Math.min(a,b);int

Math.pow(a,b);double幂次方

Math.random();返回值为double类型的随机数[0.0,1.0)

System类

一些与系统交互和进行基本系统操作的方法和属性,是无构造方法是静态的类

包含几个常用的方法

方法:

  • System.out.print();

  • public static void exit(int status);终止当前运行的java虚拟机,非零表示异常终止

  • public static long currentTimeMillis();表示返回当前时间(以毫秒为单位)当前时间与1970年之间存在时间

  • System.exit(0);

  • System.currentTimeMillis();用两个相减可以得到程序运行时间

Object类

重写tostring方法

是所有类的祖宗类只有一个无参构造方法

方法名 说明
public String toString() 返回对象的字符串表示形式包含地址,重写后是表示内容自动生成
public boolean equals(Object obj) 比较对象是否相等,默认比较地址,重写可比较内容自动生成

冒泡排序

冒泡排序:只要有大的在后面就会交换

简单选择排序:是只与最大的一个交换位置选择交换

Arrays类

用于查找和排序

直接调用就行

方法名 说明
public static String toString(int[] a) 返回指定数组的内容的字符串表示形式
public static void sort(int[] a) 按照数字顺序排序指定的数组

Arrays.toString(arr)

Arrays.sort(arr)

工具类的设计思想:

  • 构造方法用private修饰
  • 成员用public static修饰

基本类型包装类

将基本数据类型封装为对象的好处是可以在对象中定义更多功能方法操作该数据

常用与基本数据类型与字符串之间的转换

Integer类

Integer包装int类

构造方法:
  • public Integer(int value);public Integer(String s);【过时了】

  • public static Integer valueOf (int i);【现在的】

  • punlic static Integer valueOf(String s);

实例:

  • Integer i1=Integer.valueOf(100);

  • Integer i2=Integer.valueOf("100");

int与String的相互转化

int->String

  1. 字符串参与加法连接从而变成字符串

    String s1=""+number

  2. String s2= String.valueOf(number)

    public static String valueOf(int i);

  • 该方法是String类中的方法是将int转化为String类返回String类

    String->int

  1. Integer i=new Integer.valueOf(s);
    
    int x=i.intValue();
    
    public int intValue();
    
  2. int y=Integer.parseInt(s);
    
    public static int parseInt(String s);
    
  • 该方法是将String类转化为int类返回int
字符串数据排序

思路:

  1. 定义一个字符串
  2. 把字符串遍历取出并转换为int数组
  3. 把int数据排序
  4. 把int数据拼接成字符串

自动装箱和拆箱

装箱:把基本类型转换为包装类型

拆箱:是把包装类型转换为基本类型

Interger i=100;包含自动装箱

i+=200;//i=i+200;i+200自动拆箱,i=i+200;自动装箱

在使用包装类类型的时候最好先判断是否为nulll,nulllbuneng调用方法

Date类

代表了一个时间以毫秒为精度单位

public Date();

public Date(long date);

需要导入

public long grtTime();获得的是日期从1970年1月1日0:00到想在的毫秒值

public void setTime(long time);设置时间,给的是毫秒值

SimpleDateFormat

是一个具体类,用于以区域设置敏感的方式格式化和解析日期。格式化日期和解析

日期和时间格式由日期和时间模式字符串指定,在日期和时间模式字符串中,从A到Z以及从a到z引号的字母被解释为日期或时间字符串的组件的模式字母

字母 说明
y
M
d
H
m
s
构造方法
方法名 说明
public SimpleDateFormat() 构造一个SimpleDateFormat,使用默认模式和日期格式
public SimpleDateFormat(String pattern) 构造一个SimpleDateFormat使用给定的模式和默认的日期格式
格式化和解析日期
  • 格式化:public final String format(Date date)将日期格式化成日期、时间字符串
  • 解析:public Date parse(String source)从给定的字符串开始解析文本以生成日期
Date d=new Date//

SimpleDateFormat sdf=new SimpleDateFormat("yyyy年MM月dd日   HH:mm:ss");

String s=sdf.format(d);//传来的是上面格式的日期

从String到Date

String ss="2024年08月09日 11:11:11";

SimpleDateFormat sdf2=new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");

Date dd=sdf2.parse(ss);//把字符串解析成日期对象

System.out.println(dd);
定义一个日期工具类包含两个方法:把日期转化为指定格式的字符串;把字符串解析为指定格式的日期,然后定义一个测试类
  1. 因为是工具类构造方法要私有化,方法静态

  2. 第一个方法:参数为要转化的日期和代表格式的字符串,再用format方法转换日期再返回字符串日期

  3. 第二个方法:参数为要解析的字符串和字符串的格式,定义SimpleDateFormat 的对象调用parse方法再返回日期

Calendar类

概述

  • 为某一时刻和一组日历字段之间的转换提供了一些方法,并为操作日历提供了方法

  • 用类方法获取Calendar对象 ,期日历字段已使用当前日期和时间初始化:

    Calendar c= Calendar.getlnstance();

public int get(int field) 返回日历字段的值 int year=c.get(Calendar.YEAR);
public abstract void add(int filed,int amount) 将给定的时间量添加或减去给定的日历字段 c.add(Calendar.YEAR,-3)三年前的今天
public final void set (int year,int month,int date) 设置当前日段 c.set(2023,11,11)
二月天获取任意一年的二月有多少天
  1. 录入年份

  2. 设置日历对象的年月日

    年:是录入

    月:三月,月份从零开始所以设置的为2

    日:设置为1天

  3. 三月一日往前推一天即为而与人最后一天

  4. 获取这一天输出即可

异常

概述

就是程序出现了不正常情况

Error:严重问题,不需要处理

Exception:称为异常类,表示程序本身可以处理的问题

  • RuntimeException:在编译期间是不检查的,出问题后修改代码
  • 非RuntimeException:编译期间必须处理,否者不能通过编译(语法问题)
JVM的默认处理方案:
  • 把异常的名称,原因即处理异常出现的位置等信息输出到控制台
  • 程序停止执行

异常处理(手动)

try...catch...

try{

可能出现异常的代码;}

catch(异常类名 变量名){

异常的处理代码}

程序从try里面的代码开始执行出现异常,会自动生成一个异常类对象,该对象将会被提交给java运行时的系统。当java运行时的系统接收到异常对象时,会到catch中去找匹配的异常类,找到后进行处理,执行完毕后程序还会继续往下执行

Throwable的成员方法
public String getMessage() 返回此throwable的详细消息字符串
public String toString() 返回此可抛出的简短描述
public void printStackTrace() 把异常的错误信息输出在控制台上

java中的异常分为两种:编译时异常和运行时异常,也称为受检异常和非受检异常

编译时异常:必需显示处理

运行时处理:无需显示处理,也可和编译时异常一样处理

throws处理异常

有时try...catch..处理不了的异常可以用throws处理

throws 异常类名;这个是跟在括号后面的

把异常抛出去了并没有处理只是让调用者来处理

自定义异常

继承exception

public class 类名 extends Exception{

public 类名(){}

public 类名(String message){

super(message);

}}

还要再设一个使用类:

public class Techer{

public void checkScore(int score) throws 类名{

if(score<0||score>100){

throw new 类名("你给的分数有误")//在方法体内部抛出异常

}else{System.out.println("分数正常");

}

}}
区别
throws throw
用在方法后面,跟的是异常名 用在方法体内,跟的是异常对象名
表示抛出异常,由方法调用者来处理 表示抛出异常由方法体内的语句来处理
表示有出现异常的可能性,并不一定会发生这些异常 执行throw一定抛出了某些异常

集合进阶

集合:是提供了一种存储空间可变的存储模型

集合类体系:

Collection集合:

JDK无具体的实现类,只有更具体的子接口(Set,List)要调用Collection需要自己创建使用多态

是单例集合的顶层接口,表示一组对象,这些对象也称为Collection的元素

创建Collection集合的对象:

  • 多态的方式
  • 具体的实现类ArrayList
  • 要导入

Collection集合的遍历

Iterator:迭代器,集合的专用遍历方式

  • Iterator iterator():返回此集合中元素的迭代器,通过集合的iterator()的方法实现的
  • 迭代器是通过集合的iterator()方法的到的,故它是依赖于集合存在的

常用方法

  • E next():返回迭代中的下一个元素
  • boolean hasNext():如果迭代具有更多元素,则返回true

就是返回下一个元素

Collection<String> c=new ArrayList<String>();

c.add("hellow");

c.add("wrold");

Iterator<String> it=c.iterator();whle

System.out.println(it.Next());

while(it.hasNext){

System.out.println(it.Next);}

集合的使用

  1. 创建集合对象

  2. 添加元素

    2.1 创建元素

    2.2添加元素到集合

  3. 遍历集合

    1. 通过结合对象获取迭代器对象

    2. 通过迭代器对象的hasNext()方法判断是否还有元素

    3. 通过迭代器对象的Next()方法获取下一元素

Collection集合储存学生对象并遍历

创建一个储存学生对象的集合,储存三个学生对象,遍历该集合

思路:

  1. 定义学生类
  2. 创建Collection集合对象
  3. 创建学生对象
  4. 把学生添加到集合
  5. 遍历集合(迭代器方式)

快捷键

  • 直接创造方法返回的类型:在方法写完后ctrl+alt+v

  • 导入构造方法,getxxx方法,setxxx方法:alt+insert

  • 跟进查看源码:ctrl+b

  • 导包ait+enter(回车)

List集合

概述
  • 需要导入
  • 有序集合(也称为序列),用户可以精准的控制列表中的每一个元素的插入位置。用户可以通过整数索引访问元素,并搜索列表中的元素
  • 与Set集合不同,列表允许重复元素
  • 有序:存储和取出的元素顺序一致
  • 可重复:存储的元素可以重复
void add(int inder,E element) 在此集合中的指定位置插入指定的元素
E remove(int inder) 删除指定索引处的元素,返回被删除元素
E set(int inder,E element) 修改指定索引处的元素,返回被修改的元素
E get(int index) 返回指定索引处的元素
List集合存储学生对象并遍历
  1. 定义学生类
  2. 创建List集合对象
  3. 创建学生对象
  4. 把学生添加到集合
  5. 遍历集合(迭代器方式)
并发修改异常:

用迭代器时使用add等方法就会造成并发修改异常;

改用for循环就不会有问题

listlterator列表迭代器

  • 通过List集合的listlerator()方法得到的,所以说它是List集合特有的迭代器

  • 它允许从任意方向遍历集合,在迭代期间膝盖列表,并获得列表中迭代器的当前位置

常用方法:
  • E next():返回迭代中的下一个元素
  • boolean hasNext():如果迭代具有更多元素,则返回true
  • E previous():返回列表的上一个元素
  • boolean hasPrevious():如果此列表迭代器在相反的方向遍历列表是具有更多元素,则返回true
  • void add(E e):将指定元素插入列表

增强for循环

简化数组和Collecttion集合的遍历

  • 实现lterable接口的类允许其对象成为增强型for语句的目标
  • 它是JDK5之后出现的,其内部原理是一个Iterator迭代器

增强for的格式:

for(元素数据类型 变量名:数组或Collection){
    //在此处使用变量即可,变量就是元素
}
int[] arr={1,2,3,4}{
    for(int i:arr){
        System.out.println(i)
    }
}//会输出1,2,3,4
List集合储存学生对象用三种方式遍历
  1. 定义学生类

  2. 创建List集合对象

  3. 创建学生对象

  4. 把学生添加到集合

  5. 遍历集合

    迭代器:集合特有的方式

    for:带有索引的遍历方式

    增强for:最方便的遍历方式

数据结构

栈顶元素,栈底元素,先进后出

队列

队头/前端:出队列

队尾/后端:入队列

先进先出

数组

查询快,增删慢

链表

查询慢,增删快

List集合子类

  • ArrayList:底层数据结构是数组,查询快,增删慢
  • LinkedList:底层数据结构是链表,查询慢,增删快
分别使用ArrayList和LinkedList完成存储字符串并遍历

ArrayList的遍历:

  1. 定义学生类

  2. 创建ArrayList集合对象

  3. 创建学生对象

  4. 把学生添加到集合

  5. 遍历集合

    迭代器:集合特有的方式

    for:带有索引的遍历方式

    增强for:最方便的遍历方式

LinkedList的遍历

  1. 定义学生类

  2. 创建LinkedList集合对象

  3. 创建学生对象

  4. 把学生添加到集合

  5. 遍历集合

    迭代器:集合特有的方式

    for:带有索引的遍历方式

    增强for:最方便的遍历方式

LinkedList集合的特有功能:

set集合

概述

不包含重复元素的集合,是一个接口,要导入

没有带索引的方法,所以不能使用普通for循环

HashSet:对迭代顺序不作任何保证

public static void main (String[] args){
Set<String> set=new HashSet<String>();
set.add("hellow");
set.add("world");
set.add("java");
for(String s:set){
System.out.println(s);
}
} 

哈希值

  • 是JDK 根据对象的地址或字符串或数字算出来的int类型的数组

  • Object类中有一个方法可以获得对象的哈希值

  • pubhlic int hashCode():返回对象的哈希值

  • 同一个对象的哈希值是相同的,默认情况下,不同对象的哈希值是不同的

  • 可以重写hashCode()方法,让不同的对象实现相同

HashSet集合概述和特点

  • 底层数据结构是哈希表
  • 对迭代顺序不作任何保证,不保证存入的顺序和取出的顺序一致
  • 没有带索引的方法,所以不能使用普通for循环
  • 是Set集合,不包含重复元素
  • 要保证元素唯一性,就需要重写hashCode()和equals()【在对象中重写这两个方法】
用哈希表遍历集合

数据结构之哈希表

HashSet集合存储学生对象并遍历
  1. 定义学生类,在其中重写hashCode和equals()方法
  2. 创建HashSet集合对象
  3. 创建学生对象
  4. 把学生对象添加到集合
  5. 遍历集合(增强for)

LinkedHashSet集合

  • 由哈希表和链表实现的Set接口,具有可预测的迭代次序
  • 由链表保证元素有序,也就是说元素的存储顺序和取出顺序是一致的
  • 由哈希表保证元素唯一,也就是说没有重复元素
存储字符串并遍历

TreeSet集合

  • 元素有序,这里的有序是按照一定的规则进行排序,具体的排序方式取决于构造方法

    TreeSet():根据其元素的自然排序进行排序

    TreeSet(Comparator comparator):根据指定的比较器进行排序

  • 没有带索引的方法,所以不能使用普通for循环

  • 无重复元素,要导包

  • 创建集合是使用的是包装类类型,会自动装箱

public static void main(){
TreeSet<Integer> ts=new TreeSet<Integer>();
    ts.add(10);
    ts.add(23);
    ts.add(1);
    ts.add(21);
    for(Interger i:ts){
        System.out.println(i);
    }//会输出1,10,21,23
}
自然排序Comparable的使用
  • 存储学生对象并遍历,创建集合使用无参构造方法

  • 要求:按照年龄从小到大排序,年龄相同时,按照名字字母排序

public static void main(){
TreeSet<student> ts=new TreeSet<student>();
Student s1=new Student("xishi",23);
Student s2=new Student("wangzhuaojun",18);
ts.add(s1);
ts.add(s2);
for(Student s :ts){
System.out.println(s.getName()+","+s.getAge());
}
}

重写comparaTo方法时:

public int comparaTo(Student s){
    int num=this.age-s.age;//this是这个本身的对象,s是上一个的对象
    num==0?this.name.comparaTo(S.name):num;//次要条件姓名不相同
    return num;//主要条件比较年龄从小到大
    //return 0表示重复就只能存储进第一个对象
    //return 1;正数表示用升序来存储
    //return -1;负数表示用降序来存储
}

结论:

  • 用TreeSet集合存储自定义对象,无参构造方法使用的是自然排序

  • 使用类的对象时,其类要实现compareTo接口,重写comparaTo(to)方法

  • 自然排序

  • 重写方法时一定要注意排序规则必须按照要求的主要条件和次要条件来重写

比较器排序Comparator

存储学生对象并遍历使用TreeSet的带参构造方法

public static void main(String[] args){
TreeSet<Student> ts=new TreeSet<Student>(new comparator<Student>(){
public int compare(Sudent s1,Student s2){
   int num=s1.age-s2.age;
   num==0?s1.name.comparator(s2.name):num ;
   return num
}
})//用的是匿名内部类它需要一个comparaTo的实现类子接口
 Student s1=new Student("xishi",23);
Student s2=new Student("wangzhuaojun",18);
ts.add(s1);
ts.add(s2);
for(Student s :ts){
System.out.println(s.getName()+","+s.getAge());   
}
成绩排序
  1. 定义学生类

  2. 创建TreeSet集合对象,通过比较器进行排序或自然排序;

  3. 创建学生对象

  4. 把学生对象添加到集合中

  5. 遍历集合

不重复的随机数
  1. 创建Set集合对象
  2. 创建随机数对象
  3. 判断集合的长度是不是小于10
  4. 遍历集合
  5. 创建随机数方法:Random
Random r=new Random();
int numbe=r.nextInt(20)+1;

泛型

本质是参数化类型,就是将由原来的具体的类型参数化,然后在使用时传入具体的类型

可以分别应用在类,方法和接口中,分别被称为泛型类,泛型方法和泛型接口

泛型定义格式:

  • <类型>:指定一中类型格式。这里的类型可以看成是形参
  • <类型1,类型2...>:指定多种类型的格式,多种类型之间用逗号隔开。这里的类型可以看做是形参
  • 将来具体调用的时候给定的类型可以看作是实参,并且实参的类型只能是引用数据类型

泛型类:

  • 修饰符 class 类名<类型>{}
  • public class Generic{}//T为随意 的任意标识
public class Gener<T>{
private T t;
public T getT(){
return t;
}
public void setT(){
this.t=t;
}
}

Gener g=new Gener();

Gener i=new Gener();

泛型方法

修饰符<类型> 返回值类型 方法名(类型 变量名){}

public<T> void show(T t){

System.out.println(t);
}

g.show("ling");

g.show(122);

g.show("124");

泛型接口

用接口实现的泛型

类型通配符

为了表示各种泛型List的父类,可以使用类型通配符

  • 类型通配符:<?>
  • List<?>:表示元素型未知的List,它的元素可以匹配任何的类型
  • 这种带通配符的List仅表示它是各种泛型类的父类,并不能把元素添加的其中

类型通配符的上限,只表示它是代表某一类泛型List的父类

  • List<? extends Number>:表示的是Number 或者其子类型

类型通配符的下限

  • 类型通配符的下限:<? super 类型>
  • List<?super Number>:表示的是Number或其父类型
List<? > list1=new ArrayList<Object>();
List<? > list2=new ArrayList<Number>();
List<? > list3=new ArrayList<Integer>();
System.out.println("-----------")
List<? extends Number> list4=new ArrayList<Integer>();
List<? extends Number> list5=new ArrayList<Number>();
System.out.println("-----------")
List<? super Number> list6=new ArrayList<Object>();
List<? super Number> list7=new ArrayList<Number>();

可变参数

参数个数可变的方法

public static int sum(int b,int... a){}

注意:

可变参数其实就是一个数组

当包含不变参数时,可变参数要放在最后

使用:
  • Arrays类工具类的静态方法(static)

    public static List asList(T...a):放回由指定数组的大小固定的列表

    不能作增删,能修改

  • List接口中有静态方法:

    public static List of(E...e):返回包含任意数量元素的不可变列表

    不能增删改

  • Set接口中有一个静态方法:

    public static Set of(E...e):返回一包含任意数量元素的不可变集合

    元素不能重复,不能增删改

List<String> list=Arrays.asList("hellow","world","javase");
//list.add("javawed");//会报错,是固定大小的数组
//list.remove("javase")://也会报错
list.set(1,"java");
List<int> listt=List.of(12,24,353,4652);
//listt.add(21);都会报错
//listt.remove(12);都会报错
//listt.set(1,22);都会报错
Set<int> se=Set.of(12,23,234,354);//不能有重复的元素
//se.add(122);//会报错
//se.remove(12会报错
//se.set(1,33);//不能调,没有带索引的方法不存在

Map集合

  • 要导包,是一个接口

  • Interface Map<K,V>,k是键的类型,v是值的类型

  • 将键映射到值的对象;不能包含重复的键每个键可以映射到最多一个值

  • 多态方式,HashMap是具体实现对象

方法 说明
V put (k key,v value) 将指定的值与该映射中的指定值相关联,有唯一性,出现重复的会替代,添加元素
V remove(Object key) 删除键值对元素
void clear() 移除所有键值对元素
boolean containsKey(Object key) 判断集合是否包含指定的键
boolean containsValue(Object value) 判断是否有指定的值
boolean isEmpty() 判断集合是否为空
int size() 集合中键值对的个数
Map<String,String> map=new HashMap<String,String>();
map.put("wa","zhao");
map.put("guo","huang");
map.remove("guo");
map.clear();
获取方法 说明
V get(Object key) 获取键对应的值
Set keySet() 获取所有键的集合
Collection values() 获取所有值的集合
Set<Map.Entry<K,V>> entrySet() 获取所有键值对对象的集合
String inw=map.get("wa");
Set<String> key=map.keySet();
Collection<String> values=map.values();
Set<Map.Entry<String,String> en=map.entrySet();
Map集合遍历1
  1. 获取所有键的集合
  2. 遍历键的集合
  3. 根据键去找值

2

  1. 获取键值对对象的集合
  2. 遍历其集合
  3. 获得键和值
  4. getKey()和getValue()获得键和值
HashMap集合存储学生对象并遍历
  1. 定义学生类
  2. 创建HashMap集合对象
  3. 创建学生对象,值是学生对象
  4. 把学生对象添加到集合
  5. 遍历集合(键找值 或 键值对找键和值)
HashMap集合存储学生对象并遍历

要求:键是学生对象,值是居住地,存储多个键值对元素,并遍历,要保证键的唯一性

  1. 定义学生类,重写hashCode()和equals()方法
  2. 创建HashMap集合对象
  3. 创建学生对象
  4. 把学生对象添加到集合
  5. 遍历集合(键找值 或 键值对找键和值)
集合嵌套

ArrayList集合存储HashMap元素并遍历

  • 创建ArrayList集合
  • 创建HashMap集合,并添加键值对元素
  • 把HashMap作为元素添加到ArrayList中
HashMap<String,String> hum1=new HashMap<String,String>();
hum1.put("孙十万","大乔");
hum1.put("周瑜","小乔");
array.add(hum1);
HashMap<String,String> hum2=new HashMap<String,String>();
hum2.put("郭靖","黄蓉");
hum2.put("演过","小龙女");
array.add(hum2);
for(HashMap<String,String> hm:array){
    Set<String> keySet=hm.keySet();
    for(String key:keySet){
        String value=hm.get(key);
        System.out.println(key+","+value);
    }
}

HashMap集合存储ArrayList元素并遍历

  • 创建HashMap集合
  • 创建ArrayList集合,并添加元素
  • 把ArrayList作为元素添加到HashMap中
  • 并遍历
统计字符串中每个字符出现的次数
  1. 录入一个字符串

  2. 创建HashMap集合,键是Character,值是Intrger

  3. 遍历字符串,得到每一个字符

  4. 拿得到的每一个字符到HashMap中去找对应的值,看起返回值

    若返回值为null说明该字符在HashMap中没有,就把它作为键,1作为值存储

    若返回值不为null说明存在,其值加1,然后重新存储该字符和值

  5. 遍历HashMap集合,得到键和值,拼接成a()b()c()

Collections的概述

是针对集合操作的工具类

  • public static <T extends Comparable<?super T>> void sort(List list):将指定的列表按升序排序
  • public static void reverse(List<?> list):反转指定列表中的元素的顺序
  • public static void shuffle(List<?> list):使用默认的随机源随机排序列表
List<Integer> list=new ArrayList<Integer>();
list.add(12);
list.add(2);
list.add(123);
Collections.sort(list);
Collextions.reverse(list);
Collextions.shuffle(list);
ArrayList存储大学生并排序使用Collections
  1. 定义学生类
  2. 创建ArrayList集合对象
  3. 创建学生对象
  4. 把学生对象添加到集合
  5. 使用Collections对ArrayLIst集合进行排序
  6. 遍历集合
Collections.sort(array,new Comparator<Student>(){
public int compara(Student s1,Student s2){
    int num=s1.getAge-s2.getAge();
    int num2=(num==0s1.getName().compareTo(s2.getName()):num);
    return num2;
}
})//这是使用匿名内部类创造了一个VComparator(调试器)子接口的具体实现类来对ArrayList进行排序
模拟斗地主的洗牌,发牌和看牌
  1. 创建一个牌盒
  2. 往牌盒里面装牌
  3. 洗牌:把牌打散
  4. 发牌:遍历集合,给三个玩家发牌
  5. 看牌,就是玩家各自遍历自己的牌

升级版:

  1. 创建HashMap,键是编号,值是牌
  2. 创建ArrayList,存储编号
  3. 创建花色数组,点数数组
  4. 从0开始往HashMap里面存储编号,并存储对应的牌。同时往ArrayList中存储编号
  5. 洗牌(洗编号),用Coolections的shuffle()方法实现
  6. 发牌(发编号),为了保证编号是排序的,创建TreeSet集合接收
  7. 定义看牌的方法(遍历TreeSet集合,获取编号,到HashMap中找对应的牌)
  8. 调用看牌的方法
HashMap<Integer,String> hm=new HashMap<Integer,String>();//创建HashMap,键是编号,值是牌
ArrayList<Integer> array=new ArrayList<Integer>();//创建ArrayList,存储编号
String[] colors={"♦","♣","♥","♠"};
String[] numbers={"3","4","5","6","7","8","9","10","J","Q","K","A","2"};
//创建花色数组,点数数组
int inder=0;
for(String hu:colors){
    for(String mu:numbers){
        hm.put(inder,hu+mu);
        array.add(inder);
        inder++;
    }
}  //从0开始往HashMap里面存储编号,并存储对应的牌。同时往ArrayList中存储编号
hm.put(inder,"小王");
array.add(inder);
inder++;
hm.put(inder,"大王");
array.add(inder);//从0开始往HashMap里面存储编号,并存储对应的牌。同时往ArrayList中存储编号
TreeSet<Integer> lqxSet=new TreeSet<Integer>();//创建角色对象,创建TreeSet集合接收
TreeSet<Integer> wtSet=new TreeSet<Integer>();
TreeSet<Integer> lySet=new TreeSet<Integer>();
TreeSet<Integer> dpSet=new TreeSet<Integer>();
Collections.shuffle(array);//洗牌(洗编号),用Coolections的shuffle()方法实现
for(int i=0;i<array.size();i++){
    int x=array.get(i);
   if(i>=array.size()-3){
       dpSet.add(x);
   } else if(i%3==0){
       lqxSet.add(x);}
    else if(i%3==1){
        wtSet.add(x);
    }else if(i%3==2){
        lySet.add(x);
    }
}// 发牌(发编号),为了保证编号是排序的,创建TreeSet集合接收
lookpoker("林青霞",lqxSet,hm);
lookpoker("王涛",wtSet,hm);
lookpoker("柳岩",lySet,hm);
lookpoker("底牌",dpSet,hm);//看牌
public static void lookpoker(String name,TreeSet<Integer> tt,HashMap hm){
    System.out.print(name+"的牌是:");
    for(TreeSet<Integer> ka:tt){
        String poker=hm.get(ka);
        System.out.print(poker+" ");
}
    System.out.println();
}

Io流

Io:输入/输出(Input/Output)

流:是一种抽象概念,是对数据传输的总称,数据在设备之间的传输称为流

Io流就是用来处理设备之间的传输的问题的,常应用于文件复制,文件下载,文件上传

按数据流向分为;

输入流:读数据

输出流:写数据

按数据类型分:

字节流:字节输入流和字节输出流

字符流:字符输入流和字符输出流

若用记事本打开能看懂就是字符流,是乱码就是字节流,一般使用字节流

File类

file:是文件和目录路径名的抽象表示

  • 文件和目录是可以通过File封装成对象的

  • 对File来说,封装的并不是一个真正存在的文件,仅仅是一个路径名。他可以存在也可以不存在将来是要通过具体操作来把这个路径的内容转化为具体存在的

构造方法
File(String pathname) 通过给定的路径名字字符串转化为抽象路径名来创建新的File实例
File(String path,String child) 从父路径名字符串和子路径名字符串创建新的File实例
File(File parent,String child) 从父抽象路径名和子路径名字符串创建新的File实例
File f1=new File("E\\ithema\\java.txt");
System.out.println(f1);//输出E\\ithema\\java.txt
File f2=new File("E\\ithema","java.txt");
System.out.println(f2);//输出E\\ithema\\java.txt
File f3=new File("E\\ithema");
File f4=new File(f3,"java.txt");
System.out.println(f4);//输出E\\ithema\\java.txt

创建功能
public boolean createNewFile() 当具有该名称的文件不存在时,创建一个有该抽象路径命名的新文件则返回true
public boolean mkdir() 创建由此抽象路径命名的目录
public boolean mkdirs() 创建由此抽象路径命名的目录,包含任意必需但不存在的父目录
File f1=new File("E\\笔记\\java.txt");//创建文件,创建成功则返回true
System.out.ptintln(f1.createNewFile());
File f2=new File("E\\笔记\\javase");//创建目录,创建成功则返回true
System.out.ptintln(f2.mkdir());
File f3=new File("E\\笔记\\javase\\hema");
System.out.ptintln(f3.mkdirs());//一键创建多级目录,创建成功则返回true
File的判断和获取
public boolean isDirectory() 看此抽象路径名是否为目录
public boolean isFile() 是否为文件
public boolean exists() 是否存在
public String getAbsolutePath() 返回绝对路径名字符串
public String getPath() 转化为路径字符串
public String getName() 返回此抽象路径名表示的文件和目录
public String[] list() 返回此抽象路径名表示的文件和目录的名称的字符串数组
public File[] listFiles() 返回此抽象路径名表示的文件和目录的File对象数组
public boolean dalete() 删除此抽象路径表示的文件或目录,一步一步删除要先删除先删除文件

绝对路径: 完整的路径名,不需要任何其他信息就可以定位

相对路径:必须借用其他路径的信息解释

递归

不死神兔

定义一个方法f(n)表示第n个月兔子的对数

那么f(n-1),表示第n-1个月的兔子对数

f(n-2),表示第n-2个月的兔子对数

再加一个出口

递归的出口,且与原问题相似的规模较小的问题

递归求阶乘
public static void jc(int a){
    if(a==1){
        return 1;
    }else{
        return a*jc(a-1);
    }
}

用递归遍历该目录下的所有内容

思路:

  1. 创建一个File对象

  2. 定义一个方法,用于获取目录下的所有内容参数为File

  3. 获取该目录下的所有文件或目录的File数组

  4. 遍历该数组,得到File对象

  5. 判断该File对象是否是目录

    是递归调用

    不是,获取绝对路径输出

  6. 调用方法

字节流

InputStream:这个抽象类是表示字节输入流的所有类的超类

OutputStream:这个抽象类是表示字节输出流的所有类的超类

子类名都是以其父类名作为子类名的后缀

FileOutputStream:文件输出流用于将数据写入File

  • FileOutputStream(String name):创建文件输出流以指定的写入文件
  • 创建了字节输出流对象
  • 调动字节输出流方法写入
  • 释放资源
FileOutputStream fos=new FileOutputStream("developing\\fos.txt");
/*调用系统创建了文件
创建了字节输出流对象
让字节输出流对象指向文件*/
fos.write(97);//在fos文件中写入a,用的是ASKMA值
fos.close//Io操作都要释放资源,关闭输出流并释放相关资源
void write(int b) 将字节写入文件输出流,一次一个字节数据
void write(byte[] b) 将b.length字节从指定的字节数组写入此文件输出流,一次一个字节数组
void write(byte[] b,int off,int len) 从偏移量off开始写入此文件输出流写len个,一次写一个字节数组的部分数据
FileOutputStream fos=new FileOutputStream("developing\\fos.txt");
fos.write(33);
fos.write(353);
fos.write(363);
byte[] bys={97,98,99,100};
byte[] byy="abcd".getBytes();//和上面的那个写入的是一样的都是abcd
fos.write(bys);
fos.write("hellow".getBytes());
fos.write(bys,0,bys.length);//从0开始写入bys.length的字节
fos.close();//释放资源

字节流换行:

window : \r\n

linux : \n

mac : \r

追加写入:

  • public FileOutputStream(String name,boolean append)

  • 创建文件输出流以指定的名称写入文件,若第二个参数为true则将写入文件的末尾而不是开头

字节流写数据加异常处理

finally:在异常处理事提供finally块来执行所有清除操作

finally语句一定执行,除非JVM退出

try{

可能出现异常的代码;

}catch(异常类名 变量名){

异常的处理代码;

}finally{执行所有清除操作;}

字节流读数据

FileInputStream(String name): 通过打开与实际文件的链接来创建一个FileInputStream,该文件由name命名

  • 创建了字节输入流对象
  • 调动字节输入流方法写入
  • 释放资源
int by=fos.read();//一次只能读一个字节的数据,输出的是ASCII值

System.out.println(char(by));//可以强制类型转换,若到达文件末尾值为-1;
int gby;
while((gny=fos.read())!=-1){
    System.out.print((char)gby);
}//循环读取全部
复制文本文件

就是把一个文件的内容从一个文件中读取出来(数据源),再写入另一个文件中(目的地)

思路:

  1. 根据数据源创建字节输入流
  2. 根据目的地创建字节输出流
  3. 读写数据,复制文本(一次读一个字节,一次写一个字节)
FileInputStream fis=new FileInputStream("developing\\fos.txt");
FileOutputStream fos=new FileOutputStream("begin\\fos.txt");
int by;
while((by=fis.read())!=-1){
    fos.write(by);
}
fos.close();
fis.close();
读取一个字节数组

int read(byte[] b):读取最多为b.length个字节的数据到一个字节数组,并返回实际读取到的长度

FileInputStream fis=new FileInputStream("developing\\fos.txt");
byte[] bys=new byte[1024]//1024及其整数倍
    int len;
while((len=fis.read(byte))!=-1){
    System.out.print(new String(byte,0,len));//转换成String
}
fis.close();
复制图片
  1. 根据数据源创建字节输入流
  2. 根据目的地创建字节输出流
  3. 读写数据,复制图片(一次读一个字节数组,一次写一个字节数组)
  4. 释放资源
FileInputStream fis=new FileInputStream("developing\\fos.txt");
FileOutputStream fos=new FileOutputStream("begin\\fos.txt");
byte[] by=new byte[1024];
int len;
while((len=fis.read(by))!=-1){
    fos.write(by,0,len);
}
fos.close();
fis.close();
字节缓冲流

要导包

字节缓冲流:

  • BufferOutputStream: 该类实现缓冲输出流,向底层输出流写入字节,不再调动底层系统
  • 构造方法:BufferedOutputStream(OutputStream out)
  • BufferInputStream: 创建一个缓冲区,流可以从中读取字节,从而填充,一次可以很多字节
  • 构造方法:BufferedInputStream(InputStream in)
  • 字节缓冲流仅仅提供缓冲区,而真正读写数据还得依靠基本的字节流对象操作
//FileOutputStream fos=new FileOutputStream("begin\\fos.txt");
//BufferedOutputStream bos=new BufferedOutputStream(fos);
BufferedOutputStream bos=new BufferedOutputStream(new FileOutputStream("begin\\fos.txt"));//上面两个二合一
bos.write("hellow".getBytes());
BufferedInputStream fis=new BufferedInputStream(new FileInputStream("begin\\fos.txt"));
byte[] by=new byte[1024];
int len;
while((len=fis.read(by))!=-1){
    System.out.print(new String(by,0,len));
}
fis.close;
bos.close;
复制视频
  1. 根据数据源创建字节输入流
  2. 根据目的地创建字节输出流
  3. 读写数据,复制图片(一次读一个字节数组,一次写一个字节数组)
  4. 释放资源

分别使用四种方式实现,并记录时间

  1. 基本字节流,一次读写一个字节 //最慢
  2. 基本字节流,一次读写一个字节数组
  3. 字节缓冲流,一次读写一个字节
  4. 字节缓冲流,一次读写一个字节数 //最快

字符流:

字符流=字节流+编码表

一个汉字存储:

如果是GBK编码,占用2个字节

如果是UTF-8编码,占用3个字节

第一个字节都是负数

编码表:

  • 计算机中的信息存储的使用二进制表示的,英文,汉字都是二进制转换而成的
  • 将字符存储到计算机中,为编码。将存储在计算机的数解析显示出来,为解码

字符编码是一套自然语言的字符与二进制数之间的对应规则(A,65)

字符集:

  • 是一个系统支持的所有字符的集合,包括各个国家的文字,标点,图形,数字等
  • 计算机要准确的存储和识别各种字符集,就要进行字符编码,一套字符集必有一套编码。常见的字符集有ASCII字符集,GBXXX字符集,Unicode字符集
ASCII字符集:

是美国为英文和各种符号,进退等编写的

GBXXX字符集

Unicode字符集

UTF-8编码

字符串中编码解码

编码:

byte[] getBytes():使用平台默认的字符集编码

byte[] getBytes(String charsetName):使用指定的字符集编码

String(byte[] byte):使用平台默认的字符集解码,指定的字节数组来郭建新的String

String(byte[] byte,String charsetName):使用指定的字符集解码

字符流抽象基类

  • Reader :字符输入流的抽象类
  • Wreter :字符输出流的抽象类

字符流中和编码解码相关的类:

  • InputStreamReader:是从字节流到字符流的桥梁(先读再编,可指定)
  • InputStreamReader fis=new InputStreamReader(new FileInputStream("developing\ows.txt"))
  • OutputStreamWriter:是从字符流到字节流的桥梁(先读再编,可指定)
  • OutputStreamReader fos=new OutputStreamReader(new FileOutputStream("developing\ows.txt"))
写读数据
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,int len) 写一个字符串的一部分

字符流有缓冲要刷新,flush()刷新,close()是先刷新再关闭

int read() 一次读一个字符数据
int read(char[] cbuf) 一次读一个字符数组数据
复制java文件
  1. 根据数据源创建字符输入流
  2. 根据目的地创建字符输出流
  3. 读写数据,复制文本(一次读一个字符,一次写一个字符)
  4. 可以简化InputStreamReader,OutputStreamReader
  5. FileReader(String fileName):用于读取字符文件的便捷类
  6. FileWriter(String FileName);用于写入文件的便捷类
//InputStreamReader fis=new InputStreamReader(new FileInputStream("developing\\ows.txt"))//根据数据源创建字符输入流
FileReader fis=new FileReader("developing\\ows.txt")
//OutputStreamReader fos=new OutputStreamReader(new FileOutputStream("developing\\ows.txt"))//根据目的地创建字符输出流
FileWriter fos=new FileWriter("developing\\ows.txt")  
char[] ch=new char[1024];
int len;
while((len=fis.read(ch))!=-1){
    fos.while(ch,0,len);
}
fos.close();
fis.close();
字符缓冲流

BufferedWriter:将文本写入字符输出流,缓冲字符,可指定缓冲区大小,也可默认

BufferedWriter(Writer out);

BufferedReader:从字符输入流读取文本,可指定缓冲区的大小,也可默认

BufferedReader(Reader in)

BufferedWriter bw=new BufferedWriter(new FileWriter(""));

复制java文件(字符缓冲流)
  1. 根据数据源创建字符缓冲输入流
  2. 根据目的地创建字符缓冲输出流
  3. 读写数据,复制文本(一次读一个字符,一次写一个字符)
BuffererdWriter bw=new BufferedWriter(new FileWriter("developing\\ows.txt"));
BufferedReader br=new BuffereReader(new FileReader("developing\\ows.txt")) ;  char[] ch=new char[1024];
int len;
while((len=br.read(ch))!=-1){
    bw.while(ch,0,len);
}
bw.close();
br.close();
viod newLine() 写一行行分隔符,分隔符有系统定义
public String readLine() 读一行文字,结果包含行的内容的字符串,不包括任何终止字符,若到达末尾则为null
BuffererdWriter bw=new BufferedWriter(new FileWriter("developing\\ows.txt"));
BufferedReader br=new BuffereReader(new FileReader("developing\\ows.txt")) ; 
for(int i;i<10;i++){
bw.write("hellow"+1);
bw.newLine();
bw.flush();}
String line;
while((line=br.readLine())!=null){
    System.out.println(line);
}
bw.close();
br.close();

Io流小结

字节流小结

字符流小结

把集合中的数据写入文件

要求:每一个字符串元素作为文件的一行元素

思路:

  1. 创建ArrayList集合
  2. 往集合中存储字符串元素
  3. 创建字符缓冲输出流对象
  4. 遍历集合,得到每一个字符串数据
  5. 调用字符缓冲输出流对象的方法写数据
  6. 释放资源
把文件中的数据读到集合中
  1. 创建字符缓冲输入流对象
  2. 创建ArrayList集合
  3. 调用字符缓冲输入流对象的方法读数据
  4. 那读取的数据存储的到集合中
  5. 释放资源
  6. 遍历集合
点名器

有一个文件存储了同学的名字,每个姓名占一行,要求实现点名器

  1. 创建字符缓冲输入流对象
  2. 创建ArrayList集合
  3. 调用字符缓冲输入流对象的方法读数据
  4. 把独到的数据存储到集合中
  5. 释放资源
  6. 使用Random产生一个随机数范围在【0,集合长度)
  7. 把第6产生的的随机数的作为索引获取值
  8. 输出数据
把集合中的数据写入文件

要求:每一个学生对象数据作为文件的一行元素

思路:

  1. 定义学生类
  2. 创建ArrayList集合
  3. 创建学生对象
  4. 把学生对象添加到集合中
  5. 创建字符缓冲输出流对象
  6. 遍历集合,得到每一个学生对象
  7. 把学生对象拼接成指定格式的字符串
  8. 调用字符缓冲输出流对象的方法写数据
  9. 释放资源
把文件中的数据读到集合中(文件的每一行数据都是学生对象的成员变量值
  1. 定义学生类
  2. 创建字符缓冲输入流对象
  3. 创建ArrayList集合
  4. 调用字符缓冲输入流对象的方法读数据
  5. 把读到的数据用split()进行分割,得到一个字符串数组
  6. 创建学生对象
  7. 字符串数组中的每一个元素取出对应的赋值给学生对象的成员变量值
  8. 把学生对象添加到集合中
  9. 释放资源
  10. 遍历集合
BufferedReader br=new BuffereReader(new FileReader("developing\\ows.txt")) ; 
ArrayList<student> array=new Array<student>();
String line;
while((line=br.readLine())!=null){
    String[] strArray=line.split(",");

String s =new student();
s.setSid(strArray[0]);
s.setName(strArray[1]);
s.setAge(Integer.parseInt(strArray[2]));
s.setAddress(strArray[3]);
array.add(s)}
br.colse();
for(student s:array){
  System.out.println(s.getSid()+","+s.getName+","+s.getAge+","+s.getAddress);
}
集合到文件

键盘录入5个学生信息(姓名,语文成绩,数学成绩,英语成绩)要去按照成绩总分从高到低写入文件

  1. 定义学生类
  2. 创建TreeSett集合,通过比较器比较
  3. 键盘录入学生信息
  4. 创建学生对象,把信息赋值到学生变量中
  5. 把学生对象添加到集合中
  6. 创建字符缓冲输出流对象
  7. 遍历集合,得到每一个学生对象
  8. 把学生对象拼接成指定格式的字符串
  9. 调用字符缓冲输出流对象的方法写数据
  10. 释放资源
复制单级文件夹
  1. 创建数据源目录File对象,路径是E:\itcast
  2. 获取数据源目录File的名称(itcast)
  3. 创建目的地目录File对象,路径名是模块名+itcast组成
  4. 判断目的地对应的File是否存在,不存在就创建
  5. 获取数据源目录下的所有文件的File数组
  6. 遍历File数组,得到每一个File对象,该对象就是数据源文件
  7. 获取数据源文件的名称
  8. 创建目的地文件File对象,路径名是目的地目录+数据源对象名称组成
  9. 复制文件用字节流不光文件还有视频
复制多级文件夹
  1. 创建数据源File对象,路径是E:\itcast

  2. 创建目的地File对象,路径是F:\

  3. 写方法实现文件夹的复制,参数为数据源Flie对象和目的地File对象

  4. 判断数据源Fila是否是目录

    在目的地下创建和数据源File名称一样的目录

    获得数据源File下所有文件或目录File数组

    遍历该File数组,得到每一个File对象

    把该File作为数据源File对象,递归调用复制文件夹的方法

    不是:直接复制

import java.io.*;
public class srcFile {
    public static void main(String[] args) throws IOException {
        File srcFile =new File("E:\\笔记");
        File desFile =new File("F:\\");
        copyFilder(srcFile,desFile);}
        public static void copyFilder(File srcFile,File desFile) throws IOException {
            if(srcFile.isDirectory()){
                String srcFileName=srcFile.getName();
                File newFolder =new File(desFile,srcFileName);
                if(!newFolder.exists()){
                    newFolder.mkdir();
                }
                File[] fileArray = srcFile.listFiles();
                for(File file:fileArray){
                    copyFilder(file,newFolder);
                }
            }else{
                File newFile = new File(desFile,srcFile.getName());
                copyFile(srcFile,newFile);
            }   }
        public static void copyFile( File srcFile,File desFile) throws IOException {
            BufferedOutputStream fos=new BufferedOutputStream(new FileOutputStream(desFile));//上面两个二合一
            BufferedInputStream fis=new BufferedInputStream(new FileInputStream(srcFile));
            byte[] str=new byte[1024];
            int len;
            while((len=fis.read(str))!=-1){
                fos.write(str,0,len);
            }
            fos.close();
            fis.close();
        }
    }

复制文件的异常处理

之前的:

try{

可能出现异常的代码;

}catch(异常类名 变量名){

异常的处理代码;

}finally{执行所有清除操作;}

JDK7的改进:不用抛异常

try(定义流对象){

可能出现异常的代码;}

catch(异常类名 变量名){

异常的处理代码;}

JDK9的改进:要抛出异常

定义输出流对象;

定义输入流对象;

try(输入流对象;输出流对象){

可能出现异常的代码;}

catch(异常类名 变量名){

异常的处理代码;}

特殊操作流

标准输入输出流

  • public static final InputStream in:标准输入流。通常该流对应于键盘输入或主机环境或用户指定 的另一个输入源

  • public static final PrintStream out:标准输出流。通常该流对应于显示输出或主机环境或用户指定的另一个输出目标

  • 标准输入流 System.in

  • 自己实现键盘录入数据:

    BufferedReader br=new BufferedReader(new InputStreamReader(System.in));

  • 这么写太麻烦,java就提供了一个实现键盘录入

  • Scanner sc=new Scanner(System.in);

  • 标准输出流 :System.out

  • 能够方便的打印各种值

  • System.out.println();本质是一个标准的输出流

  • PrintStream ps=System.out;

  • PrintStream类特有的方法,System.out都可以使用

打印流

概述:

分类:

字节打印流

字符打印流

特点:

只输出数据不读取数据,有自己的特有方法

字节打印流:
  • PrintStream(String FileName):使用指定文件名创建新的打印流对象
  • 使用继承父类的方法写数据的时候会转码(ps.write()) ,使用自己特有的方法写数据原样输出(ps.print(33);ps.println()😉
字符打印流:
PrintWriter(String fileName) 使用指定的文件名创建一个新的PrintWriter,而不需要刷新
PrintWriter(write out,boolean autoFlush) 创建一个新的PrintWrite ,out:字符输出流 ,autoFlush:一个布尔值,为真则println,printf或format方法刷新缓冲区
PrintWriter pw=new printWriter("develop\\pw.txt",true);
pw.println("hellow");
pw.println("world");
pw.close();
复制java文件(用打印流)
  1. 根据数据源创建字符缓冲输入流
  2. 根据目的地创建字符打印流
  3. 读写数据,复制文本(一次读一个字符,一次写一个字符)

对象序列化流

对象序列化:就是将对象保存到磁盘中,或在网络中传输对象

这种机制就是使用一个字节序列表示一个对象,该字节序列包含:对象的类型,对象的数据和对象中存储的属性等信息

  • 对象序列化流:ObjectOutputStream
  • 对象反序列化流:ObjictInputStrream
对象序列化流:ObjectOutputStream
  • 将Java对象的原始数据类型和图形写入OutputStream.可以通过使用流的文件来实现对象的长时间保存,若流是网络套接字流,则可以在另一个主机或另一个进程中重构对象
  • 构造方法:OutputStream(OutputSream out)
  • 序列化对象的方法:void writeObject(Object obj):将其写入OutputStream
  • 一个对象要实现序列化,该对象所属的类必须实现Serializable接口,Serializable接口是一个标记接口,不用重写方法
对象反序列化流:ObjictInputStrream
  • ObjictInputStrream反序列化先前使用的bjectOutputStream编写的原始数据和对象
  • 构造方法:ObjictInputStrream(InputStrream in)
  • Objict readObject():从ObjictInputStrream中读取一个对象
//反序列化
public static void read() throwsIOException,ClassNotFoundException{
    ObjectInputStream ois = new ObjectInputStream(new FileInputStream()) ;
    Object obj=ois.readObject();
    student s= (student) obj;
    System.out.println(s.getName()+","+s.getAge())
        ois.close();
}

用对象序列化了一个对象后,修改了对象所属的类文件,若不加serialersionUID会报错

private static final long serialVersionUID=42L;

如果一个对象的某个成员变量不想被序列化,要给该成员加transient关键字修饰,该关键字标记的成员变量不参与序列化过程

Properties

概述

  • 是一个Map体系的集合类
  • Properties可以保存到流中或从流中加载
  • ProPerties prop = new Properties();默认使用Object
Object setProperty(String key,String value) 设置集合的键和值,都是String类型的,底层调用Hashable方法 put
String getProperty(String key) 使用此属性列表中指定的键搜索属性
Set stringPropertyNames() 从属性列表中返回一个不可修改的键集,其中键及其对应的值是字符串

ProPerties与Io流结合的方法

方法名 说明
void load(InputStream inStream) 从输入字节流读取数据列表(键和元素对)
void load(Reader reader) 从输入字符流读取属性列表(键和元素对)
void store(OutputStream out,String comments) 将此属性列表(键和元素对)写入此ProPerties表中,以适合与使用load(InputStream)方法的格式写入输出字节流
void store(Write write,String comments) 将此属性列表(键和元素对)写入此ProPerties表中,以适合与使用load(InputStream)方法的格式写入输出字符流
游戏次数

需求:请写一个猜数字小游戏只能玩三次,若还想玩请充值

思路:

  1. 写一个游戏类,里有一个猜数字小游戏

  2. 写一个测试类,测试类中有main()方法

    A:从文件中读取到Properties集合,用load方法实现

    ​ 文件已经存在:game.txt

    ​ 里面有一个数据值:count=0;

    B:通过Properties集合获取到玩游戏的次数

    C:判断次数是否到达3次,

    到了给提示

    不到:

    ​ 玩游戏,次数加1,重回写回文件,用Properties的store()方法实现

public static void main(String[] args) throws IOException {
        Properties prop =new Properties();
        FileReader fr=new FileReader("E:\\Java\\study\\basis\\练习\\developing\\src\\Gather\\game.txt");
        prop.load(fr);
        fr.close();
        String w = prop.getProperty("count");
        int ww=Integer.parseInt(w);
        if(ww>=3){
            System.out.println("游戏次数不够请充值,(www.platgame)");
        }else{
            playgame.guess();
            ww++;
            FileWriter fw=new FileWriter("E:\\Java\\study\\basis\\练习\\developing\\src\\Gather\\game.txt");
            prop.setProperty("count",String.valueOf(ww));
            prop.store(fw,null);
        }
    }

多线程

进程

是正在运行的程序

线程

是进程中的单个顺序控制流,是一条执行路径

  • 单线程:一个进程只有一条执行路径
  • 多线程:一个进程有多条执行路径

多线程的实现方式

方式1:继承Thread类

  • 定义一个类MyThread继承Thread类
  • 在MyThread类中重写run()方法
  • 创建MYThread类的对象
  • start()方法启动线程

run()方法是u用来封装被执行线性程序的代码

run():封装线性执行程序,直接调用相当于普通方法调用

start():启动线程;由JVM调用此线程的run()方法

设置和获取线程名称的方法

  • void setName(String name): 更改线程名称
  • String getName():得到线程名称
  • 构造方法:在自定类中提供带参构造方法,super(name)

获取main()方法的线程名称:

public static Thread currentThread():返回对当前正在执行的线程对象的引用

再获取线程名称

线程调度

  • 分时调度模型:所有线程轮流使用CPU的使用权,平均分配每个线程占用的CPU时间
  • 抢占式调度模型:优先让优先级高的现线程使用CPU,若优先级相同,则随机选择,优先级高的CPU获取的CPU时间片相对长
  • java使用的是抢占式调度模型

假设计算机只有一个CPU,那么CPU在某一个时刻只能执行一天指令。所以说多线程程序的执行具有随机性

Thread类中设置和获取线程优先级的方法:

  • public final int getPriority():返回此线程的优先级

  • public final void setPriority(int newPriority):更改此线程的优先级

    线程默认优先级是5;范围是1~10

    线程优先级高只表示线程获取CPU的时间片几率高,但是要在次数比较多,或多次运行的时候才能看到你想要的结果

线程控制

static void sleep(long millis) 使当前正在执行的线程停留(暂停执行)指定的毫秒数
void join() 等待这个线程死亡
void setDaemon(boolean on) 将此线程标记为守护线程,当运行的线程都是守护线程是java虚拟机将退出,随主线程的退出而停止

若有程序在主函数中先运行主函数最后运行run()线程

 public static void main(String[] args) {
        MyThread mt = new MyThread("张飞");
        MyThread mn = new MyThread("关羽");
//        mt.start();
//        mn.start();
        mt.setName("野蛮");
        mn.setName("武圣");
        mn.setPriority(9);
        mn.start();
        mt.start();
        System.out.println(mt.getPriority());

    }

多线程的实现方式

方式2:实现Runnable接口

  1. 定义一个类MyRunnable实现Runnable接口
  2. 在MyRunnable类中重写run()方法
  3. 创建MyRunnable类的对象
  4. 创建Thread类的对象,把MyRunnable对象作为构造方法的参数
  5. 启动线程

好处:

  • 避免了java单继承的局限性
  • 适合多高相同的程序的代码区处理同一个资源的情况,把线程和程序的代码,数据有效分离,较好的体现离面向对象的设计思想
MtRunnable my=new MyRunnable();
Thread t1=new Thread(my,"高铁");//构造方法:Runnable的实现子类和线程的名称
Thread t2=new Thread(my,"飞机");
t1,start();
t2.start();
卖票

有三个窗口卖票,共有100张票

  1. 定义一个类SelllTicket实现Runnable接口,里面定义一个成员变量:private int tickets=100;

  2. 在SellTicket类中重写run()方法实现卖票,并告知是那个窗口卖的

    A:判断票数打印0,就卖票,并告知那个窗口卖的,每次出票的时间为0.1秒

    B:卖票之后,中票数减1

    C:票没有了,也可能有人来问,故让卖票的动作一直执行

  3. 定义一个测试类SellTicktDemo,里面有main方法

    A:创建SellTicket类的对象

    B:创建三个Thread类的对象,把SellTicket对象作为构造方法的参数,并给出对应的窗口名称

    C:启动线程

相同的票出现了多次:当t1线程抢到的CPU之后要休息0.1秒,之后t2线程重复

线程执行的随机性:当第一个语句执行完后,第2个语句可能会被别的线程抢占

多线程的数据安全问题:

  • 多线程环境
  • 共享数据
  • 多条语句操作共享数据

解决安全问题:

让程序没有安全数据环境

把多条语句操作共享数据的代码给锁起来,让任意时刻只能有一个线程执行,java提供了同步代码块的方式来解决

格式:

  • synchronized(任意对象){
  • 多条语句操作共享数据的代码}
  • synchronized(任意对象):就相当于给代码加上了锁,任意对象可以看成是一把锁

好处:解决了多线程的数据安全问题

弊端:但线程衡多是,因为每个线程都会去判断同步上的锁,这是很耗费资源的,无形中会降低程序的运行效率

同步方法

就是把synchronized加到方法上

  • 格式:
  • 修饰符 synchronized 返回值类型 方法名(方法参数){}
  • 同步方法的锁对象是: this

同步静态方法:就是把synchronized关键字加到静态方法上

  • 格式:
  • 修饰符 static synchronized 放回值类型 方法名(方法参数){}
  • 同步静态方法的锁对象是: 类名.class

线程安全的类

StringBUffer:

Vector:

Hashtable:

可以使用Collections.synchronizedList(List list)返回指定列表支持的同步列表

List list = Collections.synchronizedList(new Arraylist());

将线程不安全类变成线程安全类

Lock锁

是接口,是一个锁对象

提供比使用synchronized方法和语句更广泛的锁定操作

  • void lock():获得锁
  • void unlock():释放锁

Lock是接口不能直接实例化,这里才用实现类ReentrantLock来实例化

  • ReentantLock():创建一个ReentrantLock的实例

生产者消费者

概述

省常中消费者模式是一个十分经典的多线程协助的模式

有2个线程:

  • 一个是生产者线程用于生产数据
  • 一列是消费者线程用于消费数据

为解耦生产者和消费者的关系,通常会在用共享的数据区域

  • 生产者生产数据之后直接凡在共享数据区域中,并不关心消费者的行为
  • 消费者中需要从共享数据区域中去获取数据,并不关心生产者的行为

Object类的等待和唤醒方法

void wait() 倒着当前线程等待,直到另一个线程调用该对象的notify()方法或notifyAll()方法
void noify() 唤醒正在等待对象监视器的单个线程
voidnotifyAll() 唤醒正在等待对象监视器的所有线程
奶箱类生产者与消费者

网络编程

概述

计算机网络:将不同的独立的多台计算机及其外部设备,通过通信路线连接起来,在饿忘了操作系统,网络管理软件及网络通信协议的管理和协调下,实现资源共享和信息换的的计算机系统

网路编程:在网络通信协议下,实现网络互连的不同计算机上运行的程序间可以实现数据交换

网络编程三要素
  1. IP地址:为网络中的计算机指定一个标识号,通过标识号来指定要接收的计算机和识别发送的计算机,IP就是这个标识号
  2. 端口:端口号就是唯一标识设备中的应用程序的,是应用程序的标识
  3. 协议:网络规定 UDP协议和TCP协议

IP地址

IPv4:是给连接在网络的主机分配的一个32bit地址,为4个字节

IPv6:每16个字节为一组,分成8组16进制数,128为地址长度

命令:

  • ipconfig:查看本机IP地址
  • ping IP地址:检查网络是否联通

特殊IP地址:

127.0.0.1:是回送地址,可以代表本机地址,一般用来测试使用

InetAddress类

InetAddress:此类表示Internet协议(IP)地址

static InetAddress grtByName(String host) 确定直接名称的IP地址,主机名称可以是机器名称,也可以是IP地址
String getHostName() 获取此IP地址的主机名
String getHostAddress() 返回文本显示中的IP地址字符串
端口

端口:设备上应用程序的唯一标识

端口号:用两个字节表示的整数,它的取值范围是065535.起重工01023之间的端口号用于一些知名的网路服务和应用,若端口号被另一个服务或应用所占用,会导致当前程序启动失败

协议:

UDP协议:消耗资源小,通信效率高,但不确定接收端是否存在

TCP协议:建立连接在传输数据,保证了数据传输的安全

UPD通信原理

是一种不可靠的网络协议,它在两端建立一个Socket对象,Socket只是发送,每有客户端和服务器的概念

发送数据
  1. 创建发送端的Socket对象(DatagramSocket)

    DatagramSocket()

  2. 创建数据,并把数据打包

    DatagramPacket(byte[] buf,int length,InetAddress address,int port)

  3. 调用DatagramSocket对象的方法发送数据

    void send(DatagramPacket p)

  4. 关闭发送端

    void close()

接收数据
  1. 创建接收端的Socket对象(DatagramSocket)

    DatagramSocket(int port)

  2. 创建一个数据包,用于接收数据

    DatagramPacket(byte[] buf,int length)

  3. 调用DatagramSocket对象的方法接收数据

    void receive(DategramPacket p)

  4. 解下数据包,并包数据在控制台上显示

    byte[] getDate()

    int getLength()

  5. 关闭接收端

    void.close()

TCP通信原理

步骤:

  1. 创建客户端的Socket对象(Socket)

    Socket(String host,int port)

  2. 获取输出流,写数据

    OutputStream getOutputStream()

  3. 释放资源

    void close()

Socket s=new Socket("192.168.2.93",30006)
    
    OutputStream os=s.getOutputStream();
os.write("hellow,wrold,".getBytes())
    s.close();

要进行三次握手

TCP接收数据

  1. 创建服务器端的Socket对象(ServerSocket)
  2. 获取输入流,读数据,并把数据显示在控制台
  3. 释放资源
ServerSocket ss= newServerSocket;
Socket s=ss.accept();
InputStream is==s.getInputStream();
btte[] bys = new byte[1024];
int len=ia.read(bys);
String data = newString(bts,0,len);
System.out.println("数据是:"+data);
s.close();
ss.close();

客户端:发送数据,接收服务器反馈,数据来自着键盘录入,知道输入的数据是886,发送数据接收

服务器:接收到的数据在控制台输出,并写进文本文档

客户端:

Socket s =new Socket("192.168.2.93",30002)
BuuferReader br = new BufferedReader(new InputStreamReader(System.in));
String line;
while((line=br.readLine()!=null){
    if("886".equals(line)){
        break;
    }
BufferedWriter bw=new BufferedWreite(new OutputStream(s.getOutputStream()));
    bw.write(line);
    bw.newLine();
    bw.flush();
    s.close();
    bw.close();
    bw.close();
}

服务器:

SreverSocket ss=new SeverSocket(30002);
Socket s=ss.accept();
BufferdReader br=new BufferedReader(New inputStreamReader(s.getInputStream()));
BufferedWrite bw=new BufferedWrite(new FileWriter(""))\\路径
String line;
while((line = br.readline())!=null){
    System.out.println(line);
    bw.write(line);
    bw.newLine();
    bw.flush();
}
BufferedWrite bwSeret=new BufferdWrite
ss.close();
bw.close();
练习5

客户端:数据来着文本,接受服务器反馈

服务器:接收到的数据写入文本,给出反馈

出现问题:程序一直等待

原因:读数据的方法是阻塞式的

解决:自定义结束标志;使用shutdownOutput()方法

结束标记:shutdownOutput()

练习6

多个线程的输入输出

服务器多线程:

ServerSocket ss= new SreverSocket(30002);
Socket s=ss.accept();
while(true){
new Thread(new ServerThread(s)).start();
}

Lambda表达式

函数式编程思想

做什么

Lambda表达式的标准格式

格式:(形参)->{代码块}

  • 形参:如果有多个参数,参数之间用逗号隔开;如果没有参数,留空即可
  • ->:有英文中的画像和大于符号组成,固定写法,代表指向动作
  • 代码块:之前的方法体

使用前提:

有一个接口,且接口只有一个抽象方法

练习

定义一个接口,且只有一个抽象方法,在主方法中使用方法

public static void useFilable(Filable f){
    f.fly("风车")
}
public static void main(String[] args){
useFlyable((String s)->{
    System.out.println(s);
    System.out.println("飞机");
})}
省略模式

参数的类型可以省略,但是有多个参数是要一致

参数有一个,小括号也能省略,

代码块只有一条可以省略大括号和分号,如果有return,return也要省略

useFlyable(s->System.out.println(s));

useFlyable((x,y)->x+y);

注意事项

接口中只有一个方法

有上下文环境,1在主函数中有相应的方法,2局部赋值,调用方法的参数

匿名内部类和Lambda表达式的区别

所需类型不同:

  • Lambda表达式必须是接口

  • 匿名内部类:可也是接口,抽象类,具体类,可以多个方法

实现原理不同:

  • 匿名内部类:编译之后,会产生一个单独的.class字节码文件
  • Lambda表达式:编译之后,没有一个单独的.class字节码文件。对应的字节码文件会在运行的时候动态生成

接口的组成更新

接口的组成:

  • 常量
  • 抽象方法
  • 默认方法
  • 静态方法
  • 私有方法

接口中不再只有抽象方法,默认方法等可以有方法体

默认方法
  • 格式:public default 返回值类型 方法名(参数列表){}

  • puublic default void show(){}

  • 可以直接调动方法

注意:

  • 默认方法不是抽象方法,不强制被重写,办事可以被重写,重写的时候去掉default
  • public可以省略,default不能省略
静态方法
  • public static void show(){}
  • 只能被接口调用,不能被实现类调用
私有方法

private 返回值类型 方法名(参数列表){}

private void show(){}

private static void method(){}

在静态方法中只能调用静态方法

方法引用

方法引用符 ::

  • Lambda表达式:usePrintable(s->System.out.println(s));

    参数通过Lambda表达式,传递给System.out.println方法去处理

  • 方法引用:usePrintable(System.out::println);

    风险:直接使用System.out中的pringln方法来取代Lambda,代码更简洁

  • 若使用Lambda,根据“可推导就是可省略”的原则,无需指定参数类型

  • 若是方法引用同样可以根据上下文推导

  • 方法引用是Lambda的孪生兄弟

Lambda表达式支持的方法引用

引用类方法:引用类的静态方法

  • 格式:类名::静态方法
  • Integer::parselent
  • Integer类的方法:pubilc static int parselent(String s)将String转换为int类型数据
  • Lambda表达式被类方法替代的时候,它的形参全部传递给静态方法作为参数
练习:
  1. 定义一个接口(Coinverter,里面定义一个抽象方法

  2. 定义一个测试类(ConverterDemo)在测试类中提供两个方法

    useConverterDemo(Converter c)

    主方法

引用对象的实例方法

:就是引用类中的成员方法

  • 格式:对象::成员方法

  • "HellowWorld"::toUpperCase

    String类中的方将此String索引字符转化为大写

Lambda表达式被对象的实例方法替代的时候,它的形参全部传递到该方法作为参数

引用类的实例方法

:就是引用类的成员方法

  • 格式:类名::成员方法

  • String::substring

  • String中的方法:从beginIndex到endIndex结束,截取字符串。返回一个子串

  • Lambda表到时被类的实例方法代替的时候

    第一个参数作为调用者,后面的参数全部传递给该方法作为参数

public static void main (String[] args){
    useMyString(String::substring);
}
public static void useMyString(MyString my){
    String s=my.myString("Hellowrld",2,6);
    System.out.println(s);
}
引用构造器

就是引用构造方法

  • 格式:类名::new

  • Student::new

Lambda表达式被构造器代替的时候,它的全部形参传递给构造器作为参数

练习:

  • 定义一个类(Student),里面有两个成员变量(name,age)

    并提供无参构造方法和带参构造方法

  • 定义一个接口(StudentBuilder),里面定义一个抽象方法

    Student build(String name,int age);

  • 定义一个测试类(StudentDemo),在测试类中提供两个方法

    一个方法是:useStudentBuilder(StudentBuilder s)

    一个方法是猪方法,在猪方法中调用useStudentBuilder方法

函数式接口

函数式接口:尤其只有一个抽象方法的接口

java中的函数式编程体现就是Lambda表达式,函数式接口就是可以适用于Lambda表达式的接口

只有确保接口中只有一个抽象方法,java中的Lambda才能推导

MyInterface my=()->Systerm.out.println("函数式接口");

函数式注解:@FunctionalInterface放在接口上方,通过就是

函数式接口作为方法的参数

如果方法的参数是一个函数式接口,我们可以使用Lambda表达式作为参数传递

  • startThread(()->System.out.println(Thread.currentThread().getName()+"线程启动了"));

函数式接口作为方法的返回值

方法的返回值是函数式接口

private static Comparator<Student> getComparator(){
    return (s1,s2)->s1.getSid().compareTo(s2.getSid());
}

自定义比较器

常用的函数式接口

  • Supplier接口
  • Consumer接口
  • Predicate接口
Supplier接口

Supplier:包含一个无参的方法

  • T get():获得结果
  • 不需要参数,他会按照某种路基范湖一个数据
  • Supplier接口也被称为生产型接口,指定接口的泛型是什么类型,接口get方法就会生产什么类型数据
private static String getString(Supplier<String> sup){
return suo.get();}
String s=getString(()->"林青霞");

定义一个类提供两个方法

一个用于返回int数据的最大值

一个是主方法interest

public static void main(String[] args){
int[] ar={12,34,5453,2};
    int maxValue=getMax(()->{
        int max=arr[0];
        for(int i=0;i<ar.length;i++){
                if(ar[i]<ma){
                    ma=ar[i] ;} }return ma;  });
    System.out.println(max);}
public static int getMax(Supplier<Integer> r){
        return r.get(); }
Consumer接口
  • void accept(T t):对给定的参数执行此操作
  • default Consumer andThen(Consumer after):返回一个组合的Consumer,依次执行此操作,然后执行after操作
  • Consumer接口也被称为消费型接口,他消费的数据好数据类型由泛型指定
public static void main(String[] args){
    operatorString("林青霞",s->System.out.println(s));
    operatorString("林青霞",s->System.out.println(s),s->System.out.println(new StringBuilder(s).reverse().toString()));
}
public static void operatorString(String name,Consumer<String> con1,Consumer<String> con2){
    con1.andThen(con2).accept(name);
}
public static void operatorString(String name,Consumer<String> con){
    con.accept(name)
}

把字符串按指定的方式打印

Predicate接口
  • boolean test(T t):对给定的参数进行判断(判断逻辑由Lambda表达式实现)返回一个布尔值
  • default Predicate negate():返回一个逻辑的否定,对应逻辑非
  • default Predicate and(Predicate other):返回一个组合判断,对应短路与
  • default Predicate or(Predicate other):返回一个组合判断,对应短路或
  • Predicate接口通常用于判断该参数是否满足条件
boolean b1=checkString("hellow",s->s.length()>8);
boolean b2=checkString("hellowworld",s->length()>8,s->length()<15);

public static void checkString(String s,Predicate<String> pre1,Predicate<String> pre2){
    return pre1.or(pre2).test(s);
    //return pre1.and(pre2).test;
}
public static void checkString (String Predicate<String>){
    return pre.negate().test(s);
}
    
Function接口
  • R apply(T t):将此函数应用于给定的参数
  • default Function andThen(Function after):返回一个组合函数,首先将函数应用于输入,然后将after函数应用于结果
  • Function<T,R>:接口通常用于对参数进行处理,转换(处理逻辑由Lamnda表达式实现),返回一个新的值

要求:将字符串截取得到数字年龄部分,将年龄转成int类型的数据,将int类型的加70输出

String s="林青霞,30";
    convert(s,ss->split(",")[1],ss->Integer.parseInt(ss),i->i+70);

public static void convert(String s,Function<String,String> fun1,Functon<String,Integer> fun2,Function<Integer,Integer> fun3){
    int i = fun1.andThen(fun2).andThen(fun3).apply(s);
System.out.println(i);
}

Stream流

生成方式

  • 生成流:

    通过数据源(集合等)生成流

    list.stream()

  • 中间操作

    多个操作

    filter()

  • 终结操作

    一个流只有一个终结操作

    forEach()

常见的生成方式:
  • Collection体现的结合可以使用默认方法stream()生成流

    default Stream stream()

  • Map体现的集合间的生成流

  • 数据可以通过流

List<String> list=new ArrayList<String>();
Stream<String> liststream = list.stream();//Collection集合的默认方法Set HashSet也有默认方法
Map<String,Integer> map=new HashMap<String,Integer>();
Stream<String> ketStream=map.KeySet().stream();
Stream<Integer> valueStream=map.values().stream();
Stream<Map<String,Integer>> entryStream = map.entrySet().stream();//Map集合间接生成流
Stream<String> strArrayStream = Stream.of("hellow","world"
,"java");
Stream<Integer> intStream=Stream.of(10,12,32);

中间操作
  • Stream filter(predicate predicate):

    Predicate接口中的方法boolean test(T,t);

ArrayList<String> list=new ArrayList<String>();
list.add("林青霞");
list.stream().filter(s->s.startsWith("张")).filter(s->s.lengtrh()==3).forEach(System.out::println);
//1判断过滤
list.stream().skip(2).limit(3).forEach(System.out::println);
//2,3取前几个数据;跳过几个数据
Stream<String> s1=list.stream().limit(4);
Stream<String> s2=list.stream().skip(2);
Stream.concat(s1,s2).distinct().forEach(System.out::println);
//3,4.合并a和b流为一个流
//返回由流的不同元素(根据Object.equals(Object))组成的流,用的是equals方法
list.stream().sorted().forEach(System.out::println);
//返回由此流的元素组成的流,根据自然顺序排序
list.stream().sorted((s1,s2)->{
    int num=s1.length()-s2.length();
    int num2=num==0?s1.comparaTo(s2):num;
return num2;}).forEach(System.out::println);
//排序5,6返回由Comparator的排序之后的流
list.stream().map(s->Integer::parseInt).forEach(System.out::println);
list.stream().mapToInt(Integer::parseInt).forEach(System.out::println);
int result= list.stream().mapToInt(Integer::parseInt).sum();
//有独属于IntStream的方法,sum求和
  • Stream limit(long maxSize):返回此流中的元素组成的流,截取前指定参数个数的数据,取前几个数据

  • Stream skip(long n):跳过指定参数个数的数据,返回由该留的剩余元素组成的流,跳过几个数据

  • static Streram concat(Stream a,Stream b):合并a和b流为一个流

  • Stream distinct():返回由流的不同元素(根据Object.equals(Object))组成的流,用的是equals方法

  • Stream sorted():返回由此流的元素组成的流,根据自然顺序排序

  • Stream sorted(Comparator comparator):返回由Comparator的排序之后的流

  • Stream map(unction mapper):返回由给定函数应用于此流的元素的结果的流

    Function 接口中的方法 Rapply(T t)

  • IntStream mapToInt(TIntFunction mapper):返回一个IntSream其中包含给定函数应用于此流的元素的结果

    IntStream:表示原始int流

    ToIntFunction接口中的方法 int applyAslnt(T value)

常见终结方法
  • void forEach(Consumer action):对此流的每一个元素执行操作

    Consumer接口中的方法 void accept(T t):对参数执行此操作

  • long count():返回此流中的元素数

练习

  1. 有两个集合分别存储6名男演员和6名女演员,
  2. 男演员要名字为3个字段前三人
  3. 女演员只要姓林的,并且不要第一个
  4. 把过滤值后的男演员和女演员合并到一起
  5. 再创建一个集合,存储上面的对象,并遍历数据
Stream.concat(manList.stream().filter(s-.s.length()==3).limit(3),womanList.stream.filter(s->s.startsWith("林")).skip(1)).map(Actor::new).forEach(p->System.out.println(p.getName()));
Stream流的收集操作

Stream流的收集方法

  • R collect(Collector collector)
  • 这个收集参数是一个Collector接口

工具类Collectors提供了具体的收集方式

  • public static Collector toKist():把元素收集到List集合中
  • public static Collector toSet():把元素收集到Set集合中
  • public static Collector toMap(Functon keyMapper,Function valueMapper):把元素收集到Map集合中
Stream<String> listStream = list.stream().filter(s->s.length()==3);
List<String>names=listStream.collect(Collectors.toList());
Stream<Integer> setStream= set.stream().filter(age->age>25);
Set<Integer> ages=setStream.collect(Collection.toSet());
arrayStream.collect(Collectros.toMpa(s->s.split(",")[0],s->Integer.parseInt(s.split(",")[1])));
//对键和值进行操作

类加载

当程序要使用蘑菇类是,若类还未加载到内存中,则系统会通过类的加载,类的连接, 类的初始化这三个步骤来对类进行初始化,

类的加载
  • 就是将类class文件读入内存中国,并为之建立一个java.lang.Class对象
  • 任何类被使用时,系统都会为其奖励一个java.lang.Class对象
类的连接
  • 验证阶段:用于检验被加载的类是否有正确的内部结构,并与其他类协调一致
  • .........
类的初始化

初始化步骤:

类加载机制

全盘机制:就是当类的加载器负责加载加载某个Class是,该Class所依赖的和引用的其他的Class也将由该加载器负责,除非显示使用另一个加载器

父类委托:先让父类的加载器尝试加载该类,父类加载器无法加载该类才从自己的类路径中加载该类

缓存机制:保证所有加载过的Class都会被缓存,当程序血药摸个Class对象时先从缓存中搜索,没有在读取转换成Class对象,并存储到缓存区

ClassLoader:是负责加载类的对象

java运行时具有以下的内置加载器

  • Bootstrap class loader:他是虚拟机的内置类加载器,通常表示null,并且没有复null
  • Platform class loader:平台类加载器可以看到所有平台类包括平台类加载器和其祖先定义的javaSE平台API,其实现类和JDK特定的运行时的类
  • System class loader:它也被称为应用程序加载类,与平台类加载器不同,系统类加载器通常用于定义应用程序类路径,模块路径和JDK特定工具上的类
  • 类加载器的继承关系:System的父加载器为Platform,而Platform的父加载器为Bootstrap

ClassLoader中的方法

static ClassLonder getSystemClassLoader():返回用于委派的系统类加载器

ClassLoader getParent():返回父类加载器进行委派

反射

java反射机制:是值在运行时获取一个类的变量和方法信息,然后通过获取到的信息来创建对象,调用方法的机制。

成员变量:Field[] field

构造方法:Constructor[] cons

成员方法 Menthod[] menthods

获取Class类的对象

要想通过反射去使用一个类,首先要获取Class文件

获取Class文件的方法

  • 是有类的Class属性来获取Class对象。Student.class将会返回Student对应的Class对象
  • 调用对象的getClass方法返回对象的Class对象
  • 使用Class类中的静态方法forName(String className),该方法需要传入字符串参数,字符串参数的值是某个类的全路径,也就是完整包名的路径
Class<Student> c=Student.class;
Class<? extends Student> c3=s.getClass();
Class<?> c4=Class.forName("包名.类名")//完整包名的路径
反射获取构造方法并使用

Class类中用于获取构造方法的方法

  • Constructor<?>[] getConstructors():返回所有公共构造方法对象的数组
  • Constructor<?>[] getDeclaredConstructors():返回所有构造方法对象的数组
  • Constructor<?> getConstructor():返回单个公共构造方法对象
  • Constructor<?> getDeclaredConstructor():返回单个构造方法对象

Constructor类中用于创建对象的方法

  • T newInstance(Object...initargs):根据指定的构造方法创建对象
通过反射实现:

Student s =new Student("林青霞",33,“西安”);

System.out.priontln(s);

基本数据也可获得Class类型

con.setAccessible(true);解除访问权限

Class<?> c=Class.forName("");
Constructor<?> con = c.getVonstructor(String.class,int.class,String.class);
Object obj=con.newInstance("林青霞",30,"西安");
Constructor<?> cin= c.getDeclaredConstructor(String.class);
//获取私有方法
//暴力反射使用私有方法
con.setAccessible(true);
Object obj=con.newInstance("林青霞");
反射获取成员变量并使用
  • Field[] getFields()返回包含Field对象的数组,反映所有可访问的对象

  • Field[] getDetlareFields()返回所有的对象

    例子:field[] s=c.getFields();

  • Field getField (String name):返回一个公共对象

  • Field getDetlareField(String name):返回对象

  • void set(Object obj,Object value):给obj成员变量赋值

    addressField.set(obj,"西安");

反射获取方法并使用
  • Method[] getMethods():返回一个包含方法的数组,公共的,包括继承的

  • Method[] getDeclaredMethods():返回所有方法,不包括继承的

  • Method[] methods = c.getMethods();

  • Method getMethod(String name,Class<?>... parameterTypes):返回一个方法对象,公共的

  • Method getDeclaredMethod(String name,Class<?>... parameterTypes):返回一个方法对象

    Method m=con.getMethod("method");

  • Object invoke(Object obj,Object...args):调用此方法

    Object:表示返回值类型

    obj:调用方法的对象

    args:方法需要的参数

    m.invoke(obj);

通过反射实现

Student s= new Student();

s.method1();

s.method2("林青霞");

String ss=s.method3("林青霞",30);

System.out.println(ss);

s.function();

通过配置文件运行文件类中的方法

模块化

把java分为N个模块

模块的基本使用

  • 创建模块

模块服务

  • 在myOne模块下创建一个包com.ithema_03,在包下提供一个接口,在接口中定义一个抽象方法

    public interface MyService{

    void service();}

  • 在com.ithema_03包下创建一个包impl,在改包下提供接口的两个实现类Itheima和Czxy

GUI

AWT

组件控件

窗体Frame

Frame f=new Frame("名称")

//创建窗体
Frame f=new Frame("我的窗体");
//窗体的大小
f.setSize(300,200);
//窗体的位置
f.setLocation(200,100);
//窗体的背景颜色
f.setBackground(Color.black);
//f.setBackground(new Color(1,2,1));
//设置窗体大小固定
f.setResizable(false);
//设置窗体是否可见
f.setVisible(true);

自定义窗体

package page1;

import java.awt.*;

public class TextFarme extends Frame {
    static int id=0;
    public TextFarme(int x,int y,int w,int h) {
        super("页面"+(++id));
        setSize(w,h);
        setLocation(x,y);
        setBackground(new Color(255,215,255));
        setVisible(true);
        //监听事件结束的,可以正常关闭
         addWindowListener(new WindowAdapter(){
            public void windowClosing(WindowEvent e){
                System.exit(0);
            }
        });
    }

}

panel面板

TextFarme f=new TextFarme(50,50,400,400);
        Panel p=new Panel();
        f.add(p);
//相对于窗体的坐标位置,在窗体内部
        p.setBounds(50,50,200,200);
        p.setBackground(new Color(227, 164, 164));

布局Layout

线性布局(流式布局)FlowLayout

f.setLayout(new FlowLayout(FlowLayout.LEFT,3,3))

不加参数默认居中,LEFT 左,RIGHT 右,水平和垂直间隔为3;

BorderLayout边界布局

f.setLayout(new BorderLayout())

东 EAST

西 WEST

南 SOUTH

北 NORTH

中 CENTER

Butten east=new Butten("东");
f.add(east,BorderLayout.EAST);
GridLayout网格布局
public class one {
    public static void main(String[] args) {
        TextFarme f=new TextFarme(200,200,400,500,"订餐系统");
        GridLayout layout = new GridLayout(2,3);
        Button b1=new Button("one");
        Button b2=new Button("two");
        Button b3=new Button("three");
        Button b4=new Button("four");
        Button b5=new Button("five");
        Button b6=new Button("six");
        f.add(b1);
        f.add(b2);
        f.add(b3);
        f.add(b4);
        f.add(b5);
        f.add(b6);
        f.setLayout(layout);
        f.setVisible(true);
    }

监听器Listener

button上绑定监听器

多个按钮共用一个监听器

TextFarme f=new TextFarme(200,200,400,500,"订餐系统");
GridLayout layout = new GridLayout(2,3);
Button b1=new Button("one");
Button b2=new Button("two");
f.add(b1);
f.add(b2);
MyListener m=new MyListener();
b1.setActionCommend("three");
b1.addActionListener(m);
b2.addActionListener(m);
class MyListener implements ActionListener {
    public void actionPerformed(ActionEvent e) {
        //e.ActionCommand()为按钮的信息,名称
        System.out.println("www"+e.getActionCommand());
        if(e.getActionCommand().equals("one"))P{
            System.out.println("wangtong");
        }
        
        
    }
}

文本框TextField

public class three {
    public static void main(String[] args) {
        new text();
    }
}
class text extends Frame{
    public text(){
        TextField tf=new TextField();
        add(tf);
        setSize(300,400);
        //设置替换编码
        tf.setEchoChar('*');
        MyListener1 m1=new MyListener1();
        tf.addActionListener(m1);
        setVisible(true);
        pack();
    }
}
class MyListener1 implements ActionListener {
    public void actionPerformed(ActionEvent e) {
        TextField text =(TextField)e.getSource();
        System.out.println(text.getText());
        text.setText("");
    }
}

画笔Graphics

import java.awt.*;

public class four {
    public static void main(String[] args) {
         new MyFarme().lacke();
    }
}
class MyFarme extends Frame{

    public void lacke(){
        setBounds(100,100,400,500);
        setVisible(true);

    }
    //画笔,要有颜色
    public void paint(Graphics g){
        g.setColor(Color.red);
        g.fillOval(50,50,150,150);
    }
}

窗体监听WindowAdapter

public class five {
    public static void main(String[] args) {
        new windowFrame().lacke();
    }
}
class windowFrame extends Frame{
    public void lacke(){
        setBounds(50,50,500,500);
        setVisible(true);
        addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e) {
                System.out.println("windowClosing");
                System.exit(0);
            }
            //窗体被激活时使用的
            public void windowActivated(WindowEvent e) {
                windowFrame w =(windowFrame) e.getSource();
                w.setTitle("快来");
                System.out.println("windowOpened");
            }
        });
        Button b1=new Button("Click Me");
        b1.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                System.out.println(e.getActionCommand());
            }
        });
        add(b1);

    }

}

键盘监听KeyAdapter

public class six {
    public static void main(String[] args) {
        new KeyFrame();
    }
}
class KeyFrame extends Frame{
    public KeyFrame() {
        setTitle("KeyFrame");
        setBounds(50,50,300,300);
        setVisible(true);
        addKeyListener(new KeyAdapter() {
            public void keyPressed(KeyEvent e) {
                int key = e.getKeyCode();
                char k=e.getKeyChar();
                if (key == KeyEvent.VK_L) {
                    System.out.println("L");
                }
                System.out.println("keyPressed: " + key);
                System.out.println("key: " + k);
            }
        });
    }
}

JFrame窗体

    public void init(){
        JFrame frame = new JFrame("这个是窗体");
        frame.setVisible(true);
        frame.setBounds(100, 100, 450, 300);
        JLabel l=new JLabel("wangtong");
        frame.add(l);
        //居中对其
        l.setHorizontalAlignment(SwingConstants.CENTER);
        //容器
        Container c=frame.getContentPane();
        c.setBackground(Color.red);

        //关闭窗体事件
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }
    public static void main(String[] args) {
        new Seven().init();
    }

}

弹窗JDialog

public class Seven extends JFrame{

    public Seven(){
        this.setVisible(true);
        this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        this.setBounds(30,30,500,500);
        Container contentPane = this.getContentPane();
        contentPane.setLayout(null);
        JButton b=new JButton("dianjiannie");
        b.setBounds(50,50,100,50);
        b.addActionListener(new ActionListener(){
            public void actionPerformed(ActionEvent e){
                new MyJFrame();
            }
        });
        contentPane.add(b);

    }
    public static void main(String[] args) {
        new Seven();
    }

}


//弹窗
class MyJFrame extends JDialog {
    public MyJFrame() {
        this.setBounds(20, 20, 450, 300);
        this.setVisible(true);
        this.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        Container c=this.getContentPane();
        c.setLayout(null);
//        c.setBackground(Color.yellow);
        c.add(new Label("成功", Label.CENTER));
    }
}

标签

label

new JLabel("xxx")

面板

JPanel

JScrollPanel

按钮

列表下拉框

JScrollPane pane = new JScrollPane(area);
posted @ 2025-04-08 19:52  畏惧不前  阅读(53)  评论(1)    收藏  举报