Java学习日记基础篇(九) —— 集合框架,泛型,异常
集合框架
有事我们会需要一个能够动态的调整大小的数组,比如说要添加新员工但是数组已经满了,并且数组的大小是在定义的时候定死的,所以我们就需要一个能够动态调整大小的数组或者用链表解决,而java中提供了这样一组数组,名为集合类。(有事还是需要链表来解决一些问题的)

重要的就是linkedlist,arraylist,vector,hashset,hashmap
从图中可以看出Java的集合类主要有以下几种:
- List结构的集合类 —— ArrayList类,LinkedList类,Vector类,Stack类
- Map结构的集合类 —— HashMap类,HashTable类
- Set结构的集合类 —— HashSet类,Hashtable类
- Queue结构的集合 —— Queue接口
List类——列表结构
ArrayList和Vector的区别
- 同步性:Vector是同步的而ArrayList则是异步的。所以ArrayList是不安全的但是效率高。
- 数据增长:Vector会增长一倍的原数组的大小,ArrayList会增长原来的50%,所以集合所占的空间要比实际的需求要大
ArrayList类
//使用ArrayList类就要引入一个包
import java.util.*;
public class test1 {
public static void main(String[] args) {
//定义一个ArrayList对象
ArrayList al = new ArrayList(); //显示大小,用ArrayList类提供的size方法
System.out.println("大小是:"+al.size()); //向al中加入数据(类型是Object,Java中所有的类都是从Object中集成下来的,这意味着集合中可以放所有类型的类)
//创建一个职员
Clerk clerk1 = new Clerk("松江", 50, 1000);
Clerk clerk2 = new Clerk("吴用",45,1200);
//将clerk1加入到al中
al.add(clerk1);//默认加载到尾部
al.add(clerk2);
System.out.println("大小是:"+al.size()); //如何访问al中对象(数据)
//访问第一个对象
//Clerk temp = al.get(0);//get()返回的对象是object类型的,是clerk类型的父类,所以会报错
//强制转换
Clerk temp = (Clerk)al.get(0);
System.out.println("第一个人的名字是:"+ temp.getName()); //从al中删除一个对象
al.remove(1);
}
}
class Clerk
{
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public float getSal() {
return sal;
}
public void setSal(float sal) {
this.sal = sal;
}
private int age;
private float sal;
public Clerk(String name,int age,float sal)
{
this.name = name;
this.age = age;
this.sal = sal;
}
}
添加,遍历和删除对象
用ArrayList来实现一个简单的员工管理系统
LinkedList类
import java.util.*;
public class test4 {
public static void main(String[] args) {
// TODO Auto-generated method stub
LinkedList l1 = new LinkedList();
Emp emp1 = new Emp("sa01","aa",1.2f);
Emp emp2 = new Emp("sa01","bb",1.2f);
l1.addFirst(emp1);//直接往前加,在链表的最前边
l1.addFirst(emp2);
for(int i=0;i<l1.size();i++)
{
System.out.println(((Emp)l1.get(i)).getName());
}
l1.remove(0);//删除也是原来的命令
for(int i=0;i<l1.size();i++)
{
System.out.println(((Emp)l1.get(i)).getName());
}
}
}
能够把后添加的数放到前边
Vector类
Stack类
Map结构的集合类
HashMap和Hashtable的区别
- 历史原因:Hashtable是基于陈旧的Dictonary类的,HashMap是java 1.2引进的Map接口的一个实现
- 同步性:HashTable是同步的。这个类中的一些方法保证了Hashtable中的对象是线程安全的。而HashMap则是异步的,因此HashMap中的对象并不是线程安全的。因为同步的要求会影响执行的效率,所以如果不需要线程安全的集合那么使用HashMap是一个很好的选择,这样可以避免由于同步带来的不必要的性能开销,从而提高效率
- 值:HashMap可以让你将空值作为一个表的条目的key或value,但是Hashtable是不能放入空值的
HashMap类
public class test7 {
public static void main(String[] args)
{
//创建一个HashMap对象
HashMap hm = new HashMap();
Emp emp1 = new Emp("s001","aaa",12.3f);
Emp emp2 = new Emp("s002","bbb",12.3f);
Emp emp3 = new Emp("s003","ccc",2.3f);
//将emp放入到hm中
//以键值对的形式存入的,查询的时候可以通过是否有指定键或值来查找
//键是key,值是value
hm.put("s001", emp1);
hm.put("s002", emp2);
}
}
创建一个HashMap对象
HashMap的对象的键的值是唯一的
public class test7 {
public static void main(String[] args)
{
//创建一个HashMap对象
HashMap hm = new HashMap();
Emp emp1 = new Emp("s001","aaa",12.3f);
Emp emp2 = new Emp("s002","bbb",12.3f);
Emp emp3 = new Emp("s003","ccc",2.3f);
//将emp放入到hm中
//以键值对的形式存入的,查询的时候可以通过是否有指定键或值来查找
//键是key,值是value
hm.put("s001", emp1);
hm.put("s002", emp2);
hm.put("s002", emp3);//emp3会替换掉emp2,不键允许重复
//如果你要查找编号是s002的人
if(hm.containsKey("s002"))//有这个键就返回真,没有就返回假
{
System.out.println("有这个员工");
//如何取出
Emp emp=(Emp)hm.get("s002");
System.out.print("名字:"+emp.getName());
}
else{System.out.println("没有");}
}
}
在HashMap类中查找对象
遍历集合中所有的对象
import java.util.*;
public class test7 {
public static void main(String[] args)
{
//创建一个HashMap对象
HashMap hm = new HashMap();
Emp emp1 = new Emp("s001","aaa",12.3f);
Emp emp2 = new Emp("s002","bbb",12.3f);
Emp emp3 = new Emp("s003","ccc",2.3f); //将emp放入到hm中
hm.put("s001", emp1);
hm.put("s002", emp2);
hm.put("s003", emp3);//emp3会替换掉emp2,不键允许重复 //遍历HashMap中所有的key和value
//用迭代器Iterator
Iterator it = hm.keySet().iterator(); //hasNext返回一个boolean
while(it.hasNext())
{
//取出key
String key = it.next().toString();
//通过key取出value
Emp emp =(Emp)hm.get(key);
System.out.println("名字:"+emp.getName());
}
}
}
遍历集合中的所有对象
注意:取出来的是乱序的,所以这是它的一个缺点
Hashtable类
总结
java的设计者给我们提供了这些集合类,在后面编程中式相当有用的,具体什么时候用什么集合,要根据我们刚才分析的集合一同来选取。
- 如果要求线程安全,使用Vector、Hashtable
- 如果不要求线程安全,应使用ArrayList,LinkedList,HashMap
- 如果要求有--键值对,则使用HashMap,Hashtable
- 如果数据量很大,又要考虑线程安全用Vector
泛型
泛型的本质是参数化类型,也就是说所有操作的数据类型被指定成为一个参数。这种参数类型可以在类,接口和方法的创建中,分别称为泛型类、泛型接口、泛型方法。
Java引入泛型的好处是安全简单。泛型的好处是在编译的时候检查类型安全,并且所有的强制转换都是自动和隐式的,提高代码的重用率。
案例:取出集合中的对象的时候需要进行强制的类型转换,否则会报错
import java.util.*; * 功能:了解泛型的必要性
* 时间:2018.10.26 public class test4 {
public static void main(String[] args) {
// TODO Auto-generated method stub
ArrayList al = new ArrayList();
Dog dog1 = new Dog();
//放入到集合中
al.add(dog1);
//取出
Dog temp = (Dog)al.get(0);//要有一个强转类型
}
} class Dog
{
private String name;
private 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;
} }
泛型

我们在创建一个猫类,可以看出猫类中属性的数据类型和狗类的完全相同,但是表达的意义却不相同,这会引发一个常见的错误,dog类不能转换成dog类型
package project1;
import java.util.*; * 功能:了解泛型的必要性
* 时间:2018.10.26 public class test4 {
public static void main(String[] args) {
// TODO Auto-generated method stub
ArrayList al = new ArrayList();
Dog dog1 = new Dog();
//放入到集合中
al.add(dog1);
//取出
//Dog temp = (Dog)al.get(0);//要有一个强转类型
Cat temp = (Cat)al.get(0); //这样写也不会报错,
//但编译的时候会出错--类型转换出错
} } class Dog
{
private String name;
private 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;
} } class Cat
{
private String color;
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
private int age;
}
类型转换出错



用泛型类解决这个问题


泛型的经典用法——Java中的反射机制
public class test5 {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Gen<String> gen1 = new Gen<String>("aaa");//括号内填写字符串类型
gen1.showTypeName();
Gen<Integer> gen2 = new Gen<Integer>(1);//括号内是Integer类型
gen2.showTypeName();
//
Gen<Bird> gen3 = new Gen<Bird>(new Bird());//括号内是自己新new的Bird类型
gen3.showTypeName();
}
}
//定义一个鸟类
class Bird
{
public void testt1()
{
System.out.println("aa");
}
public void count(int a,int b)
{
System.out.println(a+b);
}
}
class Gen<T> //T是自己定义的一个类,传入的是什么类型就是什么类型
{
private T o;
//构造函数
public Gen(T a)
{
o=a;
}
//得到T的类型名称
public void showTypeName()
{
System.out.println("类型是:"+o.getClass().getName());
}
}
结果:
类型是:java.lang.String
类型是:java.lang.Integer
类型是:project1.Bird
初识反射机制
通过反射机制可以拿到类的很多信息
import java.lang.reflect.Method;
public class test5 { /**
* @param args
*/
public static void main(String[] args) { //
Gen<Bird> gen3 = new Gen<Bird>(new Bird());//括号内是自己新new的Bird类型
gen3.showTypeName(); } } //定义一个鸟类
class Bird
{
public void testt1()
{
System.out.println("aa");
}
public void count(int a,int b)
{
System.out.println(a+b);
}
}
class Gen<T> //T是自己定义的一个类,传入的是什么类型就是什么类型
{
private T o;
//构造函数
public Gen(T a)
{
o=a;
}
//得到T的类型名称
public void showTypeName()
{
System.out.println("类型是:"+o.getClass().getName()); //通过反射机制,我们可以得到T这个类型的很多信息(比如得到成员函数名)
Method []m = o.getClass().getDeclaredMethods();
//这个method需要导包 for(int i=0;i<m.length;i++)
{
System.out.println("函数名:"+m[i].getName());
}
}
} 运行结果:
类型是:project1.Bird
函数名:count
函数名:testt1
利用反射机制拿类的信息
泛型的优点
- 类型安全
- 向后兼容
- 层次清晰
- 性能较高用GJ(Generic in Java泛型Java)编写的代码可以为java编译器和虚拟机带来更多的类型信息,这些信息对java程序做进一步优化提供条件着(以后就明白了)
异常处理
基本概念:当出现程序无法控制的外部环境问题(用户提供的文件不存在,文件内容损坏,网络不可用。。。)时,Java就会用异常对象来描述。
Java中用两种方法处理异常:
1、在发生异常的地方直接处理
2、将异常抛给调用者,让调用者处理
异常分类
- 检查性异常:java.lang.Exception
- 运行期异常:java.lang.RuntimeException
- 错误:java.lang.Error
顶层都是java.lang.Throwable集成而来,检查性异常,运行期异常,错误都是这个类的子孙类。
- 检查性异常(也叫编译异常):程序正确,但因为外在的环境条件不满足引发。例如:用户错误及I/O问题。这不是程序本身的逻辑错误。对于商用软件系统,程序开发者必须考虑并处理这个问题。Java编译器强制要求处理这类异常,如果不能捕获这类异常,程序将不能被编译。
- 运行期异常:这意味着程序存在bug,如数组越界,0被除,入参不满足规范等等,这类异常需要更改程序来避免,Java编译器要求强制处理这类异常。
- 错误:一般很少见,也很难通过程序解决。它可能源于程序的bug,但一般更可能源于环境问题,如内存耗尽,杀毒软件太sd。错误在程序中无需处理,而由运行环境处理。
案例:
package project1;
//要使用打开文件的类,就要引入IO包
import java.io.*;
import java.net.*; public class test6 {
public static void main(String[] args) {
// TODO Auto-generated method stub
//检查异常 1.打开一个不存在的文件
FileReader fr = new FileReader("d:\\a.text"); //2.连接一个不存在的ip端口
Socket s = new Socket("192.168.1.23" , 78); } }
检查性异常

运行期异常排错要比检查性异常难得多
public class test7 {
public static void main(String[] args) {
//1.除0操作
int a=4/0;
//2.数组越界
int arr[] = {1,2,3};
System.out.println(arr[123]);
}
}
运行期异常


错误
异常的解决方法——捕获异常以及将异常抛出去
捕获异常
import java.io.*;
public class test8 {
public static void main(String[] args) {
try {
FileReader fr=new FileReader("d:\\aa.text");
}
catch (Exception e)//Exception是最大的异常
{
// 把异常输出出来,易于排错
e.printStackTrace();
} //最小捕获--有什么异常就捕获什么异常
try {
FileReader fr=new FileReader("d:\\aa.text");
}
catch (FileNotFoundException e) //
{
// 把异常输出出来,易于排错
e.printStackTrace();
}
}
}
捕获异常
如果是最小捕获异常的话一次只能捕获一个异常

import java.io.*;
import java.net.Socket;
public class test8 {
public static void main(String[] args) { //最小捕获--有什么异常就捕获什么异常
try {
FileReader fr=new FileReader("d:\\aa.text");
Socket s = new Socket("192.168.1.23",88);//因为上局话出现异常后直接就跳到下面去了,所以这句话不会被执行
}
catch (FileNotFoundException e)
{
e.printStackTrace();
}
catch(IOException e2)
{
e2.printStackTrace(); //但这句话不会执行
}
}
}
解决方法
最大捕获则没有问题

还可以用getMessage方法输出信息,但是输出的内容简单,不会显示是哪一行出错
import java.io.*;
import java.net.Socket;
public class test8 {
public static void main(String[] args) { //最小捕获--有什么异常就捕获什么异常
try {
FileReader fr=new FileReader("d:\\aa.text");
}
catch (FileNotFoundException e)
{
//输出错误信息
e.printStackTrace();
System.out.println("message:=" + e.getMessage());
//处理方法
}
}
}
没什么价值的信息
finally
他是一个万能保险,经常使用。如果把finally块置放在try...catch...语句之后,finally块的语句一般都会得到执行,它相当于一个万能的保险,即使前面的try块发生异常,而又没有对应的异常的catch块,finally块将马上执行。
以下情况finally块将不会被执行
- finally块中发生了异常
- 程序所在线程死亡
- 在前面的代码中用了System.exit(); 退出系统
- 关闭cpu
打开文件后,不关闭是无法保存的
import java.io.*;
import java.net.Socket;
public class test9 {
public static void main(String[] args) { FileReader fr=null;
try {
fr=new FileReader("d:\\aa.txt");
Socket s = new Socket("192.168.1.1",78);
}
catch (Exception e)
{
e.printStackTrace();
}
//此时会出现这样一种情况
//d盘中有这个文件,文件被打开了,但是没有这台主机,所以下面的会抛出异常
//这就造成了文件会一直打开的状态,文件不关闭是无法进行保存的
//这是就需要finally语句,如果没有特殊情况它是一定会执行的
finally{
System.out.println("进入finally");
//这个语句块,不管有没有出现异常,都会执行
//一般来说,把需要关闭的资源,比如说文件,打开的链接(数据库),内存等等
if(fr!=null) //如果文件不是空,就关闭它
{
try {
fr.close();//它还是有个异常,我们把它也try..catch掉
} catch (Exception e2) {
// TODO: handle exception
e2.printStackTrace();
}
}
}
}
}
finally的用法
注意:只有没有catch,只有try和finally也是能用的,但是一般没人这么用
抛出异常——将异常抛给调用者
一般不会这么用
import java.io.FileReader;
public class test91 { public static void main(String[] args) {
// TODO Auto-generated method stub
Father father = new Father();
father.test1();
}
} class Father
{
private Son son = null;
public Father()
{
son = new Son(); }
public void test1()
{
System.out.println("ellie");
// son.test2();//此时这个方法会抛出一个异常
try {
son.test2();
} catch (Exception e) {
// TODO: handle exception
System.out.println("父亲在处理");
e.printStackTrace();
}
}
} class Son
{
public void test2() throws Exception //扔出去
{
FileReader fr = null;
//fr = new FileReader("d:\\dd.txt");//不try catch这条语句做处理,程序是无法执行的
//如果不想处理它,就把他扔出去
fr = new FileReader("d:\\dd.txt");
}
}
抛出异常
报错信息——提示好几个地方有错的时候,只看最前面的错误就可以了

Java学习日记基础篇(九) —— 集合框架,泛型,异常的更多相关文章
- Java学习日记基础篇(六)—— 抽象类、接口、final
抽象类 为什么要有抽象类? 因为父类方法有不确定性,我们在Animal中定义了一个方法,但是它会被子类的方法覆盖掉,我们就不知道这个方法原本是做什么的 public class test1 { pub ...
- Java学习日记基础篇(四)——类,对象之成员变量,成员方法,构造方法
面向对象(Object Oriented) 一.面向对象杂谈 面向对象(Object Oriented),我的翻译是以物体为目标的,就是说编程的时候是建立一个物体,然后对这个物体进行操作. Java语 ...
- Java学习日记——基础篇(二)基本语法
变量 变量和常量是程序处理的两种基本数据对象,变量是程序的基本组成单位 变量的目的就是确定目标并提供存放空间 public class Hello { public static void main( ...
- Java学习日记——基础篇(一)常识
JAVA简介 Java的标准 Java是一种语言,一个平台包含JavaSE.JavaEE.JavaME三个版本 JavaSE标准版(属于Java的基础部分,可以开发C/S构架的桌面应用程序) Java ...
- Java学习日记基础篇(八) —— 二进制、位运算、位移运算
二进制 二进制是逢2进位的进位置,0,1是基本算符 原码反码补码 在基本数据类型那里,有详细解释 二进制的最高位数是符号位:0表示整数,1表示负数 正数的原码,反码,补码都一样 负数的反码 = 它的原 ...
- Java学习日记基础篇(七) —— 数组、排序
数组 为什么要有数组? 案例:一个养鸡场有六只鸡,他们的体重分别为3kg,5kg,1kg,3.4kg,2kg,50kg.请问这六只鸡的总体重和平均体重是多少? public class test5 { ...
- Java学习日记基础篇(三-下)——流程控制之循环控制
循环控制 for循环 语法: for(循环初值;循环条件;步长) { 语句; //循环体 } 例子: import java.io.*; public class Demo4 { public sta ...
- Java学习日记——基础篇(三-上)基本语法之运算符和流程控制
运算符 算术运算符 听其名而知其意,就是用于计算的,java中常用的是: + 加 - 减 * 乘 / 除 % 取模,取余——%可以用来得到两个数相除的余数 小练习——写一个ja ...
- java学习笔记-基础篇
Java基础篇 1—12 常识 13 this关键字 14参数传递 16 继承 17 访问权限 28—31异常 1—12 常识 1.文件夹以列表展示,显示扩展名,在地址栏显示全路径 2.javac编译 ...
随机推荐
- SVN_05用戶管控
安全性设置 [1]在左侧的User上点击右键 输入上面的信息,点击OK,我们就创建一个用户了. 说明:注意到了下面图中的Groups,是的,也可以先创建组,把用户添加到各个组中,然后对组进行授权,操作 ...
- jquery.fileupload源码解读笔记
基础编程风格 新建 test.html 和 test.js和 main.js和 无论哪种顺序 <body> <script src="/Sandeep/js/jquery ...
- [转]github 上传project代码
原文地址:https://www.cnblogs.com/f1194361820/p/4741558.html 1)将远程仓库纳入管理 其实就是添加远程仓库,在你已有的本地仓库目录下执行如下命令: $ ...
- ios 日常开发常用宏定义
#pragma mark - 字体.颜色相关 #define kFONT_SIZE(f) [UIFont systemFontOfSize:(f)] #define kFONT_BOLD_SIZE ...
- STM8 LED
时钟分频寄存器(CLK_CKDIVR) 举例 int main() { CLK_HSIPrescalerConfig(CLK_PRESCALER_HSIDIV1); //高速内部时钟1分频 GPIO_ ...
- Shiro安全框架入门使用方法
详见:https://blog.csdn.net/qq_32651225/article/details/77199464 框架介绍Apache Shiro是一个强大且易用的Java安全框架,执行身份 ...
- mysql数据库事件
今天在测试一个存储过程和数据库事件,就是到某一个固定时间,数据库自动调用一个存储过程实现一些功能. 单独来看事件是没有问题的 MINUTE STARTS '2015-12-09 02:00:00' O ...
- java递归、js递归,无限极分类菜单表
java-json import com.alibaba.fastjson.JSONObject; import java.util.ArrayList; import java.util.List; ...
- c++混合使用不同标准编译潜在的问题
最近项目使用的C++的版本到C++11了,但是由于有些静态库(.a)没有源码,因此链接时还在使用非C++11版本的库文件.目前跑了几天,似乎是没出什么问题,但是我还是想说一下这样做有哪些潜在的风险. ...
- 快上车,react 入门拾遗
最近朋友圈和微博都刷了一波杰伦的回忆杀–说好不哭,想想都9012了,在学习react如火如荼的路上,也不妨停下脚步来总结总结,朝花夕拾一下. 为了便于阐述,我们还是来段小明和禅师的故事吧. 小明在学习 ...