JAVA概述
一、java之父
詹姆斯·高斯林
二、java体系
1、javaSE,标准版,各应用平台的基础,桌面开发和低端商务应用的解决方案。
2、javaEE,企业版,以企业为环境而开发应用程序的解决方案。
3、javaME,微型版,致力于消费产品和嵌入式设备的最佳方案。
三、java可以做什么
1、开发桌面应用程序。
2、开发面向Internet的web应用程序。
3、提供各行业的解决方案。
4、开发android手机应用程序。
四、java的特性
1、一种面向对象的编程语言。
2、一种与平台无关的语言(根据JVM实现的)。
3、一种健壮性语言。
4、具有较高的安全性。
五、java应用程序的运行机制
先编译(.class),在解释运行。
六、java程序开发的三个步骤
1、编写源程序,java源代码文件。
2、编译源程序,编译器编译编译成java字节码文件。
3、运行,java虚拟机(JVM)。
七、垃圾回收器(GC)
在java运行过程中自动启动,程序员无法干预。
八、JDK和JRE
JDK:java开发工具包
先编译(编译器javec),后运行(解释器java)
JRE:java运行环境
加载代码(加载器),校验代码(校验器),执行代码(解释器)
九、java虚拟机
java虚拟机实际上只是一层接口,一层Java程序和操作系统通讯的接口。java文件编译生成class文件,
而java虚拟机就是这些class文件能够在上面运行的一个平台,你把class文件看成一个软件,java虚拟机就是这个软件可以运行的操作系统。
十、开发java应用的要点
1、一个源文件中只能有一个public修饰的类,其他类个数不限。
2、一个源文件有n个类时,编译结果的class文件就有n个。
3、源文件的名字必须和public修饰的类名相同
4、java语言中单词拼写大小写严格区分。
5、main方法入口
6、每一句以分号(;)结束
十一、注释
1、单行注释//
2、多行注释/* */
3、java文档注释/** */
Java编程基础
一、标识符
1、命名规则:由字母、下划线、数字和美元符号组成,不能以数字开头,区分大小写,不能是关键字和保留字(goto、const),长度一般不超过15个字符。
2、驼峰式命名:
类名:单个单词,首字母大写,多个单词,首字母都大写。 方法名、参数名、变量名:单个单词,首字母小写,多个单词,第一单词首字母小写,其他单词首字母大写。 包名:全部小写。
二、java数据类型划分
1、基本数据类型:
数值型:byte 1字节 8位 -128~127 short 2字节 16位 -32768~32767 int 4字节 32位 -2^31~2^31-1 long 8字节 64位 2^63~2^63-1 浮点类型: float 4字节 32位 double 8字节 64位 字符型:char 2字节 16位 0~65535 布尔型:boolean true false
2、引用类型:
字符串 String、 类 class 、枚举 enum、接口interface
三、普及二进制
1、计算机中的数据都以二进制数据保存。
2、计算机信息的存储单位:
位(bit):是计算机存储处理信息的最基本的单位 字节(byte):一个字节有8个位组成。
四、转义字符
\n 换行 \r 回车 \t 水平制表 ’ 单引号 " 双引号 \斜杠
五、基本数据类型之间的转换
1、自动类型转换:范围小→范围大
byte→short→int→long→float→double; char→int→long→float→double
2、强制类型转换:范围大→范围小
需要加强制转换符
六、变量
1、数据类型划分:
基本类型变量:数据的值 引用类型变量:数据的地址
2、声明的位置划分:
局部变量 全局变量 区别: 1、默认值 局部没有默认值,使用前必须初始化。 全局有默认值,默认为0,不必须初始化。 2、声明位置 局部在方法内。 全局在方法外类内。 3、作用位置 局部只能在自己声明的方法里。 全局在整个类中
七、java中的运算符
算术运算符:+ 、 - 、 * 、 / 、 % 、 ++ 、 –
赋值运算符:= 、 += 、 -= 、 *= 、 /= 、 %=
关系运算符:> 、 < 、 >= 、 <= 、 == 、 !=
逻辑运算符:! 、 & (只要有一个false 最终结果就是false) 、
| (但凡有一个true 最终结果就是true) 、 ^ (如果两边一样 最终结果为false 如果两边不同 最终结果为true)、 &&(如果第一个是false 那第二个不执行 最终结果是false)、 ||(如果第一个表达式的结果是true 那第二个表达式 就不去计算了 ,最终结果是true)
位运算符: ~ 、 >> 、 << 、 >>>
字符串连接运算符:+
三目运算符:X ? Y : Z
X为boolean类型表达式,先计算x的值,若为true,整个三目运算的结果为表达式Y的值,否则整个运算结果为表达式Z的值。
八、程序流程控制
结构化程序的三种结构:
顺序、选择(分支)、循环
九、if语句
1、if(){}
2、if(){}else{}
3、if(){}else if(){}
4、if(){if(){}else()}
5、if()执行语句 esle 执行语句 注意:执行语句只有一条语句的时候.可以将if esle 的大括号省略
注意:()内是boolean类型表达式,{}是语句块
比较字符串用equals,比较内容。比较数值用==,比较地址。 基本数据类型:变量名、变量值在栈中。 引用数据类型:变量名在栈中,变量值在常量池中。
十、switch语句
switch(表达式expr){
case const1: statement1; break; … … case constN: statementN; break; [default: statement_dafault; break;]
}
注意:1、表达式必须是int、byte、char、short、enmu、String类型
2、constN必须是常量或者finall变量,不能是范围 3、所有的case语句的值不能相同,否则编译会报错 4、default可要可不要 5、break用来执行完一个分支后使程序跳出switch语句块,否则会一直会执行下去。
十一、if和switch的区别
1、if可以判断范围,也可以判断一个值
switch只能判断指定的值
2、若只判断指定的值,则使用switch语句,效率快
if判断范围,对数据判断灵活,自身的格式也比较灵活
十二、for循环
for ([循环变量初始值设定]; [循环条件判断]; [改变循环变量的值]){
循环体
}
注意:1、表达式2一般不可以省略,否则死循环
2、表达式3可以省略,但是在循环体中必须有语句修改变量,以使表达式2在某一时刻为false结束循环。 3、若同时省略表达式1,表表达式3,则相当于while(表达式2)语句 4、三个表达式均省略 即for(;;)语句,此时相当于while(true)语句 5、表达式1、表达式3可以是逗号表达式,以使循环变量值在修改时可以对其它变量赋值
十三、while
while( 条件表达式语句){
循环体语句; }
[初始条件]
do{
循环体;
[迭代]
}while( 循环条件判断);
注意:1、当第一次执行时,若表达式=false时,则while语句不执行,而do/while语句执行一次后面的语句
2、一定要切记在switch循环中,如果没有break跳出语句,每一个case都要执行一遍,在计算最终结果。
十四、break和continue
break跳出某个循环
continue跳过某个循环
注意:if外有循环可以用break、continue,单纯if不可以用。
十五、方法
1、为什么使用方法?
减少重复代码,提供代码复用性 使用方法将功能提炼出来 写在类内
2、声明格式
[修饰符] 返回值类型 方法名([形式参数列表]){ 程序代码; [return 返回值;] }
注意:1、方法是给外界提供内容的位置,形式参数是外界提供的
2、方法调用的时候写的是实际参数 3、实际参数的类型、顺序和形参要对应上 4、支持自动转换类型,不支持强制类型转换
十六、return
1、将数据返回给调用者,除了void外,return后必须跟着返回值,只能返回一个。
2、终止方法的执行,返回数据类型必须是void,return后不能添加数据。
注意:1、当return结束方法的时候,要让其后面的代码有可能被执行到。
2、一个方法里可以有多个return,在void里不能有返回值,其他的必须有返回值。
十七、重载overload
1、在一个类中,方法名字相同,参数类型不同。
参数类型不同:个数、数据类型、顺序。
注意:
1、重载和返回值类型,修饰符没有任何关系。 2、参数变量名修改也不能够重载
十九、递归
1、有返回值
2、有参数
3、能够有跳出循环的控制语句
4、自己调用自己
面向对象编程
一、面向对象和面向过程
1、面向对象:是以具体的事物为单位,考虑的是它的特征(属性)和行为(方法)。
2、面向过程:是以具体的流程为单位,考虑功能的实现。
二、类和对象
1、对象:看得见摸得着的具体事物。
类:抽象化的概念
2、类和对象的关系:
类是对象的模板/抽象化的概念,对象是类的实例。
3、创建类和对象
类: 特征:全局变量/属性/成员变量 动作:方法 对象: 类名 对象名=new 类名() 注意:一个类可以创建多个对象,,每个对象之间没有关系。
三、内存图
1、栈:先进后出,存放基本数据类型变量名和变量值,引用数据类型的变量名,方法执行的时候进入栈中。
2、堆:先进先出,new出来的对象的实例,包括类的属性个方法。
四、构造方法
1、构造方法是new关键字调用的,用来帮助构建对象
2、显示构造对象
3、隐示构造对象(没有显示的情况下存在)
4、构造对象可以重载,参数类型不一致。
五、关键字
1、static调用格式:
1、同一个类中: 静态的: 方法名 属性名 类名.方法名 类名.属性名 对象名.方法名 对象名.属性名 非静态的: 对象名.属性名 对象名.方法名 2、不同类中: 静态的: 对象名.方法名 对象名.属性名 类名.方法名 类名.属性名 非静态的: 对象名.属性名 类名.方法名 注意:1、static可以修饰属性、方法、代码块,不可以修饰类和构造方法。 2、静态方法随着类的加载而加载。 3、在静态方法区内的东西只有一份,所有的对象共享这一份空间,只要有一个对象对属性进行修改,所有的对象调用都是修改后的数据。 4、代码块的执行顺序:静态代码块(只被调用一次)>构造代码块{}>构造方法>普通方法(需调用)
2、this关键字
1、可以调用属性和方法。 this.属性名(全局变量) this.方法名(); 2、在构造方法中: 1、this();括号内的参数个数、顺序、类型根据调用的方法来决定。 2、必须放在第一行,只能调用一次。 3、调用构造方法时只能在构造方法中调用,调用属性和方法时可以在构造方法中可以在普通方法中。 4、当全局变量和局部变量有重名字的时候,用this来区分。
3、super关键字
1、super指代父类对象。 2、super可以调用属性、方法、构造方法。 3、super调用父类的构造方法。 4、super调用构造方法时候必须放在第一行。
4、final最终的
1、可以修饰全局变量,声明的时候必须赋值,只能赋值一次。 2、可以修饰局部变量,声明时候可以不赋值,但也只能赋值一次。 3、可以修饰方法,可以正常使用,不能被重写。 4、可以修饰类,可以正常使用,不能被继承。 5、用final修饰的属性通常叫常量。 6、static final 全局变量。每个字母都要大写。
5、this和super的区别
1、this指的是本类创建的对象。 super指代的是父类的对象 2、this可以调用属性、方法、构造方法。 super也可以调用属性、方法、构造方法。 3、this调用属性和方法的时候,调用自己本类的属性和方法。 如果本类没有,那就用super去父类中找 4、this调用构造方法调用,调用本类的其他构造方法。 super调用父类的构造方法。 5、this和super在调用构造方法的时候必须放在第一行。 6、this和super不能同时存在
6、最小作用域最强原则:
局域变量在此方法中,比全局变量在此方法中的作用强。
六、面向对象的三大特征
1、封装
作用:提高代码的安全性 1、将属性私有化,并提供对外界的接口(get/set方法)。 2、用private修饰的属性和方法,只能在本类中使用。
2、继承
作用:提高代码的复用性,减少重复代码
1、子类可以继承父类非私有的属性和方法,不能继承构造方法和私有的属性和方法。 2、可以综合子类的共同特征来去提炼父亲的类。 3、子类在继承父类的各种属性和方法时,也可以有自己的属性和方法。 4、一个子类只能有一个父类,java只能单继承,不能多继承,因为多个类中的方法名相同,方法体不同,不知使用哪个。 5、一个类继承最顶端叫做基类或者超类,所有的超类叫做object 。 6、在继承关系中,如果父类没有无参数的构造方法,如何解决? 1>子类中添加一个和父类构造方法参数列表相同的构造方法,通过super参数传递给父类的构造方法 2>如果父类允许修改的时候,可以在父类中创建一个无参的构造方法 7、在继承关系中,代码块的执行顺序:父静>子静>父构造代码块>父构造方法>子构造代码块>子构造方法
3、多态
1、分类 编译时多态:在编译过程中察觉的多态,重载,向上转型。 运行时多态:在运行过程中察觉的多态,向下转型。 2、向上转型、向下转型是在继承关系中,向下转型必须在向上转型的基之上。 3、在继承关系中,父类的对象可以指向子类的实例,父类引用实体方法的时候,是调用子类重写以后的方法。 4、向上转型 父类的引用指向子类的实体 父类类名 对象名=new 子类类(); 优点:减少重复代码,提高代码的复用性 缺点:父类的引用无法调用子类特有的属性和方法 解决方案:向下转型 5、向下转型: 子类对象的父类引用赋给子类 子类类名 对象名=(子类类名)父类对象; 6、 instanceof 判断左边的对象是否属于右边的类 对象名 instanceof 类名(子类类名) 7、匿名对象 new 类名() 只有堆空间,没有栈空间,只能属于一次,为了节省代码。
七、抽象abstract
作用:节省代码,提高代码的复用性
1、抽象类格式:访问权限修饰符 abstract class 类名{}
2、抽象方法格式:访问权限修饰符 abstract 返回值类型 方法名(形式参数列表);
注意:
1、如果一个类里有抽象方法,那么这个类必须声明成抽象类。 2、一个类里面可以没有抽象方法,可以有非抽象方法, 3、类继承抽象类: 把子类也用abstract修饰,变成抽象类。 子类重写父类的抽象的方法 4、抽象类不能创建对象。 5、抽象类可以有构造方法,在创建子类的时候,super隐式调用父类的构造方法,将父类的属性和方法放到子类的对象空间里。 6、在继承你关系中,子类能够继承抽象类的各种属性和方法,除了私有的和构造方法。 7、只有公开的才可以和abstract连用,static final private 都不可以。 static属于类方法,不允许覆盖,abstract必须被覆盖。final不能被重写。
八、接口interface
作用:规范了代码,提高代码的拓展性
1、格式:访问权限修饰符 interface 接口名称{}
2、实现类的格式:访问权限修饰符 class 实现类名 implements 接口名{必须重写接口中的所有的抽象方法}
3、接口中只有全局常量和抽象方法。
4、书写的时候可以省略部分修饰符,系统会默认给添上。
5、接口在实现的同时去继承,extends在implement前面。
6、接口可以多实现,实现的也必须是接口,方法名可以重复,实现类实现一个就行了,因为没有方法体,不会发生冲突。
九、抽象和接口的区别
1、关键字:抽象类 abstract 接口interface
2、抽象类继承 extends 接口实现 implements
3、子类继承抽象类和 实现类实现接口的格式不同
4、接口中只有全局变量和抽象方法 抽象类中有各种属性和方法
5、抽象类只能单继承 接口可以多实现
6、抽象类的子类只能继承一个父类 实现类可以实现多个接口,并且还可以继承父类
7、抽象类的作用:提高代码的复用性 接口的作用:1、规范代码2、提高代码的拓展新
十、方法重写override 覆盖(多态)
1.在子类中。
2、返回值相同、方法名相同、参数列表相同。
3、访问权限修饰符不能比父类更严格。
4、父类的方法不能够满足子类需求的时候,子类需要重写父类的方法。
十一、重写和重载的区别:
1、重写是在继承关系中 重载是在同一个类中
2、重写是方法名、参数列表和父类相同 重载,方法名相同,参数列表不相同(个数、类型、顺序)
3、重写返回值类型和父类相同 重载和返回值无关
4、重写访问权限修饰符不能比父类更加严格 重载没有要求
十二、访问权限修饰符
本类中 本包中 其他包子类 其他包非子类
public √ √ √ √
protected √ √ √ ×
default √ √ × ×
private √ × × ×
十三、equals
object中的equals比较的是地址,底层封装的是==
==比较的是基本数据类型,比较的是内容
引用数据类型比较的是地址
String中也有equals,String中的equals被重写过了,比较的是内容。
十四、空指针异常
1、声明了对象名,但没有给对象初始化,然后使用这个对象
2、遇到了类类型作为属性的时候,就必须初始化,否则就会报错
十五、内部类
分类:成员内部类、静态内部类、局部内部类、匿名内部类
1、成员内部类:
1、可以用四种访问权限修饰符修饰 2、可以有自己的属性和方法,除了静态的。 3、可以使用外部类的所有属性和方法,包括私有的。 4、创建对象 1、通过创建外部类对象的方式创建对象 外部类 外部类对象=new 外部类(); 内部类 对象名=外部类对象.new 内部类(); 2、内部类 对象名=new 外部类.new 内部类();
2、静态内部类
1、格式:static class 类名{} 2、可以声明静态的属性和方法 3、可以使用外部的静态的属性和方法 4、创建对象 内类名 对象名=new 内类名();(可以直接创建) 外部类名.内部类 对象名=new 外部类.内部类(); 包名.外部类名.内部类 对象名=new 包名.外部类.内部类(); 5、外部类与内部类同名时,默认是使用内部类对象调用外部类属性 this代表内部类对象 6、要想使用外部类属性,需要使用外部类对象调用
3、局部内部类
1、在方法中声明 2、只能用default修饰 3、可以声明属性和方法,但不能是静态的 4、创建对象,必须在声明内部类的方法内创建 5、调用方法的时候,局部内部类才会被执行
4、匿名内部类
1、匿名内部类只是用一次 2、格式: 父类或接口名 对象名=new 父类或接口名(参数列表){ 重写抽象方法 } 调用抽象方法:对象名.方法名
十六、模式
1、单例模式
分类:懒汉式、饿汉式 1、构造方法私有化 2、在本类中创建本类对象 3、保证对象的唯一性final 4、给外界提供得到对象的方法 static 5、在多线程中,饿汉式安全,懒汉式不安全
2、简单工厂模式
批量创建对象 1 创建工厂类 : 创建对象的方法 2 果汁类 是所有种类果汁的父类 3 在工厂类的方法中返回果汁类 4 根据测试类中传递的字符串判断到底返回哪种果汁 5 测试类通过工厂类返回果汁对象
3、建造者模式
内部类使用场景 目的:静态内部类创建外部类对象 1、 创建外部类,在其中创建一个静态内部类 2、静态内部类中写属性,构造方法和set get方法 3、静态内部类中写一个方法,必须返回外部类对象 4、 给外部类创建对象,传递参数。
4、装饰者模式
1、在处理流中使用 2、子类重写父类的方法,提高父类方法的功能及效率 3、为了尽可能减少重复代码,在重写的方法中用父类的对象调用父类原来的方法 4、得到父类对象可以通过将父类对象作为子类属性,通过子类构造方法传递父类对象
数组及常用算法
一、一维数组
1、声明:
int a[]; int []b;
2、初始化:
动态初始化:1、a=new int[2]; int[0]=1;... 动态初始化:2、b=new b[]{3,4}; 静态初始化:int [] c={5,6};
3、数组常用的方法:
排序:Array.sort(); 查找:Array.binarySearch(); 打印:Array.toString(); 复制:Array.copyof();
4、常用操作
1、冒泡排序 for(int i=0;i<a.length-1;i++){//控制外循环的次数 for(int j=0;j<a.length-1-i;j++){//控制内循环次数,比外循环少一次,与下一个比较 if(a[j]>a[j+1]){ int temp=a[j]; a[j]=a[j+1]; a[j+1]=temp; } } } 2、选择排序 for (int i = 0; i < a.length-1; i++) { int k=i; for (int j = i; j < a.length-1; j++) { if (a[k]>a[j+1]) { k=j+1; } } if(i!=k){ int temp=a[i]; a[i]=a[k]; a[k]=temp; } } 3、顺序查找 public static int find(int []b,int a){ for (int i = 0; i < b.length; i++) { if (a==b[i]) { return i; } } return -1; } 4、二分查找 public static int find(int b[],int a){ int max=b.length-1; int min=0; for (int i = 0; i < b.length; i++) { int midle=(max+min)/2; if(a==b[midle]){ return midle; }else if(a>b[midle]){ min=midle+1; }else if(a<b[midle]){ max=midle-1; } }
return -1;
}
Java常用类
一、装箱拆箱
1、装箱:把基本数据类型转成包装类类型。
2、拆箱:把包装类类型转成基本数据类型。
3、为什么要包装类?
八种基本数据类型不满足面向对象的思想,不包括属性和方法。如果给基本数据类型添加功能,只能创建其包装类,将方法和属性封装进去。 jdk5.0以后出现了自动拆箱,装箱。
4、Integer支持字符串,但字符串必须是数字。Integer integer3=new Integer(“2”);
compareTo(); 比较大小,大返回整数,小于返回负数,相等返回0
toBinaryString(); 将十进制数转成二进制,返回String字符串的表现形式
toHexString(); 将十进制转成十六进制
toOctalString(); 将十进制转成八进制
toString(); 将int类型数据转成String字符串
Integer.valueOf(); 将int转成integer类型对象
new Integer(); 将int转成integer类型对象
parseInt(); 将Integer转成int
intValue(); 将Integer转成int
二、String字符串
== 比较地址
.equals() 比较内容
.equalsIgnoreCase() 忽略大小写比较是否相同
.charAt(); 字符串截取出指定的下标开始
.compareTo() 比较大小
.compareToIgnore() 忽略大小比较
.concat() 将参数字符串连接到指定字符串后面
.contains() 是否包含参数字符串
.startsWith() 以指定前缀开头
.endsWith() 以指定后缀结尾
.indexOf("/") 第一次出现
.indexOf("/", 3) 指定位置开始索引
.lastIndexOf("/") 最后一次出现
.substring(string11.lastIndexOf("/")+1);截取指定位置
.substring(string11.lastIndexOf("/")+1, string11.lastIndexOf("."));//截取字符串,指定开始位置和结束位置
.replace(‘a’, ‘b’) 替换指定字符串,替换所有的
.toUpperCase() 全部转为大写
.toLowerCase() 全部转成小写
.trim() 去掉字符串前后的空格,中间的去不掉
三、StringBuffer
.append(“abckjc”); 追加
.insert(2, “mmm”); 插入
.delete(2, 4); 删除,参数1是起始下标,参数2是结束下标,左闭右开
.reverse(); 逆顺反转
String 长度不可变
StringBuffer 长度可变 线程安全 速度慢
StringBuilder 长度可变 线程不安全 速度快
四、Charcter
.isLetter(‘a’); 判断是否为字母
.isLetter(‘a’); 判断是否为小写字母
isUpperCase(‘A’); 判断是否为大写字母
toLowerCase(‘D’); 将大写字母转成小写字母 如果本身是小写字母 则转换完还是小写字母
toUpperCase(‘f’); 将字母专程为大写字母
五、Boolean
Boolean boolean1=new Boolean(“false”);
System.out.println(boolean1);// true boolean中就是true,写的不是true boolean全都是false
六、正则表达式
字符类
[abc] a、b、c其中任意一个
[^abc] 除了a、b、c中的任意一个
[a-zA-Z] a-z或A-Z范围中的任意一个
[a-zA-Z0-9] a-z A-Z 0-9 其中任意一个
[……] 可以自己定义范围
预定字符类
\d 数字0-9
\D 非数字0-9
\s 空白字符:[ \t\n\x0B\f\r]
\S 非空白字符:\s
\w 单词字符:[a-zA-Z_0-9]
\W 非单词字符\w
数量词
? 一次或者一次也没有
0次到多次
一次或者多次
{n} 恰好n次
{n,} 至少n次
{n,m} 至少n次但不超过m次
.matches(); 匹配是否适合
.spil(); 拆分
七、时间相关的类
1、Date类
.getTime();计算毫秒
2、SimpleDateFormat类 格式化时间
.format();返回的是String字符串
3、Calendar接口 日历字段之间的转换提供了一些方法
.get(Calendar.YEAR); .get(Calendar.MONTH);// 默认是当前月份减一 从0开始的 .get(Calendar.DAY_OF_MONTH); .get(Calendar.DAY_OF_WEEK); Calendar calendar = Calendar.getInstance(); Date date = calendar.getTime();
4、Runtime运行时时间
.freeMemory(); 当前的系统剩余空间
5、System.exit(0);退出程序,参数是0 是正常退出
System.gc();调用垃圾回收器 ,不一定能够起来 ,只是起到一个促进的作用
Java异常处理机制
一、异常
1、在运行时期出现的不正常的事件,从继承的角度看,throwable是错误和异常的超类
2、错误Error:程序员无法处理的严重性问题,资源耗尽,jvm系统内部的错误
异常Exception:程序员可以处理的一般性问题,偶然的外界因素,编程的逻辑性错误
3、处理的必要性角度:
受检异常:编译时期就能发现的异常,必须要去处理的异常,继承自Exception 非受检异常:运行时期发现的异常,不是必须要去处理的,继承自RuntimeException
4、异常的处理机制:
当运行代码的时候首先先碰到异常,首先产生异常对象,抛出给jvm,jvm会携带异常对象,去找代码能够处理或者捕获异常代码, 如果找到了,则交给这个代码去处理,没有找打,则程序停止运行。
5、异常处理的两种方式
1、捕获异常 try{可能会产生异常的代码}catch(异常类 异常对象){处理异常的代码} try{}catch(){}catch(){}... catch中子类异常放在父类异常的上面 try{]catch(){}finally{} finally中的代码一定会被执行到 try{}finally{} 1> 如果不去捕获异常,发生异常,异常后面的代码都不会被执行到 2> 如果捕获异常 try/catch后面的代码会被执行到 3> 捕获异常,try块中异常后面的代码不会被执行到 2、抛出异常 产生异常的位置不去处理异常,由调用此方法的调用者去处理异 throws 方法的声明后面 后面跟的是异常的类名 可以跟多个类名之间用逗号隔开 可以抛出受检异常和非受检异常 throw 方法的内部 异常的对象名 一个对象 抛出非受检异常
6、自定义异常
自定义 受检异常继承Exception 非受检异常 RuntimeException
二、final finally finalize区别
final 最终的,可修饰类,方法,属性
类:不能被继承 方法:不能被重写,可以被继承 属性:全局变量:声明是必须初始化。局部变量:声明的时候可以不初始化。但都只能赋值一次
finally 跟try/catch后面,无论是否发生异常都会被执行。关闭数据库,关闭数据流。
finalize 由系统调用,垃圾回收器回收之前做一些清理的工作。
集合
数组:长度固定,数据类型相同
集合:长度不固定,数据类型可以不同,只能存对象
collection
List Set Vector
ArrayList HashSet
LinkedList TreeSet
Map
HashMap
TreeMap
一、Collection
1、添加元素
add(Objectobj); //add方法的参数类型是Object。以便于接收任意类型对象。
2、删除元素
remove(Objectobj); removeAll(另一集合);//调用者只保留另一集合中没有的元素。 clear();//清空集合
3、判断元素
contains(Objectobj);//判断是否存在obj这个元素 isEmpty();//是否为空
null 没有初始化 只有栈空间没有堆空间
empty 已经初始化了对象 这个容器中没有数据
4、获取个数,集合长度
size();
5、取交集
retainAll(另一集合);//调用者只保留两集合的共性元素。
二、List
List:元素是有序的,元素可以重复。因为该集合体系有索引。
|--ArrayList:底层的数据结构使用的是数组结构。特点:查询速度很快。但是增删稍慢。线程不同步。 |--LinkedList:底层使用的是链表数据结构。特点:增删速度很快,查询稍慢。 |--Vector:底层是数组数据结构。线程同步。被ArrayList替代了。
ArrayList:
增:add();addAll(0,list2); 获取:get(1); 修改:set(); 截取:subList(0, 2);左闭右开
LinkedList:
增:addFirst(); addLast(); jdk1.6后 offFirst(); offLast(); 获取:getFirst(); getLast(); peekFirst(); peekLast(); 删除:removeFirst(); removeLast(); pollFirst(); pollLast(); 压栈:push(); 弹栈:pop(); 逆序输出:linkedList.descendingIterator()
三、Set
Set:元素是无序(存入和取出的顺序不一定一致),元素不可以重复。
|--HashSet:底层数据结构是哈希表。线程不同步。 保证元素唯一性的原理:判断元素的hashCode值是否相同。如果相同,还会继续判断元素的equals方法,是否为true。 |--TreeSet:可以对Set集合中的元素进行排序。默认按照字母的自然排序。底层数据结构是二叉树。保证元素唯一性的依据:compareTo方法return 0。 Set集合的功能和Collection是一致的
1、HashSet: 哈希表
1、可以通过元素的两个方法,hashCode和equals来完成保证元素唯一性。如果元素的HashCode值相同,才会判断equals是否为true。 如果元素的hashCode值不同,不会调用equals。 2、hashcode是内存地址通过一定运算的到的int类型的数值。返回值是int类型的数据,各个属性的hash值。 相加 3、hashcode值相同,也不一定是同一个对象 4、调用hashcode方法可以帮助去过滤调用完全不可能相同的 对象,提高执行效率 5、equals最终确定两个对象是否相同的 @Override public int hashCode() { // TODO Auto-generated method stub int code=name==null?0:name.hashCode(); return code; } @Override public boolean equals(Object obj) { // TODO Auto-generated method stub if(obj==this){ return true; } if (obj==null) { return false; } if (obj instanceof Person) { Person person=(Person)obj; if (this.name.equals(person.name)) { return true; } } return false;
}
2、LinkedHashSet:
1、有序不重复
3、TreeSet:红黑树
1、自然排序,实现Comparable接口,重写compareTo方法 ,系统自动调用
public int compareTo(Student o) { // TODO Auto-generated method stub if (this.score<o.score) { return 1; }else if(this.score>o.score){ return -1; }else { if(this.age<o.age){ return 1; }else if(this.age>o.age){ return -1; }else{ CollationKey collator=Collator.getInstance().getCollationKey(this.name); CollationKey collator2=Collator.getInstance().getCollationKey(o.name); return collator.compareTo(collator2); } } }
2、定制排序,单独一个类实现Comparator接口,重写compare方法(也可用内部类的方法写)
o1 相当于 自然排序中this o2 相当于自然排序中的参数对象 public class ComparatorDemo implements Comparator<Person>{ public int compare(Person o1, Person o2) { //o1本来对象 o2参数对象 //本类比参数大返回1 升序 //本类比参数小返回-1降序 if (o1.getAge()>o2.getAge()) { return -1; }else if(o1.getAge()<o2.getAge()){ return 1; }else { CollationKey collationKey=Collator.getInstance().getCollationKey(o1.getName()); CollationKey collationKey2=Collator.getInstance().getCollationKey(o2.getName()); return collationKey.compareTo(collationKey2); } } } 调用格式:TreeSet<Person> treeSet=new TreeSet<Person>(new ComparatorDemo()); 内部类的写法: TreeSet<Person> treeSet2=new TreeSet<Person>(new Comparator<Person >() { public int compare(Person o1, Person o2) { // TODO Auto-generated method stub if (o1.getAge()>o2.getAge()) { return -1; }else if(o1.getAge()<o2.getAge()){ return 1; }else { CollationKey collationKey=Collator.getInstance().getCollationKey(o1.getName()); CollationKey collationKey2=Collator.getInstance().getCollationKey(o2.getName()); return collationKey.compareTo(collationKey2); } } });
3、主要:
自然排序 测试的TreeSet集合 用无参数的构造方法 定制排序的时候 new TreeSet(Comparator接口对象的)
四、Map
1)该集合存储键值对,一对一对往里存
2)要保证键的唯一性
Map
|--Hashtable:底层是哈希表数据结构,不可以存入null键null值。该集合是线程同步的。JDK1.0,效率低。 |--HashMap:底层是哈希表数据结构。允许使用null键null值,该集合是不同步的。JDK1.2,效率高。 |--TreeMap:底层是二叉树数据结构。线程不同步。可以用于给Map集合中的键进行排序。 初始容量16,加载因子0.75 Map和Set很像。其实Set底层就是使用了Map集合。 1、添加 Vput(K key,V value);//添加元素,如果出现添加时,相同的键,那么后添加的值会覆盖原有键对应值,并put方法会返回被覆盖的值。 voidputAll(Map <? extends K,? extends V> m);//添加一个集合 2、删除 clear();//清空 Vremove(Object key);//删除指定键值对 3、判断 containsKey(Objectkey);//判断键是否存在 containsValue(Objectvalue)//判断值是否存在 isEmpty();//判断是否为空 4、获取 Vget(Object key);//通过键获取对应的值 size();//获取集合的长度
1、HashMap
HashSet底层封装HashMap,所以HashSet中的规律都是用于HashMap的键。值允许重复,允许多个null,键只允许一个null 如果自定义类作为键,需要重写hashcode的和equals方法,保证事物唯一性。如果作为值,则不重写 @Override public int hashCode() { // TODO Auto-generated method stub int code=name==null?0:name.hashCode(); int code2=age; int code3=sex.hashCode(); return code+code2+code3; } @Override public boolean equals(Object obj) { // TODO Auto-generated method stub if (this==obj) { return true; } if (obj==null) { return false; } if (obj instanceof Person) { Person person=(Person) obj; if (this.name.equals(person.name)) { if(this.age==person.age){ if (this.sex.equals(person.sex)) { return true; } } } } return false; }
2、TreeMap
1、自然排序 public int compareTo(Person o) { // TODO Auto-generated method stub if (this.age<o.age) { return 1; }else if (this.age>o.age) { return -1; }else { CollationKey collationKey=Collator.getInstance().getCollationKey(this.name); CollationKey collationKey2=Collator.getInstance().getCollationKey(o.name); return collationKey.compareTo(collationKey2); } } 2、定制排序 单独写一个类 public class GirlCom implements Comparator<Girl> { @Override public int compare(Girl o1, Girl o2) { // TODO Auto-generated method stub if(o1.age>o2.age){ return 1; }else if(o1.age<o2.age){ return -1; }else { if(o1.weight>o2.weight){ return 1; }else if(o1.weight<o2.weight){ return -1; }else { CollationKey collationKey=Collator.getInstance().getCollationKey(o1.name); CollationKey collationKey2=Collator.getInstance().getCollationKey(o2.name); return collationKey.compareTo(collationKey2); } } } } 调用格式:TreeMap< Girl,String > treeMap=new TreeMap< Girl,String>(new GirlCom());
3、Hashtable
如果自定义类作为键,则重写compato方法,如果作为值,则不重写
4、遍历集合的方式:
1、keySet();只得出来值
Set<String> set = map.keySet();//键的集合 //1、迭代 Iterator<String> iterator = set.iterator(); while (iterator.hasNext()) { String key = iterator.next(); System.out.println(map.get(key)); } //2、fore for (String string2 : set) { System.out.println(map.get(string2));// String2是键 }
2、entrySet();键-值对方式
Set<Entry<String, String>> set2=map.entrySet(); //迭代 Iterator<Entry<String, String>> iterator3=set2.iterator(); while (iterator3.hasNext()) { Entry<String, String> kEntry=iterator3.next(); System.out.println(kEntry); } //fore for (Entry<String, String> entry : set2) { System.out.println(entry); }
Java I/O
1、File类
创建:File file = new File(路径字符串); .exists();文件是否存在 .delete();删除文件 .getPath();路径 .isFile());是文件吗 .isDirectory();是目录吗 .getName();名称 .getAbsolutePath();绝对路径 .lastModified();最后修改时间 .length();文件大小,不能判断目录/文件夹 .getParent();父路径,得到指定目录的前一级目录 .getAbsoluteFile();得到文件绝对路径文件 创建: .createNewFile();创建文件 .mkdir();创建一层文件夹 .mkdirs();创建多层文件夹 File(String path) 通过将给定路径名字符串转换为抽象路径名来创建一个新 File 实例 File(String path,String child) 根据 parent 抽象路径名和 child 路径名字符串创建一个新 File 实例。 File(File file,String child)
list() 返回一个字符串数组,这些字符串目录中的文件和目录。
list(FileNameFilter) 返回一个字符串数组,这些字符串指满足指定过滤器的文件和目录。
listFiles 返回一个抽象路径名数组,这些路径名目录中的文件。
listFiles(FileNameFilter) 返回抽象路径名数组,这些路径名满足指定过滤器的文件和目录。
2、遍历文件夹是用递归。
3、流的分类
按流分向:
输入流:从数据源到程序中的流 输出流:从程序到数据源的流
按数据传输的单位:
字节流:以字节为单位传输数据的流 字符流:以字符为单位传输数据的流
按功能分:
节点流:直接与数据源打交道的流 处理流:不直接与数据源打交道,与其他流打交道
4、流类
字节流 字符流
输入流 InputStream 超类,抽象类 Reader 超类,抽象类
输出流 OutputStream 超类,抽象类 Write 超类,抽象类
5、流
read() 一个字节一个字节的读 返回值是读取到得数据的int表现形式
read(byte[]) 把字节读取到数组中 返回 的是读取到的个数 返回:读入缓冲区的字节总数,如果因为已经到达文件末尾而没有更多的数据,则返回 -1。
read(byte[],int offset,int length)
指定的数组中偏移的个数 指定的数组的下标 存储数据的长度
字符流
FileInputStream 字节流 输入流 节点流 直接操作文件的 read(); read(byte[]); read(byte[],off,,len); (byte[]接受数据,返回值!=-1) FileOutputStream 字节流 输出流 节点流 write(int); write(byte[]); write(bute[],off,len); File file = new File("E:\ceshi.wmv");// 源文件 File file2 = new File("E:\aaa\ceshi.wmv");// 目标文件 // 1、创建流对象 FileInputStream fis = new FileInputStream(file); FileOutputStream fos = new FileOutputStream(file2); // 2、读取文件 byte[] bs = new byte[1024]; int num = 0; while ((num = fis.read(bs)) != -1) { fos.write(bs); } // 3、刷新 fos.flush(); // 4、关闭流
字符流
FileReader 字符流 输入流 节点流 read(char[]); (char[]接收数据,返回值!=-1) FileWriter 字符流 输出流 节点流 write(char,offset,length); 循环读取判断 !=-1 File file=new File("E:\22.txt"); File file2=new File("E:\aa\22.txt"); FileReader fileReader=new FileReader(file); FileWriter fileWriter=new FileWriter(file2); char [] ch=new char[4]; int num=0; while((num=fileReader.read(ch))!=-1){ fileWriter.write(ch,0,num); } fileWriter.flush(); 关闭流
复制文件的流程
1、创建流对象
2、读取文件的文件(循环读取)FileInputStream、FileReader
3、写入目标文件 FileOutputStream、FileWriter
4、刷新关闭
缓冲流
BufferedInoutStream 字节流 输入流 处理流 (byte[]接受数据,返回值!=-1)
BufferedOutputStream 字节流 输出流
BufferedReader 字符流 输入流 (String接受数据,返回值!=null)resdLine();
BufferedWriter 字符流 输出流
readLine();读取一行,返回值String 循环读取判断 !=null newLine();换行 \r\n换行 BufferedInputStream bis=new BufferedInputStream(new FileInputStream(new File("E:\ceshi.wmv"))); BufferedOutputStream bos=new BufferedOutputStream(new FileOutputStream(new File("E:\aa\ceshi.wmv"))); byte []bs=new byte[1024]; int num=0; long time=System.currentTimeMillis(); while((num=bis.read(bs))!=-1){ bos.write(bs,0,num); } bos.flush(); 关闭流
转换流
字节转字符 InputStreamReader 继承自Reader (String接收数据,返回值!=null)
字符转字节 OutputStreamWriter 继承自Wriiter
BufferedReader bufferedReader=new BufferedReader(new InputStreamReader(new FileInputStream( new File("E:\ceshi.wmv")))); BufferedWriter bufferedWriter=new BufferedWriter(new OutputStreamWriter(new FileOutputStream(new File("E:\aa\demo\ceshi.wmv")))); String string=null; while((string=bufferedReader.readLine())!=null){ bufferedWriter.write(string); } bufferedWriter.flush(); 关闭流
对象流
ObjectInputStream readObject();
ObjectOutputStream writeObject(Object obj);
1、用对象流去存储对象的前提是 将对象序列化 实现接口Serializable
2、序列化和反序列化(将对象持久化储存)
将对象转成字节叫序列化 将字节转成对象叫反序列化
3、序列化ID,帮助区分版本,可写可不写。
4、transient修饰不想被序列化的属性,存储默认值
Person person =new Person("秋秋", 22); Person person2=new Person("菜菜", 21); ObjectOutputStream objectOutputStream=new ObjectOutputStream(new FileOutputStream(new File("a.txt"))); objectOutputStream.writeObject(person); objectOutputStream.writeObject(person2); objectOutputStream.flush(); if (objectOutputStream!=null) { objectOutputStream.close(); } ObjectInputStream objectInputStream=new ObjectInputStream(new FileInputStream(new File("a.txt"))); Person person3=(Person) objectInputStream.readObject(); System.out.println(person3); Person person4=(Person) objectInputStream.readObject(); System.out.println(person4); if (objectInputStream!=null) { objectInputStream.close(); }
数据包装流(了解)字节流,读取字节
DataInputStream DataOutputStream 1、新增了很多读取和写入基本数据类型的方法 2、读取的顺序和写入的顺序一样,否则数据内容会和存入时的不同 DataOutputStream dataOutputStream = new DataOutputStream(new FileOutputStream(new File("b.txt"))); dataOutputStream.writeInt(22); dataOutputStream.writeLong(34567); dataOutputStream.writeBoolean(true); dataOutputStream.flush(); if (dataOutputStream != null) { dataOutputStream.close(); } DataInputStream dataInputStream = new DataInputStream(new FileInputStream(new File("b.txt"))); System.out.println(dataInputStream.readInt()); System.out.println(dataInputStream.readLong()); System.out.println(dataInputStream.readByte()); if (dataInputStream != null) { dataInputStream.close(); }
标准输入/输出/错误流
System.in 会阻塞程序的运行等待用户输入
System.out 将内容打印到控制台上
System.err 将内容打印到控制台上,颜色是红色
标准输入/输出/错误流的重定向
System.setIn()
System.setOut()
System.setErr()
1、重定向的方法一定要放在标准输入输出错误流的前面
打印流
PrintStream 字节打印流 可以new可以通过System.out得到
PrintWriter 字符打印流 new
内存流
ByteArrayInputStream 输入流 (byte[]接受数据,返回值!=-1)
ByteArrayOutputStream 输出流
1、toByteArray() 返回值是byte,内存输出流调用的,byte[] bs=byteArrayOutputStream.toByteArray();
//将内存中的数据转化成byte数组
2、writeTo(OutputStream) 将内存流中的数据直接写入参数流中
// 1、创建文件输入流,读取文件内容 BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(new File("E:\11.txt"))); // 2、创建内存输入流,将读取后的文件存到内存中 ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); byte[] bs = new byte[1024]; int num = 0; // 3、循环读取文件内容 while ((num = bufferedInputStream.read(bs)) != -1) { // 4、将文件写入内存中 byteArrayOutputStream.write(bs,0,num); byteArrayOutputStream.flush(); 将内存中的数据转化成byte数组 byte[] bs2 = byteArrayOutputStream.toByteArray();因为读取的时候需要数组,所以在这儿写 System.out.println("---" + new String(bs2)); // 5、创建内存输入流。读取内存中的数据 ByteArrayInputStream byteArrayInputStreamnew = new ByteArrayInputStream(bs2); // 7、创建文件输出流,将内存中的文件 读取到我文件中 BufferedOutputStream bufferedOutputStream = new BufferedOutputStream( new FileOutputStream(new File("E:\aaa\11.txt"))); byte[] bs3 = new byte[1024]; int num2=0; // 8、循环读取内存中的数据 while ((num = byteArrayInputStreamnew.read(bs3)) != -1) { System.out.println("~~~" + new String(bs3)); // 9、写入到文件中 bufferedOutputStream.write(bs3,0,num2); bufferedOutputStream.flush(); } //10、关闭各种流
随机读写流:在线程中使用较多
RandomAccessFile 字节流,即可以读又可以写 // 1、文件的长度 File file = new File("E:\ceshi.wmv"); System.out.println(file.length()); int tlen = 0; if (file.exists()) { tlen = (int) file.length(); //判断文件并计算文件总长度 } int len = tlen % 4 == 0 ? tlen / 4 : tlen / 4 + 1; //计算每一段长度 int last = tlen - len * 3; //最后一段长度=总长度-前三段长度 Copy copy = new Copy(0, len); copy.start(); //第一段长度从0到len Copy copy2 = new Copy(len, len); copy2.start(); Copy copy3 = new Copy(len * 2, len); copy3.start(); Copy copy4 = new Copy(len * 3, len);copy4.start(); } } class Copy extends Thread { int star = 0; int leng = 0; public Copy(int star, int leng) { super(); this.star = star; this.leng = leng; } public void run() { RandomAccessFile read = null; RandomAccessFile write = null; read = new RandomAccessFile(new File("E:\ceshi.wmv"), "rw"); System.out.println(Thread.currentThread().getName() + "开始!!!"); write = new RandomAccessFile(new File("E:\aaa\bb\ceshi.wmv"), "rw"); read.seek(star); write.seek(star); byte[] bs = new byte[1024]; int num = 0; int readlength = 0; while (true) { if (leng - readlength < 1024) { read.read(bs, 0, leng - readlength); write.write(bs, 0, leng - readlength); break; } else { num = read.read(bs); write.write(bs, 0, num); readlength += num; } } System.out.println(Thread.currentThread().getName() + "完成~~~");
Java多线程
一、线程和进程
1、线程
注意:多线程。从宏观角度同时执行了多个线程。
从微观角度同一时间只能执行一个线程 多个线程是竞争关系,抢占cpu资源,否则只能等待。
2、进程和线程的区别:
进程是应用程序,线程是一条执行路径 进程有独立的内存空间,崩溃不会影响其他程序, 线程没有独立的空间,多个线程在同一个进程的空间,可能会影响其他线程 一个进程中,至少有一个线程
3、主线程子线程
主线程:main方法产生的线程,也叫作UI线程。 子线程:除了主线程以外的,也叫工作线程。
4、创建线程的两种方式
1、创建一个类继承Thread 2、重写run方法 3、创建线程对象 4、启动线程 5、Thread.currentThread().getName(),哪个线程调用,名字就是哪个现成的名字 getName();super调用父类的getName(),被赋值谁的名字,就打印谁的名字 main方法: Test2 test=new Test2("一号窗口");test.start(); Test2 test2=new Test2("二号窗口");test2.start(); class Test2 extends Thread{ String name; int ticket=10; public Test2(String name) { super(name); this.name = name; } public void run() { while (true) { if (ticket>0) { ticket--; System.out.println(Thread.currentThread().getName()+"还剩下"+ticket); }else { break;} } }
共享资源操作相同
1、共享资源类实现Runable接口
2、重写run方法
3、创建共享资源对象
4、创建线程对象,将共享资源对象添加到线程中
5、启动线程
main方法: Test3 test3=new Test3(); Thread thread=new Thread(test3); Thread thread2=new Thread(test3); thread.start(); thread2.start(); class Test3 extends Thread{ String name; int ticket=10; public Test2(String name) { super(name); this.name = name; } public void run() { while (true) { if (ticket>0) { ticket--; System.out.println(Thread.currentThread().getName()+"还剩下"+ticket); }else { break;} } }
贡献资源操作不相同
1、贡献资源作为一个单独的类
2、由多个操作去实现Runable接口
3、把共享资源作为多个操作类的属性
4、创建线程对象,将共享资源对象添加到线程中
5、启动线程
main方法: Card card=new Card(); Boyfriend boyfriend=new Boyfriend(card); Girlfriend girlfriend=new Girlfriend(card); Thread thread=new Thread(boyfriend); Thread thread2=new Thread(girlfriend); thread.start(); thread2.start(); class Card{ double money; } class Boyfriend implements Runnable{ Card card; public Boyfriend(Card card){ this.card=card; } @Override public void run() { // TODO Auto-generated method stub for (int i = 0; i < 5; i++) { card.money+=500; System.out.println(Thread.currentThread().getName()+"存500-剩余金额"+card.money); } } } class Girlfriend implements Runnable{ Card card; public Girlfriend(Card card){ this.card=card; } @Override public void run() { // TODO Auto-generated method stub for (int i = 0; i < 5; i++) { card.money-=500; System.out.println(Thread.currentThread().getName()+"取500,剩余金额"+card.money); } } }
5、run和start的区别
run没有开辟新的栈空间,没有新线程,都是主线程在执行
start开辟了新的栈空间,在新的栈空间启动run()方法
6、线程的调度
setPriority();分配优先级,默认5,最低1,最高10
.join();插队,阻塞指定的线程等到另一个线程完成以后再继续执行
.sleep();需要设置睡眠时间 .yield();礼让,当执行到这个方法时,会让出cpu时间,立马变成可执行状态
sleep和pield的区别:
sleep yeild 线程进入被阻塞的状态 线程转入暂停执行的状态
(没有其他线程运行)等待指定的时间再运行 马上恢复执行的状态
其他线程的执行机会是均等的 将优先级或更高的线程运行
7、打断线程的终止方式
1、用标记,当终止线程时,会执行完run方法
2、stop()方法,不建议使用,会执行不到特定的代码
3、interrupt(),只能中断正在休眠的线程,通过抛异常的方法中断线程的终止。
InputStream inputStream=System.in; int m=inputStream.read(); myThread2.interrupt();//通过外界输入打断
8、线程是五种状态
新建 就绪 执行 死亡 阻塞
二、同步
发生在两个以两个以上的线程中
解决代码的重复问题
优点:提高了线程中数据的安全性
缺点:降低了执行效率
1、同步代码块
synchronized(锁){同步代码块}
注意:锁分任意锁和互斥锁,锁是对象,琐是唯一的。
2、同步方法
public synchroinzed 返回值类型 方法名(){同步代码}
3、在共享资源中:
线程操作相同,琐是this synchronized (this) {// 同步代码块,包含同步代码块。任意锁,互斥锁。 if (ticket > 0) { System.out.println(Thread.currentThread().getName() + "---" + ticket--); } else { break; } } 线程操作不相同,琐是共享资源对象 synchronized (card) { card.setMoney(card.getMoney() + 1000); System.out.println("Boy+1000---" + card.getMoney()); }
4、在同步方法中:
共享资源,线程操作相同,资源类中的锁是this 共享资源,线程操作不相同,资源类中的锁也是this public synchronized void input(){ money+=100; System.out.println("input+100----"+money); }
5、在静态方法中同步:懒汉式
同步代码块,琐是类.class
同步方法,锁也是类.class
public static LazyInstance getInstance(){ if (instance==null) { synchronized (LazyInstance.class) { if (instance==null) { try { Thread.sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } instance=new LazyInstance(); } System.err.println(instance.hashCode()); } } return instance; }
三、经典例子:生产者消费者
面包类:class Bread{属性和构造方法}
超市类:class Market{
Bread[] breads=new Bread[];//超市里有面包数组 int index=-1;//一开始没有面包,下标为-1; public synchronized void sale(){ if(index<=-1){如果没有没有面包,就等待添加 this.wait(); } 如果有面包,就打印面包信息 System.out.println("消费面包"+breads[index].id+breads[index].name+breads[index].price); index--;//面包减少一个 this.notify();唤醒添加线程 } public synchronized vide add(Bread bread){ if(index>=4){ this.wait(); } indenx++;//面包下标+1,存入下一面包位置中 breads[index]=bread;//给数组中的面包赋值 System.out.println("添加面包"+breads[index].id+breads[index].name+breads[index].price); this.notify();//唤醒销售线程 }
工厂类:实现Runnable接口:
将超市类作为属性 添加构造方法 重写run方法,调用超市类add方法
顾客类:实现Runnable接口:
将超市类作为属性 添加构造方法 重写run方法,调用超市类sale方法
Java网络编程
1、计算机网络:
将多态计算机,通过网络通信连接到一起,实现了资源的共享和信息的传递
2、计算机网络的分类:
广域网,城域网,局域网。
3、参考模型
4、tcp/ip协议
:tcp、udp、ip
5、tcp特点:
面向连接,数据安全可靠,效率偏低,传输数据大小无限制
6、 udp特点:
面向无连接,数据安全不可靠,执行效率高,数据大小不超过64kb
注意:tcp和udp只是传输协议,只是设定了规范,真正传输的数据ip协议。
ip协议:将数据从源传递到目的地 ipv4:32位 ipv6:128位 ipconfig 查看ip相关信息 ping 查看指定ip或者地址能不能连通
7、IP编程:
1、InetAddress, 没有构造方法,只能通过自己的静态方法创建对象 2、getLocalHost(), 返回值是InetAddress,得到本机的主机名和地址 3、getByName(ip), 返回值是InetAddress,有参数,可以写ip,网址,得到指定的主机 4、getHostAddress(), 得到主机的地址 5、getHostName(), 得到指定的主机名
8、TCP编程
客户端: 1、创建socket对象,指定ip地址和端口号 2、需要从socket中得到OutputStream 聊天配合字符流输入流使用,直接转换输入输出即可 文件配合字节流使用,字节流读,socket输出。 3、将想要发送的数据写入到OutputStream中。flush 4、关闭流关闭socket 服务器: 1、创建ServerSocket对象,指定端口号 2、serversocket.accep(),返回一个Socket对象(客户端发过来的socket) 接收客户端发送的数据,如果没有接收到,阻塞程序的运行 3、从Socket中得到InputStream流,将数据从流中读取出来 聊天配合字符输出流使用。 文件配合字节输出流使用,socket读,字节流输出。 4、展示/写入到另外的地方 5、关闭流,关闭Socket 聊天: 聊天客户端: Socket socket=new Socket("127.0.0.1", 65499); OutputStream outputStream=socket.getOutputStream(); BufferedWriter bufferedWriter=new BufferedWriter(new OutputStreamWriter(outputStream)); InputStream inputStream=socket.getInputStream(); BufferedReader bufferedReader=new BufferedReader(new InputStreamReader(inputStream)); Scanner scanner=new Scanner(System.in); while (true) { System.out.println("客户端:"); String string=scanner.next(); bufferedWriter.write(string); bufferedWriter.newLine(); bufferedWriter.flush(); if (string.equals("拜拜")) { break; } //接收数据 String string2=null; string2=bufferedReader.readLine() ; System.out.println("服务器回复:"+string2); } //关闭流和socket 聊天服务器: ServerSocket serverSocket=new ServerSocket(65499); System.out.println("服务器等待中。。。"); Socket socket=serverSocket.accept(); InputStream inputStream=socket.getInputStream(); Scanner scanner=new Scanner(System.in); BufferedReader bufferedReader=new BufferedReader(new InputStreamReader(inputStream)); OutputStream outputStream=socket.getOutputStream(); BufferedWriter bufferedWriter=new BufferedWriter(new OutputStreamWriter(outputStream)); String string=null; while (true) { string=bufferedReader.readLine(); System.out.println("客户端说"+string); if (string.equals("拜拜")) { break; } System.out.println("服务器回复:"); String string2=scanner.next(); bufferedWriter.write(string2); bufferedWriter.newLine(); bufferedWriter.flush(); } //关闭各种流和socket等
9、UDP编程
客户端: 1、创建套接字对象,DatagramSocket,不需要指定端口号和地址 (聊天配合字符输入流),文件配合字节输入流 2、创建数据报包对象DatagramPacket,使用四个参数,指定数据,数据长度,地址,端口号。 3、send发放发送数据 4、关闭socket 服务器: 1、创建套接字对象DatagramSocket,指定端口号 2、创建数据报包对象DatagramPacket,用两个参数的。指定数据和数据长度。 3、receice()接收数据,如果接受不到,阻塞程序。 4、根据数据报包进行一系列需要的操作 聊天: 客户端: DatagramSocket datagramSocket=new DatagramSocket(); BufferedReader bufferedReader=new BufferedReader(new InputStreamReader(System.in)); while (true) { System.out.println("客户端--:"); String string2=bufferedReader.readLine(); DatagramPacket datagramPacket=new DatagramPacket(string2.getBytes(), string2.getBytes().length, InetAddress.getLocalHost(),65496); datagramSocket.send(datagramPacket); if (string2.equals("拜拜")) { break; } byte []buf=new byte[1024]; DatagramPacket datagramPacket2=new DatagramPacket(buf, buf.length); datagramSocket.receive(datagramPacket2); String string=new String(datagramPacket2.getData(), 0, datagramPacket2.getLength()); System.out.println("服务器--"+string); } 服务器: DatagramSocket datagramSocket = new DatagramSocket(65496); BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in)); System.out.println("客户端已准备"); byte[] buf = new byte[1024]; while (true) { DatagramPacket datagramPacket = new DatagramPacket(buf, buf.length); datagramSocket.receive(datagramPacket); String string = new String(datagramPacket.getData(), 0, datagramPacket.getLength()); if (string.equals("拜拜")) { break; } System.out.println("我说~~"+string); //回复数据 System.out.println("你说~~:"); String string3 = bufferedReader.readLine(); DatagramPacket datagramPacket2 = new DatagramPacket(string3.getBytes(), string3.getBytes().length, InetAddress.getLocalHost(), datagramPacket.getPort()); if (string3.equals("拜拜")) { break; } datagramSocket.send(datagramPacket2); }
反射机制
1、反射:
反射是将类中的属性,方法,构造方法等解剖成一个个小的对象,并且能够调用
2、为什么使用反射:
在一个类中,可以创建另外一个类的对象,调用其的属性和方法,无论那个类是否被创建了。
3、如何使用反射:
类 Class class=Class.forName(包名.类名),每一个类都有唯一的一个类对象,这个类对象可以的得到类中的所有信息。 构造方法 class.getConstructor(null); 得到无参构造方法,返回Constructor class.getConstructor(String.clss,int.class);得到有参构造方法,返回Constructor constructor2.newInstance("曹菜菜",21); 返回Object类型的对象 class.getConstructors(); 得到所有构造方法,返回Constructor[]数组 方法 getMethod(); 得到普通的方法,返回Method,指定方法名 class1.getMethod("eat", null); 无参、无返回值、非私有的方法。 class1.getMethod("play", String.class); 有参、无返回值。非私有方法。参数一,方法名。参数二,参数类型.class method(n).invoke(object,null); 方法的执行,参数一是对象,参数二是传的参数值。 getMethods(); 得到子类和父类所有普通的方法,返回Method[]数组 class1.getDeclaredMethod("sleep", null);得到私有的方法 method6.setAccessible(true); class1.getDeclaredMethods(); 得到自己类的所有方法,包括私有的,返回Method[] 属性 getFields(); 得到public所有属性,返回Field[] getFileld("name"); 得到public属性,返回Field,指定属性名 field3.set(object5, "菜菜"); Object object6 = field3.get(object5); getDeclareFields(); 得到所有属性,包括私有的,返回Field[] getDeclareField(); 得到属性,包括私有的,指定属性名,返回Field
4、反射的优点
1、提高了java程序的灵活性和扩展性,降低了耦合性,提高了自适应的能力 2、允许程序创建和控制任何类的对象,无需提前编码目标类
5、反射的缺点
1、性能问题 2、代码维护问题
HTML& SQLite
一、HTML
标签:
换行<br>、段落<p>、超链接<a href="网址">、图片 删除线<del>、下划线<u>、加粗<b>、倾斜<i>、标题<h1-h6>、文字样式<font size color> 横线<hr size width color>、空格 、 有序列表<ol> <li> </li></ol> 无序列表<ul> <li> </li></ul> 多个列表嵌套<ol><li> <ol><li></li></ol> </li></ol>
锚点:
<a name="a"><img src=""/></a> <a href="#a">超链接</a>
form表单:
文本按钮多选等:<input type="" name=""/> 下拉列表:<select><option>内容</option></select> 多行文本:<textarea conslpan="" rowspan=""></textarea>
表格:
<table><tr><td></td></tr></table>可设置跨列跨行
CSS层叠样式:
<style> 标签选择器:标签名{} id选择器:#选择器的名字 id="#名" 类选择器:.选择器的名字 class=".名字" </style>
JS:
在head标签中写,页面上想要动态的去展示或操作页面的时候
二、SQLite
固定语句:
Class.forName("org.sqlite.JDBC");加载驱动 Connection connection=DriverManager.getConnection("jdbc:sqlite:/e:/SQLite/day0919-1.db");创建连接 Statement statement=connection.createStatement();创建执行sql语句的对象 1、创建表 create table [if not exists] tablename(_id integer primary key autoincrement,name vachar(15)....); 2、追加列 alter table tablename add 字段名 integer 3、插入数据 insert into tablename(id,name...)values(1,'aa'); 4、查询数据 select * from tablename where name='aa'; 5、修改数据 update tablename set name='aa' where name='aa'; 6、删除数据 delete from tablename where name='aa' 7、模糊查询 select * from tablename where name like '%aa%'; 8、升序 select * from employees order by id ; 9、降序 select * from employees order by id desc; 10、多字段 select * from employees order by department_id desc,salary asc; 11、and or 执行语句: statement 用于查询(executequery)删除(executeupdate)修改(executeupdate) preparastatement 用于插入(executeupdate) 注意:insert into tablename(id,name...)values(?,?,?...); preparedStatement.setString(1, id);//用占位符的时候需要prepareStatement设置
Servlet
1、浏览器和服务器的交互 请求/响应式交互
1>浏览器先发送请求给服务器 2>指定的servlet去接收 (根据method属性值如果是post则调用doPost,如果不是则 调用doGet) 3>在servlet中动态的执行逻辑代码,也可以动态给浏览器发送数据 4>服务器响应浏览器的请求
2、C/S结构:客户端/服务器
优势:充分利用两端硬件的优势,提高了执行效率 劣势:必须安装客户端软件,维护客户端的更新
3、B/S结构:浏览器/服务器
优势:操作简单,不需要下载软件。只需要网络 劣势:将所有的操作全部交给服务器处理,增加了服务器的压力。
4、页面跳转:
request.getRequestDispatcher("new.jsp").forward(request, response); 地址栏显示servelet的名字?属性名=属性值&...,可以将前一个网页的值传递过去。
5、重定向:
response.sendRedirect("new.jsp"); 地址栏中显示指定页面的值。不能传递数据。
6、request
request.getParameter("useName");括号内写的是输入框的名字。 request.getParameterValues("hobby");复选框,返回数组。 requst.setAttribute(属性的名字,属性值) requst.getAttribute(属性名字),在另一个页面中写。 doGet() name = new String(name.getBytes("iso-8859-1"),"utf-8") doPost() 给requst设置统一的编码格式 (要在得到表单中内容之前调用) request.setCharacterEncoding("utf-8");
7、response
response.sendRedirect("new.jsp");地址栏中显示的是 指定页面的地址。
8、请求方式:
get: 1、可以缓存 2、请求保留在浏览器的历史中 3、可以收藏为书签 4、处理敏感数据时不能用 5、数据的长度有限制 6、数据在URL中对所有人可见 7、数据类型必须使用ASCII编码。 8、安全性差 post: 1、不可以缓存 2、请求不保留在浏览器的历史中 3、不可以收藏为书签 4、数据的长度无限制 5、数据在URL中不可见 6、数据类型无限制 7、安全在好
9、生命周期:
http请求→解析请求→创建servlet实例→调用init()方法→调用service方法→输出响应信息→响应
10、错误提示
404没有找到页面 500服务器发生错误,一般代码有误 200正确连接
HttpClient& HttpURLConnection&OkHttpClient
一、HttpClient
1、get方法
1、创建对象 HttpClient client = new DefaultHttpClient(); 2、创建请求方式对象,参数是地址 HttpGet get = new HttpGet("path"); 3、客户端发出请求,服务器进行响应 HttpResponse response = client.execute(get); 4、判断是否成功,得到状态信息 if(response.getStatusLine().getStatusCode()==200){ 5、获取数据,entity 得到返回数据的"实体" HttpEntity entity = response.getEntity(); InputStream inputStream = entity.getContent(); // 通过entityUtils工具类可以将 返回数据直接 格式化成 String字符串 String result = EntityUtils.toString(httpEntity); // 可以将entity转化成byte数组 (下载图片) byte[] bs = EntityUtils.toByteArray(entity);
2、post方法
1、创建httpclient对象 HttpClient client = new DefaultHttpClient();
2、创建请求方式对象,参数是地址 HttpPost post = new HttpPost(path);
3、创建BasicNameValuePair对象 BasicNameValuePair pair = new BasicNameValuePair(“useName”, “李四”);
4、创建可以盛放参数的对象 List list = new ArrayList();
5、将参数封装到 httpEntity中 HttpEntity entity = new UrlEncodedFormEntity(list);
6、将带有参数的实体放入进httpPost中 post.setEntity(entity);
7、客户端请求数据 ,服务器端作出相应 HttpResponse response = client.execute(post);
8、 判断是否成功 if(response.getStatusLine().getStatusCode()==200){
HttpEntity entity2 = response.getEntity(); String result = EntityUtils.toString(entity2);
二、HttpURLConnection
1、get方法
1、统一资源定位符 URL url=new URL(path); 2、打开连接,向下转型 HttpURLConnection httpURLConnection=(HttpURLConnection) url.openConnection(); 3、设置请求方式 httpURLConnection.setRequestMethod("GET"); 4、连接服务器,可写可不写 httpURLConnection.connect(); 5、接收数据,先判断是否正确连接 if (httpURLConnection.getResponseCode()==200) { 6、从从httpURLConnection取得数据 InputStream inputStream=httpURLConnection.getInputStream(); 7、读取数据等其他操作 BufferedReader bufferedReader=new BufferedReader(new InputStreamReader(inputStream, "utf-8"));
2、post
1、统一资源定位符 URL url=new URL(path); 2、打开连接,向下转型 HttpURLConnection httpURLConnection=(HttpURLConnection) url.openConnection(); 3、设置请求方式 httpURLConnection.setRequestMethod("GET"); 4、设置post属性 httpURLConnection.setDoOutput(true); httpURLConnection.setDoInput(true);、 5、设置传递的数据(输出流) OutputStream outputStream=httpURLConnection.getOutputStream(); outputStream.write(string.getBytes()); outputStream.flush(); 6、判断服务器响应码 if(httpURLConnection.getResponseCode()==200){ 7、从httpURLConnection取得数据 InputStream inputStream=httpURLConnection.getInputStream(); 8、读取数据等其他操作 BufferedReader bufferedReader=new BufferedReader(new InputStreamReader(inputStream, "utf-8"));
三、OkHttpClient
1、get方法
1、创建客户端对象 OkHttpClient okHttpClient=new OkHttpClient(); 2、创建请求,使用构建起模式,通过自己的静态内部类创建对象并赋值 Request request=new Request.Builder().url(path).build(); 3、通过客户端发送请求,获取响应 Response reponse=okHttpClient.newCall(request).execute(); 4、判断是否成功 if(reponse.isSuccessful()){ //通过响应得到响应的内容 String result=response.body().string();//字符串 byte[] bs=response.body().bytes();//byte数组(图片,文件等)}
2、post方法
1、创建OkHttpCilent对象 OkHttpClient okHttpClient=new OkHttpClient(); 2、将post请求需要传递的参数放置到自己的对象中 RequestBody body=new FormBody.Builder().add("","").add("","").build(); 3、如果想要实现post请求,必须创建requst对象时,调用post方法 传递RequstBodyRequest request = new Request.Builder().url(path).post(body).build();调用post方法 证明是post请求 4、客户端请求,服务端响应 Response response = client.newCall(request).execute(); 5、判断是否成功 if(reponse.isSuccessful()){ //通过响应得到响应的内容 String result=response.body().string();//字符串 }
XML解析&JSON解析
一、XML解析
xml和html的区别:
HTML XML 可扩展性 不具有扩展性 是元标记语言,可定义新的标签 侧重点 如何显示信息 如何结构化的描述信息 语法要求 不要求标记的嵌套配对顺序等 严格要求标记的嵌套配对顺序等 可读性可维护性 难阅读维护 结构清晰便于阅读维护 数据和显示 内容描述和显示方式融合一起 内容描述和显示方式相分离 保值性 不具有保值性 具有保值性
1、xml:可拓展的标记语言。
xml的命名规范: 允许英文字母,数字,
只允许字母和下划线开头, 不能使用空格,区分大小写, 属性值必须用""引起来,不能交叉使用。
2、解析:
Dom:先将整个文档全部加载在内存中,然后以树的结构去解析 优点:解析速度快 缺点:浪费内存 Sax:
根据结点去解析,不会将这个文档全部加载内存中
区分文档开始、标签开始、数据、标签结束、文档结束 缺点:不会记录读取到哪一个标签,需要自己标记 SAXParserFactory factory=SAXParserFactory.newInstance(); SAXParser parser=factory.newSAXParser(); MyHandler myHandler=new MyHandler(); parser.parse("student2.xml",myHandler); List<Student> list=myHandler.result(); MyHandle List<Student> students=null; Student student=null; String tag=""; public List<Student> result(){ return students; } @Override public void startDocument() throws SAXException { students=new ArrayList<>(); } @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { //qName当前解析的标签 //开始标签 tag=qName; if ("student".equals(qName)) { student=new Student(); //标签内有多个属性时 //int count=attributes.getLength(); //for (int i = 0; i < count; i++) { //String name=attributes.getQName(i); //String value=attributes.getValue(i); //if ("id".equals(name)) { //student.setId(Integer.parseInt(value)); //} //} //标签内只要一个属性时 student.setId(Integer.parseInt(attributes.getValue(0))); } } @Override public void endElement(String uri, String localName, String qName) throws SAXException { // TODO Auto-generated method stub //遇到结束标签进入 if ("student".equals(qName)) { students.add(student); } tag=""; } @Override public void endDocument() throws SAXException { // TODO Auto-generated method stub super.endDocument(); } @Override public void characters(char[] ch, int start, int length) throws SAXException { // TODO Auto-generated method stub String count=new String(ch, start, length).trim(); if ("id".equals(tag)) { student.setId(Integer.parseInt(count)); }else if ("name".equals(tag)) { student.setName(tag); }else if ("age".equals(tag)) { student.setAge(Integer.parseInt(count)); }else if ("sex".equals(tag)) { student.setSex(count); } }
Pull:
android中的解析方式
解析数据的时候可以记录标签 1、得到pull解析对象的工厂对象 XmlPullParseFactory factory=XmlPullParseFactory.newInatance(); 2、通过工厂对象得到解析对象 XmlPullParse parse=factory.newPullParse(); 3、设置解析数据源 parse.setInput(new FileReader(".xml")); 4、设置解析文件中事件的状态 int type=parse.getEventType(); 5、存放解析结果的集合 Lst<Student> student=null; 6、声明解析对象 Student student=null; 7、判断状态,根据状态取得数据。 if(type!=XmlPullParse.END_DOCUMENT){ switch(type){ case XmlPullParse.START_DOCUMENT: student=new ArrayList<>(); break; case XmlPullParse.START_TAG: if("student".queals(parser.getName())){ student=new Student(); }else if("id".equals(parse.getName())) String id=parse.nextInt(); student.setId(Integer.parseInt(id)); ...... } } 8、事件的状态进行下一个 type=parse.next(); } 9、若标签中有很多属性 int count=parser.getAttributeCount(); for (int i = 0; i <count; i++) { String arrName=parser.getAttributeName(i); String arrValue=parser.getAttributeValue(i); if ("id".equals(arrName)) { student.setId(Integer.parseInt(arrValue)); }
3、用途:结构化的保存信息,通过服务端和服务器交互使用的,设置配置信息。
二、JSON解析
1、JSON
1、对象 JSONObject jsonObject=new JSONObject(string);
2、数组 JSONArray jsonArray=new JSONArray(string);
3、对象里对象 JSONObject jsonObject2=jsonObject.getJSONObject(“dept”);
4、对象里数组 JSONArray jsonArray=jsonObject.getJSONArray(“persons”);
例子:
String string="{persons:[{name:'zhangsan',age:20},{name:'lisi',age:21},{name:'wangwu',age:22}]}"; JSONObject jsonObject=new JSONObject(string); JSONArray jsonArray=jsonObject.getJSONArray("persons"); List<Person3> list=new ArrayList<>(); for (int i = 0; i < jsonArray.length(); i++) { JSONObject jsonObject2=jsonArray.getJSONObject(i); String name=jsonObject2.getString("name"); int age=jsonObject2.getInt("age"); Person3 person3=new Person3(name, age); list.add(person3); } for (Person3 person3 : list) { System.out.println(person3); } } } class Person3{ String name; int age; public Person3(String name, int age) { super(); this.name = name; this.age = age; } @Override public String toString() { return "person2 [name=" + name + ", age=" + age + "]"; } }
2、Gson
Gson gson=new Gson(); Person6 person6=gson.fromJson(string, Person6.class);
例子:
String string = "{no:1,name:'android',employees:[{name:'zhangsan',age:20},{name:'lisi',age:21},{name:'wangwu',age:22}]}"; Gson gson=new Gson(); Person6 person6=gson.fromJson(string, Person6.class); System.out.println(person6);、 } } class Person5{ @Override public String toString() { return "Person5 [name=" + name + ", age=" + age + "]"; } String name; int age; } class Person6 { int no; String name; ArrayList<Person5> employees; @Override public String toString() { return "Person6 [no=" + no + ", name=" + name + ", employees=" + employees + "]"; }
3、FastJson
Person4 person4=JSON.parseObject(string, Person4.class);
例子:
String string = "{no:1,name:'android',employees:[{name:'zhangsan',age:20},{name:'lisi',age:21},{name:'wangwu',age:22}]}"; Person4 person4=JSON.parseObject(string, Person4.class); System.out.println(person4); } }
class Person3{
String name; int age; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "Person3 [name=" + name + ", age=" + age + "]"; }
}
class Person4{
int no;
String name;
ArrayList employees;
public int getNo() {
return no;
}
public void setNo(int no) {
this.no = no;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public ArrayList getEmployees() {
return employees;
}
public void setEmployees(ArrayList employees) {
this.employees = employees;
}
@Override
public String toString() {
return "Person4 [no=" + no + ", name=" + name + ", employees=" + employees + "]";
}
}
68人点赞
JAVA基础知识
更多精彩内容,就在简书APP
“小礼物走一走,来简书关注我”
赞赏支持
共2人赞赏
鹅鹅鹅曲项向天歌呀
我太难了…
总资产33 (约2.11元)共写了4.6W字获得420个赞共188个粉丝
关注
推荐阅读
更多精彩内容
Java基础知识总结
一:java概述:1,JDK:Java Development Kit,java的开发和运行环境,java的开发工…
ZaneInTheSun
阅读 1,935
评论 0
赞 9
有关“减肥”的事
近几年,白米饭被批判为令人长胖的垃圾食品,取代油脂成为了新一代「万人嫌」。 由于白米饭背负的骂声太大,导致面条、土…
快乐天使_快乐飞翔
阅读 153
评论 0
赞 0
不经意的浪漫
有段时间,我受邀为一部青春爱情片做编剧。电影一立项,导演便安排我到大学里去采风,说是采风,主要目的是想收集一些发生…
午歌
阅读 205
评论 0
赞 4
JVM内幕:Java虚拟机详解
编译地址: jamesdbloom译者: ImportNew.com - 挖坑的张师傅原文地址: http://w…
IT程序狮
阅读 2,370
评论 1
赞 26
为什么要用redis做验证码缓存, 这样做有什么好处?
1.redis缓存运行效率高2.redis可以通过expire来设定过期策略,比较适用于验证码的场景。3.考虑到分…
不见当年三月花
阅读 4,149
评论 0
赞 0
鹅鹅鹅曲项向天歌呀
关注
总资产33 (约2.11元)
Java中的加密,[干货]
阅读 86
Jenkins 之 android 自动 安装 apk(六)
阅读 220
作者:鹅鹅鹅曲项向天歌呀
链接:https://www.jianshu.com/p/eae86b35a500
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。