JavaSE知识概述集
丨逸仙 人气:2一、HelloWord(文档启动Java)
/* 使用命令行的方式执行的时候,cmd的默认编码格式是GBK 因此在输入中文的时候需要设置文件的编码格式位ANSI,不会出现乱码错误 注意: 0、先用javac来编译.java文件,然后执行 java 命令 1、java文件的名称必须跟public class的名称保持一致 2、一个java文件中可以包含多个class,凡是public class只能有1个 3、public static void main(String[] args)是所有java程序的入口,如果向 执行对应的java代码,则必须要添加如下方法,且格式是固定 4、main方法中参数列表可以支持多种写法:String[] args,String [] args,String args[] 5、main方法中参数的名称无所谓,但是一般写成args 6、java代码在编写的时候,每行结尾的时候需要使用;结束 7、java代码的代码块需要使用{}括起来,前后匹配 */ /*java中的注释分为三类*/ // 1、单行注释: /* 2、多行注释:*/ /** *3、文档注释: */
二、命名规范
/* 标识符命名规范 硬性规定: 1、标识符必须以字母,下划线或者美元符号开头 2、其他部分必须是字母,数字,下划线或者美元符号,但是不能出现特殊符号 3、标识符大小写敏感 4、不能是java的关键字或者保留字(留给系统使用的表示特殊含义的字符串) 常规建议: 1、驼峰标识 1、类名,接口名称在命名的时候要首字符大写 2、方法,变量命名的时候首字符要小写 3、多个单词拼接表示一个标识符的时候,每个单词的首字符都大写 2、见名知义 通过标识符的名称能知道代表的含义 千万不要写拼音 */
三、数据类型
/* 数据类型 Java是一种强类型的语言 强类型表示,变量在定义的时候必须显式的声明类型是什么 java 弱类型表示,变量会根据值自己去推断,不需要指定类型是什么 js,python,scala java数据类型 基本数据类型(4类8种) 整数类型:byte short int long(不同类型表示不同的长度) byte: 使用一个字节存储,因此范围是 -128-127 short: 使用两个字节存储,因此范围是 -32768-32767 int: 使用四个字节存储,因此范围是 正负21亿 long: 使用八个字节存储,因此范围是。。。。。。 注意: 1、在使用整型类型的时候,默认都是int类型, 2、如果需要使用long类型的话,必须要在数字的后面添加L,建议使用大写,小写容易跟1混淆。 浮点类型: float double 小数类型:使用小数点 使用科学计数法 float: 单精度,精度可以精确到小数点后7位 double: 双精度,精度是float的双倍 注意: 1、默认浮点类型是double类型 2、使用float的时候,数字后要添加f 3、浮点类型并不能表示一个精确的值,会损失一定的精度 字符类型: char 占用2个字节,使用的时候使用''表示 布尔类型: boolean 只有true和false两值,在存储的时候占1位 引用数据类型: 类 接口 数组 */ /* 基本数据类型之间的转换 自动转换(隐形转换): 强制转换 注意: 1、在进行算术运算操作的时候,必须要求数据类型一致,否则无法操作 2、在运算过程中,如果两个值得类型不一致,会自动将小的类型转换为大的类型 3、在运算过程中,可以手动强制转换,将大的类型转换为小的类型 实现方式,(datatype) 4、强制转换,会发生精度损失,结果可能不准确 */
四、常亮和变量
/* 常量和变量 常量:在程序运行过程中,值不会发生改变的量叫做常量 变量:在程序运行过程中,值会发生改变的量叫做变量 变量:变量名称,变量类型,作用域 1、先声明,后赋值 int a;声明 a =10;赋值 2、声明+赋值 常量: 使用final关键字修饰的变量称之为常量或者叫做最终常量,表示不可修改 注意: 在类内,方法外定义的变量叫成员变量,会存在默认值 在方法内,定义的变量必须要进行初始化操作,不会存在默认值 在一行中可以定义多个变量,但是不推荐,每个变量最好单独一行 给变量赋值过程中,变量的值成为常量 */
五、运算符
/* 运算符: 算术运算符: +,-,*,/,%,++,-- 赋值运算符 = java中=表示赋值运算符,==表示相等的操作 扩展赋值运算符:+=,-=,*=,/= 关系运算符: >,<,>=,<=,==,!= 用来比较两值的关系, 逻辑运算符: &&,||,! 逻辑运算符一般两边的值不是具体的值,而是表达式 位运算符: &,|,^,~ , >>,<<,>>> (了解!!!) 条件运算符 ?: */ //逻辑运算符 /* &&:表示短路与,两边表达式中只要有一个是false,整体结果就是false 两边表达式从左向右开始对比,如果左边的表达式是false,右边不需要进行判断 ||:表示短路或,两边表达式中只要有一个是true,整体结果就是true 两边表达式从左向右开始对比,如果左边的表达式是true,右边不需要进行判断 !:取反,如果是true,取反是false,如果是false,取反就是true &:与运算符,但是两都会参与运算 |:或运算符,两边都会参与运算 */
演示代码
public class OperatorDemo{ public static void main(String[] args){ int a = 1; int b = 2; //算数运算符 System.out.println(a+b); System.out.println(a-b); System.out.println(a*b); //取整除,或者取商 System.out.println(a/b); //取余数,或者取模 System.out.println(a%b); //单目运算符 //++,表示在变量原有的基础上+1,谁在前,先运算谁 System.out.println(a++); System.out.println(++a); //--,表示在变量原有的基础上-1,谁在前,先运算谁 System.out.println(a--); System.out.println(--a); //6 ???? System.out.println(++b+b++); //扩赋值运算符 int c = 1; //两写法意义一样,表示加2的基本操作 c = c + 2; c += 2; //类型转换问题,d是byte,d+1整体变成int类型,需要将int类型的值转换位byte,会有精度算是,因此需要强制转换 //建议在进行操作的时候使用扩赋值运算符 byte d = 10; /https://img.qb5200.com/download-x/d = d+1; d+=1; //关系运算符:返回的值是布尔类型,也就是说只有true和false两情况 System.out.println(1>2); System.out.println(1<2); System.out.println(1>=2); System.out.println(1<=2); System.out.println(1==2); System.out.println(1!=2); System.out.println("-----"); //逻辑运算符 /* &&:表示短路与,两边表达式中只要有一个是false,整体结果就是false 两边表达式从左向右开始对比,如果左边的表达式是false,右边不需要进行判断 ||:表示短路或,两边表达式中只要有一个是true,整体结果就是true 两边表达式从左向右开始对比,如果左边的表达式是true,右边不需要进行判断 !:取反,如果是true,取反是false,如果是false,取反就是true &:与运算符,但是两都会参与运算 |:或运算符,两边都会参与运算 */ System.out.println(3>5 & 3<4); System.out.println(3>5 | 3<4); System.out.println(!true); System.out.println(!false); //位运算符:只能操作数值,操作的时候会转成二进制进行运算 System.out.println(4 & 5); System.out.println(4 | 5); System.out.println(4 ^ 5); //移码,补码,原码,反码 ???? System.out.println(~4); //左移表示乘以2,右移表示除以2 System.out.println(2<<3); System.out.println(16>>2); //条件运算符或者三目运算符 //使用的时候需要跟一个表达式,表达式如果是true,则返回?后的结果, //如果是false,则返回:后的结果 System.out.println(3>2?3:2); System.out.println(false?false:true?false:true); /* 基本数据类型之间的转换 自动转换(隐形转换): 强制转换 注意: 1、在进行算术运算操作的时候,必须要求数据类型一致,否则无法操作 2、在运算过程中,如果两个值得类型不一致,会自动将小的类型转换为大的类型 3、在运算过程中,可以手动强制转换,将大的类型转换为小的类型 实现方式,(datatype) 4、强制转换,会发生精度损失,结果可能不准确 */ byte bb = 10; int aa = 200; byte cc; cc = (byte)(aa+bb); System.out.println(cc); } }
六、多分支语句
import java.util.Scanner; /* 分支结构: 单分支结构: 只做单一条件的判断,如果符合,做某些事情 双分支结构: 当做条件判断的时候,只有两种选择 多分支结构: 可以进行多个条件的判断,每个匹配项可以选择不同的执行结果 嵌套分支结构: 在分支结构中嵌套分支结构 switch多分支结构: 一般用作等值判断 */ public class IfDemo{ public static void main(String[] args){ //单分支判断,Math.random()产生数据的范围是[0,1) //得到0-5之间的随机数 //int i = (int)(Math.random()*6); //if(i>3){ // System.out.println("值大于3"); //} //System.out.println("number:"+i); /* double i = 6 * Math.random(); double j = 6 * Math.random(); double k = 6 * Math.random(); int count = (int) (i + j + k); if(count > 15) { System.out.println("今天手气不错"); } if(count >= 10 && count <= 15) { //错误写法:10<count<15 System.out.println("今天手气很一般"); } if(count < 10) { System.out.println("今天手气不怎么样"); } System.out.println("得了" + count + "分");*/ //双分支结构 /* int r = 1; double PI = 3.14; double area = PI * r * r; double length = 2 * PI * r; if(area >= length){ System.out.println("面积大于等于周长"); }else{ System.out.println("周长大于面积"); } */ //Scanner //创建文件扫描器对象,System.in表示的是标准输入,可以从控制台读取数据(装饰者模式) //注意:每次读取回来的值都是字符串类型,需要进行类型转换 //Scanner sc = new Scanner(System.in); //System.out.println("请输入数据"); //String str = sc.nextLine(); //System.out.println(str); //多分支结构 /* int age = (int)(Math.random()*100); if(age<10){ System.out.println("儿童"); }else if(age<20){ System.out.println("少年"); }else if(age<30){ System.out.println("青年"); }else if(age<50){ System.out.println("中年"); }else if(age<70){ System.out.println("老年"); }else{ System.out.println("耄耋"); } */ //嵌套分支结构 /* int time = (int)(Math.random()*40); if(time<20){ System.out.println("恭喜进入决赛"); String sex = ((int)(Math.random()*2))==0?"girl":"boy"; if(sex=="girl"){ System.out.println("欢迎进入女子组"); }else{ System.out.println("欢迎进入男子组"); } }else{ System.out.println("成绩太差,被淘汰"); } */ //switch多分支结构 /*注意: 1、每个case模块中要添加break,防止多次匹配 2、如果多个case中处理的逻辑代码块的功能一致,可以考虑只在最后添加一次处理 3、default表示默认选项,当所有的case不匹配的时候,会执行此选项 4、defult可以有,也可以没有 */ int random = (int)(Math.random()*26); char ch = (char)('a'+random); switch(ch){ /* case 'a': System.out.println("元音:"+ch); break; case 'e': System.out.println("元音:"+ch); break; case 'i': System.out.println("元音:"+ch); break; case 'o': System.out.println("元音:"+ch); break; case 'u': System.out.println("元音:"+ch); break; case 'y': System.out.println("半元音:"+ch); break; case 'w': System.out.println("半元音:"+ch); break; default: System.out.println("辅音:"+ch);*/ case 'a': case 'e': case 'i': case 'o': case 'u': System.out.println("元音:"+ch); break; case 'y': case 'w': System.out.println("半元音:"+ch); break; default: System.out.println("辅音:"+ch); } } }
七、循环结构
whilehttps://img.qb5200.com/download-x/do-while
/* 循环结构: 1、while 先进行判断,再进行逻辑执行 需要四部分组成 初始化:变量的初始化 条件判断:必须要求返回true或者false的值 循环体:具体的要执行的逻辑代码 迭代变量:促使此循环结束 2、do while 先执行代码逻辑,再执行判断 */ public class WhileDemo{ public static void main(String [] args){ //while循环样例 /* int i = 1; while(i<=100){ System.out.println("第"+i+"遍输出"); i++; } */ //求100内的偶数和 /* int i = 1; //求和最终的存储变量 int sum = 0; while(i<=100){ if(i % 2 == 0){ sum+=i; } i++; } System.out.println("100以内的偶数和是:"+sum); */ // do while /* int i = 1; do{ System.out.println("第"+i+"遍输出"); i++; }while(i<=100); */ int i = 1; int sum = 0; do{ if(i % 2 == 0){ sum+=i; } i++; }while(i<=100); System.out.println("100以内的偶数和是:"+sum); } }
for
/* 第三种循环结构是for循环,使用最多 语法规则: for(初始化1;条件表达式2;步进器4){ 代码逻辑3 } 使用for循环的好处: 1、代码简洁 2、变量初始化的时候,for循环的作用域仅仅是当前for循环结构 while循环的作用域是从变量的定义开始到整个方法结束 */ public class ForDemo{ public static void main(String[] args){ /* for(int i = 1;i<=100;i++){ System.out.println("第"+i+"遍输出"); } //100以内的偶数和 int sum = 0; for(int i = 1;i<=100;i++){ if(i%2==0){ sum+=i; } } System.out.println("100以内的偶数和是:"+sum); */ for(int i =1;;){ System.out.println(i); } } }
练习:将十进制数变二进制数
import java.util.Scanner; public class TenToTwo{ public static void main(String[] args){ Scanner sc = new Scanner(System.in); System.out.println("ÇëÊäÈëÒ»¸öÊ®½øÖÆÊý£º"); int number = sc.nextInt(); String str = ""; while(number!=0){ int i = number % 2; str = i+str; number = number/2; } System.out.println(str); } }
break
/* 生成0-100随机数,直到生成88为止,停止循环! break:跳出本层循环,当包含多层循环的时候,break只能跳出内层循环,无法跳出外层循环 */ public class BreakDemo{ public static void main(String[] args){ /* int count = 0; while(true){ int i = (int)(Math.random()*101); if(i==88){ break; } count++; System.out.println(count+"--"+i); } */ //请打印输出(1,1)(1,2)(1,3)...直到输出(6,6)停止 for(int i = 1;i<10;i++){ for(int j =1;j<10;j++){ System.out.println("("+i+","+j+")"); if(i==6&&j==6){ return; } } } } }
continue
/* 把100~150之间不能被3整除的数输出: continue:跳出本次循环 */ public class ContinueDemo{ public static void main(String[] args){ for(int i = 100;i<150;i++){ if(i%3==0){ continue; } System.out.println(i); } } }
return
/* return有两基本用途 1、返回方法的返回值 2、终止当前程序 */ public class ReturnDemo{ public static void main(String[] args){ System.out.println(get()); for(int i = 0;i<10;i++){ System.out.println(i); if(i==5){ return; //System.exit(100); } System.out.println("接着执行"); } } public static int get(){ return 100; } }
练习:九九乘法表
public class ManyFor{ public static void main(String[] args){ //打印九九乘法表 for(int i = 1;i<10;i++){ for (int j = 1;j<=i;j++){ System.out.print(j+"*"+i+"="+i*j+"\t"); } System.out.println(); } } }
练习:斐波那契数列 / 递归函数
import java.util.Scanner; /* 斐波那契数列,可以选择打印多少个值 */ public class Fibonacci{ public static void main(String[] args){ /* Scanner sc = new Scanner(System.in); System.out.println("请输入要打印的斐波那契数列的个数"); int count = sc.nextInt(); int x = 1; int y = 1; int z = 0; //前两位是1 for(int i = 1;i<=count;i++){ if(i==1 || i==2){ System.out.print(1+"\t"); }else{ z=x+y; x=y; y=z; System.out.print(z+"\t"); } } */ for(int i = 1;i<=10;i++){ System.out.print(getNumber(i)+"\t"); } } /* 递归函数: 再程序运行过程中,有时需要调用程序本身,此时可以使用递归 注意: 再程序中,能不使用递归就不要使用递归 使用递归的时候会加大资源的消耗 如果递归的层次比较深,会造成栈溢出。 如果不使用递归无法解决问题的话,就必须要使用递归 比如:输出某个磁盘目录下的所有文件名称 */ public static int getNumber(int number){ if(number==1||number==2){ return 1; }else{ return getNumber(number-1)+getNumber(number-2); } } }
练习:百钱白鸡
public class BuyChicken{ public static void main(String[] args){ for(int i = 0;i<=20;i++){ for(int j = 0;j<=34;j++){ for(int k = 0;k<=300;k++){ if(((i+j+k)==100) && ((5*i+3*j+ k/3)==100) && (k%3==0)){ System.out.println("¹«¼¦£º"+i+"\tĸ¼¦£º"+j+"\tС¼¦£º"+k); } } } } } }
八、数组
/* 数组表示存储相同数据类型数据的有序集合 特点: 1、数组中存放的数据必须是同一个数据类型,可以是基本数据类型也可以是引用数据类型 2、数组在定义的时候必须要给定大小,且大小不可以改变 3、可以通过下标值来获取数据,下标从0开始 4、插入数组中的数据是有序集合,此时有序并不是指代大小排序,而是指插入的顺序 使用: 1、声明数组 2、创建空间 3、赋值 4、数组操作 */ public class ArrayDemo{ public static void main(String[] args){ /* //声明数组 int[] array; //创建内存空间 array = new int[5]; //数组赋值 array[0] = 0; array[1] = 1; array[2] = 2; array[3] = 3; array[4] = 4; //数组操作 System.out.println(array[0]); //数组的几种创建方式 //1、声明并申请空间 int[] arr1 = new int[5]; int [] arr2 = new int[5]; int arr3[] = new int[5]; //2、声明数组并赋值 int[] arr4 = new int[]{1,2,3,4,5}; //3、直接初始化操作 int[] arr5 = {1,2,3}; //获取数组的长度 System.out.println(arr1.length); //输入5个数值,求平均值 int[] arr6 = new int[]{56,98,34,89,100}; int sum = 0; for(int i = 0;i<arr6.length;i++){ sum+=arr6[i]; } System.out.println("平均值是:"+sum/arr6.length); */ /* 数组是引用类型,当创建完成数组之后相当于是在方法外定义了一个变量,此时数组中的值是有默认值的 默认是什么,取决于你定义的数组的类型: int:0 String null boolean false 数组可以根据下标获取值,但是获取的时候下标的范围是[0,length-1] */ int[] array = new int[5]; System.out.println(array[0]); } }
数组排序
import java.util.Arrays; /* 数组相当于数据结构的一种实现,很多数据在进行存储的时候需要使用数组 数据结构: 线性表 非线性表 树 图 队列 栈 数组经常会用来考排序算法: 面试需求: 1、写出某种排序算法 冒泡排序 选择排序 插入排序 快速排序 2、排序算法的时间复杂度(空间复杂度) 衡量一个数据结构是否合适的衡量标准 3、排序算法的稳定性 排序之后的值跟排序之前的值位置是否发生变化 */ public class ArraySort{ public static void main(String[] args){ //定义数组 int[] array = new int[]{4,1,7,2,9,3,5,8,6}; //将数组进行排序操作,从小到大 //冒泡排序 /* for(int i=0;i<array.length;i++){ for(int j = 0;j<array.length-1-i;j++){ if(array[j]>array[j+1]){ int tmp = array[j]; array[j] = array[j+1]; array[j+1] = tmp; } } } */ //选择排序 /* for(int i = 0;i<array.length;i++){ for(int j = i+1;j<array.length;j++ ){ if(array[i]>array[j]){ int tmp = array[i]; array[i] = array[j]; array[j] = tmp; } } } */ Arrays.sort(array); for(int i = 0;i<array.length;i++){ System.out.print(array[i]+"\t"); } } }
九、面向对象
类
/* * 所有类定义的时候可以添加属性和方法,但是不是必须要写的 * 一个java文件中可以定义N多个class,但是只能有一个public class并且public class的类名跟文件名保持一致 * 属性: * 语法: * [访问修饰符] 数据类型 属性名称 = 值; * * 注意: * 定义属性的时候可以有值也可以没有值 * 必须要包含类型和名称 * * * 方法:表示行为 * 语法: * [访问修饰符] 返回值类型(任何类型) 方法名称(形参列表){ * 逻辑代码 * * } * 注意: * 1、方法的访问修饰符可以不写 * 2、方法可以有返回值,也可以没有,void表示没有返回值的意思 * 3、形参列表可以有,也可以没有 * 4、java中方法的传参都是值传递(后续会讲) * * 对象的创建和使用 * 1、使用new关键字来创建对象 * ClassName objectName = new ClassName(); * 2、对象的使用 * 使用对象的时候可以通过 对象名称.属性 或者 对象名称.方法 来使用属性和方法 * */ public class Student { //属性的定义 int stuNumber; String name; int age = 20; //方法的定义 void study(){ System.out.println("我正在学习"); } void eat(String food){ System.out.println("我在吃"+food); } public static void main(String[] args) { //创建对象 Student student = new Student(); //使用属性 System.out.println(student.name); System.out.println(student.age); System.out.println(student.stuNumber); //修改属性值,给属性赋值 student.name="张三"; student.age=40; student.stuNumber=20190818; System.out.println(student.name); System.out.println(student.age); System.out.println(student.stuNumber); //调用方法 student.study(); student.eat("apple"); } }
String字符串的比较
/* * 字符串在比较的时候: * ==:比较的是地址 * equals:比较的是具体的值 * */ public class StringDemo { public static void main(String[] args) { String str = "abc"; String str1 = str; System.out.println(str == str1);//true System.out.println(str.equals(str1));//true Scanner sc = new Scanner(System.in); String str2 = sc.nextLine(); System.out.println(str == str2);//false System.out.println(str.equals(str2));//true String str3 = new String("abc"); System.out.println(str == str3);//false System.out.println(str.equals(str3));//true } }
变量
/* * 变量: * 局部变量: * 定义在方法中的变量称之为局部变量 * 作用域:从定义的位置开始到整个方法结束 * 局部变量不包含默认值,如果没有使用当前变量的话,可以不赋值 * 注意:局部变量只能在当前方法中使用,其他地方无法使用 * 成员变量: * 定义在方法外,类内的变量叫做成员变量(全局变量) * 成员变量包含初始值:int 0 String null boolean false * 作用域:整个类体内 * * */ public class VarDemo { int age = 20; public void test(){ System.out.println(age); age = 10; System.out.println(age); int age = 30; System.out.println(age); } public void show(){ //局部变量 int a ; String name = "zhangsan"; System.out.println(age); // System.out.println(a); } public static void main(String[] args) { VarDemo vd = new VarDemo(); System.out.println(vd.age); vd.test(); System.out.println(vd.age); } }
构造方法 / 构造方法
/* * 构造方法: * 创建对象的时候默认会调用构造方法来创建对象,(在堆中开辟空间),可以完成成员变量的某些初始化操作 * 构造方法的语法: * 方法名称:构造方法的方法名称必须跟类的名称保持一致 * 访问修饰符:后面讲 * 形参:可以用户自定义添加,跟方法的普通参数一样 * 方法体:完成对象的初始化功能 * 返回值:没有返回值 * 注意: * 1、创建完类之后,如果没有手动调用构造方法,会有一个默认的无参的构造方法供调用 * 2、当用户自定义了构造方法之后,默认的无参构造方法就不能够使用了,必须要手动定义无参构造方法 * 3、同一个类中可以包含多个同名的构造方法 * * 重载:在一个类中可以包含多个重名的方法,但是注意方法的参数列表不能相同 * 三个方面的不同: * 参数的个数不同 * 参数的类型不同 * 参数的顺序不同 * 注意: * 一般构造方法都会进行重载(一个类中可能包含多个属性值,当只需要给部分属性初始化的时候需要调用不同的构造方法) * */ public class Teacher { String name; int age; public Teacher(){ } public Teacher(String xname){ System.out.println("one argument"); name = xname; } //构造方法 public Teacher(String xname,int xage){ System.out.println("two argument"); System.out.println("new......"); name = xname; age =xage; } public void teach(String a,int b){ } public void teach(int b,String a ){ System.out.println("上课"); } public static void main(String[] args) { Teacher teach = new Teacher(); teach.name="连"; teach.age=18; System.out.println(teach.name); System.out.println(teach.age); Teacher teacher2 = new Teacher("lisi",29); System.out.println(teacher2.name); System.out.println(teacher2.age); Teacher t3 = new Teacher("wangwu"); System.out.println(t3.name); } }
this
/* * this:表示当前对象的指针 * 指向当前对象,表示当前对象的引用 * 用处: * 1、构造方法,当构造方法中的参数名称跟类的成员变量名称一样的时候,可以使用this代表当前对象 * 注意:有了this之后,可以将构造方法的参数跟成员变量保持一致 * 当构造方法中需要调用其他的构造方法时,可以使用this(name)调用其他构造方法,但是必须位于方法体的第一行 * 2、普通方法中: * 当多个普通方法之间需要调用的时候,可以使用this来进行调用,指的是当前对象的其他方法 * 3、成员变量的使用: * 当方法中的参数名称跟成员变量保持一致的时候,使用 this.变量名称 表示的是对象的值,而使用变量名称表示形参列表中的值 * */ public class ThisDemo { String name; int age; public ThisDemo(){ } public ThisDemo(String name){ System.out.println("one"); this.name = name; } public ThisDemo(String name,int age){ this(name); System.out.println("two"); this.age = age; } public void test1(){ System.out.println("test1"); this.test2("hehe"); } public void test2(String name){ System.out.println("test2"); test1(); System.out.println(name); System.out.println(this.name); } public static void main(String[] args) { ThisDemo td = new ThisDemo("zhangsan",12); System.out.println(td.name); System.out.println(td.age); td.test2("lisi"); } }
static
/* * static: * 修饰成员变量的时候,表示静态成员变量或者叫类变量 * 普通变量在使用的时候,必须要通过对象名进行调用 * 类变量或者静态变量可以使用对象名调用也可以使用类名进行调用 * 修饰方法的时候,表示静态方法或者叫类方法 * 普通方法在使用的时候,必须要通过对象名进行调用 * 类方法或者静态方法可以使用类名,也可以使用对象名 * 注意: * 1、静态变量,在创建对象之前被初始化,或者说在类被载入之前进行初始化 * 2、静态变量被所有的对象共享,属于公共变量,对象和类都可以直接调用,但是推荐使用类来调用 * 3、成员变量放在堆中,而静态变量放在方法去中静态区 * 4、静态变量不能定义在静态方法中 * 5、静态方法可以在非静态方法中进行调用 * 6、静态方法中不能直接调用非静态方法 * 7、静态方法中不允许出现this调用 * 8、一般工具类中的方法定义为static * */ public class StaticDemo { String name = "zhangsan"; static int age = 10; public static void test(){ // test2(); // static int a = 10; } public void test2(){ System.out.println("non-static"); } public static void main(String[] args) { // StaticDemo staticDemo = new StaticDemo(); // //使用对象进行调用 // System.out.println(staticDemo.name); // System.out.println(staticDemo.age);//10 // // staticDemo.age = 20; // System.out.println(staticDemo.age);//20 // System.out.println(StaticDemo.age);//20 // // StaticDemo.age = 30; // System.out.println(staticDemo.age);//30 // System.out.println(StaticDemo.age);//30 // // StaticDemo staticDemo1= new StaticDemo(); // System.out.println(staticDemo1.age);//30 //使用类名调用 // System.out.println(StaticDemo.name); // System.out.println(StaticDemo.age); // StaticDemo sd = new StaticDemo(); // sd.test(); // StaticDemo.test(); // sd.test2(); StaticDemo staticDemo = null; staticDemo.test2(); } }
代码块
/* * 代码块: 使用{}括起来的一段代码叫做代码块 * 分类: * 普通代码块:定义在方法中,使用{}括起来的代码叫做普通代码块 * 构造代码块:定义在类中的使用{}括起来的代码叫做构造代码块 * 注意:每次代码运行的时候回将构造代码块中的代码添加到构造方法的前面 * 构造代码块中的代码会添加到每一个构造方法中,当使用this(参数)的时候不会添加 * 静态代码块:使用static{}括起来的代码叫做静态代码块,在程序载入的时候优先执行 * 数据库连接等其他提前需要准备好的代码会放在static代码块 * 同步代码块: * 在多线程的时候回使用,用来给共享空间进行加锁操作(后面讲) * 执行顺序:静态代码块--》构造代码块(创建对象的时候才会用到)--》普通代码块 * */ public class CodeBlockDemo { int a ; int b; static{ System.out.println("静态代码块"); } public CodeBlockDemo(){ System.out.println("无参"); System.out.println("构造方法"); } public CodeBlockDemo(int a){ this.a = a; } public CodeBlockDemo(int a,int b){ this(a); this.b = b; } { System.out.println("构造代码块"); } public void test(){ System.out.println("test"); { System.out.println("我应该是什么分类"); } } public static void main(String[] args) { CodeBlockDemo codeBlockDemo = new CodeBlockDemo(1,2); codeBlockDemo.test(); { System.out.println("main"); } } }
package
/* * package:包,对应到文件系统就是多级目录 * 为了解决两个问题: * 1、文件同名问题 * 2、为了方便管理类,将具体处理功能的代码放到同一个目录下 * 使用: * 一般定义package会放置在java文件的第一行 * package 域名的倒写 * package com.packagename. * 完全限定名: 包名+类名 * * JDK中常用的包: * lang:不需要手动导入,自动加载 * util:工具包 * net:网络包 * io:输入输出流包 * * */ public class PackageDemo { public static void main(String[] args) { java.util.Date date = new java.util.Date(); } }
import
/* * import: * 当需要引入非lang包的其他java类的时候,需要使用import工具 * 如果不使用import,每次在使用某个类的时候必须要将类的完全限定名都加上才可以使用,太过于繁琐 * * 用法: * import java.包名.类名;导入具体的类 推荐使用 * import 包名.*; 将当前包下的所有类文件都进行导入 * 注意: * 当一个java文件中需要使用多个同名的类的时候,只能选择导入一个,另一个使用完全限定名的方式进行导入 * * 静态导包: * 当需要使用某个类的多个方法的时候,同时又不想频繁写该类的名称,此时可以使用静态导包 * */ public class ImportDemo { // public void sqrt(){ // System.out.println("sqrt"); // } public static void main(String[] args) { // java.util.Date date = new java.util.Date(); // Date date = new Date(); // java.sql.Date date1 = new java.sql.Date(); System.out.println(Math.sqrt(2)); System.out.println(Math.abs(-2)); System.out.println(sqrt(2)); System.out.println(abs(-2)); } }
封装
/* * 封装: * 概念: * 将类的某些信息隐藏在类内部,不允许外部程序直接访问, * 而是通过该类提供的方法来实现对隐藏信息的操作和访问 * 封装解决什么问题: * 如果任何一个处理类都可以直接对Dog进行赋值操作,那么当值不准确的时候,可以回产生额外的结果, * 如何在赋值的同时添加一些逻辑判断呢? * 封装可以解决此问题 * 作用: * 使用封装可以保证数据的规范,不符合规范的数据将无法进行操作 * 好处: * 1、隐藏类的内部实现细节 * 2、只能通过提供的方法进行访问,其他方法无法访问 * 3、可以根据需求添加复杂的逻辑判断语句 * 4、方便修改实现 * 面向对象的封装(狭义)可以用一句话概述: 为了保证数据安全和规范 * 将类中的属性设置为私有属性,提供共有的外部方法供程序进行调用,可以实现丰富的细节操作 * 广义的封装: * 可以将完成特定功能的代码块封装成一个方法,供不同的程序进行调用 * */ public class DogTest { public static void main(String[] args) { Dog dog = new Dog(); // dog.name="大黄"; // dog.setAge(-20); dog.setAge(20); // dog.color="yellow"; // dog.show(); System.out.println(dog.getAge()); } }
/* * 定义类的时候需要包含以下组件: * 私有属性 * 构造方法(无参构造方法和自定义构造方法) * set/get方法 * 普通方法 * * * * */ public class Dog { private String name; private int age; private String color; public Dog(){ } public Dog(String name,int age,String color){ this.name = name; if(age>0){ this.age = age; }else{ System.out.println("年龄不规范"); } this.color = color; } public void setAge(int age){ if(age>0){ this.age = age; }else{ System.out.println("输入年龄不规范,重新输入"); } } public int getAge(){ return this.age; } public void setName(String name){ this.name = name; } public String getName(){ return this.name; } public void setColor(String color){ this.color = color; } public String getColor(){ return this.color; } public void eat(){ System.out.println("eating 骨头"); } public void play(){ System.out.println("palying...."); } public void show(){ System.out.println("name:"+this.name); System.out.println("age:"+this.age); System.out.println("color:"+this.color); } }
访问权限
/* * 在java中明确定义了访问权限: * 限制访问,以下分类按照从大到小进行排列 * public:公共的 * 当前项目的所有的类都可以进行访问 * protected:受保护的 * 可以被当前类访问,可以被当前包访问,也可以被子类访问 * default:默认权限 * 可以被当前类访问,可以被当前包访问, * private:私有权限 * 只能被当前类访问 * * 注意:四种访问修饰符可以修饰属性和方法 * 类的访问修饰符只有两个 public default * * */ public class AccessControlDemo { public AccessControlDemo(){ } protected AccessControlDemo(int a,int b){ } private String str = "test"; } class Test{ }
参数传递
/* * * 方法参数的值是否改变 * 方法中的参数列表叫做形式参数,没有具体的值,只是为了方便在方法体中使用 * 调用方法的时候实际传入的值叫实际参数,代表具体的数值,用来替换在方法体中代码逻辑的值进行运算 * 注意: * 1、形式参数的变量名称也是局部变量 * 2、当方法的参数值是基本数据类型的时候,不会改变原来的值 * 3、当方法的参数值是引用类型的时候,如果改变了该引用类型的值,会改变原来对象的值 * java中的参数传递是值传递 * */ public class ArgumentDemo { public static void test(int a,int b){ int tmp = a; a = b; b = tmp; } public static void test2(Point point){ int x = point.getX(); int y = point.getY(); int tmp = x; x = y; y = tmp; point.setX(x); point.setY(y); } public static void main(String[] args) { // int a = 10; // int b = 20; // test(a,b); // System.out.println(a); // System.out.println(b); Point point = new Point(2,3); test2(point); System.out.println(point.getX()); System.out.println(point.getY()); } }
extend / 重写
/* * 继承: * 表示父类跟子类之间的关系 * 当两个类或者多个类具备相同的属性和方法的时候,可以提取出来,变成父类,子类可以继承 * * 子类跟父类是is-a的关系 * * 使用: * 1、使用继承的时候需要使用extend关键字 * 2、使用继承关系之后,父类中的属性和方法都可以在子类中进行使用(非私有属性和非私有方法) * 3、java中是单继承关系(如果包含多个父类,同时父类中包含重名方法,无法决定改调用谁) * * * super:是 直接父类 对象的引用 * 用途: * 1、可以在子类中调用父类中被子类覆盖的方法 super.父类方法名称 * 2、当super在普通方法中使用的话,可以任意位置编写 * 3、当super在构造方法中使用的话,会调用父类的构造方法,一定要将super放在第一行 * 4、在构造方法中super关键字和this关键字不能同时出现 * 5、父类中私有的属性和方法都不能被调用,包括构造方法 * 6、子类的构造方法中都会默认使用super关键字调用父类的无参构造方法,因此在定义类的时候,无论自己是否自定义了 * 其他构造方法,最好将无参构造方法写上 * 7、如果构造方法中显式的指定了super的构造方法,那么无参的构造方法就不会被调用 * * 总结: * 1、在创建子类对象的时候一定会优先创建父类对象 * 2、所有的java类都具备同一个老祖宗类,称之为Object,是所有类的根类 * * 重写: * 必须要存在继承关系,当父类中的方法无法满足子类需求的时候可以选择使用重写的方式 * 注意: * 1、重写表示的是子类覆盖父类的方法,当覆盖之后,调用同样的方法的时候会优先调用子类 * 2、重写的方法名称,返回值类型,参数列表必须跟父类一直 * 3、子类重写的方法不允许比父类的方法具备更小的访问权限 * 父类 public 子类 public * 父类 protected 子类 public protected * 父类 protected 子类 public protected default * 父类的静态方法子类可以进行调用,但是子类不可以重写 * */ public class PetTest { public static void main(String[] args) { // Dog dog = new Dog("小黑",12,"男","汪汪"); // dog.setName("大黄"); // System.out.println(dog.getName()); // dog.play(); // dog.p Pet pet = new Pet(); System.out.println(pet); Dog dog = new Dog(); System.out.println(dog); dog.test(); } }
public class Pet { private String name; private int age; private String gender; protected String abc; public Pet(){ System.out.println("pet 无参构造方法"); } public Pet(String name, int age, String gender) { // this(); this.name = name; this.age = age; this.gender = gender; } 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 getGender() { return gender; } public void setGender(String gender) { this.gender = gender; } private void play(){ System.out.println("play....."); } public static void test(){ System.out.println("static test"); } @Override public String toString(){ return "my name is "+this.name+",my age is "+this.age+",my gender is"+this.gender; } }
public class Penguin extends Pet{ // private String name; // private int age; // private String gender; private String color; public Penguin(){ } public Penguin(String name, int age, String gender, String color) { // this.name = name; // this.age = age; // this.gender = gender; super(name,age,gender); this.color = color; } // 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 getGender() { // return gender; // } // // public void setGender(String gender) { // this.gender = gender; // } public String getColor() { return color; } public void setColor(String color) { this.color = color; } public void play(){ System.out.println("penguin is playing ice"); } }
public class Dog extends Pet{ private String sound; public Dog(){ System.out.println("dog 无参构造"); } public Dog(String name, int age, String gender, String sound) { this.sound = sound; } public String getSound() { return sound; } public void setSound(String sound) { this.sound = sound; } public void play(){ System.out.println("dog is playing ball"); } public String toString(){ return super.toString()+",my sound is"+this.sound; } }
abstract
/* * java中的对象是对现实世界的具象化,但是在现实世界中,某些类并不具备实例化的意义,因此可以定义为抽象类 * * 抽象类: * 1、创建抽象类的时候需要添加 abstract 的关键字 * 2、不能进行实例化,也就是不能new对象 * 3、抽象类中的某些方法需要子类进行更丰富的实现,父类实现没有意义,此时可以将抽象类 * 中的方法定义为抽象方法,没有具体的实现,只包含方法名称,返回值,参数列表,访问修饰符 * 4、使用abstract关键字修饰的方法叫做抽象方法,可以不写方法的实现 * 5、子类在继承抽象父类的时候,必须要将父类中的抽象方法进行实现或者将子类也定义为抽象类 * 6、有抽象方法的一定是抽象类,但是抽象类中不一定包含抽象方法 * */ public class AbstractTest { public static void main(String[] args) { Dog dog = new Dog(); dog.print(); dog.play(); } }
public abstract class Pet { private String name; private int age; public abstract void print(); public void play(){ System.out.println("play...."); } }
public class Dog extends Pet{ private String gender; @Override public void print() { System.out.println("dog print"); } }
final
/* * final的使用: * final可以修饰变量: * 表示变量的值不可变 * final可以修饰方法: * 表示方法不可以被重写 * final可以修饰类: * 表示类不可以被继承 * * */ public final class FinalDemo { public final String name = "zhangsan"; public final void test(){ System.out.println("final test"); } public static final int age =10; public static void main(String[] args) { // age = 20; } }
多态
/* * 多态: * 对应同一个指令(调用同一个名称的方法),不同的对象给予不同的反应(不同的方法实现) * 规范(多态实现的提前): * 1、必须要有继承关系 * 2、子类方法必须重写父类的方法 * 3、父类引用指向子类对象 * 多态的目的: * 为了提高代码的扩展性和维护性 * 方便代码逻辑的编写 * 多态的两种表现形式: * 1、父类作为方法的参数 * 2、父类作为方法的返回值类型 * * 引用类型的转换跟基本数据类型的转换类似: * 1、当父类需要转成子类的时候,要进行强制转换,但是在强制转换之前一定要先判断父类引用指向的子类对象到底是谁, * 如果无法确定,在运行过程中可以出错 * 2、当子类需要向父类转换的时候,直接自动转换,不需要进行任何的判断。 * * */ public class Person{ // public void feed(Cat cat){ // cat.feed(); // } // // public void feed(Dog dog){ // dog.feed(); // } public void feed(Pet pet){ pet.feed(); } public void play(Pet pet){ pet.play(); } public Pet buyPet(int type){ if(type==1){ return new Dog(); }else if(type == 2){ return new Cat(); }else{ return new Penguin(); } } public static void main(String[] args) { Person p = new Person(); Pet dog = new Dog(); Pet cat = new Cat(); Pet penguin = new Penguin(); p.feed(dog); p.feed(cat); p.feed(penguin); p.play(dog); p.play(cat); // Person p1 = (Person)dog; Pet pet = p.buyPet(2); if(pet instanceof Dog){ System.out.println("买的是一只狗"); }else if(pet instanceof Cat){ System.out.println("买的是一只猫"); }else{ System.out.println("买的是一只企鹅"); } } }
public abstract class Pet { public abstract void feed(); public void play(){ System.out.println("playing....."); } }
public class Dog extends Pet { @Override public void feed() { System.out.println("狗在吃骨头"); } }
public class Cat extends Pet { @Override public void feed() { System.out.println("猫在吃鱼"); } }
public class Penguin extends Pet { @Override public void feed() { System.out.println("企鹅在吃。。。。"); } }
interface
/* * java中的继承关系是单继承,如果拥有多个父类的时候,可以考虑使用接口进行实现 * java中的接口具备广泛的使用: * 用法: * 使用interface来修饰 * 接口中可以包含多个方法,且方法跟抽象类中的抽象方法一致,可以不写实现,子类在实现的时候必须要实现代码逻辑 * 子类实现接口使用implements关键字 * 特征: * 1、接口中的所有方法都是抽象方法,不能包含方法的实现 * 2、接口中的所有方法的访问修饰权限都是public,不写并不是默认访问权限,而是public * 3、接口不能被实例化 * 4、接口的子类必须要实现接口中的所有方法,跟抽象类有所不同,抽象类中的抽象方法必须要被子类实现 * 5、子类可以拥有实现多个接口 * 6、接口中的变量都是静态常量,如果变量没有使用static关键字修饰,它也表示静态常量,不用final关键字修饰,也是常量 * 7、接口中的方法和常量无论是否添加public修饰,默认的权限有且仅有一个,就是public * * 接口的使用: * 1、接口代表一种能力,接口中可以定义N多个方法,子类在进行实现的时候,必须要实现这些方法 * 将这些方法进行实现,就意味着具体了方法的能力 * 关心实现类有何能力,而不关心实现细节 * * 抽象类和接口的区别: * 1、抽象类中的方法可以有抽象方法,也可以有普通方法,但是接口中只能包含抽象方法 * 2、抽象类需要使用abstract关键字来修饰,而接受使用interface关键字来修饰 * 3、子类使用extends关键字来继承抽象类,使用implements来实现接口 * 4、子类继承抽象类的时候必须要实现所有的抽象方法,普通方法可以不重写,而接口中的所有方法必须实现 * 5、抽象类中可以定义成员变量,而接口中只能定义静态常量 * 6、抽象类在子类实现的时候是单继承,而接口时多继承 * 7、抽象类和接口都不能实例化,但是抽象类中可以有构造方法,而接口中不能有构造方法 * 8、抽象类中可以实现接口,并且不实现接口中方法,而接口只能继承接口,不能实现接口 * 注意: * 在实际的项目开发过程中,如果可以使用接口,尽量使用接口,将单继承的父类留在最关键的地方 * */ public class TestLockDoor { public static void main(String[] args) { LockDoor lockDoor = new LockDoor(); // Lock lock = new Lock(); lockDoor.openDoor(); lockDoor.openLock(); lockDoor.closeDoor(); lockDoor.closeLock(); lockDoor.photo(); System.out.println(LockDoor.a); // LockDoor.a = 300; } }
public class LockDoor extends Door implements Lock,DoorBell { @Override public void openDoor() { System.out.println("开门"); } @Override public void closeDoor() { System.out.println("关门"); } @Override public void openLock() { System.out.println("开锁"); } @Override public void closeLock() { System.out.println("关锁"); } @Override public void photo() { System.out.println("拍照存档"); } }
public interface Lock { int a = 200; void openLock(); void closeLock(); }
public abstract class Door { public abstract void openDoor(); public abstract void closeDoor(); }
public interface DoorBell { void photo(); }
Proxy
/* * * 代理人 * */ public class WangPo implements KindWomen { private KindWomen kindWomen; public WangPo(){ this.kindWomen = new PanJinLian(); } public WangPo(KindWomen kindWomen){ this.kindWomen = kindWomen; } @Override public void makeEyesWithMen() { this.kindWomen.makeEyesWithMen(); } @Override public void playWithMen() { this.kindWomen.playWithMen(); } }
public class XiMenQing { public static void main(String[] args) { // WangPo wangPo = new WangPo(); // wangPo.playWithMen(); // wangPo.makeEyesWithMen(); JiaShi jiaShi = new JiaShi(); WangPo wangPo = new WangPo(jiaShi); wangPo.makeEyesWithMen(); wangPo.playWithMen(); } }
public class PanJinLian implements KindWomen{ @Override public void makeEyesWithMen() { System.out.println("潘金莲在抛媚眼"); } @Override public void playWithMen() { System.out.println("潘金莲。。。。。"); } }
public interface KindWomen { /* * 抛媚眼 * */ public void makeEyesWithMen(); public void playWithMen(); }
public class JiaShi implements KindWomen{ @Override public void makeEyesWithMen() { System.out.println("贾事抛媚眼"); } @Override public void playWithMen() { System.out.println("贾事。。。。。"); } }
内部类
/* * 内部类(当作类中的一个普通成员变量,只不过此成员变量是class的类型): * 一个java文件中可以包含多个class,但是只能有一个public class * 如果一个类定义在另一个类的内部,此时可以称之为内部类 * 使用: * 创建内部类的时候,跟之前的方法不一样,需要在内部类的前面添加外部类来进行修饰 * InnerClassDemo.InnerClass inner = new InnerClassDemo().new InnerClass(); 特点: 1、内部类可以方便的访问外部类的私有属性 2、外部类不能访问内部类的私有属性,但是如果创建了内部类的对象,此时可以在外部类中访问私有属性 3、内部类中不能定义静态属性 4、当内部类和外部类具有相同的私有属性的时候,在内部类中访问的时候,可以直接访问内部类的属性, 如果需要访问外部类的属性,那么需要添加 外部类类名.this.属性。 分类: 匿名内部类:当定义了一个类,实现了某个接口的时候,在使用过程中只需要使用一次,没有其他用途 其实考虑到代码编写的简洁,可以考虑不创建具体的类,而采用new interface(){添加未实现的方法} 就叫做匿名内部类 静态内部类:在内部类中可以定义静态内部类,使用static关键字进行修饰,使用规则 外部类.内部类 类的引用名称 = new 外部类.内部类(); 方法内部类:在外部类的方法中也可以定义类,此时叫做方法内部类(了解即可) 使用的时候需要注意,只能在方法中创建对象,因为此class的作用域就是当前方法 * */ public class TestInnerClass { public static void main(String[] args) { // System.gc(); InnerClassDemo innerClassDemo = new InnerClassDemo(); innerClassDemo.show(); System.out.println(innerClassDemo.getName()); InnerClassDemo.InnerClass inner = new InnerClassDemo().new InnerClass(); inner.test(); // System.out.println(inner.age); InnerClassDemo.InnerClass.InnerInner innerInner = new InnerClassDemo().new InnerClass().new InnerInner(); } }
public class InnerClassDemo { private int id; private String name; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public void show(){ System.out.println("show"); // System.out.println(age); InnerClass inner = new InnerClass(); System.out.println(inner.age); } class InnerClass{ private int age; // static String name = "zhangsan"; public void test(){ System.out.println("test"); System.out.println(id); System.out.println(name); } class InnerInner{ private int id; public void print(){ System.out.println("print"); } } } public static void main(String[] args) { InnerClass innerClass = new InnerClassDemo().new InnerClass(); } }
十、 异常
try_catch
/* * 异常: * 在程序运行过程中,出现的不正常情况叫做异常 * * 注意: * 1、相同的代码在运行的时候,根据输入的参数或者操作的不同,有可能会发生异常,有可能不会发生异常 * 应该在写代码的过程中尽可能的保证代码的正确性,不要到处都bug * 2、如果要解决代码中出现的异常,需要添加非常复杂的代码逻辑来进行判断,会使代码变得非常臃肿,不利于维护,可读性比较差 * 因此,推荐大家使用异常机制来处理程序运行过程中出现的问题 * 3、程序在运行过程中如果出现了问题,会导致后面的代码无法正常执行,而使用异常机制之后,可以对异常情况进行处理 * 同时后续的代码会继续执行,不会中断整个程序 * 4、在异常的处理过程中,不要只是简单的输出错误,要尽可能的讲详细的异常信息进行输出 * e.printStackTrace():打印异常的堆栈信息,可以从异常信息的最后一行开始追踪,寻找自己编写的java类 * * 异常处理的方式: * 1、捕获异常 * try{代码逻辑}catch(Exception e){异常处理逻辑} * try{代码逻辑}catch(具体的异常Exception e){异常处理逻辑}catch(具体的异常): * 可以针对每一种具体的异常做相应的更丰富的处理 * 注意:当使用多重的catch的时候一定要注意相关异常的顺序,将子类放在最前面的catch,父类放在后面的catch * 执行过程中可能存在的情况: * 1、正常执行,只执行try中的代码 * 2、遇到异常情况,会处理try中异常代码之前的逻辑,后面的逻辑不会执行,最后会执行catch中的代码 * 3、使用多重catch的时候,会遇到异常子类不匹配的情况,此时依然会报错,因此建议在catch的最后将所有的异常的父类写上 *InputMismatchException * ArithmeticException * */ public class TestException { public static void main(String[] args) { Scanner in = new Scanner(System.in); try { System.out.print("请输入被除数:"); int num1 = in.nextInt(); System.out.print("请输入除数:"); int num2 = in.nextInt(); System.out.println(String.format("%d / %d = %d", num1, num2, num1 / num2)); System.out.println("前面没有出现异常"); /*}catch(Exception e){ // System.out.println("出现异常"); e.printStackTrace(); // System.out.println("--------"); System.out.println(e.getMessage()); }*/ }catch(ArithmeticException e){ System.out.println("数学异常,除数不能是0"); e.printStackTrace(); }catch (InputMismatchException e){ System.out.println("输入的参数值类型不匹配"); e.printStackTrace(); }catch (NullPointerException e){ System.out.println("空指针异常"); e.printStackTrace(); } System.out.println("感谢使用本程序!"); } }
finally
/* * 在程序运行过程中,如果处理异常的部分包含finally的处理,那么无论代码是否发生异常,finally中的代码总会执行 * finally包含哪些处理逻辑? * 1、IO流的关闭操作一般设置在finally中 * 2、数据库的连接关闭操作设置在finally中 * * */ public class FinallyDemo { public static void main(String[] args) { } public static void test(){ try{ System.out.println(1/10); return; }catch (Exception e){ e.printStackTrace(); return; }finally { System.out.println("我是finally处理块"); return; } } }
try_catch_finally_return(点我)
throw / throws
/* throws:声明异常 * 在异常情况出现的时候,可以使用try...catch...finally的方式对异常进行处理,除此之外,可以将异常向外跑出,由外部的进行处理 * 1、在方法调用过程中,可以存在N多个方法之间的调用,此时假如每个方法中都包含了异常情况 * 那么就需要在每个方法中都进行try。。catch,另外一种比较简单的方式,就是在方法的最外层调用处理一次即可 * 使用throws的方法,对所有执行过程中的所有方法出现的异常进行统一集中处理 * 2、如何判断是使用throws还是使用try...catch.. * 最稳妥的方式是在每个方法中都进行异常的处理 * 偷懒的方式是判断在整个调用的过程中,外层的调用方法是否有对异常的处理,如果有,直接使用throws,如果没有 * 那么就要使用try...catch... * throw:抛出异常 * * */ public class Excepton2 { public static void main(String[] args) { try { show(); } catch (GenderException e) { e.printStackTrace(); } // new FileInputStream(new File("")); System.out.println("hehe"); } public static void show() throws GenderException{ String gender = "1234"; if (gender.equals("man")){ System.out.println("man"); }else if(gender.equals("woman")){ System.out.println("woman"); }else{ // throw new Exception("性别出现错误"); throw new GenderException("gender is wrong"); } } public static void test1() throws Exception{ System.out.println(1/0); } public static void test2() throws Exception { test1(); System.out.println(100/0); } public static void test3() throws Exception{ test2(); } public static void test4() throws Exception{ test3(); } }
自定义异常
/* * 自定义异常: * 在java的api中提供了非常丰富的异常类,但是在某些情况下不太满足我们的需求,此时需要自定义异常 * 步骤: * 1、继承Exception类 * 2、自定义实现构造方法 * 3、需要使用的时候,使用throw new 自定义异常的名称; * 什么时候需要自定义异常? * 一般情况下不需要 * 但是在公司要求明确,或者要求异常格式规范统一的时候是必须要自己实现的 * * */ public class GenderException extends Exception { public GenderException(){ System.out.println("性别异常"); } public GenderException(String msg){ System.out.println(msg); } }
十一、常用类及包装类与基本数据类型
自动拆装箱
/* * 包装类与基本数据类型 * 包装类是将基本数据类型封装成一个类,包含属性和方法 * 使用: * 在使用过程中,会涉及到自动装箱和自动拆箱 * 装箱:将基本数据类型转换成包装类 * 拆箱:将包装类转换成基本数据类型 * * * * * */ public class IntegerDemo { public static void main(String[] args) { // int a = 10; // Integer i = new Integer(10); // //通过方法进行类型的转换 // Integer i2 = Integer.valueOf(a); // int i3 = i.intValue(); // System.out.println(a == i); // Float f1 = new Float(3.14); // Double d1 = new Double(3.14); // int i =100; // Integer i1 = 100; // Integer i2 = 100; // Integer i3 = 200; // Integer i4 = 200; // System.out.println(i1==i2);//true // System.out.println(i3==i4);//false // Double d1 = 1.0; // Double d2 = 1.0; // Double d3 = 2.0; // Double d4 = 2.0; // System.out.println(d1==d2);//false // System.out.println(d3==d4);//false Integer i = 10; int a = i; System.out.println(a==i);//true } }
String
/* * 注意:常量池在1.7之后放置在了堆空间之中 * 字符串的使用: * 1、创建 * String str = "abc"; * String str2 = new String("abc"); * 两种方式都可以用,只不过第一种使用比较多 * 2、字符串的本质 * 字符串的本质是字符数组或者叫做字符序列 * String类使用final修饰,不可以被继承 * 使用equals方法比较的是字符数组的每一个位置的值 * String是一个不可变对象 * * */ public class StringDemo { public static void main(String[] args) { String str = "abc"; String str2 = new String("abc"); // str2 = str2.intern(); System.out.println(str==str2); System.out.println(str.equals(str2)); System.out.println(str.charAt(0)); //数组的复制过程 System.out.println(str.concat("cde")); //返回指定下标的元素 System.out.println(str.indexOf("a")); String s = "abcdefghijklmn"; System.out.println(s.substring(3)); //在截取字符串的时候,需要注意是左闭右开区间 System.out.println(s.substring(3,5)); System.out.println(s.length()); System.out.println("-----------------"); // String a = "abc"; // String b = new String("abc"); // b = b.intern(); // System.out.println(a==b); String a = "abc"; String b = "def"; String c = "abcdef"; String d = (a+b).intern(); String e = "abc"+"def"; System.out.println(c==d); System.out.println(c==e); String f = "a" + "b" +"c"; String a1 = "a"; String a2 = "b"; String a3 = "c"; String f1 = a1+a2+a3; } }
StringBuffer
/* * 可变字符串 * StringBuffer:线程安全,效率低 * StringBuilder: 线程不安全,效率高 * * * */ public class StringBufferDemo { public static void main(String[] args) { StringBuffer stringBuffer = new StringBuffer(); stringBuffer.append(1).append(1.234).append("abc").append(true); System.out.println(stringBuffer); System.out.println(stringBuffer.length()); System.out.println(stringBuffer.capacity()); StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append("123").append(1).append(false); System.out.println(stringBuilder); } }
Date与Calendar
public class DateDemo { public static void main(String[] args) throws ParseException { Date date = new Date(); System.out.println(date); System.out.println(date.getTime()); DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); //将Date类按照规范转换为字符串格式 String str = dateFormat.format(date); System.out.println(str); //将字符串转换成对应的日期类 Date d1 = dateFormat.parse("2010-10-10 20:20:20"); System.out.println(d1); //获取的是当前系统的时间 Calendar calendar = Calendar.getInstance(); System.out.println(calendar); //设置指定时间的日历类 calendar.setTime(d1); System.out.println(calendar); System.out.println(calendar.get(Calendar.YEAR)); System.out.println(calendar.get(Calendar.MONTH)); System.out.println(calendar.get(Calendar.DAY_OF_MONTH)); System.out.println(calendar.get(Calendar.HOUR_OF_DAY)); System.out.println(calendar.get(Calendar.MINUTE)); System.out.println(calendar.get(Calendar.SECOND)); } }
Math
public class MathDemo { public static void main(String[] args) { System.out.println(Math.abs(-1)); System.out.println(Math.sqrt(2)); System.out.println(Math.ceil(-3.14)); System.out.println(Math.floor(-3.14)); System.out.println(Math.pow(2,3)); } }
枚举
/* 枚举类型: 1.只能够取特定值中的一个 2.使用enum关键字 3.所有的枚举类型隐性地继承java.lang.Enum。(枚举实质上还是类! 而每个被枚举的成员实质就是一个枚举类型的实例,他们默认都是public static final的。可以直接通过枚举类型名直接使用他们。) 4.强烈建议你需要定义一组常量时,使用枚举类型 */ public enum EventEnum { LAUNCH("launch"),PAGEVIEW("pageview"),EVENT("event"); EventEnum(String name){ this.name = name; } private String name; public void show(){ System.out.println(this.name); EventEnum[] ee = values(); for(int i = 0;i<ee.length;i++){ System.out.println(ee[i]); } } }
public class Test { Gender gender = Gender.女; Gender gender2 = Gender.男; public static void main(String[] args) { EventEnum ee = EventEnum.LAUNCH; ee.show(); String name = EventEnum.PAGEVIEW.name(); System.out.println(name); } }
十二、Java容器(集合1)
Collection
/* * java集合框架: * Collection:存放的是单一值 * 特点: * 1、可以存放不同类型的数据,而数组只能存放固定类型的数据 * 2、当使用arraylist子类实现的时候,初始化的长度是10,当长度不够的时候会自动进行扩容操作 * api方法: * 增加数据的方法 * add:要求必须传入的参数是Object对象,因此当写入基本数据类型的时候,包含了自动拆箱和自动装箱的过程 * addAll:添加另一个集合的元素到此集合中 * * 删除数据的方法 * clear:只是清空集合中的元素,但是此集合对象并没有被回收 * remove:删除指定元素 * removeAll:删除集合元素 * * 查询数据的方法 * contains:判断集合中是否包含指定的元素值 * containsAll:判断此集合中是否包含另一个集合 * isEmpty:判断集合是否等于空 * retainAll:若集合中拥有另一个集合的所有元素,返回true,否则返回false * size:返回当前集合的大小 * * //集合转数组的操作 * toArray:将集合转换成数组 * */ public class CollectionDemo { public static void main(String[] args) { Collection collection = new ArrayList(); collection.add(1); collection.add(true); collection.add(1.23); collection.add("abc"); System.out.println(collection); ((ArrayList) collection).add(0,"mashibing"); System.out.println(collection); Collection collection1 = new ArrayList(); collection1.add("a"); collection1.add("b"); collection1.add("c"); collection1.add("d"); collection.addAll(collection1); System.out.println(collection); // collection.clear(); // System.out.println(collection); System.out.println(collection.contains("a")); System.out.println(collection.containsAll(collection1)); System.out.println(collection.isEmpty()); // collection.remove("a"); // System.out.println(collection); System.out.println(collection1.retainAll(collection)); Object[] objects = collection.toArray(); collection.add("a"); System.out.println(collection); } }
List
/* * java集合框架: * List:存放的是单一值 * 特点: * 1、可以存放不同类型的数据,而数组只能存放固定类型的数据 * 2、当使用arraylist子类实现的时候,初始化的长度是10,当长度不够的时候会自动进行扩容操作 * api方法: * 增加数据的方法 * add:要求必须传入的参数是Object对象,因此当写入基本数据类型的时候,包含了自动拆箱和自动装箱的过程 * addAll:添加另一个集合的元素到此集合中 * * 删除数据的方法 * clear:只是清空集合中的元素,但是此集合对象并没有被回收 * remove:删除指定元素 * removeAll:删除集合元素 * * 查询数据的方法 * contains:判断集合中是否包含指定的元素值 * containsAll:判断此集合中是否包含另一个集合 * isEmpty:判断集合是否等于空 * retainAll:若集合中拥有另一个集合的所有元素,返回true,否则返回false * size:返回当前集合的大小 * * //集合转数组的操作 * toArray:将集合转换成数组 * */ public class ListDemo { public static void main(String[] args) { List list = new ArrayList(); list.add("a"); list.add(1); list.add("a"); list.add(true); System.out.println(list); // System.out.println(list.get(3)); System.out.println(list.indexOf("a")); System.out.println(list.lastIndexOf("a")); list.set(0,"mashibing"); System.out.println(list); List list1 = list.subList(0, 2); System.out.println(list1); // List of = List.of(1,2,3,4); // System.out.println(of); } }
LinkedList
/** * @author: 马士兵教育 * @create: 2019-09-08 15:18 */ /* * linkedList拥有更加丰富的方法实,需要用的时候查询api即可,不需要记忆 * * */ public class LinkedListDemo { public static void main(String[] args) { LinkedList linkedList = new LinkedList(); linkedList.add(123); linkedList.add(false); linkedList.add("abc"); System.out.println(linkedList); linkedList.add(2,"mashibing"); System.out.println(linkedList); linkedList.addFirst("1111"); System.out.println(linkedList); linkedList.addLast("2222"); System.out.println(linkedList); System.out.println(linkedList.element()); linkedList.offer("3333"); System.out.println(linkedList); } }
Vector
/** * @author: 马士兵教育 * @create: 2019-09-08 15:34 */ /** * 1、Vector也是List接口的一个子类实现 * 2、Vector跟ArrayList一样,底层都是使用数组进行实现的 * 3、面试经常问区别: * (1)ArrayList是线程不安全的,效率高,Vector是线程安全的效率低 * (2)ArrayList在进行扩容的时候,是扩容1.5倍,Vector扩容的时候扩容原来的2倍 * * */ public class VectorDemo { public static void main(String[] args) { Vector vector = new Vector(); vector.add(1); vector.add("abc"); System.out.println(vector); } }
Iterator(ListIterator与Lterator区别)(点我)
/* * 在java代码中包含三种循环的方式 * do...while * while * for * 还有一种增强for循环的方式,可以简化循环的编写 * * * 所有的集合类都默认实现了Iterable的接口,实现此接口意味着具备了增强for循环的能力,也就是for-each * 增强for循环本质上使用的也是iterator的功能 * 方法: * iterator() * foreach() * 在iterator的方法中,要求返回一个Iterator的接口子类实例对象 * 此接口中包含了 * hasNext() * next() * * 在使用iterator进行迭代的过程中如果删除其中的某个元素会报错,并发操作异常,因此 * 如果遍历的同时需要修改元素,建议使用listIterator(), * ListIterator迭代器提供了向前和向后两种遍历的方式 * 始终是通过cursor和lastret的指针来获取元素值及向下的遍历索引 * 当使用向前遍历的时候必须要保证指针在迭代器的结果,否则无法获取结果值 * */ public class IteratorDemo { public static void main(String[] args) { ArrayList list= new ArrayList(); list.add(1); list.add(2); list.add(3); list.add(4); // for(int i=0;i<list.size();i++){ // System.out.println(list.get(i)); // } //迭代器 // Iterator iterator = list.iterator(); ListIterator iterator = list.listIterator(); while(iterator.hasNext()){ Object o = iterator.next(); if(o.equals(1)){ iterator.remove(); } System.out.println(o); } System.out.println("-------------"); while (iterator.hasPrevious()){ System.out.println(iterator.previous()); } // for(Object i : list){ // System.out.println(i); // } } }
Set / Treeset
/* * 1、set中存放的是无序,唯一的数据 * 2、set不可以通过下标获取对应位置的元素的值,因为无序的特点 * 3、使用treeset底层的实现是treemap,利用红黑树来进行实现 * 4、设置元素的时候,如果是自定义对象,会查找对象中的equals和hashcode的方法,如果没有,比较的是地址 * 5、树中的元素是要默认进行排序操作的,如果是基本数据类型,自动比较,如果是引用类型的话,需要自定义比较器 * 比较器分类: * 内部比较器 * 定义在元素的类中,通过实现comparable接口来进行实现 * 外部比较器 * 定义在当前类中,通过实现comparator接口来实现,但是要将该比较器传递到集合中 * 注意:外部比较器可以定义成一个工具类,此时所有需要比较的规则如果一致的话,可以复用,而 * 内部比较器只有在存储当前对象的时候才可以使用 * 如果两者同时存在,使用外部比较器 * 当使用比较器的时候,不会调用equals方法 * */ public class SetDemo implements Comparator<Person> { public static void main(String[] args) { // Set set = new HashSet(); // set.add("123"); // set.add(1); // set.add(true); // set.add("123"); // System.out.println(set); // Iterator iterator = set.iterator(); // while (iterator.hasNext()){ // System.out.println(iterator.next()); // } // System.out.println("---------"); // //将while循环改成for循环,推荐使用 // for(Iterator iter = set.iterator(); iter.hasNext();){ // System.out.println(iter.next()); // } // TreeSet treeSet = new TreeSet(); // treeSet.add(34); // treeSet.add(1); // treeSet.add(65); // System.out.println(treeSet.ceiling(1)); // System.out.println(treeSet); // HashSet hashSet = new HashSet(); // hashSet.add(new Person("zhangsan",12)); // hashSet.add(new Person("zhangsan",12)); // hashSet.add(new Person("lisi",13)); // System.out.println(hashSet); TreeSet treeSet = new TreeSet(new SetDemo()); treeSet.add(new Person("lisi",15)); treeSet.add(new Person("wangwu",13)); treeSet.add(new Person("maliu",12)); treeSet.add(new Person("zhangsan",19)); treeSet.add(new Person("zhangsan",12)); System.out.println(treeSet); } @Override public int compare(Person o1, Person o2) { if(o1.getAge()>o2.getAge()){ return -1; }else if(o1.getAge() < o2.getAge()){ return 1; }else{ return 0; } } }
Map
/** * map存储的是k-v键值对映射的数据 * 实现子类: * HashMap:数据+链表(1.7) 数组+链表+红黑树(1.8) * LinkedHashMap:链表 * TreeMap:红黑树 * * 基本api操作: * 增加: * put(k,v) 添加元素 * 查找: * isEmpty 判断是否为空 * size 返回map的大小 * containsKey * containsValue * get * 删除: * clear 清空集合中的所有元素 * remove:删除指定元素 * Map.entry:表示的是K-V组合的一组映射关系,key和value成组出现 * * hashmap跟hashtable的区别: * 1、hashmap线程不安全,效率比较高,hashtable线程安全,效率低 * 2、hashmap中key和value都可以为空,hashtable不允许为空 * * * hashmap初始值为2的N次幂, * 1、方便进行&操作,提高效率,&要比取模运算效率要高 * hash & (initCapacity-1) * 2、在扩容之后涉及到元素的迁移过程,迁移的时候只需要判断二进制的前一位是0或者是1即可 * 如果是0,表示新数组和就数组的下标位置不变,如果是1,只需要将索引位置加上旧的数组的长度值即为新数组的下标 * 1.7源码知识点: 数组+链表 * 1、默认初始容量 * 2、加载因子 * 3、put操作 * 1、设置值,计算hash * 2、扩容操作 * 3、数据迁移的过程 * 1.8源码知识点: 数组+链表+红黑树 */ public class MapDemo { public static void main(String[] args) { Map<String,Integer> map = new HashMap<String,Integer>(13); map.put("a",1); map.put("b",2); map.put("c",3); map.put("d",4); map.put(null,null); System.out.println(map); System.out.println(map.isEmpty()); System.out.println(map.size()); // map.clear(); System.out.println(map.containsKey("a")); System.out.println(map.containsValue(2)); System.out.println(map.get("a")); map.remove("a"); System.out.println(map); //遍历操作 Set<String> keys = map.keySet(); for(String key:keys){ System.out.println(key+"="+map.get(key)); } //只能获取对应的value值,不能根据value来获取key Collection<Integer> values = map.values(); for (Integer i:values){ System.out.println(i); } //迭代器 Set<String> keys2 = map.keySet(); Iterator<String> iterator = keys2.iterator(); while(iterator.hasNext()){ String key = iterator.next(); System.out.println(key+"="+map.get(key)); } //Map.entry Set<Map.Entry<String, Integer>> entries = map.entrySet(); Iterator<Map.Entry<String, Integer>> iterator1 = entries.iterator(); while (iterator1.hasNext()){ Map.Entry<String, Integer> next = iterator1.next(); System.out.println(next.getKey()+"--"+next.getValue()); } } }
十三、泛型
/** * 当做一些集合的统一操作的时候,需要保证集合的类型是统一的,此时需要泛型来进行限制 * 优点: * 1、数据安全 * 2、获取数据时效率比较高 * 给集合中的元素设置相同的类型就是泛型的基本需求 * 使用: * 在定义对象的时候,通过<>中设置合理的类型来进行实现 * 泛型的高阶应用: * 1、泛型类 * 在定义类的时候在类名的后面添加<E,K,V,A,B>,起到占位的作用,类中的方法的返回值类型和属性的类型都可以使用 * 2、泛型接口 * 在定义接口的时候,在接口的名称后添加<E,K,V,A,B>, * 1、子类在进行实现的时候,可以不填写泛型的类型,此时在创建 * 具体的子类对象的时候才决定使用什么类型 * 2、子类在实现泛型接口的时候,只在实现父类的接口的时候指定 * 父类的泛型类型即可, * 此时,测试方法中的泛型类型必须要跟子类保持一致 * 3、泛型方法 * 在定义方法的时候,指定方法的返回值和参数是自定义的占位符, * 可以是类名中的T,也可以是自定义的Q, * 只不过在使用Q的时候需要使用<Q>定义在返回值的前面 * 4、泛型的上限(工作中不用) * 如果父类确定了,所有的子类都可以直接使用 * 5、泛型的下限(工作中不用) * 如果子类确定了,子类的所有父类都可以直接传递参数使用 * * */ public class FanXingDemo { public static void main(String[] args) { // List<String> list = new ArrayList<String>(); // list.add("1"); // new Integer(1) // list.add("abc");//new String("abc) // list.add("true");//new Boolean(true) // list.add(new Person("zhangsan",12).toString()); // System.out.println(list); // // for(int i = 0;i<list.size();i++){ // System.out.println(list.get(i)); // } // // for(String iter:list){ // System.out.println(iter); // } // FanXingClass<String> fxc = new FanXingClass<String>(); // fxc.setA("mashibing"); // fxc.setId(1); // fxc.show(); // // FanXingClass<Integer> fxc2 = new FanXingClass<Integer>(); // fxc2.setA(34); // fxc2.setId(2); // fxc2.show(); // // FanXingClass<Person> fxc3 = new FanXingClass<Person>(); // fxc3.setA(new Person("aaa",123)); // fxc3.setId(3); // fxc3.show(); // System.out.println(fxc3.get()); // fxc3.set(new Person("hhe",123)); // FanXingInterfaceSub fxi = new FanXingInterfaceSub() ; // fxi.test2("123"); FanXingMethod<String> fxm = new FanXingMethod<>(); fxm.setT("ttt"); fxm.show(123); fxm.show(true); } }
public class FanXingClass<A> { private int id; private A a; public int getId() { return id; } public void setId(int id) { this.id = id; } public A getA() { return a; } public void setA(A a) { this.a = a; } public void show(){ System.out.println("id : "+id+" ,A : "+a); } public A get(){ return a; } public void set(A a){ System.out.println("执行set方法:" + a); } }
public interface FanXingInterface<B> { public B test(); public void test2(B b); }
public class FanXingInterfaceSub implements FanXingInterface<String> { @Override public String test() { return null; } @Override public void test2(String string) { } }
public class FanXingMethod<T> { private T t; public T getT() { return t; } public void setT(T t) { this.t = t; } public <Q> void show(Q q){ System.out.println(q); System.out.println(t); } }
十四、IO
File
import java.io.File; import java.io.IOException; /** * File提供了对当前文件系统中文件的部分操作 * * */ public class FileDemo { public static void main(String[] args) throws IOException { File file = new File("src/abc.txt"); //创建文件 try { file.createNewFile(); } catch (IOException e) { e.printStackTrace(); } //判断文件的属性,都会返回boolean类型的值 file.canExecute(); file.canRead(); file.canWrite(); //判断当前文件是否存在 System.out.println(file.exists()); //获取文件的名称 System.out.println(file.getName()); //获取文件的绝对路径 System.out.println(file.getAbsolutePath()); //获取文件的父路径名称,如果文件的路径中只包含文件名称,则显示空 System.out.println(file.getParent()); //返回文件绝对路径的规范格式 System.out.println(file.getCanonicalPath()); //返回操作系统的文件分割符 System.out.println(File.separator); //无论当前文件是否存在,只要给定具体的路径,都可以返回相应的路径名称 File file2 = new File("c:/a/b/c"); System.out.println(file2.getAbsolutePath()); //判断文件是否是文件或者目录 System.out.println(file2.isDirectory()); System.out.println(file2.isFile()); // String[] list = file2.list(); // for(String str:list){ // System.out.println(list.toString()); // } // System.out.println("---------------"); // File[] files = file2.listFiles(); // for(File f : files){ // System.out.println(f); // } //打印当前文件系统的所有盘符 File[] files1 = File.listRoots(); for(int i = 0;i<files1.length;i++){ System.out.println(files1[i]); } //创建单级目录 file2.mkdir(); //创建多级目录 file2.mkdirs(); //循环遍历输出C盘中的所有文件的绝对路径 //使用递归的方式 printFile(new File("D:\\Github\\javase")); } /** * * 文件在遍历的时候,会出现空指针的问题,原因在于当前文件系统受保护,某些文件没有访问权限,此时会报空指针异常 * @param file */ public static void printFile(File file){ if(file.isDirectory()){ File[] files = file.listFiles(); for(File f:files){ printFile(f); } }else{ System.out.println(file.getAbsolutePath()); } } }
字节流 Stream
/** * 在java中需要读写文件中的数据的话,需要使用流的概念 * 流表示从一个文件将数据返送到另一个文件,包含一个流向的问题 * 最终需要选择一个参照物:当前程序作为参照物 * 从一个文件中读取数据到程序叫做输入流 * 从程序输出数据到另一个文件叫做输出流 * * 注意:当编写io流的程序的时候一定要注意关闭流 * 步骤; * 1、选择合适的io流对象 * 2、创建对象 * 3、传输数据 * 4、关闭流对象(占用系统资源) */ public class InputStreamDemo { public static void main(String[] args) { InputStream inputStream = null; try { inputStream = new FileInputStream("abc.txt"); int read = inputStream.read(); System.out.println((char)read); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }finally { try { inputStream.close(); } catch (IOException e) { e.printStackTrace(); } } } }
/** * 将abc.txt中的数据写入到aaa.txt中 * 文件复制的过程 * * */ public class OutputStreamDemo { public static void main(String[] args) { File file = new File("aaa.txt"); OutputStream outputStream = null; try { outputStream = new FileOutputStream(file); outputStream.write(99); outputStream.write("\r\nmashibing".getBytes()); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }finally { try { outputStream.close(); } catch (IOException e) { e.printStackTrace(); } } } }
/* * 存在问题,每次只能读取一个字节,效率比较低,需要循环N多次 * */ public class StreamDemo2 { public static void main(String[] args) { InputStream inputStream = null; try { inputStream = new FileInputStream("abc.txt"); int read = 0; //循环输出所有的字节, while((read = inputStream.read())!=-1){ System.out.println((char)read); } // int read = inputStream.read(); // System.out.println((char)read); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }finally { try { inputStream.close(); } catch (IOException e) { e.printStackTrace(); } } } }
/** * 在java中需要读写文件中的数据的话,需要使用流的概念 * 流表示从一个文件将数据返送到另一个文件,包含一个流向的问题 * 最终需要选择一个参照物:当前程序作为参照物 * 从一个文件中读取数据到程序叫做输入流 * 从程序输出数据到另一个文件叫做输出流 * * 注意:当编写io流的程序的时候一定要注意关闭流 * 步骤; * 1、选择合适的io流对象 * 2、创建对象 * 3、传输数据 * 4、关闭流对象(占用系统资源) */ public class StreamDemo3 { public static void main(String[] args) { InputStream inputStream = null; try { inputStream = new FileInputStream("abc.txt"); int length = 0; //添加缓冲区的方式进行读取,每次会将数据添加到缓冲区中,当缓冲区满了之后,一次 读取,而不是每一个字节进行读取 byte[] buffer = new byte[1024]; while((length = inputStream.read(buffer))!=-1){ System.out.println(new String(buffer,0,length)); } // int read = inputStream.read(); // System.out.println((char)read); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }finally { try { inputStream.close(); } catch (IOException e) { e.printStackTrace(); } } } }
public class StreamDemo4 { public static void main(String[] args) { InputStream inputStream = null; try { inputStream = new FileInputStream("abc.txt"); int length = 0; //添加缓冲区的方式进行读取,每次会将数据添加到缓冲区中,当缓冲区满了之后,一次 读取,而不是每一个字节进行读取 byte[] buffer = new byte[1024]; while((length = inputStream.read(buffer,5,5))!=-1){ System.out.println(new String(buffer,5,length)); } // int read = inputStream.read(); // System.out.println((char)read); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }finally { try { inputStream.close(); } catch (IOException e) { e.printStackTrace(); } } } }
public class CopyFile { public static void main(String[] args) { //定义源数据文件 File src = new File("abc.txt"); //定义目的数据文件 File dest = new File("aaa.txt"); //创建输入流对象 InputStream inputStream = null; //创建输出流对象 OutputStream outputStream = null; try { inputStream = new FileInputStream(src); outputStream = new FileOutputStream(dest); //带缓存的输入输出方式 byte[] buffer = new byte[1024]; int length = 0; //完成数据传输的过程 while((length = inputStream.read(buffer))!=-1){ outputStream.write(buffer); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }finally { try { outputStream.close(); } catch (IOException e) { e.printStackTrace(); } try { inputStream.close(); } catch (IOException e) { e.printStackTrace(); } } } }
public class BufferedInputStreamDemo { public static void main(String[] args) { File file = new File("abc.txt"); FileInputStream fileInputStream = null; BufferedInputStream bufferedInputStream = null; try { fileInputStream = new FileInputStream(file); bufferedInputStream = new BufferedInputStream(fileInputStream); int read = 0; while((read = bufferedInputStream.read())!=-1){ bufferedInputStream.skip(10); System.out.print((char)read); } ; } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }finally { try { bufferedInputStream.close(); } catch (IOException e) { e.printStackTrace(); } try { fileInputStream.close(); } catch (IOException e) { e.printStackTrace(); } } } }
public class BufferedOutputStreamDemo { public static void main(String[] args) { File file = new File("123.txt"); FileOutputStream fileOutputStream = null; BufferedOutputStream bufferedOutputStream =null; try { fileOutputStream = new FileOutputStream(file); bufferedOutputStream = new BufferedOutputStream(fileOutputStream); bufferedOutputStream.write(98); bufferedOutputStream.write("www.baidu.com".getBytes()); } catch (IOException e) { e.printStackTrace(); }finally { try { bufferedOutputStream.close(); } catch (IOException e) { e.printStackTrace(); } try { fileOutputStream.close(); } catch (IOException e) { e.printStackTrace(); } } } }
字符流
/** * 字符流可以直接读取中文汉字,而字节流在处理的时候会出现中文乱码 */ public class ReaderDemo { public static void main(String[] args) { Reader reader = null; try { reader = new FileReader("abc.txt"); int read = reader.read(); System.out.println((char)read); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }finally { try { reader.close(); } catch (IOException e) { e.printStackTrace(); } } } }
/** * 字符流可以直接读取中文汉字,而字节流在处理的时候会出现中文乱码 */ public class ReaderDemo2 { public static void main(String[] args) { Reader reader = null; try { reader = new FileReader("abc.txt"); int read = 0; while((read = reader.read())!=-1){ System.out.println((char)read); } // int read = reader.read(); // System.out.println((char)read); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }finally { try { reader.close(); } catch (IOException e) { e.printStackTrace(); } } } }
/** * 字符流可以直接读取中文汉字,而字节流在处理的时候会出现中文乱码 */ public class ReaderDemo3 { public static void main(String[] args) { Reader reader = null; try { reader = new FileReader("abc.txt"); int length = 0; char[] chars = new char[1024]; //添加缓冲区 while((length = reader.read(chars))!=-1){ System.out.println(new String(chars,0,length)); } // int read = reader.read(); // System.out.println((char)read); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }finally { try { reader.close(); } catch (IOException e) { e.printStackTrace(); } } } }
/* * 什么时候需要加flush,什么时候不加flush * 最保险的方式,在输出流关闭之前每次都flush一下,然后再关闭 * 当某一个输出流对象中带有缓冲区的时候,就需要进行flush,不建议大家去记住每个输出流的分类 * * */ public class WriterDemo { public static void main(String[] args) { File file = new File("writer.txt"); Writer writer = null; try { writer = new FileWriter(file); writer.write("www.mashibing.com"); writer.write("马士兵教育"); writer.flush(); } catch (IOException e) { e.printStackTrace(); }finally { try { writer.close(); } catch (IOException e) { e.printStackTrace(); } } } }
public class BufferedReaderTest { public static void main(String[] args) { BufferedReader reader = null; try { reader = new BufferedReader(new FileReader("aaa.txt")); String read = null; while((read = reader.readLine())!=null){ System.out.println(read); }; } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }finally { try { reader.close(); } catch (IOException e) { e.printStackTrace(); } } } }
public class BufferedWriterTest { public static void main(String[] args) { BufferedWriter bufferedWriter = null; FileWriter fileWriter = null; try { fileWriter = new FileWriter(new File("abc.txt")); bufferedWriter = new BufferedWriter(fileWriter); bufferedWriter.append("mashibing"); bufferedWriter.newLine(); bufferedWriter.append("马士兵教育"); bufferedWriter.flush(); } catch (IOException e) { e.printStackTrace(); }finally { try { fileWriter.close(); } catch (IOException e) { e.printStackTrace(); } try { bufferedWriter.close(); } catch (IOException e) { e.printStackTrace(); } } } }
这里有一个万能的文件复制代码(不用此法复制的时候,成功复制的文件大小不一样,请点击我!)
public class CopyFile { public static void main(String[] args) { try(FileInputStream fileInputStream = new FileInputStream("E:\\88.docx"); FileOutputStream fileOutputStream = new FileOutputStream("E:\\55.docx"); BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream); BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(fileOutputStream); ) { byte[] buffer = new byte[1024]; int read = 0; while((read = bufferedInputStream.read(buffer))!=-1){ bufferedOutputStream.write(buffer,0,read); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } }
十五、线程
/** * 实现多线程的时候: * 1、需要继承Thread类 * 2、必须要重写run方法,指的是核心执行的逻辑 * 3、线程在启动的时候,不要直接调用run方法,而是要通过start()来进行调用 * 4、每次运行相同的代码,出来的结果可能不一样,原因在于多线程谁先抢占资源无法进行人为控制 * 第二种实现方式:使用了代理设计模式 * 1、实现Runnable接口 * 2、重写run方法 * 3、创建Thread对象,将刚刚创建好的runnable的子类实现作为thread的构造参数 * 4、通过thread.start()进行启动 * 两种实现方式哪种用的比较多 * 推荐使用第二种方式, * 1、java是单继承,将继承关系留给最需要的类 * 2、使用runnable接口之后不需要给共享变量添加static关键字,每次创建一个对象,作为共享对象即可 * 线程的生命周期: * 1、新生状态: * 当创建好当前线程对象之后,没有启动之前(调用start方法之前) * ThreadDemo thread = new ThreadDemo() * RunnableDemo run = new RunnableDemo() * 2、就绪状态:准备开始执行,并没有执行,表示调用start方法之后 * 当对应的线程创建完成,且调用start方法之后,所有的线程会添加到一个就绪队列中,所有的线程同时去抢占cpu的资源 * 3、运行状态:当当前进程获取到cpu资源之后,就绪队列中的所有线程会去抢占cpu的资源,谁先抢占到谁先执行,在执行的过程中就叫做运行状态 * 抢占到cpu资源,执行代码逻辑开始 * 4、死亡状态:当运行中的线程正常执行完所有的代码逻辑或者因为异常情况导致程序结束叫做死亡状态 * 进入的方式: * 1、正常运行完成且结束 * 2、人为中断执行,比如使用stop方法 * 3、程序抛出未捕获的异常 * 5、阻塞状态:在程序运行过程中,发生某些异常情况,导致当前线程无法再顺利执行下去,此时会进入阻塞状态,进入阻塞状态的原因消除之后, * 所有的阻塞队列会再次进入到就绪状态中,随机抢占cpu的资源,等待执行 * 进入的方式: * sleep方法 * 等待io资源 * join方法(代码中执行的逻辑) * * 注意: * 在多线程的时候,可以实现唤醒和等待的过程,但是唤醒和等待操作的对应不是thread类 * 而是我们设置的共享对象或者共享变量 * 多线程并发访问的时候回出现数据安全问题: * 解决方式: * 1、同步代码块 * synchronized(共享资源、共享对象,需要是object的子类){具体执行的代码块} * 2、同步方法 * 将核心的代码逻辑定义成一个方法,使用synchronized关键字进行修饰,此时不需要指定共享对象 * */ public class ThreadDemo extends Thread{ @Override public void run() { for(int i = 0;i<10;i++){ System.out.println(Thread.currentThread().getName()+"--------------"+i); } } public static void main(String[] args) { ThreadDemo threadDemo = new ThreadDemo(); threadDemo.start(); for(int i =0;i<5;i++){ System.out.println(Thread.currentThread().getName()+"==========="+i); } } }
api
/* * 介绍线程类api方法 * */ public class ThreadApiDemo implements Runnable{ public static void main(String[] args) { //获取当前线程对象 Thread thread = Thread.currentThread(); //获取当前线程的名称 System.out.println(thread.getName()); //获取线程的id System.out.println(thread.getId()); //获取线程的优先级,在一般系统中范围是0-10的值,如果没有经过设置的话,就是默认值5,有些系统是0-100 System.out.println(thread.getPriority()); //设置线程池的优先级 /* * 优先级越高一定越先执行吗? * 不一定,只是优先执行的概率比较大而已 * */ thread.setPriority(6); System.out.println(thread.getPriority()); ThreadApiDemo threadApiDemo = new ThreadApiDemo(); Thread t1 = new Thread(threadApiDemo); System.out.println(t1.isAlive()); t1.start(); System.out.println(t1.isAlive()); System.out.println(t1.getPriority()); // for(int i = 0;i<5;i++){ // System.out.println(Thread.currentThread().getName()+"-----"+i); // } System.out.println(t1.isAlive()); } @Override public void run() { // for(int i = 0;i<5;i++){ // System.out.println(Thread.currentThread().getName()+"-----"+i); // } } }
买票案例
/** * 此时出现的问题: * 1、每次在启动线程对象的时候都会创建自己对象的属性值,相当于每个线程操作自己,没有真正意义上实现贡献 * 解决方法:将共享对象,共享变量设置成static * 2、每次访问共享对象的时候,数据不一致了、 * 解决方法:使用线程同步 * * */ public class TicketThread extends Thread{ private static int ticket = 5; @Override public void run() { for(int i = 0;i<100;i++){ if (ticket > 0) { System.out.println(Thread.currentThread().getName() + "正在出售第" + (ticket--) + "张票"); } } } public static void main(String[] args) { TicketThread t1 = new TicketThread(); TicketThread t2 = new TicketThread(); TicketThread t3 = new TicketThread(); TicketThread t4 = new TicketThread(); t1.start(); t2.start(); t3.start(); t4.start(); } }
/** * 使用接口的方式,每次只创建了一个共享对象,所有的线程能够实现资源共享 * 1、数据不一致的问题 * 解决方法:线程同步 * */ public class TicketRunnable implements Runnable { private int ticket = 5; @Override public void run() { for (int i = 0; i < 100; i++) { if (ticket > 0) { System.out.println(Thread.currentThread().getName() + "正在出售第" + (ticket--) + "张票"); } } } public static void main(String[] args) { TicketRunnable ticket = new TicketRunnable(); Thread t1 = new Thread(ticket); Thread t2 = new Thread(ticket); Thread t3 = new Thread(ticket); Thread t4 = new Thread(ticket); t1.start(); t2.start(); t3.start(); t4.start(); } }
/** * 使用接口的方式,每次只创建了一个共享对象,所有的线程能够实现资源共享 * 1、数据不一致的问题 * 解决方法:线程同步 * */ public class TicketRunnable2 implements Runnable { private int ticket = 5; @Override public void run() { for (int i = 0; i < 100; i++) { // try { // Thread.sleep(200); // } catch (InterruptedException e) { // e.printStackTrace(); // } synchronized (this){ if (ticket > 0) { System.out.println(Thread.currentThread().getName() + "正在出售第" + (ticket--) + "张票"); } } } } public static void main(String[] args) { TicketRunnable2 ticket = new TicketRunnable2(); Thread t1 = new Thread(ticket,"A"); Thread t2 = new Thread(ticket,"B"); Thread t3 = new Thread(ticket,"C"); Thread t4 = new Thread(ticket,"D"); t1.start(); t2.start(); t3.start(); t4.start(); } }
/** * 使用接口的方式,每次只创建了一个共享对象,所有的线程能够实现资源共享 * 1、数据不一致的问题 * 解决方法:线程同步 */ public class TicketRunnable3 implements Runnable { private int ticket = 5; @Override public void run() { for (int i = 0; i < 100; i++) { try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } this.sale(); } } /* * 使用同步方法解决多线程数据安全的问题 * */ public synchronized void sale() { if (ticket > 0) { System.out.println(Thread.currentThread().getName() + "正在出售第" + (ticket--) + "张票"); } } public static void main(String[] args) { TicketRunnable3 ticket = new TicketRunnable3(); Thread t1 = new Thread(ticket, "A"); Thread t2 = new Thread(ticket, "B"); Thread t3 = new Thread(ticket, "C"); Thread t4 = new Thread(ticket, "D"); t1.start(); t2.start(); t3.start(); t4.start(); } }
两个线程交替输出数字
public class Test1 implements Runnable{ @Override public void run() { for(int i = 0;i<10;i++){ System.out.println(Thread.currentThread().getName()+"====="+i); try { Thread.sleep(1001); } catch (InterruptedException e) { e.printStackTrace(); } } } public static void main(String[] args) { Test1 test1 = new Test1(); Thread thread = new Thread(test1); thread.start(); for(int i=10;i>0;i--){ System.out.println(Thread.currentThread().getName()+"----"+i); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } }
生产者与消费者问题(1v1)
发现问题
/* * 多线程访问的时候出现了数据安全的问题 * 1、生产者没有生产商品,消费者就可以获取 * 2、商品的品牌和名称对应不上 * * */ public class Test { public static void main(String[] args) { Goods goods = new Goods(); Producer producer = new Producer(goods); Consumer consumer = new Consumer(goods); Thread t1 = new Thread(producer); Thread t2 = new Thread(consumer); t1.start(); t2.start(); }
/* * * 从共享空间中取走产品 * */ public class Consumer implements Runnable { private Goods goods; public Consumer(Goods goods) { this.goods = goods; } @Override public void run() { for(int i = 0;i<10;i++){ try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("消费者取走了"+this.goods.getBrand()+"----"+this.goods.getName()); } } }
public class Goods { private String brand; private String name; public String getBrand() { return brand; } public void setBrand(String brand) { this.brand = brand; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
/* * * 生产产品,将产房放置到共享空间中 * * */ public class Producer implements Runnable { private Goods goods; public Producer(Goods goods) { this.goods = goods; } @Override public void run() { for (int i = 0; i < 10; i++) { if (i % 2 == 0) { goods.setBrand("娃哈哈"); try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } goods.setName("矿泉水"); } else { goods.setBrand("旺仔"); try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } goods.setName("小馒头"); } System.out.println("生产者生产了" + this.goods.getBrand() + "--" + this.goods.getName()); } } }
解决问题方式1 (synchronized/wait)
/* * 多线程访问的时候出现了数据安全的问题 * 1、生产者没有生产商品,消费者就可以获取 * 2、商品的品牌和名称对应不上 * * */ public class Test { public static void main(String[] args) { Goods goods = new Goods(); Producer producer = new Producer(goods); Consumer consumer = new Consumer(goods); Thread t1 = new Thread(producer); Thread t2 = new Thread(consumer); t1.start(); t2.start(); }
/* * * 从共享空间中取走产品 * */ public class Consumer implements Runnable { private Goods goods; public Consumer(Goods goods) { this.goods = goods; } @Override public void run() { for(int i = 0;i<10;i++){ goods.get(); } } }
/* * * 生产产品,将产房放置到共享空间中 * * */ public class Producer implements Runnable { private Goods goods; public Producer(Goods goods) { this.goods = goods; } @Override public void run() { for (int i = 0; i < 10; i++) { if (i % 2 == 0) { goods.set("娃哈哈","矿泉水"); } else { goods.set("旺仔","小馒头"); } } }
public class Goods { private String brand; private String name; //默认是不存在商品的,如果值等于true的话,代表有商品 private boolean flag = false; public String getBrand() { return brand; } public void setBrand(String brand) { this.brand = brand; } public String getName() { return name; } public void setName(String name) { this.name = name; } //消费者获取商品 public synchronized void get(){ /* * 如果flag等于false的话,意味着生产者没有生产商品,此时消费者无法消费,需要让消费者线程进入到阻塞状态,等待生产者生产,当 * 有商品之后,再开始消费 * */ if (!flag){ try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } //模拟消费时间 try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("消费者取走了"+this.getBrand()+"----"+this.getName()); flag = false; //唤醒生产者去进行生产 notify(); } //生产者生产商品 public synchronized void set(String brand,String name){ //当生产者抢占到cpu资源之后会判断当前对象是否有值,如果有的话,以为着消费者还没有消费,需要提醒消费者消费,同时 //当前线程进入阻塞状态,等待消费者取走商品之后,再次生产,如果没有的话,不需要等待,不需要进入阻塞状态,直接生产即可 if(flag){ try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } //模拟生产所用的时间 try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } this.setBrand(brand); this.setName(name); System.out.println("生产者生产了" + this.getBrand() + "--" + this.getName()); //如果代码执行到此处,意味着已经生产完成,需要将flag设置为true flag = true; //唤醒消费者去进行消费 notify(); } }
解决问题方式2 (BlockingQueue)
public class Test { public static void main(String[] args) { BlockingQueue<Goods> queue = new ArrayBlockingQueue<>(5); ProducerQueue producerQueue = new ProducerQueue(queue); ConsumerQueue consumerQueue = new ConsumerQueue(queue); new Thread(producerQueue).start(); new Thread(consumerQueue).start(); } }
public class ConsumerQueue implements Runnable { private BlockingQueue<Goods> blockingQueue; public ConsumerQueue(BlockingQueue blockingQueue) { this.blockingQueue = blockingQueue; } @Override public void run() { for(int i = 0;i<10;i++){ try { Goods goods = blockingQueue.take(); System.out.println("消费者消费的商品是:"+goods.getBrand()+"--"+goods.getName()); Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } } } }
public class ProducerQueue implements Runnable { private BlockingQueue<Goods> blockingQueue; public ProducerQueue(BlockingQueue blockingQueue) { this.blockingQueue = blockingQueue; } @Override public void run() { for(int i = 0;i<10;i++){ Goods goods = null; if(i%2==0){ goods = new Goods("娃哈哈","矿泉水"); }else{ goods = new Goods("旺仔","小馒头"); } System.out.println("生产者开始生产商品:"+goods.getBrand()+"--"+goods.getName()); try { blockingQueue.put(goods); } catch (InterruptedException e) { e.printStackTrace(); } } } }
public class Goods { private String brand; private String name; public Goods(String brand, String name) { this.brand = brand; this.name = name; } public String getBrand() { return brand; } public void setBrand(String brand) { this.brand = brand; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
线程通信
▪ Java提供了3个方法解决线程之间的通信问题
方法名 作用
final void wait() 表示线程一直等待,直到其它线程通知
final void wait(long timeout) 线程等待指定毫秒参数的时间
final void wait(long timeout,int nanos) 线程等待指定毫秒、微妙的时间
final void notify() 唤醒一个处于等待状态的线程
final void notifyAll() 唤醒同一个对象上所有调用wait()方法的线程, 优先级别高的线程优先运行
▪ 注意事项:以上方法都只能在同步方法戒者同步代码块中使用,否则会抛出异常
十六、线程池
ThreadPoolExecutor
public class Task implements Runnable { @Override public void run() { // try { // Thread.sleep(1000); // } catch (InterruptedException e) { // e.printStackTrace(); // } System.out.println(Thread.currentThread().getName()+" running"); } }
public class CacheThreadPoolDemo { public static void main(String[] args) { ExecutorService executorService = Executors.newCachedThreadPool(); for(int i = 0;i<20;i++){ executorService.execute(new Task()); } executorService.shutdown(); } }
public class FixedThreadPoolDemo { public static void main(String[] args) { ExecutorService executorService = Executors.newFixedThreadPool(5); for (int i = 0 ;i<20;i++){ executorService.execute(new Task()); } executorService.shutdown(); } }
public class SingleThreadPoolDemo { public static void main(String[] args) { ExecutorService executorService = Executors.newSingleThreadExecutor(); for(int i = 0;i<20;i++){ executorService.execute(new Task()); } executorService.shutdown(); } }
ScheduledThreadPool
public class ScheduledThreadPoolDemo { public static void main(String[] args) { ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(3); System.out.println(System.currentTimeMillis()); scheduledExecutorService.schedule(new Runnable() { @Override public void run() { System.out.println("延迟三秒执行"); System.out.println(System.currentTimeMillis()); } },3, TimeUnit.SECONDS); scheduledExecutorService.shutdown(); } }
public class ScheduledThreadPoolDemo2 { public static void main(String[] args) { ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1); System.out.println(System.currentTimeMillis()); scheduledExecutorService.scheduleAtFixedRate(new Runnable() { @Override public void run() { System.out.println("1------延迟一秒执行,每三秒执行一次"); System.out.println(System.currentTimeMillis()); } },1,3, TimeUnit.SECONDS); scheduledExecutorService.scheduleAtFixedRate(new Runnable() { @Override public void run() { System.out.println("2------延迟一秒执行,每三秒执行一次"); System.out.println(System.currentTimeMillis()); } },1,3, TimeUnit.SECONDS); scheduledExecutorService.scheduleAtFixedRate(new Runnable() { @Override public void run() { System.out.println("3-------延迟一秒执行,每三秒执行一次"); System.out.println(System.currentTimeMillis()); } },1,3, TimeUnit.SECONDS); scheduledExecutorService.scheduleAtFixedRate(new Runnable() { @Override public void run() { System.out.println("4--------延迟一秒执行,每三秒执行一次"); System.out.println(System.currentTimeMillis()); } },1,3, TimeUnit.SECONDS); // scheduledExecutorService.shutdown(); } }
ForJoinPoll
分段打印0-300之间的数
/** * * 简单的打印0-300的数值。用多线程实现并行执行 * */ public class ForkJoinPoolAction { public static void main(String[] args) throws Exception{ PrintTask task = new PrintTask(0, 300); //创建实例,并执行分割任务 ForkJoinPool pool = new ForkJoinPool(); pool.submit(task); //线程阻塞,等待所有任务完成 pool.awaitTermination(2, TimeUnit.SECONDS); pool.shutdown(); } }
class PrintTask extends RecursiveAction { private static final int THRESHOLD = 50; //最多只能打印50个数 private int start; private int end; public PrintTask(int start, int end) { super(); this.start = start; this.end = end; } @Override protected void compute() { if(end - start < THRESHOLD){ for(int i=start;i<end;i++){ System.out.println(Thread.currentThread().getName()+"的i值:"+i); } }else { int middle =(start+end)/2; PrintTask left = new PrintTask(start, middle); PrintTask right = new PrintTask(middle, end); //并行执行两个“小任务” left.fork(); right.fork(); } } }
分段累加的join方法
public class ForJoinPollTask { public static void main(String[] args) throws Exception { int[] arr = new int[100]; Random random = new Random(); int total =0; //初始化100个数组元素 for(int i=0,len = arr.length;i<len;i++){ int temp = random.nextInt(20); //对数组元素赋值,并将数组元素的值添加到sum总和中 total += (arr[i]=temp); } System.out.println("初始化数组总和:"+total); SumTask task = new SumTask(arr, 0, arr.length); // 创建一个通用池,这个是jdk1.8提供的功能 ForkJoinPool pool = ForkJoinPool.commonPool(); Future<Integer> future = pool.submit(task); //提交分解的SumTask 任务 System.out.println("多线程执行结果:"+future.get()); pool.shutdown(); //关闭线程池 } }
class SumTask extends RecursiveTask<Integer> { private static final int THRESHOLD = 20; //每个小任务 最多只累加20个数 private int arry[]; private int start; private int end; /** * Creates a new instance of SumTask. * 累加从start到end的arry数组 * @param arry * @param start * @param end */ public SumTask(int[] arry, int start, int end) { super(); this.arry = arry; this.start = start; this.end = end; } @Override protected Integer compute() { int sum =0; //当end与start之间的差小于threshold时,开始进行实际的累加 if(end - start <THRESHOLD){ for(int i= start;i<end;i++){ System.out.println(Thread.currentThread().getName()+"的i值:"+arry[i]); sum += arry[i]; } return sum; }else {//当end与start之间的差大于threshold,即要累加的数超过20个时候,将大任务分解成小任务 int middle = (start+ end)/2; SumTask left = new SumTask(arry, start, middle); SumTask right = new SumTask(arry, middle, end); //并行执行两个 小任务 left.fork(); right.fork(); //把两个小任务累加的结果合并起来 return left.join()+right.join(); } } }
newWorkStealingPool
public class newWorkStealingPoolTest { public static void main(String[] args) throws Exception { // 设置并行级别为2,即默认每时每刻只有2个线程同时执行 ExecutorService m = Executors.newWorkStealingPool(); for (int i = 1; i <= 10; i++) { final int count=i; m.submit(new Runnable() { @Override public void run() { Date now=new Date(); System.out.println("线程" + Thread.currentThread() + "完成任务:" + count+" 时间为:"+ now.getSeconds()); try { Thread.sleep(1000);//此任务耗时1s } catch (InterruptedException e) { e.printStackTrace(); } } }); } while(true){ //主线程陷入死循环,来观察结果,否则是看不到结果的 } } }
线程池分类:
工作原理:
▪ 线程池执行所提交的任务过程:
▪ 1、先判断线程池中核心线程池所有的线程是否都在执行任务。
如果不是,则新创建一个线程执行刚提交的任务,否则,核心线
程池中所有的线程都在执行任务,则进入第2步;
▪ 2、判断当前阻塞队列是否已满,如果未满,则将提交的任务放
置在阻塞队列中;否则,则进入第3步;
▪ 3、判断线程池中所有的线程是否都在执行任务,如果没有,则
创建一个新的线程来执行任务,否则,则交给饱和策略进行处理
线程池生命周期:
▪ RUNNING: 能接受新提交的任务,并且也能处理阻塞队列中的任务;
▪ SHUTDOWN: 关闭状态,不再接受新提交的任务,但却可以继续处理阻塞队列中已保存的任务。
▪ STOP: 不能接受新任务,也不处理队列中的任务,会中断正在处理任务的线程。
▪ TIDYING: 如果所有的任务都已终止了,workerCount (有效线程数) 为0,
线程池进入该状态后会调用 terminated() 方法进入TERMINATED 状态。
▪ TERMINATED:在terminated() 方法执行完后进入该状态,默认terminated()方法中什么也没有做。
创建线程池:
public ThreadPollExecutor(int corePollSize, //▪corePoolSize:核心线程池的大小 int maximumPollSize, //▪ maximumPoolSize:线程池能创建线程的最大个数 long keepAliceTime, //▪ keepAliveTime:空闲线程存活时间 TimeUnit unit, //▪ unit:时间单位,为keepAliveTime指定时间单位 BlockingQueue<Runnable> workQueue, //▪ workQueue:阻塞队列,用于保存任务的阻塞队列 ThreadFactory threadFactory, //▪ threadFactory:创建线程的工程类 RejecteExecutionHandler handler){} //▪ handler:饱和策略(拒绝策略)
execute执行逻辑:
▪ 如果当前运行的线程少于corePoolSize,则会创建新的线程来执
行新的任务;
▪ 如果运行的线程个数等于或者大于corePoolSize,则会将提交的
任务存放到阻塞队列workQueue中;
▪ 如果当前workQueue队列已满的话,则会创建新的线程来执行
任务;
▪ 如果线程个数已经超过了maximumPoolSize,则会使用饱和策
略RejectedExecutionHandler来进行处理。
线程池关闭:
▪ 关闭线程池,可以通过shutdown和shutdownNow两个方法
▪ 原理:遍历线程池中的所有线程,然后依次中断
▪ 1、shutdownNow首先将线程池的状态设置为STOP,然后尝试停
止所有的正在执行和未执行任务的线程,并返回等待执行任务的
列表;
▪ 2、shutdown只是将线程池的状态设置为SHUTDOWN状态,然
后中断所有没有正在执行任务的线程
十七、网络编程
传输协议
UDP:相当于収短信(有字数限制), 不需要建立连接, 数据报的大小限制在64k内, 效率较高,不安全,容易丢包
TCP:相当于打电话,需要建立连接, 效率相对比较低,数据传输安全, 三次握手完成。 (点名-->答到-->确认)
socket简单通信
public class Server2 { public static void main(String[] args) throws IOException { //创建serversocket对象 ServerSocket serverSocket = new ServerSocket(10000); //获取服务端的套接字对象 Socket server = serverSocket.accept(); //--------------------接受客户端的输入--------------------------- //获取输入流对象 InputStream inputStream = server.getInputStream(); byte[] buf = new byte[1024]; int length = inputStream.read(buf); System.out.println("客户端传输的数据是:" + new String(buf,0,length)); //---------------------返回客户端数据---------------------------------- OutputStream outputStream = server.getOutputStream(); outputStream.write("你好,收到".getBytes()); //关闭流 outputStream.close(); inputStream.close(); server.close(); serverSocket.close(); } }
public class Client2 { public static void main(String[] args) throws IOException { //创建客户端的套接字 Socket client = new Socket("127.0.0.1",10000); //--------------------向外进行输出--------------- //获取输出流对象 OutputStream outputStream = client.getOutputStream(); //数据输出 outputStream.write("hello java".getBytes()); //--------------------接受服务端返回的消息--------------------------- //获取输出流对象 InputStream inputStream = client.getInputStream(); byte[] buf = new byte[1024]; int length = inputStream.read(buf); System.out.println("服务端的响应数据是:" + new String(buf,0,length)); //关闭流操作 inputStream.close(); outputStream.close(); client.close(); } }
模拟上传图片
public class PicServer { public static void main(String[] args) throws IOException { //创建服务端对象,开放端口 ServerSocket serverSocket = new ServerSocket(10086); //创建服务端的socket Socket server = serverSocket.accept(); //获取输入流对象 InputStream inputStream = server.getInputStream(); //创建文件输出流对象 FileOutputStream fileOutputStream = new FileOutputStream("qige.jpg"); int temp = 0; while((temp = inputStream.read())!=-1){ fileOutputStream.write(temp); } server.shutdownInput(); //添加流输出完成的标志 //上传图片结束之后给予客户端响应 OutputStream outputStream = server.getOutputStream(); outputStream.write("上传成功".getBytes()); server.shutdownOutput(); //关闭操作 outputStream.close(); fileOutputStream.close(); inputStream.close(); server.close(); serverSocket.close(); } }
public class PicClient { public static void main(String[] args) throws Exception { //创建图片的输入流对象 FileInputStream fileInputStream = new FileInputStream("img.jpg"); //创建Socket Socket client= new Socket("localhost",10086); //获取输出流对象 OutputStream outputStream = client.getOutputStream(); int temp = 0; while((temp = fileInputStream.read())!=-1){ outputStream.write(temp); } client.shutdownOutput(); //接受服务端的响应 InputStream inputStream = client.getInputStream(); byte[] buf = new byte[1024]; int length = inputStream.read(buf); System.out.println(new String(buf,0,length)); client.shutdownInput(); //关闭操作 inputStream.close(); outputStream.close(); fileInputStream.close(); client.close(); } }
模拟登录(可while循环登录)
public class LoginServer { public static void main(String[] args) throws Exception { ServerSocket serverSocket = new ServerSocket(10000); Socket server = serverSocket.accept(); //获取输入流对象 InputStream inputStream = server.getInputStream(); //需要使用ObjectInputStream对象 ObjectInputStream objectInputStream = new ObjectInputStream(inputStream); User user = (User) objectInputStream.readObject(); String str = ""; if("msb".equals(user.getUsername()) && "msb".equals(user.getPassword())){ System.out.println("欢迎你:"+user.getUsername()); str = "登录成功"; }else{ str="登录失败"; } //截断输入流 server.shutdownInput(); //给客户端响应 DataOutputStream outputStream = new DataOutputStream(server.getOutputStream()); outputStream.writeUTF(str); server.shutdownOutput(); //关闭流操作 outputStream.close(); inputStream.close(); server.close(); serverSocket.close(); /* ServerSocket serverSocket = new ServerSocket(10000); while(true){ Socket server = serverSocket.accept(); //获取输入流对象 InputStream inputStream = server.getInputStream(); //需要使用ObjectInputStream对象 ObjectInputStream objectInputStream = new ObjectInputStream(inputStream); User user = (User) objectInputStream.readObject(); String str = ""; if("msb".equals(user.getUsername()) && "msb".equals(user.getPassword())){ System.out.println("欢迎你:"+user.getUsername()); str = "登录成功"; }else{ str="登录失败"; } //截断输入流 server.shutdownInput(); //给客户端响应 DataOutputStream outputStream = new DataOutputStream(server.getOutputStream()); outputStream.writeUTF(str); server.shutdownOutput(); //关闭流操作 outputStream.close(); inputStream.close(); server.close(); } // serverSocket.close();*/ } }
public class LoginClient { public static void main(String[] args) throws IOException { Socket client = new Socket("localhost",10000); OutputStream outputStream = client.getOutputStream(); //完成登录功能,需要传输一个user对象 User user = getUser(); //传输对象需要ObjectOutputStream ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream); objectOutputStream.writeObject(user); //调用shutdown方法告诉对对方传输完成 client.shutdownOutput(); //接受响应 DataInputStream dataInputStream = new DataInputStream(client.getInputStream()); String str = dataInputStream.readUTF(); System.out.println(str); //关闭流操作 dataInputStream.close(); objectOutputStream.close(); outputStream.close(); client.close(); } public static User getUser(){ Scanner scanner = new Scanner(System.in); System.out.println("请输入用户名:"); String username = scanner.nextLine(); System.out.println("请输入密码:"); String password = scanner.nextLine(); return new User(username,password); } }
public class User implements Serializable { private static final long serialVersionUID = 1590020726742801370L; private String username; private String password; public User(){ } public User(String username, String password) { this.username = username; this.password = password; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } }
模拟登录(thread循环登录)
public class LoginServer2 { public static void main(String[] args) throws Exception { ServerSocket serverSocket = new ServerSocket(10000); while(true){ Socket socket = serverSocket.accept(); LoginThread loginThread = new LoginThread(socket); new Thread(loginThread).start(); } // serverSocket.close(); } }
public class LoginThread implements Runnable{ private Socket socket; public LoginThread(Socket socket){ this.socket = socket; } @Override public void run() { ObjectInputStream objectInputStream = null; DataOutputStream dataOutputStream = null; try { objectInputStream = new ObjectInputStream(socket.getInputStream()); User user = (User) objectInputStream.readObject(); String str = ""; if("msb".equals(user.getUsername()) && "msb".equals(user.getPassword())){ System.out.println("欢迎你:"+user.getUsername()); str = "登录成功"; }else{ str="登录失败"; } socket.shutdownInput(); dataOutputStream = new DataOutputStream(socket.getOutputStream()); dataOutputStream.writeUTF(str); socket.shutdownOutput(); } catch (IOException | ClassNotFoundException e) { e.printStackTrace(); }finally { try { dataOutputStream.close(); objectInputStream.close(); socket.close(); } catch (IOException e) { e.printStackTrace(); } } } }
public class LoginClient { public static void main(String[] args) throws IOException { Socket client = new Socket("localhost",10000); OutputStream outputStream = client.getOutputStream(); //完成登录功能,需要传输一个user对象 User user = getUser(); //传输对象需要ObjectOutputStream ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream); objectOutputStream.writeObject(user); //调用shutdown方法告诉对对方传输完成 client.shutdownOutput(); //接受响应 DataInputStream dataInputStream = new DataInputStream(client.getInputStream()); String str = dataInputStream.readUTF(); System.out.println(str); //关闭流操作 dataInputStream.close(); objectOutputStream.close(); outputStream.close(); client.close(); } public static User getUser(){ Scanner scanner = new Scanner(System.in); System.out.println("请输入用户名:"); String username = scanner.nextLine(); System.out.println("请输入密码:"); String password = scanner.nextLine(); return new User(username,password); } }
public class User implements Serializable { private static final long serialVersionUID = 1590020726742801370L; private String username; private String password; public User(){ } public User(String username, String password) { this.username = username; this.password = password; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } }
DatagramSocket (UDP - Socket)
public class UDPClient { public static void main(String[] args) throws Exception { //创建udp通信的socket DatagramSocket datagramSocket = new DatagramSocket(10000); //从控制台读取数据 Scanner scanner = new Scanner(System.in); String str = scanner.nextLine(); DatagramPacket datagramPacket = new DatagramPacket(str.getBytes(),str.getBytes().length, InetAddress.getByName("localhost"),10001); datagramSocket.send(datagramPacket); datagramSocket.close(); } }
public class UDPServer { public static void main(String[] args) throws Exception { DatagramSocket datagramSocket = new DatagramSocket(10001); byte[] buf = new byte[1024]; //用来接受传输过来的数据 DatagramPacket datagramPacket = new DatagramPacket(buf,buf.length); //利用创建好的数据报包对象来接受数据 datagramSocket.receive(datagramPacket); //打印输出信息 System.out.println( new String(datagramPacket.getData(),0,datagramPacket.getLength())); datagramSocket.close(); } }
十八、Lambda
Lambda表达式应用场景: 任何有函数式接口的地方
函数式接口: 只有一个抽象方法(Object类中的方法除外)的接口是函数式接口
函数式接口
Supplier 代表一个输出
Consumer 代表一个输入
BiConsumer 代表两个输入
Function 代表一个输入,一个输出(一般输入和输出是不同类型的)
UnaryOperator 代表一个输入,一个输出(输入和输出是相同类型的)
BiFunction 代表两个输入,一个输出(一般输入和输出是不同类型的)
BinaryOperator 代表两个输入,一个输出(输入和输出是相同类型的)
方法引用的分类
静态方法引用 类名::staticMethod (args) -> 类名.staticMethod(args)
实例方法引用 inst::instMethod (args) -> inst.instMethod(args)
对象方法引用 类名::instMethod (inst,args) ->类名.instMethod(args)
构造方法引用 类名::new (args) -> new 类名(args)
十九、Stream
Stream特性
1:不是数据结构,没有内部存储
2:不支持索引访问
3:延迟计算
4:支持并行
5:很容易生成数组或集合(List,Set)
6:支持过滤,查找,转换,汇总,聚合等操作
Stream的创建
1、通过数组
2、通过集合来
3、通过Stream.generate方法来创建
4、通过Stream.iterate方法来创建
5、其他API创建
演示代码
public class StreamDemo { //通过数组来生成 static void gen1(){ String[] strs = {"a","b","c","d"}; Stream<String> strs1 = Stream.of(strs); strs1.forEach(System.out::println); } //通过集合来生成 static void gen2(){ List<String> list = Arrays.asList("1","2","3","4"); Stream<String> stream = list.stream(); stream.forEach(System.out::println); } //generate static void gen3(){ Stream<Integer> generate = Stream.generate(() -> 1); generate.limit(10).forEach(System.out::println); } //使用iterator static void gen4() { Stream<Integer> iterate = Stream.iterate(1, x -> x + 1); iterate.limit(10).forEach(System.out::println); } //其他方式 static void gen5(){ String str = "abcdefg"; IntStream stream =str.chars(); stream.forEach(System.out::println); } public static void main(String[] args) { //stream生成的操作 // gen1(); // gen2(); // gen3(); // gen4(); // gen5(); //中间操作:如果调用方法之后返回的结果是Stream对象就意味着是一个中间操作 Arrays.asList(1,2,3,4,5).stream().filter((x)->x%2==0).forEach(System.out::println); //求出结果集中所有偶数的和 int count = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9).stream().filter(x -> x % 2 == 0).mapToInt(x->x).sum(); System.out.println(count); //求集合中的最大值 List<Integer> list = Arrays.asList(1,2, 3,4, 5, 6); Optional<Integer> max = list.stream().max((a, b) -> a - b); System.out.println(max.get()); //求集合的最小值 System.out.println(list.stream().min((a, b) -> a-b).get()); Optional<Integer> any = list.stream().filter(x -> x % 2 == 0).findAny(); System.out.println(any.get()); Optional<Integer> first = list.stream().filter(x -> x % 10 == 6).findFirst(); System.out.println(first.get()); Stream<Integer> integerStream = list.stream().filter(i -> { System.out.println("运行代码"); return i % 2 == 0; }); System.out.println(integerStream.findAny().get()); System.out.println("---------------"); //获取最大值和最小值但是不使用min和max方法 Optional<Integer> min = list.stream().sorted().findFirst(); System.out.println(min.get()); Optional<Integer> max2 = list.stream().sorted((a, b) -> b - a).findFirst(); System.out.println(max2.get()); Arrays.asList("java","c#","python","scala").stream().sorted().forEach(System.out::println); Arrays.asList("java","c#","python","scala").stream().sorted((a,b)->a.length()-b.length()).forEach(System.out::println); System.out.println("---------------"); //想将集合中的元素进行过滤同时返回一个集合对象 List<Integer> collect = list.stream().filter(x -> x % 2 == 0).collect(Collectors.toList()); collect.forEach(System.out::println); System.out.println("---------------"); //去重操作 Arrays.asList(1,2,3,3,3,4,5,2).stream().distinct().forEach(System.out::println); System.out.println("---------------"); Arrays.asList(1,2,3,3,3,4,5,2).stream().collect(Collectors.toSet()).forEach(System.out::println); //打印20-30这样的集合数据 Stream.iterate(1,x->x+1).limit(50).skip(20).limit(10).forEach(System.out::println); String str ="11,22,33,44,55"; System.out.println(Stream.of(str.split(",")).mapToInt(x -> Integer.valueOf(x)).sum()); System.out.println(Stream.of(str.split(",")).mapToInt(Integer::valueOf).sum()); System.out.println(Stream.of(str.split(",")).map(x -> Integer.valueOf(x)).mapToInt(x -> x).sum()); System.out.println(Stream.of(str.split(",")).map(Integer::valueOf).mapToInt(x -> x).sum()); //创建一组自定义对象 String str2 = "java,scala,python"; Stream.of(str2.split(",")).map(x->new Person(x)).forEach(System.out::println); Stream.of(str2.split(",")).map(Person::new).forEach(System.out::println); Stream.of(str2.split(",")).map(x->Person.build(x)).forEach(System.out::println); Stream.of(str2.split(",")).map(Person::build).forEach(System.out::println); //将str中的每一个数值都打印出来,同时算出最终的求和结果 System.out.println(Stream.of(str.split(",")).peek(System.out::println).mapToInt(Integer::valueOf).sum()); System.out.println(list.stream().allMatch(x -> x>=0)); } }
@SuppressWarnings(value="all") public class Person { private String name; public Person() { } /** * * @param name */ public Person(String name) { this.name = name; } /** * * @param name * @return */ public static Person build(String name){ Person p = new Person(); p.setName(name); return p; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Deprecated public static void show(){ System.out.println("show"); } @Override public String toString() { return "Person{" + "name='" + name + '\'' + '}'; } public static void main(String[] args) { Person p = new Person(); show(); Date date = new Date(); System.out.println(date.getMinutes()); } }
二十、自定义注解
内置注解
▪ @Override:定义在java.lang.Override中,此注释叧适用于修 饰方法,表示一个方法声明打算重写超类中的另一个方法声明
▪ @Deprecated:定义在java.lang.Deprecated中,此注释可以 修饰方法、属性、类,表示不鼓励程序员使用这样的元素,
通常 是因为它很危险戒者存在更好的选择
▪ @SuppressWarnings:定义在java.lang.SuppressWarnings中, 用来抑制编写编译时的警告信息
元注解
▪ 元注解的做哟个是负责注解其他注解,java中定义了四个标准的 meta-annotation类型,他们被用来提供对其他annotation类型 作说明
▪ 这些类型和它们所支持的类在java.lang.annotation包中
– @Target:用来描述注解的使用范围(注解可以用在什么地方)
– @Retention:表示需要在什么级别保存该注释信息,描述注解的生命周期 ▪ Source < Class < Runtime
– @Document:说明该注解将被包含在javadoc中 – @Inherited:说明子类可以继承父类中的该注解
自定义注解
▪ 使用@interfac自定义注解时,自劢继承了 java.lang.annotation.Annotation接口
▪ 使用觃则:
– @interface用来声明一个注解,格式:public @interface 注解名{}
– 其中的每一个方法实际上是声明了一个配置参数
– 方法的名称就是参数的名称
– 返回值类型就是参数的类型(返回值叧能是基本类型,Class,String,enum)
– 可以头盖骨default来声明参数的默认值
– 如果叧有一个参数成员,一般参数名为value
– 注解元素必须要有值,我们定义注解元素时,经常使用空字符串,0作为默 认值
演示代码
//@MyAnnotation(name="hehe",age=12,id=3,likes = {"book","lol","movie"}) @MyAnnotation public class MetaAnnotation { public void test() { } } //target用来声明当前自定义的注解适合适用于什么地方,类,方法,变量,包。。。。 @Target({ElementType.METHOD, ElementType.TYPE}) //retention用来表示当前注解适用于什么环境,是源码级别还是类级别还是运行时环境,一般都是运行时环境 @Retention(RetentionPolicy.CLASS) //表示该注解是否是显示在javadoc中 @Documented //表示当前注解是否能够被继承 @Inherited @interface MyAnnotation { //定义的方式看起来像是方法,但是实际上使用在使用注解的时候填写的参数的名称,默认的名称是value //自定义注解中填写的所有方法都需要在使用注解的时候,添加值,很麻烦,因此包含默认值 String name() default "zhangsan"; int age() default 12; int id() default 1; String[] likes() default {"a", "b", "c"}; }
加载全部内容