java数据结构-基础知识

本文详细介绍了Java中的包装类、装箱与拆箱概念,包括valueOf和intValue方法,以及泛型的使用、擦除机制、类型边界和上界。还通过实例探讨了ArrayList的构造和遍历方法,以及泛型方法的应用。
摘要由CSDN通过智能技术生成

包装类&简单认识泛型

1,包装类

在Java中,由于基本类型不是继承自Object类,为了在泛型代码中可以支持基本类型,故Java给每个基本类型都对应了一个包装类型。

所以在Java中,类型也可以面对对象。

(1)包装类-装箱和拆箱

在Java中,将基本类型赋值给包装类的行为称之为装箱,将包装类赋值给基本类型称之为拆箱。

装箱

如下述代码便是装箱:

Java中装箱是通过 valueOf 方法来实现的。

我们若是直接赋值给包装类,此时包装类会自动调用 valueOf 方法进行装箱,此时称之为隐式装箱;

我们若是手动调用 valueOf 进行装箱,此时称之为显式装箱。

拆箱

如下代码便是拆箱:

Java中拆箱是通过 (类型可变)intValue 方法实现的。

我们若是直接将包装类的值赋给基本类型,编译器会自动调用 intValue 方法,此时称之为饮食拆箱;

我们若是手动调用 intValue 方法进行拆箱,此时称之为显示拆箱。

拆箱不限制类型

如下述代码:

a原本是Integer类型,但是却可以被拆箱为double类型;

b原本是in类型,但是却被装箱为Float类型。

通过上述例子可以得出,无论是拆箱、装箱、不一定要包装类与基本类型一一匹配,其实还可以混搭的!

装箱之valueOf深入理解

我们首先要注意的一点,其是使用 == 对两个引用数据类型进行比较,那么比较的其实是两个对象的地址。

这也就说明,当使用100赋值装箱时,其地址是相同的;但是当使用200赋值装箱时,其地址不同了。这是为什么?

答:这一切要从 装箱的实现方法==》valueOf说起,以下是Integer包装类中重载的 valueOf 源码:

在Integer包装类中重载的valueOf 源码中我们可以看到:当我们赋值的数值在[low,high] 区间时,其会返回cache中的数据;但是当我们赋值的数值不在这个区间时,它会重新new一个Integer对象返回。

所以:当对Integer类进行装箱时,若是其赋值在-128 ~ 127 之间时,其会从cache数组中return数据;若是赋值不在这个区间时,return一个新new的对象。

(2)泛型

泛型是在JDK1.5引入的新的语法,通俗讲,泛型:就是适用于许多许多类型。从代码上讲,就是对类型实现了参数化。

直白地来说就是:可以传递类型

泛型的语法

//1 calss 泛型类名称<类型形参列表>{ //这里可以使用类型参数 } //例如 class className<T,Z,X....(可以放很多)>{ } //2 class 泛型类名称<类型形参列表> extends 继承类/*继承类可以使用泛型*/ { //这里可以使用类型参数 } //例如: class className<T,X,Z..> extends ParentClass<T1> { //这里只能使用部分类型参数 }

语法解释:

1:类名后的代表占位符,表示当前类是一个泛型类

泛型代码示例

注意:泛型只能接受类,所有的基本数据类型必须使用包装类!

擦除机制 -- 重要

擦除机制是编译泛型的方式,当泛型在编译时,会将所有的泛型替换为Object,对于这种机制,我们称之为擦除机制

泛型的上界

在定义泛型类时,有时需要对传入的类型变量做一定的约束,可以通过类型边界来约束

语法:

class 泛型类名称<类型形参 extends 类型边界> { //... }

示例1:

因为此时Person只能接受Number类或Number类的子类作为实参,故当我们试图传递String时报错。

示例2:

假设我们需要对一个创建一个方法对泛型数组求最大值,如下:

因为泛型只能传递引用类型,故我们一定要保证所传递的类型能够进行比较,那么如何保证呢?答:只需要该类实现了Comparable接口并重写compareTo方法即可进行比较。所以我们可以对代码进行如下的修改:

这也是泛型的上界。

示例3(泛型方法):

以示例2的例子我们再进一步拓展。示例2中,我们每次调用findMaxValue方法之前都要实例化myArrays,但是一旦将findMaxValue方法改为静态方法,就会导致无法使用泛型T,那么是否可以直接对方法传递类型呢?答案是可以的,如下:

此类方法称之为泛型方法,即是使用方法来接收类型。

但是调用此类方法时要注意:在调用泛型方法时,编译器会根据方法参数的类型自动传递类型,故黄色箭头指向的可以省略,这个称之为类型推导。

顺序表 与 ArrayList

1,顺序表:

顺序表是线性表的一种,其底层是由一个动态可扩容的数组 + 计数器组成。

2,实现

import java.util.Arrays;

public class MyArrayList<T> {
    private static final int DEFAULT_CAPACITY = 10;
    private Object[] array;
    private int size;

    public MyArrayList() {
        this.array = new Object[DEFAULT_CAPACITY];
        this.size = 0;
    }

    public void add(T element) {
        if (size == array.length) {
            resizeArray();
        }
        array[size++] = element;
    }

    public T get(int index) {
        if (index < 0 || index >= size) {
            throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);
        }
        return (T) array[index];
    }

    public void remove(int index) {
        if (index < 0 || index >= size) {
            throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);
        }
        System.arraycopy(array, index + 1, array, index, size - index - 1);
        size--;
    }

    public int size() {
        return size;
    }

    private void resizeArray() {
        int newCapacity = array.length * 2;
        array = Arrays.copyOf(array, newCapacity);
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append("[");
        for (int i = 0; i < size; i++) {
            sb.append(array[i]);
            if (i < size - 1) {
                sb.append(", ");
            }
        }
        sb.append("]");
        return sb.toString();
    }

    public static void main(String[] args) {
        MyArrayList<Integer> list = new MyArrayList<>();
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(4);
        list.add(5);
        System.out.println("List: " + list);
        System.out.println("Element at index 2: " + list.get(2));
        list.remove(2);
        System.out.println("List after removing element at index 2: " + list);
        System.out.println("Size of list: " + list.size());
    }
}

ArrayList的使用方法

1))构造方法

ArrayList有三种构造方法,分别是:无参构造,指定顺序表初始容量构造,利用其它Collection构造

无参构造

    • 无参构造方法实际上不开辟空间。
    • 当ArrayList第一次调用add方法时,会帮助ArrayList开辟十个元素的空间;
    • 当顺序表的内存使用完时,add方法会以原内存大小的1.5倍进行扩容(如果1.5倍扩容的内存小于我们需要的内存,则会直接开辟我们所需的内存大小,并且每次扩容都会判断是否超过该顺序表最大容量)

指定内存大小构造

当指定的数大于零时:直接开辟指定大小的空间

当指定的数等于零时:按照无参构造方法执行

当指定的数小于零时:抛出异常

利用其它Collection 构造

构造方法源码如下:

可以看到上文中有这样一段代码

public ArrayList(Collection<? extends E> c) { //... }

参数链表中的代码是什么意思呢?接下来,我们一个一个进行拆分讲解:

collection-->表示实参必须使用 实现了 Collection接口的类

示例如下:

(仅示范一个,ArrayList的构造方法,不仅仅可以使用ArrayList类型进行构造,还能使用所有实现Collection接口的类进行构造,如:Stack、Vector、LinkedList...)

c-->表示泛型类型必须是该构造类的泛型类型或是其泛型的子类。即是说,如下图:

arrayLis实例化,调用构造方法,此时其泛型传递的是Number类型。这就代表其帮助他构造的对象类型,泛型传递的类型必须是 Number 或是 Number 的子类。

? 是通配符,因为我们并不知道帮助其构造的对象 对象泛型传递的类型是什么,所以使用通配符替代。

c是实参名,接收的是传递过来的对象

| 操作               | 描述                                                  |
|--------------------|-------------------------------------------------------|
| add(E element)    | 将指定的元素追加到列表的末尾                          |
| add(int index, E element) | 将指定的元素插入到列表中的指定位置                  |
| get(int index)    | 返回列表中指定位置的元素                                |
| set(int index, E element) | 用指定的元素替换列表中指定位置的元素              |
| remove(int index) | 移除列表中指定位置的元素                                |
| remove(Object o)  | 移除列表中首次出现的指定元素                            |
| isEmpty()         | 如果列表不包含任何元素,则返回 true                    |
| size()            | 返回列表中的元素数                                      |
| clear()           | 从列表中移除所有元素                                    |
| contains(Object o)| 如果列表中包含指定的元素,则返回 true                   |
| indexOf(Object o) | 返回列表中首次出现的指定元素的索引,如果不存在则返回 -1 |
| lastIndexOf(Object o) | 返回列表中最后出现的指定元素的索引,如果不存在则返回 -1 |
| toArray()         | 返回一个包含列表所有元素的数组                          |
| subList(int fromIndex, int toIndex) | 返回列表中指定范围的视图(子列表)           |
| iterator()        | 返回在列表上的迭代器,允许在列表中迭代元素              |
| forEach(Consumer<? super E> action) | 对列表中的每个元素执行给定的操作             |
| sort(Comparator<? super E> c) | 根据指定的比较器对列表进行排序                  |

3))遍历方式

在 ArrayList 中可以使用三种方式进行遍历:for+小标,foreach,使用迭代器

以如下代码为例示范:

for循环遍历

foreach

使用迭代器

迭代器可以更便捷地为集合类进行遍历,使用方法如下:

使用迭代器之前需进行导包:import java.util.Iterator;

迭代器使用语法如下:

//使用前需要导包! Iterator<单个元素的类型> it = 集合类名.iterator(); while(it.hasNext()) { System.out.println(it.next()); }

  • 20
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值