1.1包装数据类型
针对于基本数据类型实现的类类型转换。例如,一个int类型如果想要完成比如类似于数据类型转换,再比如完成获取到整型的最大值。在包装数据类型当中对以上的操作都提供对应的API。能够更加的面向对象设计。在java中一共有八种包装数据类型,都来自于java.lang包,提供了Boolean、Byte、Character、Double、Float、Integer、Logn、short。这里以Integer举例:
1.2 Integer
1.2.1基本使用方式
//自动拆装箱
//自动装箱
Integer num = 25 ; //将一个int类型转换为Integer包装数据类型
num.xxx() ;
//自动拆箱
int num1 = num ; // 将一个Integer类型转换为int类型
//Integer中提供了大量的静态方法,可以实现各种不同所需操作。
Integer num = Integer.valueOf(int num) ;
API:
valueOf():实现将一个字符串(数值)或者是普通int类型转换为Integer包装类型。
public static Integer valueOf(String s)
throws NumberFormatException
public static Integer valueOf(int i)
NumberFormatException:在进行数字格式化转换的过程中,如果无法转换就会抛出异常
parseInt():将一个字符串转换为int类型。
public static int parseInt(String s)
throws NumberFormatException
1.2.2Integer中的cache缓存
在Integer类中,为了能够提高性能,所以采用了缓存的机制。在进行复制过程中。如果值得范围在-128~127之间,就会从缓存中直接返回对应的值,但如果超过了范围,就会从新构建一个Integer对象。
private final int value;
public Integer(int value) {
this.value = value;
}
private static class IntegerCache {
static final int low = -128;
static final int high;
static final Integer[] cache; //缓存
static {
// high value may be configured by property
int h = 127;
String integerCacheHighPropValue =
VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
if (integerCacheHighPropValue != null) {
try {
h = Math.max(parseInt(integerCacheHighPropValue), 127);
// Maximum array size is Integer.MAX_VALUE
h = Math.min(h, Integer.MAX_VALUE - (-low) -1);
} catch( NumberFormatException nfe) {
// If the property cannot be parsed into an int, ignore it.
}
}
high = h;
// Load IntegerCache.archivedCache from archive, if possible
CDS.initializeFromArchive(IntegerCache.class);
int size = (high - low) + 1;
// Use the archived cache if it exists and is large enough
if (archivedCache == null || size > archivedCache.length) {
Integer[] c = new Integer[size];
int j = low;
for(int i = 0; i < c.length; i++) {
c[i] = new Integer(j++);
}
archivedCache = c;
}
cache = archivedCache;
// range [-128, 127] must be interned (JLS7 5.1.7)
assert IntegerCache.high >= 127;
}
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
int num = 20 ;
Integer num1 = 20 ;
num == num1 true
Integer num1 = 122 ;
Integer num2 = 122 ;
num1 == num2 //true
Integer num1 = 128 ;
Integer num2 = 128 ;
num1 == num2 //false
1.3Collection框架
Collection集合的特点是不唯一且无序。该集合接口是List与Set的父接口,为子类定义了大量的方法。该接口位于java.util包中。
java集合框架提供了一套性能优良、使用方便的接口和类,他们位于java.util包中。Collections提供了对集合进行排序、遍历等多种算法实现。
collection:接口存储一组不唯一,无序的对象。
List:接口存储一组不唯一,有序(插入顺序)的对象
ArrayList底层是动态数组,初始容量是0
LinkedList底层为双向链表
Set接口存储一组唯一,无序的对象
HashSet利用散列表的形式,将对象存储在HashMap的key位置上。
Treeset底层时红黑树。
Map接口存储一组键值对象,提供key到value的映射
HashMap是线程不安全的类,底层是哈希桶。
TreeMap是线程安全的,底层为红黑树。
1.3.1 Collections
Collections是集合中的一个工具类、提供了大量的静态方法,如addAll()、bianarySearch()、max()、mix()、copy()、synchronizedCollection(Collection<T> c)提供程序员的开发效率。
1.4List
List集合继承了Collection接口。是一个线程不安全的集合类。能够存储null对象。其元素不唯一且有序。主要有ArrayList和LinkedList实现。是一个线程不安全的类。
List接口常用方法:
1.4.1ArrayList
ArrayList实现了长度可变的数组,在内存中分配连续的空间。遍历元素和随机访问元素的效率比较高。能够存放任意Object类型,还能够自动扩容和缩放。
使用ArrayList数组:
List dogs = new ArrayList();
ArrayList和数组之间的区别:
数组:数据类型不可变。长度也不可发生改变,能够存放基本数据类型和引用数据类型。
ArrayList:采用的是纯面向对象方式设计,底层应用是数组实现。只能够放置对象类型,即使放置的是基本数据类型,也会自动实现装箱过程。同时可以支持长度扩容和收缩。提供了大量的方法提供程序员使用,性能在固定大小以及数据类型场景下,性能不如数组。
1.4.2LinkedList
LinkedList底层是双向链表结构。
LinkedList采用链表存储方式。插入、删除元素时效率比较高,并且允许所有元素(包括null)。除了实现List接口外,LinkedList类还为在列表的开头以及结尾add、get、remove和insert元素提供了统一的命名方法。
使用LinkedList数组:
LinkedList dogs = new LinkedList();
LinkedList的特殊方法:
1.5Set
Set集合继承了Collection接口。是一个线程不安全的集合类。能够存储null对象。其存储元素唯一且无序,底层应用是HashMap的实例实现的。
Set集合中的API方法和Collection父类接口基本一致:
1.5.1HashSet
HashSet,利用散列表的形式,将对象存储在HashMap的key位置上。元素唯一且无序。
唯一性:如果在进行一个位置计算时,能够找到合适的位置(没有值),就会将值直接放进去,但是如果该位置有值,就会采用qeuals()方法和hashcode对位置上的内容进行比较。如果完全一致,就会直接覆盖。
用法:
Set<类型> set = new HashSet();
Dog dog1 = new Dog("花花","拉布拉多",20) ;
Dog dog2 = new Dog("草草","雪橇",40) ;
Dog dog3 = new Dog("树树","吉娃娃",50) ;
Dog dog4 = new Dog("木木","萨摩耶",80) ;
Dog dog5 = new Dog("水水","阿拉斯加",10) ;
set.add(dog1) ;
set.add(dog2) ;
set.add(dog3) ;
set.add(dog4) ;
set.add(dog5) ;
set.add(dog1) ;
//打印时会发现只有5只狗,由于dog1对象已经存在,所以set将后面的dog1对前面dog1对象进行了覆盖(equals、hashcode)。
1.5.2Iterator迭代器
对Collection进行迭代的迭代器。Iterator接口,其中包含了hasNext()以及next()
方法。可以判断是否还拥有下一个元素,如果还拥有下一个元素,可以通过next()获取对应元素。该迭代器只能作用在集合中。
Dog dog1 = new Dog("花花","拉布拉多",20) ;
Dog dog2 = new Dog("草草","雪橇",40) ;
Dog dog3 = new Dog("树树","吉娃娃",50) ;
Dog dog4 = new Dog("木木","萨摩耶",80) ;
Dog dog5 = new Dog("水水","阿拉斯加",10) ;
//ArrayList会出现重复对象
List<Dog> list =new ArrayList() ;
list.add(dog1);
list.add(dog2);
list.add(dog3);
list.add(dog4);
list.add(dog5);
list.add(dog2);
Iterator it = list.iterator() ;
while(it.hasNext()) {
//输出或者进行类型转换
System.out.println(it.next()) ;
}
1.5.3一对多双向绑定
代表类中两个类的关系表示。通常在一的一方放置一个集合属性,在多的一方放置一的一方的引用。这里用一个年纪有多个学生为例:
Grade类:
package com.csi.domain;
import java.util.Set;
public class Grade {
//年级编号
private int gradeNO ;
//年级名称
private String gradeName ;
//年级备注
private String gradeDesc ;
//一对多关系映射:表示多个学生对象
private Set<Student> studentSet ;
public int getGradeNO() {
return gradeNO;
}
public void setGradeNO(int gradeNO) {
this.gradeNO = gradeNO;
}
public String getGradeName() {
return gradeName;
}
public void setGradeName(String gradeName) {
this.gradeName = gradeName;
}
public String getGradeDesc() {
return gradeDesc;
}
public void setGradeDesc(String gradeDesc) {
this.gradeDesc = gradeDesc;
}
public Set<Student> getStudentSet() {
return studentSet;
}
public void setStudentSet(Set<Student> studentSet) {
this.studentSet = studentSet;
}
}
Student类:
package com.csi.domain;
public class Student {
private String studentNO ;
private String studentName ;
private int age ;
//建立一对一关系映射,表示一个学生对应一个年级
private Grade grade ;
public String getStudentNO() {
return studentNO;
}
public void setStudentNO(String studentNO) {
this.studentNO = studentNO;
}
public String getStudentName() {
return studentName;
}
public void setStudentName(String studentName) {
this.studentName = studentName;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Grade getGrade() {
return grade;
}
public void setGrade(Grade grade) {
this.grade = grade;
}
}
测试:
package com.csi.test;
import com.csi.domain.Grade;
import com.csi.domain.Student;
import java.util.HashSet;
import java.util.Set;
public class TestGradeAndStudent {
public static void main(String[] args) {
/*实现类关系设计的双向绑定*/
Grade grade = new Grade() ;
grade.setGradeNO(1);
grade.setGradeName("三年二班");
grade.setGradeDesc("这是三年二班");
/*********************************************/
Student mzh = new Student() ;
mzh.setStudentNO("100110");
mzh.setStudentName("xxx");
mzh.setAge(20);
//一对一关系绑定
mzh.setGrade(grade);
Student cjx = new Student() ;
cjx.setAge(21);
cjx.setStudentName("xxx");
cjx.setStudentNO("100119");
cjx.setGrade(grade);
Set<Student> set = new HashSet<>() ;
set.add(mzh) ;
set.add(cjx) ;
/*****************************************/
//建立一对多的关系
grade.setStudentSet(set);
System.out.println("年级名称:" + grade.getGradeName());
System.out.println("该年级中包含了" + grade.getStudentSet().size() + "名学生");
System.out.println("学生编号\t\t学生姓名\t\t所属年级");
for(Student student: grade.getStudentSet()) {
System.out.println(student.getStudentNO() +
"\t\t" + student.getStudentName() +
"\t\t" + student.getGrade().getGradeName());
}
}
}
1.5.4Treeset
Treeset默认情况下能够对“基本数据类型”进行自然排序,但是功能更加倾斜于对于对象的排序。对象如果想要实现自定义排序的排序方式,则需要自定义类采用实现‘java.lang.comp’
1.6Map
Map接口存储一组键值对象,提供key(唯一)到value的映射。
Map实现:
Map countries = new HashMap();
countruies.put("CN","中华人民共和国");
countruies.put("US","美利坚和众国");
Map接口常用方法:
1.6.1HashMap
注意,此实现不是同步的。左侧的key是不能够重复的,右侧的值可以重复。基于哈希表的Map接口的实现。此实现提供所有可选的映射操作,并允许使用null值和null键。(除了非同步和允许使用null之外,HashMap类与Hashtable大致相同。)由于采用的是数组+链表+红黑树的结构,所以需要保障将key能够均匀分布在数组中,在过程当中,应用了key的hashcode值重新计算(高低位参与计算)结合位运算(数组长度-1&hashcode[该作用与hash值对数组长度取模一致]),此类不保证映射的顺序,特别是它不保证该顺序恒久不变【当数据量过多可能会出现集合扩容】
此实现假定哈希函数将元素适当的分布在个桶之间,可为基本操作(get和put)提供稳定的性能。迭代collection视图所需的时间与HashMap实例的“容量”(桶的数量)及其大小(键-值映射关系数)成比例。所以,如果迭代性能很重要,则不要将初始容量设置太高(或将加载因子设置的太低)。
扩容点实在‘数组长度(1<<4 16)*负载因子(0.75)',负载因子0.75是一种通过大量的运算和实验所得到的最佳值,过大会造成空间不够使用,过小会造成空间浪费。
1.6.2遍历Map集合的方法:
方法1:通过迭代器Iterator实现遍历
获取Iterator:Collection接口的iterator()方法
Iterator的方法:boolean hasNext():判断是否存在另一个可访问的元素。Object next():返回要访问的下一个元素。
方法2:增强for循环
public static void main(String[] args) {
Map<String, List<Goods>> map = new HashMap<>();
Goods goods1 = new Goods("1001","洗衣机",2000);
Goods goods2 = new Goods("1002","电视",3000);
Goods goods3 = new Goods("1003","电脑",1000);
Goods goods4 = new Goods("1004","手机",4000);
List<Goods> list = new ArrayList<>();
list.add(goods1);
list.add(goods2);
list.add(goods3);
list.add(goods4);
Goods goods11 = new Goods("1011","小米汽车",210000);
Goods goods12 = new Goods("1012","奥迪汽车",230000);
Goods goods13 = new Goods("1013","奔驰汽车",310000);
Goods goods14 = new Goods("1014","宝马汽车",410000);
List<Goods> list1 = new ArrayList<>();
list1.add(goods11);
list1.add(goods12);
list1.add(goods13);
list1.add(goods14);
map.put("电子产品",list);
map.put("汽车",list1);
for (Map.Entry<String,List<Goods>> listEntry : map.entrySet()){
System.out.println(listEntry.getKey());
for (Goods list2 : listEntry.getValue()){
System.out.println(list2.getGoodsNO()+"\t\t"+list2.getGoodsName()+"\t\t"+list2.getGoosPrice());
}
}
}
1.7异常处理
顶级父类是Throwable类,其中包括Error错误类,Exception异常类。Exception包括两类,一类是运行时异常,另一类是检测异常。所有错误都是Error的直接或间接子类。
运行时异常和非运行时异常;RuntimeException的子类都是运行时异常,其他的都是非运行时异常。
运行时异常:也称为非检测异常(unchecked Exception),这些异常在编译期不检测,程序可以选择处理,也可以不处理。如果不处理运行时会中断,但是编译没问题;
非运行时异常:也称为检测异常(checked Exception),是必须进行处理的异常,如果不处理,将发生编译期错误;
1.7.1 try...catch...finally
try{
//代码块:要包含的内容可能就会产生异常。
}catch(异常类型 e) {
e.printStackTrace() ;
}catch(异常类型 e) {
System.out.println(e.getMessage()) ;
}catch(Exception e) { //大的异常要放在后面。
System.out.println(e) ;
return ; //return永远都会最后执行。先会执行finally块。
}finally{
//最终要执行的代码块。一般用作资源释放或者是关闭。
}
try{
}finally{
}
当try块中代码抛出了异常对象后,异常处理机制就将这个对象的类型与try后的catch语句中的异常类型进行匹配,如果类型相同,或者抛出的是捕获的子类,就称为匹配成功,那么异常就被捕获,就允许catch块中的语句,否则,称为异常没有被捕获,程序将中断。
如果try中有多行代码,有可能抛出多种类型异常,那么可以使用多个catch语句:
注意:catch语句的异常类型必须从子类到父类的顺序,否则编译错误。
如果希望不管什么情况,有一些代码都是必须被执行,那么就可以把这些代码写道finally块中,一般用于资源的清理和释放工作。如:关闭已打开的文件、删除临时文件, 释放数据库连接。
try可以省略catch与finally连用,如果出现了异常,不会被捕获处理,而是会继续finally。
1.7.2 throw与throws
两个关键字都是用于抛出异常。throw作用在方法体内容,而throws是放置在方法声明中。throw可以和自定义异常以及系统异常一起使用。
如果抛出的是运行时异常,那么调用者是不需要进行异常处理,将异常信息在运行过程中出现异常时,由JVM虚拟机进行处理。
public void show(int i) {
if(i == 0) {
throw new RuntimeException() ;
}
}
//自定义异常
public class MyException extends Exception {
public MyException() {
super("2003:异常信息") ;
}
public MyException(String msg) {
super(msg) ;
}
public MyException(Throwable th) {
super(th) ;
}
public MyException(Throwable th,String message) {
super(th,message) ;
}
}
public class Person {
//如果是一个普通异常继承,则必须抛出时在方法声明上也要同时配合抛出。
public void show(int i) throws MyException {
if(i == 0) {
throw new MyException() ;
}
}
}
public static void main() {
try{
new Person.show() ;
}catch(MyException e) {
e.printStackTrace() ;
}
}
1.7.3 如果存在了finally、return、exit方法、运行顺序:
在try中没有异常的情况下try、catch、finally的执行顺序try --- finally
如果rty中有异常,执行顺序是try---catch---finally
如果try中没有异常并且try中有return这时候正常执行顺序是try---finally---return
如果try中有异常并且try中有return这时候正常执行顺序是try---catch---finally---return
如果try中有异常,相应catch中有return,顺序是try---catch---finally---return
总之fianlly永远执行!!!!!!!!除非前边有System.exit(0)退出虚拟机。
当try中有异常时,在catch中如果加了System.exit(1)--->(退出虚拟机的方法)
当try中没有异常时如果加了System.exit(1);--->(退出虚拟机的方法)
System.exit(参数);
参数: 0 或 1 都代表退出虚拟机
0:正常退出
1:非正常退出