01 API是什么
答:API 全称 Application Programming Interfaace 应用程序编程接口。就是别人写好的一些程序,我们可以使用它们去解决相关问题。
02 为什么要学API
答:不要重复造轮子。Java已经有20多年的历史了,在这20多年里Java已经沉淀了很多优秀的程序,每一个程序可以用来解决一个问题,如果我们掌握得越多,那么我们的编程能力也就会越强,并且很多事情我们就可以不自己干了,直接调用别人的程序开发效率也会越高。
03 包
【1】概念:包就是文件夹,是用来分门别类管理程序的。
【2】如何在idea中建包:右键单机src --》点击new --》点击package
如果在src下直接创建类,则在java文件的第一行不会出现package语句;如果在自定义包下创建类,则idea会在java文件的第一行自动写上 package 完整路径;这条语句,例如:package bag;
【3】在自己程序中使用其包中的类:
04 String
【1】所在包:import java.lang.String;
【2】功能:封装字符串数据,对字符串数据进行处理。
【3】创建字符串对象:
【4】打印:String内部重写了toString方法,所以可以用sout直接打印字符串对象里的内容。
【5】String类中常用方法:
注意:是substring,不是subString
【6】遍历字符串:
【7】注意事项:
① 字符串对象的不可变性,内存原理:
为main方法开辟栈帧空间 --》加载String类 --》在main方法的栈帧中为name变量开辟空间 --》以""写出的字符串对象会存储在堆区的字符串常量池中 --》把"黑马"的地址给name变量记住 --》把以""写出的字符串对象"程序员"放到堆区的字符串常量池中 --》以+号拼接的字符串对象会存储在堆区中 --》把堆区"黑马程序员"的地址给name变量记住 --》把以""写出的字符串对象"播妞"放到堆区的字符串常量池中 --》以+号拼接的字符串对象会存储在堆区中 --》把堆区"黑马程序员播妞"的地址给name变量记住。
结论:每次试图改变字符串对象实际上是新产生了新的字符串对象,变量每次都是指向了新的字符串对象,之前字符串对象的内容确实是没有改变的,因此说String的对象是不可变的。
② 只要是以""写出来的字符串对象都是存储在堆区的字符串常量池中的,且相同的内容只会存一份。Java为什么要把以""写出来的字符串放在常量池中,且只存一份呢?答:为了节约内存。比如只要是""写出的播妞即使有几千个,在内存中只会有一份,且字符串对象具有不可变性,也保证了它的内容不可变。
③ 通过new方式创建的字符串对象,每new一次都会产生一个新的对象放在堆区内存中。
【8】相关习题:
下图代码中,为什么"a"+"b"+"c"在编译阶段被优化成了“abc”,而s2 + "c"没有在编译阶段被优化,是因为,s2是一个变量只有在运行的时候才知道里面是什么,而"a","b",“c”是常量,编译器可以在编译器期间自动优化,以便减少后序在运行过程中的计算,这也导致了s1和s都指向着常量池中的“abc”。要验证"a"+"b"+"c"在编译阶段是否真的被优化成了“abc”,可以通过反汇编来查看。
04 案例:用户登录
代码位置:用户登录.txt
05 案例:使用String生成验证码
代码位置:使用String生成验证码.txt
06 ArrayList
【1】介绍:集合是一种容器,用于存储数据的。
【2】说明:如果在创建对象时直接写ArrayList则表示这个容器内可以存储任意类型的数据;如果在创建对象时写ArrayList<E>则可以指定这个容器可以存储什么数据。
【3】构造器的介绍:
① ArrayList() :如果在实例化ArrayList<E>对象时调用的是不带参数的构造器则,编译器会默认让顺序表指向一个大小为0的Object[]常量数组。
② ArrayList(int):如果在实例化ArrayList<E>对象时调用的是参数为int的构造器则,如果initialCapacity的值大于0,则实例化一个大小为initialCapacity大小的Object[]类型的数组,如果initialCapacity的值等于0,则编译器会让顺序表指向一个大小为0的常量Object[]数组,如果initialCapacity的值小于0,则会抛出异常。
③ ArrayList(Collection<? extends E> c):
- 在实例化ArrayList对象时可以给构造器传引用数据类型的对象,但是对象的类型必须实现了Collection接口,且接口的<>里得是E或E的子类,其中E表示ArrayList中<>的泛型。
- 下图中我们将arrayList对象作为参数传递给了ArrayList<E>的构造方法,为什么不报错,而将arrayList3对象作为参数传递给了ArrayList<E>的构造方法,为什么报错?
答:不能将ArrayList<Integer>理解成Integer的子类,arrayList传入之所以符合是因为,它的类型ArrayList<Integer>,ArrayList实现了Collection接口,而<>中的Integer也是E的子类所以可以,如果把arrayList的类型修改成ArrayList<String>,String不是E的子类,在编译器中可以看到是不可以的。
【4】ArrayList中常用的方法:
① boolean add(E e):
- 了解完ArrayLisr<E>的构造器后,我们会发现在ArrayList<E>类中如果不明确指定顺序表的大小,则编译器在构造器初始化顺序表时会让顺序表指向一个大小为0的Object[]类型的数组,如果我们直接在实例化ArrayList<E>对象后,使用对象的引用调用add方法,会发现编译器并没有报错,可是顺序表的大小不是0吗,我们也没看到扩容操作啊,为什么不报错呢?
- 答:如下图所示,我们观察到add方法内部的代码,发现在给顺序表有效数据后插入新的数据前,会先判断顺序表的大小和有效数组个数size的大小是否相等,如果相等,表示需要先对顺序表进行扩容操作,具体的扩容细节见下图所示,如果是因为顺序表本身就没开辟空间,则会将顺序表的大小设置成10(此时顺序表指向的是一个新的数组),如果是因为顺序表已满,则将顺序表按照原本大小的1.5被扩容。总之,之所以没报错的原因是,add方法里存在扩容代码。
② E remove(int index) 和 boolean remove(Object o):
E remove(int index) :删除 index 位置元素,并返回被删除的值
boolean remove(Object o):删除遇到的第一个 o
注意:在给remove方法传参时,如果传递的是整型,编译器只会把它认为是下标,而不会认为是你想删除顺序表中第一次出现的元素10,如果想达到删除顺序表中第一次出现的元素10,得先将10装箱,示例代码:arrayList.remove(Integer.valueOf(10))
③ List subList(int fromIndex, int toIndex):
List<E> subList(int fromIndex, int toIndex):截取部分 list,左闭右开(注意一下该方法的返回值为List<E>,接收subList方法的返回值时得用List<>类型的引用接收)。
注意:使用subList截取的结果并不是重新new了一个数组存放的截取部分,而是返回了顺序表中下标为formLindex元素的地址。如果我们修改了截取部分数组中的元素的值,顺序表中的对应部分元素的值也会同时发生改变。
【5】打印:ArrayList内部重写了toString方法,所以可以用sout直接打印对象里的内容。
07 案例:批量删除容器中的某元素
关键点,批量删除时怎样避免漏删元素:法一:每次删除成功就让i--, 法二:从容器后面开始遍历
代码位置:批量删除容器中的某元素.txt
08 案例:上架菜品和展示菜品
代码位置:上架菜品和展示菜品.txt