JAVASE
JRE与JDK
初步了解
1.JRE(Java Runtime Environment)
是Java程序的运行时环境,包含JVM 和运行时所需要的核心类库。我们想要运行一个已有的Java程序,那么只需安装JRE即可
2.JDK (Java Development Kit)
是Java程序开发工具包,包含JRE和开发人员使用的工具其中的开发工具: 编译工具 (avac.exe)和运行具 (ava.exe) 0我们想要开发一个全新的Java程序,那么必须安装JDK
https://tvvffi13ib.feishu.cn/file/boxcnSDkMSKurH2HPTkXHbH2ZKa
常用dos命令
盘符名称 | 盘符切换 |
---|---|
dir | 查看当前路径下的内容 |
cd目录 | 进入单级目录 |
cd.. | 回退到上一级目录 |
cd 目录1\目录\ ... | 进入多级目录 |
cd\ | 回退到盘符目录 |
cls | 清屏 |
exit | 退出命令提示符窗口 |
程序员第一句向世界问好
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello World");
}
}
public static void main (String[] args)
访问修饰符 关键字 返回类型 方法名 string类 字符串数组
基本语法
基本语法
编写 Java 程序时,应注意以下几点:
- 大小写敏感:Java 是大小写敏感的,这就意味着标识符 Hello 与 hello 是不同的。
- 类名:对于所有的类来说,类名的首字母应该大写。如果类名由若干单词组成,那么每个单词的首字母应该大写,例如 * MyFirstJavaClass* 。
- 方法名:所有的方法名都应该以小写字母开头。如果方法名含有若干单词,则后面的每个单词首字母大写。
- 源文件名:源文件名必须和类名相同。当保存文件的时候,你应该使用类名作为文件名保存(切记 Java 是大小写敏感的),文件名的后缀为 .java。(如果文件名和类名不相同则会导致编译错误)。
- 主方法入口:所有的 Java 程序由 public static void main(String[] args) 方法开始执行。
Java 标识符
Java 所有的组成部分都需要名字。类名、变量名以及方法名都被称为标识符。
关于 Java 标识符,有以下几点需要注意:
- 所有的标识符都应该以数字、字母(A-Z 或者 a-z) 、美元符($)、或者下划线(_)开始
- 不能是数字开头
- 不能是关键字
- 标识符是大小写敏感的
- 合法标识符举例:age、$salary、_value、__1_value
- 非法标识符举例:123abc、-salary、#itheima
Java修饰符
像其他语言一样,Java可以使用修饰符来修饰类中方法和属性。主要有两类修饰符:
- 访问控制修饰符 : default, public , protected, private
- 非访问控制修饰符 : final, abstract, static, synchronized
Java 变量
Java 中主要有如下几种类型的变量
- 局部变量
- 类变量(静态变量)
- 成员变量(非静态变量)
Java 数组
数组是储存在堆上的对象,可以保存多个同类型变量。在后面的章节中,我们将会学到如何声明、构造以及初始化一个数组。
Java 关键字
类别 | 关键字 | 说明 |
---|---|---|
访问控制 | private | 私有的 |
protected | 受保护的 | |
public | 公共的 | |
default | 默认 | |
类、方法和变量修饰符 | abstract | 声明抽象 |
class | 类 | |
extends | 扩充、继承 | |
final | 最终值、不可改变的 | |
implements | 实现(接口) | |
interface | 接口 | |
native | 本地、原生方法(非 Java 实现) | |
new | 创建 | |
static | 静态 | |
strictfp | 严格浮点、精准浮点 | |
synchronized | 线程、同步 | |
transient | 短暂 | |
volatile | 易失 | |
程序控制语句 | break | 跳出循环 |
case | 定义一个值以供 switch 选择 | |
continue | 继续 | |
do | 运行 | |
else | 否则 | |
for | 循环 | |
if | 如果 | |
instanceof | 实例 | |
return | 返回 | |
switch | 根据值选择执行 | |
while | 循环 | |
assert | 断言表达式是否为真 | |
catch | 捕捉异常 | |
finally | 有没有异常都执行 | |
throw | 抛出一个异常对象 | |
throws | 声明一个异常可能被抛出 | |
try | 捕获异常 | |
包相关 | import | 引入 |
package | 包 | |
基本类型 | boolean | 布尔型 |
byte | 字节型 | |
char | 字符型 | |
double | 双精度浮点 | |
float | 单精度浮点 | |
int | 整型 | |
long | 长整型 | |
short | 短整型 | |
变量引用 | super | 父类、超类 |
this | 本类 | |
void | 无返回值 | |
保留关键字 | goto | 是关键字,但不能使用 |
const | 是关键字,但不能使用 |
Java注释
public class HelloWorld {
/* 这是第一个Java程序
* 它将输出 Hello World
* 这是一个多行注释的示例
*/
public static void main(String[] args){
// 这是单行注释的示例
/* 这个也是单行注释的示例 */
System.out.println("Hello World");
}
}
Java 基本数据类型
类型 | 存储大小 | 值范围 |
---|---|---|
byte | 1 字节 | -128 到 127 |
short | 2 字节 | -32,768 到 32,767 |
int | 4 字节 | -2的31次方到2的31次方-1 |
long | 8字节 | -2的63次方到2的63次方-1 |
float | 4 字节 | 负数:-3.402823E+38到-1.401298E-45 正数:1.401298E-45到3.402823E+38295 |
double | 8字节 | 负数: -1.797693E+308到-4.9000000E-324 正数:4.9000000E-324 到1.797693E+308 |
char | 2 字节 | 0 到 65,535 |
boolean | 1 字节 | true,flase |
long类型,为了防止不兼容,要加L
float类型,为了防止不兼容,要加F
public class PrimitiveTypeTest {
public static void main(String[] args) {
// byte
System.out.println("基本类型:byte 二进制位数:" + Byte.SIZE);
System.out.println("包装类:java.lang.Byte");
System.out.println("最小值:Byte.MIN_VALUE=" + Byte.MIN_VALUE);
System.out.println("最大值:Byte.MAX_VALUE=" + Byte.MAX_VALUE);
System.out.println();
// short
System.out.println("基本类型:short 二进制位数:" + Short.SIZE);
System.out.println("包装类:java.lang.Short");
System.out.println("最小值:Short.MIN_VALUE=" + Short.MIN_VALUE);
System.out.println("最大值:Short.MAX_VALUE=" + Short.MAX_VALUE);
System.out.println();
// int
System.out.println("基本类型:int 二进制位数:" + Integer.SIZE);
System.out.println("包装类:java.lang.Integer");
System.out.println("最小值:Integer.MIN_VALUE=" + Integer.MIN_VALUE);
System.out.println("最大值:Integer.MAX_VALUE=" + Integer.MAX_VALUE);
System.out.println();
// long
System.out.println("基本类型:long 二进制位数:" + Long.SIZE);
System.out.println("包装类:java.lang.Long");
System.out.println("最小值:Long.MIN_VALUE=" + Long.MIN_VALUE);
System.out.println("最大值:Long.MAX_VALUE=" + Long.MAX_VALUE);
System.out.println();
// float
System.out.println("基本类型:float 二进制位数:" + Float.SIZE);
System.out.println("包装类:java.lang.Float");
System.out.println("最小值:Float.MIN_VALUE=" + Float.MIN_VALUE);
System.out.println("最大值:Float.MAX_VALUE=" + Float.MAX_VALUE);
System.out.println();
// double
System.out.println("基本类型:double 二进制位数:" + Double.SIZE);
System.out.println("包装类:java.lang.Double");
System.out.println("最小值:Double.MIN_VALUE=" + Double.MIN_VALUE);
System.out.println("最大值:Double.MAX_VALUE=" + Double.MAX_VALUE);
System.out.println();
// char
System.out.println("基本类型:char 二进制位数:" + Character.SIZE);
System.out.println("包装类:java.lang.Character");
// 以数值形式而不是字符形式将Character.MIN_VALUE输出到控制台
System.out.println("最小值:Character.MIN_VALUE="
+ (int) Character.MIN_VALUE);
// 以数值形式而不是字符形式将Character.MAX_VALUE输出到控制台
System.out.println("最大值:Character.MAX_VALUE="
+ (int) Character.MAX_VALUE);
}
}
默认值
数据类型 | 默认值 |
---|---|
byte | 0 |
short | 0 |
int | 0 |
long | 0L |
float | 0.0f |
double | 0.0d |
char | 'u0000' |
String (or any object) | null |
boolean | false |
转义字符
符号 | 字符含义 |
---|---|
\n | 换行 (0x0a) |
\r | 回车 (0x0d) |
\f | 换页符(0x0c) |
\b | 退格 (0x08) |
\0 | 空字符 (0x0) |
\s | 空格 (0x20) |
\t | 制表符 |
" | 双引号 |
' | 单引号 |
\ | 反斜杠 |
\ddd | 八进制字符 (ddd) |
\uxxxx | 16进制Unicode字符 (xxxx) |
public class printall {
public static void main(String[] args){
//字符常量输出
System.out.println("lihuibear");
System.out.println("xiaoxiong");
//整数常量
System.out.println(20030304);
System.out.println(-20230512);
//小数常量
System.out.println(13.14);
//字符常量
System.out.println('A');
System.out.println('X');
//布尔常量
System.out.println(true);
System.out.println(false);
//空常量
//空常量不能直接输出
// System.out.println(null);
}
}
类型转换
自动类型转化
数据范围大小(小到大)
byte→short↘
`int→long→float→double`
`char↗`
public class ZiDongLeiZhuan{
public static void main(String[] args){
int a=10;
float b=a;
byte c=11;
short d=c;
System.out.println(a);
System.out.println(b);
System.out.println(c);
System.out.println(d);
}
}
/*
10
10.0
11
11
*/
必须满足转换前的数据类型的位数要低于转换后的数据类型
public class ZiDongLeiZhuan{
public static void main(String[] args){
char c1='a';//定义一个char类型
int i1 = c1;//char自动类型转换为int
System.out.println("char自动类型转换为int后的值等于"+i1);
char c2 = 'A';//定义一个char类型
int i2 = c2+1;//char 类型和 int 类型计算
System.out.println("char类型和int计算后的值等于"+i2);
}
}
//char自动类型转换为int后的值等于97
//char类型和int计算后的值等于66
强制类型转换
1.条件是转换的数据类型必须是兼容的。
2.格式:(type)value type是要强制类型转换后的数据类型
public class QiangZhiZhuanHuan{
public static void main(String[] args){
int i1 = 123;
byte b = (byte)i1;//强制类型转换为byte
System.out.println("int强制类型转换为byte后的值等于"+b);
}
}
//int强制类型转换为byte后的值等于123
运算符
算数运算符
+、-、*、/、%
不同类型,转换为高类型,13.14+10->float;
字符串的+操作->做的是字符串的拼接工作
技巧:从左到右,先遇到字符串就进行拼接,先遇到连续数字就进行+操作
public class yunsuanfu{
public static void main(String[] arges){
System.out.println("lihuibear"+666);
System.out.println(1+99+"lihuibear");
System.out.println("lihuibear"+1+99);
}
}
//lihuibear666
//100lihuibear
//lihuibear199
赋值运算符
public class printall{
public static void main(String[] args){
int i = 10; //把10赋值给int类型的变量i
System.out.println("i:" +i) ;
i += 20; // +- 把左边和右边的数据做加法操作,结果赋值给左边
//i= i + 20;
System.out.println("i:" + i);
//注意: 扩展的赋值运算符底层隐含了强制类型转换
short s = 10;
//s += 20;
s = (short)(s + 20) ;
System.out.println("s:"+ s);
}
}
//进行此类操作的,都最好采用s+=20;这种形式
自增自减
i++先赋值再运算
++i先运算再赋值
关系运算符
基本运算符
逻辑与&
逻辑或| a和b都是false,结果为false,否则为true
逻辑异或^ a和b结果不同为true,相同为false
逻辑非!
短路运算符
短路与
短路或
逻辑与&, 无论左边真假,右边都要执行。
短路与&&,如果左边为真,右边执行;如果左边为假,右边不执行
逻辑或|, 无论左边真假,右边都要执行。
短路或||,如果左边为假,右边执行;如果左边为真,右边不执行
三元运算符
数据输入
导包
import java.util.Scanner
导包的动作必须出现在类定义的上边
创建对象
Scanner sc = new Scanner (System.in);
上面这个格式里面,只有sc是变量名,可以变,其他的都不允许变
接收数据
int i = sc.nextInt() ;
上面这个格式里面,只有i是变量名,可以变,其他的都不允许变
//导包
import java.util.Scanner;
public class printall{
public static void main(String[] args){
//创建对象
Scanner a =new Scanner(System.in);
//接收数据
int aa= a.nextInt();
//输出数据
System.out.println(aa);
}
}
流程控制
顺序结构
分支结构(if,switch)
循环结构(for while, do...while)
三种循环
三种循环的区别
for循环和while循环先判断条件是否成立,然后决定是否执行循环体 (先判断后执行)
do...while循环 先执行一次循环体,然后判断条件是否成立,是否继续执行循环体 (先执行后判断)
for和while的区别
条件控制语句所控制的自增变量i,因为归属for循环的语法结构中,在for循环结束后,就不能再次被访问到了
条件控制语句所控制的自增变量i,对于while循环来说不归属其语法结构中,在while循环结束后,该变量还可以继续使用
死循环格式
for(;😉{} while(true) {} 最常用 do{}while(true);
跳转控制语句
continue用在循环中,基于条件控制,跳过某次循环体内容的执行,继续下一次的执行用在循环中
break基于条件控制,终止循环体内容的执行,也就是说结束当前的整个循环
Random的使用
//导包
import java.util.Random;
//创建对象
Random r= new Random;
//接收数据
int num =r.nextInt(100)+1;
数组
格式
推荐格式
格式一: 数据类型[] 变量名
int[] arr
定义了一个int类型的数组,数组名是arr
格式二: 数据类型 变量名[] int arr[]
定义了一个int类型的变量,变量名是arr数组
动态初始化
int [] arr = new int [3];
左边: int:说明数组中的元素类型是int类型
[]:说明这是一个数组
arr:这是数组的名称
右边: new:为数组申请内存空间
int:说明数组中的元素类型是int类型
[]:说明这是一个数组
3:数组长度,其实就是数组中的元素个数
数组元素访问
//输出数组名,地址分配
System.out.println(arr);
//输出数组元素
System.out.println(arr[0]);
System.out.println(arr[1]);
System.out.println(arr[2]);
内存分配
类型 | 初始值 |
---|---|
整数 | 0 |
浮点数 | 0.0 |
布尔值 | false |
字符 | 空字符 |
引用数据类型 | null |
---------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------
*--------------------------------------------------------------------------------------------------------------------------------------------- **
多个数组 指向相同的内存图,一个数组改变数据值,另外一个数组相应的也改变
静态初始化
public class printall {
public static void main(String[] args) {
//int [] arr = {1,2,3,4};
int [] arr = new int[] {1,2,3,4};
int i;
for(i=0;i<4;i++){
System.out.println(arr[i]);
}
}
}
数组操作的两个问题
索引越界
空指针异常
null
数组常见操作
遍历->for
最大值->max=arr[0];->max
方法
概念
方法(method)是将具有独立功能的组织成为一个整体,使其具有特殊功能的
方法必须先创建才可以使用,该过程称为方法定义 方法创建后并不是直接运行的,需要手动使用后才执行,该过程称为方法调用
方法的定义和调用
一般方法的定义
public static void isEvenNumber(){
//方法体
}
方法的调用
isEvenNumber()
import java.util.Scanner;
public class printall {
public static void main(String[] args) {
Getmax();
}
public static void Getmax(){
Scanner num =new Scanner(System.in);
int a = num.nextInt();
int b = num.nextInt();
int max= (a>b)?a:b;
System.out.println(max);
}
}
带参数的方法定义和调用
带参数的方法定义
带参数的方法调用
形参和实参
带返回值方法的定义和调用
带返回值方法的定义
带返回值方法的调用
方法的注意事项
注意事项
通用格式
方法重载
方法重载指同一个类中定义的多个方法之间的关系,满足下列条件的多个方法相互构成重载
- 多个方法在同一个类中
- 多个方法具有相同的方法名
- 多个方法的参数不相同,类型不同或者数量不同
练习
public class fangfachongzai {
public static void main(String[] args) {
boolean c = compare(10,11);//默认int
System.out.println(c);
boolean d = compare((long)10,(long)11);//强制转换
System.out.println(d);
}
public static boolean compare(int a,int b) {
System.out.println("int");
return a==b;
}
public static boolean compare(long a,long b) {
System.out.println("long");
return a==b;
}
public static boolean compare(byte a,byte b) {
System.out.println("byte");
return a==b;
}
public static boolean compare(short a,short b) {
System.out.println("short");
return a==b;
}
}
//自动选择符合的类型
方法的参数传递
题目演练
1.遍历数组
设计一个方法用于数组遍历,要求遍历的结果是在一行上的。例如:[11,22,33,44,55]
public class pprintarr {
public static void main(String[] args) {
int [] arr ={11,22,33,44,55};
printarr(arr);
}
public static void printarr(int arr []){
System.out.print("[");
for (int i= 0;i < arr.length;i++){
if(i== arr.length-1){
System.out.print(arr[i]);
}
else{
System.out.print(arr[i]+",");
}
}
System.out.println("]");
}
}
2.返回最大值
import java.util.Scanner;
public class getmax {
public static void main(String[] args) {
Scanner scanf =new Scanner(System.in);
int a =scanf.nextInt();
int b =scanf.nextInt();
int c =scanf.nextInt();
getMax(a,b,c);
}
public static void getMax(int a,int b, int c) {
int max1 = (a>b)?a:b;
int max = (max1>c)?max1:c;
System.out.println(max);
}
}
3.减肥计划(switch版)
package lihuibear;
import java.util.Scanner;
public class lihuibear {
public static void main(String[] args) {
Scanner sc = new Scanner (System.in);
int w = sc.nextInt();
jianfei(w);
while(w!=0) {
w = sc.nextInt();
jianfei(w);
}
}
public static void jianfei(int w) {
switch (w){
case 1:
System.out.println("跑步");
break;
case 2:
System.out.println("游泳");
case 3:
System.out.println("慢走");
break;
case 4:
System.out.println("单车");
break;
case 5:
System.out.println("拳击");
break;
case 6:
System.out.println("爬山");
break;
case 7:
System.out.println("好好吃一顿");
break;
default:
System.out.println("星期错误");
}
}
}
4.逢七过
package lihuibear;
public class lihuibear {
public static void main(String[] args) {
printfengqi();
}
public static void printfengqi() {
for(int i = 0;i<100;i++){
if(i/7==0||i%10==7||(i/10)%10==7) {
System.out.printf("%4d",i);
}
}
}
}
5.不死神兔
斐波那契数列
package lihuibear;
public class lihuibear {
public static void main(String[] args) {
feibonaqie();
}
public static void feibonaqie() {
int [] arr = new int[20];
arr[0]=1;
arr[1]=1;
int i;
for ( i= 2; i < 20; i++) {
arr[i]=arr[i-1]+arr[i-2];
}
for ( i= 0; i < 20; i++) {
System.out.printf("%5d",arr[i]);
}
}
}
6.百钱百鸡
需求:我国古代数学家张丘建在《算经》一书中提出的数学问题:鸡翁一值钱五,鸡母一值钱三,鸡维三值钱一百钱买百鸡,问鸡翁、鸡母、鸡维各几何?
public class lihuibear {
public static void main(String[] args) {
Buyji();
}
public static void Buyji() {
int x,y,z;
x=0;
y=0;
for(x= 0 ;x<20;x++){
for(y=0;y<33;y++){
z=100-x-y;
if(z%3==0&&(5*x+3*y+z/3 ==100)){
System.out.printf("%2d,%2d,%2d\n",x,y,z);
}
}
}
}
}
7.数组元素求和
有这样的一个数组,元素是(68,27,95,88,171,996,51,210)。求出该数组中满足要求的元素和
求和的元素个位和十位都不能是7,并且只能是偶数
定义一个数组,用静态初始化完成数组元素的初始化 定义一个求和变量,初始值是0 遍历数组,获取到数组中的每一个元素 判断该元素是否满足条件,如果满足条件就累加
public class lihuibear {
public static void main(String[] args) {
printarrsum();
}
public static void printarrsum() {
int sum=0;
int[] arr={68,27,95,88,171,996,51,210};
for(int i=0;i< arr.length;i++){
if(arr[i]%10!=7&&(arr[i]/10%10!=7)&&arr[i]%2==0){
sum+=arr[i];
}
}
System.out.println(sum);
}
}
8.判断数组是否相同
public class lihuibear {
public static void main(String[] args) {
int[] arr1={11,22,33,44,55};
int[] arr2={11,22,33,44,55};
boolean flag=comper(arr1,arr2);
System.out.println(flag);
}
public static boolean comper(int[] arr1,int[] arr2){
if(arr1.length!=arr2.length){
return false;
}
for (int i= 0;i< arr1.length;i++){
if(arr1[i]!=arr2[i]){
return false;
}
}
return true;
}
}
9.查找下标
package lihuibear;
import java.util.Scanner;
public class lihuibear {
public static void main(String[] args) {
int[] arr = {11, 22, 33, 44, 55};
Scanner sc = new Scanner(System.in);
int a = sc.nextInt();
chazhao(arr, a);
while (true) {
a = sc.nextInt();
chazhao(arr, a);
}
}
public static void chazhao(int[] arr,int a){
int idex=-1;
for(int i=0 ;i<arr.length;i++){
if(arr[i]==a){
idex=i;
System.out.println(idex);
break;
}
}
if(idex==-1) {
System.out.println("无数据");
}
}
}
10.反转输出
package lihuibear;
import java.util.Scanner;
public class lihuibear {
public static void main(String[] args) {
int[] arr = {19,28,37,46,50};
fanzuan(arr);
}
public static void fanzuan(int[] arr) {
for (int start = 0, end = arr.length - 1; start <= end; start++, end--) {
int temp = arr[start];
arr[start] = arr[end];
arr[end] = temp;
}
printarr(arr);
}
public static void printarr(int[] arr){
System.out.print("[");
for(int i = 0; i < arr.length; i++) {
if (i == arr.length - 1) {
System.out.print(arr[i]);
} else {
System.out.print(arr[i] + ",");
}
}
System.out.println("]");
}
}
11.评分
去掉最低最高
增加自我改进,使用sort排序
package lihuibear;
import java.util.Scanner;
public class lihuibear {
public static void main(String[] args) {
int[] arr = new int[6];
Scanner sc = new Scanner(System.in);
for (int i = 0; i < arr.length; i++) {
arr[i] = sc.nextInt();
}
sort(arr);
int max = getmax(arr);
int min = getmin(arr);
jianfa(arr,max,min);
}
public static int getmax(int[] arr) {
int max= arr[0];
for(int i= 0;i< arr.length;i++){
if(arr[i]>max) {
max = arr[i];
}
}
System.out.println("最大值为:"+max);
return max;
}
public static int getmin(int[] arr) {
int min= arr[0];
for(int i= 0;i< arr.length;i++){
if(arr[i]<min) {
min = arr[i];
}
}
System.out.println("最小值为:"+min);
return min;
}
public static void jianfa (int arr [],int max,int min){
int score1 = 0;
for(int i =0 ;i< arr.length;i++){
score1+=arr[i];
}
int score =score1-max-min;
System.out.println("减法:"+score);
}
public static void sort(int[] arr) {
for (int i = 0; i < arr.length - 1; i++) {
for (int j = 0; j < arr.length - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
System.out.print("有序:");
for (int i = 0; i < arr.length; i++) {
System.out.printf("%2d", arr[i]);
}
System.out.println();
int score=0;
for (int i = 1; i < arr.length-1; i++) {
score+=arr[i];
}
System.out.print("sort方法:"+score);
System.out.println();
}
}
类和对象
初步认知
类是对象的数据类型
类是具有相同属性和行为的一组对象的集合
每个对象的每个属性都拥有特定的值
对象能够执行的操作
关系
**类:**类是对现实生活中一类具有共同属性和行为的事物的抽象
对象:是能够看得到摸的着的真实存在的实体
类的定义
//类的定义
public class Phone {
//成员变量
String brand;
int price;
//成员方法
public void call() {
System.out.println("打电话");
public void sendMessage{
System.out.printIn("发短信");
}
对象的使用
代码演示
例题
package lihuibear1;
/*
学生类
*/
public class Student {
//成员变量
String name;
int age;
//成员方法
public void study(){
System.out.println("好好学习,天天向上");
}
public void doHomework(){
System.out.println("键盘敲烂,月薪过万");
}
}
package lihuibear1;
/*
学生测试类
*/
public class StudentDemo {
public static void main(String[] args){
//创建对象
Student s=new Student();
//使用对象
System.out.println(s.name+","+s.age);
s.name="lihuibear";
s.age= 20;
System.out.println(s.name+","+s.age);
s.study();;
s.doHomework();
}
}
内存图
单个对象
成员变量
调用方法成员方法
多个对象
多个对象指向相同
成员变量和局部变量
封装
private关键字
介绍
是一个权限修饰符
可以修饰成员(成员变量和成员方法)
作用是保护成员不被别的类使用,被private修饰的成员只在本类中才能访问
针对private修饰的成员变量,如果需要被其他类使用,提供相应的操作
提供方法,用于获取成员变量的值,方法用修饰
提供方法,用于设置成员变量的值,方法用修饰
package lihuibear1;
/*
学生类
*/
public class Student {
//成员变量
// String name;
// int age;
private String name;
private int age;
public void setName(String n) {
name=n;
}
public String getName() {
return name;
}
public void setAge(int a) {
age=a;
}
public int getAge() {
return age;
}
public void show(){
System.out.println(name+","+age);
}
//成员方法
public void study(){
System.out.println("好好学习,天天向上");
}
public void doHomework(){
System.out.println("键盘敲烂,月薪过万");
}
}
package lihuibear1;
/*
学生测试类
*/
public class StudentDemo {
public static void main(String[] args){
//创建对象
Student s=new Student();
//使用对象
s.setName("lihuibear");
s.setAge(20);
//get方法
System.out.println(s.getName()+s.getAge());
//show方法
s.show();
s.study();
s.doHomework();
}
}
this关键字
代码实现
//Student类中
public void setName(String name){
this.name= name;
}
public String getName(){
return name;
}
public void setAge(int age){
this.age=age;
}
public int getAge(){
return age;
}
原理
封装
是面向对象三大特征之一 (封装,继承,多态)
是面向对象编程语言对客观世界的模拟,客观世界里成员变量都是隐藏在对象内部的,外界是无法直接操作的
将类的某些信息隐藏在类内部,不允许外部程序直接访问,而是通过该类提供的方法来实现对隐藏信息的操作和访问成员变量private,提供对应的getXxx() /setXxx(方法
通过方法来控制成员变量的操作,提高了代码的安全性把代码用方法进行封装,提高了代码的复用性
构造方法
注意事项
1.构造方法的创建
- 如果没有定义构造方法,系统将给出一个默认的无参数构造方法
- 如果定义了构造方法,系统将不再提供默认的构造方法
2.构造方法的重载
- 如果自定义了带参构造方法,还要使用无参数构造方法,就必须再写一个无参数构造方法
3.推荐的使用方式
- 无论是否使用,都手工书写无参数构造方法
标准类制作
package lihuibear1;
/*
学生类
*/
public class Student {
//成员变量
private String name;
private int age;
//构造方法
public Student(){
}
public Student(String name,int age){
this.age=age;
this.name=name;
}
//成员方法
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
public int getAge() {
return age;
}
public String getName() {
return name;
}
//show方法
public void show(){
System.out.println(name+","+age);
}
}
package lihuibear1;
/*
学生测试类
*/
public class StudentDemo {
public static void main(String[] args){
//创建对象
Student s1=new Student();
//构造方法
Student s2=new Student("2lihuibear",20);
//使用对象
s1.setName("1lihuibear");
s1.setAge(20);
//get方法
System.out.println(s1.getName()+","+s1.getAge());
// System.out.println(s2.getName()+","+s2.getAge());
//show方法
s1.show();
s2.show();
}
}
API的使用
帮助文档
String
构造方法
string构造方法
public class lihuibear{
public static void main(String[] args){
//public string();创建一个空白字符串对象,
String s1=new String();
System.out.println("s1"+s1);
//public string(char[] chs);根据字符数组的内容,来创建字符串对象
char[] chs ={'a','b','c'};
String s2=new String(chs);
System.out.println("s2"+s2);
//public string(byte[] bys);根据字节数组的内容,来创建字符串对象
byte[] byt={97,98,99};
String s3= new String(byt);
System.out.println("s3"+s3);
//string s =“abc”;直接赋值的方式创建字符串对象,
String s4 ="abc";
System.out.println("s4"+s4);
}
}
string对象的特点
字符串的比较
练习
用户登录
import java.util.Scanner;
public class lihuibear{
public static void main(String[] args) {
String username = "lihuibear";
String password = "xiaoxiong";
Scanner sc = new Scanner(System.in);
for (int i = 0; i < 3; i++) {
String name = sc.nextLine();
String mima = sc.nextLine();
if (name.equals(username) && mima.equals(password)) {
System.out.println("登陆成功!");
break;
}
if (2-i == 0) {
System.out.println("稍后重试!!!");
} else {
System.out.println("你还有" + (2-i) + "次机会");
}
}
}
}
字符串的遍历
import java.util.Scanner;
public class lihuibear{
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("请输入一个字符串");
String line =sc.nextLine();
System.out.println(line.length());
for(int i= 0;i<line.length();i++){
System.out.println(line.charAt(i));
}
}
}
统计字符个数
1.键盘录入一个字符串,统计该字符串中大写字母字符,小写字母字符,数字字符出现的次数(不考虑其他字符)
import java.util.Scanner;
public class lihuibear{
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("请输入一个字符串");
String line =sc.nextLine();
int a=0,b=0,c=0,d=0;
for(int i= 0;i<line.length();i++){
char ch=line.charAt(i);
if(ch>='A'&&ch<='Z'){
a++;
}else if(ch>='a'&&ch<='z'){
b++;
}else if(ch>='0'&&ch<='9'){
c++;
}
else{
d++;
}
}
System.out.println("大写字母"+a);
System.out.println("小写字母"+b);
System.out.println("数字"+c);
System.out.println("其他"+d);
}
}
2.相同字母,数字多少个
用到了后面的知识
package lihuibear;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
public class lihuibear {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("请输入一个字符串");
String line = sc.nextLine();
Map<Character, Integer> charCount = new HashMap<>();
for (int i = 0; i < line.length(); i++) {
char ch = line.charAt(i);
if (charCount.containsKey(ch)) {
int count = charCount.get(ch);
charCount.put(ch, count + 1);
} else {
charCount.put(ch, 1);
}
}
for (Map.Entry<Character, Integer> entry : charCount.entrySet()) {
System.out.println(entry.getKey() + "有" + entry.getValue() + "个");
}
}
}
字符串反转
package lihuibear;
import java.util.Scanner;
public class lihuibear {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("请输入一个字符串");
String line = sc.nextLine();
String ch = fanzuan(line);
System.out.println(ch);
}
public static String fanzuan(String s){
String ss ="";
for (int i = s.length() - 1; i >=0; i--) {
ss+=s.charAt(i);
}
return ss;
}
}
StringBuilder
作用
减少空间浪费
构造方法
添加与反转
代码
package lihuibear;
import java.util.Scanner;
public class lihuibear {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("请输入一个字符串");
//空内容
StringBuilder a =new StringBuilder();
System.out.println("空内容a:"+a);
//自带内容
StringBuilder aa =new StringBuilder("lihuibear");
System.out.println("自带内容aa:"+aa);
//一般编程
a.append("li");
a.append("hui");
a.append("bear");
System.out.println("一般编程a:"+a);
//链式编程
a.append("li").append("hui").append("bear");
System.out.println("链式编程:a:"+a);
//反转
a.reverse();
System.out.println("反转a:"+a);
}
}
StringBuilder和String的转化
代码
package lihuibear;
import java.util.Scanner;
public class lihuibear {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
StringBuilder sb1 =new StringBuilder();
sb1.append("lihuibear");
System.out.println("append:"+sb1);
String s1 = sb1.toString();
System.out.println("toString法:"+s1);
String s22="lihuibear";
String s2= new String("lihuibear");
StringBuilder sb2 =new StringBuilder(s22);
System.out.println("构造法转换:"+sb2);
}
}
练习
字符串拼接
String->StringBuilder->append->String
字符串反转
String->StringBuilder->reverse->String
package lihuibear;
import java.util.Scanner;
public class lihuibear {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("请输入一个字符串");
String line = sc.nextLine(); // 读取用户输入
String s = myreserve(line); // 调用反转方法
System.out.println(s); // 输出反转后的字符串
}
public static String myreserve(String s) {
//流程
// String->StringBuilder->reverse->String
//1.String->StringBuilder
StringBuilder sb=new StringBuilder(s);
// 2.
// sb.reverse();
// 3.
//String ss =sb.toString();
//一般方法
// StringBuilder sb=new StringBuilder(s);
// sb.reverse();
//String ss =sb.toString();
String ss = new StringBuilder(s).reverse().toString(); // 反转字符串
return ss; // 返回反转后的字符串
}
}
ArrayList
基本使用
ArrayList构造方法和添加方法
方法名 | 说明 | 代码 |
---|---|---|
public ArrayList | 创建一个空的集合对象 | ArrayList <String> arry = new ArrayList<>(); |
public boolen add(E e) | 将指定的元素追加到此集合的末尾 | boolean b = arry.add("world"); |
public void add(int index,E element) | 在此集合中的指定位置插入指定的元素 | arry.add(1,lihuibear) |
public boolen remove(Object o) | 删除指定的元素,返回删除是否成功 | boolen b =arry.remove(“world”); |
public E remove (int index) | 删除指定索引处的元素,返回被删除的元素 | arry.remove(1); |
public E set (int index E element) | 修改指定索引处的元素,返回被修改的元素 | arry.set (1,“lihuibear4”); |
public E get(int index) | 返回指定索引处的元素 | arry.get(0); |
public int size() | 返回集合中元素的个数 | arry.size(); |
一切索引都不能越界
练习
//学生类
package lihuibear;
public class Student {
private String name;
private int age;
public Student(){}
public Student(String name,int age){
this.name=name;
this.age=age;
}
public void setName(String name){
this.name=name;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public int getAge(){
return age;
}
}
import java.util.ArrayList;
public class ArryListStudent {
public static void main(String[] args) {
ArrayList<Student> arry =new ArrayList<>();
Student s1 = new Student("lihuibear0",20);
Student s2 = new Student("lihuibear1",21);
Student s3 = new Student("lihuibear2",22);
Student s4 = new Student("lihuibear3",23);
arry.add(s1);
arry.add(s2);
arry.add(s3);
arry.add(s4);
for (int i= 0;i< arry.size();i++){
Student s = arry.get(i);
System.out.println(s.getName()+" "+s.getAge());
}
}
}
改进
package lihuibear;
import java.util.ArrayList;
import java.util.Scanner;
public class ArryListStudent {
public static void main(String[] args) {
ArrayList<Student> array = new ArrayList<>();
Scanner sc = new Scanner(System.in);
System.out.println("请输入录入的学生人数");
int n = sc.nextInt();
for (int i = 0; i < n; i++) {
addStudent(array);
}
printStudent(array);
}
public static void addStudent(ArrayList<Student> array){
Scanner sc = new Scanner(System.in);
System.out.println("请输入学生姓名:");
String name = sc.nextLine();
System.out.println("请输入学生年龄:");
int age = sc.nextInt();
Student s = new Student();
s.setName(name);
s.setAge(age);
array.add(s);
}
public static void printStudent (ArrayList<Student> array){
for (int i =0 ;i<array.size();i++) {
Student s= array.get(i);
System.out.println(s.getName()+s.getAge());
}
}
}
思路1
public static void gaiStudent(ArrayList<Student> array) {
Scanner sc = new Scanner(System.in);
System.out.println("输入你想要修应该的学生的学号");
String id = sc.nextLine();
// System.out.println("输入学生新姓名");
// String name = sc.nextLine();
// System.out.println("输入学生新年龄");
// String age = sc.nextLine();
// System.out.println("输入学生新地址");
// String address = sc.nextLine();
//
// Student s = new Student();
//
// s.setId(id);
// s.setName(name);
// s.setAge(age);
// s.setAddress(address);
Student s = new Student();
while(true){
System.out.println("输入你想要修应该的内容name输入1 age输入2 address输入3 退出输入4");
s.setId(id);
int nn = sc.nextInt();
switch (nn) {
case 1:
System.out.println("输入学生新姓名");
String name = sc.nextLine();
s.setName(name);
break;
case 2:
System.out.println("输入学生新年龄");
String age = sc.nextLine();
s.setAge(age);
break;
case 3:
System.out.println("输入学生新地址");
String address = sc.nextLine();
s.setAddress(address);
break;
case 4:
System.out.println("谢谢使用!");
System.exit(0);
}
}
for (int i = 0; i < array.size(); i++) {
Student student = array.get(i);
if (student.getId().equals(id)) {
array.set(i, s);
break;
} else {
System.out.println("没有该学生");
break;
}
}
改
public static void gaiStudent(ArrayList<Student> array) {
Scanner sc = new Scanner(System.in);
Student s = new Student();
System.out.println("输入你想要修应该的学生的学号");
String id = sc.nextLine();
for (int i = 0; i < array.size(); i++) {
Student ss = array.get(i);
if (ss.getId().equals(id)) {
array.set(i, s);
if (s.getId().equals(id)) {
System.out.println("输入学生新姓名");
String name = sc.nextLine();
System.out.println("输入学生新年龄");
String age = sc.nextLine();
System.out.println("输入学生新地址");
String address = sc.nextLine();
s.setId(id);
s.setName(name);
s.setAge(age);
s.setAddress(address);
}
else {
System.out.println("没有该学生,重新输入");
gaiStudent(array);
}
}
}
for (int i = 0; i < array.size(); i++) {
Student student = array.get(i);
if (student.getId().equals(id)) {
array.set(i, s);
break;
}
}
练习 学生管理系统
package Studentall;
public class Student {
private String id;
private String name;
private String age;
private String address;
public Student() {}
public Student(String id, String name, String age, String address) {
this.id = id;
this.name = name;
this.age = age;
this.address = address;
}
public void setId(String id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
public void setAge(String age) {
this.age = age;
}
public void setAddress(String address) {
this.address = address;
}
public String getId() {
return id;
}
public String getName() {
return name;
}
public String getAge() {
return age;
}
public String getAddress() {
return address;
}
}
package Studentall;
import lihuibear.ArryListStudent;
import java.util.ArrayList;
import java.util.Scanner;
public class Studentmain {
public static void main(String[] args) {
ArrayList<Student> array = new ArrayList<>();
while (true) {
System.out.println("-----------欢迎来到学生管理系统----------");
System.out.println("1 添加学生");
System.out.println("2 删除学生");
System.out.println("3 查看全部学生");
System.out.println("4 修改学生");
System.out.println("5 退出");
System.out.println("请输入你选择");
Scanner sc = new Scanner(System.in);
int num = sc.nextInt();
switch (num) {
case 1:
System.out.println("添加学生");
addStudent(array);
break;
case 2:
System.out.println("删除学生");
deleteStudent(array);
break;
case 3:
System.out.println("查看全部学生");
findStudent(array);
break;
case 4:
System.out.println("修改学生");
gaiStudent(array);
break;
case 5:
System.out.println("谢谢使用!");
System.exit(0);
}
}
}
//增加
public static void addStudent(ArrayList<Student> array) {
Scanner sc = new Scanner(System.in);
System.out.println("输入学生学号id");
String id = sc.nextLine();
if(idsame(array,id)){
System.out.println("输入学生姓名");
String name = sc.nextLine();
System.out.println("输入学生年龄");
String age = sc.nextLine();
System.out.println("输入学生地址");
String address = sc.nextLine();
Student s = new Student();
s.setId(id);
s.setName(name);
s.setAge(age);
s.setAddress(address);
array.add(s);
System.out.println("添加成功!");
}
else{
System.out.println("已经有该同学了!!!重新输入");
addStudent(array);
}
}
//删除
public static void deleteStudent(ArrayList<Student> array) {
Scanner sc = new Scanner(System.in);
System.out.println("请输入要删除学生的学号");
String id = sc.nextLine();
// String name = sc.nextLine();
for (int i = 0; i < array.size(); i++) {
Student s = array.get(i);
if (s.getId().equals(id)) {//||s.getName().equals(name)
array.remove(i);
System.out.println("删除成功!");
break;
} else {
System.out.println("没有该学生!!!");
deleteStudent(array);
}
}
}
//查找全部
public static void findStudent(ArrayList<Student> array) {
Scanner sc = new Scanner(System.in);
System.out.println("学号\t\t\t姓名\t\t\t年龄\t\t地址");
for (int i = 0; i < array.size(); i++) {
Student s = array.get(i);
System.out.println(s.getId() + "\t" + s.getName() + "\t" + s.getAge() + "岁" + "\t" + s.getAddress());
}
System.out.println("查询完成");
}
//修改
public static void gaiStudent(ArrayList<Student> array) {
Scanner sc = new Scanner(System.in);
Student s = new Student();
System.out.println("输入你想要修应该的学生的学号");
String id = sc.nextLine();
for (int i = 0; i < array.size(); i++) {
Student ss = array.get(i);
if (ss.getId().equals(id)) {
System.out.println("输入学生新姓名");
String name = sc.nextLine();
System.out.println("输入学生新年龄");
String age = sc.nextLine();
System.out.println("输入学生新地址");
String address = sc.nextLine();
s.setId(id);
s.setName(name);
s.setAge(age);
s.setAddress(address);
array.set(i, s);
break;
} else {
System.out.println("没有该学生,重新输入");
gaiStudent(array);
}
}
}
//判断相同Id
public static boolean idsame(ArrayList<Student> array, String id) {
for (int i = 0; i < array.size(); i++) {
Student sid = array.get(i);
if(sid.getId().equals(id)){
return false;
}
}
return true;
}
}
继承
概述
继承的好处和弊端
继承中变量访问的特点
super
关键字 | 访问对象 | 代码 |
---|---|---|
子类局部 | age | |
this | 子类成员 | this.age |
super | 父类成员 | super.age |
继承中,构造方法的访问特点
子类初始化前一定要完成父类数据的初始化
子类构造方法默认第一句为super(),访问父类无参构造方法
父类 | 子类 | 测试类 |
---|---|---|
无参构造方法 带参构造方法 | 无参构造方法 | 父类无参 子类无参 |
带参构造方法 | 父类无参 子类带参 | |
带参构造方法 | super() 无参构造方法 | 父类带参 子类无参 |
super() 带参构造方法 | 父类带参 子类带参 |
继承中,成员方法的访问特点
通过子类对象访问一个方法
- 子类成员范围找
- 父类成员范围找
- 如果都没有就报错(不考虑父亲的父亲...)
super内存图
![image-20230704074956004](../images/JAVASE基础09/image-20230704074956004.png)
方法重写
@Override的使用检查方法重写是否有误
方法重写注意事项
父类中,私有方法,子类不能继承,
权限
public > 默认 > 私有
继承的注意事项
不能同时继承多个类
支持多层继承
修饰符
包package
什么是包
包其实就是文件夹,方便对类进行分类管理
导包
import 包名
简化代码书写
修饰符
权限修饰符
修饰符 | 同一个类 | 同一个包中 子类和无关类 | 不同包的子类 | 不同包的无关类 |
---|---|---|---|---|
private | √ | |||
默认 | √ | √ | ||
protected | √ | √ | √ | |
pbulic | √ | √ | √ | √ |
状态修饰符 final
关键字fianl是最终的意思,可以修饰成员方法,成员变量,类
状态修饰符 final特点
修饰局部变量
静态修饰符 static
静态修饰符 static访问特点
多态
概述
多态中成员访问特点
成员变量:编译看左边,执行看左边->>都看父类
**成员方法:**编译看左边,执行看右边
多态的好处和弊端
多态中的转型
向上转型
从子到父 Animal a = new Cat();
父类引用指向子类对象 a.eat();
向下转型
从父到子 Animal a = new Cat();
Cat c =(Cat)a;
父类引用转为子类对象c.eat(); c.game;
多态转型内存图
抽象类
概述
在Java中,一个没有方法体的方法应该定义为抽象方法,而类中如果有抽象方法,该类必须定义为抽象类
关键字:abstract
抽象类的特点
抽象类和抽象方法必须使用abstract 关键字修饰
public abstract class 类名
public abstract void eat();
抽象类中不一定有抽象方法,有抽象方法的类一定是抽象类
抽象类不能实例化
抽象类如何实例化——>参照多态的方式,通过子类对象实例化,这叫抽象类多态
抽象类的子类
要么重写抽象类中的所有抽象方法
要么是抽象类
抽象类的成员特点
接口
概述
接口就是一种公共的规范标准,只要符合规范标准,大家都可以通用
接口特点
接口的成员特点
成员变量 只能是常量
默认修饰符: public static final
构造方法
接口,因为接口主要是对行为进行抽象的,是没有具体存在
只能是抽象方法
默认修饰符: public abstract
类和接口的关系
强调
案例
形参和返回值(再看看)
类名作为形参和返回值
方法的形参是类名,其实需要的是该类的对象
方法的返回值是类名,其实返回的是该类的对象
抽象类名作为形参和返回值
方法的形参是抽象类名,其实需要的是该抽象类的子类对象
方法的返回值是抽象类名,其实返回的是该抽象类的子类对象
接口名作为形参和返回值
方法的形参是接口名,其实需要的是该接口的实现类对象
方法的返回值是接口名,其实返回的是该接口的实现类对象
内部类
概述
public class Outer{
private int num = 10;
public class Inter{
public void show(){
System.out.println(num);
}
}
public void method(){
//show();
Inter i = new Inter();
i.show();
}
}
成员内部类
使用
**格式:**
外部类名.内部类名.对象名=外部类对象.内部类对象
**范例:**
Outer.Inner.oi = new Outer0.new Inner();
但是常用
局部内部类
在方法中定义的类
外界是无法直接使用,
需要在方法内部创建对象并使用该类可以直接访问外部类的成员,也可以访问方法内的局部变量
匿名内部类
格式
例子
无输出
对象调方法
匿名内部类在开发中的使用
课程p193
减少类的书写
常用API
Math
math常用方法
System
system常用方法
方法名 | |
---|---|
public static void exit (int status) | 终止当前运行的Java 虚拟机,非零表示异常终止 |
public static currentTimeMillis() | 返回当前时间(以毫秒为单位) |
Object
概述
Object是类层次结构的根,每个类都可以将 Object作为超类。所有类都直接或者间接的继承自该类 构造方法: public Object() 回想面向对象中,为什么说子类的构造方法默认访问的是父类的无参构造方法?因为它们的顶级父类只有无参构造方法
to String()
返回对象的字符串表示形式。建议所有子类重写该方法,自动生成
建议每次重写Alt+Insert
equals()
比较对象是否相等。默认比较地址,重写可以比较内容,自动生成
Arrays
常用
方法名 | 说明 |
---|---|
public static String toString(int[] a) | 返回指定数组的内容的字符串表示形式 |
public static void sort(int[] a) | 按照数字顺序排列指定的数组 |
工具类的设计思想
构造方法用private修饰
成员用 public static修饰
基本类型包装类
概述
将基本数据类型封装成对象的好处在于可以在对象中定义更多的功能方法操作该数据常用的操作之一:**用于基本数据类型与字符串之间的转换 **
基本数据类型 | 包装类 |
---|---|
byte | Byte |
short | Short |
int | Integer |
long | Long |
float | Float |
double | Double |
char | Character |
boolean | Boolean |
Integer
int和String的相互转换
int-------String
“”+number 进行连接
public static String = String.valueOf(number)
String s = String.valueOf(number);
String------int
String-------Integer----int
Integer i = Integer.valueOf(s);
int x = i.intValue;
int y = Integer.parseInt(s);
案例 字符串数组排序
import java.util.Arrays;
public class demo {
public static void main(String[] args) {
String s = "11 66 45 77 33 8 3 7";
//把字符串中的数字数据存储到一个int类型的数组中
String[] array = s.split(" ");
int[] arr = new int[array.length];
for (int i = 0; i < arr.length; i++) {
arr[i] = Integer.parseInt(array[i]);
}
//输出数组
for (int i = 0; i < arr.length; i++) {
System.out.printf("%4d", arr[i]);
}
System.out.println();
//排序
Arrays.sort(arr);
//输出排序完的数组
for (int i = 0; i < arr.length; i++) {
System.out.printf("%4d", arr[i]);
}
System.out.println();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < arr.length; i++) {
if (i == arr.length - 1) {
sb.append(arr[i]);
} else {
sb.append(arr[i]).append(" ");
}
}
String ss = sb.toString();
System.out.println(ss);
}
}
自动装箱与拆箱
装箱:把基本数据类型转换为对应的包装类类型
拆箱:把包装类类型转换为对应的基本数据类型
装箱
Integer i = Integer.valueOf(100);
自动装箱
Integer ii = 100;
注意:ii!=null
拆箱
ii = i.intValue()+200;
自动拆箱
ii+=200;
日期类
Date类
方法名 | 说明 |
---|---|
public Date() | 分配一个 Date对象,并初始化,以便它代表它被分配的时间,精确到毫秒 |
public Date(long data) | 分配一个 Date对象,并将其初始化为表示从标准基准时间起指定的毫秒数 |
Data常用方法
方法名 | 说明 |
---|---|
public long getTime() | 获取的是日期对象从1970年1月1日00:00:00到现在的毫秒值 |
public void setTime(long time) | 设置时间,给的是毫秒值 |
SimpleDateFormat 类
概述
SimpleDateFormat是一个具体的类,用于以区域设置敏感的方式格式化和解析日期。我们重点学习日期格式化和解析
日期和时间格式由日期和时间模式字符串指定,在期和时间模式字符串中,从A到以及从a到引号的字母被解释为表示日期或时间字符串的组件的模式字母
构造方法
例:从 Date 到 string和从 String 到 Date
从 Date 到 string
public final String format(Date date) 将日期格式化成日期/时间字符串解析:
从 String 到 Date
public Date parse (String source) 从给定字符串的开始解析文本以生成日期
日期工具类的编写
Calendar类
概述
Calendar为某一时刻和一组日历字段之间的转换提供了一些方法,并为操作日历字段提供了一些方法
Calendar提供了一个类方法getlnstance 用于获取 Calendar对象,
其日历字段已使用当前日期和时间初始化:Calendar rightNow =Calendar.getlnstance();
常用方法
方法名 | 说明 |
---|---|
public int get(int filed) | 返回给定日历字段的值 |
public abstract void add(int filed,int amount) | 根据日历的规则,将指定的时间量添加或减去给定的日历字段 |
public final void set(int year,int month,int date) | 设置当前日历的年月日 |
异常
概述
异常:就是程序出现了不正常的情况
异常体系
JVM的默认处理方案
如果程序出现了问题,我们没有做任何处理,
最终JVM会做默认的处理:
把异常的名称,异常原因及异常出现的位置等信息输出在了控制台
程序停止执行
异常处理
try....catch
三种异常处理的显示方法
多用e.printStackTrace();
编译时异常和运行时异常的区别
Java 中的异常被分为两大类: 和 也被称为和
所有的RuntimeException类及其子类被称为运行时异常,
其他的异常都是编译时异常
处理方案
编译时异常:必须显示处理,否则程序就会发生错误,无法通过编译
运行时异常:无需显示处理,也可以和编译时异常一样处理
异常处理之 throws
格式:
throws 异常类名;
注意:这个格式是跟在方法的括号后面的
只是抛出了异常,还是不能继续运行
编译时异常必须要进行处理,两种外理方案:tvcatch或者throws,如果采用throws 这种方案,将来谁调,用谁处理
运行时异常可以不处理,出现问题后,需要我们回来修改代码
自定义异常
例子
1
package myyichang;
public class ScoreException extends Exception {
public ScoreException(){
}
public ScoreException(String message) {
super(message);
}
}
2
package myyichang;
public class Teacher {
public void checkScore(int score) throws ScoreException {
if(score<0||score>100){
// throw new ScoreException();
throw new ScoreException("分数有误");
}else{
System.out.println("分数正常");
}
}
}
3
package myyichang;
import java.sql.SQLOutput;
import java.util.Scanner;
public class Teachertext {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("输入分数");
int score = sc.nextInt();
Teacher t = new Teacher();
try {
t.checkScore(score);
} catch (ScoreException e) {
e.printStackTrace();
}
}
}
集合体系结构
特点
集合类的特点:提供一种存储空间可变的存储模型,存储的数据容量可以随时发生改变
集合类体系结构
collection
collection 常用方法
Collection 集合的遍历
lterator:迭代器,集合的专用遍历方式
lterator < E >iterator(): 返回此集合中元素的迭代器,通过集合的iterator()方法得到
迭代器是通过集合的iterator()方法得到的,所以我们说它是依赖于集合而存在的
lterator中的常用方法
E next(): 返回选代中的下一个元素
boolean hasNext(): 如果选代具有更多元素,则返回true
List
List集合概述
有序集合(也称为序列),用户可以精确控制列表中每个元素的插入位置。用户可以通过整数索引访问元素并搜索列表中的元素与Set集合不同,列表通常允许重复的元素
List < String > list = new ArrayList< String>();cv
List集合特点
有序:存储和取出的元素顺序一致
可重复:存储的元素可以重复
特有方法
方法 | 说明 |
---|---|
void add (int index E element) | 在此集合中的指定位置插入指定的元素 |
E remove(int index) | 删除指定索引处的元素,返回被删除的元素 |
E set (int index,E element) | 修改指定索引处的元素,返回被修改的元素 |
E get(int index) | 返回指定索引处的元素 |
并发修改异常
通过迭代器遍历的 过程中,通过集合获取元素,预期修改值与实际修改值不一样
Listlterator列表迭代器
通过List集合的listlterator0方法得到,所以说它是List集合特有的迭代器用于允许程序员沿任一方向遍历列表的列表迭代器,在迭代期间修改列表,并获取列表中迭代器的当前位置
增强for循环
使用情况
常见数据结构
栈
队列
数组
链表
List集合子类特点
List集合常用子类: ArrayList,LinkedList
ArrayList: 底层数据结构是数组,查询快,增删慢
LinkedList: 底层数据结构是链表,查询慢,增删快
LinkedLIst集合的特有功能
Set集合
概述
Set集合特点
不包含重复元素的集合
没有带索引的方法,所以不能使用普通for循环遍历
哈希值
HashSet
HashSet集合特点:
底层数据结构是哈希表
对集合的迭代顺序不作任何保证,也就是说不保证存储和取出的元素顺序一致没有带索的方法,所以不能使用普通for循环遍历
由于是Set集合,所以是不包含重复元素的集合
HashSet集合保证元素唯一性源码分析
HashSet集合存储元素 要保证元素唯一性,需要重写hashCode()和equals()
HashSet集合添加一个元素的过程
哈希表
JDK8之前,底层采用实现,可以说是一个元素为链表的数组
JDK8以后,在长度比较长的时候,底层实现了优化
LinkedHashSet集合特点
1:哈希表和链表实现的Set接口,具有可预测的迭代次序
2:由链表保证元素有序,也就是说元素的存储和取出顺序是一致的
3:由哈希表保证元素唯一,也就是说没有重复的元素
TreeSet集合特点
元素有序,这里的顺序不是指存储和取出的顺序,而是按照一定的规则进行排序,具体排序方式取决于构造方法 TreeSet(): 根据其元素的自然排序进行排序 TreeSet(Comparator comparaton): 根据指定的比较器进行排序
没有带索引的方法,所以不能使用普通for循环遍历
由于是Set集合,所以不包含重复元素的集合
自然排序Comparable的使用
存储学生对象并遍历,创建TreeSet集合使用无参构造方法要求:按照年龄从小到大排序,年龄相同时,按照姓名的字母顺序排序结论 用TreeSet集合存储自定义对象,无参构造方法使用的是自然排序对元素进行排序的自然排序,就是让元素所属的类实现Comparable接口,重写compareTo( To)方法重写方法时,一定要注意排序规则必须按照要求的主要条件和次要条件来写
比较器排序Comparator的使用
存储学生对象并遍历,创建TreeSet集合使用带参构造方法要求:按照年龄从小到大排序,年龄相同时,按照姓名的字母顺序排序结论
用TreeSet集合存储自定义对象,带参构造方法使用的是比较器排序对元素进行排序的
比较器排序,就是让集合构造方法接收Comparator的实现类对象,重写compare(To1,To2)方法
重写方法时一定要注意排序规则必须按照要求的主要条件和次要条件来写
泛型
概述
泛型:是JDK5中引入的特性,它提供了编译时类型安全检测机制,该机制允许在编译时检测到非法的类型它的本质是参数化类型 ,也就是说所操作的数据类型被指定为一个参数
提到参数,最熟悉的就是定义方法时有形参,然后调用此方法时传递实参。那么参数化类型怎么理解呢?
顾名思义,就是将类型由原来的具体的类型参数化,然后在使用/调用时传入具体的类型
这种参数类型可以用在类、方法和接口中,分别被称为泛型类、泛型方法、泛型接口
格式及好处
泛型方法改进
泛型接口
类型通配符
为了表示各种泛型List的父类,可以使用类型通配符
类型通配符:<?>
List<?>:表示元素类型未知的List,它的元素可以匹配任何的类型这种带通配符的
List仅表示它是各种泛型List的父类,并不能把元素添加到其中
可变参数
可变参数又称参数个数可变,用作方法的形参出现,那么方法参数个数就是可变的了
格式:修饰符返回值类型方法名(数据类型...变量名)
范例: public static int sum(int...a){}
实际上封装到了数组a中
有多个参数,可变参数放到后面
可变参数的使用
Arrays工具类中有一个静态方法:
public static < T >List< T > asList (T...a): 返回由指定数组支持的固定大小的列表
不支持add,remove 因为会改变集合的大小
支持set(1,”lihuibear”);
List接口中有一个静态方法:
public static < E > List< E > of (E...elements): 返回包含任意数量元素的不可变列表
不支持增删改操作
Set接口中有一个静态方法:
public static< E >Set< E > of (E...elements) : 返回一个包含任意数量元素的不可变集合
不支持增删,没有改的操作
Map
概述
Interface Map<K,V>
K:键的类型,V:值的类型
将键映射到值的对象;不能包含重复的键;每个键可以映射到最多一个值
基本功能
Map集合的获取功能
Map集合的遍历
1
2
Collections
概述
是针对集合操作的工具类
常用方法
publicstatic<T extends Comparable<? super T >> void sort(List< T > list): 将指定的列表按升序排序
publicstatic void reverse(List<?> list): 反转指定列表中元素的顺序
public static void shuffle(List<?>list): 使用默认的随机源随机排列指定的列表
IO流
概述
IO:输入/输出(Input/Output)
流:是一种抽象概念,是对数据传输的总称。也就是说数据在设备间的传输称为流,流的本质是数据传输
lO流就是用来处理设备间数据传输问题的
常见的应用:文件复制;文件上传;文件下载
分类
一般来说,我们说IO流的分类是按照数据类型来分的
使用
那么这两种流都在什么情况下使用呢? 如果数据通过Window自带的记事本软件打开,我们还可以读懂里面的内容否则使用字节流。如果你不知道该使用哪种类型的流,就使用字节流。
File
概述
File:它是文件和目录路径名的抽象表示 文件和目录是可以通过File封装成对象的 对于File而言,其封装的并不是一个真正存在的文件,仅仅是一个路径名而已。它可以是存在的,也可以是不存在的.将来是要通过具体的操作把这个路径的内容转换为具体存在的
方法
删除功能
递归
递归概述:
以编程的角度来看,递归指的是方法定义中调用方法本身的现象
递归解决问题的思路:
把一个复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解递归策
略只需少量的程序就可描述出解题过程所需要的多次重复计算
字节流
字节流写数据
字节流抽象基类
InputStream: 这个抽象类是表示字节输入流的所有类的超类
OutputStream:这个抽象类是表示字节输出流的所有类的超类
子类名特点:子类名称都是以其父类名作为子类名的后缀
FileOutputStream: 文件输出流用于将数据写入File
FileOutputStream(Stringname): 创建文件输出流以指定的名称写入文件
步骤
字节流写数据的3种方式
字节流写数据的两个小问题
异常处理
字节流读数据
一次读一个
//标准格式
FileInputStream fis = new FileInputStream("FILE\\lihuibear002.txt");
int by;
while((by=fis.read())!=-1){
System.out.print((char)by);
}
fis.close();
字节缓冲流
字节缓冲流: BufferOutputStream: 该类实现缓冲输出流。通过设置这样的输出流,应用程序可以向底层输出流写入字节,而不必为写入的每个字节导致底层系统的调用
BuferedinputStream: 创建BufferedInputStream将创建一个内部缓冲区数组。当从流中读取或跳过字节时,内部缓冲区将根据需要从所包含的输入流中重新填充,一次很多字节
构造方法: 字节缓冲输出流:
BufferedOutputStream(OutputStream out)
字节缓冲输入流:
BufferedInputStream(InputStream in)
字节缓冲流,而真正的读写数据还得依靠基本的字节流对象进行操作
字符流
编码表
基础知识
字符集
是一个系统支持的所有字符的集合,包括各国家文字、标点符号、图形符号、数字等计算机要准确的存储和识别各种字符集符号,就需要进行字符编码,一套字符集必然至少有一套字符编码.常见字符集有ASCII字符集、GBXXX字符集、Unicode字符集等
编码解码问题
字符流抽象基本类
Reader:字符输入流的抽象类
Writer:字符输出流的抽象类
字符流中和编码解码问题相关的两个类
InputStreamReader
OutputStreamWriter
字符流写数据的5种方式
字符流读数据的2种方法
和字节流一样
字符缓冲流复制文件
字符缓冲流特有功能
小结
//成绩文本
package lihuibear002;
//import com.sun.org.apache.xpath.internal.operations.String;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Comparator;
import java.util.Scanner;
import java.util.TreeSet;
public class Stuedntscore {
public static void main(String[] args) throws IOException {
TreeSet<Student> ts = new TreeSet<>(new Comparator<Student>() {
@Override
public int compare(Student s1, Student s2) {
int num = s2.getSum() - s1.getSum();
int num2 = num == 0 ? s1.getScore_CH() - s2.getScore_CH() : num;
int num3 = num2 == 0 ? s1.getScore_MA() - s2.getScore_MA() : num2;
int num4 = num3 == 0 ? s1.getName().compareTo(s2.getName()) : num3;
return num4;
}
});
for (int i = 0; i < 2; i++) {
Scanner sc = new Scanner(System.in);
System.out.println("姓名:");
String name = sc.nextLine();//???
System.out.println("语文:");
int score_CH = sc.nextInt();
System.out.println("数学:");
int score_MA = sc.nextInt();
System.out.println("英语:");
int score_EN = sc.nextInt();
Student s = new Student();
s.setName(name);
s.setScore_CH(score_CH);
s.setScore_MA(score_MA);
s.setScore_EN(score_EN);
ts.add(s);
}
BufferedWriter bw = new BufferedWriter(new FileWriter("FILE\\lihuibear004.txt"));
for (Student s : ts) {
StringBuilder sb = new StringBuilder();
sb.append(s.getName()).append(",").append(s.getScore_CH()).append(",").append(s.getScore_MA()).append(",").append(s.getScore_EN()).append(",").append(s.getSum());
bw.write(sb.toString());
bw.newLine();
bw.flush();
}
bw.close();
}
}
package lihuibear002;
public class Student {
private String name;
private int score_CH;
private int score_MA;
private int score_EN;
public Student(){
}
public Student(String name, int score_CH, int score_MA, int score_EN) {
this.name = name;
this.score_CH = score_CH;
this.score_MA = score_MA;
this.score_EN = score_EN;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getScore_CH() {
return score_CH;
}
public void setScore_CH(int score_CH) {
this.score_CH = score_CH;
}
public int getScore_MA() {
return score_MA;
}
public void setScore_MA(int score_MA) {
this.score_MA = score_MA;
}
public int getScore_EN() {
return score_EN;
}
public void setScore_EN(int score_EN) {
this.score_EN = score_EN;
}
public int getSum(){
return this.score_CH+this.score_MA+this.score_EN;
}
}
复制文件的异常处理
标准写法
改进
特殊操作流
System类中有两个静态的成员变量: publicstatic finallnputStreamin: 标准输入流。通常该流对应于键盘输入或由主机环境或用户指定的另一个输入源
publicstatic final PrintStream out: 标准输出流。通常该流对应于显示输出或由主机环境或用户指定的另一个输出目标
标准输入输出流
输入
输出
字节打印流
字符打印流
对象序列化流
对象序列化:就是将对象保存到磁盘中,或者在网络中传输对象这种机制就是使用一个字节序列表示一个对象,该字节序列包念: 对象的类型、对象的数据和对象中存储的属性等信息字节序列写到文件之后,相当于文件中持久保存了一个对象的信息反之,该字节序列还可以从文件中读取回来,重构对象,对它进行反序列化
要实现序列化和反序列化就要使用对象序列化流和对象反序列化流:
对象序列化流:ObiectOutputStream
对象反序列化流:ObjectlnputStream
对象序列化流
一个对象要想被序列化,该对象所属的类必须必须实现Serializable 接口
Serializable是一个标记接口,实现该接口,不需要重写任何方法
对象反序列化流
seeriaVersionUID &transient
Properties概述
是一个Map体系的集合类
Properties可以保存到流中或从流中加载
properties特有方法
例子:
properties与IO流结合
多线程
实现多线程
进程
进程:是正在运行的程序
- 是系统进行资源分配和调用的独立单位
- 每一个进程都有它自己的内存空间和系统资源
线程
线程:是进程中的单个顺序控制流,是一条执行路径
- 单线程:一个进程如果只有一条执行路径,则称为单线程程序
- 多线程:一个进程如果有多条执行路径,则称为多线程程序
多线程的实现方法1
设置和获取线程名称
Thread类中设置和获取线程名称的方法
- void setName (String name): 将此线程的名称更改为等于参数name
- String getName0:返回此线程的名称
- 通过构造方法也可以设置线程名称
如何获取main0方法所在的线程名称?
public static Thread currentThread()
: 返回对当前正在执行的线程对象的引用
线程调度
线程有两种调度模型
- **分时调度模型:**所有线程轮流使用CPU的使用权,平均分配每个线程占用CPU的时间片
- **抢占式调度模型:**优先让优先级高的线程使用 CPU,如果线程的优先级相同,那么会随机选择一个,优先级高的线程获取的CPU时间片相对多一些
Java使用的是抢占式调度模型
假如计算机只有一个CPU,那么CPU 在某一个时刻只能执行一条指令,线程只有得到CPU时间片,也就是使用权才可以执行指令。所以说多线程程序的执行是有 随机性,因为谁抢到CPU的使用权是不一定的
//System.out.println(Thread.MAX PRIORITY);10
//System.out.println(Thread.MIN PRIORITY);1
//System.out.println(Thread.NORM PRIORITY); //5默认
//设置正确的优先级
tp1.setPriority(5);
tp2.setPriority(10);
tp3.setPriority(1);
设置优先级仅仅表示抢占cpu的概率高,不是一定要是优先级最大的先执行
线程控制
线程生命周期
多线程的实现方式2
线程同步
数据安全问题的解决
同步代码块
同步方法
线程安全的类
Lock锁
虽然我们可以理解同步代码块和同步方法的锁对象问题,但是我们并没有直接看到在哪里加上了锁,在哪里释放了锁为了更清晰的表达如何加锁和释放锁,JDK5以后提供了一个新的锁对象 Lock
Lock实现提供比使用synchronized方法和语句可以获得更广泛的锁定操作Lock中提供了获得锁和释放锁的方法
- void lock(): 获得锁
- void unlock():释放锁
Lock是接口不能直接实例化,这里采用它的实现类ReentrantLock来实例化
ReentrantLock的构造方法
ReentrantLock():创建一个ReentrantLock的实例
生产者消费者
概述
方法
案例
/*
//定义一个成员变量,表述第x瓶奶
private int milk;
//定义一个成员变量表示奶箱的状态
private boolean state = false;
//提供存储牛奶和获取牛奶的操作
public synchronized void putmilk(int milk){
//如果有奶,等待
if(state){
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//如果没有奶,送
this.milk = milk;
System.out.println("生产送第"+this.milk+"奶");
//生产完,改变状态
state =true;
//唤醒
notifyAll();
}
public synchronized void getmilk(){
//如果没有,等待生产
if(!state){
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//有就消费
System.out.println("用户拿到第"+this.milk+"奶");
//消费完改变状态
state = false;
//唤醒
notifyAll();
}*/
/*private Box b;
public Prodocer(Box b) {
this.b = b;
}
@Override
public void run() {
for (int i = 1; i <= 5; i++) {
b.putmilk(i);
}
}*/
/*private Box b;
public Customer(Box b) {
this.b = b;
}
@Override
public void run() {
while (true) {
b.getmilk();
}
}*/
/* public static void main(String[] args) {
Box b = new Box();
Prodocer p = new Prodocer(b);
Customer c = new Customer(b);
Thread t1 = new Thread(p);
Thread t2 = new Thread(c);
t1.start();
t2.start();
}*/
网路编程
网络编程入门
概述
- 计算机网络 是指将地理位置不同的具有独立功能的多台计算机及其外部设备,通过通信线路连接起来,在网络操作系统,网络管理软件及网络通信协议的管理和协调下,实现资源共享和信息传递的计算机系统
- 网络编程 在网络通信协议下,实现网络互连的不同计算机上运行的程序间可以进行数据交换
网络编程三要素
IP地址
常用命令
ipconfig:查看本机IP地址
ping IP 地址:检查网络是否连通
特殊IP地址
127.0.0.1:是回送地址,可以代表本机地址,一般用来测试使用
端口
端口:设备上应用程序的唯一标识 端口号:用两个字节表示的整数,它的取值范围是0—65535。其中,0—1023之间的端口号用于一些知名的网络服务和应用,普通的应用程序需要使用1024以上的端口号。如果端口号被另外一个服务或应用所占用,会导致当前程序启动失败
协议
协议:计算机网络中,连接和通信的规则被称为网络通信协议
UDP协议
- 用户数据报协议(UserDatagram Protocol)
- UDP是无连接通信协议,即在数据传输时,数据的发送端和接收端不建立逻辑连接。简单来说,当一台计算机向另外一台计算机发送数据时,发送端不会确认接收端是否存在,就会发出数据,同样接收端在收到数据时,也不会向发送端反馈是否收到数据 由于使用UDP协议消耗资源小,通信效率高,所以通常都会用于音频、视频和普通数据的传输
TCP协议
- 传输控制协议(Transmission Control Protocol)
TCP协议是面向连接的通信协议,即传输数据之前,在发送端和接收端建立逻辑连接,然后再传输数据它提供了两台计算机之间可靠无差错的数据传输。在TCP连接中必须要明确客户端与服务器端,由客户端向服务端发出连接请求,每次连接的创建都需要经过“三次握手”
三次握手:TCP协议中,在发送数据的准备阶段,客户端与服务器之间的三次交互,以保证连接的可靠
- 第一次握手,客户端向服务器端发出连接请求,等待服务器确认
- 第二次握手,服务器端向客户端回送一个响应,通知客户端收到了连接请求
- 第三次握手,客户端再次向服务器端发送确认信息,确认连接
完成三次握手,连接建立后,客户端和服务器就可以开始进行数据传输了。由于这种面向连接的特性TCP协议可以保证传输数的安全,所以应用十分广泛。例如上传文件、下载文件、浏览网页等
UDP通信程序
原理
UDP协议是一种不可靠的网络协议,它在通信的两端各建立一个Socket对象,但是这两个Socket只是发送,接收数据的对象因此对于基于UDP协议的通信双方而言, 没有所谓的客户端和服务器的概念,Java提供了DatagramSocket类作为基于UDP协议的Socket
UDP发送数据
发送数据的步骤
- 创建发送端的Socket对象(DatagramSocket) DatagramSocket()
- 创建数据,并把数据打包 DatagramPacket(bytel] buf, int length, lnetAddress address, int port)调用
- DatagrlmSocket对象的方法发送数据 void send(DatagramPacket p)
- 关闭发送端 void close()
接收
案例
package bear003;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
public class ReceiveDemo {
public static void main(String[] args) throws IOException {
DatagramSocket ds = new DatagramSocket(10001);
while (true) {
byte[] by = new byte[1024];
DatagramPacket dp = new DatagramPacket(by, by.length);
ds.receive(dp);
// byte[] data = dp.getData();
//
// int len = dp.getLength();
//
// String dataString = new String(data, 0, len);
//
//
// System.out.println("数据为:"+dataString);
System.out.println("数据为:" + new String(dp.getData(), 0, dp.getLength()));
}
// ds.close();
}
}
package bear003;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
public class Senddemo {
public static void main(String[] args) throws IOException {
DatagramSocket ds = new DatagramSocket();
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String line;
while ((line = br.readLine()) != null) {
if("886".equals(line)){
break;
}
byte[] by = line.getBytes();
DatagramPacket dp = new DatagramPacket(by, by.length, InetAddress.getByName("192.168.188.39"), 10001);
ds.send(dp);
}
ds.close();
}
}
TCP通信程序
原理
TCP通信协议是一种可靠的网络协议,它在通信的两端各建立-个Socket对象,从而在通信的两端形成网络虚拟链路旦建立了虚拟的网络链路,两端的程序就可以通过虚拟链路进行通信Java对基于TCP协议的的网络提供了良好的封装,使用Socket对象来代表两端的通信端口,并通过Socket产生I0流来进行网络通信Java为客户端提供了Socket类,为服务器端提供了ServerSocket类
发送数据
接收
练习
void | shutdownInput() 将此套接字的输入流放置在“流的末尾”。 |
---|---|
void | shutdownOutput() 禁用此套接字的输出流。 |
案例1
其他案例见https://github.com/lihuibear4/NET.git
Lambda表达式
概述
标准格式
Lambda表达式的格式
- 格式:(形式参数)->代码块)
- 形式参数:如果有多个参数,参数之间用逗号隔开,如果没有参数,留空即可
- ->:由英文中画线和大于符号组成,固定写法。代表指向动作
- 代码块:是我们具体要做的事情,也就是以前我们写的方法体内容
前提
Lambda表达式的使用前提
- 有一个接口
- 接口中有且仅有一个抽象方法
省略模式
注意事项
- 使用Lambda必须要有接口,并且要求接口中有且仅有一个抽象方法
- 必须有上下文环境,才能推导出Lambda对应的接口
根据局部变量的赋值得知Lambda对应的接口: Runnable r= () ->System.out.println("Lambda表达式”);
根据调用方法的参数得知Lambda对应的接口: new Thread(() -> System.out,println("Lambda表达式”)).start();
Lambda表达式和匿名内部类的区别
接口的组成更新
概述
接口的组成
- 常量 public static final
- 抽象方法 public abstract
默认方法
接口中默认方法的定义格式:
格式:publicdefault返回值类型方法名(参数列表)
范例: public default void show30{}
接口中默认方法的注意事项默认方法不是抽象方法,所以不强制被重写。但是可以被重写,
写的时候去掉default关键字public可以省略,default不能省略
静态方法
私有方法
方法引用
方法引用符
Lambda表达式支持的方法引用
常见的引用方式
- 引用类方法
- 引用对象的实例方法
- 引用类的实例方法
- 引用构造器
引用类方法的使用
//Lambda表达式被类的实例方法替代的时候
//第一个参数作为调用者
//后面的参数全部传递给该方法作为参数
函数式接口
概述
函数式接口:有且仅有一个抽象方法的接口
Java中的函数式编程体现就是Lambda表达式,所以函数式接口就是可以适用于Lambda使用的接口只有确保接口中有且仅有一个抽象方法,Java中的Lambda才能顺利地进行推导
如何检测一个接口是不是函数式接口呢?
@Functionallnterface
- 放在接口定义的上方:如果接口是函数式接口,编译通过;如果不是,编译失败
注意 我们自己定义函数式接口的时候,@Functionallnterface
是可选的,就算我不写这个注解,只要保证满足函数式接口定义的条件,也照样是函数式接口。 但是,建议加上该注解
函数式接口作为方法的参数
函数式接口作为方法的返回值
常用函数式接口
- Supplier接口
- Consumer接口
- Predicate接口
- Function接口
Supplier接口
Supplier<T>
:包含一个无参的方法
- T get():获得结果
- 该方法不需要参数,它会按照某种实现逻辑(由Lambda表达式实现)返回一个数据
Supplier<T>
接口也被称为生产型接口,如果我们指定了接口的泛型是什么类型,那么接口中的get方法就会生产什么类型的数据供我们使用
001
002
Consumer接口
Consumer<T>
:包含两个方法
void accept(T t)
:对给定的参数执行此操作defaultConsumer<T>andThen(Consumer after)
: 返回一个组合的Consumer,依次执行此操作,然后执行after操作Consumer<T>
接口也被称为消费型接口,它消费的数据的数据类型由泛型指定
001
002
Predicate接口
Predicate<T>
:常用的四个方法
boolean test(T t)
:对给定的参数进行判断(判断逻辑由Lambda表达式实现),返回一个布尔值default Predicate<T> negate()
: 返回一个逻的否定,对应逻辑非defaultPredicate<T>and(Predicate other)
: 返回一个组合判断,对应短路与defaultPredicate<T>or(Predicate other)
: 返回一个组合判断,对应短路或Predicate<T>
接口通常用于判断参数是否满足指定的条件
Function接口
Rapply(Tt)
:将此函数应用于给定的参数default <V> FunctionandThen(Function after)
: 返回一个组合函数,首先将该函数应用于输入,然后将after函数应用于结果Function<T,R>
接口通常用于对参数进行处理,转换处理逻辑由Lambda表达式实现),然后返回一个新的值
Stream流
展示
Stream流的生成方式
Stream流的常见生成方式 Collection体系的集合可以使用默认方法stream()生成流
default Stream<E> stream()
Map体系的集合间接的生成流
数组可以通过Stream接口的静态方法of(T...values)生成流
Stream流的常见中间操作方法
Stream<T> filter(Predicate predicate)
: 用于对流中的数据进行过滤Predicate接口中的方法 boolean test(T t):对给定的参数进行判断,返回一个布尔值
Stream<T>limit(long maxSize)
: 返回此流中的元素组成的流,截取前指定参数个数的数据Stream<T>skip(long n)
:跳过指定参数个数的数据,返回由该流的剩余元素组成的流static <T> Stream<T> concat(Stream a, Stream b)
:合并a和b两个流为一个流Stream<T>distinct0
: 返回由该流的不同元素(根Objectequals(Object)) 组成的流Stream<T>sorted0
:返回由此流的元素组成的流,根据自然顺序排序Stream<T>sorted(Comparatorcomparator)
: 返回由该流的元素组成的流,根据提供的Comparator进行排序
<R> Stream<R>map(Functionmapper)
:返回由给定函数应用于此流的元素的结果组成的流 Function接口中的方法 R apply(T t)IntStream mapTolnt(TolntFunction mapper)
: 返回一NntStream其中包含将给定函数应用于此流的元素的结果 IntStream:表示原始int流
TolntFunction接口中的方法int applyAslnt(T value)
Stream流的常见终结操作方法
void forEach(Consumeraction)
: 对此流的每个元素执行操作 Consumer接中的方法void accept(Tt)
:对给定的参数执行此操作long count()
:返回此流中的元素数
Stream流的收集操作
Stream流的收集方法
R collect(Collector collector)
- 但是这个收集方法的参数是一个Collector 接口
工具类Collectors提供了具体的收集方式
publicstatic<T> Collector toList0
: 把元素收集到List集合中publicstatic <T> Collector toSet0
: 把元素收集到Set集合中publicstatic CollectortoMap(Function keyMapper,FunctionvalueMapper)
: 把元素收集到Map集合中
反射
类加载器
类加载
当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过类的加载,类的连接,类的初始化这三个步骤来对类进行初始化。如果不出现意外情况,JVM将会连续完成三个步骤,所以有时也把这三个步骤统称为类加载或者类初始化
类的加载
- 就是指将class文件读入内存,并为之创建一个iava.lang.Class对象
- 任何类被使用时,系统都会为之建立一个iavalangClass对象
类的连接
- 验证阶段:用于检验被加载的类是否有正确的内部结构,并和其他类协调一致
- 准备阶段:负责为类的类变量分配内存,并设置默认初始化值
- 解析阶段:将类的二进制数据中的符号引用替换为直接引用
类的初始化
- 在该阶段,主要就是对类变量进行初始化
类的初始化步骤
- 假如类还未被加载和连接,则程序先加载并连接该类
- 假如该类的直接父类还未被初始化,则先初始化其直接父类
- 假如类中有初始化语句,则系统依次执行这些初始化语句
- 注意:在执行第2个步骤的时候,系统对直接父类的初始化步骤也遵循初始化步骤1-3
类的初始化时机:
- 创建类的实例
- 调用类的类方法
- 访问类或者接口的类变量,或者为该类变量赋值
- 使用反射方式来强制创建某个类或接口对应的java.lang.Class对象
- 初始化某个类的子类
- 直接使用java.exe命令来运行某个主类
类加载器
类加载器的作用
- 负责将.class文件加载到内存中,并为之生成对应的java.lang.Class对象
- 虽然我们不用过分关心类加载机制,但是了解这个机制我们就能更好的理解程序的运行
JVM的类加载机制
- 全盘负责:就是当一个类加载器负责加载某个Class时,该Class所依赖的和引用的其他Class也将由该类加载器负责载入,除非显示使用另外一个类加载器来载入
- 父类委托:就是当一个类加载器负责加载某个Class时,先让父类加载器试图加载该Class,只有在父类加载器无法加载该类时才尝试从自己的类路径中加载该类
- 缓存机制: 保证所有加载过的Class都会被缓存,当程序需要使用某个Class对象时,类加载器先从缓存区中搜索该Class,只有当缓存区中不存在该Class对象时,系统才会读取该类对应的二进制数据,并将其转换成CIass对象,存储到缓存区
ClassLoader:是负责加载类的对象
Java运行时具有以下内置类加载器
Bootstrap classloader: 它是虚拟机的内置类加载器,通常表示为null,并且没有父null
Platform classloader:平台类加载器可以看到所有平台类,平台类包括由平台类加载器或其祖先定义的Java SE平台API其实现类和JDK特定的运行时类
System classloader:它也被称为应用程序类加载器,与平台类加载器不同。系统类加载器通常用于定义应用程序类路径模块路径和JDK特定工具上的类
类加载器的继承关系: System的父加载器为Platform,而Platform的父加载器为Bootstrap
ClassLoader中的两个方法
- static ClassLoadergetSystemClassLoader0: 返回用于委派的系统类加载器
- ClassLoadergetParent0: 返回父类加载器进行委派
反射
概述
Java反射机制:
是指在运行时去获取一个类的变量和方法信息。然后通过获取到的信息来创建对象,调用方法的一种机制。由于这种动态性,可以极大的增强程序的灵活性,程序不用在编译期就完成确定,在运行期仍然可以扩展
获取Class类的对象
我们要想通过反射去使用一个类,首先我们要获取到该类的字节码文件对象,也就是类型为Class类型的对象这里我们提供三种方式获取Class类型的对象
使用类的class属性来获取该类对应的Class对象。举例: Studentclass将会返回Student类对应的CIass对象
调用对象的getClass()方法,返回该对象所属类对应的Class对象 该方法是Obiect类中的方法,所有的Java对象都可以调用该方法
使用Class类中的静态方法forName(StringclassName),该方法需要传入字符由参数,该字符串参数的值是某个类的全路径,也就是完整包名的路径
反射获取构造方法并使用
Class类中用于获取构造方法的方法
Constructo r< ?> getConstfuctors(): 返回所有公共构造方法对象的数组
Constructor< ? >getDeclaredConstructors(): 返回所有构造方法对象的数组
Constructor< T >getConstructor(Class< ? >...parameterTypes): 返回单个公共构造方法对象
Constructor< T >getDeclaredConstructor(Class<?>...parameterTypes): 返回单个构造方法对象
Constructor类中用于创建对象的方法
- Tnewlnstance(Object...initargs): 根据指定的构造方法创建对象
练习
package bear004;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
public class Refectdemo001 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
Class<?> c = Class.forName("bear002.Student");
Constructor<?> con = c.getConstructor(String.class, int.class, String.class);
Object obj = con.newInstance("李慧", 20, "sjz");
System.out.println(obj);
}
}
暴力反射
public void setAccessible (boolean flag):值为true,取消访问检查
con.setAccessible(true);
反射获取成员变量并使用
Class类中用于获取成员变量的方法
- Field[] getFields(): 返回所有公共成员变量对象的数组
- Field[] getDeclaredFields(): 返回所有成员变量对象的数组Field getField (String name): 返回单个公共成员变量对象
- Field getDeclaredField(String name): 返回单个成员变量对象
- Field类中用于给成员变量赋值的方法
- void set(Objectobi,Objectvalye): 给obi对象的成员变量赋值为value
反射获取成员方法并使用
Class类中用于获取成员方法的方法
- MethodlgtMethods0: 返回所有公共成员方法对象的数组,包括继承的
- MethodlgetDeclaredMethods0: 返回所有成员方法对象的数组,不包括继承的
- MethodgetMethod(Stringname, Class< ? >... parameterTypes): 返回单个公共成员方法对象
- MethodgetDeclaredMethod(String name,Class<?>... parameterTypes): 返回单个成员方法对象