标识符
· 标识符必须以字母、下划线_、美元符号$开头。
· 标识符其它部分可以是字母、下划线“_”、美元符“$”和数字的任意组合。
· Java 标识符大小写敏感,且长度无限制。
· 标识符不可以是Java的关键字。
· 标识符的使用规范
· 表示类名的标识符:每个单词的首字母大写,如Man,Body等
· 表示方法和变量的标识符:第一个单词的首字母小写,从第二个单词开始首字母大写,称之为“驼峰原则”,如queryAll();
【注意】:Java不采用通常语言使用的ASCⅡ字符集,而是采用Unicode的国际字符集。因此,这里的字母含义不只是英文字母,汉字也是可以的,但是不建议使用汉字来定义标识符!
package com.yuxuange.test;
public class Yuxuange {
public static void main(String[] args) {
int a123=1;
//int 123abc=1; //数字不能作为标识符的开头
int a_123=1;
int _123=1;
//int class=1; //关键字不能作为标识符
int Class=1; //首字母大写,所以不是关键字
int 今天=1; //可以使用汉字作为标识符,但是不推荐
}
}
注解
单行注释: 使用“//”开头,“//”后面的单行内容均为注释。
多行注释: 以“/”开头以“/”结尾,在“/”和“/”之间的内容为注释,我们也可以使用多行注释作为行内注释。但是在使用时要注意,多行注释不能嵌套使用。
文档注释: 以“/**”开头以“*/”结尾,注释中包含一些说明性的文字及一些JavaDoc标签
变量
· 变量本质上代表一个“可操作的存储空间”,空间位置是确定的,但是里面存放的值不确定。我们可以通过变量名来访问“对应的存储空间”,从而操纵这个“存储空间”存储的值。这个过程我们可以想象为一个日常生活中的停车场,车位位置固定,编号固定,里面停放的车不一定是什么。
· Java中每个变量都必须声明其数据类型。变量的数据类型决定了变量占据存储空间的大小。
· 变量作为程序中最基本的存储单元,其要素包括变量名,变量类型,及作用域。变量在使用前必须对其声明,只有在变量声明以后,才能为其分配相应长度的存储空间。
package com.yuxuange.test;
public class Yuxuange {
public static void main(String[] args) {
int test1; //只是声明了变量test1,但是未对其进行初始化
System.out.println(test1); //所以不能再控制台输出此变量的值
int test2=18; //声明了变量test2,并对其进行赋值
System.out.println(test2); //输出test2的值
}
}
· 分类
类型 | 声明位置 | 从属于 | 生命周期 |
局部变量 | 方法或语句块内部 | 方法/语句块 | 从声明位置开始,直到方法或语句块执行完毕,局部变量消失 |
成员变量(实例变量) | 类内部,方法外部 | 对象 | 对象创建,成员变量也跟着创建。对象消失,成员变量也跟着消失; |
静态变量(类变量) | 类内部,static修饰 | 类 | 类被加载,静态变量就有效;类被卸载,静态变量消失。 |
基本数据类型
· 整型数据类型
类型 | 占用存储空间 | 表数范围 |
byte | 1字节 | -27 ~ 27-1(-128~127) |
short | 2字节 | -215 ~ 215-1 (-32768~32767) |
int | 4字节 | -231 ~ 231-1 (-2147483648~2147483647) 约21亿 |
long | 8字节 | -263 ~ 263-1 |
· 整型的四种表示形式
· 十进制整数,如:99, -500, 0
· 八进制整数,要求以 0 开头,如:015
· 十六进制数,要求 0x 或 0X 开头,如:0x15
· 二进制数,要求0b或0B开头,如:0b01110011
package com.yuxuange.test;
public class Yuxuange {
public static void main(String[] args) {
int a = 12; // 十进制
int b = 012; // 八进制
int c = 0x12; // 十六进制
int d = 0b1011; // 二进制
System.out.println(a);
System.out.println(b);
System.out.println(c);
System.out.println(d);
}
}
输出结果为:
如果想了解各进制之间计算,请转到https://blog.youkuaiyun.com/weixin_43845597/article/details/108767712
浮点型数据类型
类型 | 占用存储空间 | 表数范围 |
float | 4字节 | -3.403E38~3.403E38 |
double | 8字节 | -1.798E308~1.798E308 |
package com.yuxuange.test;
public class Yuxuange {
public static void main(String[] args) {
//浮点数是不精确的,不要进行比较,切记
float a=0.01F;
double b = 1.0/100;
if(a==b) {
System.out.println("a与b相等");
}else {
System.out.println("a与b不相等");
}
float c =66666666F;
float d = c+1;
if(c==d) {
System.out.println("c与d相等");
}else {
System.out.println("c与d不相等");
}
}
}
输出结果为;
· 如果需要进行不产生舍入误差的精确数字计算,需要使用BigDecimal类。BigDecimal的具体用法请看:https://blog.youkuaiyun.com/weixin_43845597/article/details/89075688
字符型数据类型
· 字符型在内存中占2个字节,在Java中使用单引号来表示字符常量。例如’A’是一个字符,它与”A”是不同的,”A”表示含有一个字符的字符串。
· char 类型用来表示在Unicode编码表中的字符。Unicode编码被设计用来处理各种语言的文字,它占2个字节,可允许有65536个字符。
· 转义字符
转义符 | 含义 | Unicode值 |
\b | 退格(backspace) | \u0008 |
\n | 换行 | \u000a |
\r | 回车 | \u000d |
\t | 制表符(tab) | \u0009 |
\“ | 双引号 | \u0022 |
\‘ | 单引号 | \u0027 |
\\ | 反斜杠 | \u005c |
布尔类型数据类型
boolean类型有两个常量值,true和false,在内存中占一位(不是一个字节)
package com.yuxuange.test;
public class Yuxuange {
public static void main(String[] args) {
boolean flag=true;
if(flag) { // flag == true的写法,不推荐。请牢记:"=="与"="的区别
System.out.println("这是一个标识");
}else {
System.out.println("这不是一个标识");
}
}
}
输出结果为:
运算符
二元运算符的运算规则:
整数运算:
1. 如果两个操作数有一个为Long, 则结果也为long。
2. 没有long时,结果为int。即使操作数全为short,byte,结果也是int。
浮点运算:
3. 如果两个操作数有一个为double,则结果为double。
4. 只有两个操作数都是float,则结果才为float。
取模运算:
1.其操作数可以为浮点数,一般使用整数,结果是“余数”,“余数”符号和左边操作数相同,如:7%3=1,-7%3=-1,7%-3=1。
2.算术运算符中++,–属于一元运算符,该类运算符只需要一个操作数。
package com.yuxuange.test;
public class Yuxuange {
public static void main(String[] args) {
int a = 3;
int b = a++; // 执行完后,b=3。先给b赋值,再自增。
System.out.println("a=" + a + "\nb=" + b);
a = 3;
b = ++a; // 执行完后,a先自增,a=4,再给b赋值
System.out.println("a=" + a + "\nb=" + b);
}
}
输出结果为:
赋值及其扩展运算符
package com.yuxuange.test;
public class Yuxuange {
public static void main(String[] args) {
int a = 5;
int b = 10;
a *= b + 5; //相当于a*(b+5)
System.out.println("a=" + a + "\nb=" + b);
}
}
输出结果为:
关系运算符
关系运算符用来进行比较运算,关系运算的结果是布尔值:true/false;
【注意】:
· =是赋值运算符,而真正的判断两个操作数是否相等的运算符是==。
· ==、!= 是所有(基本和引用)数据类型都可以使用
· > 、>=、 <、 <= 仅针对数值类型(byte/short/int/long, float/double。以及char)
逻辑运算符
逻辑运算的操作数和运算结果都是boolean值。
短路与和短路或采用短路的方式。从左到右计算,如果只通过运算符左边的操作数就能够确定该逻辑表达式的值,则不会继续计算运算符右边的操作数,提高效率。
package com.yuxuange.test;
public class Yuxuange {
public static void main(String[] args) {
boolean a1 = 1 > 2 && 2 > (3 / 0); //短路与,第一个操作数的值为false,则不需要再计算后面的操作数
System.out.println(a1);
boolean a2 = 1 > 2 & 2 > (3 / 0);
System.out.println(a2);
}
}
输出结果为:
位运算符
package com.yuxuange.test;
public class Yuxuange {
public static void main(String[] args) {
int a = 5; //0b101
int b = 10; //0b1010
System.out.println(a & b);
System.out.println(a | b);
System.out.println(a ^ b);
System.out.println(~a);
// 移位
int c = 5 << 2;
System.out.println(c);
System.out.println(10 >> 1);
}
}
输出结果为:
字符串连接符
“+”运算符两侧的操作数中只要有一个是字符串(String)类型,系统会自动将另一个操作数转换为字符串然后再进行连接。
package com.yuxuange.test;
public class Yuxuange {
public static void main(String[] args) {
int a = 5;
int b = 10;
System.out.println(a+b);
System.out.println(a+"b");
}
}
输出结果为:
条件运算符(三元运算符)
语法格式:x?y:z
· 其中 x 为 boolean 类型表达式,先计算 x 的值,若为true,则整个运算的结果为表达式 y 的值,否则整个运算结果为表达式 z 的值。
package com.yuxuange.test;
public class Yuxuange {
public static void main(String[] args) {
int score = 62;
String type = score > 60 ? "及格" : "不及格";
System.out.println(type);
}
}
输出结果为:
运算符优先级
【建议】:逻辑与,逻辑或,逻辑非的优先级一定要熟悉!(逻辑非>逻辑与>逻辑或)。
如:a||b&&c的运行结果为:a||(b&&c),而不是自左向右执行。
自动类型转换
自动类型转换指的是容量小的数据类型可以自动转换为容量大的数据类型。
实线表示无数据丢失的自动类型转换,而虚线表示在转换时可能会有精度的损失。
强制类型转换
强制类型转换,又被称为造型,用于显式的转换一个数值的类型。在有可能丢失信息的情况下进行的转换是通过造型来完成的,但可能造成精度降低或溢出。
package com.yuxuange.test;
public class Yuxuange {
public static void main(String[] args) {
double x =3.1415926;
double u =3.998;
int y=(int) x;
int t=(int) u;
char z = 'A';
int v = z+1;
System.out.println(y);
System.out.println(t);
System.out.println(v);
System.out.println((char)v);
}
}
输出结果为:
控制语句
流程控制语句是用来控制程序中各语句执行顺序的语句,控制语句分为三类:顺序、选择和循环。
· “顺序结构”代表“先执行a,再执行b”的逻辑。
· “选择结构”代表“如果…,则…”的逻辑。
· “循环结构”代表“如果…,则再继续…”的逻辑。
if单选择结构
· 语法结构:
if(布尔表达式){
语句块
}
if语句对布尔表达式进行一次判定,若判定为真,则执行{}中的语句块,否则跳过该语句块。
· 流程图:
package com.yuxuange.test;
public class Yuxuange {
public static void main(String[] args) {
double d =Math.random(); //返回【0,1)之间的随机数
System.out.println(d);
int i =(int) (6*Math.random()+1);
int j =(int) (6*Math.random()+1);
int k =(int) (6*Math.random()+1);
int count= i+j+k;
System.out.println("获得的分数为:"+count);
if(count>15) {
System.out.println("手气很好");
}
if(count>=10 && count<=15) {
System.out.println("手气一般");
}
if(count<10) {
System.out.println("手气很差");
}
}
}
if-else双选择结构
· 语法结构
if(布尔表达式){
语句块1
}else{
语句块2
}
当布尔表达式为真时,执行语句块1,否则,执行语句块2。也就是else部分。
· 流程图:
if-else if-else多选择结构
· 语法结构:
if(布尔表达式1) {
语句块1;
} else if(布尔表达式2) {
语句块2;
}……
else if(布尔表达式n){
语句块n;
} else {
语句块n+1;
}
当布尔表达式1为真时,执行语句块1;否则,判断布尔表达式2,当布尔表达式2为真时,执行语句块2;否则,继续判断布尔表达式3······;如果1~n个布尔表达式均判定为假时,则执行语句块n+1,也就是else部分。
· 流程图:
package com.yuxuange.test;
public class Yuxuange {
public static void main(String[] args) {
int day = (int) (30*Math.random()+1);
System.out.println(day);
if(day<=10) {
System.out.println("当前是在本月上旬");
}else if(day>10&&day<=20) {
System.out.println("当前是在本月中旬");
}else {
System.out.println("当前是在本月下旬");
}
}
}
switch多选择结构
· 语法结构:
switch (表达式) {
case 值1:
语句序列1;
[break];
case 值2:
语句序列2;
[break];
… … … … …
[default:
默认语句;]
}
switch语句会根据表达式的值从相匹配的case标签处开始执行,一直执行到break语句处或者是switch语句的末尾。如果表达式的值与任一case值不匹配,则进入default语句(如果存在default语句的情况)。
根据表达式值的不同可以执行许多不同的操作。switch语句中case标签在JDK1.5之前必须是整数(long类型除外)或者枚举,不能是字符串,在JDK1.7之后允许使用字符串(String)。
· 流程图:
package com.yuxuange.test;
import java.util.Scanner;
public class Yuxuange {
public static void main(String[] args) {
Scanner scanner =new Scanner(System.in);
System.out.println("请输入今天的星期数...");
int i =scanner.nextInt();
switch (i) {
case 1:
System.out.println("今天是星期一");
break;
case 2:
System.out.println("今天是星期二");
break;
case 3:
System.out.println("今天是星期三");
break;
case 4:
System.out.println("今天是星期四");
break;
case 5:
System.out.println("今天是星期五");
break;
case 6:
System.out.println("今天是星期六");
break;
case 7:
System.out.println("今天是星期天");
break;
default:
System.out.println("输入有误....");
break;
}
}
}
while循环
· 语法结构:
while (布尔表达式) {
循环体;
}
· 流程图:
package com.yuxuange.test;
/**
* 计算1+2+3+4+...+99+100之和,输出结果为5050
* @author 羽轩阁
*
*/
public class Yuxuange {
public static void main(String[] args) {
int x= 1;
int sum=0;
while(x<=100) {
sum+=x;
x++;
}
System.out.println(sum);
}
}
do-while循环
· 语法结构:
do {
循环体;
} while(布尔表达式) ;
do-while循环结构会先执行循环体,然后再判断布尔表达式的值,若条件为真,执行循环体,当条件为假时结束循环。do-while循环的循环体至少执行一次。
· 流程图:
for循环
· 语法结构:
for (初始表达式; 布尔表达式; 迭代因子) {
循环体;
}
for循环语句是支持迭代的一种通用结构,是最有效、最灵活的循环结构。for循环在第一次反复之前要进行初始化,即执行初始表达式;随后,对布尔表达式进行判定,若判定结果为true,则执行循环体,否则,终止循环;最后在每一次反复的时候,进行某种形式的“步进”,即执行迭代因子。
A. 初始化部分设置循环变量的初值
B. 条件判断部分为任意布尔表达式
C. 迭代因子控制循环变量的增减
for循环在执行条件判定后,先执行的循环体部分,再执行步进。
· 流程图:
package com.yuxuange.test;
/**
* 计算1+2+3+4+...+99+100之和
* @author 羽轩阁
*
*/
public class Yuxuange {
public static void main(String[] args) {
int sum=0;
for(int i=0;i<=100;i++) {
sum+=i;
}
System.out.println(sum);
}
}
嵌套循环
在一个循环语句内部再嵌套一个或多个循环,称为嵌套循环。while、do-while与for循环可以任意嵌套多层。
package com.yuxuange.test;
/**
* 9*9乘法表
* @author 羽轩阁
*
*/
public class Yuxuange {
public static void main(String[] args) {
for(int i=1;i<=9;i++) {
for(int j=1;j<=i;j++) {
System.out.print(i+"*"+j+"="+i*j+"\t");
}
System.out.println();
}
}
}
输出结果为:
package com.yuxuange.test;
/**
* 100以内奇数之和与偶数之和
* @author 羽轩阁
*
*/
public class Yuxuange {
public static void main(String[] args) {
int oddSum=0; //奇数之和
int evenSum=0; //偶数之和
for(int i=1;i<=100;i++) {
if(i%2==0) { //当为偶数时
evenSum+=i;
}else { //当为奇数时
oddSum+=i;
}
}
System.out.println("100以内奇数之和为:"+oddSum);
System.out.println("100以内偶数之和为:"+evenSum);
}
}
输出结果为:
break语句和continue语句
· break用于强行退出循环,不执行循环中剩余的语句。
· continue 语句用在循环语句体中,用于终止某次循环过程,即跳过循环体中尚未执行的语句,接着进行下一次是否执行循环的判定。
package com.yuxuange.test;
/**
* 随机生成数字,看多少次后生成88这个数字
* @author 羽轩阁
*
*/
public class Yuxuange {
public static void main(String[] args) {
int total=0;
while(true) {
total++;
int i=(int)Math.round(100*Math.random());
if(i==88) {
break;
}
}
System.out.println("一共运行了"+total+"次");
}
}
package com.yuxuange.test;
/**
* 100~200之间不能被8整除的数字,每行输出5个
* @author 羽轩阁
*
*/
public class Yuxuange {
public static void main(String[] args) {
int count=0;
for(int i=100;i<=200;i++) {
if(i%8==0) {
continue;
}
System.out.print(i+"\t");
count++;
if(count%5==0) {
System.out.println();
}
}
}
}
带标签的break语句和continue语句
package com.yuxuange.test;
/**
* 101~150之间所有的质数
* @author 羽轩阁
*
*/
public class Yuxuange {
public static void main(String[] args) {
outer:for(int i=101;i<=150;i++) {
for(int j=2;j<i/2;j++) {
if(i%j==0) {
continue outer;
}
}
System.out.print(i+" ");
}
}
}
输出结果为:
方法
· 方法就是一段用来完成特定功能的代码片段,类似于其它语言的函数。
· 方法用于定义该类或该类的实例的行为特征和功能实现。 方法是类和对象行为特征的抽象。
· 方法的声明格式:
[修饰符1 修饰符2 …] 返回值类型 方法名(形式参数列表){
Java语句;… … …
}
· 方法的调用方式:
对象名.方法名(实参列表)
· 方法的详细说明:
1. 形式参数:在方法声明时用于接收外界传入的数据。
2. 实参:调用方法时实际传给方法的数据。
3. 返回值:方法在执行完毕后返还给调用它的环境的数据。
4. 返回值类型:事先约定的返回值的数据类型,如无返回值,必须显示指定为为void。
· 【注意】:
-
实参的数目、数据类型和次序必须和所调用的方法声明的形式参数列表匹配。
-
return 语句终止方法的运行并指定要返回的数据。
-
Java中进行方法调用中传递参数时,遵循值传递的原则(传递的都是数据的副本)
-
基本类型传递的是该数据值的copy值。
-
引用类型传递的是该对象引用的copy值,但指向的是同一个对象。
package com.yuxuange.test;
/**
* 方法的调用
* @author 羽轩阁
*
*/
public class Yuxuange {
public static void main(String[] args) {
Yuxuange yuxuange=new Yuxuange();
int sum=yuxuange.add(20, 30);
System.out.println(sum);
}
public int add(int a,int b) {
return a+b;
}
}
输出结果为:50
方法的重载(overload)
· 方法的重载是指一个类中可以定义多个方法名相同,但参数不同的方法。 调用时,会根据不同的参数自动匹配对应的方法。
· 构成方法重载的条件:
1.不同的含义:形参类型、形参个数、形参顺序不同
2.只有返回值不同不构成方法的重载
3.只有形参的名称不同,不构成方法的重载
package com.yuxuange.test;
/**
* 方法的重载
* @author 羽轩阁
*
*/
public class Yuxuange {
public static void main(String[] args) {
System.out.println(add(3, 5));// 8
System.out.println(add(3, 5, 10));// 18
System.out.println(add(3.0, 5));// 8.0
System.out.println(add(3, 5.0));// 8.0
}
/** 求和的方法 */
public static int add(int n1, int n2) {
int sum = n1 + n2;
return sum;
}
// 方法名相同,参数个数不同,构成重载
public static int add(int n1, int n2, int n3) {
int sum = n1 + n2 + n3;
return sum;
}
// 方法名相同,参数类型不同,构成重载
public static double add(double n1, int n2) {
double sum = n1 + n2;
return sum;
}
// 方法名相同,参数顺序不同,构成重载
public static double add(int n1, double n2) {
double sum = n1 + n2;
return sum;
}
//编译错误:只有返回值不同,不构成方法的重载
public static double add(int n1, int n2) {
double sum = n1 + n2;
return sum;
}
//编译错误:只有参数名称不同,不构成方法的重载
public static int add(int n2, int n1) {
double sum = n1 + n2;
return sum;
}
}
递归结构
· 递归的基本思想就是“自己调用自己”,一个使用递归技术的方法将会直接或者间接的调用自己。
· 递归结构包括两个部分:
1.定义递归头。解答:什么时候不调用自身方法。如果没有头,将陷入死循环,也就是递归的结束条件。
2.递归体。解答:什么时候需要调用自身方法。
package com.yuxuange.test;
/**
* 计算10!
* @author 羽轩阁
*
*/
public class Yuxuange {
public static void main(String[] args) {
long time1=System.currentTimeMillis();//获取当前的时间
System.out.printf("%d阶乘的结果:%s%n",10,factorial(10));
long time2=System.currentTimeMillis();
System.out.printf("递归耗时:%s%n",time2-time1);
}
static long factorial(int x) {
if(x==1) {
return 1;
}else {
return x*factorial(x-1);
}
}
}
输出结果为:
面向对象的内存分析
Java虚拟机的内存可以分为三个区域:栈stack、堆heap、方法区method area。
··· 栈的特点如下:
1. 栈描述的是方法执行的内存模型。每个方法被调用都会创建一个栈帧(存储局部变量、操作数、方法出口等)
2. JVM为每个线程创建一个栈,用于存放该线程执行方法的信息(实际参数、局部变量等)
3. 栈属于线程私有,不能实现线程间的共享!
4. 栈的存储特性是“先进后出,后进先出”
5. 栈是由系统自动分配,速度快!栈是一个连续的内存空间!
··· 堆的特点如下:
1. 堆用于存储创建好的对象和数组(数组也是对象)
2. JVM只有一个堆,被所有线程共享
3. 堆是一个不连续的内存空间,分配灵活,速度慢!
··· 方法区(又叫静态区)特点如下:
1. JVM只有一个方法区,被所有线程共享!
2. 方法区实际也是堆,只是用于存储类、常量相关的信息!
3. 用来存放程序中永远是不变或唯一的内容。(类信息【Class对象】、静态变量、字符串常量等)
构造方法
· 构造器也叫构造方法(constructor),用于对象的初始化。构造器是一个创建对象时被自动调用的特殊方法,目的是对象的初始化。构造器的名称应与类的名称一致。Java通过new关键字来调用构造器,从而返回该类的实例,是一种特殊的方法。
· 声明格式:
[修饰符] 类名(形参列表){
//n条语句
}
· 要点:
1. 通过new关键字调用!!
2. 构造器虽然有返回值,但是不能定义返回值类型(返回值的类型肯定是本类),不能在构造器里使用return返回某个值。
3. 如果我们没有定义构造器,则编译器会自动定义一个无参的构造函数。如果已定义则编译器不会自动添加!
4. 构造器的方法名必须和类名一致!
static关键字
· 在类中,用static声明的成员变量为静态成员变量,也称为类变量。 类变量的生命周期和类相同,在整个应用程序执行期间都有效。
· 特点:
1. 为该类的公用变量,属于类,被该类的所有实例共享,在类被载入时被显式初始化。
2. 对于该类的所有对象来说,static成员变量只有一份。被该类的所有对象共享!!
3. 一般用“类名.类属性/方法”来调用。(也可以通过对象引用或类名(不需要实例化)访问静态成员。)
4. 在static方法中不可直接访问非static的成员。
· 要点:
static修饰的成员变量和方法,从属于类。
普通变量和方法从属于对象的。
参数传值
方法中所有参数都是“值传递”,也就是“传递的是值的副本”。 也就是说,得到的是“原参数的复印件,而不是原件”。因此,复印件改变不会影响原件。
· 基本数据类型参数的传值
传递的是值的副本。 副本改变不会影响原件。
· 引用类型参数的传值
传递的是值的副本。但是引用类型指的是“对象的地址”。因此,副本和原参数都指向了同一个“地址”,改变“副本指向地址对象的值,也意味着原参数指向对象的值也发生了改变”。
package com.yuxuange.test;
/**
* 参数传值
* @author 羽轩阁
*
*/
public class Yuxuange {
private int id;
private String name;
private String password;
public Yuxuange(String name,String password) {
this.name=name;
this.password=password;
}
public void method1(Yuxuange u) {
u.name="张三";
}
public void method2(Yuxuange u) {
u = new Yuxuange("李四", "123456");
}
public static void main(String[] args) {
Yuxuange u = new Yuxuange("王五", "JQKA");
u.method1(u);
System.out.println(u.name);
u.method2(u);
System.out.println(u.name);
}
}
输出结果如下:
Java面向对象的三大特征:继承、封装、多态
继承
· Java中只有单继承
package com.yuxuange.test;
/**
* 继承
* @author 羽轩阁
*
*/
public class Yuxuange {
public static void main(String[] args) {
Train train1 =new Train();
train1.name="高速列车";
train1.source="电能";
train1.length=125;
train1.speed=379.3;
train1.run();
Train train2=new Train("磁悬浮列车","磁能",88,397.5);
System.out.println(train2 instanceof Train);
System.out.println(train2 instanceof Landvehicle);
System.out.println(train2 instanceof Object);
System.out.println(new Landvehicle() instanceof Train);
}
}
class Landvehicle{
//交通工具名称
String name;
//所用能源
String source;
public void run() {
System.out.println("moving now!");
}
}
class Train extends Landvehicle{
//长度
int length;
//速度
double speed;
public void stop() {
System.out.println("stop here now!");
}
public Train(String name,String source,int length,double speed) {
this.name=name;
this.source=source;
this.length=length;
this.speed=speed;
}
public Train() {
}
}
输出结果如下:
重写
· 方法的重写需要符合下面的三个要点:
1.“==”: 方法名、形参列表相同。
2.“≤”:返回值类型和声明异常类型,子类小于等于父类。
3.“≥”: 访问权限,子类大于等于父类。
package com.yuxuange.test;
/**
* 重写
* @author 羽轩阁
*
*/
public class Yuxuange {
public static void main(String[] args) {
Train train=new Train();
train.run();
Car car=new Car();
car.run();
}
}
class Landvehicle{
//交通工具名称
String name;
//所用能源
String source;
public void run() {
System.out.println("moving now!");
}
public void stop() {
System.out.println("stop here now!");
}
}
class Train extends Landvehicle{
public void run() {
System.out.println("准备完毕,可以出发...");
}
}
class Car extends Landvehicle{
public void run() {
System.out.println("速度太快了,闯红灯啦...");
}
}
输出结果如下:
Object类
Object类是所有Java类的根基类,也就意味着所有的Java对象都拥有Object类的属性和方法。
package com.yuxuange.test;
/**
* Object类
* @author 羽轩阁
*
*/
public class Yuxuange {
public static void main(String[] args) {
Yuxuange yuxuange=new Yuxuange();
System.out.println(yuxuange.toString());
Person person =new Person("张三",18);
System.out.println(person.toString());
}
public String toString() {
return "toString()方法已被重写...";
}
}
class Person{
String name;
int age;
public Person(String name,int age) {
this.name=name;
this.age=age;
}
public String toString() {
return "姓名:"+name+",年龄:"+age;
}
}
输出结果如下:
==和equals方法
“==”代表比较双方是否相同。如果是基本类型则表示值相等,如果是引用类型则表示地址相等即是同一个对象。
Object类中定义有:public boolean equals(Object obj)方法,提供定义“对象内容相等”的逻辑。
Object 的 equals 方法默认就是比较两个对象的hashcode,是同一个对象的引用时返回 true 否则返回 false。但是,我们可以根据我们自己的要求重写equals方法。
package com.yuxuange.test;
/**
* ==和equals
*
* @author 羽轩阁
*
*/
public class Yuxuange {
public static void main(String[] args) {
Student student1 = new Student(1, "张三", 18);
Student student2 = new Student(1, "李四", 21);
System.out.println(student1 == student2);
System.out.println(student1.equals(student2));
System.out.println("--------------------------------------------");
String str1 = new String("羽轩阁");
String str2 = new String("羽轩阁");
System.out.println(str1 == str2);
System.out.println(str1.equals(str2));
}
}
class Student {
int id;
String name;
int age;
public Student(int id, String name, int age) {
super();
this.id = id;
this.name = name;
this.age = age;
}
// 自动生成
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + id;
return result;
}
输出结果如下;
super关键字
super是直接父类对象的引用。可以通过super来访问父类中被子类覆盖的方法或属性。
使用super调用普通方法,语句没有位置限制,可以在子类中随便调用。
若是构造方法的第一行代码没有显式的调用super(…)或者this(…);那么Java默认都会调用super(),含义是调用父类的无参数构造方法。这里的super()可以省略。
package com.yuxuange.test;
/**
* super关键字
*
* @author 羽轩阁
*
*/
public class Yuxuange {
public static void main(String[] args) {
new ChildClass().method();
}
}
class FatherClass{
public int value;
public void method() {
value=1;
System.out.println("FatherClass.value="+value);
}
}
class ChildClass extends FatherClass{
public int value;
public void method() {
super.method();
value=100;
System.out.println("ChildClass.value="+value);
System.out.println(super.value);
System.out.println(value);
}
}
输出结果如下:
·构造方法调用顺序:
构造方法第一句总是:super(…)来调用父类对应的构造方法。所以,流程就是:先向上追溯到Object,然后再依次向下执行类的初始化块和构造方法,直到当前子类为止。
package com.yuxuange.test;
/**
* 构造方法调用顺序
*
* @author 羽轩阁
*
*/
public class Yuxuange {
public static void main(String[] args) {
new ChildClass();
}
}
class FatherClass{
public FatherClass() {
//super();
System.out.println("创建FatherClass");
}
}
class ChildClass extends FatherClass{
public ChildClass() {
//super();
System.out.println("创建ChildClass");
}
}
输出结果如下:
访问修饰符的权限
本类中 | 同一个包中 | 不同包中的子类中 | 不同包中 | |
---|---|---|---|---|
private | ✔ | |||
默认 | ✔ | ✔ | ||
protected | ✔ | ✔ | ✔ | |
public | ✔ | ✔ | ✔ | ✔ |
多态
多态的要点:
-
多态是方法的多态,不是属性的多态(多态与属性无关)。
-
多态的存在要有3个必要条件:继承,方法重写,父类引用指向子类对象。
-
父类引用指向子类对象后,用该父类引用调用子类重写的方法,此时多态就出现了。
package com.yuxuange.test; /** * 多态 * * @author 羽轩阁 * */ public class Yuxuange { public static void main(String[] args) { // Animal animal=new Animal(); // animalShout(animal); // Cat cat=new Cat(); // animalShout(cat); // Dog dog=new Dog(); // animalShout(dog); animalShout(new Animal()); animalShout(new Dog()); animalShout(new Cat()); } static void animalShout(Animal animal) { animal.shout(); } } class Animal{ public void shout() { System.out.println("叫了一声..."); } } class Dog extends Animal{ public void shout() { System.out.println("汪汪汪..."); } } class Cat extends Animal{ public void shout() { System.out.println("喵喵喵..."); } }
输出结果为:
对象的转型
package com.yuxuange.test;
/**
* 对象转型
*
* @author 羽轩阁
*
*/
public class Yuxuange {
public static void main(String[] args) {
Animal animal=new Animal();
animalShout(animal);
//自动向上转型,是猫狗的一定是动物,但是动物不一定是猫狗(小-->大)
Animal Dog=new Dog();
animalShout(Dog);
Animal Cat=new Cat();
animalShout(Cat);
//强制向下转型(大-->小)
Dog dog2=(Dog) Dog;
dog2.watchDoor();
//强转失败,编译通过,运行异常
Dog dog3=(Dog) Cat;
dog3.watchDoor();
}
static void animalShout(Animal animal) {
animal.shout();
}
}
class Animal{
public void shout() {
System.out.println("叫了一声...");
}
}
class Dog extends Animal{
public void shout() {
System.out.println("汪汪汪...");
}
public void watchDoor() {
System.out.println("看门...");
}
}
class Cat extends Animal{
public void shout() {
System.out.println("喵喵喵...");
}
}
输出结果为:
final关键字
final关键字的作用:
1.修饰变量: 被他修饰的变量不可改变。一旦赋了初值,就不能被重新赋值。
2. 修饰方法:该方法不可被子类重写。但是可以被重载!
如图:
3. 修饰类: 修饰的类不能被继承。比如:Math、String等。
数组
1.定义:数组是相同类型数据的有序集合。数组描述的是相同类型的若干个数据,按照一定的先后次序排列组合而成。其中,每一个数据称作一个元素,每个元素可以通过一个索引(下标)来访问它们。2.基本特点:
· 长度是确定的。数组一旦被创建,它的大小就是不可以改变的。
· 其元素必须是相同类型,不允许出现混合类型。
· 数组类型可以是任何数据类型,包括基本类型和引用类型。
package com.yuxuange.test;
/**
* 数组声明方式
*
* @author 羽轩阁
*
*/
public class Yuxuange {
public static void main(String[] args) {
//第一种数组声明的方式
int[] arr01=new int[3];
Car[] arr03=new Car[2];
//第二种数组声明的方式
int arr04[]=new int[3];
Car arr05[]=new Car[4];
//索引下标[0,length-1]
arr01[0]=1;
arr01[1]=2;
arr01[2]=3;
//arr01[100]=4; java.lang.ArrayIndexOutOfBoundsException(数据越界异常)
for(int i=0;i<arr01.length;i++) {
System.out.println(arr01[i]);
}
arr03[0]=new Car("宝马", "最大速度230km/h");
arr03[1]=new Car("奥迪", "最大速度240km/h");
for(int i=0;i<arr03.length;i++) {
System.out.println(arr03[i].getBrand()+"-----"+arr03[i].getAttribute());
}
}
}
class Car{
private String brand;
private String attribute;
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public String getAttribute() {
return attribute;
}
public void setAttribute(String attribute) {
this.attribute = attribute;
}
public Car(String brand,String attribute) {
this.brand=brand;
this.attribute=attribute;
}
}
输出结果为:
注意:
· 声明的时候并没有实例化任何对象,只有在实例化数组对象时,JVM才分配空间,这时才与长度有关。
· 声明一个数组的时候并没有数组真正被创建。
· 构造一个数组,必须指定长度。
3.初始化及数组遍历
package com.yuxuange.test;
/**
* 数组初始化,及遍历方式
*
* @author 羽轩阁
*
*/
public class Yuxuange {
public static void main(String[] args) {
//动态初始化
int arr1[] = new int[3];
arr1[0]=1;
arr1[1]=2;
arr1[2]=3;
//for遍历
for(int i=0;i<arr1.length;i++) {
System.out.println(arr1[i]);
}
//静态初始化
String names[]= {"张三","李四","王五"};
//foreach遍历
for (String string : names) {
System.out.println(string);
}
}
}
输出结果为:
· 拷贝
package com.yuxuange.test;
/**
* 数组的拷贝
*
* @author 羽轩阁
*
*/
public class Yuxuange {
public static void main(String[] args) {
String[] name= {"张三","李四","王五"};
String[] copyname=new String[6];
//src原数组对象,srcPos原数组从哪个位置开始拷贝,dest新数组对象,destPos新数组的拷贝起始位置,length从原数组拷贝几个到新数组
//System.arraycopy(src, srcPos, dest, destPos, length);
System.arraycopy(name, 1, copyname, 4, 2);
for(int i=0;i<copyname.length;i++) {
System.out.println(i+"---"+copyname[i]);
}
}
}
输出结果为:
抽象方法和抽象类
抽象方法:使用abstract修饰的方法,没有方法体,只有声明。
抽象类:包含抽象方法的类就是抽象类。
要点:
· 有抽象方法的类只能定义成抽象类
· 抽象类不能实例化,即不能用new来实例化抽象类。
· 抽象类可以包含属性、方法、构造方法。但是构造方法不能用来new实例,只能用来被子类调用。
· 抽象类只能用来被继承。
· 抽象方法必须被子类实现。
接口
· 声明格式:
[访问修饰符] interface 接口名 [extends 父接口1,父接口2…] {
常量定义;
方法定义;
}
· 说明
访问修饰符:只能是public或默认。
接口名:和类名采用相同命名机制。
extends:接口可以多继承。
常量:接口中的属性只能是常量,总是:public static final 修饰。不写也是。
方法:接口中的方法只能是:public abstract。 省略的话,也是public abstract。
· 要点
子类通过implements来实现接口中的规范。
接口不能创建实例,但是可用于声明引用变量类型。
一个类实现了接口,必须实现接口中所有的方法,并且这些方法只能是public的。
JDK1.7之前,接口中只能包含静态常量、抽象方法,不能有普通属性、构造方法、普通方法。
JDK1.8后,接口中包含普通的静态方法。
· 接口支持多继承
package com.yuxuange.test;
/**
* 接口
*
* @author 羽轩阁
*
*/
public class Yuxuange {
public static void main(String[] args) {
brand brand = new car();
brand.brand();
running running = new car();
running.run();
}
}
interface running {
int RUN_LENGTH = 800;
void run();
}
interface brand {
void brand();
}
class car implements running, brand {
@Override
public void brand() {
System.out.println("宝马");
}
@Override
public void run() {
System.out.println("时速240km/h");
}
}
输出结果为:
自动装箱与拆箱
自动装箱和拆箱就是将基本数据类型和包装类之间进行自动的互相转换。
package com.yuxuange.test;
/**
* 自动装箱和拆箱
*
* @author 羽轩阁
*
*/
public class Yuxuange {
public static void main(String[] args) {
Integer a=234; //自动装箱,编译器会自动修改成:Integer a=Integer.valueOf(234);
int b =a;//自动拆箱,编译器会自动修改成:int b=a.intValue();
//缓存[-128,127]之间的数字。实际就是系统初始化的时候,创建了[-128,127]之间的一个缓存数组。
//当调用valueOf()的时候,首先检查是否在[-128,127]之间,如果在这个范围则直接从缓存数组中拿出已经创建好的对象
//如果不在这个范围,则创建新的对象
Integer in1=Integer.valueOf(-128);
Integer in2=-128;
System.out.println(in1==in2);
System.out.println(in1.equals(in2));
System.out.println("-------------------------");
Integer in3=1234;
Integer in4=1234;
System.out.println(in3==in4);
System.out.println(in3.equals(in4));
}
}
输出结果为:
为什么in1和in2是两个不同的对象,当"=="时却返回true呢?
这是源码valueOf():
枚举
所有的枚举类型隐性地继承自 java.lang.Enum。枚举实质上还是类!而每个被枚举的成员实质就是一个枚举类型的实例,他们默认都是public static final修饰的。可以直接通过枚举类型名使用它们。
package com.yuxuange.test;
import java.util.Random;
/**
* 测试枚举
*
* @author 羽轩阁
*
*/
public class Yuxuange {
public static void main(String[] args) {
int a = new Random().nextInt(6);
switch (Week.values()[a]) {
case 星期一:
System.out.println("今天是星期一");
break;
case 星期二:
System.out.println("今天是星期二");
break;
case 星期三:
System.out.println("今天是星期三");
break;
case 星期四:
System.out.println("今天是星期四");
break;
case 星期五:
System.out.println("今天是星期五");
break;
case 星期六:
System.out.println("今天是星期六");
break;
case 星期天:
System.out.println("今天是星期天");
break;
}
}
}
enum Week {
星期一, 星期二, 星期三, 星期四, 星期五, 星期六, 星期天
}
异常机制
· 本质: 就是当程序出现错误,程序安全退出的机制。
· 概念:异常指程序运行过程中出现的非正常现象,例如用户输入错误、除数为零、需要处理的文件不存在、数组下标越界等。
· 在Java的异常处理机制中,引进了很多用来描述和处理异常的类,称为异常类。异常类定义中包含了该类异常的信息和对异常进行处理的方法。
· 异常处理,就是指程序在出现问题时依然可以正确的执行完。
· 分类:
捕获异常
捕获异常是通过try-catch-finally这三个关键字来实现的。用try来执行一段程序,如果出现异常,系统抛出一个异常,可以通过它的类型来捕捉(catch)并处理它,最后一步是通过finally语句为异常处理提供一个统一的出口,finally所指定的代码都要被执行(catch语句可有多条;finally语句最多只能有一条,根据自己的需要可有可无)。
-
try:
try语句指定了一段代码,该段代码就是异常捕获并处理的范围。在执行过程中,当任意一条语句产生异常时,就会跳过该条语句中后面的代码。代码中可能会产生并抛出一种或几种类型的异常对象,它后面的catch语句要分别对这些异常做相应的处理。
一个try语句必须带有至少一个catch语句块或一个finally语句块 。
注意事项: 当异常处理的代码执行结束以后,不会回到try语句去执行尚未执行的代码。
-
catch:
n-每个try语句块可以伴随一个或多个catch语句,用于处理可能产生的不同类型的异常对象。
n-常用方法,这些方法均继承自Throwable类 。
u-toString ()方法,显示异常的类名和产生异常的原因
u-getMessage()方法,只显示产生异常的原因,但不显示类名。
u-printStackTrace()方法,用来跟踪异常事件发生时堆栈的内容。
n-catch捕获异常时的捕获顺序:
u-如果异常类之间有继承关系,在顺序安排上需注意。越是顶层的类,越放在下面,再不然就直接把多余的catch省略掉。 也就是先捕获子类异常再捕获父类异常。
-
finally:
n-有些语句,不管是否发生了异常,都必须要执行,那么就可以把这样的语句放到finally语句块中。
n-通常在finally中关闭程序块已打开的资源,比如:关闭文件流、释放数据库连接等。
try-catch-finally语句块的执行过程:
程序首先执行可能发生异常的try语句块。如果try语句没有出现异常则执行完后跳至finally语句块执行;如果try语句出现异常,则中断执行并根据发生的异常类型跳至相应的catch语句块执行处理。catch语句块可以有多个,分别捕获不同类型的异常。catch语句块执行完后程序会继续执行finally语句块。finally语句是可选的,如果有的话,则不管是否发生异常,finally语句都会被执行。
声明异常(throws子句)
当CheckedException产生时,不一定立刻处理它,可以再把异常throws出去。
自定义异常
· 在程序中,可能会遇到JDK提供的任何标准异常类都无法充分描述清楚我们想要表达的问题,这种情况下可以创建自己的异常类,即自定义异常类。
· 自定义异常类只需从Exception类或者它的子类派生一个子类即可。
· 自定义异常类如果继承Exception类,则为受检查异常,必须对其进行处理;如果不想处理,可以让自定义异常类继承运行时异常RuntimeException类。
· 习惯上,自定义异常类应该包含2个构造器:一个是默认的构造器,另一个是带有详细信息的构造器。
package com.yuxuange.test;
/**
* 自定义异常
*
* @author 羽轩阁
*
*/
public class Yuxuange {
public static void main(String[] args) {
Week week=new Week();
week.setWeek(9);
}
}
class Week{
private int week;
public int getWeek() {
return week;
}
public void setWeek(int week) {
if(week<0 || week>7) {
throw new IllegalWeekException("数据有误,请重新输入...");
}
this.week = week;
}
}
class IllegalWeekException extends RuntimeException{
public IllegalWeekException() {}
public IllegalWeekException(String message) {
super(message);
}
}
输出结果为:
泛型
自定义泛型:
package com.yuxuange.test;
/**
* 自定义泛型
*
* @author 羽轩阁
*
*/
public class Yuxuange {
public static void main(String[] args) {
MyCollection myCollection=new MyCollection();
myCollection.setObjects("羽轩阁", 0);
myCollection.setObjects(666, 1);
System.out.println(myCollection.getObjects(0));
System.out.println(myCollection.getObjects(1));
MyNewCollection<String> myNewCollection=new MyNewCollection();
myNewCollection.setObjects("羽轩阁", 0);
myNewCollection.setObjects("学习中...", 1);
规定反应报错
//myNewCollection.setObjects(666,2);
System.out.println(myNewCollection.getObjects(1));
}
}
class MyCollection{
Object[] objects=new Object[5];
public Object getObjects(int index) {
return objects[index];
}
public void setObjects(Object object,int index) {
objects[index]=object;
}
}
class MyNewCollection<T>{
Object[] objects=new Object[5];
public T getObjects(int index) {
return (T) objects[index];
}
public void setObjects(T t,int index) {
objects[index]=t;
}
}
输出结果为:
Collection接口
Collection接口的两个子接口是List、Set接口。
package com.yuxuange.test;
import java.util.ArrayList;
import java.util.Collection;
/**
* Collection接口
*
* @author 羽轩阁
*
*/
public class Yuxuange {
public static void main(String[] args) {
Collection<String> c = new ArrayList<>() ;
System.out.println(c.size());
//判断list中是否为空
System.out.println(c.isEmpty());
//添加两个对象
c.add("张三");
c.add("李四");
System.out.println(c.size());
//移除“李四”对象
c.remove("李四");
System.out.println(c.size());
//判断“李四”对象是否在list中
System.out.println(c.contains("李四"));
//再添加一个对象
c.add("王五");
Object[] objects=c.toArray();
for(int i=0;i<objects.length;i++) {
System.out.println(objects[i]);
}
//移除所有对象
c.clear();
System.out.println(c.size());
}
}
输出结果为:
package com.yuxuange.test;
import java.util.ArrayList;
import java.util.Collection;
/**
* Collection接口
*
* @author 羽轩阁
*
*/
public class Yuxuange {
public static void main(String[] args) {
Collection<Integer> list1 = new ArrayList<>();
list1.add(10);
list1.add(20);
list1.add(30);
Collection<Integer> list2 = new ArrayList<>();
list2.add(10);
list2.add(100);
list2.add(1000);
System.out.println("list1" + list1);
System.out.println("list2" + list2);
// 将list2中的元素添加list1中
list1.addAll(list2);
System.out.println("list1" + list1);
System.out.println("list2" + list2);
Collection<Integer> list3 = new ArrayList<>();
list3.add(1);
list3.add(10);
list3.add(19);
System.out.println("list3" + list3);
// 移除list3与list2中相同的元素
list3.removeAll(list2);
System.out.println("list3" + list3);
}
}
输出结果为:
List
List是有序、可重复的容器。
· 有序:List中每个元素都有索引标记。可以根据元素的索引标记(在List中的位置)访问元素,从而精确控制这些元素。
· 可重复:List允许加入重复的元素。更确切地讲,List通常允许满足 e1.equals(e2) 的元素重复加入容器。
List接口常用的实现类有3个:ArrayList(常见)、LinkedList和Vector。
package com.yuxuange.test;
import java.util.ArrayList;
import java.util.List;
/**
* List接口
*
* @author 羽轩阁
*
*/
public class Yuxuange {
public static void main(String[] args) {
List<String> list =new ArrayList<>();
//添加四个元素
list.add("A");
list.add("B");
list.add("C");
list.add("D");
System.out.println(list);
//在指定位置添加元素
list.add(1, "+");
System.out.println(list);
//移除指定位置上的元素
list.remove(1);
System.out.println(list);
//修改指定位置上的元素
list.set(1, "+");
//添加两个相同的元素
list.add("A");
list.add("A");
System.out.println(list);
//获取指定位置上的元素
System.out.println(list.get(1));
//显示第一个匹配的元素索引,有该元素显示索引数,无则显示-1
System.out.println(list.indexOf("A"));
System.out.println(list.indexOf("-"));
//获取最后一个匹配的元素索引
System.out.println(list.lastIndexOf("A"));
}
}
输出结果为:
Map
Map就是用来存储“键(key)-值(value) 对”的。 Map类中存储的“键值对”通过键来标识,所以“键对象”不能重复。
Map 接口的实现类有HashMap(常用)、TreeMap、HashTable、Properties等。
package com.yuxuange.test;
import java.util.HashMap;
import java.util.Map;
/**
* Map接口
*
* @author 羽轩阁
*
*/
public class Yuxuange {
public static void main(String[] args) {
Map<Integer, String> map=new HashMap<>();
map.put(1, "first");
map.put(2, "second");
map.put(3, "third");
//获取key为1对应的值
System.out.println(map.get(1));
//获取Map的大小
System.out.println(map.size());
//判断Map是否为空
System.out.println(map.isEmpty());
//判断Map中是否包含key为3的值
System.out.println(map.containsKey(3));
Map<Integer, String> map2=new HashMap<>();
map2.put(4, "fourth");
map2.put(5, "fifth");
//将map2中所有的键值对放入map中
map.putAll(map2);
System.out.println(map);
//Map中的键不能重复;如果重复(判断利用 equals方法),新的值将覆盖旧的值;
map.put(3, "叁");
System.out.println(map);
//将key为3的键值对删除
map.remove(3);
System.out.println(map);
//清空Map中所有的键值对
map.clear();
System.out.println(map.size());
}
}
输出结果如下:
TreeMap
TreeMap和HashMap实现了同样的接口Map,HashMap效率高于TreeMap;在需要排序的Map时才选用TreeMap。
package com.yuxuange.test;
import java.util.Map;
import java.util.TreeMap;
/**
* TreeMap接口
*
* @author 羽轩阁
*
*/
public class Yuxuange {
public static void main(String[] args) {
Map<Emp, String> map=new TreeMap<>();
map.put(new Emp(400, "钱二", 20000), "超高等收入人群");
map.put(new Emp(100, "张三", 10000), "高等收入人群");
map.put(new Emp(200, "李四", 5000), "中等收入人群");
map.put(new Emp(300, "王五", 2500), "低等收入人群");
for (Emp key : map.keySet()) {
System.out.println(key+"-----"+map.get(key));
}
}
}
class Emp implements Comparable<Emp> {
int id;
String name;
double salary;
public Emp(int id, String name, double salary) {
super();
this.id = id;
this.name = name;
this.salary = salary;
}
@Override
public String toString() {
return "Emp [id=" + id + ", name=" + name + ", salary=" + salary + "]";
}
@Override
//负数:小于;0:等于;正数:大于
public int compareTo(Emp o) {
if(this.salary>o.salary) {
return 1;
}else if(this.salary<o.salary) {
return -1;
}else {
if(this.id>o.id) {
return 1;
}else if(this.id<o.id) {
return -1;
}else {
return 0;
}
}
}
}
输入结果如下:
HashTable
· HashTable类和HashMap用法几乎一样,底层实现几乎一样,只不过HashTable的方法添加了synchronized关键字确保线程同步检查,效率较低。
· 与HashMap的区别
1.HashMap: 线程不安全,效率高。允许key或value为null。
2.HashTable: 线程安全,效率低。不允许key或value为null。
package com.yuxuange.test;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
/**
* HashTable
*
* @author 羽轩阁
*
*/
public class Yuxuange {
public static void main(String[] args) {
Map<String, String> map=new HashMap<>();
map.put(null, "map空key");
map.put("map空value", null);
System.out.println(map);
Map<String, String> map2=new Hashtable<>();
//map2.put(null, "table空key");
map2.put("table空value", null);
System.out.println(map2);
}
}
Set接口
· Set接口继承自Collection,Set接口中没有新增方法,方法和Collection保持完全一致。
· Set容器特点:无序、不可重复。无序指Set中的元素没有索引,只能遍历查找;不可重复指不允许加入重复的元素。
· Set中也只能放入一个null元素,不能多个。
TreeSet
TreeSet底层实际是用TreeMap实现的,内部维持了一个简化版的TreeMap,通过key来存储Set的元素。 TreeSet内部需要对存储的元素进行排序,因此,我们对应的类需要实现Comparable接口。
package com.yuxuange.test;
import java.util.Set;
import java.util.TreeSet;
/**
* HashSet
*
* @author 羽轩阁
*
*/
public class Yuxuange {
public static void main(String[] args) {
Set<Integer> set=new TreeSet<>();
set.add(100);
set.add(125);
set.add(75);
for (Integer integer : set) {
System.out.println(integer);
}
Set<Emp> emps=new TreeSet<>();
emps.add(new Emp(100, "张三", 5000));
emps.add(new Emp(200, "李四", 10000));
emps.add(new Emp(300, "王五", 7500));
for (Emp emp : emps) {
System.out.println(emp);
}
}
}
class Emp implements Comparable<Emp> {
int id;
String name;
double salary;
public Emp(int id, String name, double salary) {
super();
this.id = id;
this.name = name;
this.salary = salary;
}
@Override
public String toString() {
return "Emp [id=" + id + ", name=" + name + ", salary=" + salary + "]";
}
@Override
//负数:小于;0:等于;正数:大于
public int compareTo(Emp o) {
if(this.salary>o.salary) {
return 1;
}else if(this.salary<o.salary) {
return -1;
}else {
if(this.id>o.id) {
return 1;
}else if(this.id<o.id) {
return -1;
}else {
return 0;
}
}
}
}
输出结果如下:
迭代器
迭代器提供了统一的遍历容器的方式
package com.yuxuange.test;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
/**
* 迭代器遍历List,Set,Map
*
* @author 羽轩阁
*
*/
public class Yuxuange {
public static void main(String[] args) {
List<Integer> list=new ArrayList<>();
list.add(1);
list.add(100);
list.add(50);
iteratorList(list);
System.out.println("------------------------------");
Set<String> set=new HashSet<>();
set.add("张三");
set.add("王五");
set.add("李四");
iteratorSet(set);
System.out.println("------------------------------");
Map<Integer, String> map=new HashMap<>();
map.put(1, "张三");
map.put(100, "王五");
map.put(50, "李四");
iteratorMapByEntrySet(map);
System.out.println("------------------------------");
iteratorMapByKeySet(map);
}
//使用迭代器遍历List集合
public static void iteratorList(List<Integer> list) {
for (Iterator<Integer> iter=list.iterator();iter.hasNext();) {
Integer temp= iter.next();
System.out.println(temp);
}
}
//使用迭代器遍历Set集合
public static void iteratorSet(Set<String> set) {
for(Iterator<String> iter=set.iterator();iter.hasNext();) {
String temp=iter.next();
System.out.println(temp);
}
}
//使用迭代器遍历Map集合1
public static void iteratorMapByEntrySet(Map<Integer, String> map) {
Set<Entry<Integer, String>> set=map.entrySet();
for(Iterator<Entry<Integer, String>> iter=set.iterator();iter.hasNext();) {
Entry<Integer, String> temp=iter.next();
System.out.println(temp);
}
}
//使用迭代器遍历Map集合2
public static void iteratorMapByKeySet(Map<Integer, String> map) {
Set<Integer> set=map.keySet();
for(Iterator<Integer> iter=set.iterator();iter.hasNext();) {
Integer temp=iter.next();
System.out.println(temp+"="+map.get(temp));
}
}
}
输出结果为:
容器遍历方法总结:
package com.yuxuange.test;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
/**
* 遍历容器方法总结
*
* @author 羽轩阁
*
*/
public class Yuxuange {
public static void main(String[] args) {
//List
List<Human> list = new ArrayList<>();
list.add(new Human("张三", "男"));
list.add(new Human("李四", "女"));
// List第一种:普通for循环
System.out.println("List第一种方法");
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i).getName() + "------" + list.get(i).getSex());
}
// List第二种:增强for循环
System.out.println("List第二种方法");
for (Human human : list) {
System.out.println(human.getName() + "------" + human.getSex());
}
// List第三种:使用Iterator迭代器(1)
System.out.println("List第三种方法");
for (Iterator<Human> iterator = list.iterator(); iterator.hasNext();) {
Human human = iterator.next();
System.out.println(human.getName() + "------" + human.getSex());
}
// List第四种:使用Iterator迭代器(2)
System.out.println("List第四种方法");
Iterator<Human> iterator = list.iterator();
while (iterator.hasNext()) {
Human human = iterator.next();
System.out.println(human.getName() + "------" + human.getSex());
}
System.out.println("---------------------------");
//Set
Set<Human> set=new HashSet<>();
set.add(new Human("王五", "男"));
set.add(new Human("赵六", "女"));
//Set第一种:增强for循环
System.out.println("Set第一种方法");
for (Human human : set) {
System.out.println(human.getName()+"------"+human.getSex());
}
//Set第二种:使用Iterator迭代器
System.out.println("Set第二种方法");
for(Iterator<Human> iterator2=set.iterator();iterator2.hasNext();) {
Human human=iterator2.next();
System.out.println(human.getName()+"------"+human.getSex());
}
System.out.println("---------------------------");
//Map
Map<Integer, Human> map=new HashMap<>();
map.put(1, new Human("冯七", "男"));
map.put(2, new Human("钱八", "女"));
//Map第一种:根据key获取value
System.out.println("Map第一种方法");
Set<Integer> keySet=map.keySet();
for (Integer integer : keySet) {
System.out.println(integer+"------"+map.get(integer).getName()+"------"+map.get(integer).getSex());
}
//Map第二种:使用entrySet
System.out.println("Map第二种方法");
Set<Entry<Integer,Human>> entrySet=map.entrySet();
for(Iterator<Entry<Integer, Human>> iterator3=entrySet.iterator();iterator3.hasNext();) {
Entry<Integer, Human> entry=iterator3.next();
System.out.println(entry.getKey()+"------"+entry.getValue().getName()+"------"+entry.getValue().getSex());
}
}
}
class Human {
private String name;
private String sex;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public Human(String name, String sex) {
super();
this.name = name;
this.sex = sex;
}
}
输出结果为:
IO
流
流是一个抽象、动态的概念,是一连串连续动态的数据集合。
分类
按流向分类:
输入流:数据源到程序(InputStream,Reader读进来)
输出流:程序到数据源(OutputStream,Writer写出去)
按功能分类:
节点流:可以直接从数据源或目的地读写数据
处理流(包装流):不直接连接到数据源或目的地,是其他流进行封装。目的主要是简化操作和提高性能
节点流和处理流的关系:
1.节点流处于IO操作的第一线,所有操作都必须通过他们进行。
2.处理流可以对其他流进行处理(提高效率或操作灵活性)。
按数据分类:
字节流:按照字节读取数据(InputStream,OutputStream)
字符流:按照字符读取数据(Reader,Writer),因为文件编码的不同,从而有了对字符进行高效操作的字符流对象
File类操作文件的常用方法
File类操作文件夹的常用方法
package com.yuxuange.test;
import java.io.File;
/**
* 统计路径内的文件目录名称
*
* @author 羽轩阁
*
*/
public class Yuxuange {
public static void main(String[] args) {
String path = "D:/workspace/Players";
File src = new File(path);
printFileName(src, 1);
}
public static void printFileName(File src, int deep) {
for (int i = 0; i < deep; i++) {
System.out.print("-");
}
System.out.println(src.getName());
if (null == src || !src.exists()) {
return;
} else if (src.isDirectory()) {
for (File s : src.listFiles()) {
printFileName(s, deep + 1);
}
}
}
}
编码和解码
编码:字符串–>字节
解码:字节–>字符串
IO四个抽象类
抽象类 | 说明 | 常用方法 |
InputStream | 字节输入流的父类,数据单位为字节 |
|
OutputStream | 字节输出流的父类,数据单位为字节 |
|
Reader | 字符输出流的父类,数据单位为字符 |
|
Writer | 字符输出流的父类,数据单位为字符 |
|
步骤(雏形)
在项目里创建一个txt文件,并在txt文件里写入hello;
步骤(标准)
package com.yuxuange.test;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
/**
* IO步骤(雏形)
* @author 羽轩阁
*
*/
public class Yuxuange {
public static void main(String[] args) {
//1.创建源
File src=new File("test.txt");
//2.选择流
try {
InputStream inputStream=new FileInputStream(src);
//3.操作(读取)
int data1=inputStream.read();
int data2=inputStream.read();
int data3=inputStream.read();
int data4=inputStream.read();
int data5=inputStream.read();
//文件的末尾返回-1
int data6=inputStream.read();
System.out.println((char)data1);
System.out.println((char)data2);
System.out.println((char)data3);
System.out.println((char)data4);
System.out.println((char)data5);
System.out.println(data6);
//4.释放资源
inputStream.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
输出结果为:
package com.yuxuange.test;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
/**
* IO步骤(标准)
* @author 羽轩阁
*
*/
public class Yuxuange {
public static void main(String[] args) {
//1.创建源
File src=new File("test.txt");
InputStream inputStream=null;
//2.选择流
try {
inputStream=new FileInputStream(src);
//3.操作(读取)
int temp;
while((temp=inputStream.read())!=-1) {
System.out.println((char)temp);
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
//4.释放资源
try {
if(null!=inputStream) {
inputStream.close();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
输出结果为:
文件字节流
FileInputStream通过字节的方式读取文件,适合读取所有类型的文件(图像、视频、文本文件等)。
FileOutputStream 通过字节的方式写数据到文件中,适合所有类型的文件。
将test.txt文件中输入大量的文本,如图:
package com.yuxuange.test;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
/**
* IO文件字节输入流
* @author 羽轩阁
*
*/
public class Yuxuange {
public static void main(String[] args) {
//1.创建源
File src=new File("test.txt");
InputStream inputStream=null;
//2.选择流
try {
inputStream=new FileInputStream(src);
//3.操作(分段读取)
//缓冲容器
byte[] flush=new byte[1024];
//接收长度
int len=-1;
while((len=inputStream.read(flush))!=-1) {
//字节数组-->字符串(解码)
String string=new String(flush, 0, len);
System.out.println(string);
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
//4.释放资源
try {
if(null!=inputStream) {
inputStream.close();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
输出结果为:
package com.yuxuange.test;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
/**
* IO文件字节输出流
*
* @author 羽轩阁
*
*/
public class Yuxuange {
public static void main(String[] args) {
// 1.创建源
File src = new File("testOut.txt");
// 2.选择流
OutputStream outputStream = null;
try {
//true在文件内容后追加,false则是删除原先内容重新写入
outputStream = new FileOutputStream(src,true);
// 3.操作(写出)
String message = "Welcome to yuxuange\r\n";
// 字符串-->字节数组(编码)
byte[] datas = message.getBytes();
outputStream.write(datas, 0, datas.length);
outputStream.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
// 4.释放资源
if (null != outputStream) {
outputStream.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
程序执行5次后的输出结果为:
在项目结构中出现文件:
文件拷贝
在项目结构放入图片,取名为IT.png
图片内容:
package com.yuxuange.test;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
/**
* 文件拷贝:文件输入,输出字节流
*
* @author 羽轩阁
*
*/
public class Yuxuange {
public static void main(String[] args) {
// 1.创建源
File srcIn = new File("IT.png");
File srcOut = new File("ITCopy.png");
// 2.选择流
InputStream inputStream = null;
OutputStream outputStream = null;
try {
inputStream = new FileInputStream(srcIn);
outputStream = new FileOutputStream(srcOut);
// 3.操作(分段读取)
//缓冲容器
byte[] flush=new byte[1024];
//接收长度
int len=-1;
while((len=inputStream.read(flush))!=-1) {
outputStream.write(flush, 0, len);
}
outputStream.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
// 4.释放资源,先打开的后关闭,后代开的先关闭
try {
if (null != outputStream) {
outputStream.close();
}
} catch (IOException e) {
e.printStackTrace();
}
try {
if (null != inputStream) {
inputStream.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
执行结果后,在项目结构中出现:
文件字符流
FileReader:通过字符的方式读取文件,仅适合字符文件
FileWriter:通过字节的方式写出或追加数据到文件中,仅适合字符文件
将test.txt中的内容改为:
package com.yuxuange.test;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
/**
* IO文件字符输入流
*
* @author 羽轩阁
*
*/
public class Yuxuange {
public static void main(String[] args) {
// 1.创建源
File src = new File("test.txt");
Reader reader = null;
// 2.选择流
try {
reader = new FileReader(src);
// 3.操作(分段读取)
// 缓冲容器
char[] flush = new char[1024];
// 接收长度
int len = -1;
while ((len = reader.read(flush)) != -1) {
String string = new String(flush, 0, len);
System.out.println(string);
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
// 4.释放资源
try {
if (null != reader) {
reader.close();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
执行后,输出结果为:
package com.yuxuange.test;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
/**
* IO文件字符输出流
*
* @author 羽轩阁
*
*/
public class Yuxuange {
public static void main(String[] args) {
// 1.创建源
File src = new File("testOut.txt");
// 2.选择流
Writer writer = null;
try {
writer = new FileWriter(src);
// 3.操作(写出)
String message = "欢迎来到羽轩阁";
char[] datas = message.toCharArray();
writer.write(datas);
writer.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
// 4.释放资源
if (null != writer) {
writer.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
执行结果,在项目结构中出现testOut.txt文件,其中的内容为:
字节数组流
所有对象都可以读入字节数组流
package com.yuxuange.test;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
/**
* IO:字节数组输入流
* 1、创建源:字节数组 不要太大
* 2、选择流
* 3、操作
* 4、释放资源:可以不用处理
* @author 羽轩阁
*
*/
public class Yuxuange {
public static void main(String[] args) {
// 1.创建源
byte[] src = "Hello World!Hello World".getBytes();
// 2.选择流
InputStream inputStream = null;
try {
inputStream = new ByteArrayInputStream(src);
// 3.操作
byte[] flush = new byte[5];
int length = -1;
while ((length = inputStream.read(flush)) != -1) {
String string = new String(flush, 0, length);
System.out.println(string);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
// 4.释放资源
try {
if (null != inputStream) {
inputStream.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
package com.yuxuange.test;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
/**
* IO:字节数组输出流
* 1、创建源:内部维护
* 2、选择流:不关联源头
* 3、操作(写出数据)
* 4、释放资源:可以不用处理
* @author 羽轩阁
*
*/
public class Yuxuange {
public static void main(String[] args) {
// 1.创建源
byte[] dest = null;
// 2.选择流
ByteArrayOutputStream byteArrayOutputStream=null;
try {
byteArrayOutputStream = new ByteArrayOutputStream();
// 3.操作
String message="Hello World!Hello World!";
byte[] src=message.getBytes();
byteArrayOutputStream.write(src,0,src.length);
byteArrayOutputStream.flush();
//获取数据
dest = byteArrayOutputStream.toByteArray();
System.out.println(new String(dest,0,byteArrayOutputStream.size())+" 共"+dest.length+"个字节");
} catch (IOException e) {
e.printStackTrace();
} finally {
// 4.释放资源
try {
if (null != byteArrayOutputStream) {
byteArrayOutputStream.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
输出结果为:
利用字节数组流实现文件拷贝:
package com.yuxuange.test;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
/**
* IO:文件拷贝 说明:图片读取到字节数组中,将字节数组写出到文件
*
* @author 羽轩阁
*
*/
public class Yuxuange {
public static void main(String[] args) {
// 图片转成字节数组
byte[] array = fileToByteArray("IT.png");
System.out.println(array.length);
//字节数组写出到文件
byteArrayToFile(array, "ITCopy.png");
}
/**
* 图片读取到字节数组中 1.图片到程序 FileInputStream 2.程序到字节数组中 ByteArrayOutputStream
*/
public static byte[] fileToByteArray(String filePath) {
// 1.创建源
File src = new File(filePath);
// 2.选择流
InputStream inputStream = null;
ByteArrayOutputStream byteArrayOutputStream = null;
try {
inputStream = new FileInputStream(src);
byteArrayOutputStream = new ByteArrayOutputStream();
// 3.操作(分段读取)
// 缓冲容器
byte[] flush = new byte[1024];
// 接收长度
int len = -1;
while ((len = inputStream.read(flush)) != -1) {
// 写出到字节数组中
byteArrayOutputStream.write(flush, 0, len);
}
byteArrayOutputStream.flush();
return byteArrayOutputStream.toByteArray();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
// 4.释放资源
try {
if (null != inputStream) {
inputStream.close();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return null;
}
/**
* 字节数组写出到图片 1.字节数组到程序中 ByteArrayInputStream 2.程序写出到文件 FileOutputStream
*/
public static void byteArrayToFile(byte[] dest, String filePath) {
// 1.创建源
File src = new File(filePath);
// 2.选择流
InputStream inputStream = null;
OutputStream outputStream = null;
try {
inputStream = new ByteArrayInputStream(dest);
outputStream = new FileOutputStream(src);
// 3.操作
byte[] flush = new byte[1024];
int len = -1;
while ((len = inputStream.read(flush)) != -1) {
outputStream.write(flush, 0, len);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
// 4.释放资源
if (null != outputStream) {
outputStream.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
文件工具类的封装
package com.yuxuange.utils;
import java.io.Closeable;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
/**
* 文件工具类 1.封装文件拷贝 2.封装释放资源
*
* @author 羽轩阁
*
*/
public class FileUtils {
/**
* 对接:文件输入流-->文件输出流
*
* @param inputStream
* @param outputStream
*/
public static void copy(InputStream inputStream, OutputStream outputStream) {
try {
byte[] flush = new byte[1024];
int len = -1;
while ((len = inputStream.read(flush)) != -1) {
outputStream.write(flush, 0, len);
}
outputStream.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
close(inputStream, outputStream);
}
}
/**
* 释放资源:输出、输出流
*
* @param inputStream
* @param outputStream
*/
public static void close(InputStream inputStream, OutputStream outputStream) {
try {
if (null != outputStream) {
outputStream.close();
}
} catch (IOException e) {
e.printStackTrace();
}
try {
if (null != inputStream) {
inputStream.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 释放资源
* @param ios
*/
public static void close(Closeable... ios) {
for (Closeable io : ios) {
try {
if(null!=io) {
io.close();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
装饰器模式
- 1.抽象组件:需要装饰的抽象对象(一般情况:接口或抽象父类)
- 2.具体组件:需要装饰的对象
- 3.抽象装饰类:包含了对抽象组件的引用以及装饰着共有的方法
- 4.具体装饰类:被装饰的对象
模拟扩音器放大声音:
package com.yuxuange.test;
/**
* 模拟扩音器放大声音
*
* @author 羽轩阁
*
*/
public class Yuxuange {
public static void main(String[] args) {
Person person=new Person();
person.voice();
//扩音器开始扩音:装饰器模式
Amplifier amplifier=new Amplifier(person);
amplifier.voice();
}
}
interface Voice {
void voice();
}
class Person implements Voice {
private int peopleSay = 10;
@Override
public void voice() {
System.out.println("人说话的声音为:" + this.getPeopleSay()+"分贝");
}
public int getPeopleSay() {
return peopleSay;
}
public void setPeopleSay(int peopleSay) {
this.peopleSay = peopleSay;
}
}
class Amplifier implements Voice {
private Person person;
public Amplifier(Person person) {
this.person = person;
}
@Override
public void voice() {
System.out.println("人说话的声音经扩音器放大后为:" + person.getPeopleSay() * 100+"分贝");
}
}
输出结果为:
模拟购买咖啡加入其它原料:
package com.yuxuange.test;
/**
* 模拟咖啡加入糖,牛奶,巧克力
*
* @author 羽轩阁
*
*/
public class Yuxuange {
public static void main(String[] args) {
Drink coffee=new Coffee();
System.out.println("现价格为:"+coffee.cost()+"元");
Drink milk=new Milk(coffee);//装饰
System.out.println(milk.info()+"-->"+"现价格为:"+milk.cost()+"元");
Drink sugar=new Sugar(coffee);//装饰
System.out.println(sugar.info()+"-->"+"现价格为:"+sugar.cost()+"元");
Drink chocolate=new Chocolate(coffee);//装饰
System.out.println(chocolate.info()+"-->"+"现价格为:"+chocolate.cost()+"元");
milk=new Milk(sugar);//装饰
System.out.println(milk.info()+"-->"+"现价格为:"+milk.cost()+"元");
}
}
//抽象组件
interface Drink{
//费用
double cost();
//信息
String info();
}
//具体组件
class Coffee implements Drink{
private String name="原味咖啡";
@Override
public double cost() {
return 25;
}
@Override
public String info() {
return name;
}
}
//抽象装饰类
abstract class Decorate implements Drink{
private Drink drink;
public Decorate(Drink drink) {
this.drink=drink;
}
@Override
public double cost() {
return this.drink.cost();
}
@Override
public String info() {
return this.drink.info();
}
}
//具体装饰类
class Milk extends Decorate{
public Milk(Drink drink) {
super(drink);
}
@Override
public double cost() {
return super.cost()*4;
}
@Override
public String info() {
return super.info()+"加入了牛奶";
}
}
//具体装饰类
class Sugar extends Decorate{
public Sugar(Drink drink) {
super(drink);
}
@Override
public double cost() {
return super.cost()*2;
}
@Override
public String info() {
return super.info()+"加入了蔗糖";
}
}
//具体装饰类
class Chocolate extends Decorate{
public Chocolate(Drink drink) {
super(drink);
}
@Override
public double cost() {
return super.cost()*6;
}
@Override
public String info() {
return super.info()+"加入了巧克力";
}
}
输出结果为:
字节缓冲流
提升性能
package com.yuxuange.test;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
/**
* 文件拷贝:文件输入,输出字节流
* 文件拷贝:字节缓冲输入,输出流
*
* @author 羽轩阁
*
*/
public class Yuxuange {
/**
* 文件输入,输出流实现文件拷贝
*
* @param srcPath
* @param destPath
*/
public static void copy(String srcPath, String destPath) {
// 1.创建源
File srcIn = new File(srcPath);
File srcOut = new File(destPath);
// 2.选择流
InputStream inputStream = null;
OutputStream outputStream = null;
try {
inputStream = new FileInputStream(srcIn);
outputStream = new FileOutputStream(srcOut);
// 3.操作(分段读取)
// 缓冲容器
byte[] flush = new byte[1024];
// 接收长度
int len = -1;
while ((len = inputStream.read(flush)) != -1) {
outputStream.write(flush, 0, len);
}
outputStream.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
// 4.释放资源,先打开的后关闭,后代开的先关闭
try {
if (null != outputStream) {
outputStream.close();
}
} catch (IOException e) {
e.printStackTrace();
}
try {
if (null != inputStream) {
inputStream.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static void copyStrong(String srcPath, String destPath) {
// 1.创建源
File srcIn = new File(srcPath);
File srcOut = new File(destPath);
// 2.选择流
InputStream inputStream = null;
OutputStream outputStream = null;
try {
inputStream = new BufferedInputStream(new FileInputStream(srcIn));
outputStream = new BufferedOutputStream(new FileOutputStream(srcOut));
// 3.操作(分段读取)
// 缓冲容器
byte[] flush = new byte[1024];
// 接收长度
int len = -1;
while ((len = inputStream.read(flush)) != -1) {
outputStream.write(flush, 0, len);
}
outputStream.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
// 4.释放资源,先打开的后关闭,后代开的先关闭
try {
if (null != outputStream) {
outputStream.close();
}
} catch (IOException e) {
e.printStackTrace();
}
try {
if (null != inputStream) {
inputStream.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
字符缓冲流
提升性能
使用字符缓冲流实现纯文本文件的拷贝:
package com.yuxuange.utils;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
/**
* 文件(纯文本)的拷贝
*
* @author 羽轩阁
*
*/
public class TxtCopyUtils {
/**
* 文件(纯文本)的拷贝 说明:使用jdk1.7的try...with...resource关闭资源
*
* @param srcPath
* @param destPath
*/
public static void copyTxt(String srcPath, String destPath) {
// 1.创建源
File src = new File(srcPath);
File dest = new File(destPath);
// 2.选择流
try (BufferedReader bReader = new BufferedReader(new FileReader(src));
BufferedWriter bWriter = new BufferedWriter(new FileWriter(dest))) {
// 3.操作(逐行读取)
String line = null;
while ((line = bReader.readLine()) != null) {
bWriter.write(line);
bWriter.newLine();
}
bWriter.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
转换流
实现控制台输入内容并输出
package com.yuxuange.test;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
/**
* 转换流:InputStreamReader OutputStreamWriter 1.以字符流的形式操作字节流(纯文本) 2.指定字符集
*
* @author 羽轩阁
*
*/
public class Yuxuange {
public static void main(String[] args) {
// 操作System.in与System.out
try (BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(System.out));) {
//循环获取键盘的输入(exit退出),输出此内容
String message="";
while(!message.equals("exit")) {
message=reader.readLine();
writer.write(message);
writer.newLine();
//强制刷新
writer.flush();
}
} catch (IOException e) {
System.out.println("操作异常");
}
}
}
下载百度网站的资源和字符集的设置
package com.yuxuange.test;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
/**
* 转换流:网络资源和字符集设置
* @author 羽轩阁
*
*/
public class Yuxuange {
public static void main(String[] args) {
// 操作网络流,下载百度网站源码
try (BufferedReader reader = new BufferedReader(new InputStreamReader(new URL("http://www.baidu.com").openStream(),"UTF-8"));) {
//操作(读取)
String message="";
while((message=reader.readLine())!=null) {
System.out.print(message);
}
} catch (IOException e) {
System.out.println("操作异常");
}
}
}
数据流
package com.yuxuange.test;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
/**
* 数据流
* @author 羽轩阁
*
*/
public class Yuxuange {
public static void main(String[] args) throws IOException {
//写出
ByteArrayOutputStream byteArrayOutputStream=new ByteArrayOutputStream();
DataOutputStream dataOutputStream=new DataOutputStream(new BufferedOutputStream(byteArrayOutputStream));
//操作数据类型+数据
dataOutputStream.writeUTF("羽轩阁");
dataOutputStream.writeInt(688);
dataOutputStream.writeBoolean(true);
dataOutputStream.writeChar('A');
dataOutputStream.flush();
byte[] datas=byteArrayOutputStream.toByteArray();
//读取
DataInputStream dataInputStream=new DataInputStream(new BufferedInputStream(new ByteArrayInputStream(datas)) );
//顺序应与写出的顺序保持一致
String name=dataInputStream.readUTF();
int price=dataInputStream.readInt();
boolean flag=dataInputStream.readBoolean();
char temp=dataInputStream.readChar();
System.out.println(name);
System.out.println(price);
System.out.println(flag);
System.out.println(temp);
}
}
对象流
ObjectInputStream/ObjectOutputStream是以“对象”为数据源,但是必须将传输的对象进行序列化与反序列化操作。
把Java对象转换为字节序列的过程称为对象的序列化。把字节序列恢复为Java对象的过程称为对象的反序列化。
序列化也称为持久化。
package com.yuxuange.test;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.Date;
/**
* 对象流 1.写出后读取 2.读取的顺序与写出保持一致 3.不是所有的对象可以序列化,必须实现Serializable
*
* @author 羽轩阁
*
*/
public class Yuxuange {
public static void main(String[] args) throws IOException, ClassNotFoundException {
// 写出 --> 序列化
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ObjectOutputStream outputStream = new ObjectOutputStream(new BufferedOutputStream(byteArrayOutputStream));
outputStream.writeObject(new Date());
outputStream.writeObject(new Person("张三", 18, "男"));
// 操作数据类型+数据
outputStream.flush();
byte[] datas = byteArrayOutputStream.toByteArray();
// 读取 --> 反序列化
ObjectInputStream inputStream = new ObjectInputStream(
new BufferedInputStream(new ByteArrayInputStream(datas)));
// 对象的数据还原,顺序应与写出的顺序保持一致
Object date=inputStream.readObject();
Object person=inputStream.readObject();
if(date instanceof Date) {
Date dateObj=(Date)date;
System.out.println(dateObj);
}
if(person instanceof Person) {
Person personObj=(Person)person;
System.out.println(personObj.getName()+"---"+personObj.getAge()+"---"+personObj.getSex());
}
}
}
class Person implements Serializable{
private static final long serialVersionUID = 1L;
private String name;
//transient关键字,表示该数据不需要序列化
private transient int age;
private String sex;
public Person() {
}
public Person(String name, int age, String sex) {
super();
this.name = name;
this.age = age;
this.sex = sex;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
}
输出结果为:
打印流
package com.yuxuange.test;
import java.io.BufferedOutputStream;
import java.io.FileDescriptor;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintStream;
/**
* 打印流
*
* @author 羽轩阁
*
*/
public class Yuxuange {
public static void main(String[] args) throws FileNotFoundException {
PrintStream printStream = System.out;
printStream.println("打印流");
printStream=new PrintStream(new BufferedOutputStream(new FileOutputStream("printOutputStream.txt")),true);
printStream.println("打印流");
printStream.close();
//重定向输出端
System.setOut(printStream);
System.out.println("这句话将被输出到文件中...");
//重定向回控制台
System.setOut(new PrintStream(new BufferedOutputStream(new FileOutputStream(FileDescriptor.out)),true));
System.out.println("这句话将被重新输出到控制台");
}
}
CommonsIO
1.下载CommonsIO包:
http://commons.apache.org/proper/commons-io/
本人使用的JDK是1.8,所以下载的是
2.下载完成后,解压,将红箭头指向的文件拷入项目中
3.在名称为commons-io-2.6.jar文件上点击鼠标右键后出现菜单来点击Build Path 后,再点击Add to Build Path
4.上步操作完成后,会在项目出现如下图的现象,可以成功使用jar包了
5.使用Commons IO
· 文件大小
package com.yuxuange.commons;
import java.io.File;
import org.apache.commons.io.FileUtils;
/**
* 文件大小
* @author 羽轩阁
*
*/
public class CommonsIO01 {
public static void main(String[] args) {
//文件的大小
long length=FileUtils.sizeOf(new File("src/com/yuxuange/commons/CommonsIO01.java"));
System.out.println(length);
//目录的大小
length=FileUtils.sizeOf(new File("D:/workspace/Players"));
System.out.println(length);
}
}
在项目中创建一个名字为empty.txt文件,并且使该文件为空文件。进行如下操作:
· 文件操作
package com.yuxuange.commons;
import java.io.File;
import java.util.Collection;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.filefilter.DirectoryFileFilter;
import org.apache.commons.io.filefilter.EmptyFileFilter;
import org.apache.commons.io.filefilter.FileFilterUtils;
import org.apache.commons.io.filefilter.SuffixFileFilter;
/**
* 文件操作
* @author 羽轩阁
*
*/
public class CommonsIO02 {
public static void main(String[] args) {
//查看操作指定路径下文件内容不为空的文件
//EmptyFileFilter.NOT_EMPTY文件过滤器过滤掉文件内容为空的文件
Collection<File> files01=FileUtils.listFilesAndDirs(new File("D:/workspace/Players"), EmptyFileFilter.NOT_EMPTY, null);
for (File file : files01) {
System.out.println(file.getAbsolutePath());
}
System.out.println("----------华丽的分隔符----------");
//查看操作指定路径下的子孙级文件,且文件内容不能为空
Collection<File> files02=FileUtils.listFiles(new File("D:/workspace/Players"), EmptyFileFilter.NOT_EMPTY, DirectoryFileFilter.INSTANCE);
for (File file : files02) {
System.out.println(file.getAbsolutePath());
}
System.out.println("----------华丽的分隔符----------");
//查看操作指定路径下的子孙级文件,且文件后缀名为.java和.class的文件
Collection<File> files03=FileUtils.listFiles(new File("D:/workspace/Players"),FileFilterUtils.or(new SuffixFileFilter("java"),new SuffixFileFilter("class")), DirectoryFileFilter.INSTANCE);
for (File file : files03) {
System.out.println(file.getAbsolutePath());
}
System.out.println("----------华丽的分隔符----------");
//查看操作指定路径下的子孙及文件,且文件后缀名为.java的内容不为空的文件
Collection<File> files04=FileUtils.listFiles(new File("D:/workspace/Players"),FileFilterUtils.and(new SuffixFileFilter("java"),EmptyFileFilter.NOT_EMPTY), DirectoryFileFilter.INSTANCE);
for (File file : files04) {
System.out.println(file.getAbsolutePath());
}
}
}
在项目中创建一个名字为article.txt的文件,并在文件中输入内容
· 文件读取
package com.yuxuange.commons;
import java.io.File;
import java.io.IOException;
import java.util.List;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.LineIterator;
/**
* 文件读取
* @author 羽轩阁
*
*/
public class CommonsIO03 {
public static void main(String[] args) throws IOException {
//读取文件
String message=FileUtils.readFileToString(new File("article.txt"),"UTF-8");
System.out.println(message);
System.out.println("----------华丽的分隔符----------");
//将文件读入字节数组中
byte[] datas=FileUtils.readFileToByteArray(new File("article.txt"));
System.out.println(datas.length);
System.out.println("----------华丽的分隔符----------");
//逐行读取
List<String> msg=FileUtils.readLines(new File("article.txt"),"UTF-8");
for (String string : msg) {
System.out.println(string);
}
System.out.println("----------华丽的分隔符----------");
//迭代器读取
LineIterator it= FileUtils.lineIterator(new File("article.txt"),"UTF-8");
while(it.hasNext()) {
System.out.println(it.nextLine());
}
}
}
· 文件写出
package com.yuxuange.commons;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.io.FileUtils;
/**
* 文件写出
*
* @author 羽轩阁
*
*/
public class CommonsIO04 {
public static void main(String[] args) throws IOException {
// 写出文件
FileUtils.write(new File("NewWrite.txt"), "Hello,world!你好,世界\r\n", "UTF-8");
FileUtils.writeStringToFile(new File("NewWrite.txt"), "Hello,everyone!大家好\r\n", "UTF-8", true);
FileUtils.writeByteArrayToFile(new File("NewWrite.txt"),
"Hello,the perfect world!你好,完美世界\r\n".getBytes("UTF-8"), true);
// 写出列表
List<String> list = new ArrayList<>();
list.add("世界");
list.add("国家");
list.add("省份");
list.add("城市");
FileUtils.writeLines(new File("NewWrite.txt"), list, "---", true);
}
}
将一张图片放入项目中
· 文件拷贝
package com.yuxuange.commons;
import java.io.IOException;
/**
* 文件拷贝
* @author 羽轩阁
*
*/
public class CommonsIO05 {
public static void main(String[] args) throws IOException {
//文件复制
//FileUtils.copyFile(new File("IT.png"), new File("ITCopy.png"));
//复制文件到指定目录
//FileUtils.copyFileToDirectory(new File("IT.png"), new File("lib"));
//复制目录到目录:将lib文件夹里的内容包括文件夹,复制到lib2中
//FileUtils.copyDirectoryToDirectory(new File("lib"), new File("lib2"));
//复制目录:将lib文件夹中的文件复制到lib2中
//FileUtils.copyDirectory(new File("lib"), new File("lib2"));
//拷贝URL内容到文件
//FileUtils.copyURLToFile(new URL("http://www.baidu.com"), new File("NewWrite.txt"));
//复制网站内容
//String datas=IOUtils.toString(new URL("http://www.163.com"),"GBK");
//System.out.println(datas);
}
}
多线程
进程与线程
创建线程
· 继承Thread类
package com.yuxuange.thread;
/**
* 创建线程:方式1
* @author 羽轩阁
*
*/
public class FirstThread extends Thread{
/**
* 线程入口点
*/
@Override
public void run() {
//线程执行的代码
for(int i=0;i<50;i++) {
System.out.print("我在听歌...");
}
}
public static void main(String[] args) {
//创建对象
FirstThread firstThread=new FirstThread();
//启动线程,不保证立即运行,由CPU调用
firstThread.start();
for(int i=5;i<50;i++) {
System.out.print("我在跳舞...");
}
}
}
· 实现Runnable接口(推荐)
package com.yuxuange.thread;
/**
* 创建线程:方式2
* @author 羽轩阁
*
*/
public class SecondThread implements Runnable {
@Override
public void run() {
for (int i = 0; i < 50; i++) {
System.out.print("我在听歌...");
}
}
public static void main(String[] args) {
// 创建实现类对象
SecondThread secondThread = new SecondThread();
// 创建代理类对象
Thread thread=new Thread(secondThread);
// 启动线程
thread.start();
for (int i = 5; i < 50; i++) {
System.out.print("我在跳舞...");
}
}
}
package com.yuxuange.thread;
/**
* 模拟龟兔赛跑
* @author 羽轩阁
*
*/
public class Race implements Runnable{
private String winner;
@Override
public void run() {
for(int steps=1;steps<=100;steps++) {
//模拟兔子赛跑时经常休息,每25步休息一次
try {
if(Thread.currentThread().getName().equals("Rabbit") && steps%25==0) {
Thread.sleep(100);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"-->"+steps);
boolean flag=getWin(steps);
if(flag) {
break;
}
}
}
private boolean getWin(int steps) {
//有胜利者产生
if(winner!=null) {
return true;
}else {
//步数达到100步
if(steps==100) {
winner=Thread.currentThread().getName();
//打印胜利者的名字
System.out.println("winner is "+winner);
return true;
}
}
return false;
}
public static void main(String[] args) {
//一场比赛
Race race=new Race();
//两个线程:兔子与乌龟
new Thread(race,"Tortoise").start();
new Thread(race,"Rabbit").start();
}
}
· 实现Callable接口
线程状态
· 新生状态(New):用new关键字建立一个线程对象后,该线程对象就处于新生状态。处于新生状态的线程有自己的内存空间,通过调用start方法进入就绪状态。
· 就绪状态(Runnable):
处于就绪状态的线程已经具备了运行条件,但是还没有被分配到CPU,处于“线程就绪队列”,等待系统为其分配CPU。就绪状态并不是执行状态,当系统选定一个等待执行的Thread对象后,它就会进入执行状态。一旦获得CPU,线程就进入运行状态并自动调用自己的run方法。有4种原因会导致线程进入就绪状态:
-
新建线程:调用start()方法,进入就绪状态;
-
阻塞线程:阻塞解除,进入就绪状态;
-
运行线程:调用yield()方法,直接进入就绪状态;
-
运行线程:JVM将CPU资源从本线程切换到其他线程。
▪ 运行状态(Running)
在运行状态的线程执行自己run方法中的代码,直到调用其他方法而终止或等待某资源而阻塞或完成任务而死亡。如果在给定的时间片内没有执行结束,就会被系统给换下来回到就绪状态。也可能由于某些“导致阻塞的事件”而进入阻塞状态。
▪ 阻塞状态(Blocked)
阻塞指的是暂停一个线程的执行以等待某个条件发生(如某资源就绪)。有4种原因会导致阻塞:
-
执行sleep(int millsecond)方法,使当前线程休眠,进入阻塞状态。当指定的时间到了后,线程进入就绪状态。
-
执行wait()方法,使当前线程进入阻塞状态。当使用nofity()方法唤醒这个线程后,它进入就绪状态。
-
线程运行时,某个操作进入阻塞状态,比如执行IO流操作(read()/write()方法本身就是阻塞的方法)。只有当引起该操作阻塞的原因消失后,线程进入就绪状态。
-
join()线程联合: 当某个线程等待另一个线程执行结束后,才能继续执行时,使用join()方法。
▪ 死亡状态(Terminated)
死亡状态是线程生命周期中的最后一个阶段。线程死亡的原因有两个。一个是正常运行的线程完成了它run()方法内的全部工作; 另一个是线程被强制终止,如通过执行stop()或destroy()方法来终止一个线程(注:stop()/destroy()方法已经被JDK废弃,不推荐使用)。
当一个线程进入死亡状态以后,就不能再回到其它状态了。
· sleep():
1.使线程停止运行一段时间,将处于阻塞状态
2.如果调用了sleep方法之后,没有其他等待执行的线程,这个时候当前线程不会马上恢复执行
· join():
阻塞指定线程等到另一个线程完成以后再继续执行
·yield():
1.让当前正在执行线程暂停,不是阻塞线程,而是将线程转入就绪状态
2.调用了yield()方法之后,如果没有其他等待执行的线程,此时当前线程就会马上恢复执行
· setDaemon():
1.可以将指定的线程设置成后台线程,守护线程
2.创建用户线程的线程结束时,后台线程也随之消亡
3.只能在线程启动之前把它设为后台线程
· setPriority(int newPriority) getPriority()
1.线程的优先级代表的是概率
2.范围从1到10,默认为5
· stop():不推荐使用
package com.yuxuange.thread;
/**
* 终止线程
* 1.线程正常执行完毕-->次数
* 2.外部干涉-->加入标识
* 不推荐使用stop(),destroy()
*
* @author 羽轩阁
*
*/
public class ThreadStatus implements Runnable{
//1.加入标识 标记线程体是否可以运行
private boolean flag=true;
private String name;
public ThreadStatus(String name) {
super();
this.name = name;
}
@Override
public void run() {
int i=0;
//2.关联标识,true-->运行,false-->停止
while(flag) {
System.out.println(name+"-->"+i++);
}
}
//3.对外提供方法改变标识
public void changeFlag() {
this.flag=false;
}
public static void main(String[] args) {
ThreadStatus tStatus=new ThreadStatus("A Thread");
new Thread(tStatus).start();
for(int i=0;i<50;i++) {
if(i==45) {
tStatus.changeFlag();
System.out.println("终止...");
}
System.out.println("main() -->"+i);
}
}
}
sleep
· sleep(时间) 指定当前线程阻塞的毫秒数
· sleep存在异常InterruptedException
· sleep时间达到后线程进入就绪状态
· sleep可以模拟网络延时、倒计时等
· 每一个对象都有一个所,sleep不会释放锁
yield
· 礼让线程,让当前正在执行线程暂停
· 不是阻塞线程,而是将线程从运行状态转入就绪状态
· 让CPU调度器重新调度
package com.yuxuange.thread;
public class YieldDemo2 {
public static void main(String[] args) {
new Thread(() -> {
for (int i = 0; i < 100; i++) {
System.out.println("lambda....." + i);
}
}).start();
//100以内,每10的倍数时,main方法礼让线程
for (int i = 0; i < 100; i++) {
if (i % 10 == 0) {
Thread.yield();
}
System.out.println("main....." + i);
}
}
}
join
· 合并线程(插队线程),待此线程执行完成后,在执行其他线程,其他线程阻塞
package com.yuxuange.thread;
/**
* join:合并线程,插队线程
* @author 羽轩阁
*
*/
public class JoinDemo {
public static void main(String[] args) throws InterruptedException {
Thread thread=new Thread(() -> {
for (int i = 0; i < 100; i++) {
System.out.println("lambda....." + i);
}
});
thread.start();
for (int i = 0; i < 100; i++) {
if (i == 50) {
//插队,main方法被阻塞
thread.join();
}
System.out.println("main....." + i);
}
}
}
priority
· 线程优先级,提供一个线程调度器来监控程序中启动后进入就绪状态的所有线程。线程调度器按照线程的优先级决定应调度哪个线程来执行
· 优先级的设定建议在start()方法前调用
【注意】:优先级低只是意味着获得调度的概率低。并不是绝对先调用优先级高后调用优先级低的线程。
package com.yuxuange.thread;
/**
* 线程优先级 1-10
* 1.NORM_PRIORITY 5
* 2.MIN_PRIORITY 1
* 3.MAX_PRIORITY 10
* @author 羽轩阁
*
*/
public class PriorityDemo {
public static void main(String[] args) {
System.out.println(Thread.currentThread().getPriority());
MyPriority myPriority=new MyPriority();
Thread thread1=new Thread(myPriority);
Thread thread2=new Thread(myPriority);
Thread thread3=new Thread(myPriority);
Thread thread4=new Thread(myPriority);
Thread thread5=new Thread(myPriority);
//设置线程优先级,优先级高的【调用概率】大
thread1.setPriority(Thread.MAX_PRIORITY);
thread2.setPriority(Thread.MAX_PRIORITY);
thread3.setPriority(Thread.NORM_PRIORITY);
thread4.setPriority(Thread.MIN_PRIORITY);
thread5.setPriority(Thread.MIN_PRIORITY);
thread1.start();
thread2.start();
thread3.start();
thread4.start();
thread5.start();
}
}
class MyPriority implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"-->"+Thread.currentThread().getPriority());
}
}
并发
并发:同一个对象多个线程同时操作
线程同步
处理多线程问题时,多个线程访问同一个对象,并且某些线程还想修改这个对象。 这时候,我们就需要用到“线程同步”。 线程同步其实就是一种等待机制,多个需要同时访问此对象的线程进入这个对象的等待池形成队列,等待前面的线程使用完毕后,下一个线程再使用。
由于同一进程的多个线程共享同一块存储空间,在带来方便的同时,也带来了访问冲突的问题。为了保证数据在方法中被访问时的正确性,在访问时加入锁机制(synchronized),当一个线程获得对象的排它锁,独占资源,其他线程必须等待,使用后释放锁即可。但存在以下问题:1.一个线程持有锁会导致其他所有需要此锁的线程挂起。2.在多线程竞争下,加锁、释放锁会导致比较多的上下文切换和调度延时,引起性能问题。3.如果一个优先级高的线程等待一个优先级低的线程释放锁会导致优先级倒置,引起性能问题
synchronized
由于我们可以通过 private 关键字来保证数据对象只能被方法访问,所以我们只需针对方法提出一套机制,这套机制就是synchronized关键字,它包括两种用法:synchronized 方法和 synchronized 块。
· 同步方法:
public synchronized void method(int args){}
synchronized 方法控制对“成员变量|类变量”对象的访问:每个对象对应一把锁,每个 synchronized 方法都必须获得调用该方法的对象的锁方能执行,否则所属线程阻塞,方法一旦执行,就独占该锁,直到从该方法返回时才将锁释放,此后被阻塞的线程方能获得该锁,重新进入可执行状态。
【缺陷】:若将一个大的方法声明为synchronized 将会大大影响效率。
网络编程
计算机网络
计算机网络是指将地理位置不同的具有独立功能的多台计算机及其外部设备,通过通信线路连接起来,在网络操作系统,网络管理软件及网络通信协议的管理和协调下,实现资源共享和信息传递的计算机系统。
网络通信协议
通过计算机网络可以实现不同计算机之间的连接与通信,但是计算机网络中实现通信必须有一些约定即通信协议,对速率、传输代码、代码结构、传输控制步骤、出错控制等制定标准。就像两个人想要顺利沟通就必须使用同一种语言一样,如果一个人只懂英语而另外一个人只懂中文,这样就会造成没有共同语言而无法沟通。
国际标准化组织(ISO,即International Organization for Standardization)定义了网络通信协议的基本框架,被称为OSI(Open System Interconnect,即开放系统互联)模型。要制定通讯规则,内容会很多,比如要考虑A电脑如何找到B电脑,A电脑在发送信息给B电脑时是否需要B电脑进行反馈,A电脑传送给B电脑的数据格式又是怎样的?内容太多太杂,所以OSI模型将这些通讯标准进行层次划分,每一层次解决一个类别的问题,这样就使得标准的制定没那么复杂。
OSI模型制定的七层标准模型,分别是:应用层,表示层,会话层,传输层,网络层,数据链路层,物理层。
虽然国际标准化组织制定了这样一个网络通信协议的模型,但是实际上互联网通讯使用最多的网络通信协议是TCP/IP网络通信协议。
TCP/IP 是一个协议族,也是按照层次划分,共四层:应用层,传输层,互连网络层,网络接口层(物理+数据链路层)。
那么TCP/IP协议和OSI模型有什么区别呢?OSI网络通信协议模型,是一个参考模型,而TCP/IP协议是事实上的标准。TCP/IP协议参考了OSI 模型,但是并没有严格按照OSI规定的七层标准去划分,而只划分了四层,这样会更简单点,当划分太多层次时,你很难区分某个协议是属于哪个层次的。TCP/IP协议和OSI模型也并不冲突,TCP/IP协议中的应用层协议,就对应于OSI中的应用层,表示层,会话层。就像以前有工业部和信息产业部,现在实行大部制后只有工业和信息化部一个部门,但是这个部门还是要做以前两个部门一样多的事情,本质上没有多大的差别。TCP/IP中有两个重要的协议,传输层的TCP协议和互连网络层的IP协议,因此就拿这两个协议做代表,来命名整个协议族了,再说TCP/IP协议时,是指整个协议族。
网络协议的分层
由于网络结点之间联系很复杂,在制定协议时,把复杂成份分解成一些简单的成份,再将它们复合起来。最常用的复合方式是层次方式,即同层间可以通信、上一层可以调用下一层,而与再下一层不发生关系。
把用户应用程序作为最高层,把物理通信线路作为最低层,将其间的协议处理分为若干层,规定每层处理的任务,也规定每层的接口标准。
数据的封装和解封
由于用户传输的数据一般都比较大,有的可以达到MB字节,一次性发送出去十分困难,于是就需要把数据分成许多片段,再按照一定的次序发送出去。这个过程就需要对数据进行封装。
数据封装(Data Encapsulation)是指将协议数据单元(PDU)封装在一组协议头和协议尾中的过程。在OSI七层参考模型中,每层主要负责与其它机器上的对等层进行通信。该过程是在协议数据单元(PDU)中实现的,其中每层的PDU一般由本层的协议头、协议尾和数据封装构成。
1.数据发送处理过程
(1)应用层将数据交给传输层,传输层添加上TCP的控制信息(称为TCP头部),这个数据单元称为段(Segment),加入控制信息的过程称为封装。然后,将段交给网络层。
(2)网络层接收到段,再添加上IP头部,这个数据单元称为包(Packet)。然后,将包交给数据链路层。
(3) 数据链路层接收到包,再添加上MAC头部和尾部,这个数据单元称为帧(Frame)。然后,将帧交给物理层。
(4)物理层将接收到的数据转化为比特流,然后在网线中传送。
2.数据接收处理过程
(1)物理层接收到比特流,经过处理后将数据交给数据链路层。
(2)数据链路层将接收到的数据转化为数据帧,再除去MAC头部和尾部,这个除去控制信息的过程称为解封,然后将包交给网络层。
(3)网络层接收到包,再除去IP头部,然后将段交给传输层。
(4)传输层接收到段,再除去TCP头部,然后将数据交给应用层。
从以上传输过程中,可以总结出以下规则:
(1)发送方数据处理的方式是从高层到底层,逐层进行数据封装。
(2)接收方数据处理的方式是从底层到高层,逐层进行数据解封装。
接收方的每一层只把对该层有意义的数据拿走,或者说每一层只能处理发送方同等层的数据,然后把其余的部分传递给上一层,这就是对等层通信的概念。
IP地址
用来标识网络中的一个通信实体的地址。通信实体可以是计算机、路由器等。 比如互联网的每个服务器都要有自己的IP地址,而每个局域网的计算机要通信也要配置IP地址。路由器是连接两个或多个网络的网络设备。
目前主流使用的IP地址是IPV4,但是随着网络规模的不断扩大,IPV4面临着枯竭的危险,所以推出了IPV6。
IPV4:32位地址,并以8位为一个单位,分成四部分,以点分十进制表示,如192.168.0.1。因为8位二进制的计数范围是00000000—11111111,对应十进制的0-255,所以-4.278.4.1是错误的IPV4地址。
IPV6:128位(16个字节)写成8个16位的无符号整数,每个整数用四个十六进制位表示,每个数之间用冒号(:)分开,如:3ffe:3201:1401:1280:c8ff:fe4d:db39:1984
【注意】
1.127.0.0.1 本机地址
2.192.168.0.0–192.168.255.255为私有地址,属于非注册地址,专门为组织机构内部使用。
package com.yuxuange.net;
import java.net.InetAddress;
import java.net.UnknownHostException;
/**
* IP:定位一个节点:计算机,通信设备,路由
* InetAddress:静态方法
* 1.getLocalHost:本机
* 2.getByName:根据域名DNS | IP地址 --> IP
*
* 两个成员方法
* 1.getHostAddress:返回地址
* 2.getHostName:返回计算机名
* @author 羽轩阁
*
*/
public class Netstudy {
public static void main(String[] args) throws UnknownHostException {
InetAddress inetAddress1=InetAddress.getByName("www.baidu.com");
System.out.println(inetAddress1.getHostAddress());
InetAddress inetAddress2=InetAddress.getLocalHost();
System.out.println(inetAddress2.getHostAddress());
System.out.println(inetAddress2.getHostName());
}
}
端口
IP地址用来标识一台计算机,但是一台计算机上可能提供多种网络应用程序,如何来区分这些不同的程序呢?这就要用到端口。
端口是虚拟的概念,并不是说在主机上真的有若干个端口。通过端口,可以在一个主机上运行多个网络应用程序。 端口的表示是一个16位的二进制整数,对应十进制的0-65535。
TCP传输协议
TCP是一种面向连接(连接导向)的、可靠的、基于字节流的运输层通信协议。
特点:
1.面向连接
2.点到点的通信
3.高可靠性
4.占用系统资源多且效率较低
UDP传输协议
UDP是一种无连接的传输层协议,提供面向事务的简单不可靠信息传送服务。
特点:
1.非面向连接,传输不可靠,可能丢失
2.发送不管对方是否准备好,接收方收到也不确认
3.可以广播发送
4.非常简单的协议,开销小
Socket
网络应用程序位于应用层,TCP和UDP属于传输层协议,在应用层如何使用传输层的服务呢?在应用层和传输层之间,则是使用套接Socket来进行分离。
套接字就像是传输层为应用层开的一个小口,应用程序通过这个小口向远程发送数据,或者接收远程发来的数据;而这个小口以内,也就是数据进入这个口之后,或者数据从这个口出来之前,是不知道也不需要知道的,也不会关心它如何传输,这属于网络其它层次工作。
Socket实际是传输层供给应用层的编程接口。Socket就是应用层与传输层之间的桥梁。使用Socket编程可以开发客户机和服务器应用程序,可以在本地网络上进行通信,也可通过Internet在全球范围内通信。
package com.yuxuange.net;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
/**
* 发送端
* 1.使用DatagramSocket 指定端口,创建发送端
* 2.准备数据一定装成字节数组
* 3.封装成DatagramPacket包裹,需要制定目的地
* 4.发送包裹send(DatagramPacket p)
* 5.释放资源
* @author 羽轩阁
*
*/
public class UdpClient {
public static void main(String[] args) throws Exception {
System.out.println("发送方启动中...");
//1.使用DatagramSocket 指定端口,创建发送端
DatagramSocket client =new DatagramSocket(8888);
//2.准备数据一定装成字节数组
String data="Hello,world";
byte[] datas=data.getBytes();
//3.封装成DatagramPacket包裹,需要制定目的地
DatagramPacket datagramPacket=new DatagramPacket(datas, 0, datas.length,new InetSocketAddress("localhost", 9999));
//4.发送包裹send(DatagramPacket p)
client.send(datagramPacket);
//5.释放资源
client.close();
}
}
package com.yuxuange.net;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
/**
* 接收端
* Address already in use : Cannot bind 同一个协议下端口不允许冲突
* 1.使用DatagramSocket 指定端口,创建接收端
* 2.准备容器 封装成DatagramPacket包裹
* 3.阻塞式接受包裹receive(DatagramPacket p)
* 4.分析数据 getData()及getLength() 字节数组
* 5.释放资源
* @author 羽轩阁
*
*/
public class UdpServer {
public static void main(String[] args) throws Exception {
System.out.println("接收方启动中...");
//1.使用DatagramSocket 指定端口,创建接收端
DatagramSocket datagramSocket=new DatagramSocket(9999);
//2.准备容器 封装成DatagramPacket包裹 字节数组
byte[] contain=new byte[1024*60];
DatagramPacket packet=new DatagramPacket(contain, 0 , contain.length);
//3.阻塞式接受包裹receive(DatagramPacket p)
datagramSocket.receive(packet);
//4.分析数据 getData()及getLength() 字节数组
byte[] datas=packet.getData();
int len=packet.getLength();
System.out.println(new String(datas,0,len));
//5.释放资源
datagramSocket.close();
}
}
发送端和接收端的封装
package com.yuxuange.net;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.SocketException;
/**
* 发送端
*
* @author 羽轩阁
*
*/
public class TalkSend implements Runnable {
private DatagramSocket client;
private BufferedReader reader;
private String toIP;
private int toPort;
public TalkSend(int port, String toIP, int toPort) {
this.toIP = toIP;
this.toPort = toPort;
try {
client = new DatagramSocket(port);
reader = new BufferedReader(new InputStreamReader(System.in));
} catch (SocketException e) {
e.printStackTrace();
}
}
@Override
public void run() {
while (true) {
String data;
try {
data = reader.readLine();
byte[] datas = data.getBytes();
DatagramPacket datagramPacket = new DatagramPacket(datas, 0, datas.length,
new InetSocketAddress(toIP, toPort));
client.send(datagramPacket);
if (data.equals("bye")) {
break;
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
client.close();
}
}
package com.yuxuange.net;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
/**
* 接受端
* @author 羽轩阁
*
*/
public class TalkReceive implements Runnable{
private DatagramSocket datagramSocket;
private String from;
public TalkReceive(int port,String from) {
this.from=from;
try {
datagramSocket=new DatagramSocket(port);
} catch (SocketException e) {
e.printStackTrace();
}
}
@Override
public void run() {
while (true) {
byte[] contain = new byte[1024 * 60];
DatagramPacket packet = new DatagramPacket(contain, 0, contain.length);
try {
datagramSocket.receive(packet);
byte[] datas = packet.getData();
int len = packet.getLength();
String data=new String(datas, 0, len);
System.out.println(from+"说:"+data);
if(data.equals("bye")) {
break;
}
} catch (IOException e) {
e.printStackTrace();
}
}
datagramSocket.close();
}
}
TCP
package com.yuxuange.net;
import java.io.DataInputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
/**
* 创建服务器
* @author 羽轩阁
*
*/
public class Server {
public static void main(String[] args) throws IOException {
System.out.println("---Server---");
//1.指定端口 使用ServerSocket创建服务器
ServerSocket serverSocket=new ServerSocket(8888);
//2.阻塞式等待连接accept
Socket socket=serverSocket.accept();
System.out.println("A client has been connected...");
//3.操作:输入输出流操作
DataInputStream dataInputStream=new DataInputStream(socket.getInputStream());
String data=dataInputStream.readUTF();
System.out.println(data);
//4.释放资源
dataInputStream.close();
serverSocket.close();
}
}
package com.yuxuange.net;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;
/**
* 创建客户端
* @author 羽轩阁
*
*/
public class Client {
public static void main(String[] args) throws UnknownHostException, IOException {
System.out.println("---Client---");
//1.建立连接:使用Socket创建客户端+服务的地址和端口
Socket socket=new Socket("localhost",8888);
//2.操作:输入输出流的操作
DataOutputStream dataOutputStream=new DataOutputStream(socket.getOutputStream());
String data = "Hello,world";
dataOutputStream.writeUTF(data);
dataOutputStream.flush();
//3.释放资源
dataOutputStream.close();
socket.close();
}
}
反射(reflection)
反射机制
– 指的是可以于运行时加载、探知、使用编译期间完全未知的类。
– 程序在运行状态中,可以动态加载一个只有名称的类,对于任意一个已加载的类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;
Class clazz=Class.forName(“yuxuange.reflection.User”);
– 加载完类之后,在堆内存中,就产生了一个Class类型的对象(一个类只有一个Class对象),这个对象就包含了完整的类的结构信息。我们可以通过这个对象看到类的结构。这个对象就像一面镜子,透过这个镜子看到类的结构,所以,我们形象的称之为:反射。
package yuxuange.reflection;
@SuppressWarnings("all")
public class Demo01{
public static void main(String[] args) {
String path = "yuxuange.reflection.User";
try {
//对象是表示灬封装一些数据。一个类被加载后,JVM会创建一个对应该类的Class对象,类的整个结构信息会放到对应的Class对象中。
//这个Class对象就像一面镜子一样,通过这面镜子可以看到对应类的全部信息
Class clazz1 = Class.forName(path);
System.out.println(clazz1.hashCode());
//一个类只对应一个反射对象
Class clazz2 = Class.forName(path);
System.out.println(clazz2.hashCode());
//获得class对象的其他方法
Class strClazz1=String.class;
Class strClazz2=path.getClass();
System.out.println(strClazz1==strClazz2);
} catch (Exception e) {
e.printStackTrace();
}
}
}
package yuxuange.reflection;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
/**
* 应用反射的API,获取类的信息(类的名字,属性,方法,构造器等)
*/
@SuppressWarnings("all")
public class Demo02 {
public static void main(String[] args) {
String path = "yuxuange.reflection.User";
try {
Class clazz = Class.forName(path);
//获取类的名字
System.out.println("类名:"+clazz.getName());
System.out.println("类名:"+clazz.getSimpleName());
//获取属性的信息
// Field[] fields=clazz.getFields();//只能获取到public修饰的属性
Field[] fields=clazz.getDeclaredFields();//获取所有的属性
for (Field f: fields) {
System.out.println("属性名:"+f.getName());
}
//获取方法的信息
Method[] methods=clazz.getMethods();
for (Method method: methods) {
System.out.println("方法名:"+method.getName());
}
Method method1=clazz.getDeclaredMethod("getAge",null);
Method method2=clazz.getDeclaredMethod("setAge", int.class);
//获取构造器信息
// Constructor[] constructor=clazz.getConstructors();//只能获取到public修饰的构造器
Constructor[] constructors=clazz.getDeclaredConstructors();
for (Constructor constructor:constructors) {
System.out.println("构造器名:"+constructor.getName());
}
Constructor constructor=clazz.getDeclaredConstructor(int.class,String.class,int.class);
System.out.println("构造器名:"+constructor.getName());
} catch (Exception e) {
e.printStackTrace();
}
}
}
package yuxuange.reflection;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
@SuppressWarnings("all")
public class Demo03 {
public static void main(String[] args) {
String path = "yuxuange.reflection.User";
try {
Class<User> clazz =(Class<User>) Class.forName(path);
//通过反射API调用构造方法,构造对象
User user1=clazz.newInstance();//调用了User对象的无参构造方法,创建javaBean时需创建无参构造器
System.out.println(user1);
//调用有参构造器
Constructor<User> constructor=clazz.getDeclaredConstructor(int.class,String.class,int.class);
User u2=constructor.newInstance(1000,"张三",18);
System.out.println(u2.getName());
//通过反射API调用普通方法
User u3=clazz.newInstance();
Method method=clazz.getDeclaredMethod("setName", String.class);
method.invoke(u3,"李四");
System.out.println(u3.getName());
//通过反射API操作属性
User user4=clazz.newInstance();
Field f=clazz.getDeclaredField("name");
f.setAccessible(true);//这个属性取消安全检查,可以直接访问
f.set(user4,"王五");
System.out.println(f.get(user4));
} catch (Exception e) {
e.printStackTrace();
}
}
}
反射机制性能问题
· setAccessible
– 启用和禁用访问安全检查的开关,值为true则指示反射的对象再使用时应该取消Java语言访问检查。值为false则只是反射的对象应该实施Java语言访问检查。并不是为true就能访问为false就不能访问。
– 禁止安全检查,可以提高反射的运行速度
反射操作泛型
· Java采用泛型擦除的机制来引入泛型。Java中的泛型仅仅是给编译器javac使用的,确保数据的安全性和免去强制类型转换的麻烦。但是,一旦编译完成,所有的和泛型有关的类型全部擦除。
· 为了通过反射操作这些类型以迎合实际开发的需要,Java就新增了ParameterizedType,GenericArrayType,TypeVariable,WildcardType几种类型来代表不能被归一到Class类中的类型但是又和原始类型齐名的类型。
· ParameterizedType:表示一种参数化的类型。
· GenericArrayType:表示一种元素类型是参数化类型或者类型变量的数组类型。
· TypeVariable:是各种类型变量的公共父接口。
· WildcardType:代表一种通配符类型表达式。
反射操作注解
· 可以通过反射API:getAnnotations,getAnnotation获得相关的注解信息
Java字节码操作
Javassist
官网位置:http://www.javassist.org/
package yuxuange.Javassist;
import javassist.*;
/**
* 使用Javassist生成类
*/
public class Demo01 {
public static void main(String[] args) throws Exception {
ClassPool pool=ClassPool.getDefault();
CtClass clazz=pool.makeClass("yuxuange.Javassist.model.Student");
//创建属性
CtField f1=CtField.make("private int no;",clazz);
CtField f2=CtField.make("private String name;",clazz);
clazz.addField(f1);
clazz.addField(f2);
//创建set,get方法
CtMethod ms1=CtMethod.make("public void setNo(int no) {this.no = no; }",clazz);
CtMethod mg1=CtMethod.make("public int getNo() {return no;}",clazz);
CtMethod ms2=CtMethod.make("public void setName(String name){this.name=name;}",clazz);
CtMethod mg2=CtMethod.make("public String getName(){return name;}",clazz);
clazz.addMethod(ms1);
clazz.addMethod(mg1);
clazz.addMethod(ms2);
clazz.addMethod(mg2);
//创建无参构造器
CtConstructor constructor1=new CtConstructor(new CtClass[]{},clazz);
clazz.addConstructor(constructor1);
//创建有参构造器
CtConstructor constructor2= new CtConstructor(new CtClass[]{CtClass.intType,pool.get("java.lang.String")},clazz);
constructor2.setBody("{this.no=no;this.name=name;}");
clazz.addConstructor(constructor2);
//将生成的文件导出到指定位置
clazz.writeFile("C:\\Users\\L\\Desktop");
System.out.println("generate code success!");
}
}
Javassist常用API
package yuxuange.Javassist;
import javassist.*;
import java.lang.reflect.Method;
import java.util.Arrays;
/**
* Javassist的API部分常用方法
*/
public class Demo02 {
/**
* 常用的处理类的方法
*
* @throws Exception
*/
public static void test01() throws Exception {
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.get("yuxuange.Javassist.Student");
//获取字节数组信息
byte[] bytes = cc.toBytecode();
System.out.println(Arrays.toString(bytes));
//获取类名
System.out.println(cc.getName());
//获取简要类名
System.out.println(cc.getSimpleName());
//获取父类名
System.out.println(cc.getSuperclass());
//获取接口
System.out.println(cc.getInterfaces());
}
/**
* 常用的处理方法的方法
*/
public static void test02() throws Exception {
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.get("yuxuange.Javassist.Student");
//声明一个加法
CtMethod m1 = CtMethod.make("public int add(int a,int b){return $1+$2;System.out.println(\"加法计算成功\");}", cc);
cc.addMethod(m1);
//声明一个乘法
CtMethod m2 = new CtMethod(CtClass.intType, "multiplication", new CtClass[]{CtClass.intType, CtClass.intType}, cc);
//设置方法的访问权限
m2.setModifiers(Modifier.PUBLIC);
m2.setBody("{return $1*$2;System.out.println(\"乘法计算成功\");}");
cc.addMethod(m2);
//通过反射获取新生成的方法
Class clazz = cc.toClass();
Object obj = clazz.newInstance();
Method method1 = clazz.getDeclaredMethod("add", int.class, int.class);
Method method2 = clazz.getDeclaredMethod("multiplication", int.class, int.class);
int a = 250;
int b = 300;
Object result1 = method1.invoke(obj, a, b);
Object result2 = method2.invoke(obj, a, b);
System.out.println(result1);
System.out.println(result2);
}
/**
* 在调用方法前,后执行某程序
*
* @throws Exception
*/
public static void test03() throws Exception {
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.get("yuxuange.Javassist.Student");
CtMethod method = cc.getDeclaredMethod("introduceMyself", new CtClass[]{pool.get("java.lang.String")});
method.insertBefore("System.out.println($1);System.out.println(\"start!!!\");");
method.insertAfter("System.out.println($1);System.out.println(\"end!!!\");");
//通过反射调用修改之后的方法
Class clazz = cc.toClass();
Object obj = clazz.newInstance();
Method methodTemp = clazz.getDeclaredMethod("introduceMyself", String.class);
Object result = methodTemp.invoke(obj, "我太帅气了!");
System.out.println(result);
}
public static void test04() throws Exception {
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.get("yuxuange.Javassist.Student");
//声明新的属性--性别
CtField field1=CtField.make("private int sex;",cc);
cc.addField(field1);
//声明新的属性--分数
CtField field2=new CtField(CtClass.intType,"score",cc);
field2.setModifiers(Modifier.PRIVATE);
cc.addField(field2);
//生成set,get方法
cc.addMethod(CtNewMethod.setter("setScore",field2));
cc.addMethod(CtNewMethod.getter("getScore",field2));
//通过反射调用修改之后的方法
Class clazz=cc.toClass();
Object obj=clazz.newInstance();
Method methodSet=clazz.getDeclaredMethod("setScore",int.class);
methodSet.invoke(obj,92);
Method methodGet=clazz.getDeclaredMethod("getScore",null);
Object result=methodGet.invoke(obj);
System.out.println(result);
}
public static void test05() throws Exception {
ClassPool pool=ClassPool.getDefault();
CtClass cc = pool.get("yuxuange.Javassist.Student");
CtConstructor[] ctConstructors=cc.getConstructors();
for (CtConstructor cs: ctConstructors) {
System.out.println(cs.getLongName());
}
}
public static void main(String[] args) throws Exception {
//test01();
//test02();
//test03();
//test04();
test05();
}
}