Java中关于泛型、包装类及ArrayList的详细教程
作者:来学习的小张 发布时间:2021-12-25 00:46:34
一、泛型
1.1 泛型类的定义
// 1. 尖括号 <> 是泛型的标志
// 2. E 是类型变量(Type Variable),变量名一般要大写
// 3. E 在定义时是形参,代表的意思是 MyArrayList 最终传入的类型,但现在还不知道
public class MyArrayList<E> {
private E[] array;
private int size;
}
泛型类可以一次有多个类型变量,用逗号分割。
泛型是作用在编译期间的一种机制,即运行期间没有泛型的概念。
泛型代码在运行期间,利用 Object 达到的效果(这里不是很准确)。
泛型的意义:自动对类型进行检查
1.2 泛型类的使用
示例:
class MyArrayList<E>{// <E>代表当前类是一个泛型类,此时的E就是一个占位符而已
private E[] elem;
private int usedSize;
public MyArrayList() {
// this.elem = elem;
this.elem = (E[])new Object[10];//这样的写法不是十分正确
}
public void add(E val){
this.elem[usedSize] = val;
usedSize++;
}
public E get(int pos){
return this.elem[pos];
}
}
public class test02 {
public static void main(String[] args) {
//泛型中尖括号里面的内容不参与类型的组成
MyArrayList<String> myArrayList = new MyArrayList<>();
System.out.println(myArrayList);
MyArrayList<Integer> myArrayList1 = new MyArrayList<>();
System.out.println(myArrayList1);
MyArrayList<Boolean> myArrayList2 = new MyArrayList<>();
System.out.println(myArrayList2);
}
public static void main2(String[] args) {
MyArrayList<String> myArrayList = new MyArrayList<>();
myArrayList.add("ni");//自动对类型进行检查,不是字符串类型就会报错
myArrayList.add("n");
String ret = myArrayList.get(1);//自动对类型进行强制类型转换
System.out.println(ret);
}
}
1.3 泛型总结
泛型是为了解决某些容器、算法等代码的通用性而引入,并且能在编译期间做类型检查。
泛型利用的是
Object
是所有类的祖先类,并且父类的引用可以指向子类对象的特定而工作。泛型是一种编译期间的机制,即
MyArrayList<Integer>
和MyArrayList<String>
在运行期间是一个类型。即泛型中尖括号里面的内容不参与类型的组成。泛型是
java
中的一种合法语法,标志就是尖括号<>
。
二、包装类
2.1基本数据类型和包装类直接的对应关系
基本数据类型 | 包装类 |
---|---|
byte | Byte |
short | Short |
int | Integer |
long | Long |
float | Float |
double | Double |
char | Character |
boolean | Boolean |
基本就是类型的首字母大写,除了 Integer
和 Character
。
2.2 包装类的使用,装箱(boxing)和拆箱(unboxing)
装箱(装包):把简单类型变成包装类型。 拆箱(拆包):把包装类型变成简单类型。
public static void main(String[] args) {
Integer a = 123;//装箱 装包(隐式的)
//Integer 的范围[-128,127];
int b= a;//拆箱 拆包(隐式的)
System.out.println("a="+a+" "+ "b="+ b);
System.out.println("===============");
Integer a2 = Integer.valueOf(123);//显式的装包
Integer a3 = new Integer(123);//显式的装包
int b2 = a2.intValue();//显式的拆包
double d = a2.doubleValue();//显式的拆包
int i = 10;//显式的初始化
}
2.3 自动装箱(autoboxing)和自动拆箱(autounboxing)
在使用过程中,装箱和拆箱带来不少的代码量,所以为了减少开发者的负担,java 提供了自动机制。 自动装箱和自动拆箱是工作在编译期间的一种机制。
int b2 = a2.intValue();//显式的拆包
double d = a2.doubleValue();//显式的拆包
三、List 的使用
3.1 ArrayList简介
在集合框架中,ArrayList是一个普通的类,实现了List接口,具体框架图如下:
ArrayList
实现了RandomAccess
接口,表明ArrayList
支持随机访问。ArrayList
实现了Cloneable
接口,表明ArrayList
是可以clone
的。ArrayList
实现了Serializable
接口,表明ArrayList
是支持序列化的。和
Vector
不同,ArrayList
不是线程安全的,在单线程下可以使用,在多线程中可以选择Vector或者CopyOnWriteArrayList
。ArrayList
底层是一段连续的空间,并且可以动态扩容,是一个动态类型的顺序表。 3.2 ArrayList的构造
public static void main(String[] args) {
// ArrayList创建,推荐写法
// 构造一个空的列表
List<Integer> list1 = new ArrayList<>();
// 构造一个具有10个容量的列表
List<Integer> list2 = new ArrayList<>(10);
list2.add(1);
list2.add(2);
list2.add(3);
// list2.add("hello"); // 编译失败,List<Integer>已经限定了,list2中只能存储整形元素
// list3构造好之后,与list2中的元素一致
//使用另外一个ArrayList对list3进行初始化
ArrayList<String> list3 = new ArrayList<>(list2);
// 避免省略类型,否则:任意类型的元素都可以存放,使用时将是一场灾难
List list4 = new ArrayList();
list4.add("111");
list4.add(100);
}
3.3 ArrayList的遍历
ArrayList
可以使用三种方式遍历:for循环+下标
、foreach
、使用迭代器
。
public static void main(String[] args) {
List<String> list = new ArrayList<>();
ArrayList<String> list2 = new ArrayList<>();
list2.add("hello");
list2.add("world");
System.out.println(list2);//打印方式一
System.out.println("============");
for (int i = 0; i < list2.size(); i++) {//打印方式二
System.out.print(list2.get(i)+" ");
}
System.out.println();
System.out.println("==========");
for (String s:list2) {//打印方式三
System.out.print(s+" ");
}
System.out.println();
System.out.println("====迭代器打印方式1======");
Iterator<String> it = list2.iterator();
while (it.hasNext()){
System.out.print(it.next()+" ");
}
System.out.println();
System.out.println("=====迭代器打印方式2=====");
ListIterator<String> it2 = list2.listIterator();//打印方式四,使用迭代器进行打印
while (it2.hasNext()){
System.out.print(it2.next()+" ");
}
}
输出结果:
3.4 ArrayList的常见操作
3.4.1 删除 index 位置元素(remove)
E remove(int index) //删除 index 位置元素
示例:
public static void main(String[] args) {
ArrayList<String> list2 = new ArrayList<>();
list2.add("hello");
list2.add("bit");
list2.add("haha");
Iterator<String> it = list2.iterator();
while (it.hasNext()) {
String ret = it.next();
if(ret.equals("hello")) {
it.remove();//首先需要使用next方法迭代出集合中的元素 ,然后才能调用remove方法
}else {
System.out.print(ret + " ");
}
}
System.out.println();
System.out.println("========迭代器List相关打印==========");
ListIterator<String> it2 = list2.listIterator();
while (it2.hasNext()) {
String ret = it2.next();
if(ret.equals("hello")) {
it2.remove();//首先需要使用next方法迭代出集合中的元素 ,然后才能调用remove方法
}else {
System.out.print(ret + " ");
}
}
}
输出结果:
3.4.1尾插(add)
boolean add(E e) //尾插 e
示例:
public static void main(String[] args) {
ArrayList<String> list2 = new ArrayList<>();
//CopyOnWriteArrayList<String> list2 = new CopyOnWriteArrayList<>();
list2.add("hello");
list2.add("bit");
list2.add("haha");
//Iterator迭代器没有add方法
/* Iterator<String> it = list2.iterator();
while (it.hasNext()) {
String ret = it.next();
if(ret.equals("hello")) {
it.add();//没有add方法
}else {
System.out.print(ret + " ");
}
}*/
//使用ListIterator迭代器的方法添加元素,会将元素添加到其紧跟着的后面
ListIterator<String> it2 = list2.listIterator();
while (it2.hasNext()) {
String ret = it2.next();
if(ret.equals("bit")) {
it2.add("world");
//若使用list2.add()就会抛出异常,
//但是将上面的list2变成CopyOnWriteArrayList<String>类型就不会报错。
//就可以使用list2.add()的方法就可以
// list2.add("world");
}else {
System.out.print(ret + " ");
}
}
System.out.println("=================");
System.out.println(list2);
}
运行结果:
ArrayList<String> list2 = new ArrayList<>();//不是线程安全的
迭代时使用的是it2.add("world");
CopyOnWriteArrayList<String> list2 = new CopyOnWriteArrayList<>();//是线程安全的
迭代时使用的是list2.add("world");
3.4.2将元素插入到list中的指定位置add
3.4.3 尾插一个ArrayList中的所有元素到另一个ArrayList当中(addAll)
方法:
void add(int index, E element) //将 e 插入到 index 位置
boolean addAll(Collection<? extends E> c) //尾插 c 中的元素
示例:
public static void main(String[] args) {
ArrayList<String> list2 = new ArrayList<>();
list2.add("a");
list2.add("b");
list2.add("c");
list2.add("d");
list2.add("d");
System.out.println(list2);//add方法默认将字符串放到数组的最后一个位置
list2.add(0,"hello");//在list2的零下标位置加入字符串"hello"
System.out.println(list2);
ArrayList<String> list3 = new ArrayList<>();
list3.add("加入");
list2.addAll(list3);//将list3中的所有元素放到list2中
System.out.println(list2);
}
输出结果:
3.4.4 删除指定下标位置的元素remove(int index)
3.4.5删除list中第一次出现的某元素remove(Object o)
3.4.6 获取某下标位置的元素get()
3.4.7 将指定下标位置的元素设置为指定值set()
方法:
E remove(int index) //删除 index 位置元素
boolean remove(Object o) //删除遇到的第一个 o
E get(int index) //获取下标 index 位置元素
E set(int index, E element) //将下标 index 位置元素设置为 element
示例:
public static void main(String[] args) {
ArrayList<String> list2 = new ArrayList<>();
list2.add("a");
list2.add("b");
list2.add("c");
list2.add("d");
list2.add("d");
System.out.println(list2);//add方法默认放到数组的最后一个位置
String ret = list2.remove(0);//删除0下标位置元素
System.out.println(list2);
boolean ret1 = list2.remove("d"); //删除遇到的第一个"d"
//如果要删除的数list2中没有则返回false
System.out.println(ret1); //true
String ret2 = list2.get(2);//获取下标为2位置的元素
System.out.println(ret2);//d
String ret3 = list2.set(2,"hello");//将下标为2位置的元素改为"hello"
System.out.println(ret3);//d
System.out.println(list2);//[b, c, hello]
输出结果:
3.4.8 清空线性表中的元素clear()
3.4.9 判断线性表中是否包含某元素 contains()
3.4.10 返回第一个 o 所在下标位置 indexOf()
3.4.11 返回最后一个o出现的下标位置 lastIndexOf()
3.4.12 截取部分 list 中的部分元素 subList()
方法:
void clear() //清空
boolean contains(Object o) //判断 o是否在线性表中
int indexOf(Object o) //返回第一个 o 所在下标
int lastIndexOf(Object o) //返回最后一个 o 的下标
List<E> subList(int fromIndex, int toIndex) //截取部分 list
示例:
public static void main(String[] args) {
ArrayList<String> list2 = new ArrayList<>();
list2.add("a");
list2.add("b");
list2.add("c");
list2.add("d");
list2.add("d");
System.out.println(list2);//add方法默认放到数组的最后一个位置
System.out.println(list2.indexOf("a"));//0 判断a的下标位置
System.out.println(list2.lastIndexOf("d"));//4 判断最后一个d出现的下标位置
List<String> sub = list2.subList(1,3);//[b, c] 截取下标为[1,3)位置的元素,截取的区间范围为左闭右开的
System.out.println(sub);//[b, c]
System.out.println(list2);//[a, b, c, d, d]
System.out.println("===================");
sub.set(0,"p");
System.out.println(sub);//[p, c]
System.out.println(list2);//[a, p, c, d, d]
System.out.println(list2.contains("c"));//true //判断list2当中是否包含字符"c"
list2.clear();//将list2中的元素清空
System.out.println(list2);
输出结果:
四、ArrayList的扩容机制
如果ArrayList
调用不带参数的构造方法,那么顺序表的大小为0
,当第一次add
的时候,整个顺序表才变为了10
;当这个10
放满了,开始扩容,以1.5
倍的方式进行扩容。 如果调用的是给定容量的构造方法,那么顺序表的大小就是给定的容量,放满了还是以1.5
倍进行扩容。
来源:https://blog.csdn.net/dddddrrrzz/article/details/121691217


猜你喜欢
- 本文实例为大家分享了Java实现酒店客房管理系统的具体代码,供大家参考,具体内容如下LoginFrame.javapackage login
- 下面通过一段内容有文字说明有代码分析,并附有展示图供大家学习。要解析HTTP报文,需要实现以下操作:读取HTTP报头提供的各种属性分析属性值
- protobuf对象不能直接使用jsonlib去转,因为protobuf生成的对象的get方法返回的类型有byte[],而只有String类
- @Value获取yml和properties配置参数Yml:#定时任务配置 application:
- 本文实例讲述了Java枚举类用法。分享给大家供大家参考。具体如下:package com.school.stereotype; /** *
- 使用场景:自己项目对接多个外部系统,各个外部系统使用的字段并没有统一,所以要根据不同系统动态的输出序列化数据,使适应各个系统的要求实现方式使
- 大家好,欢迎来到老胡的博客,今天我们继续了解设计模式中的职责链模式,这是一个比较简单的模式。跟往常一样,我们还是从一个真实世界的例子入手,这
- DataBindings属性是很多控件都有的属性,作用有2方面。一方面是用于与数据库的数据进行绑定,进行数据显示。另一方面用于与控件或类的对
- 一般在使用RecyclerView的时候不免要修改RecyclerView的数据,使用notifyDataSetChanged()来刷新界面
- IDEA打成jar包并在windows后台运行一、IDEA打成jar包1、File=>Project Structure=>Pr
- 开发过程, 我们习惯把数据源配置, 项目常量, 日志配置等基础数据配置写到一个个单独的的文件中. 如jdbc.properties等各种.格
- 介绍Java桥梁模式(也称桥接模式)(Bridge Pattern)是一种设计模式,它将抽象和实现分离,使它们可以独立地变化.它通过一个大类
- 以Java web的方式显示图片到浏览器以Java web的方式下载服务器文件到浏览器以Spring Boot的方式显示图片或下载文件到浏览
- 本文实例讲述了JavaMail实现发送超文本(html)格式邮件的方法。分享给大家供大家参考。具体如下:附件以超文本形式,很常用,与普通的邮
- 本文实例讲述了Android授权访问网页的实现方法,即使用Webview显示OAuth Version 2.a ImplicitGrant方
- Java是一种强类型, 许多流行的编程语言都已经支持局部变量类型推断,如js,Python,C++等JDK10 可以使用var作为局部变量类
- 什么是Handler?Handler可以发送和处理消息对象或Runnable对象,这些消息对象和Runnable对象与一个线程相关联。每个H
- Spring Boot如何实现分布式系统中的服务发现和注册?随着互联网的快速发展,越来越多的企业开始将自己的业务迁移到分布式系统中。在这种情
- 一、简介1.什么是GUID?全局唯一标识符(GUID,Globally Unique Identifier),GUID也称作 UUID(Un
- 摘要在我们使用MyBatis的过程中,如果所有实体类和单表CRUD代码都需要手写,那将会是一件相当麻烦的事情。MyBatis官方代码生成器M