day15(异常)
异常
Java异常分为两大类:
编译时异常: 在写代码的编译器会报红
运行时异常: 在运行的时候 出现的异常
异常的捕捉
语法格式:
try {//尝试 可能出现异常代码 } catch(异常对象) {//抓 //针对于上面异常的处理方案 } 执行流程: 如果try里面的代码没有异常,跳过catch 然后接着往下执行。 如果trye里面有异常,就执行catch后面大括号的代码
语法格式:
多个异常
try { 可能出现的异常的代码 } catch(异常对象1) { } catch (异常对象2) { }
或
try { 可能出现的异常的代码 } catch(异常对象1 | 异常对象2 e) { }
语法格式:
try {//尝试 可能出现异常代码 } catch(异常对象) {//抓 //针对于上面异常的处理方案 } finally { 最终执行的代码 } 执行流程: 如果try里面的代码没有异常,跳过catch 然后接着往下执行。 如果trye里面有异常,就执行catch后面大括号的代码 finally代码无论有没有异常都要执行
异常的抛出
throws : 关键字 名词 告知调用者 此处有异常 一定注意一下 别写错了
总结: 在有异常的地方的方法的后面 throws 异常类
throw :抛的动作, 可以抛出来一个异常对象。 自己可以造错!!!
package com.qf.d_exception; import java.util.Scanner; public class Demo6 { public static void main(String[] args) throws Exception{ Scanner scanner = new Scanner(System.in); System.out.println("请输入用户名:"); String username = scanner.next(); if (!username.equals( "狗蛋")) { //throw 是抛的动作 后面跟的是一个异常的对象 //new Exception("用户名不存在"); 编译时异常 throw new Exception("用户名不存在");//造错!!! } System.out.println("请输入密码:"); String password = scanner.next(); if (!password.equals("123")) { throw new Exception("密码错误"); } System.out.println("登陆成功!!!"); } }
throw 和throws 区别 面试
throws: 跟在方法声明后面,后面跟的是异常类名
可以跟多个异常类名,用逗号隔开
表示抛出异常,由该方法的调用者来处理
throws表示有出现异常的可能性,并不一定出现这些异常
throw:用在方法体内,后面跟的是异常类对象名
只能抛出一个异常对象名
表示抛出异常,由该方法体内的语句来处理
throw则是抛出了异常,执行throw一定出现了某种异常
自定义异常
开发中会遇到很多的异常,但是Java中给咱们提供的异常不足以描述了。
咱们可以自己造异常
day16(String类型与泛型)
String类下面的方法
获取字符串长度 int length();
获取特定位置的字符 char charAt(int index);
获取特定字符的下标 int indexOf(String str);
获取特定字符的最后的一个位置 int lastIndexOf(int ch);
package com.qf.a_string; public class Demo3 { public static void main(String[] args) { String str1 = "中国梦"; System.out.println(str1.length());//6 String str2 = "abcdef"; System.out.println(str2.charAt(3));//找str2字符串中下标为 0位置的上的字符 String str3 = "abcdecvf"; System.out.println(str3.indexOf("cd"));//获取的是字符的下标 System.out.println(str3.indexOf(98));//1 System.out.println(str3.indexOf('c'));//2 System.out.println(str3.lastIndexOf('c'));//5 } }
返回值是布尔类型数据
boolean endWith(String str); 是否以指定的字符或者字符串结尾
boolean isEmpty();判断是否为空,如果字符串为空就 true
boolean contains(); 判断是否包含子字符串
boolean equals(Object anOnject); 判断两个字符串是否相等
boolean equalsIgoreCase(Object anObject); 忽略大小写判断两个字符串是否相等
package com.qf.a_string; public class Demo4 { public static void main(String[] args) { String str1 = "Demo1.java"; System.out.println(str1.endsWith(".java"));//true System.out.println(str1.endsWith("av"));//false System.out.println(str1.endsWith("va"));//true String str2 = ""; System.out.println(str2.isEmpty());//true String str3 = " "; System.out.println(str3.isEmpty());//flase 不为空 空格也是有内容的 String str4 = "abcdef"; System.out.println(str4.contains("cd"));//true System.out.println(str4.contains("ce"));//false System.out.println(str4.contains("abcde"));//true System.out.println(str4.equals("abcdeF"));//false System.out.println(str4.equalsIgnoreCase("abcDeF"));//true } }
将字符数组转为字符串
直接可以使用String类的构造方法
String(char[] value)
String(char[] value, int offset, int count)
static String valueOf(char[] chs);
将字符串转为字符数组
char[] toCharArray();
package com.qf.a_string; public class Demo5 { public static void main(String[] args) { //将字符数组转为字符串 char[] chs = {'a', 'b', 'c', 'd', 'e'}; String str = new String(chs); System.out.println(str);//abc //String(char[] chs, int offset, int count); //第二个参数 int offset 偏移量 从第几个开始 //第三个参数 int count 个数 数量 String str1 = new String(chs, 4, 1); System.out.println(str1); String str2 = String.valueOf(chs); System.out.println(str2); //将字符串转为字符数组 char[] arr1 = "狗蛋很狗".toCharArray(); for (int i = 0; i < arr1.length; i++) { System.out.println(arr1[i]); } } }
以下是几个比较重要的方法
String replace(char oldChar, char newChar); 字符在字符串中替换
String [] split(String regex); 以 regex 对当前的字符串进行切割
String subString(int beginIndex); 截取字符串一部分
String subString(int beginIndex, int endIndex); 截取字符串一部分
String toUpperCase();将小写字母转为大写的字母
String toLowerCase();将大写转为小写字母
String trim(); 去除左右空格
package com.qf.a_string; import java.util.Arrays; public class Demo6 { public static void main(String[] args) { String str = "abcdef"; System.out.println(str.replace('c', '中')); System.out.println(str.replace("cd", "牛彩云")); String str1 = "嘻嘻哒呵呵哒么么哒哈哈哒"; //以哒切割 String[] strs = str1. v("哒"); System.out.println(strs); System.out.println(Arrays.toString(strs));//[嘻嘻, 呵呵, 么么, 哈哈] for (int i = 0; i < strs.length; i++) { System.out.println(strs[i]); } String str2 = "ab,cd,ef,g"; //以, 切割 String[] strs1 = str2.split(","); System.out.println(Arrays.toString(strs1)); //截取一部分的字符串 String str3 = "abcdef"; System.out.println(str3.substring(2));//cdef String str4 = "大学先把手机农村"; System.out.println(str4.substring(2, 4));// 先把//要头不要尾 String str5 = "abCDF"; System.out.println(str5.toUpperCase());//ABCDF System.out.println(str5.toLowerCase());//abcdf String str6 = " index xixi "; System.out.println(str6); System.out.println(str6.trim()); } }
泛型【重点难点】
广泛的类型
自定义泛型在方法中的使用
语法格式:
public <无意义的占位符> 返回值的类型 方法的名字 (参数) { }
无意义的占位符:可以任意的字符 但是都大写的 开发中一般是 T (Type) E (Element) ?(未知)
泛型类[重点]
和之前的普通类不一样
语法格式:
class 类名 <无意义的占位符> {
泛型抽象类
语法格式:
abstract class 类<无意义的占位符> { }
泛型接口
语法格式:
interface 接口名字<无意义的占位符> { }
day17(权限修饰符与集合)
权限修饰符
权限修饰符 | 当前类 | 同一个包下面的其他类 | 其他包下面的子类 | 其他包其他类 |
---|---|---|---|---|
public | 可以 | 可以 | 可以 | 可以 |
protected | 可以 | 可以 | 可以 | 不可以 |
默认的 | 可以 | 可以 | 不可以 | 不可以 |
private | 可以 | 不可以 | 不可以 | 不可以 |
集合
集合结构
Interface Collection<E> Java 中集合的总接口
---|List<E> Colletion的子接口,特征: 存放数据是有序的,可以重复
---|---| ArrayList<E> List的实现类,里面写好了List接口所有的抽象方法都已经实现好了,功能写好 底层是数组
---|---|LinkedList<E> List的实现类, 里面有自己独有的方法 底层是链表
---|Set<E> Collection的子接口, 特征: 存放数据是无序的,不可重复
--|--| HashSet<E> Set的实现类 底层是Hash算法
--|--| TreeSet<E> Set的实现类 底层是二叉树
Collection接口【开发不用】
Collection下面的方法: 增: boolean add(E e); 添加数据的 boolean addAll(Collection<? extends E> c); 将一个集合添加到另外的一个集合中 删: boolean remove(Object obj); 删除指定的元素 boolean removeAll(Collection<?> c)删除指定集合中包含的所有此集合的元素(可选操作) void clear(); 清空集合中所有的元素 查: int size(); 集合中元素的个数 Object[] toArray();将集合转为数组 boolean contains(Object obj);在集合中是否包含一个obj元素 boolean containsAll(Collection<? extends E> c); 判断一个集合是否是另外一个结合的子集合 boolean isEmpty(); 判断一个集合是否为空
package com.qf.c_collection; import java.util.ArrayList; import java.util.Collection; public class Demo1 { public static void main(String[] args) { //父类的引用指向了子类的对象,意味着 对象只能调用父类的方法 //对象不能调用子类独有的方法 只能调用重写的方法 //Collection 所有的抽象方法都被ArrayList 重写了 Collection<String> collection = new ArrayList<String>();//容器 只能放String类型的数据 collection.add("红旗渠"); collection.add("散花"); collection.add("黄鹤楼"); System.out.println(collection);//[红旗渠, 散花, 黄鹤楼] Collection<String> collection1 = new ArrayList<String>();//容器 只能放String类型的数据 collection1.add("舍得"); collection1.add("茅台"); collection1.add("牛栏山"); System.out.println(collection1); collection.addAll(collection1);//将collection1这个集合添加到collection中 System.out.println(collection);//[红旗渠, 散花, 黄鹤楼, 舍得, 茅台, 牛栏山] // Collection<Integer> collection2 = new ArrayList<Integer>();//容器 只能放String类型的数据 // collection2.add(1); // collection2.add(2); // collection2.add(3); // // collection.addAll(collection2); System.out.println(collection.remove("舍得"));//删除指定的数据 System.out.println(collection);//删除之后的结果 //[红旗渠, 散花, 黄鹤楼, 茅台, 牛栏山] //System.out.println(collection.remove("舍得")); Collection<String> collection3 = new ArrayList<String>();//容器 只能放String类型的数据 collection3.add("舍得"); collection3.add("茅台"); collection3.add("牛栏山"); collection3.add("红花郎"); System.out.println(collection3);//[舍得, 茅台, 牛栏山, 红花郎] collection.removeAll(collection3);//删除指定集合中包含的所有此集合的元素 //在collection 删除collection3 中包含的元素 System.out.println(collection);//[红旗渠, 散花, 黄鹤楼] collection.clear(); System.out.println(collection);//[] } }
遍历集合中的数据
使用for循环遍历集合数据
package com.qf.c_collection; import java.util.ArrayList; import java.util.Collection; public class Demo2 { public static void main(String[] args) { Collection<Character> list = new ArrayList<Character>(); list.add('a'); list.add('b'); list.add('c'); System.out.println(list);//[a, b, c] //for循环遍历 //将集合转为数组 然后再遍历 Object[] objs = list.toArray(); for (int i = 0; i < objs.length; i++) { System.out.println(objs[i]); } } }
使用增强for循环
语法格式:
for (集合或者数组的元素的数据类型 临时变量名字 : 集合或者数组) { }
package com.qf.c_collection; import java.util.ArrayList; import java.util.Collection; public class Demo3 { public static void main(String[] args) { Collection<String> liStrings = new ArrayList<String>(); liStrings.add("张三"); liStrings.add("狗蛋"); liStrings.add("老邢"); System.out.println(liStrings); //使用增强for循环遍历数据 for (String s : liStrings) { System.out.println(s); } } }
使用迭代器【重点】
也是对集合进行遍历的一种方式
package com.qf.c_collection; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; public class Demo4 { public static void main(String[] args) { Collection<String> liStrings = new ArrayList<String>(); liStrings.add("张三"); liStrings.add("狗蛋"); liStrings.add("老邢"); //使用迭代器进行遍历 // Iterator<E> iterator() 是Collection 方法 // 返回此集合中的元素的迭代器。 //将集合变成了一个迭代器对象 这个迭代器有没有数据? 有集合中原始的数据的 //1.创建迭代器的对象 Iterator<String> iterator = liStrings.iterator(); //boolean hasNext()如果迭代具有更多元素,则返回 true 。 // ["张三", "狗蛋", "老邢"] // || //游标 // System.out.println(iterator.hasNext());//判断游标后面有没有元素 true // System.out.println(iterator.next());//返回迭代的下一个元素,并将游标往后挪一位 // System.out.println(iterator.hasNext()); // System.out.println(iterator.next());//狗蛋 // System.out.println(iterator.hasNext());//true // System.out.println(iterator.next());//老邢 // System.out.println(iterator.hasNext());//false // System.out.println(iterator.next()); while (iterator.hasNext()) { System.out.println(iterator.next()); } } }
List接口
List下面有自己独有的一些方法,子接口比父接口的功能全
子接口不但重写父接口所有的方法而且加了自己的独有方法
所以开发用List
List接口存储数据的时候 有序的 可以重复 只讲独有的方法 增: boolean add(int index, E e); 在指定索引下标的位置插入一个数据 boolean addAll(int index, Collection<? extends E> c); 在指定下标为位置 插入另外一个集合 删: E remove(int index); 通过索引删除数据,返回的是被删除的元素 改: E set(int index, E e);在指定下标的元素 被别的元素替代,返回值是被替代吗的元素 查: size() toArray() contains() isEmpty() E get(int index); 获取指定的下标的元素 int indexOf(Object obj); 通过元素获取指定的下标的 int lastIndexOf(Object obj);获取指定元素的最后一次出现的位置 List<E> subList(int startIndex, int endIndex); 截取集合中的一段
package com.qf.d_list; import java.util.ArrayList; import java.util.List; public class Demo1 { public static void main(String[] args) { List<String> list = new ArrayList<String>(); System.out.println(list); list.add("狗蛋"); list.add("张三"); list.add("李四"); list.add("张三"); list.add("李四"); list.add("李四"); list.add("张三"); System.out.println(list);//[狗蛋, 张三, 李四] list.add(1, "王五");//在指定的下标的位置上面添加一个元素 System.out.println(list);//[狗蛋, 王五, 张三, 李四] //通过元素删除 System.out.println(list.remove("二蛋"));//false //通过索引下标删除 System.out.println(list.remove(0));//狗蛋 // System.out.println(list);//被删除之后的集合元素 //[王五, 张三, 李四] System.out.println(list.set(1, "王八"));//返回值是被替换的元素 System.out.println(list);//[王五, 王八, 李四] System.out.println(list.get(2));//李四 System.out.println(list.indexOf("王博"));//-1 System.out.println(list.indexOf("王八"));//1 System.out.println(list.lastIndexOf("张三"));//6 //list = [王五, 王八, 李四, 张三, 李四, 李四, 张三] System.out.println(list.subList(2, 4));//[李四, 张三] } }
day18
List集合中存自定义对象
现在集合容器中存数据的时候,字符串 整型 等
但是也可以存对象,集合中带有泛型 是一个类
ArrayList源码
RandomAccess :这个接口可以让ArrayList拥有快速随机访问的能力
源码: for循环比迭代器速度更快的
elementData 数组 默认是10 自动扩容
LinkedList【开发不用】
List是LinkedList的父接口
底层是链表
ArrayList和LinkedList区别
1.ArrayList底层是数组,LinkedList底层是链表 2.ArrayList在随机取数据的时候效率高于LinkedList 3.ArrayList在删除 和插入 的时候效率低于LinkedList 4.ArrayList会自己扩容 需要预留一定空间的 5.LinkedList 是存储数据的节点的信息以及节点信息的内存的指针
day19
Object类
Object是所有类的基类
public String toString()
返回对象的字符串表示形式。 一般来说, toString
方法返回一个“textually代表”这个对象的字符串。 结果应该是一个简明扼要的表达,容易让人阅读。 建议所有子类覆盖此方法
public boolean equals(Object obj)
指示一些其他对象是否等于此对象。判断两个对象是否相等
public boolean equals(Object obj) { return (this == obj); }
== : 比较的是内存地址
objec1.equals(object2)
为啥 String类下面equals如果内容一样的可以返回true? 当父类的需求满足不了子类的需求
String类重写了Object类的equals
package com.qf.a_object; class Student { String name; int age; public Student(String name, int age) { this.name = name; this.age = age; } @Override public boolean equals(Object obj) { if (this == obj) {//如果内存地址一样 就返回true return true; } //如果内存地址不一样,但是内容一样咋写 //equals(Object obj) Object obj = student2;//向上转型 //student1.equals(student2) //obj instanceof Student if (obj instanceof Student) {// student2 instanceof Student true Student stu = (Student)obj;//向下转型 //student2===>stu // student1.name.equals(student2.name) true && student1.age == student2.age return this.name.equals(stu.name) && this.age == stu.age; } return false; } @Override public String toString() { return "Student [name=" + name + ", age=" + age + "]"; } } public class Demo3 { public static void main(String[] args) { Student student1 = new Student("土豆", 12); Student student2 = new Student("土豆", 12); System.out.println(student1.equals(student2));//因为Object类是Student的父类 //以上是false, 但是真实的开发的时候,关注的是内容 而不是地址 //只要内容一样也得给我true。 咋办?重写eqauls方法 } }
public int hashCode()
返回对象的哈希码值。 支持这种方法是为了散列表,如HashMap提供的那样 。
在Object类中,将十六进制的内存地址转为十进制的值,就叫hash值
如果内存地址不一样,那么哈希也是不一样的
hashCode
的总合同是:
如果根据equals(Object)
方法两个对象相等,则在两个对象中的每个对象上调用hashCode
方法必须产生相同的整数结果
请注意,无论何时覆盖equlas方法,通常需要覆盖hashCode方法,以便维护hashCode方法的通用合同,该方法规定相等的对象必须具有相等的哈希码
Set集合
Set集合也是用来存储数据的
Set集合父接口 Collection 接口
Set存储数据的时候的效果是 无序的 不可重复的
Set接口下面有两个 实现类:
HashSet : 底层是hash值进行存储的。如果hash值一样的就无法存到集合中
TreeSet: 底层是二叉树,对存入的数据进行自然排序
HashSet
set集合中自定义的对象
package com.qf.b_hashSet; import java.util.HashSet; import java.util.Set; class Person { int id; String name; public Person(int id, String name) { this.id = id; this.name = name; } @Override public String toString() { return "Person [id=" + id + ", name=" + name + "]"; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + id; result = prime * result + ((name == null) ? 0 : name.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; Person other = (Person) obj; if (id != other.id) return false; if (name == null) { if (other.name != null) return false; } else if (!name.equals(other.name)) return false; return true; } } public class Demo2 { public static void main(String[] args) { Set<Person> set = new HashSet<Person>(); Person person1 = new Person(1, "老邢"); Person person2 = new Person(2, "骚磊"); Person person3 = new Person(1, "老邢"); set.add(person1); set.add(person2); set.add(person3); System.out.println(set); //现在存了三个对象。感觉可以吗?不可以 关注是内容!!!咋干掉? //重写equlas和hashCode方法 } }
总结: 如果将对象存入到hashSet中的时候,必须重写当前类的equals和hashCode方法 为了保证对象的内容不重复。
HashSet的底层是HashMap JDK1.8 数组 + 链表 + 红黑树 三个组成
TreeSet
也是Set接口的实现类。可以保证数据唯一型。存储也是无序的。
同时对存入数据会进行自然排序
package com.qfb_set; import java.util.Set; import java.util.TreeSet; public class Demo3 { public static void main(String[] args) { Set<Integer> set = new TreeSet<>(); set.add(64); set.add(94); set.add(54); set.add(54); System.out.println(set); Set<String> set1 = new TreeSet<String>(); set1.add("dad"); set1.add("dde"); set1.add("axs"); set1.add("ce"); System.out.println(set1); } }
TreeSet存自定义的对象
存对象的时候需要在类的实现Comparable这个接口。该接口对实现它的每个类的对象强加一个整体排序。 这个排序被称为类的自然排序 ,类的compareTo
方法被称为其自然比较方法 。
int compareTo(T o)
将此对象与指定的对象进行比较以进行排序。
返回一个负整数,零或正整数,因为该对象小于,等于或大于指定对象。
person1.compareTo(person2)
如果返回值是负数, 就证明 person1小于 person2 排序 person1 排在person2前面
如果返回值是0,就证明相等,不存了
如果是个正数,就证明大于 person2 排在person1的前面
package com.qf.c_treeset; import java.util.Set; import java.util.TreeSet; //先按照年龄 如果年龄 再字符串比较 class Student implements Comparable<Student>{ String name; int age; public Student(String name, int age) { this.name = name; this.age = age; } @Override public String toString() { return "Student [name=" + name + ", age=" + age + "]"; } @Override public int compareTo(Student o) { int num = this.age - o.age; if (num == 0) {//当 age 相等的时候 int num1 = this.name.compareTo(o.name); return num1; } return num; } } public class Demo3 { public static void main(String[] args) { Set<Student> set = new TreeSet<Student>(); set.add(new Student("b", 65)); set.add(new Student("d", 35)); set.add(new Student("c", 25)); set.add(new Student("a", 35)); set.add(new Student("浩正", 35)); System.out.println(set); } }
通过查阅API我们得知TreeSet集合是基于TreeMap的实现,而TreeMap是基于二叉树(红黑树)结构,也就是说TreeSet集合的底层使用的二叉树(红黑树)结构。 树结构:它也是数据结构中的一种。在计算机领域中树结构指的是倒立的树。 树结构存储的数据,每个数据也需要节点来保存。 而TreeSet集合底层是二叉树的数据结构,什么是二叉树呢? 二叉树:每个节点的下面最多只能有2个子节点。 说明:最多表示一个节点下面可以有两个子节点或者一个子节点或者没有子节点。 在二叉树的根节点左侧的节点称为左子树,在根节点的右侧的节点称为右子树。 既然已经得知TreeSet集合底层是二叉树,那么二叉树是怎样存储数据的呢?是怎样保证存储的数据唯一并有序的呢? 二叉树的存储流程: 当存储一个元素的时候,如果是树的第一个元素,这个元素就作为根节点。 如果不是第一个元素,那么就拿要存储的元素与根节点进行比较大小: 大于根元素:就将要存储的元素放到根节点的右侧,作为右叶子节点。 等于根元素:丢弃。 小于根元素:就将要存储的元素放到根节点的左侧,作为左叶子节点。 总结:二叉树是通过比较大小来保证元素唯一和排序的。 20 10 31 5 13 23 51
关于TreeSet在存储数据的时候,会有一个排序的问题u,。使用一个接口叫Comparable这个接口
咱们还可以使用另外一种方式进行排序。叫比较器的写法
TreeSet(Comparator<? super E> comparator)
构造一个新的,空的树集,根据指定的比较器进行排序。
匿名内部类
目的为了减少代码量
基于抽象类匿名内部类
一个方法的参数是一个抽象类
package com.qf.d_niming; abstract class Student { public abstract void sleep(); } public class Demo2 { public static void main(String[] args) { //test方法参数是抽象类的对象 test(new Student() { @Override public void sleep() { // TODO Auto-generated method stub System.out.println("睡得老想了"); } }); } public static void test (Student stu) { stu.sleep(); } }
基于接口的匿名内部类
package com.qf.c_treeset; import java.util.Comparator; import java.util.TreeSet; class Emp { String name; int age; public Emp(String name, int age) { this.name = name; this.age = age; } @Override public String toString() { return "Emp [name=" + name + ", age=" + age + "]"; } } public class Demo4 { public static void main(String[] args) { //借助于有参的构造方法 //TreeSet(Comparator<? super E> comparator) //构造一个新的,空的树集,根据指定的比较器进行排序。 TreeSet<Emp> emps = new TreeSet<Emp>(new Comparator<Emp>() { @Override public int compare(Emp o1, Emp o2) { // TODO Auto-generated method stub int num = o1.age - o2.age; return num; } }); emps.add(new Emp("狗蛋", 23)); emps.add(new Emp("狗蛋1", 22)); emps.add(new Emp("狗蛋2", 24)); emps.add(new Emp("狗蛋3", 21)); System.out.println(emps); } }