1.相同点:
都是List集合中常用的实现类
对集合中的元素操作的方法基本一致
都是线程不安全的
2.不同点:
ArrayList的底层实现是数组,使用数组这种数据结构进行数据的存储
LinkedList的底层实现是双链表,使用双链表这种数据结构进行数据的存储
数组实现功能时查找快,增删慢
链表实现功能时,查找慢,增删快
如果对集合中的元素,增删操作不怎么频繁,查询比较频繁时,使用ArrayList
如果对集合中的元素,增删非常频繁,查询不怎么频繁,使用LinkedList
类分为系统类和对象类
系统类往往已经重写了toString().equals(),hashcode()等方法
自定义类,为了实现我们的功能,我们往往需要重写父类的常用方法
定义:
数据结构是计算机存储,组织数据的方式,是相互之间存在一种或多种特定关系的数据元素的集合,即带"结构"的数据元素的集合。“结构”就是指数据元素之间存在的关系,分为逻辑结构,和存储结构,通常情况下,精心选择的数据结构可以带来更高的运行和存储效率
数据的逻辑结构和物理结构是数据结构的两个密切相关的方面,同一逻辑结构可以对应着不同的存储结构,算法的设计取决于数据的逻辑结构,而算法的实现依赖于指定的存储结构
数据的逻辑结构:
指反映数据元素之间的逻辑关系的数据结构,其中的逻辑关系是指数据元素之间的前后间关系,而与他们在计算机中的存储位置无关。逻辑结构包括:
集合:数据结构中的元素之间除了同属于一个集合的相互关系外,别无其它关系
线性结构:数据结构中的元素存在一对一的相互关系
树形结构:数据结构中的元素存在一对多的相互关系
图形结构:数据结构中的元素存在着多对多的相互关系
数据的物理结构:
指数据的逻辑结构在计算机存储空间的存放形式
常用的数据结构:
(这里的数据结构分类是从逻辑上进行的)
1.Array(数组)
数组是一种聚合数据结构,他将具有相同类型的若干变量有序地组织在一起的集合,数据可以说是最基本的数据结构,在各种编程语言中都有对应,一个数组可以分解成多个数组元素,按照数据元素的类型,数组可以分成整型数组,字符型数组,浮点型数组,指针数组,和结构数组,数组还有一维,二维以及多维等表现形式
2.stack(栈)
栈是一种特殊的线性表,他只能在一个表的一个固定的一端进行数据节点的插入和删除操作。栈是按照后进先出的原则来存储数据,也就是说,先插入的数据将被压入栈底,最后插入的数据在栈顶,读出数据时,从栈顶开始逐个读出,栈在汇编语言程序中,经常用于重要数据的现场保护,栈中没有数据时,称为空栈
3.queue(队列)
队列和栈类似,也是一种特殊的线性表,和栈不同的是,队列再进行数据的存储时,遵循先进先出的原则,而且队列只允许在表的一端进行插入操作,而在另一端进行删除操作,一般来说,进行插入操作的一端称为队尾,进行删除操作的一端称为对头,队列中,队列中没有数据元素时,成为空队列
4.LinkedList(链表)
链表是一种数据元素按照链式存储结构进行存储的数据结构,这种数据结构具有在物理上存在非连续的特点。链表有一系列数据节点构成,每个数据节点包括数据域和指针域两部分,其中,指针域保存了数据结构中下一个元素存放的地址,链表结构中的数据元素的逻辑顺序是通过链表中的指针链接次序来实现的
5.tree(树)
树是典型的非线性结构,它包括,2个结点的有穷集合K,在树结构中,有且仅有一个根结点,该结点没有前驱节点。在树结构中的其他结点都有且仅有一个前驱节点,而且可以有两个后继节点,m>=0
6.graph(图)
图是另一种非线性数据结构,在图结构中,数据节点一般称为顶点,而边是顶点的有序偶对,如果两个顶点之间存在一条边,那么就表示这两个顶点具有相邻关系
7.heap(堆)
堆是一种特殊的树形数据结构,一般讨论的堆都是二叉堆,堆的特点是根节点的值是所有结点中最小或者最大的,并且根节点的两个子树也是一个堆结构
8.hash(散列)
散列表源自散列函数(hash function)其思想是如果在数据结构中存在关键字来和T相等的记录,那么必定在F(T)的存储位置可以找到该记录,这样就不用进行比较操作而直接取得所查记录
泛型指的是“泛指的类型”。将数据类型参数化,使用泛型,将某些类型,在类与类,类与接口,方法之间进行传递,类似于传参
用在集合当中,限制存储的元素的类型,不再使用元素的时候,逐个元素进行类型检查
可以提高代码的可读性
可以使某些发生在运行时期的逻辑错误问题,提前到编译期
泛型是定义在<>里面的,在<>里面定义一个类型,此时,定义在<>中的类型就是泛型
泛型是一个标识符,遵循驼峰命名法
泛型一般情况下,不用太长的类型来描述,一般情况下,只需要用一个字母代替即可
如果需要定义多种泛型,直接在尖括号中定义,泛型和泛型之间以“,”分隔开来
在使用到泛型类,接口,方法的时候,指派每一个泛型具体是什么类型
注意事项:泛型类型的指派,只能是引用数据类型。泛型不能设置为基本数据类型。如果真的需要使用到基本数据类型,使用它们对应的包装类
//语法
//定义:在类的后面,紧跟上<>
class Animal <T>{
}
class Dog <T>{
}
/*
泛型类的使用:
*/
//声明引用
Animal<String> animal;
//2.实例化对象
Animal<Integer> animal = new Animal<>();
//3.访问静态成员
Animal<Integer>.display();
//4.被继承
class Dog extends Animal<String>{
}
class Dog<T> extends Animal<T>{
}
在类中定义的泛型,虽然还不明确是什么类型,但是在当前类中是可以使用的
在使用到这个类的时候,必须要指定泛型的类型,如果不指定,默认是Object
泛型,只能在当前类中使用,不能在其他的类中使用,包括子类
package bk.javase.p529;
/*
学生使用工具类,用手机电话和电脑玩游戏
*/
public class demo7 {
public static void main(String[] args){
Students student = new Students();
Phone phone = new Phone("华为");
Computer computer = new Computer("小米");
//不用泛型加以约束,因为多态,我可以将任意子类对象作为参数传入
student.setTools(computer);//tools = computer 多态
student.setTools(phone); // tools = phone 多态
Tools tools = student.getTools();//多态
//使用泛型前
if (tools instanceof Phone){
Phone phone1 = (Phone)tools;
phone1.callPhone();
}else{
throw new ClassCastException("不是Phone类");
}
//使用泛型后
//我创建对象时,加以约束,能传的参数固定了下来,只能为Compouter
Student1<Computer> student1 = new Student1();
// student1.setTools(phone);
student1.setTools(computer);
}
}
//使用泛型前
class Students{
Tools tools;
public Tools getTools() {
return tools;
}
public void setTools(Tools tools) {
this.tools = tools;
}
}
//使用泛型后
/*
给Student1类加泛型,方式:在类的后面直接添加,E代表任意一种数据类型,这里不一定是E,任意字母都可以
这就是在类上使用泛型
在类上确定的泛型可以直接在方法上使用
当泛型,没有指定时默认是Object
*/
class Student1<E>{
E tools;
public E getTools(){
return tools;
}
public void setTools(E tools){
this.tools = tools;
}
}
class Tools{
String name;
}
class Phone extends Tools{
public Phone(String name){
this.name = name;
}
public void callPhone(){
System.out.println("打电话");
}
}
class Computer extends Tools{
public Computer(String name){
this.name = name;
}
public void play(){
System.out.println("play");
}
}
语法部分:
泛型接口的定义:
在接口名字的后面,添加<>,在<>里面定义泛型
interface MyInterface <T> {
}
interface MyInterface<T,M>{
}
泛型接口的使用:
实现类实现接口,使用接口访问接口中的静态成员,被继承
//1.实现类实现接口
class MyInterfaceImpl implements MyInterface<Person>{
}
//2.使用接口访问接口中的静态成员
MyInterface<String>.test();
//3.被继承
interface SubMyinterface extends MyInterface<String>{
}
泛型接口的特点:
在接口中定义的泛型,虽然还不明确是什么类型,但是在当前的接口中是可以使用的
在使用到这个接口的时候,必须要指定泛型的类型,如果不指定,默认是Object
泛型,只能在当前的接口中使用,不能在其他的接口中使用,包括子接口
package bk.javase.p529;
public class demo8 {
public static void main(String[] args){
//使用匿名内部类的形式实现接口
MyInterface<MyPerson> impl = new MyInterface<MyPerson>() {
@Override
public int compareTo(MyPerson t1, MyPerson t2) {
return 0;
}
};
//使用lambda表达式实现接口
//此时,会根据左侧的接口引用中的泛型,导出接口实际指派的类型是谁
MyInterface<MyPerson> impl2 = ((t1, t2) -> t1.age - t2.age);
MyInterface<String> impl3 = ((t1, t2) -> t1.length() - t2.length());
}
}
//定义一个泛型接口
interface MyInterface<T>{
int compareTo(T t1,T t2);
}
//子接口
interface SubMyInterface extends MyInterface<String>{
}
//实现类
class MyInterfaceImpl implements MyInterface<MyPerson>{
@Override
public int compareTo(MyPerson t1, MyPerson t2) {
return 0;
}
}
class MyPerson{
int age;
}
第一种:子类泛型与接口泛型一致,泛型无须具体
第二种:接口使用泛型,子类不用,在实现的接口位置必须指定一个具体的数据类型
package bk.javase.p529;
import java.util.ArrayList;
import java.util.Comparator;
public class demo9 {
public static void main(String[] args){
Bird<String> bird = new Bird();
bird.show("haha");
}
}
interface Inter<R>{
public void show(R r);
}
/*
子类与接口一致
类上的泛型确定了,接口上的泛型就确定了,方法上的泛型就确定了
*/
class Bird<R> implements Inter<R>{
@Override
public void show(R r) {
}
}
/*
接口使用泛型,子类不用
在实现接口的位置,必须指定一个具体的泛型
方法使用泛型的情况:
如果是重写的方法,泛型与接口一致
如果是子类自己的方法,可以与接口一致,也可以有自己的泛型
*/
class Cat implements Inter<String>{
@Override
public void show(String s) {
}
}
class Pigs implements Comparable<Pigs>{
@Override
public int compareTo(Pigs o) {
return 0;
}
}
class ComWithA implements Comparator<String>{
@Override
public int compare(String o1, String o2) {
ArrayList list = null;
return 0;
}
}
语法部分:
定义:泛型方法中,在定义方法时,再返回之前面通过定义泛型
public static void test(){
}
//在定义处的<>用来定义泛型
//在调用处的<>用来使用泛型
泛型方法的分类:
第一:方法上的泛型与类上的泛型一致
第二:方法上的独立使用泛型
在方法中定义的泛型,虽然还不明确是什么类型,但是在当前的方法是可以使用的
泛型方法,在使用的时候,不能跟类,接口似的,手动地设置类型,泛型方法中,泛型的设置,在参数中体现
泛型方法中,一定需要是有参的,参数列表中,必须有泛型类型
泛型方法中地泛型的设置,是通过在调用方法的时候,实参的类型推导出来的
泛型,只能在当前的方法中使用,不能再其他的方法中使用
第三:静态方法使用泛型
package bk.javase.p529;
import java.util.ArrayList;
public class demo10 {
}
class MyDog<E>{
//第一:方法上的泛型与类上的一致
public void run(E e){
System.out.println(e);
}
//第二:方法上独立使用泛型
/*
注意:泛型在使用之前一定要先进行定义
定义的方式:在当前方法的最前面添加<泛型>
作用:让方法与方法内的泛型保持一致
*/
public <F> void show(F f){
ArrayList<F> list = new ArrayList<>();
}
//静态方法使用泛型
/*
必须独立使用
方式:在static后面定义泛型(泛型)
不能使用类上定义的泛型
*/
public static <W> void eat(W w){
}
}
用于 ?: 中,这里是三目运算符的一部分,前面是判断条件,后面是两个分支结果
用于数据库中地sql语句,“select * from emp where name = ?”
用于泛型,是通配符,表示任意一种数据类型
//这里的Object和前面的?没有任何关系
Class<?> class = Object.class;
//如果类的泛型使用时可以写成?是可以的,作为返回值时,会默认成Object类型,但是作为参数不行,所以在给对象指定泛型的时候要写具体的类型
Test<?> test = new Test();
//test.run(new Object());错误
class Test<T>{
T t;
public T run(T a){
T t = null;
return t;
}
}
定义:限制的是整个<>可以取的泛型类型的上限是E,<>中可以取得是E以及E的子类
定义:限制的是整个的<>可以取得泛型类型的下限是E,<>中可以取得类型是E以及E的父类
API:
返回值 | 方法 | 描述 |
---|---|---|
static boolean | addAll() | 批量向一个集合中添加数据 |
static | max() | 获取集合中最大的元素 |
static T | min() | 获取集合中最小的元素 |
static | shuffle() | 将集合中的元素随机排列 |
static void | swap() | 交换集合中的两个元素 |
static void | reverse() | 将集合中的元素倒序 |
static void | sort () | 将集合中的元素升序排序 |
static int | binarySearch() | 使用二分查找法查询元素下标 |
static void | copy() | 拷贝 |
static void | fill() | 使用指定的值填充集合 |
static CollectionsynchronizedCollection |
获取一个线程安全的集合 |
|
package bk.javase.p529;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class demo12 {
public static void main(String[] args){
//1.实例化一个List集合对象
List<Integer> list = new ArrayList<>();
//2.添加元素
Collections.addAll(list,10,20,30,40);
//3.获取一个集合中的最大值,大小比较通过比较元素对应的类实现的Comparable接口进行比较
Integer max = Collections.max(list);
//获取一个集合中的最大值,大小比较通过第二个参数Comparator
Integer max2 = Collections.max(list,(i1,i2) ->i2-i1);
//4.获取一个集合中的最小值,大小比较通过元素对应的实现类实现的Comparable接口进行比较
Integer min = Collections.min(list);
//获取一个集合中的最小值,大小比较通过第二个参数Comparator
Integer min2 = Collections.min(list,(i1,i2)->i2-i1);
//5.将List集合中的数据进行随机的排列(洗牌)
Collections.shuffle(list);
//6.交换一个List集合中两个下标对应的元素
Collections.swap(list,0,2);
//7.将一个List集合中的元素进行倒序排列
Collections.reverse(list);
//8.将一个List集合进行排序,元素的大小比较规则是使用元素对应的实现类实现Comparable接口进行比较大小
Collections.sort(list);
//将一个List集合中的元素按照制定的规则进行升序排序(基本不用),List集合中本身就有这样的排序方法
Collections.sort(list,(i1,i2)->i2-i1);
//9.元素的拷贝,将第二个参数集合中的数据拷贝到第一个集合中
List<Integer> copy = new ArrayList<>();
Collections.addAll(copy,0,0,0,0,0);
Collections.copy(copy,list);
//10.使用指定的数据填充一个集合
Collections.fill(list,0);
//11.将线程不安全的集合转成线程安全的集合
// Collections.synchronizedCollection();
// Collections.synchronizedList();
// Collections.synchronizedSet();
// Collections.synchronizedMap();
}
}