集合框架

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

    

重要的就是linkedlist,arraylist,vector,hashset,hashmap

从图中可以看出Java的集合类主要有以下几种:

  • List结构的集合类 —— ArrayList类,LinkedList类,Vector类,Stack类
  • Map结构的集合类 —— HashMap类,HashTable类
  • Set结构的集合类 —— HashSet类,Hashtable类
  • Queue结构的集合 —— Queue接口

List类——列表结构

ArrayList和Vector的区别

  1. 同步性:Vector是同步的而ArrayList则是异步的。所以ArrayList是不安全的但是效率高。
  2. 数据增长: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的区别

  1. 历史原因:Hashtable是基于陈旧的Dictonary类的,HashMap是java 1.2引进的Map接口的一个实现 
  2. 同步性:HashTable是同步的。这个类中的一些方法保证了Hashtable中的对象是线程安全的。而HashMap则是异步的,因此HashMap中的对象并不是线程安全的。因为同步的要求会影响执行的效率,所以如果不需要线程安全的集合那么使用HashMap是一个很好的选择,这样可以避免由于同步带来的不必要的性能开销,从而提高效率
  3. 值: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的设计者给我们提供了这些集合类,在后面编程中式相当有用的,具体什么时候用什么集合,要根据我们刚才分析的集合一同来选取。

  1. 如果要求线程安全,使用Vector、Hashtable
  2. 如果不要求线程安全,应使用ArrayList,LinkedList,HashMap
  3. 如果要求有--键值对,则使用HashMap,Hashtable
  4. 如果数据量很大,又要考虑线程安全用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

利用反射机制拿类的信息

泛型的优点

  1. 类型安全
  2. 向后兼容
  3. 层次清晰
  4. 性能较高用GJ(Generic in Java泛型Java)编写的代码可以为java编译器和虚拟机带来更多的类型信息,这些信息对java程序做进一步优化提供条件着(以后就明白了)

异常处理

  基本概念:当出现程序无法控制的外部环境问题(用户提供的文件不存在,文件内容损坏,网络不可用。。。)时,Java就会用异常对象来描述。

Java中用两种方法处理异常:

  1、在发生异常的地方直接处理

  2、将异常抛给调用者,让调用者处理

异常分类

  1. 检查性异常:java.lang.Exception
  2. 运行期异常:java.lang.RuntimeException
  3. 错误: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块将不会被执行

  1. finally块中发生了异常
  2. 程序所在线程死亡
  3. 在前面的代码中用了System.exit();   退出系统
  4. 关闭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学习日记基础篇(九) —— 集合框架,泛型,异常的更多相关文章

  1. Java学习日记基础篇(六)—— 抽象类、接口、final

    抽象类 为什么要有抽象类? 因为父类方法有不确定性,我们在Animal中定义了一个方法,但是它会被子类的方法覆盖掉,我们就不知道这个方法原本是做什么的 public class test1 { pub ...

  2. Java学习日记基础篇(四)——类,对象之成员变量,成员方法,构造方法

    面向对象(Object Oriented) 一.面向对象杂谈 面向对象(Object Oriented),我的翻译是以物体为目标的,就是说编程的时候是建立一个物体,然后对这个物体进行操作. Java语 ...

  3. Java学习日记——基础篇(二)基本语法

    变量 变量和常量是程序处理的两种基本数据对象,变量是程序的基本组成单位 变量的目的就是确定目标并提供存放空间 public class Hello { public static void main( ...

  4. Java学习日记——基础篇(一)常识

    JAVA简介 Java的标准 Java是一种语言,一个平台包含JavaSE.JavaEE.JavaME三个版本 JavaSE标准版(属于Java的基础部分,可以开发C/S构架的桌面应用程序) Java ...

  5. Java学习日记基础篇(八) —— 二进制、位运算、位移运算

    二进制 二进制是逢2进位的进位置,0,1是基本算符 原码反码补码 在基本数据类型那里,有详细解释 二进制的最高位数是符号位:0表示整数,1表示负数 正数的原码,反码,补码都一样 负数的反码 = 它的原 ...

  6. Java学习日记基础篇(七) —— 数组、排序

    数组 为什么要有数组? 案例:一个养鸡场有六只鸡,他们的体重分别为3kg,5kg,1kg,3.4kg,2kg,50kg.请问这六只鸡的总体重和平均体重是多少? public class test5 { ...

  7. Java学习日记基础篇(三-下)——流程控制之循环控制

    循环控制 for循环 语法: for(循环初值;循环条件;步长) { 语句; //循环体 } 例子: import java.io.*; public class Demo4 { public sta ...

  8. Java学习日记——基础篇(三-上)基本语法之运算符和流程控制

    运算符 算术运算符 听其名而知其意,就是用于计算的,java中常用的是: +   加 -    减 *    乘 /    除 %  取模,取余——%可以用来得到两个数相除的余数 小练习——写一个ja ...

  9. java学习笔记-基础篇

    Java基础篇 1—12 常识 13 this关键字 14参数传递 16 继承 17 访问权限 28—31异常 1—12 常识 1.文件夹以列表展示,显示扩展名,在地址栏显示全路径 2.javac编译 ...

随机推荐

  1. VSCode 搭建 React Native 环境

    安装 React Native Tools 在插件市场搜索 react 找到 React Native Tools 进行安装: 创建的react-native的工程拖入vscode中 点击F5即可运行 ...

  2. MM-发票校验与收货的差异处理

    SAP FI-财务发票校验修改金额后没有进入差异科目问题:公司新建物料采购订单,在MM科目自动确定配置完成后,做发票校验时,修改金额没修改数量时,差异进入了原材料科目 换采购订单继续测试时,修改金额没 ...

  3. php协议任意文件读取

    php://filter/read=convert.base64-encode/resource=index.php

  4. python3之面向对象编程理解

    面向对象主要有三个特征:封装,继承,多态度. 一.封装 定义类语 class Animal(): class为定义类的关键字,后面跟名字(): python命名规范建议:类一般首字母单词大写,属性变量 ...

  5. 使用华为云+GitHub搭建自己的博客

    1.搭建自己博客首先创建GitHub账号 在GitHub官网上创建一个账号:   我的账号地址是 : https://github.com/SueKayTian 2.GitHub账号创建好之后,客户端 ...

  6. Spring Cloud 之 服务网关

    在微服务架构体系中,使用API 服务网关后的系统架构图如下: API服务网关的主要作用如下: 服务访问的统一入口 服务访问的负载均衡功能 服务访问的路由功能 在SpringCloud中,基于Netfl ...

  7. 【转】provisional headers are shown 知多少

    前言 请求里面provisional headers are shown(显示临时报头) 出现的情况很多,但原因是多样的.如果你去直接匹配关键字搜索,得到的结果可能与你自己的情况大相径庭.网上大部分都 ...

  8. node中的npm的使用

    1.node中npm的使用 nodejs软件 1.安装nodejs 自带了npm  npm install Bootstrap 好比python自带pip  pip3 install requests ...

  9. [转]BIO/NIO/AIO的几个思考

    原文:https://www.jianshu.com/p/ff29e028af07 ----------------------------------------------------- BIO/ ...

  10. 前端学习笔记--CSS样式--背景和超链接

    1.背景 2.超链接: 举例: