包装类
其实就是8种基本数据类型对应的引用类型
Java为了实现一切皆对象,为了8种基本类型提供了对应的引用类型
后面的集合和泛型其实也只是支持包装类型,不支持基本数据类型
自动装箱:基本类型的数据和变量可以直接赋值给包装类型的变量
自动拆箱:包装类型的变量可以直接赋值给基本数据类型的变量
包装类的特有功能:
包装类的变量的默认值可以是null,容错率更高。
可以把基本类型的数据转换成字符串类型(用处不大)
①调用toString()方法得到字符串结果。
②调用Integer.toString(基本类型的数据)。
可以把字符串类型的数值转换成真实的数据类型(真的很有用)
①Integer.parseInt(“字符串类型的整数”)
②Double.parseDouble(“字符串类型的小数”)public class Test { public static void main(String[] args) { Integer it = 23; System.out.println(it); int age = 100; Integer it2 = age; // 自动装箱:可以把基本类型的变量直接赋值给包装类型的变量。 System.out.println(it2); Integer it3 = 111; int age3 = it3; // 自动拆箱:可以直接把包装类型的变量赋值给基本数据类型。 System.out.println(age3); System.out.println("---------------------------"); Integer it4 = 0; Integer it5 = null; // 包装类的特有功能2:把基本数据类型转换成字符串类型。 Integer it6 = 23; String s1 = it6.toString(); // "23" System.out.println(s1 + 1); // 231 Integer it7 = 23; String s2 = Integer.toString(it7); System.out.println(s2 + 1); // 231 String s3 = it7 + ""; // 字符串了! System.out.println(s3 + 1); // 231 // 包装的特有功能3:把字符串类型的数值转换成对应的基本数据类型 (真的有用) String str = "23"; // int a = Integer.parseInt(str); // 23 int a = Integer.valueOf(str); // 23 System.out.println(a + 1); // 24 String str2 = "99.5"; // double score = Double.parseDouble(str2); double score = Double.valueOf(str2); System.out.println(score + 0.5); ArrayList<Integer> lists = new ArrayList<>(); } }
正则表达式
正则表达式可以用一些规定的字符来制定规则,并用来校验数据格式的合法性
public class RegexDemo { public static void main(String[] args) { System.out.println(checkQQ("363921799")); System.out.println(checkQQ("363921799dazz")); System.out.println(checkQQ2("363921799")); System.out.println(checkQQ2("363921799dazz")); } public static boolean checkQQ2(String qq){ return qq != null && !qq.startsWith("0") && qq.matches("\\d{6,20}"); } public static boolean checkQQ(String qq){ // 1、判断qq是否为null,以及是否不满足6位以上。 不能以0开始。 if(qq == null || qq.length() < 6 || qq.length() > 20 || qq.startsWith("0")) { return false; } // 2、必须全部是数字 遍历qq号码中的每个字符 323a242442 for (int i = 0; i < qq.length(); i++) { char ch = qq.charAt(i); // 3、判断这个字符是否是非数字 if(ch < '0' || ch > '9') { return false; } } // 4、返回正确 return true; } }
字符串对象提供了匹配正则表达式的方法:
public boolean matches(String regex)
判断是否匹配正则表达式,匹配返回true,不匹配返回false
public class RegexDemo { public static void main(String[] args) { //public boolean matches(String regex):判断是否与正则表达式匹配,匹配返回true // 只能是 a b c System.out.println("a".matches("[abc]")); // true System.out.println("z".matches("[abc]")); // false // 不能出现a b c System.out.println("a".matches("[^abc]")); // false System.out.println("z".matches("[^abc]")); // true System.out.println("a".matches("\\d")); // false System.out.println("3".matches("\\d")); // true System.out.println("333".matches("\\d")); // false 每次只能匹配一个字符! System.out.println("z".matches("\\w")); // true System.out.println("2".matches("\\w"));// true System.out.println("21".matches("\\w")); // false System.out.println("你".matches("\\w")); // false System.out.println("你".matches("\\W")); // true System.out.println("---------------------------------"); // 以上正则匹配只能校验单个字符。 // 校验密码 // 必须是数字 字母 下划线 至少 6位 System.out.println("242dxf_33".matches("\\w{6,}")); System.out.println("243".matches("\\w{6,}")); // 验证码 必须是数字和字符 必须是4位 System.out.println("23dA".matches("[\\w&&[^_]]{4}")); System.out.println("2_dA".matches("[\\w&&[^_]]{4}")); System.out.println("24dA".matches("[a-zA-Z0-9]{4}")); System.out.println("2_dA".matches("[a-zA-Z0-9]{4}")); } }
正则表达式在字符串方法中的使用:
public class RegexDemo { public static void main(String[] args) { String names = "小路dawd54845sdaw蓉儿516845wdaada小何"; String[] nameArr = names.split("\\w+"); for (int i = 0; i < nameArr.length; i++) { System.out.println(nameArr[i]); } String result = names.replaceAll("\\w+", ","); System.out.println(result);//小路,蓉儿,小何 } }
正则表达式支持爬取信息:
public class RegexDemo { public static void main(String[] args) { String rs = "学习Java,电话020-43422424,或者联系邮箱" + "666666@qq.com,电话18432832633,0203232323" + "邮箱dazz@qq.com,400-100-3233 ,4001003232"; // 需求:从上面的内容中爬取出 电话号码和邮箱。 // 1、设计爬取规则对象 Pattern p = Pattern.compile("(0\\d{2,7}-?\\d{5,20})|(\\w{2,30}@\\w{2,20}(\\.\\w{2,10}){1,2})|(1[3-9]\\d{9})"); // 2、得到一个匹配器对象:集合爬取规则,内容。 Matcher m = p.matcher(rs); // 3、开始爬取内容输出 while (m.find()) { System.out.println(m.group()); } } }
Arrays类
数组操作工具类,专门用于操作数组元素的
Arrays类常用API
public class ArraysDemo { public static void main(String[] args) { // 目标:学会使用Arrays类的常用API ,并理解其原理 int[] arr = {10, 2, 55, 23, 24, 100}; System.out.println(arr); // 1、返回数组内容的 toString(数组) // String rs = Arrays.toString(arr); // System.out.println(rs); System.out.println(Arrays.toString(arr)); // 2、排序的API(默认自动对数组元素进行升序排序) Arrays.sort(arr); System.out.println(Arrays.toString(arr)); // 3、二分搜索技术(前提数组必须排好序才支持,否则出bug) int index = Arrays.binarySearch(arr, 55); System.out.println(index); // 返回不存在元素的规律: - (应该插入的位置索引 + 1) int index2 = Arrays.binarySearch(arr, 22); System.out.println(index2); // 注意:数组如果么有排好序,可能会找不到存在的元素,从而出现bug!! int[] arr2 = {12, 36, 34, 25 , 13, 24, 234, 100}; System.out.println(Arrays.binarySearch(arr2 , 36)); } }
Arrays类的排序方法
自定义排序规则
设置Comparator接口对应的比较器对象,来定制比较规则
如果认为左边数据 大于 右边数据 返回正整数
如果认为左边数据 小于 右边数据 返回负整数
如果认为左边数据 等于 右边数据 返回0
import java.util.Arrays; import java.util.Comparator; public class ArraysDemo { public static void main(String[] args) { // 目标:自定义数组的排序规则:Comparator比较器对象。 // 1、Arrays的sort方法对于有值特性的数组是默认升序排序 int[] ages = {34, 12, 42, 23}; Arrays.sort(ages); System.out.println(Arrays.toString(ages)); // 2、需求:降序排序!(自定义比较器对象,只能支持引用类型的排序!!) Integer[] ages1 = {34, 12, 42, 23}; /** 参数一:被排序的数组 必须是引用类型的元素 参数二:匿名内部类对象,代表了一个比较器对象。 */ Arrays.sort(ages1, new Comparator<Integer>() { @Override public int compare(Integer o1, Integer o2) { // 指定比较规则。 // if(o1 > o2){ // return 1; // }else if(o1 < o2){ // return -1; // } // return 0; // return o1 - o2; // 默认升序 return o2 - o1; // 降序 } }); System.out.println(Arrays.toString(ages1)); System.out.println("-------------------------"); Student[] students = new Student[3]; students[0] = new Student("大珍珠",23 , 175.5); students[1] = new Student("黑珍珠",18 , 185.5); students[2] = new Student("胖珍珠",20 , 195.5); System.out.println(Arrays.toString(students)); // Arrays.sort(students); // 直接运行奔溃 Arrays.sort(students, new Comparator<Student>() { @Override public int compare(Student o1, Student o2) { // 自己指定比较规则 // return o1.getAge() - o2.getAge(); // 按照年龄升序排序! // return o2.getAge() - o1.getAge(); // 按照年龄降序排序!! // return Double.compare(o1.getHeight(), o2.getHeight()); // 比较浮点型可以这样写 升序 return Double.compare(o2.getHeight(), o1.getHeight()); // 比较浮点型可以这样写 降序 } }); System.out.println(Arrays.toString(students)); } }
public class Student { private String name; private int age; private double height; public Student() { } public Student(String name, int age, double height) { this.name = name; this.age = age; this.height = height; } 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 double getHeight() { return height; } public void setHeight(double height) { this.height = height; } @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", age=" + age + ", height=" + height + '}'; } }
常见算法
冒泡排序
每次从数组中找出最大值放在数组的后面去
关键步骤:
🐼确定总共需要做几轮: 数组的长度-1
🐼每轮比较几次:
i(轮数) j(次数) 次数规律: 数组的长度 - i
1 3
2 2
3 1
🐼当前位置大于后一个位置则交换数据
选择排序
每轮选择当前位置,开始找出后面的较小值与该位置交换
关键步骤:
🐼确定总共需要选择几轮: 数组的长度-1
🐼控制每轮从以前位置为基准,与后面元素选择几次
二分查找
二分查询性能好,二分查找的前提是必须是排好序的数据
二分查找相当于每次去掉一半的查找范围
二分查找正常的检索条件应该是开始位置min <= 结束位置max
数组的二分查找的实现步骤是什么样的?
定义变量记录左边和右边位置。
使用while循环控制查询(条件是左边位置<=右边位置)
循环内部获取中间元素索引
判断当前要找的元素如果大于中间元素,左边位置=中间索引+1
判断当前要找的元素如果小于中间元素,右边位置=中间索引-1
判断当前要找的元素如果等于中间元素,返回当前中间元素索引。
Lambda表达式
Lambda表达式是JDK 8开始后的一种新语法形式,简化匿名内部类的代码写法
格式:
(匿名内部类被重写方法的形参列表) -> {
被重写方法的方法体代码。
}注:-> 是语法形式,无实际含义
注意:Lambda表达式只能简化函数式接口的匿名内部类的写法形式
函数式接口:首先必须是接口,其次接口中有且仅有一个抽象方法的形式
public class LambdaDemo { public static void main(String[] args) { goSwimming( new Swimming() { @Override public void swim() { System.out.println("去游泳吧~"); } } ); } public static void goSwimming(Swimming swimming) { swimming.swim(); } }
public class LambdaDemo { public static void main(String[] args) { //简化 goSwimming( () -> { System.out.println("去游泳吧~") } ); } public static void goSwimming(Swimming swimming) { swimming.swim(); } }
Lambda表达式简化Comparator接口的匿名形式
注意:通常我们见到的函数式接口上都有一个@FunctionalInterface注解,标记该接口必须是满足函数式接口
public static void main(String[] args) { Integer[] ages = {66, 33, 22, 55, 88}; Arrays.sort(ages, new Comparator<Integer>(){ @Override public int compare(Integer o1, Integer o2) { return o2 - o1; } }); System.out.println("内容:" + Arrays.toString(ages)); }
public static void main(String[] args) { Integer[] ages = {66, 33, 22, 55, 88}; //简化 Arrays.sort(ages, (Integer o1, Integer o2) -> { return o2 - o1; }); System.out.println("内容:" + Arrays.toString(ages)); }
Lambda表达式的省略写法
进一步在Lambda表达式的基础上继续简化
参数类型可以省略不写。
🐼如果只有一个参数,参数类型可以省略,同时()也可以省略。
🐼如果Lambda表达式的方法体代码只有一行代码。可以省略大括号不写,同时要省略分号!
🐼如果Lambda表达式的方法体代码只有一行代码。可以省略大括号不写。此时,如果这行代码是return语句,必须省略return不写,同时也必须省略";"不写
泛型
泛型优势
JDK5中引入的特性,可以在编译阶段约束操作的数据类型,并进行检查
泛型的格式:
<数据类型>;
注:泛型只能支持引用数据类型
集合体系的全部接口和实现类都是支持泛型的使用
泛型的好处:
统一数据类型
把运行时期的问题提前到了编译期间,避免了强制类型转换可能出现的异常,因为编译阶段类型就能确定下来泛型可以在很多地方进行定义:
类后面 → 泛型类
方法申明上 → 泛型方法
接口后面 → 泛型接口
自定义泛型类
定义类时同时定义了泛型的类就是泛型类
泛型类格式:修饰符 class 类名<泛型变量>{}
例:public class MyArrayList<T> {}
注:此处泛型变量T可以随便写为任意标识,常见的如E、T、K、V等
作用:编译阶段可以指定数据类型,类似于集合的作用
泛型类的原理:把出现泛型变量的地方全部替换成传输的真实数据类型
模拟ArrayList集合自定义一个集合MyArrayList集合,完成添加和删除功能的泛型设计即可
import java.util.ArrayList; /** 自定义泛型类 * @param <E> */ public class MyArrayList<E> { private ArrayList list = new ArrayList(); public void add(E e){ list.add(e); } public void remove(E e){ list.remove(e); } @Override public String toString() { return list.toString(); } }
import java.util.ArrayList; public class Test { public static void main(String[] args) { // 需求:模拟ArrayList定义一个MyArrayList ,关注泛型设计 ArrayList<String> lists = new ArrayList<>(); MyArrayList<String> myList = new MyArrayList<>(); myList.add("Java"); myList.add("Java2"); myList.add("Java3"); myList.remove("Java2"); System.out.println(myList); } }
1.泛型类的核心思想
把出现泛型变量的地方全部替换成传输的真实数据类型
2.泛型类的作用
编译阶段约定操作的数据的类型,类似于集合的作用
自定义泛型方法
定义方法时同时定义了泛型的方法就是泛型方法
泛型方法的格式:修饰符 <泛型变量> 方法返回值 方法名称(形参列表){}
例:public <T> void show(T t) {}
作用:方法中可以使用泛型接收一切实际类型的参数,方法更具备通用性
泛型方法的原理:
把出现泛型变量的地方全部替换成传输的真实数据类型
任何一个类型的数组,都能返回它的内容。也就是实现Arrays.toString(数组)的功能
/** 目标:自定义泛型方法。 什么是泛型方法? 定义了泛型的方法就是泛型方法。 泛型方法的定义格式: 修饰符 <泛型变量> 返回值类型 方法名称(形参列表){ } 注意:方法定义了是什么泛型变量,后面就只能用什么泛型变量。 泛型类的核心思想:是把出现泛型变量的地方全部替换成传输的真实数据类型。 需求:给你任何一个类型的数组,都能返回它的内容。Arrays.toString(数组)的功能! 小结: 泛型方法可以让方法更灵活的接收数据,可以做通用技术! */ public class GenericDemo { public static void main(String[] args) { String[] names = {"小璐", "蓉容", "小何"}; System.out.println(toString(names)); Integer[] ages = {10, 20, 30}; System.out.println(toString(ages)); } public static <T> String toString(T[] arr){ if(arr == null) { return null; } StringBuilder sb = new StringBuilder("["); for (int i = 0; i < arr.length; i++) { T ele = arr[i]; sb.append(ele).append(i == arr.length - 1 ? "" : ", "); } sb.append("]"); return sb.toString(); } }
1.泛型方法的核心思想
把出现泛型变量的地方全部替换成传输的真实数据类型
2.泛型方法的作用
方法中可以使用泛型接收一切实际类型的参数,方法更具备通用性
自定义泛型接口
使用了泛型定义的接口就是泛型接口
泛型接口的格式:修饰符 interface 接口名称<泛型变量>{}
例:public interface Data<E>{}
作用:泛型接口可以让实现类选择当前功能需要操作的数据类型
泛型接口的原理:
实现类可以在实现接口的时候传入自己操作的数据类型,这样重写的方法都将是针对于该类型的操作
教务系统,提供一个接口可约束一定要完成数据(学生,老师)的增删改查操作
/** 目标:泛型接口。 什么是泛型接口? 使用了泛型定义的接口就是泛型接口。 泛型接口的格式: 修饰符 interface 接口名称<泛型变量>{ } 需求: 教务系统,提供一个接口可约束一定要完成数据(学生,老师)的增删改查操作 小结: 泛型接口可以约束实现类,实现类可以在实现接口的时候传入自己操作的数据类型 这样重写的方法都将是针对于该类型的操作。 */ public class GenericDemo { public static void main(String[] args) { StudentData s = new StudentData(); s.add(new Student()); TeacherData t = new TeacherData(); t.add(new Teacher()); } }
public interface Data<E> { void add(E s); void delete(int id); void update(E e); E queryById(int id); }
public class Student { }
public class StudentData implements Data<Student>{ @Override public void add(Student s) { } @Override public void delete(int id) { } @Override public void update(Student student) { } @Override public Student queryById(int id) { return null; } }
public class Teacher{ }
public class TeacherData implements Data<Teacher>{ @Override public void add(Teacher s) { } @Override public void delete(int id) { } @Override public void update(Teacher teacher) { } @Override public Teacher queryById(int id) { return null; } }
1.泛型接口的作用
泛型接口可以约束实现类,实现类可以在实现接口的时候传入自己操作的数据类型这样重写的方法都将是针对于该类型的操作
泛型通配符、上下限
通配符:?
? 可以在“使用泛型”的时候代表一切类型
E T K V 是在定义泛型的时候使用的
注意:
虽然BMW和BENZ都继承了Car但是ArrayList<BMW>和ArrayList<BENZ>与ArrayList<Car>没有关系的!
泛型的上下限:
? extends Car: ?必须是Car或者其子类 泛型上限
? super Car : ?必须是Car或者其父类 泛型下限开发一个极品飞车的游戏,所有的汽车都能一起参与比赛
import java.util.ArrayList; /** 目标:泛型通配符: ? 需求:开发一个极品飞车的游戏,所有的汽车都能一起参与比赛。 注意: 虽然BMW和BENZ都继承了Car 但是ArrayList<BMW>和ArrayList<BENZ>与ArrayList<Car>没有关系的!! 通配符:? ?可以在“使用泛型”的时候代表一切类型。 E T K V 是在定义泛型的时候使用的。 泛型的上下限: ? extends Car : ?必须是Car或者其子类 泛型上限 ? super Car :?必须是Car或者其父类 泛型下限 小结: 通配符:? ?可以在“使用泛型”的时候代表一切类型。 */ public class GenericDemo { public static void main(String[] args) { ArrayList<BMW> bmws = new ArrayList<>(); bmws.add(new BMW()); bmws.add(new BMW()); bmws.add(new BMW()); go(bmws); ArrayList<BENZ> benzs = new ArrayList<>(); benzs.add(new BENZ()); benzs.add(new BENZ()); benzs.add(new BENZ()); go(benzs); // ArrayList<Dog> dogs = new ArrayList<>(); // dogs.add(new Dog()); // dogs.add(new Dog()); // dogs.add(new Dog()); // go(dogs); } /** 定义方法,让汽车可以一起参加比赛 */ public static void go(ArrayList<? extends Car> cars){ } } class Dog{ } class Car{ } class BMW extends Car{ } class BENZ extends Car{ }