一、String类常用方法
- 用于获取的方法
char charAt(int index) 返回指定索引处的 char值。
int length() 返回此字符串的长度。
int indexOf(String s) 返回指定字符串s第一次出现的字符串内的索引。
int lastIndexOf(String s) 返回指定字符串s的最后一次出现的字符串中的索引。
- 用于判断相关的方法
boolean contains(CharSequence s) 当且仅当此字符串包含指定的char值序列时才返回true。
boolean startsWith(String prefix) 测试此字符串是否以指定的前缀开头。
boolean endsWith(String suffix) 测试此字符串是否以指定的后缀结尾。
boolean equals(Object anObject) 将此字符串与指定对象进行比较。
boolean equalsIgnoreCase(String anotherString) 将此 String与另一个 String比较,忽略案例注意事项。
boolean isEmpty() 返回 true如果,且仅当 length()为 0 。
- 用于转换相关的方法
byte[] getBytes() 使用平台的默认字符集将该 String编码为一系列字节,将结果存储到新的字节数组中。
char[] toCharArray() 将此字符串转换为新的字符数组。
String toLowerCase() 使用默认语言环境的规则将此 String所有字符转换为小写。
String toUpperCase() 将此 String所有字符转换为大写,使用默认语言环境的规则。
static String valueOf(boolean b) 返回 boolean参数的字符串表示形式。
- 用于替换、切割、截取相关的方法
String replace(CharSequence target, CharSequence replacement) 将与字面目标序列匹配的字符串的每个子字符串替换为指定的文字替换序列。
String[] split(String regex) 将此字符串拆分为给定的 regular expression的匹配。
String substring(int beginIndex) 返回一个字符串,该字符串是此字符串的子字符串。
String substring(int beginIndex, int endIndex) 返回一个字符串,该字符串是此字符串的子字符串。
- 其他方法
String concat(String str) 将指定的字符串连接到该字符串的末尾。
String trim() 返回一个字符串,其值为此字符串,并删除任何前导和尾随空格。
二、泛型
1、泛型的概念
在学习集合时,我们都知道集合中是可以存放任意对象的,只要把对象存储集合后,那么这时他们都会被提升成Object类型。当我们在取出每一个对象,并且进行相应的操作,这时必须采用类型转换。
泛型:可以在类或方法中预支地使用未知的类型。它是数据类型的一部分,我们将类名与泛型合并一起看做数据类型。
集合是一个类(是对象的数据类型),泛型指的是集合中元素数据的类型!
一般在创建对象时,将未知的类型确定具体的类型。当没有指定泛型时,默认类型为Object类型。
2、泛型的好处
① 将运行时期的ClassCastException,转移到了编译时期变成了编译失败。
② 避免了类型强转的麻烦。
扩展:泛型仅仅只是针对编译阶段有效!在运行时期是会被擦除的(运行时期代码的类型是限制不了的)!
/*
泛型仅仅只是针对编译阶段有效!在运行时期是会被擦除的(运行时期代码的类型是限制不了的)
*/
public class Test03 {
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
// 定义集合对象
ArrayList<String> list = new ArrayList<>();
list.add("itheima");
list.add("itcast");
list.add("javaee");
//list.add(true); // 由于设定了泛型类型,在编译阶段会进行语法检测(添加的数据只要不是String类型的,就会报错!)
// 本质:集合是可以存放任意类型的数据的!【以下代码:在运行阶段执行了list的add方法将boolean类型的true值添加到list集合中去】
Class aClass = list.getClass();
Method add = aClass.getMethod("add", Object.class);
add.invoke(list,true); // 将boolean类型的true值添加到list集合中去
System.out.println("list:"+ list); // list:[itheima, itcast, javaee, true]
}
}
3、泛型的定义与使用
- 定义和使用含有泛型的类
- 定义格式:
修饰符 class 类名<代表泛型的变量> { }
例如:ArrayList的定义 ======>>>> public class ArrayList{}- 确定泛型类型:
在创建对象的时候确定泛型
// 定义含有泛型的类!
public class MyArrayList<A>{ // A是一个预支的类型,在创建对象的时候来进行确定,一旦确定,那么操作对象的时候,指定的类型就只能是创建对象时的类型
public static void main(String[] args){
// 在创建对象的时候确定泛型
MyArrayList<String> list1 = new MyArrayList<>(); // list1以后在编译阶段只能操作String类型的数据
// 在创建对象的时候确定泛型
MyArrayList<Boolean> list2 = new MyArrayList<>();// list2以后在编译阶段只能操作Boolean类型的数据
}
// 定义了很多其它功能的方法,比如向集合中添加数据的方法
}
// 泛型类的学习,可以参考ArrayList集合!!!
2.含有泛型的方法
- 定义格式:
修饰符 <代表泛型的变量类型> 返回值类型 方法名(参数){ }- 确定泛型类型:
调用方法时,确定泛型的类型
public class Test05 {
public static void main(String[] args) {
show1("xxx");
String xxx = show2("xxx");
Boolean flag = show2(true);
}
//VIP对应的类型为String类型
public static void show2(VIP vip){
System.out.println(“xxxx”);
}
//VIP对应的类型为Boolean类型
public static VIP show2(VIP vip){
System.out.println(“xxxx”);
return vip;
}
}
3 .含有泛型的接口
- 定义格式:
修饰符 interface 接口名<代表泛型的变量> { }
例如:public interface List- 确定泛型类型:
①定义类时确定泛型的类型
②始终不确定泛型的类型,直到创建对象时,确定泛型的类型
4、 泛型通配符
当使用泛型类或者接口时,传递的数据中,泛型类型不确定,可以通过通配符<?>表示。但是一旦使用泛型的通配符后,只能使用Object类中的共性方法,集合中元素自身方法无法使用。
泛型的通配符:不知道使用什么类型来接收的时候,此时可以使用?,?表示未知通配符。
此时只能接受数据,不能往该集合中存储数据。
public class Test06 {
public static void main(String[] args) {
// 创建2个集合对象
Collection<String> coll1 = new ArrayList<>();
Collection<Integer> coll2 = new ArrayList<>();
// 调用方法
add(coll1); // coll1和coll2是Colleciont接口的子类对象!
add(coll2); // 若add方法的Collection泛型类型定义为String的时候,此时coll2就添加不进去了!
//ArrayList<Object> list = new ArrayList<String>(); // 编译报错! 泛型类型不能使用继承!(必须要求2个泛型的类型一致!)
}
// 这个方法:后面调用的时候,传递进来的Colleciont子类对象的泛型类型是不确定的!也就是说明参数Colletion的泛型类型不能确定写死!
public static void add(Collection<?> coll){ // 定义方法给定父接口类型(多态)
// 此时只能接受数据,不能往该集合中存储数据
//coll.add("xxx"); // 编译报错!
}
}
泛型不存在继承关系(左右两侧得一致)
boolean containsAll(Collection<?> c) 如果此集合包含指定集合中的所有元素,则返回 true 。
public class Test07 {
public static void main(String[] args) {
Collection<String> coll1 = new ArrayList<>();
coll1.add("itheima");
coll1.add("itcast");
Collection<String> coll2 = new ArrayList<>();
coll2.add("itcast");
// boolean containsAll(Collection<?> c) 如果此集合包含指定集合中的所有元素,则返回 true 。
System.out.println(coll1.containsAll(coll2)); // true
Collection<Integer> coll3 = new ArrayList<>();
coll3.add(100);
coll3.add(99);
Collection<Integer> coll4 = new ArrayList<>();
coll4.add(25);
System.out.println(coll3.containsAll(coll4)); // false
}
}
5.受限泛型
之前设置泛型的时候,实际上是可以任意设置的,只要是类就可以设置。但是在JAVA的泛型中可以指定一个泛型的上限和下限。
?表示泛型通配符,如果要对?泛型通配符的取值范围进行限制,可以使用泛型限定
5.1 泛型的上限
* 格式:
类型名称 <? extends 类 > 对象名称
* 意义:
只能接收该类型及其子类
5.2 泛型的下限
* 格式:
类型名称 <? super 类 > 对象名称
* 意义:
只能接收该类型及其父类型
比如:现已知Object类,String 类,Number类,Integer类,其中Number是Integer的父类
public class Test08 {
public static void main(String[] args) {
Collection<Integer> list1 = new ArrayList<Integer>();
Collection<String> list2 = new ArrayList<String>();
Collection<Number> list3 = new ArrayList<Number>();
Collection<Object> list4 = new ArrayList<Object>();
getElement1(list1);
getElement1(list2); // 报错!
getElement1(list3);
getElement1(list4); // 报错!
getElement2(list1); // 报错!
getElement2(list2); // 报错!
getElement2(list3);
getElement2(list4);
}
// 当前这个方法内部集合的泛型类型只能是: Number类型和它的子类Integer类型
public static void getElement1(Collection<? extends Number> coll) {
}
// 当前这个方法内部集合的泛型类型只能是: Number类型和它的父类Object类型
public static void getElement2(Collection<? super Number> coll) {
}
}
三、数据结构
数据结构 : 数据用什么样的方式组合在一起。
常见数据结构
数据存储的常用结构有:栈、队列、数组、链表和红黑树。
学习目的:通过学习数据结构(特点),最终正确的选择出合适的集合对象来完成实际的需求!【不同的集合对象其内部的数据结构是不一样】
1. 栈
**栈:**stack,又称堆栈,它是运算受限的线性表,其限制是仅允许在栈的一端进行插入和删除操作,不允许在其他任何位置进行添加、查找、删除等操作。
* 特点:
先进后出,后进先出!
* 2个概念:
① 压栈:存数据!
② 弹栈:取数据!
* 假设有一个集合对象内部使用了栈作为数据存储的结构,那么: 向集合中添加数据abc,取数据应该就是: cba
2 .队列
**队列:**queue,简称队,它同堆栈一样,也是一种运算受限的线性表,其限制是仅允许在表的一端进行插入,而在表的另一端进行删除。
* 特点:
先进先出!
4.1.3 数组
**数组:**Array,是有序的元素序列,数组是在内存中开辟一段连续的空间,并在此空间存放元素。
* 特点:
① 数组一旦创建,其长度不可更改!
② 查询和修改效率高!增删效率低!
③ 有索引值,从0开始的连续整数(依次+1)
4.1.4 链表
**链表:**linked list,由一系列结点node(链表中每一个元素称为结点)组成,结点可以在运行时i动态生成。每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。我们常说的链表结构有单向链表与双向链表,那么这里给大家介绍的是单向链表。
* 特点:
查询、修改效率低!
添加、删除效率高!
4.1.5 树
1.树的特点
1. 每一个节点有零个或者多个子节点
2. 没有父节点的节点称之为根节点,一个树最多有一个根节点。
3. 每一个非根节点有且只有一个父节点
2.二叉树
如果树中的每个节点的子节点的个数不超过2,那么该树就是一个二叉树。
3.二叉查找树
* 特点:
1. 左子树上所有的节点的值均小于等于他的根节点的值
2. 右子树上所有的节点值均大于或者等于他的根节点的值
3. 每一个子节点最多有两个子树
案例演示(20,18,23,22,17,24,19)数据的存储过程
注意:二叉查找树存在的问题:会出现"瘸子"的现象,影响查询效率
4.平衡二叉树
为了避免出现"瘸子"的现象,减少树的高度,提高我们的搜素效率,又存在一种树的结构:“平衡二叉树”
规则:它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树
左图是一棵平衡二叉树,根节点10,左右两子树的高度差是1,而右图,虽然根节点左右两子树高度差是0,但是右子树15的左右子树高度差为2,不符合定义,所以右图不是一棵平衡二叉树。
5.旋转
在构建一棵平衡二叉树的过程中,当有新的节点要插入时,检查是否因插入后而破坏了树的平衡,如果是,则需要做旋转去改变树的结构。
左旋:左旋就是将节点的右支往左拉,右子节点变成父节点,并把晋升之后多余的左子节点出让给降级节点的右子节点;
右旋:将节点的左支往右拉,左子节点变成了父节点,并把晋升之后多余的右子节点出让给降级节点的左子节点
举个例子,像上图是否平衡二叉树的图里面,左图在没插入前"19"节点前,该树还是平衡二叉树,但是在插入"19"后,导致了"15"的左右子树失去了"平衡",
所以此时可以将"15"节点进行左旋,让"15"自身把节点出让给"17"作为"17"的左树,使得"17"节点左右子树平衡,而"15"节点没有子树,左右也平衡了。
对于旋转感兴趣的同学,可以参考讲义,或者网站查看动画效果
6.红黑树
红黑树是一种自平衡的二叉查找树,是计算机科学中用到的一种数据结构,它是在1972年由RudolfBayer发明的,当时被称之为平衡二叉B树,后来,在1978年被Leoj.Guibas和Robert Sedgewick修改为如今的"红黑树"。它是一种特殊的二叉查找树,红黑树的每一个节点上都有存储位表示节点的颜色,可以是红或者黑;红黑树不是高度平衡的,它的平衡是通过"红黑树的特性"进行实现的;
* 红黑树特点:
1. 每一个节点或是红色的,或者是黑色的。
2. 根节点必须是黑色
3. 每个叶节点(Nil)是黑色的;(如果一个节点没有子节点或者父节点,则该节点相应的指针属性值为Nil,这些Nil视为叶节点)
4. 如果某一个节点是红色,那么它的子节点必须是黑色(不能出现两个红色节点相连的情况)
5. 对每一个节点,从该节点到其所有后代叶节点的简单路径上,均包含相同数目的黑色节点;
在进行元素插入的时候,和之前一样; 每一次插入完毕以后,使用黑色规则进行校验,如果不满足红黑规则,就需要通过变色,左旋和右旋来调整树,使其满足红黑规则