java基础知识
java基础知识
java转义字符
\t制表位;
\n换行;
\\:一个斜杠
\r:一个回车
java常见错误
1、找不到文件
2、文件名或类错误
3、缺少分号
注释
1、单行注释://
2、多行注释:/ /
快捷注释:ctrl+shift+c
文档注释:
/**
@author 人名
@version 你好
**/
java代码规范
1、类,方法的注释,要以javadoc的方式来写
2、非javadoc的注释,往往是给代码的维护者看的
DOS原理:
控制台输入指令—>发送给dos系统—>
1、接受指令2、解析指令3、执行指令
—>windows进行执行
DOS命令
1、查看当前目录下有什么内容:dir dir d:abc2\test200
2、cd ..\..\ABC\test200 或者 cd D:abc2\test200
3、cd \ 直接跳转到当前最起始目录
4、查看目录下所有内容 :tree d:
5、清屏:cls
6、创建目录:md marry100
7、删除目录:rd marry100
8、创建文件:echo 填写内容 > 文件名
9、删除文件:del 文件名
浮点型
double num1=1.1f;
float num=1.1f;
double num2=.52;
System.out.println(num2);
System.out.println(num);
*2.7近似相等与8.1/3
double c=2.7;
double b=8.1/3;
System.out.println(c);
System.out.println(b);
结果:
2.7
2.6999999999999997
解决方案:
if(Math.abs(c-b)<0.001)
System.out.println(“两个数近似相等”);
}
使用Math函数下的abs 进行判断两个数的差值
字符型
1、字符常量用单引号(’ ‘)括起来的单个字符,例如:char c1=’a‘
2、java中允许使用转义字符’\n’来将其后的字符转变为特殊字符性常量,例如: char c3=’\n’;//‘\n’表示换行符
3、char的本质是一个整数,在输出时,是对应的unicode吗对应的字符
4、、可以直接给char赋一个整数,然后输出时,会按照对应的unicode字符输出
5、char类型是可以i进行运算的,相当于一个整数,因为它都对应有unicode码
字符型本质
存储:char a->97->(二进制)1100001->进行存储
读取:二进制->97====->”a”=->显示
ASCLL表
ASCLL表一个字节表示,一共有128个字符,实际上一个字节可以表示256个字符,只有了128个
unicode
unicode编码表使用两个字节表示字符,字母和汉字统一都是占两个字节,这样浪费空间(广泛,容易造成资源浪费)
unicode兼容ascll
utf-8
字母用一个字节,汉字用三个字节(范围大)
gbk
字母用一个字节,汉字用两个字节(范围小)
gb2312《gbk
49
boolean(布尔类型)
boolean ispass=true;
if(ispass==true)
{
System.out.println(“两个数近似相等”);
}
else {
System.out.println("两个数不相等");
}
结果:两个数近似相等
数据类型转换
数据类型按精度容量大小排序为:
char->int->long->float->double-
byte->short->int->long->float->double
int a=’c‘ double d=80 都是正确的
int n1 = 10;
float d1 = n1 + 1.1;
System.out.println(d1);(x)
byte :-128—127(byte和short、char之间不会像相互转换)
byte b1=10;
int n2=1;
byte b2=n2; (X)
如果是变量赋值,判断类型
1、多种类型的数据混合运算时,系统首先自动将所有数据转换成容量大的那种数据,然后再进行计算
2、byte short char三者不会相互转换
3、byte 1个字节,1属于 -128-127之间,n2为4个字节,把n2赋值给一个字节的byte类型就会报错
4、byte short char他们三者可以计算,在计算时首先转换为int类型
5、Boolean类型不参与转换
6、自动提升原则:表达式结果的类型自动提升为操作数种最大的类型
7、强制类型转换过程可能会会造成精度降低或溢出,要格外注意!
double q = 2.9;
System.out.println((int) q);(精度溢出)
byte w = (byte) n1;
System.out.println(w);(溢出)
结果:
2
-24
基本数据类型和string类型转换
基本类型转string:
语法:1、将基本类型的值+“ ”即可
2、String s2=String.valueOf(100);//对于所有数据类型都适用
System.out.println(s2);
string类型转基本数据类型:
通过基本类型的包装类调用parseXX方法即可
String s5 = “123”;
int num1 = Integer.parseInt(s5);
double num2 = Double.parseDouble(s5);
float num3 = Float.parseFloat(s5);
long num4 = Long.parseLong(s5);
byte num5 = Byte.parseByte(s5);
boolean num6 = Boolean.parseBoolean(s5);
short num7 = Short.parseShort(s5);
System.out.println(num1);
System.out.println(num2);
System.out.println(num3);
System.out.println(num4);
System.out.println(num5);
System.out.println(num6);
结果:
123
123.0
123.0
123
123
false
123
算术运算符难点
先加后增:
int i = 1;
i = i++;
System.out.println(i);
结果:1
先用再加实质:temp=i;i=i+1;i=temp;采用临时变量最后将temp的值重新赋给i;
先增后加:
int i = 1;
i = ++i;
System.out.println(i);
结果:2
先加后用实质:i=i++;temp=i;i=temp;
逻辑运算符
a&b 和 a&&b a|b 和 a||b意思相同
a^b叫逻辑异或,当ab 不同时,结果为true ,否则为false
赋值运算符
a++ byte b=2; b+=i ->b=b+i 实质为:b=(byte)(b+i)
java中会有一个类型的强制转换
数组使用注意事项和细节
1、数组中的元素可以是任何数据类型,包括基本类型和引用类型,但是不能混用
2、数组创建后,不进行赋值,有默认值,int 0,shrot 0,byte 0,long 0,float 0,double 0.0,char \u000,boolean false,String null
3、使用数组步骤:1、声明数组并开辟空间,2、给数组各个元素赋值3、使用数组。
4、数组下标从0开始
5、数组下标必须在指定范围内使用,否则会报错
6、数组属于引用类型,数组类型是对象(object)
7、数组在默认情况下是引用传递,赋的值 是地址,赋值方式为引用
ps:int []arr1={1,2,3}; int []arr2=arr1;
是把arr1的地址赋给arr2,arr2的变化会影响arr1
类和对象
1、引用传递
对象和数组传递属于引用传递,
main函数中:
B b=new B();
int []arr={1,2,3};//arr在栈区,数据123在堆区有存放地址
b.test(arr);
属于栈区部分,调用test()函数后,会重新在栈区新开辟一部分空间
在新开辟的栈区中,新的数组同样指向arr的地址,在其中修改arr中的数据,会影响main函数中arr数组中的数据
代码示例:
public class yinyongchaundi {
public static void main(String[] args) {
// TODO 自动生成的方法存根
B b = new B();
int[] arr = { 1, 2, 3 };
b.test100(arr);
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i] + "\t");
}
System.out.println();
}
}
class B {
public void test100(int[] a) {
a[0] = 200;
for (int i = 0; i < a.length; i++) {
System.out.println(a[i] + “\t”);
}
System.out.println();
}
}
结果:
200
2
3
200
2
3
示例代码2:
public class yinyongchaundi {
public static void main(String[] args) {
nihao P=new nihao();
P.age=18;
P.name="zhangxinqi";
B b = new B();
b.print(P);
System.out.println("main:p.age="+P.age+",p.name="+P.name);
}
}
class B {
public void print(nihao a) {
a.age=20;//改变对象P对应的数据
a=null;//将新在栈区开辟的空间中的对象a(实际就是指向P)指向的数据地址置为空,
//但并不影响main原始空间中对象P指向的数据
a =new nihao();
a.name=”lizhihui”;
//同理,new一个新的对象,在堆区新开一个空间用来存储新初始化的值,对象a指向新地址
//与原地址毫无任何关系,初始化后不再使用就会自动回收该新在堆区开辟的空间
}
}
class nihao{
int age;
String name;
}
结果:main:p.age=20,p.name=zhangxinqi
递归调用(迷宫问题,罗汉塔,八个皇后)(p222-p227)老韩java
1、执行一个方法,会创建一个新的受保护的独立空间(栈空间)2、方法的局部变量是独立的,不会互相影响,比如n变量(即形参)
3、如果方法中使用的是引用类型变量(比如数组,对象),就会共享该引用类型的数据
4、递归必须向退出递归的条件逼近,否则就无限递归
5、当一个方法执行完毕,或者遇到return,就会返回,遵守谁调用,就将结果返回给谁,同时当方法执行完毕或者返回时,该方法也就执行完毕
函数重载
1、函数名相同
2、参数个数、类型、顺序不同
3、对函数返回值无要求
变量作用域
1、在java中,主要的变量就是属性(方法变量)和局部变量
2、局部变量一般是指在成员方法中定义的变量
3、java中的作用域分类:
全局变量:也就是属性,作用域为整个类体 cat类cry eat等方法使用属性
4、全局变量可以不赋值,直接使用,因为有默认值,局部变量必须赋值,因为没有默认值(main函数中属于局部变量,类中属性和代码块属于相对全局变量,注意类中方法定义属于局部变量)
注意事项:
1、属性和局部变量可以重名,访问遵循就近原则
ps:class cat{
int age=10;
public static void test(){
int age=20;
System.out.println(age);//20 就近原则
}
}
2、在同一个作用域中,比如在同一个成员方法中,两个局部变量不能重名//即不能定义两个一样的变量
3、属性生命周期较长,盘随着对象的创建而创建,伴随着对象的销毁而销毁,局部变量,生命周期较短,伴随着他的代码块的执行而创建,伴随着代码块的结束而销毁。即在一次方法调用过程中。
4、作用域范围不同
全局变量/属性:可以被本类使用,或被其他类使用
局部变量:只能在本类中对应的方法中使用
5、修饰符不同
全局变量/属性可以加修饰符
局部变量不可以加修饰符
6、内存位置不同,成员变量是在堆内存,局部变量是在栈内存
7、成员变量是在类中方法外,局部变量方法内或者方法声明上
8、成员变量有默认的初始化值,局部变量没有初始化值,必须先定义赋值
构造函数/构造器
【修饰符】方法名(形参列表){
方法体;
}
1、构造器的修饰可以是默认的,也可以是 public protected private
2、构造器没有返回值
3、方法名和类名必须要一样
4、参数列表和成员方法一样的规则
5、构造器的调用系统完成
注意事项
1、一个类可以定义多个不同的构造器,即构造器重载
2、构造器必须和类名相同
3、构造器没有返回值
4、构造器是完成对象的初始化,并不是创建对象
5、在创建对象时,系统自动的调用该类的构造方法
6、如果程序猿没有定义构造器,系统会自动生成一个无参构造器,也是默认构造器
7、一旦定义了自己的构造器,默认的构造器就覆盖了,不能再使用默认的无参构造器,除非显式定义一个;
string以及StringBuilder
1、字符数组转化为字符串
char a[]= {‘a’,’b’,’c’};
String aString=new String(a);
System.out.println(aString);
StringBuffer 方法
| 序号 | 方法描述 |
|---|---|
| 1 | public StringBuffer append(String s) 将指定的字符串追加到此字符序列。 |
| 2 | public StringBuffer reverse() 将此字符序列用其反转形式取代。 |
| 3 | public delete(int start, int end) 移除此序列的子字符串中的字符。 |
| 4 | public insert(int offset, int i) 将 int 参数的字符串表示形式插入此序列中。 |
| 5 | insert(int offset, String str) 将 str 参数的字符串插入此序列中。 |
| 6 | replace(int start, int end, String str) 使用给定 String 中的字符替换此序列的子字符串中的字符。 |
StringBuilder 类在 Java 5 中被提出,它和 StringBuffer 之间的最大不同在于 StringBuilder 的方法不是线程安全的(不能同步访问)。
在应用程序要求线程安全的情况下,必须要使用stringBuffer类型
string与stringbuilder之间的转换
1、stringbuilder转换为string
StringBuilder A=new StringBuilder();
A.append(100).append(“nihao”).append(“java”);// 链式编程
String a=A.toString();
System.out.println(a);
2、string转换为stringbuilder
构造方法
StringBuilder B=new StringBuilder(a);
System.out.println(B);
集合
集合的底层是一个可变数组,ArrayList:
1、可调整大小的数组实现
2、
如何使用:
在出现E的地方我们使用引用数据类替换即可
举例:ArrayList
ArrayList构造方法和添加方法
1、public ArrayList() //创建一个空的集合对象
2、public boolean add(E e) //将制定的数据追加到集合的末尾
3、public void add(int index,E element)//在此集合的指定位置插入指定的元素
ArrayList常用方法
1、public boolean remove(Object o) //删除指定的元素,返回删除是否成功
2、public E remove(int index)//删除指定索引处的元素,返回被删除的元素,E代表被删除数据的类型
3、public E set(int index,E element)//修改指定索引处的元素,返回被修改的元素
4、public E get(int index)//返回指定索引处的元素
5、public int size()//返回集合中的元素个数
//System.out.println(arrayList.set(0, “xiugai”));//修改指定索引处的元素,返回被修改的元素
// System.out.println(arrayList.remove(“world”));
//System.out.println(arrayList.remove(0));//没
有就会返回false
//System.out.println(arrayList.get(0));//返回指定索引处的元素
//System.out.println(arrayList.size());//返回集合中的元素个数
继承
1、在子类方法中访问一个变量
(1)在子类方法中找(2)在子类成员属性中找(3)在父类成员属性中找
2、super关键字
this 代表本类对象的引用
super 代表父类对象的引用
1、调用父类中的成员方法super.test();
2、调用父类中的成员属性super.nums
3、调用父类中的构造函数
public guanjianzi_super() {
super();//必须写在第一行
}
3、继承中构造方法的访问特点
1、子类中所有的构造方法默认都会访问父类中无参的构造方法
2、调用有参构造方法需要在子类构造函数中super(参数);
传进去一个参数即可调用父类的有参构造函数
4、继承中成员方法的访问特点
(1)在子类成员范围中找
(2)在父类成员范围中找
(3)如果都没有就报错
5、方法重写注意事项
1、父类中的私有方法,子类无法继承和重写
2、子类重写父类方法时只要不比父类低即可
即:父类如果是public 子类必须为 public
父类若是默认的,子类可以是默认,也可以是public
6、继承注意事项
1、单一继承,不支持多继承,但支持继承体系、多层继承,例如:父亲继承爷爷,孙子继承父亲。
包的使用
1、同一个项目中使用别的包需要引入
例如:import 包名称.类名;
访问修饰符
1、private 只能在本类中访问,默认和保护和公共可以被其他无关的类访问
2、不同类中,另一个类不可以访问该类的私有方法
3、不同包中,只能访问另一个包的一个中类中的公共的方法
4、final 关键字是最终的意思,可以修饰成员方法,成员变量,类
最终方法不可以被重写
最终类不可以被继承
最终修饰基本类型变量不可以被重新赋值,引用类型可以被重新赋值,原理是final修饰引用类型是地址不可以被改变,但是里面的值是可以改变的.
final Cat aCat=new Cat();
aCat =new Cat();//会报错
final Cat aCat=new Cat();
aCat.age=5;//不报错
aCat.name="加菲猫";//不报错
5、static
(1)、被所有对象共享的成员用static修饰,建议通过类名进行访问(2)、被类的所有成员共享,这也是我们判断是否使用静态关键字的条件
访问特点:
(1)、非静态成员方法可以访问所有静态成员和非静态成员变量
(2)、静态成员方法只能访问静态成员变量和静态成员方法,main方法也是静态的,所以可以调用。
多态
多态的前提和体现
1、有继承/实现关系2、有方法重写3、有父类引用指向子类对象
访问特点
1、成员变量:编译和执行都看父类
2、成员方法:编译看父类中有没有,执行是执行子类中重写的此方法
原因:成员方法有重些,成员变量无重写
例如:
Animal animal=new Cat();
System.out.println(animal.age);//父类中的成员变量
animal.TextStyle();//子类中的成员方法
多态的好处和弊端
好处:多个类继承同一个父类时,可以写一个方法,使用参数为父类型,在使用的时候,使用具体的子类形参与操作,从而调用该子类的成员方法(可以调用的是子类中重写的方法)
例如:
private static void test( Animal a) {
// 传进来的子类对象
//原理为:Animal a=new 子类();
//即父类引用指向子类对象
a.TextStyle();//此方法多个子类进行重写
}
弊端:调用的方法只能是所有继承该父类的子类进行重写
的成员方法,不能调用某个子类中特有的方法
多态的转型
向上转型:即为有父类引用指向子类对象
向下转型:即父类引用转为子类对象
例如:
Animal animal=new Cat(); //向上转型
Cat bCat=(Cat)animal; //向下转型,注意黑体加粗部分
bCat.catwork1();
注意:
向下转型中转型的对象必须与new 类型名 相符
抽象类
抽象类的特点:抽象类和抽象方法必须用abstract关键字修饰
public abstract class 类名{}
public abstract void eat();
抽象类中不一定有抽象方法,有抽象方法的类一定是抽象类
抽象类不能实例化对象,可以参照多态的方式,通过子类对象实例化对象
抽象类的子类要么重写抽象类的所有抽象方法,要么他本身就是一个抽象类
抽象类的成员特点
成员变量:可以是变量也可以是常量
构造方法:有构造方法,但是不能实例化,通过子类访问父类的数据
成员方法:可以有抽象的方法来限定子类必须完成某些操作
也可以有非抽象方法提高代码复用性
接口
接口用关键字interface修饰:
public interface 接口名 {}
类实现接口用implements 表示
public class 类名 implements 接口名{}
接口不能实例化,参照多态的方式,通过实现类对象实例化,这叫接口多态(具体类多态,抽象类多态,接口多态)
多态的前提:有继承或者实现关系,有方法重写,有父类引用指向子类对象
接口的实现类:
要么重写接口中的所有抽象方法
要么是抽象类
接口的成员特点
变量默认是公共、静态、最终的,静态即可以通过接口名访问,最终即值无法改变
接口中无构造方法,因为接口主要是对行为进行抽象,是没有具体存在,一个类如果没有父类,默认继承Object类
成员方法
只能是抽象方法,默认修饰符:public abstract
接口和类的区别:
接口不能被实例化对象,类可以;
接口没有构造方法;
接口中所有方法是抽象的;
接口中不能有变量,除了final和static修饰的变量;
接口不是被继承了,而是被实现了;
多个类可以同时实现同一个接口;
类和接口的关系
类和类的关系:只能单继承,但是可以多层继承
类和接口的关系:可以单实现,也可以多实现,还可以在继承一个类的同时实现多个接口
接口与接口的关系:可以单继承,也可以多继承
抽象类和接口的区别
成员区别:
抽象类:常量,变量,有构造方法,也有抽象方法,也有非抽象方法
接口: 常量,抽象方法
关系区别:
类和类:单继承
类和接口:单实现、多实现
接口与接口:单继承、多继承
设计理念区别:
抽象类:对象抽象,包括属性、行为
接口:对行为抽象,主要是行为
- 抽象类中的方法可以有方法体,就是能实现方法的具体功能,但是接口中的方法不行。
- 抽象类中的成员变量可以是各种类型的,而接口中的成员变量只能是 public static final 类型的。
- 接口中不能含有静态代码块以及静态方法(用 static 修饰的方法),而抽象类是可以有静态代码块和静态方法。
- 一个类只能继承一个抽象类,而一个类却可以实现多个接口。
注:JDK 1.8 以后,接口里可以有静态方法和方法体了。
注:JDK 1.8 以后,接口允许包含具体实现的方法,该方法称为”默认方法”,默认方法使用 default 关键字修饰。更多内容可参考 Java 8 默认方法。
注:JDK 1.9 以后,允许将方法定义为 private,使得某些复用的代码不会把方法暴露出去。更多内容可参考 Java 9 私有接口方法。
接口名作为形参和返回值
方法的形参是接口名,其实需要的是该接口的实现类对象
方法的返回值是接口名,其实是返回的是该接口的实现类对象
其实类似于抽象类,需要通过父类引用指向子类对象,创建一个子类,重写接口中的方法,通过实例化一个子类对象调用接口中的方法。
内部类
定义:在一个类中定义一个类
内部类的访问特点:
内部类可以直接访问外部类的成员,包括私有
外部类要访问内部类的成员,必须创建对象
成员内部类
1、在类的成员位置:成员内部类
2、在类的局部位置:局部内部类
一般格式:Player.nihao a=new Player(). new nihao();(不推荐)
常用方法:通过在外部类中写一个方法实例化一个内部类对象,访问内部类方法,再通过实例化外部类对象访问该方法,间接访问内部类
局部内部类
定义:在外部类的一个成员方法内定义一个类
调用方法:在外部类内的方法内部定义内部类并且实例化该内部类,通过实例化外部类对象,调用外部类方法进而调用内部类
匿名内部类
前提:存在一个类或者是接口,这里的类可以是具体类,也可以是抽象类
本质:是一个继承了该类或者实现了该接口的子类匿名对象
创建格式:
public class neibulei {
public void method() {
new SpeakEnglish() {
@Override
public void speak() {
// TODO 自动生成的方法存根
System.out.println("说英语");
}
};
}
}
调用方法:
new SpeakEnglish() {
@Override
public void speak() {
// TODO 自动生成的方法存根
System.out.println("说英语");
}
}.speak();
完善方法:
public class neibulei {
public void method() {
SpeakEnglish as=new SpeakEnglish() {
public void speak() {
System.out.println(“说英语”);
}
};
as.speak(); }
static double |
abs(double a)返回值为 double绝对值。 |
|---|---|
static float |
abs(float a)返回 float值的绝对值。 |
static int |
abs(int a)返回值为 int绝对值。 |
static long |
abs(long a)返回值为 long绝对值。 |
static double |
acos(double a)返回值的反余弦值; 返回的角度在0.0到pi的范围内。 |
static int |
addExact(int x, int y)返回其参数的总和,如果结果溢出int,则抛出 int 。 |
static long |
addExact(long x, long y)返回其参数的总和,如果结果溢出long,则抛出 long 。 |
static double |
asin(double a)返回值的正弦值; 返回角度在pi / 2到pi / 2的范围内。 |
static double |
atan(double a)返回值的反正切值; 返回角度在pi / 2到pi / 2的范围内。 |
static double |
atan2(double y, double x)返回从直角坐标(转换角度 theta x , y )为极坐标 (R,θ-)。 |
static double |
cbrt(double a)返回 double值的多维数据集根。 |
static double |
ceil(double a)返回大于或等于参数的最小(最接近负无穷大) double值,等于一个数学整数。 |
static double |
copySign(double magnitude, double sign)使用第二个浮点参数的符号返回第一个浮点参数。 |
static float |
copySign(float magnitude, float sign)使用第二个浮点参数的符号返回第一个浮点参数。 |
static double |
cos(double a)返回角度的三角余弦。 |
static double |
cosh(double x)返回的双曲余弦 double值。 |
static int |
decrementExact(int a)返回一个递减1的参数,如果结果溢出int,则 int 。 |
static long |
decrementExact(long a)将返回的参数递减1,如果结果溢出long,则 long 。 |
static double |
exp(double a)返回欧拉的数字 e提高到一个 double价值。 |
static double |
expm1(double x)返回 e x -1。 |
static double |
floor(double a)返回小于或等于参数的最大(最接近正无穷大) double值,等于一个数学整数。 |
static int |
floorDiv(int x, int y)返回小于或等于代数商的最大(最接近正无穷大) int值。 |
static long |
floorDiv(long x, long y)返回小于或等于代数商的最大(最接近正无穷大) long值。 |
static int |
floorMod(int x, int y)返回 int参数的底部模数。 |
static long |
floorMod(long x, long y)返回 long参数的底模数。 |
static int |
getExponent(double d)返回a的表示中使用的无偏指数 double 。 |
static int |
getExponent(float f)返回a的表示中使用的无偏指数 float 。 |
static double |
hypot(double x, double y)返回sqrt( x 2 + y 2 ),没有中间溢出或下溢。 |
static double |
IEEEremainder(double f1, double f2)根据IEEE 754标准计算两个参数的余数运算。 |
static int |
incrementExact(int a)返回自变量1,如果结果溢出int,则 int 。 |
static long |
incrementExact(long a)返回一个增加1的参数,如果结果溢出long,则 long 。 |
static double |
log(double a)返回的自然对数(以 e为底) double值。 |
static double |
log10(double a)返回一个 double的基数10对数值。 |
static double |
log1p(double x)返回参数和1的和的自然对数。 |
static double |
max(double a, double b)返回两个 double值中的较大值。 |
static float |
max(float a, float b)返回两个 float的较大值。 |
static int |
max(int a, int b)返回两个 int值中的较大值。 |
static long |
max(long a, long b)返回两个 long的较大值。 |
static double |
min(double a, double b)返回两个 double的较小值。 |
static float |
min(float a, float b)返回两个 float的较小值。 |
static int |
min(int a, int b)返回两个 int的较小值。 |
static long |
min(long a, long b)返回两个 long的较小值。 |
static int |
multiplyExact(int x, int y)返回参数的乘积,如果结果溢出int,则抛出 int 。 |
static long |
multiplyExact(long x, long y)返回参数的乘积,如果结果溢出long,则抛出 long 。 |
static int |
negateExact(int a)返回参数的否定,如果结果溢出int,则 int 。 |
static long |
negateExact(long a)返回参数的否定,如果结果溢出long,则 long 。 |
static double |
nextAfter(double start, double direction)返回与第二个参数方向相邻的第一个参数的浮点数。 |
static float |
nextAfter(float start, double direction)返回与第二个参数方向相邻的第一个参数的浮点数。 |
static double |
nextDown(double d)返回与负无穷大方向相邻的 d的浮点值。 |
static float |
nextDown(float f)返回与负无穷大方向相邻的 f的浮点值。 |
static double |
nextUp(double d)返回与正无穷大方向相邻的 d的浮点值。 |
static float |
nextUp(float f)返回与正无穷大方向相邻的 f的浮点值。 |
static double |
pow(double a, double b)将第一个参数的值返回到第二个参数的幂。 |
static double |
random()返回值为 double值为正号,大于等于 0.0 ,小于 1.0 。 |
static double |
rint(double a)返回与参数最接近值的 double值,并且等于数学整数。 |
static long |
round(double a)返回参数中最接近的 long ,其中 long四舍五入为正无穷大。 |
static double |
sqrt(double a)返回的正确舍入正平方根 double值。 |
system
static long |
currentTimeMillis()返回当前时间(以毫秒为单位)。 |
|---|---|
static void |
exit(int status)终止当前运行的Java虚拟机。 |
Object
boolean |
equals(Object obj)指示一些其他对象是否等于此。 |
|---|---|
String |
toString()返回对象的字符串表示形式。 |
Arrays
arrays.toString(数组名) //返回指定数组的内容的字符串表示形式。
arrays.sort(数组)//按升序排列数组的指定范围。
Integer
static int |
MAX_VALUE一个持有最大值一个 int可以有2 31 -1。 |
|---|---|
static int |
MIN_VALUE的常量保持的最小值的 int可以具有,-2 31。 |
static int |
SIZE用于表示二进制补码二进制形式的 int值的位数。 |
static 类<Integer> |
TYPE``类原始类型 int的 类实例。 |
Integer nInteger=new Integer(100);//只能是数字,其他类型会报错
System.out.println(nInteger);
日期类
1、打印当前日期
Calendar aCalendar=Calendar.getInstance();
int year=aCalendar.get(Calendar.YEAR);
int month=aCalendar.get(Calendar.MONDAY);
int data=aCalendar.get(Calendar.DATE);
System.out.println(year+”年”+month+”月”+data+”日”);
2、添加某个数据(年月日)
aCalendar.add(aCalendar.MONDAY,5);//添加月份
通过add方法可以对日历进行修改
3、获取对应月份的天数
Calendar aCalendar=Calendar.getInstance();
Scanner aScanner =new Scanner(System.in);
int year=aScanner.nextInt();
aCalendar.set(year,1,1);
aCalendar.add(aCalendar.DATE, -1);
int data=aCalendar.get(aCalendar.DATE);
System.out.println(data);
先获取年份,然后月份下标从0开始,1代表第二月,第二月最后一天减去一天就是第一个月最后一天,就可以获取第一个月的天数
4、计算某一天是这一年的第几天
import java.util.Calendar;
import java.util.Scanner;
Calendar aCalendar = Calendar.getInstance();
Scanner aScanner = new Scanner(System.in);
int year = aScanner.nextInt();
int month = aScanner.nextInt();
int data=aScanner.nextInt();
int nums=0;
for (int i = 1; i < month; i++) {
aCalendar.set(year,i, 1);
aCalendar.add(aCalendar.DATE, -1);
nums = nums+aCalendar.get(aCalendar.DATE);
}
System.out.println(nums+data);
异常
异常体系
Throwable
Error Exception
RuntimeException 非 RuntimeException
Error:严重问题,不需要处理
Exception:称为异常类,他表示程序本身可以处理的问题
RuntimeException :在编译期是不需要检查的,出现问题后,需要回来修改代码
非 RuntimeException :编译期间就必须处理的,否则程序不能通过编译,更不能正常运行。
collection

Collection 集合的常用方法:
- |
boolean|add(E e)确保此集合包含指定的元素(可选操作)。 |
| ————- | ————————————————————————— |
|void|clear()从此集合中删除所有元素(可选操作)。 |
- |
- |
boolean|contains(Object o)如果此集合包含指定的元素,则返回true。 |
| ————- | —————————————————————————————— |
|boolean|isEmpty()如果此集合不包含元素,则返回true。 |
- |
- |
Iterator<E>|iterator()返回此集合中的元素的迭代器。 |
| ——————- | —————————————————————————————— |
|boolean|remove(Object o)从该集合中删除指定元素的单个实例(如果存在)(可选操作)。 |
- |
- |
int|size()返回此集合中的元素数。 |
| ——- | ———————————————— |
| | |
- |
collection集合的遍历
Collection<String>collection=new ArrayList<String>();
collection.add("你好");
collection.add("wode");
//collection.remove("wode");
// System.out.println(collection);
Iterator<String>aIterator=collection.iterator();
while(aIterator.hasNext()) {
System.out.println(aIterator.next());
}
集合的使用步骤
1、创建集合对象
2、添加元素
3、遍历集合
Student aStudent = new Student("12", "zxq", "10", "henan");
Student aStudent1 = new Student("11", "zhangxinqi", "9", "han");
Collection<Student> aCollection = new ArrayList<Student>();
aCollection.add(aStudent);
aCollection.add(aStudent1);
Iterator<Student> iterator = aCollection.iterator();
while (iterator.hasNext()) {
Student aStudent2 = iterator.next();
System.out.println(aStudent2.getName() + "," + aStudent2.getSid() + "," + aStudent2.getAge() + ","
+ aStudent2.getAddress());
}
list集合概述和特点
List集合概述:
有序集合,可以精准控制列表中每个元素的插入位置,通过整数索引访问
与set集合不同,列表通常允许重复的元素
特点:
有序:存储和取出的元素顺序一致
可重复:存储的元素可以重复
List
strList.add(“nihao”);
Iterator
while (aIterable.hasNext()) {
System.out.println(aIterable.next());
}
使用List集合存储学生类对象信息
Student aStudent = new Student("12", "zxq", "10", "henan");
Student aStudent1 = new Student("11", "zhangxinqi", "9", "han");
List<Student> strList = new ArrayList<>();
strList.add(aStudent);
strList.add(aStudent1);
//迭代器输出
Iterator<Student>aIterable=strList.iterator();
while (aIterable.hasNext()) {
Student aStudent2=aIterable.next();
System.out.println(aStudent2.getAge()+aStudent2.getName());
}
//for循环遍历输出
for (int i = 0; i < strList.size(); i++) {
Student aStudent2=strList.get(i);
System.out.println(aStudent2.getAge()+aStudent2.getName());
}
List并发修改异常
在Java开发中Exception in thread “main” java.util.ConcurrentModificationException, 这是一个并发修改异常,迭代器是依赖于集合而存在的,在判断成功后,集合的中新添加了元素,而迭代器却不知道,所以就报错了,这个错叫并发修改异常。
简单描述就是:迭代器遍历元素的时候,通过集合是不能修改元素的。
ArrayList<String> array = new ArrayList<String>();
// 创建并添加元素
array.add("hello");
array.add("world");
array.add("java");
// 方式1:迭代器迭代元素,迭代器修改元素
// 而Iterator迭代器却没有添加功能,所以我们使用其子接口ListIterator,本质是每次修改后会把实际修改值赋值给预期修改值
// ListIterator lit = array.listIterator();
// while (lit.hasNext()) {
// String s = (String) lit.next();
// if ("world".equals(s)) {
// lit.add("javaee");
// }
// }
// System.out.println("list1:" + array);
// 方式2:集合遍历元素,集合修改元素(普通for)
for (int x = 0; x < array.size(); x++) {
String s = (String) array.get(x);
if ("world".equals(s)) {
array.add("javaee");
}
}
System.out.println("list2:" + array);
}
}
提示:集合有个属性modCount,每当对集合修改一次,modCount的值就会自增,,迭代器在遍历的时候,底层会new一个Itr的内部类,初始化了一个变量记录了集合的实际修改次数modCount,变量名expectedModCount是预期修改次数。迭代器在调用next()方法时候会去比较这两个值是否相等,不相等则抛出异常
final void checkForComodification()
{
if (modCount != expectedModCount) throw new ConcurrentModificationException();
}
ListIterator列表迭代器(用的不多,多用Iterator)
1、通过list集合的listlterator()方法得到,所以说他是List集合特有的迭代器
2、用于允许程序猿沿任意方向遍历列表的列表迭代器,在迭代期间修改列表,并获取列表迭代器的当前位置
常用方法
|
void|add(E e)将指定的元素插入列表(可选操作)。 |
| ————- | —————————————————————————————— |
|boolean|hasNext()返回true如果遍历正向列表,列表迭代器有多个元素。 |
|boolean|hasPrevious()返回true如果遍历反向列表,列表迭代器有多个元素。 |
|E|next()返回列表中的下一个元素,并且前进光标位置。 |
|int|nextIndex()返回随后调用next()返回的元素的索引。 |
|E|previous()返回列表中的上一个元素,并向后移动光标位置。 |
|int|previousIndex()返回由后续调用previous()返回的元素的索引。 |
|void|remove()从列表中删除由next()或previous()返回的最后一个元素(可选操作)。 |
|void|set(E e)用 指定的元素替换由next()或previous()返回的最后一个元素(可选操作)。 |while (lit.hasPrevious()) {
String string = (String) lit.previous(); System.out.println("list1:" + string); }
增强for循环
其底层是一个迭代器
格式:
// 增强for循环写的话会报同样的错误,因为它本身就是用来替代迭代器的
// for (String s : array) {
// if ("world".equals(s)) {
// array.add("javaee");
// }
// }
// System.out.println("list3:" + array);
for (String s : strList) {
System.out.println(s);
}
三种遍历集合的方法
Student aStudent = new Student("12", "zxq", "10", "henan");
Student aStudent1 = new Student("11", "zhangxinqi", "9", "han");
List<Student> strList = new ArrayList<>();
strList.add(aStudent);
strList.add(aStudent1);
Iterator<Student> aIterable=strList.iterator();
while (aIterable.hasNext()) {
Student aStudent2=aIterable.next();
System.out.println(aStudent2.getAge());
}
for (int i = 0; i < strList.size(); i++) {
Student aStudent2=strList.get(i);
System.out.println(aStudent2.getAge());
}
for (Student aStudent2:strList) {
System.out.println(aStudent2.getAge());
}
List集合子类特点
ArrayList:底层数据结构是数组,查询快,增删慢
LinkedList:底层数据结构式链表,查询慢,增删快
LinkedList集合的特有功能
- |
E|get(int index)返回此列表中指定位置的元素。 |
| —— | ——————————————————————— |
|E|getFirst()返回此列表中的第一个元素。 |
|E|getLast()返回此列表中的最后一个元素。 |
- |
- |
E|removeFirst()从此列表中删除并返回第一个元素。 |
| —— | ————————————————————————— |
| | |
|E|removeLast()从此列表中删除并返回最后一个元素。 |
- |
- |
void|addFirst(E e)在该列表开头插入指定的元素。 |
| ——— | ———————————————————————— |
|void|addLast(E e)将指定的元素追加到此列表的末尾。 |
|void|clear()从列表中删除所有元素。 |
- |
Set集合的概述和特点
set集合特点
1、不包含重复元素的集合
2、没有带索引的方法,所以不能使用普通for循环遍历
set集合练习
1、存储字符串遍历
哈希值
哈希值:是jdk根据对象的地址或者字符串或者数字计算出来的int类型的数值
Object类中有一个方法可以获取对象的哈希值
System.out.println(aStudent.hashCode());
1、同一个对象的哈希值在默认情况下是相同的,即默认Object方法
2、通过对Object方法重写可以实现不同对象有相同的哈希值
System.out.println(“重地”.hashCode());
System.out.println(“通话”.hashCode());
输出:
1179395
1179395
原因:string肯定会有一个上限,当字符长时产生的数值过大string放不下时会进行截取,一旦截取HashCode的正确性就无法保证了,所以这点可以推断出HashCode存在不相同字符拥有相同HashCode。
HashSet集合的概述特点
1、HashSet这个类是set接口的实现类,
2、HashSet底层结构是hash表
3、不保证存储和取出的元素顺序一致
4、没有带索引的方法,所以不能使用普通for循环遍历
5、不包含重复元素的集合
注意:要实现存储元素的唯一性需要重写哈希code和equals方法,自动生成即可
哈希表存储元素原理
1、先对哈希值对16取余,取余的结果存储到0-15对应的位置
2、依次存储对应位置,当对应位置无元素直接存储,有元素先比较哈希值,不一样存储进去
3、哈希值一样,对元素进行比较,一样就不存储
LinkerHashSet集合
1、哈希表和链表实现的set接口,具有可预测的迭代次序
2、由链表保证元素有序,也就是说元素的存储和取出顺序是一致的
3、LinkerHashSet继承于HashSet,实现于set接口
4、HashSe表保证元素的唯一性
TreeSet集合(比较器)
- ```
public class TreeSet
extends AbstractSet
implements NavigableSet, Cloneable, Serializable 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
TreeSet间接继承于set接口,TreeSet集合可以自然排序,也可以使用比较器排序(使用什么比较方法取决于使用哪种构造器)
- - | Constructor and Description |
| ------------------------------------------------------------ |
| `TreeSet()` 构造一个新的,空的树组,根据其元素的自然排序进行排序。 |
| `TreeSet(Collection<? extends E> c)` 构造一个包含指定集合中的元素的新树集,根据其元素的 *自然排序进行排序* 。 |
| `TreeSet(Comparator<? super E> comparator)` 构造一个新的,空的树集,根据指定的比较器进行排序。 |
| `TreeSet(SortedSet<E> s)` 构造一个包含相同元素的新树,并使用与指定排序集相同的顺序。 |
TreeSet<Integer>aSet=new TreeSet<>();
aSet.add(10);
aSet.add(20);
aSet.add(100);
aSet.add(625);
aSet.add(666);
aSet.add(30);
Iterator<Integer>aIterator=aSet.iterator();
while (aIterator.hasNext()) {
Integer student =aIterator.next();
System.out.println(student);
}
注意:使用TreeSet集合存储时使用的是引用类型(基本类型的包装类类型)
**测试类:**
TreeSet<Student> aHashSet = new TreeSet<Student>();
Student aStudent = new Student("1001", "10", "zxq", "henan");
Student bStudent = new Student("1002", "11", "axq", "henan");
Student cStudent = new Student("1003", "12", "bxq", "henan");
Student dStudent = new Student("1004", "10", "cxq", "henan");
aHashSet.add(aStudent);
aHashSet.add(bStudent);
aHashSet.add(cStudent);
aHashSet.add(dStudent);
Iterator<Student> aIterator = aHashSet.iterator();
while (aIterator.hasNext()) {
Student student = aIterator.next();
System.out.println(
student.getSid() + "," + student.getAge() + "," + student.getName() + "," + student.getAddress());
}
**学生类:**
若TreeSet集合中数据类型为自定义的类型(类),需要继承Comparable接口,并且需要重写compareTo方法
,返回值为0,默认相同,不比较,返回值为负数,降序排列,返回值为正数,默认升序排列,比较的是存储时的第一个元素,若想按照自己的意愿按照其他方式排序,int 类型就做减法,string类型就直接调用compareTo方法
```java
public class Student implements Comparable<Student> {
String sid;
String name;
String age;
String address;
@Override
public int compareTo(Student o) {
// TODO 自动生成的方法存根
int num2=this.getAge().compareTo(o.getAge());
int num=num2==0?this.getSid().compareTo(o.getSid()):num2;
return num;
}
public Student() {
}
public String getSid() {
return sid;
}
public String getName() {
return name;
}
public String getAge() {
return age;
}
public String getAddress() {
return address;
}
public void setSid(String sid) {
this.sid = sid;
}
public void setName(String name) {
this.name = name;
}
public void setAge(String age) {
this.age = age;
}
public void setAddress(String address) {
this.address = address;
}
public Student(String sid, String age, String name, String address) {
// TODO 自动生成的方法存根
this.age = age;
this.name = name;
this.sid = sid;
this.address = address;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((address == null) ? 0 : address.hashCode());
result = prime * result + ((age == null) ? 0 : age.hashCode());
result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result + ((sid == null) ? 0 : sid.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Student other = (Student) obj;
if (address == null) {
if (other.address != null)
return false;
} else if (!address.equals(other.address))
return false;
if (age == null) {
if (other.age != null)
return false;
} else if (!age.equals(other.age))
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
if (sid == null) {
if (other.sid != null)
return false;
} else if (!sid.equals(other.sid))
return false;
return true;
}
}
结果:
1001,10,zxq,henan
1004,10,cxq,henan
1002,11,axq,henan
1003,12,bxq,henan
Comparator
Comparator 比较器和TreeSet构造器中重写Comparable方法本质一样,Comparator 本质是一个内部类
TreeSet<Student> aSet = new TreeSet<>(new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
// TODO 自动生成的方法存根
int num2 = o1.getAge().compareTo(o2.getAge());//比较年龄
int num = num2 == 0 ? o1.getSid().compareTo(o2.getSid()) : num2;//年龄相同比学号
return num;
}
});
Student aStudent = new Student("1001", "10", "zxq", "henan");
Student bStudent = new Student("1002", "11", "axq", "henan");
Student cStudent = new Student("1003", "12", "bxq", "henan");
Student dStudent = new Student("1004", "10", "cxq", "henan");
aSet.add(aStudent);
aSet.add(bStudent);
aSet.add(cStudent);
aSet.add(dStudent);
Iterator<Student> aIterator = aSet.iterator();
while (aIterator.hasNext()) {
Student student = aIterator.next();
System.out.println(
student.getSid() + "," + student.getAge() + "," + student.getName() + "," + student.getAddress());
}
成绩排序
注意:学生类中成绩需要使用int类型
TreeSet<Student> aSet = new TreeSet<>(new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
// TODO 自动生成的方法存根
int num2=o1.getAge()+o1.getSid()-o2.getAge()-o2.getSid();
int num = num2 == 0 ? o1.getSid()-o2.getSid() : num2;
int num3=num==0?o1.getName().compareTo(o2.getName()):num;
return num;
}
});
Student aStudent = new Student(99, 99, "zxq", "henan");
Student bStudent = new Student(98, 99, "axq", "henan");
Student cStudent = new Student(98, 95, "bxq", "henan");
Student dStudent = new Student(96, 97, "cxq", "henan");
aSet.add(aStudent);
aSet.add(bStudent);
aSet.add(cStudent);
aSet.add(dStudent);
Iterator<Student> aIterator = aSet.iterator();
while (aIterator.hasNext()) {
Student student = aIterator.next();
System.out.println(
student.getSid() + "," + student.getAge() + "," + student.getName() + "," + student.getAddress());
}
随机数排序
Set<Integer> aSet=new TreeSet<Integer>();
Random aRandom=new Random();
while (aSet.size()<10) {
int num=aRandom.nextInt(20)+1;
aSet.add(num);
}
System.out.println(aSet);
泛型
泛型格式:
<类型>:指定一种数据类型,看成是形参
<类型1,类型2>:指定多种类型的格式,多个类型之间用逗号隔开
好处:
1、把运行时候的问题提前到编译期间
2、避免了强制类型转换
泛型类
测试类:
public static void main(String[] args) {
// TODO 自动生成的方法存根
Teach1 <String>bTeach=new Teach1();
bTeach.setName("zxq");
Teach1 aTeach1=new Teach1();//未指定类型,不规范
aTeach1.setAge(30);
aTeach1.setAge("60");
System.out.println(bTeach.getName());
System.out.println(aTeach1.getAge());
// Teach1 <Integer>aTeach=new Teach1();
// aTeach.setAge("10");//实例化对象时指定类型,调用方法不按照指定类型就会报错
}
老师类:
public class Teach1<T> {
private T name;
private T age;
public T getName() {
return name;
}
public void setName(T name) {
this.name = name;
}
public T getAge() {
return age;
}
public void setAge(T age) {
this.age = age;
}
}
泛型方法
优点:
一个对象可以多次调用同一个方法,传入的类型不同
测试类:
Teach1 aTeach1=new Teach1<>();
aTeach1.TexR(“zxq”);
aTeach1.TexR(13);
aTeach1.TexR(12.63);
泛型方法:
public <T> void TexR(T t){
System.out.println(t);
}
注意:泛型方法不一定要写在泛型类中
泛型接口
泛型接口示例:
public interface teach
void show(T t);
}
泛型类示例:
public class Teach1<T> implements teach<T> {
private T name;
private T age;
public T getName() {
return name;
}
public void setName(T name) {
this.name = name;
}
public T getAge() {
return age;
}
public void setAge(T age) {
this.age = age;
}
@Override
public void show(T t) {
// TODO 自动生成的方法存根
System.out.println(t);
}
}
类型通配符
为了表示各种泛型List的父类,可以使用类型通配符
类型通配符:<?>
List<?>:表示元素类型未知的List,他的元素可以匹配任何的类型
这种带有通配符的List仅表示他是各种泛型List的父类,并不能把元素添加进去
类型通配符:<?>
类型通配符上限:<? extends 类型> List最高的类型不能超过该类型
类型通配符下限:<? super 类型>List最低的类型不能超过该类型
List<?> aList = new ArrayList
可变参数
注意事项:
1、可变参数的实参可以为0个或者任意多个
2、克变参数的实参可以为数组
3、可变参数本质就是数组
4、可变参数可以与普通类型的参数放在形参列表,但必须保证可变参数放在最后
5、一个形参列表只能出现一个可变参数
public static void main(String[] args) {
System.out.println(sum(1, 2, 5, 630));
System.out.println(sum(1, 2, 3, 5, 8, 4));
}
public static int sum(int b, int... a) {
int sum = 0;
for (int i : a) {
sum += i;
}
return sum;
}
Arrays的一个静态方法:
- |
static <T> List<T>|asList(T... a)返回由指定数组支持的固定大小的列表。 |
| —————————— | ——————————————————————————— |
| | |
- |
List
// 不允许改变长度,但是可以修改元素
// aList3.add(“JAVA”);
// aList3.remove(0);
aList3.set(0, “javaee”);
System.out.println(aList3);
List接口中的一个静态方法(JDK9以及以上):
//返回包含任意数量元素的不可变列表,不能添加修改删除
List
Set集合中一个静态方法返回集合中任意数量元素的不可变列表(JKD9以及以上)
//返回包含任意数量元素的不可变列表,不能添加删除
Set
Map
1、Map
2、put可以将映射的键和值相对性,即添加方法,当第一次添加一个键时是添加操作,同一个键再次赋值即为修改操作
基本功能方法
1、put方法添加元素
2、remove方法删除元素//(指定的key键),返回对应的V值
3、clear移除所有键值对元素
4、containsKey判断集合是否包含所指定的键
5、containsVaiue判断集合是否包含指定的值
6、isEmpty判断集合是否为空
7、size集合长度,也就是集合中键值对应的个数
获取功能
1、V get 根据键获取返回值
2、Set
3、Collection
//Collection
- |
Set<Map.Entry<K,V>>|entrySet()返回此地图中包含的映射的Set视图。 |
| ——————————- | —————————————————————————————— |
| | |
- |
Map集合的遍历
1、方法一(获取所有的键集合,遍历键集合中每个键对应的值)
Map<String, String> aMap = new HashMap<String, String>();
//创建Map集合
aMap.put("zxq", "180");
aMap.put("zwq", "125");
aMap.put("z6q", "198");
aMap.put("zxsdq", "1870");
//添加元素
Set<String> aMap2 = aMap.keySet();
//获取所有键的集合
for (String string : aMap2) {
//增强for根据键去找值,用get(object key)方法实现
String value = aMap.get(string);
System.out.println(string+"="+value);
}
结果:
zxq=180
z6q=198
zwq=125
zxsdq=1870
2、方法二(依次获取一对键值对象,分别获取键和值)
Map<String, String> aMap = new HashMap<String, String>();
//创建Map集合
aMap.put("zxq", "180");
aMap.put("zwq", "125");
aMap.put("z6q", "198");
aMap.put("zxsdq", "1870");
//添加元素
Set<Map.Entry<String, String>>aSet=aMap.entrySet();
//遍历键值对对象的集合,得到每一个键值对对象
for (Map.Entry<String, String> map : aSet) {
//根据键值对对象获取键和值
String key=map.getKey();
String value=map.getValue();
System.out.println(key+"="+value);
}
File
File类的概述和构造方法
File:它是文件和目录路径名的抽象表示
1、文件和目录是可以通过file封装成对象的
2、对于File而言,器封装的 并不一定是一个真正存在的文件,仅仅是一个路径名而已,可以是存在的,也可以是不存在的
将来是要通过具体的操作把这个路径的内容转换为具体存在的
File af1=new File(“C:\java.txt”);//将指定的路径名字转换为抽象路径名来创建新的File实现
File类的创建
- |
boolean|createNewFile()当且仅当具有该名称的文件尚不存在时,原子地创建一个由该抽象路径名命名的新的空文件。 |
| ————- | —————————————————————————————— |
| | |
- |
|
boolean|mkdir()创建由此抽象路径名命名的目录。 |
| ————- | —————————————————————————————— |
|boolean|mkdirs()创建由此抽象路径名命名的目录,包括任何必需但不存在的父目录。 | File af1=new File(“D:\itcast\java.txt”);
System.out.println(af1.createNewFile());//创建空文件
File aFile=new File(“D:\\itcast\\javaSE”);
System.out.println(aFile.mkdir());//创建目录
File bFile=new File(“D:\\itcast\\javaSE\HTML”);
System.out.println(bFile.mkdir());//
File cFile=new File(“D:\\itcast\\javaWeb\HTML”);
System.out.println(cFile.mkdirs());//创建多级目录
注意:不能根据文件名称判断创建的是文件还是目录,需要根据调用方法来判断
File类的删除功能
- |
boolean|delete()删除由此抽象路径名表示的文件或目录。 |
| ————- | ———————————————————————— |
| | |
- |
删除目录需要先删除当前目录下的文件
File类的判断和获取功能
File file=new File(“D:\itcast\java.txt”);
//isDirectory()判断是否为目录
System.out.println(file.isDirectory());
//isFile()判断是否为文件
System.out.println(file.isFile());
//exists()判断是否存在
System.out.println(file.exists());
//获取文件的绝对路径
System.out.println(file.getAbsolutePath());
//将此抽象类的路径名转换为字符串
System.out.println(file.getPath());
//返回次抽象路径名表示的文件或者名称
System.out.println(file.getName());
File aFile = new File(“D:\itcast”);
// String [] list();此方法有局限,获取目录中的文件和目录名称
String[] aStrings = aFile.list();
for (String string : aStrings) {
System.out.println(string);
}
// 创建一个File文件对象,在for循环中可以对file进行文件操作,例如判断文件是否存在,输出文件等等
File[] a = aFile.listFiles();
for (File file : a) {
System.out.println(file.getName());
}
字节流
1、字节流写数据
字节流抽象基类:
inputStream:这个抽象类是表示字节输入流的所有类的超类
outputStream:这个抽象类是表示字节输出流的所有类的超类
子类名特点:子类名称都是以其父类作为子类名的后缀
1、创建字节流对象
2、写数据
3、释放资源
FileOutputStream aFileOutputStream = new FileOutputStream(“java.txt”);
aFileOutputStream.write(97);
aFileOutputStream.close();
|
void|close()关闭此文件输出流并释放与此流相关联的任何系统资源。 |
| ———————— | —————————————————————————————— |
|protected void|finalize()清理与文件的连接,并确保当没有更多的引用此流时,将调用此文件输出流的close方法。 |
|FileChannel|getChannel()返回与此文件输出流相关联的唯一的FileChannel对象。 |
|FileDescriptor|getFD()返回与此流相关联的文件描述符。 |
|void|write(byte[] b)将b.length个字节从指定的字节数组写入此文件输出流。 |
|void|write(byte[] b, int off, int len)将len字节从位于偏移量off的指定字节数组写入此文件输出流。 |
|void|write(int b)将指定的字节写入此文件输出流。 |FileOutputStream aFileOutputStream = new FileOutputStream("java.txt"); aFileOutputStream.write(97); byte []a={1,2,3}; aFileOutputStream.write(a); byte []bs="12345679".getBytes();//
write(byte[] b)将b.length个字节从指定的字节数组写入此文件输出流。aFileOutputStream.write(bs);//write(byte[] b, int off, int len) 将
len字节从位于偏移量off的指定字节数组写入此文件输出流。aFileOutputStream.write(bs, 0, 5); aFileOutputStream.close();2、字節流写数据存在的问题
字节流写数据如何实现换行:
换行使用 :\n
字节流写数据如何追加写入:
追加在创建对象时对append属性:true
FileOutputStream aFileOutputStream = new FileOutputStream(“java.txt”, true);
for (int i = 0; i < 10; i++) {
aFileOutputStream.write(“i”.getBytes());
aFileOutputStream.write(“\n”.getBytes());
}
3、字节流写数据加异常处理
FileOutputStream aFileOutputStream = null;
try {
aFileOutputStream = new FileOutputStream(“java.txt”, true);
aFileOutputStream.write(“i”.getBytes());
aFileOutputStream.write(“\n”.getBytes());
} catch (IOException e1) {
// TODO 自动生成的 catch 块
e1.printStackTrace();
} finally {
try {
aFileOutputStream.close();
} catch (IOException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
4、字节流读数据(一个一个读)
FileInputStream aFileInputStream=new FileInputStream(“java.txt”);
//一个一个读
// int by= aFileInputStream.read();
// System.out.println(by);
// System.out.println((char)by);
// aFileInputStream.close();
int by;
while((by=aFileInputStream.read())!=-1){
System.out.print((char)by);
}
采用的是 int read()方法,当没有元素时返回的是-1,所以-1作为判断条件。
从一个文本读数据写到另一个文本案例
1、打开源文件
2、遍历源文件
3、打开目标文件,将原文件中的数据写到目标文件中
4、关闭目标文件
5、关闭源文件
FileInputStream aFileInputStream=new FileInputStream(“D:\txt.txt”);
int by;
while ((by=aFileInputStream.read())!=-1) {
FileOutputStream aFileOutputStream=new FileOutputStream(“java.txt”,true);
System.out.print((char)by);
aFileOutputStream.write(by);
aFileOutputStream.close();
}
aFileInputStream.close();
字节流读数据一次都一个数组
// FileInputStream aFileInputStream=new FileInputStream(“java.txt”);
// byte []bys=new byte[10];
// //第一次读取
// int len=aFileInputStream.read(bys);
// System.out.println(len);
// System.out.println(new String(bys, 0, len));
// //第二次读取
// len=aFileInputStream.read(bys);
// System.out.println(len);
// System.out.println(new String(bys, 0, len));
// aFileInputStream.close();
// //第三次读取
// len=aFileInputStream.read(bys);
// System.out.println(len);
// System.out.println(new String(bys, 0, len));
// aFileInputStream.close();
FileInputStream aFileInputStream=new FileInputStream(“java.txt”);
byte []bys=new byte[1024];
int len;
while((len=aFileInputStream.read(bys))!=-1) {
System.out.print(new String(bys, 0, len));
}
字节流复制图片
FileInputStream aFileInputStream=new FileInputStream("C:\\Users\\22603\\Pictures\\Saved Pictures\\2.png");//实例化源文件路径
FileOutputStream aFileOutputStream=new FileOutputStream("DLA.png");//实例化目标文件路径
int len;//定义字节长度
byte[]bys=new byte[1024];//定义字节数组
while((len=aFileInputStream.read())!=-1) {//判断条件,当字节长度为-1说明到达文件结尾
aFileOutputStream.write(bys,0,len);
}
aFileInputStream.close();
aFileOutputStream.close();//关闭文件
字节缓冲流
BufferOutputStream:该类实现缓冲输出流。通过设置这样的缓冲输出流,应用程序可以向底层输出流写入字节,而不必为写的的每一个字节导致底层系统的调用
BufferInputStream:创建该类将创造一个内部缓冲区数组,当从流中读取或跳过字节时,内部缓冲区,将根据所需要从包含的输入流中重新填充,一次很多字节。
BufferedOutputStream aBufferedOutputStream = new BufferedOutputStream(new FileOutputStream("text1.txt"));
aBufferedOutputStream.write("nihaoa".getBytes());
// Input读文件
BufferedInputStream aBufferedInputStream = new BufferedInputStream(new FileInputStream("text1.txt"));
int len;
byte[] a = new byte[1024];
while ((len = aBufferedInputStream.read(a)) != -1) {
System.out.println(new String(a, 0, len));
}
aBufferedOutputStream.close();
aBufferedInputStream.close();
字节文件(读入,写出)
字节流读写视频
import java.io.*;
import javax.imageio.stream.FileImageInputStream;
public class DemoMain7 {
public static void main(String[] args) throws IOException {
// TODO 自动生成的方法存根
long start=System.currentTimeMillis();
method1(); 4
// method2(); 2
// method3(); 3
// method4();//耗时最少 1
long endTime=System.currentTimeMillis();
System.out.println("共用时:"+(endTime-start)+"毫秒");
}
public static void method1() throws IOException {
//基本字节流一次写一个字节
FileInputStream aFileInputStream=new FileInputStream("C:\\Users\\22603\\Music\\MV\\1.mp4");
FileOutputStream aFileOutputStream=new FileOutputStream("音乐.mp4");
int by;
while ((by=aFileInputStream.read())!=-1) {
aFileOutputStream.write(by);
}
aFileInputStream.close();
aFileOutputStream.close();
}
public static void method2() throws IOException {
//基本字节流一次读一个字节数组
FileInputStream aFileInputStream=new FileInputStream("C:\\Users\\22603\\Music\\MV\\1.mp4");
FileOutputStream aFileOutputStream=new FileOutputStream("音乐.mp4");
byte []a=new byte[1024];
int len;
while ((len=aFileInputStream.read(a))!=-1) {
aFileOutputStream.write(a,0,len);
}
aFileInputStream.close();
aFileOutputStream.close();
}
public static void method3() throws IOException {
//字节缓冲流一次读一个字节
BufferedInputStream aBufferedInputStream = new BufferedInputStream(new FileInputStream("C:\\\\Users\\\\22603\\\\Music\\\\MV\\\\1.mp4"));
// Input读文件
BufferedOutputStream aBufferedOutputStream = new BufferedOutputStream(new FileOutputStream("音乐.mp4"));
int by;
while ((by=aBufferedInputStream.read())!=-1) {
aBufferedOutputStream.write(by);
}
aBufferedInputStream.close();
aBufferedOutputStream.close();
}
public static void method4() throws IOException {
//字节缓冲流一次读一个字节数组
BufferedInputStream aBufferedInputStream = new BufferedInputStream(new FileInputStream("C:\\\\Users\\\\22603\\\\Music\\\\MV\\\\1.mp4"));
// Input读文件
BufferedOutputStream aBufferedOutputStream = new BufferedOutputStream(new FileOutputStream("音乐.mp4"));
int len;
byte[] a = new byte[1024];
while ((len = aBufferedInputStream.read(a)) != -1) {
System.out.println(new String(a, 0, len));
}
aBufferedOutputStream.close();
aBufferedInputStream.close();
}
}
字符流
字符流写数据、读数据(读写编码需要对应)
- |
OutputStreamWriter(OutputStream out)创建一个使用默认字符编码的OutputStreamWriter。 |
| —————————————————————————————— |
|OutputStreamWriter(OutputStream out, Charset cs)创建一个使用给定字符集的OutputStreamWriter。 |
- |
|
InputStreamReader(InputStream in)创建一个使用默认字符集的InputStreamReader。 |
| —————————————————————————————— |
|InputStreamReader(InputStream in, Charset cs)创建一个使用给定字符集的InputStreamReader。 |
|InputStreamReader(InputStream in, CharsetDecoder dec)创建一个使用给定字符集解码器的InputStreamReader。 |
|InputStreamReader(InputStream in, String charsetName)创建一个使用命名字符集的InputStreamReader。 |// OutputStreamWriter(OutputStream out)
// 创建一个使用默认字符编码的OutputStreamWriter。
// OutputStreamWriter(OutputStream out, Charset cs)
// 创建一个使用给定字符集的OutputStreamWriter。OutputStreamWriter aFileOutputStream=new OutputStreamWriter( new FileOutputStream("test.txt"),"utf-8"); aFileOutputStream.write("测试文件"); aFileOutputStream.close();// InputStreamReader(InputStream in)
// 创建一个使用默认字符集的InputStreamReader。
// InputStreamReader(InputStream in, String charsetName)
// 创建一个使用命名字符集的InputStreamReader。InputStreamReader aInputStreamReader=new InputStreamReader(new FileInputStream("test.txt"),"utf-8"); int by; while ((by=aInputStreamReader.read())!=-1) { System.out.print((char)by); } aInputStreamReader.close();
字符流写数据、读数据
close和flush区别
- |
void|close()关闭流,先刷新。 |
| ——— | —————————————- |
|void|flush()刷新流。 |
- |
使用close后无法写数据,使用flush后还可以写数据。
OutputStreamWriter aFileOutputStream=new OutputStreamWriter(
new FileOutputStream(“test1.txt”),”utf-8”);
aFileOutputStream.write(97);
//aFileOutputStream.flush();
aFileOutputStream.write(97);
//aFileOutputStream.flush();
aFileOutputStream.close();
字符流写数据的五种方法
OutputStreamWriter aFileOutputStream=new OutputStreamWriter(
new FileOutputStream(“test1.txt”),”utf-8”);
1、一次写一个字符
aFileOutputStream.write(97);
//aFileOutputStream.flush();
aFileOutputStream.write(97);
//aFileOutputStream.flush();
aFileOutputStream.close();
2、一次写一个字符数组
char a[]={‘f’,’f’,’f’,’f’,’f’,’f’,’f’,’f’};
aFileOutputStream.write(a);
aFileOutputStream.close();
3、一次写一字符数组部分数据
调用的是 void write(cbuf, off, len);
char a[]={'f','f','f','f','f','f','f','f'};
aFileOutputStream.write(a, 1, 3);
aFileOutputStream.close();
4、一次写一个字符串
aFileOutputStream.write(“acdac”);
aFileOutputStream.close();
5、一次写字符串的一部分
aFileOutputStream.write("acdac", 1, 3);
aFileOutputStream.close();
aFileOutputStream.close();
字符流读数据的两种方法
InputStreamReader aStreamReader=new
InputStreamReader(new FileInputStream(“test1.txt”));
1、一次读一个字符
int by;
while ((by=aStreamReader.read())!=-1) {
System.out.println((char)by);
}
2、一次读一个字符数组
char []a=new char[1024];
int len;
while ((len=aStreamReader.read(a))!=-1) {
System.out.print(new String(a,0,len));
}
aStreamReader.close();
读写文件最简单的方法
FileWriter aFileWriter=new FileWriter(“test1.txt”);
FileReader aFileReader=new FileReader(“test1.txt”);
FileWriter 和 FileReader 分别是OutputStreamWriter 和 InputStreamReader 的子类。但不可以转换编码,如需转换编码仍需要用父类
字符缓冲流
BufferedReader aaReader=new BufferedReader(new FileReader(“test1.txt”));
BufferedWriter aBufferedWriter=new BufferedWriter(new FileWriter(“test1.txt”));
特有方法:
1、 BufferedReader aaReader=new BufferedReader(new FileReader(“test1.txt”));
String line;
while ((line=aaReader.readLine())!=null) {//readLine读取一行的数据,不读取换行符
System.out.println(line);
}
aaReader.close();
2、 BufferedWriter aBufferedWriter=new BufferedWriter(new FileWriter(“test1.txt”));
aBufferedWriter.write(“nihao”);
aBufferedWriter.newLine();//换行符
aBufferedWriter.close();
字符缓冲流特有功能复制文件(最常用)
BufferedReader aBufferedReader=new BufferedReader(new FileReader(“test1.txt”));
BufferedWriter aBufferedWriter=new BufferedWriter(new FileWriter(“test2.txt”));
String line;
while ((line=aBufferedReader.readLine())!=null) {
aBufferedWriter.write(line);
aBufferedWriter.newLine();
aBufferedWriter.flush();
}
aBufferedReader.close();
aBufferedWriter.close();
io流小结


集合到文件
ArrayList
arrayList.add(“nihao”);
arrayList.add(“wohao”);
arrayList.add(“dajiahao”);
BufferedWriter aBufferedWriter = new BufferedWriter(new FileWriter(“test3.txt”));
for (String string : arrayList) {
aBufferedWriter.write(string);
aBufferedWriter.newLine();
aBufferedWriter.flush();
}
aBufferedWriter.close();
文件到集合
BufferedReader aBufferedReader = new BufferedReader(new FileReader(“test3.txt”));
ArrayList
String line;
while ((line = aBufferedReader.readLine()) != null) {
arrayList.add(line);
}
aBufferedReader.close();
for (String string : arrayList) {
System.out.println(string);
}
点名器
ArrayList<Student>arrayList=new ArrayList<>();
BufferedWriter aBufferedWriter=new BufferedWriter(new FileWriter("test4.txt"));
Student a1=new Student("1001","zxq","18","xians");
Student a2=new Student("1002","sss","18","xianan");
Student a3=new Student("1003","sff","18","xianss");
Student a4=new Student("1004","www","18","xiandf");
arrayList.add(a1);
arrayList.add(a2);
arrayList.add(a3);
arrayList.add(a4);
for (Student student : arrayList) {
StringBuffer stringBuffer=new StringBuffer();
stringBuffer.append(student.getName()).append(",").append(student.getAge()).append(",").
append(student.getAddress());
aBufferedWriter.write(stringBuffer.toString());
aBufferedWriter.newLine();
aBufferedWriter.flush();
}
aBufferedWriter.close();
复制单级文件夹
package Demo3;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import javax.swing.text.DefaultEditorKit.CopyAction;
//TODO 自动生成的方法存根
//1、创建数据源目录File对象 ,路径为C:\Users\22603\Pictures\Saved Pictures
//2、获取数据源目录File对象的名称,即文件所保存的外层文件夹,Saved Pictures
//3、创建目的地目录File对象,路径名是File+Saved Pictures
//4、判断目的地目录对应的File是否存在,如果不存在,就创建
//5、获得数据源目录下所有文件的File数组
//6、遍历File数组,得到每一个File对象,其实就是数据源文件
//7、获得数据源文件File对象的,名称
//8、创建目的地文件File对象,路径名是目的地目录File\\Saved Pictures\\+.png
//9、复制文件,采用字节流
public class DemoMain1 {
public static void main(String[] args) throws IOException {
//1、创建数据源目录File对象 ,路径为C:\\pecsa
File srcFind=new File("C:\\pecsa");
//2、获取数据源目录File对象的名称,即文件所保存的外层文件夹,pecsa
String aString=srcFind.getName();
//3、创建目的地目录File对象,路径名是File+Saved Pictures
File Creade=new File("File",aString);
//4、判断目的地目录对应的File是否存在,如果不存在,就创建
if (!Creade.exists()) {
Creade.mkdir();
}
//5、获得数据源目录下所有文件的File数组
File[]list=srcFind.listFiles();
//6、遍历File数组,得到每一个File对象,其实就是数据源文件
for (File file : list) {
//7、获得目录下的每个文件名
String srcFileName=file.getName();
//8、创建目的地文件File对象,路径名是目的地目录File\\Saved Pictures\\+.png
File destFile=new File(Creade,srcFileName);
//9、复制文件,采用字节流,这里的File是源文件名,destFile是新创建的文件对象
CopyFile(file,destFile);
}
}
private static void CopyFile(File file, File destFile) throws IOException {
// TODO 自动生成的方法存根
BufferedOutputStream aBufferedOutputStream=new BufferedOutputStream(new FileOutputStream(destFile));
BufferedInputStream aBufferedInputStream=new BufferedInputStream(new FileInputStream(file));
byte a[]=new byte[1024];
int len;
while((len=aBufferedInputStream.read(a))!=-1) {
aBufferedOutputStream.write(a,0,len);
}
aBufferedOutputStream.close();
aBufferedInputStream.close();
}
}
复制多级文件(用到时回头看)
多线程
1、进程
进程是正在运行的程序,是系统进行资源分配和调用的独立单位
每个进程都有他自己的内存空间和系统资源
2、线程
线程是进程的单个顺序控制流,是一条执行路径
单线程:一个进程如果只有一条执行路径,则称为单线程程序
多线程:一个进程如果有多个执行路径,则成为多线程程序
举例:记事本程序(单线程)
扫雷程序(多线程)
3、多线程的实现方式
(方式1):继承Thread类
定义一个类继承Thread类,并重写该类中的run方法,创建多个对象,调用start方法执行多线程44
4、设置和获取线程名称
底层远吗中默认有getName和setName方法,为了简化我们可以在创建子类对象时传进去name,即有参构造方法
Thread(String name) 分配一个新的 Thread对象。
static Thread currentThread() 返回对当前正在执行的线程对象的引用。
1 | MyThread a1=new MyThread("线程1"); |
5、线程调度
分配调度模型:所有线程轮流使用cpu的权,平均分配每个线程占用cpu的时间片
抢占式调度模型:优先让优先级搞得线程使用cpu,如果线程优先级相同,随机选择一个,优先级高的线程获取cpu的时间相对多一点
java使用的是抢占式调度模型
//int getPriority() 返回此线程的优先级。 (线程优先级最高为10,最低为1,默认为5)
//void setPriority(int newPriority) 更改此线程的优先级。
MyThread a1=new MyThread("线程1");
MyThread a2=new MyThread("线程2");
a1.setPriority(10);
a2.setPriority(1);
改变线程优先级是优先级高的表示获取cpu时间片的几率高一点,并不是彻底改变优先级次序
6、线程控制
(1)//static void sleep(long millis) 使当前正在执行的线程以指定的毫秒数暂停(暂时停止执行),具体取决于系统定时器和调度程序的精度和准确性。
public void run() {
// TODO 自动生成的方法存根
for (int i = 0; i < 600; i++) {
System.out.println(getName()+”:”+i);
}
try {
//static void sleep(long millis) 使当前正在执行的线程以指定的毫秒数暂停(暂时停止执行)
//,具体取决于系统定时器和调度程序的精度和准确性。
Thread.sleep(10);
} catch (InterruptedException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
}
(2)//void join() 等待这个线程死亡。
Test a1=new Test(“刘备”);
Test a2=new Test(“孙权”);
Test a3=new Test(“曹操”);
//void join() 等待这个线程死亡。
a1.start();
//这里的意思是等刘备死后孙权和曹操抢占cup时间
a1.join();
a2.start();
a3.start();
(3)//void setDaemon(boolean on) 将此线程标记为 daemon线程或用户线程。
Test a1=new Test("刘备");
Test a2=new Test("张飞");
Thread.currentThread().setName("关羽");//为当前main线程重新命名
//void setDaemon(boolean on) 将此线程标记为 daemon线程或用户线程。即主线程死亡后守卫线程也灭亡
//设置守护线程
a1.setDaemon(true);
a2.setDaemon(true);
a1.start();
a2.start();
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName()+":"+i);
}
**ps:主线程灭亡后,守卫不会立马死亡,会挣扎运行一段时间**
ps:主线程灭亡后,守卫不会立马死亡,会挣扎运行一段时间
7、另一种多线程实现方式(实现Runnable接口)
1 | package bb; |
1 | Thread aThread=new Thread(new Test(),"zxq"); |
相比继承Thread类,实现Runnable接口的好处:
1、避免了java单继承的局限性
2、适合多个相同程序的代码去处理同一个资源的情况,吧线程和程序的代码、数据有效分离,较好的体现了面向对象的设计思想
8、数据安全问题
是否是多线程环境
是否有共享数据
是否有多条语句操作共享数据
9、线程同步代码块
1 | package Sell; |
10、同步方法
把synchronized关键字加到方法上
修饰符 synchronized 返回值类型 方法名(方法参数){ }
同步方法的锁对象是什么?
this
同步静态方法:就是把synchronized关键字加到静态方法上
同步静态方法的锁对象是什么?
类名.class
11、线程安全的类
(1)StringBuffer从jdk5开始被stringBuilder替代,通常应使用stringBuilder类
(2)vector从java2平台V1.2开始,该类改进了list接口,如果不需要线程安全的实现,建议使用arraylist替代vector
(3)Hashtable
实现了哈希表,如果不需要线程安全的实现,建议使用Hashmap替代Hashtable
12、
枚举
1、枚举是一种特殊的类,一般用来表示常量。
2、Java 枚举类使用 enum 关键字来定义,各个常量使用逗号 , 来分割。
3、每个枚举都是通过 Class 在内部实现的,且所有的枚举值都是 public static final 的。
4、枚举既可以单独写一个类,也可以在已经定义的类中写
1 | public class DemoMain1 { |
等同于:
1 | public class DemoMain1 { |
5、迭代枚举元素
for (color c : color.values()) {
System.out.println(c);
}
6、values(), ordinal() 和 valueOf() 方法
enum 定义的枚举类默认继承了 java.lang.Enum 类,并实现了 java.lang.Seriablizable 和 java.lang.Comparable 两个接口。
values(), ordinal() 和 valueOf() 方法位于 java.lang.Enum 类中:
values() 返回枚举类中所有的值。
ordinal()方法可以找到每个枚举常量的索引,就像数组索引一样。
valueOf()方法返回指定字符串值的枚举常量。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16color aColor=color.Red;
System.out.println(aColor);
for (color c : color.values()) {
System.out.println(c+" "+c.ordinal());//ordinal返回索引下标
System.out.println(c.valueOf("Red"));//返回指定字符串值的枚举常量
}
enum{
Red,Green,Blue;
private color(){
System.out.println(this.toString());
}
public void colorInfo()
{
System.out.println("Universal Color");
}
}
7、枚举类成员
枚举跟普通类一样可以用自己的变量、方法和构造函数,构造函数只能使用 private 访问修饰符,所以外部无法调用。
枚举既可以包含具体方法,也可以包含抽象方法。 如果枚举类具有抽象方法,则枚举类的每个实例都必须实现它。
构造函数时,创建对象就会调用,遍历枚举类中的所有常量。
1 | enum Color{ |
