java try catch 之后定位不到具体报错行_JAVA入门(三)上
点击蓝字|关注我们一、异常与异常处理异常简介代码中:阻止当前方法或作用域继续实现的,称之为异常java中的所有异常类都继承Throwable类,Exception 的父类是 Throwable编码 环境 用户操作输入出现问题由java虚拟机自动抛出和自动捕获需要手动添加抛出和捕获语句文件找不到ThrowableErrorException虚拟机错误 VirtualMachineError...
点击蓝字|关注我们
一、异常与异常处理
异常简介
代码中:阻止当前方法或作用域继续实现的,称之为异常
java中的所有异常类都继承Throwable类,
Exception 的父类是 Throwable
编码 环境 用户操作输入出现问题由java虚拟机自动抛出和自动捕获需要手动添加抛出和捕获语句文件找不到ThrowableErrorException虚拟机错误 VirtualMachineError线程死锁 ThreadDeath非检查异常 RuntimeException检查异常空指针异常 NullPointerException数组下标越界异常 ArrayIndexOutOfBoundsException类型转换异常 ClassCastException算数异常 ArithmeticException......文件异常 IOExceptionSQL异常 SQLException......
RuntimeException运行时异常会由java虚拟机自动抛出和自动捕获,运行时异常的出现绝大部分因为代码的问题,应该从逻辑上改进代码
处理异常
使用try-catch 和try-catch-finally
try{ //一些会抛出异常的方法}catch(Exception e){ //处理该异常的代码块 //根据不同的异常情况做出不同的处理方式}
如果try中的方法抛出异常,首先会终止执行,然后程序的控制权将被移交给catch块中的异常处理程序catch中的处理方式,如:
提示警告用户或编程人员检查配置或网络连接等
进行错误日志的记录等
import java.util.InputMismatchException;import java.util.Scanner;public class Demo02 { public static void main(String[] args) { try { System.out.println("请输入你的年龄:"); Scanner input = new Scanner(System.in); int age = input.nextInt(); System.out.println("十年后你"+(age + 10)+"岁"); }catch(InputMismatchException e) { System.out.println("你应该输入整数"); } System.out.println("程序结束啦!"); } }
如果try中的代码块会抛出很多种类型的异常呢?针对不同的异常需要进行不同的处理,在try后边添加多个catch如:
import java.util.InputMismatchException;import java.util.Scanner;public class Demo02 { public static void main(String[] args) { Scanner input = new Scanner(System.in); try { System.out.println("请输入第一个数:"); int one = input.nextInt(); System.out.println("请输入第二个数:"); int two = input.nextInt(); System.out.println("两数相除结果为:"+ one / two); }catch(InputMismatchException e) { System.out.println("你应该输入整数"); }catch (ArithmeticException e) { System.out.println("除数不能为0"); }catch (Exception e) { System.out.println("我是不知名异常"); } System.out.println("程序结束啦!"); } }
catch的异常从上往下应该从小到大,从子类到父类,针对于父类的异常处理程序,对于子类也是适用的。Exception 为InputMismatchException和ArithmeticException的父类,因此放到最后边如果顺序写错了,编译会报错。
public class TryCatchTest { public static void main(String[] args) { TryCatchTest q = new TryCatchTest(); int result = q.test(); System.out.println("test方法执行完毕,返回值为:"+ result); } /** * divider(除数) * result(结果) * try-catch捕获while循环 * 每次循环,divider-1,result=result+100/divider * 如果:捕获异常,打印输出“抛出异常了!!!”,返回-1 * 否则:返回result * finally:打印输出:这是finally * @return */ public int test() { int divider = 10; int result = 100; try { while(divider > -1) { divider--; result += 100/divider; } return result; }catch(Exception e) { e.printStackTrace();//打印异常信息 System.out.println("抛出异常了!!!"); return -1; }finally { System.out.println("这是finally!!!"); } } }/*打印结果:java.lang.ArithmeticException: / by zero抛出异常了!!!这是finally!!! at com.imooc.test.TryCatchTest.test(TryCatchTest.java:26) at com.imooc.test.TryCatchTest.main(TryCatchTest.java:6)test方法执行完毕,返回值为:-1*/
java中的异常抛出以及自定义异常
throw ---- 将产生的异常抛出(动作)
throws ----声明将要抛出任何类型的异常(声明)
public void 方法名(参数列表)
throws 异常列表{
//调用会抛出异常的方法或者:
throw new Exception();
}
//异常抛出 public void divide(int one, int two) throws Exception{ if(two == 0) { throw new Exception("两数相除,除数不能为0!!"); }else { System.out.println("两数相除,结果为:" + one / two); } }
自定义异常
class 自定义异常类 extends 异常类型{}
自定义异常类必须继承相近含义的java的异常类,或直接继承Exception类
public class DrunkException extends Exception{ public DrunkException() { } public DrunkException(String message) { super(message); }}
java中的异常链
捕获到的异常,可以在当前方法的 catch 块中处理,也可抛出给调用者去处理
public class ChianTest { /** * test1();抛出“喝大了”异常 * test2();调用test1(),捕获“喝大了”异常,并且包装成运行时异常,继续抛出 * main()中调用test2(),尝试捕获test2()方法抛出的异常 * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub ChianTest ct = new ChianTest(); try { ct.test2(); }catch(Exception e){ e.printStackTrace(); } } public void test1() throws DrunkException{ throw new DrunkException("喝车别开酒"); } public void test2() { try { test1(); } catch (DrunkException e) { // TODO Auto-generated catch block RuntimeException newExc = new RuntimeException("司机一滴酒,亲人两行泪"); newExc.initCause(e); throw newExc; // 或者// RuntimeException newExc = new RuntimeException(e);// throw newExc; } }}
异常处理经验总结
处理运行时异常,采用逻辑去合理规避同时辅助try-catch处理
在多重catch块后边,可以加一个
catch(Exception)
来处理可能会被遗漏的异常对于不确定的代码,也可以加上try-catch,处理潜在的异常
尽量去处理异常,切忌知识简单的调用printStackTrace()去打印输出
具体如何处理异常,要根据不同的业务需求和异常类型去决定
尽量添加finally语句块去释放占用的资源
二、Java中的字符串
字符串被作为String类型的对象处理,String类位于java.lang包中。默认情况下,该包会被自动导入到所有的程序中。
字符串的不变性
String对象创建后则不能被修改,是不可变的,所谓的修改其实是创建了新的对象,所指向的内存空间不同。
public class Demo02 { public static void main(String[] args) { String s1 = "imooc"; String s2 = "imooc"; String s3 = new String("imooc"); String s4 = new String("imooc"); System.out.println(s1 == s2);//true,多次出现的字符产量,java编译程序只创建一个,因此为true System.out.println(s1 == s3);//false,s1和s3是不同对象,因此为false System.out.println(s3 == s4);//false,s3和s4是不同对象,因此为false s1 = "welcome to "+s1; System.out.println(s1);//字符串s1被修改,指向新的内存空间 } }
一旦一个字符串在内存中创建,则这个字符串将不可改变。如果需要一个可以改变的字符串,我们可以使用StringBuffer或者StringBuilder
每次 new 一个字符串就是产生一个新的对象,即便两个字符串的内容相同,使用 ”==” 比较时也为 ”false” ,如果只需比较内容是否相同,应使用 ”equals()” 方法、
public class Demo02 { public static void main(String[] args) { String s1 = "imooc"; String s2 = "imooc"; //定义字符串s3,保存“I love”和s1拼接后的内容 String s3 = "I love "+s1; // 比较字符串s1和s2 // imooc为常量字符串,多次出现时会被编译器优化,只创建一个对象 System.out.println("s1和s2内存地址相同吗?" + (s1 == s2));//true //比较字符串s1和s3 System.out.println("s1和s3内存地址相同吗?" + (s1 == s3));//false String s4 = "I love " + s1; //比较字符串s4和s3 // s1是变量,s4在运行时才知道具体值,所以s3和s4是不同的对象 System.out.println("s3和s4内存地址相同吗?" + (s4 == s3));//false } }
String类的常用方法
public class Demo02 { public static void main(String[] args) { String s1 = "I love IMOOC love"; String s2 = "I love IMOOC love"; System.out.println(s1.length());//17 System.out.println(s1.indexOf('I'));//0 index从0到length-1,区分大小写,如果没有返回-1 System.out.println(s1.indexOf("love"));//2 第一个love的l的index,区分大小写,如果没有返回-1 System.out.println(s1.lastIndexOf('I'));//7 System.out.println(s1.lastIndexOf("love"));//13 最后一个love的l的index System.out.println(s1.substring(3));//ove IMOOC love index从0开始 System.out.println(s1.substring(3, 7)+"--");//ove -- [3,7)index从0开始 System.out.println(s1.trim());//I love IMOOC love 去除前后空格 System.out.println(s1.equals(s2));//true System.out.println(s1.toLowerCase()+","+s1.toUpperCase()); System.out.println(s1.charAt(4));//v index从0开始 for(int i =0;i"I", System.out.println(s1.split("l", 6)[i]+"----"+i); } /** * I ----0 * ove IMOOC ----1 * ove----2 * split(int regex, int limit)不明白参数limit的作用 */ for(int j=0;j System.out.println(s1.getBytes()[j]+"---"+j); } /** * 73---0 大写i的ascII码 * 32---1 空格的ascII码 * 108---2 小写L的ascII码 * ... * 101---16 e的ascII码 * 汉字的ascII码为两个负数 */ } }
1 个字节等于 8 位, gbk 编码中 1 个汉字字符存储需要 2 个字节,1 个英文字符存储需要 1 个字节。
每个汉字对应两个字节值,如“学”对应 “-47 -89”
汉字对应的字节值为负数,原因在于每个字节是 8 位,最大值不能超过 127,而汉字转换为字节后超过 127,如果超过就会溢出,以负数的形式显示。
==: 判断两个字符串在内存中首地址是否相同,即判断是否是同一个字符串对象
equals(): 比较存储在两个字符串对象中的内容是否一致
public class Demo02 { public static void main(String[] args) { // Java文件名 String fileName = "HelloWorld.java"; // 邮箱 String email = "laurenyang@imooc.com"; // 判断.java文件名是否正确:合法的文件名应该以.java结尾 /* 参考步骤: 1、获取文件名中最后一次出现"."号的位置 2、根据"."号的位置,获取文件的后缀 3、判断"."号位置及文件后缀名 */ //获取文件名中最后一次出现"."号的位置 int index = fileName.lastIndexOf('.'); // 获取文件的后缀 String prefix =fileName.substring(index); // 判断必须包含"."号,且不能出现在首位,同时后缀名为"java" if (index != -1 && index != 0 && prefix.equals(".java")) { // == 比较地址,equals()比较内容 System.out.println("Java文件名正确"); } else { System.out.println("Java文件名无效"); } // 判断邮箱格式是否正确:合法的邮箱名中至少要包含"@", 并且"@"是在"."之前 /* 参考步骤: 1、获取文件名中"@"符号的位置 2、获取邮箱中"."号的位置 3、判断必须包含"@"符号,且"@"必须在"."之前 */ // 获取邮箱中"@"符号的位置 int index2 = email.indexOf('@'); // 获取邮箱中"."号的位置 int index3 = email.indexOf('.'); // 判断必须包含"@"符号,且"@"必须在"."之前 if (index2 != -1 && index3 > index2) { System.out.println("邮箱格式正确"); } else { System.out.println("邮箱格式无效"); } } }
StringBuilder类
除了String之外,还可以用StringBuilder类或StringBuffer类来存储字符串
使用String:
String str = "Hello";System.out.println(str + "World");//程序会额外创建一个对象,保存HelloWorldSystem.out.println(str);//Hello
当程序频繁操作字符串时,就会额外产生很多临时变量。使用StringBuilder或者StringBuffer就可以避免这些问题。二者基本相似,不同之处在于StringBuffer 是线程安全的,而 StringBuilder 则没有实现线程安全功能,所以性能略高。因此一般情况下,如果需要创建一个内容可变的字符串对象,应优先考虑使用 StringBuilder 类。
//StringBuilder类对象定义的两种方法StringBuilder str1 = new StringBuilder();StringBuilder str2 = new StringBuilder("imooc");
!!! 不能使用 StringBuilder str2 = "imooc";
的方式定义
StringBuilder类的常用方法
StringBuilder str = new StringBuilder("imooc");str.append(".com");str.append(100);System.out.println(str.length());//12System.out.println(str);//imooc.com100str.insert(1, "!!!");//insert到index为1的位置System.out.println(str);//i!!!mooc.com100String str2 = str.toString();System.out.println(str2);//i!!!mooc.com100
练习:从后往前,每隔三个字符添加一个逗号
↓↓↓
public class Demo02 { public static void main(String[] args) { // 创建一个空的StringBuilder对象 StringBuilder str = new StringBuilder(); // 追加字符串 str.append("jaewkjldfxmopzdm"); System.out.println(str.length()); // 从后往前每隔三位插入逗号 int length = str.length(); int i=0; int index = length; while(index >= 3) { length = str.length(); index = length-3*(i+1)-i; str.insert(index, ","); i++; } // 将StringBuilder对象转换为String对象并输出 System.out.print(str.toString()); } }
三、Java中的常用类
java中的包装类
为了让基本数据类型也具备对象的特性,java为每个基本数据类型都提供了一个包装类,可以像操作对象那样来操作基本数据类型。
包装类提供的两大类方法
将本类型和其他基本类型进行转换的方法
将字符串和本类型及包装类互相转换的方法
Integer包装类的构造方法:
int i = 2;//定义int类型,值为2Integer m = new Integer(5);//定义Integer包装类对象,值为5Integer n = new Integer("8");//定义Integer包装类对象,值为5
Integer包装类的常用方法:
int score1 = 86; Integer score2 = new Integer(score1);//86 double score3 = score2.doubleValue();//86.0 float score4 = score2.floatValue();//86.0 int score5 = score2.intValue();//86
基本类型和包装类之间的转换
Integer a = new Integer(3);//定义Integer包装类对象,值为3int b = a + 5;//将对象和基本类型进行运算
!!! 以Inteter和int为例,其他基本类型和包装类与其一致↓↓↓
装箱:
把基本类型转换成包装类,使其具有对象的性质
int i = 10;Integer x = new Integer(i);//手动装箱Integer y = i;//自动装箱
拆箱:
与装箱相反,把包装类对象转换成基本类型的值
Integer j = new Integer(8);int m = j.intValue();//手动拆箱为int类型int n = j;//自动拆箱为int类型
基本类型和字符串之间的转换
基本类型转为字符串
int c = 10;
包装类的toString()方法
String str1 = Integer.toString(c);
String类的valueOf()方法
String str2 = String.valueOf(c)
空字符串加上基本类型,得到的就是基本类型数据对应的字符串
String str3 = c + "";
字符串转为基本类型
String str = "8";
调用包装类的parseXxx静态方法
int d = Integer.parseInt(str);
调用包装类的valueOf()方法转换为基本类型的包装类,会自动拆箱
int e = Integer.valueOf(str);
Date和SimpleDateFormat类表示时间
Date d = new Date();System.out.println(d);//Thu Apr 16 14:19:21 GMT+08:00 2020
使用format()方法将日期转换为指定格式的文本
import java.text.SimpleDateFormat;import java.util.Date;public class Demo02 { public static void main(String[] args) { Date e = new Date(); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); String today = sdf.format(e); System.out.println(today); } }
使用parse()方法将文本转换为日期
!!! 调用 SimpleDateFormat 对象的 parse() 方法时可能会出现转换异常,即ParseException ,因此需要进行异常处理
!!! 使用 Date 类时需要导入 java.util 包,使用 SimpleDateFormat 时需要导入 java.text 包
import java.text.ParseException;import java.text.SimpleDateFormat;import java.util.Date;public class Demo02 { public static void main(String[] args) throws ParseException { String day = "2020年04月16日 14:51:19"; SimpleDateFormat df = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss"); Date date = df.parse(day); System.out.println(date); } }
Calendar类的应用
相比Date类,更推荐使用Calendar类进行时间和日期处理
Calendar类的getInstance()和get(类中定义的静态变量)
java.util.Calendar 类是一个抽象类,可以通过调用getInstance()
静态方法获取一个 Calendar 对象,此对象已由当前日期时间初始化,即默认代表当前时间
如Calendar c = Calendar.getInstance();
import java.text.ParseException;import java.util.Calendar;public class Demo02 { public static void main(String[] args) throws ParseException { Calendar c = Calendar.getInstance();//创建Calendar对象 int year = c.get(Calendar.YEAR);//Calendar.YEAR等为Calendar类中定义的静态常量 int month = c.get(Calendar.MONTH)+1;//0表示1月份 int day = c.get(Calendar.DAY_OF_MONTH); int hour = c.get(Calendar.HOUR_OF_DAY); int minute = c.get(Calendar.MINUTE); int second = c.get(Calendar.SECOND); System.out.println(year+"-"+month+"-"+day+" "+hour+":"+minute+":"+second ); } }
Calendar类的getTime()方法
用来获取Date对象,完成Calendar和Date的转换
Calendar的getTime()将Calendar类对象转换为Date类对象
Calendar的getTimeInMillis()来获取当前的毫秒数
import java.text.ParseException;import java.util.Calendar;import java.util.Date;public class Demo02 { public static void main(String[] args) throws ParseException { Calendar c = Calendar.getInstance(); Date date = c.getTime();//将Calendar转换为Date对象 Long time = c.getTimeInMillis();//获取当前毫秒数 System.out.println(date); System.out.println(time); } }
使用Math类操作数据
Math 类位于 java.lang 包中,包含用于执行基本数学运算的方法, Math 类的所有方法都是静态方法,所以使用该类中的方法时,可以直接使用类名.方法名,如:Math.round();
Math类的常用方法
import java.text.ParseException;public class Demo02 { public static void main(String[] args) throws ParseException { double a = 123.456; long b = Math.round(a);//123---四舍五入整数 double c = Math.floor(a);//123.0---小于该数的最大整数 double d = Math.ceil(a);//124.0---大于该数的最小整数 double e = Math.random();//?---[0,1)之间的随机数浮点数 } }
四、Java中的集合框架(上)
集合的概念
是一种工具类,像容器一样,储存任意数量的具有共同属性的对象
集合的作用
在类的内部,对数据进行组织;简单而快速的搜索大数量的条目;有的集合接口,提供了一系列排列有序的元素,并且可以在序列中间快速的插入或者删除有关元素;有的集合接口,提供了映射关系,可以通过关键字(key)去快速查找到对应的唯一对象,而这个关键字可以是任意类型。
集合与数组对比
数组的长度固定,集合长度可变
数组的长度(容量)是固定的,如果数组的长度不够用,就需要再新建一个数组,再把原数组的元素都复制过来;
集合的长度(容量)可以在运行时动态扩展
数组只能通过下标访问,集合可以任意查找
数组只能通过下标访问元素,类型固定,下标必须是整型的,通常情况下并不知道某元素的下标,只能通过遍历进行筛选,数据量很大时就很不方便
而有的集合可以通过任意类型查找所映射的具体对象
Java集合框架体系结构
Collection中存储的即为一个一个的对象;
Map中以来进行存储,这样的一个映射,即为Entry(Map的内部类,翻译:键值对)类的实例,key和value可以是任意类型的对象。
ArrayList HashSet HashMap比较常用
Collection接口
是java集合框架中接口的根接口,是List Set和Queue接口的父接口
定义了可用于操作List、Set和Queue的方法——增删改查
Collection接口的子接口——List接口
List是元素有序并且可以重复的集合,被称为序列
List可以精确的控制每个元素的插入位置,或删除某个位置元素
List接口的实现类——ArrayList
ArrayList(数组序列),是List的一个重要实现类
ArrayList底层是由数组实现的
ArrayList:增删慢,查询快。由于是数据组实现,需要连续的内存空间,如果删除数组中间的值,为了保证下标的有效性,需要将后面的数据往前移,所以删除慢。当插入A对象到B对象的前面时,需要将B对象和B对象之后的所有对象后移一位,再插入A对象。所以插入慢。数组的大小是固定的,如果数组满了,需要重新分配空间,new一个新数组并copy旧数据之后再增加新数据,所以增加慢。因为是连续内存空间,可以通过下标查询数据,所以查询快。
LinkedList:增删快,查询慢。由于是链表实现,当前节点的next指向下一个节点,prev指向上一个节点,不需要连续的内存空间,所以增删快。
因为不是连续内存空间,所以不能使用下标查询,只能通过next遍历,所以查询慢。
使用List和ArrayList
模拟学生选课功能
选择课程(往集合中添加课程)
删除所选的某门课程(删除集合中的元素)
查看所选课程
修改所选课程
Course.java
/** * 课程类 * @author Wang Jiaxin * */public class Course { public String id; public String name; public Course(String id,String name) { this.id = id; this.name = name; } public Course() {}//为了不让子类报错 //实际开发过程,应该将属性私有化,通过使用getter和setter来获取属性// private String id;// public String getId() {// return id;// } public void setId(String id) {// this.id = id;// } }
Student.java
import java.util.HashSet;import java.util.Set;/** * 学生类 * @author Wang Jiaxin * */public class Student { public String id; public String name; public Set courses; public Student(String id,String name) { this.id = id; this.name = name; this.courses = new HashSet(); }}
ListTest.java
List集合的增删改查
import java.util.ArrayList;import java.util.Arrays;import java.util.Iterator;import java.util.List;/** * 备选课程类 * @author Wang Jiaxin * */public class ListTest { /** * 用于存放备选课程的List */ public List coursesToSelect; public ListTest() { this.coursesToSelect = new ArrayList(); } /** * 用于往coursesToSelect中添加备选课程 */ public void testAdd() { //创建一个课程对象,并通过调用add(Object element)方法,添加到备选课程中 Course cr1 = new Course("1","数据结构"); coursesToSelect.add(cr1);// Course temp = coursesToSelect.get(0);//存入的时候是object,取出的时候也是object,因此需要强制类型转换 Course temp = (Course) coursesToSelect.get(0); System.out.println("添加了课程:"+temp.id+":"+temp.name); //创建一个课程对象,并通过调用add(int index,Object element)方法,添加到备选课程中 Course cr2 = new Course("2","C语言"); coursesToSelect.add(0, cr2); Course temp2 = (Course) coursesToSelect.get(0); System.out.println("添加了课程:"+temp2.id+":"+temp2.name); /** * 当前coursesToSelect的长度为2, * index从0开始,add(int index,Object element)的index可选为0,1,2 * index为0/1,则element放在第0/1位,后边元素的依次往后错一位 * index为2(当前list的容量,即长度),则直接添加在list的尾部 * index取小于0或者大于list长度的值都会报IndexOutOfBoundsException,下标越界 */ //以下方法会抛出数组下标越界异常:// Course cr3 = new Course("3","test");// coursesToSelect.add(2, cr3); //重复添加课程cr1: coursesToSelect.add(cr1); Course temp0 = (Course) coursesToSelect.get(2); System.out.println("添加了课程:"+temp0.id+":"+temp0.name); //创建一个课程数组,并通过调用addAll(Arrays.asList(course))方法,添加到备选课程中 Course[] course = { new Course("3","离散数学"), new Course("4","汇编语言") }; //使用Arrays.asList()将数组转换为List coursesToSelect.addAll(Arrays.asList(course)); Course temp3 = (Course) coursesToSelect.get(3); Course temp4 = (Course) coursesToSelect.get(4); System.out.println("添加了两门课程:"+temp3.id+":"+temp3.name+";" +temp4.id+":"+temp4.name); //创建一个课程数组,并通过调用addAll(int index, Arrays.asList(course))方法,添加到备选课程中 Course[] course2 = { new Course("5","高等数学"), new Course("6","大学英语") }; coursesToSelect.addAll(2, Arrays.asList(course2)); Course temp5 = (Course) coursesToSelect.get(2); Course temp6 = (Course) coursesToSelect.get(3); System.out.println("添加了两门课程:"+temp5.id+":"+temp5.name+";" +temp6.id+":"+temp6.name); } /** * 取得List中的元素的方法 * @param args */ public void testGet() { int size = coursesToSelect.size(); System.out.println("有如下课程待选:"); for(int i=0;i Course temp = (Course) coursesToSelect.get(i); System.out.println("课程:"+temp.id+":"+temp.name); } } /** * 通过迭代器来遍历List * 迭代器只是用来遍历集合中元素的,本身并不拥有任何存储功能 * 即迭代器是依赖于某个集合存在的,本身并不能独立存在 * @param args */ public void testIterator() { //通过集合的iterator()方法,取得迭代器的实例 Iterator it = coursesToSelect.iterator(); System.out.println("有如下课程待选(通过迭代器访问):"); while(it.hasNext()) { Course cr = (Course) it.next(); System.out.println("课程:"+cr.id+":"+cr.name); } } /** * 通过for each方法访问元素 * @param args */ public void testForEach() { System.out.println("有如下课程待选(通过for each访问):"); for(Object obj:coursesToSelect) { /** * 当一个元素被存入集合时,它的类型被忽略,集合只把它当做Object, * 当取出来的时候,还是Object类型,要强转换为原来类型 */ Course cr = (Course) obj; System.out.println("课程:"+cr.id+":"+cr.name); } } /** * 修改List中的元素 * @param args */ public void testModify() { coursesToSelect.set(4, new Course("7","毛概")); testForEach(); } /** * 删除List中的元素 * @param args */ public void testRemove() { //单个删除 Course cr = (Course) coursesToSelect.get(4); System.out.println("我是课程:"+cr.id+":"+cr.name+",我即将被删除"); coursesToSelect.remove(cr); //或 System.out.println("即将删除4位置上的课程"); coursesToSelect.remove(4); //批量删除 System.out.println("即将删除4位置和5位置上的课程"); Course[] courses = {(Course) coursesToSelect.get(4),(Course) coursesToSelect.get(5)}; coursesToSelect.removeAll(Arrays.asList(courses)); System.out.println("成功删除课程!!!"); testForEach(); } /** * 往List中添加一些奇怪的东西 * @param args */ public void testType() { System.out.println("能否往List中添加一些奇怪的东西呢?"); coursesToSelect.add("我不是课程,我只是一个无辜的字符串"); /** * 报错java.lang.ClassCastException: * java.lang.String cannot be cast to com.imooc.collection.Course * String类型不能强转为Course类型 */ } public static void main(String[] args) { ListTest lt = new ListTest(); lt.testAdd();// lt.testGet();// lt.testIterator();// lt.testForEach();// lt.testModify();// // lt.testRemove(); lt.testType(); lt.testForEach(); } }
泛型
集合中的元素可以是任意类型的对象(对象的引用)
如果把某个对象放入集合,则会忽略他的类型,而把他当做Object处理泛型则是规定了某个集合只可以存放特定类型的对象
会在编译期间进行类型检查,可以直接按指定类型获取集合元素
TestGeneric.java
泛型,规定集合中只能添加何种引用类型
import java.util.ArrayList;import java.util.List;public class TestGeneric { /** * 带有泛型——Course的List类型属性 * @param args */ public List courses;//泛型 public TestGeneric() { this.courses = new ArrayList(); } /** * 测试添加 */ public void testAdd() { Course cr1 = new Course("1","大学语文"); courses.add(cr1); //泛型集合中,不能添加泛型规定的类型及其子类型以外的对象,否则会报错!// courses.add("能否添加奇怪的东西"); Course cr2 = new Course("2","java基础"); courses.add(cr2); } /** * 测试循环遍历 */ public void testForEach() { for(Course cr:courses) { System.out.println(cr.id+":"+cr.name); } } /** * 泛型集合可以添加泛型的子类型的对象实例 */ public void testChild() { ChildCourse ccr = new ChildCourse(); ccr.id = "3"; ccr.name="我是子类型的课程对象实例"; courses.add(ccr); } /** * 泛型集合中的限定类型,不能使用基本数据类型,必须是引用数据类型 * 可以通过使用包装类限定允许存入的基本数据类型 */ public void testBasicType() { //编译错误,限定类型不能使用基本类型 //List list = new ArrayList(); List list = new ArrayList(); list.add(1);//1本身是基本类型,在此强制转换成了Integer类型添加到了list中 System.out.println("基本类型必须使用包装类作为泛型!!"+list.get(0)); } /** * * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub TestGeneric tg = new TestGeneric(); tg.testAdd(); tg.testForEach(); tg.testChild(); tg.testForEach(); tg.testBasicType(); }}
ChildCourse.java
泛型集合中不可以添加规定类型及其子类型以外的任意类型
public class ChildCourse extends Course { /** * 默认会报错 * 因为父类中写了一个有参构造器,系统就不会自动为其生成一个无参构造器, * 而子类必须要调用父类的无参构造器, * 因此在父类中定义一个无参构造器即可 */ //不定义任何属性,直接继承父类属性即可 }
Collection接口的子接口——Set接口
Set是元素无序且不可以重复的集合,被称为集
Set没有提供类似List的set()方法来修改某个元素,因为Set是无序的,没有办法定位到某个元素的位置并对其进行修改。
Set接口的实现类——HashSet
哈希集是Set的一个重要实现类
案例实现Set
提供备选课程
创建学生对象,并给该学生添加三门课程(添加在学生的courses——Set类型的属性中)
显示备选课程
循环3次,每次输入课程 id
往学生的courses属性中添加与输入的id匹配的课程
输出学生选择的课程
Student.java
import java.util.HashSet;import java.util.Set;/*** 学生类* @author Wang Jiaxin**/public class Student { public String id; public String name; public Set courses; public Student(String id,String name) { this.id = id; this.name = name; this.courses = new HashSet(); }}
Course.java
/*** 课程类* @author Wang Jiaxin**/public class Course { public String id; public String name; public Course(String id,String name) { this.id = id; this.name = name; } public Course() {}//为了不让子类报错 //实际开发过程,应该将属性私有化,通过使用getter和setter来获取属性// private String id;// public String getId() {// return id;// } public void setId(String id) {// this.id = id;// } }
SetTest.java
import java.util.ArrayList;import java.util.Arrays;import java.util.List;import java.util.Scanner;public class SetTest { public List coursesToSelect; public SetTest() { coursesToSelect = new ArrayList(); } public void testAdd() { //创建一个课程对象,并通过调用add(Object element)方法,添加到备选课程中 Course cr1 = new Course("1","数据结构"); coursesToSelect.add(cr1);// Course temp = coursesToSelect.get(0);//存入的时候是object,取出的时候也是object,因此需要强制类型转换 Course temp = (Course) coursesToSelect.get(0);// System.out.println("添加了课程:"+temp.id+":"+temp.name); //创建一个课程对象,并通过调用add(int index,Object element)方法,添加到备选课程中 Course cr2 = new Course("2","C语言"); coursesToSelect.add(0, cr2); Course temp2 = (Course) coursesToSelect.get(0);// System.out.println("添加了课程:"+temp2.id+":"+temp2.name); /** * 当前coursesToSelect的长度为2, * index从0开始,add(int index,Object element)的index可选为0,1,2 * index为0/1,则element放在第0/1位,后边元素的依次往后错一位 * index为2(当前list的容量,即长度),则直接添加在list的尾部 * index取小于0或者大于list长度的值都会报IndexOutOfBoundsException,下标越界 */ //以下方法会抛出数组下标越界异常:// Course cr3 = new Course("3","test");// coursesToSelect.add(2, cr3); // //重复添加课程cr1:// coursesToSelect.add(cr1);// Course temp0 = (Course) coursesToSelect.get(2);// System.out.println("添加了课程:"+temp0.id+":"+temp0.name); //创建一个课程数组,并通过调用addAll(Arrays.asList(course))方法,添加到备选课程中 Course[] course = { new Course("3","离散数学"), new Course("4","汇编语言") }; //使用Arrays.asList()将数组转换为List coursesToSelect.addAll(Arrays.asList(course)); Course temp3 = (Course) coursesToSelect.get(2); Course temp4 = (Course) coursesToSelect.get(3);// System.out.println("添加了两门课程:"+temp3.id+":"+temp3.name+";"// +temp4.id+":"+temp4.name); //创建一个课程数组,并通过调用addAll(int index, Arrays.asList(course))方法,添加到备选课程中 Course[] course2 = { new Course("5","高等数学"), new Course("6","大学英语") }; coursesToSelect.addAll(2, Arrays.asList(course2)); Course temp5 = (Course) coursesToSelect.get(2); Course temp6 = (Course) coursesToSelect.get(3);// System.out.println("添加了两门课程:"+temp5.id+":"+temp5.name+";"// +temp6.id+":"+temp6.name); } /** * 通过for each方法访问元素 * @param args */ public void testForEach() { System.out.println("有如下课程待选(通过for each访问):"); for(Object obj:coursesToSelect) { /** * 当一个元素被存入集合时,它的类型被忽略,集合只把它当做Object, * 当取出来的时候,还是Object类型,要强转换为原来类型 */ Course cr = (Course) obj; System.out.println("课程:"+cr.id+":"+cr.name); } } public static void main(String[] args) { // TODO Auto-generated method stub SetTest st = new SetTest(); st.testAdd(); st.testForEach(); //创建一个学生对象 Student student = new Student("1","小明"); System.out.println("欢迎学生"+student.name+"选课!"); //创建Scanner对象,用来接收从键盘输入的课程ID Scanner console = new Scanner(System.in); for(int i=0;i<3;i++){ System.out.println("请输入课程ID"); String courseId = console.next(); for (Course cr : st.coursesToSelect) { if(cr.id.equals(courseId)) { student.courses.add(cr); /** * Set中添加某个对象,无论重复添加多少次, * 最终只保留一个该对象(的引用), * 并且保留的是第一次添加的那个 * 因为Set元素不重复 */ //student.courses.add(cr); /** * 添加null不报错, * 但是对实际情况没有任何作用, * 因此一般不这么写 */ //student.courses.add(null); } } } st.testForEachForSet(student); } public void testForEachForSet(Student student) { //打印输出,学生所选的课程 System.out.println("共选择了"+student.courses.size()+"门课程"); for (Course cr : student.courses) { System.out.println("选择了课程:"+cr.id+":"+cr.name); } //循环遍历Set中的元素只能使用foreach和iterator方法,不能像List一样还能使用get方法 //因为Set是无序的,本身并不能够查找指定位置上的元素 }}
点赞关注回复“JavaSE”或者点击粉丝福利领取学习资料,简单清晰无套路,不给小编秃头!!
更多推荐
所有评论(0)