Java 面向对象(十)
常用类之Arrays
java.util.Arrays 类是 JDK 提供的一个工具类,用来处理数组的各种方法,而且每个方法基本上都是静态方法,能直接通过类名Arrays调用。
1、asList
返回由指定数组支持的固定大小列表。
public static <T> List<T> asList(T... a) {
return new ArrayList<>(a);
}
注意:这个方法返回的 ArrayList 不是我们常用的集合类 java.util.ArrayList。这里的 ArrayList 是 Arrays 的一个内部类 java.util.Arrays.ArrayList。
这个内部类有如下属性和方法:
private static class ArrayList<E> extends AbstractList<E>
implements RandomAccess, java.io.Serializable
{
private static final long serialVersionUID = -2764017481108945198L;
private final E[] a;
ArrayList(E[] array) {
a = Objects.requireNonNull(array);
}
@Override
public int size() {
return a.length;
}
@Override
public Object[] toArray() {
return a.clone();
}
@Override
@SuppressWarnings("unchecked")
public <T> T[] toArray(T[] a) {
int size = size();
if (a.length < size)
return Arrays.copyOf(this.a, size,
(Class<? extends T[]>) a.getClass());
System.arraycopy(this.a, 0, a, 0, size);
if (a.length > size)
a[size] = null;
return a;
}
@Override
public E get(int index) {
return a[index];
}
@Override
public E set(int index, E element) {
E oldValue = a[index];
a[index] = element;
return oldValue;
}
@Override
public int indexOf(Object o) {
E[] a = this.a;
if (o == null) {
for (int i = 0; i < a.length; i++)
if (a[i] == null)
return i;
} else {
for (int i = 0; i < a.length; i++)
if (o.equals(a[i]))
return i;
}
return -1;
}
@Override
public boolean contains(Object o) {
return indexOf(o) != -1;
}
@Override
public Spliterator<E> spliterator() {
return Spliterators.spliterator(a, Spliterator.ORDERED);
}
@Override
public void forEach(Consumer<? super E> action) {
Objects.requireNonNull(action);
for (E e : a) {
action.accept(e);
}
}
@Override
public void replaceAll(UnaryOperator<E> operator) {
Objects.requireNonNull(operator);
E[] a = this.a;
for (int i = 0; i < a.length; i++) {
a[i] = operator.apply(a[i]);
}
}
@Override
public void sort(Comparator<? super E> c) {
Arrays.sort(a, c);
}
}
(1)返回的 ArrayList 数组是一个定长列表,我们只能对其进行查看或者修改,但是不能进行添加或者删除操作
通过源码我们发现该类是没有add()或者remove() 这样的方法的,如果对其进行增加或者删除操作,都会调用其父类 AbstractList 对应的方法,而追溯父类的方法最终会抛出 UnsupportedOperationException 异常。
String[] str = {"a","b","c"};
List<String> listStr = Arrays.asList(str);
listStr.set(1, "e"); // 可以进行修改
System.out.println(listStr.toString()); // [a, e, c]
listStr.add("a"); // 添加元素会报错 java.lang.UnsupportedOperationException
(2)引用类型的数组和基本类型的数组区别
String[] str = { "a", "b", "c" };
List listStr = Arrays.asList(str);
System.out.println(listStr.size()); // 3
int[] i = { 1, 2, 3 };
List listI = Arrays.asList(i);
System.out.println(listI.size()); // 1
上面的结果第一个listStr.size()=3,而第二个 listI.size()=1。
我们看源码,在 Arrays.asList 中,方法声明为 List asList(T... a)。该方法接收一个可变参数,并且这个可变参数类型是作为泛型的参数。我们知道基本数据类型是不能作为泛型的参数的,但是数组是引用类型,所以数组是可以泛型化的,于是 int[] 作为了整个参数类型,而不是 int 作为参数类型。
所以将上面的方法泛型化补全应该是:
String[] str = { "a", "b", "c" };
List<String> listStr = Arrays.asList(str);
System.out.println(listStr.size()); // 3
int[] i = { 1, 2, 3 };
List<int[]> listI = Arrays.asList(i); // 注意这里List参数为 int[] ,而不是 int
System.out.println(listI.size()); // 1
Integer[] in = { 1, 2, 3 };
List<Integer> listIn = Arrays.asList(in); // 这里参数为int的包装类Integer,所以集合长度为3
System.out.println(listIn.size()); // 3
(3)返回的列表ArrayList里面的元素都是引用,不是独立出来的对象
String[] str = { "a", "b", "c" };
List<String> listStr = Arrays.asList(str);
// 执行更新操作前
System.out.println(Arrays.toString(str));// [a, b, c]
listStr.set(0, "d");// 将第一个元素a改为d
// 执行更新操作后
System.out.println(Arrays.toString(str));// [d, b, c]
我们看修改集合的内容,原数组的内容也变化了,所以这里传入的是引用类型。
(4)已知数组数据,如何快速获取一个可进行增删改查的列表List?
String[] str = { "a", "b", "c" };
List<String> listStr = new ArrayList<>(Arrays.asList(str));
listStr.add("d");
System.out.println(listStr.size()); // 4
(5)Arrays.asList() 方法使用场景
Arrays工具类提供了一个方法asList,使用该方法可以将一个变长参数或者数组转换成List 。但是,生成的List的长度是固定的;能够进行修改操作(比如,修改某个位置的元素);不能执行影响长度的操作(如add、remove等操作),否则会抛出UnsupportedOperationException异常。
所以 Arrays.asList 比较适合那些已经有数组数据或者一些元素,而需要快速构建一个List,只用于读取操作,而不进行添加或删除操作的场景。
2、sort
该方法是用于数组排序,在 Arrays 类中有该方法的一系列重载方法,能对7种基本数据类型,包括 byte,char,double,float,int,long,short 等都能进行排序,还有 Object 类型(实现了Comparable接口),以及比较器 Comparator 。
(1)基本类型的数组
int[] num = { 1, 3, 8, 5, 2, 4, 6, 7 };
Arrays.sort(num);
System.out.println(Arrays.toString(num));// [1, 2, 3, 4, 5, 6, 7, 8]
(2)对象类型数组
该类型的数组进行排序可以实现 Comparable 接口,重写 compareTo 方法进行排序。
String[] str = { "a", "f", "c", "d" };
Arrays.sort(str);
System.out.println(Arrays.toString(str));// [a, c, d, f]
String 类型实现了 Comparable 接口,内部的 compareTo 方法是按照字典码进行比较的。
没有实现Comparable接口的,可以通过Comparator实现排序
class Person {
String name;
int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
}
public class Test {
public static void main(String[] args) {
Person[] p = new Person[] { new Person("zhangsan", 22), new Person("wangwu", 11), new Person("lisi", 33) };
Arrays.sort(p, new Comparator<Person>() {
@Override
public int compare(Person o1, Person o2) {
if (o1 == null || o2 == null) {
return 0;
}
return o1.getAge() - o2.getAge();
}
});
System.out.println(Arrays.toString(p));
}
}
3、binarySearch
用二分法查找数组中的某个元素。该方法和 sort 方法一样,适用于各种基本数据类型以及对象。
注意:二分法是对有序的数组进行查找(比如先用Arrays.sort()进行排序,然后调用此方法进行查找)。找到元素返回下标,没有则返回 -1
int[] num = { 1, 3, 8, 5, 2, 4, 6, 7 };
Arrays.sort(num);
System.out.println(Arrays.toString(num));// [1, 2, 3, 4, 5, 6, 7, 8]
System.out.println(Arrays.binarySearch(num, 2));// 返回元素的下标 1
具体源码实现:
public static int binarySearch(int[] a, int key) {
return binarySearch0(a, 0, a.length, key);
}
private static int binarySearch0(int[] a, int fromIndex, int toIndex,int key) {
int low = fromIndex;
int high = toIndex - 1;
while (low <= high) {
int mid = (low + high) >>> 1;//取中间值下标
int midVal = a[mid];//取中间值
if (midVal < key)
low = mid + 1;
else if (midVal > key)
high = mid - 1;
else
return mid;
}
return -(low + 1);
}
4、copyOf 和 copyOfRange
(1)copyOf
拷贝数组元素。以使副本具有指定的长度。底层采用 System.arraycopy() 实现,这是一个native方法。
public static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length);
e.g.
String[] str = { "1", "2", "5", "3", "4" };
str = Arrays.copyOf(str, 10);
System.out.println(Arrays.toString(str));
(2)copyOfRange
将指定数组的指定范围复制到一个新数组。 底层采用 System.arraycopy()实现。
5、equals 和 deepEquals
(1)equals
equals 用来比较两个数组中对应位置的每个元素是否相等。
八种基本数据类型以及对象都能进行比较。
我们先看看 int类型的数组比较源码实现:
public static boolean equals(int[] a, int[] a2) {
if (a==a2)//数组引用相等,则里面的元素一定相等
return true;
if (a==null || a2==null)//两个数组其中一个为null,都返回false
return false;
int length = a.length;
if (a2.length != length)//两个数组长度不等,返回false
return false;
for (int i=0; i<length; i++)//通过for循环依次比较数组中每个元素是否相等
if (a[i] != a2[i])
return false;
return true;
}
在看对象数组的比较:
public static boolean equals(Object[] a, Object[] a2) {
if (a==a2)
return true;
if (a==null || a2==null)
return false;
int length = a.length;
if (a2.length != length)
return false;
for (int i=0; i<length; i++) {
Object o1 = a[i];
Object o2 = a2[i];
if (!(o1==null ? o2==null : o1.equals(o2)))
return false;
}
return true;
}
(2)deepEquals
也是用来比较两个数组的元素是否相等,不过 deepEquals 能够进行比较多维数组,而且是任意层次的嵌套数组。
String[][] name1 = { { "G", "a", "o" }, { "H", "u", "a", "n" }, { "j", "i", "e" } };
String[][] name2 = { { "G", "a", "o" }, { "H", "u", "a", "n" }, { "j", "i", "e" } };
System.out.println(Arrays.equals(name1, name2)); // false
System.out.println(Arrays.deepEquals(name1, name2)); // true
6、fill
该系列方法用于给数组赋值,并能指定某个范围赋值。
源码分析:
// 给a数组所有元素赋值 val
public static void fill(int[] a, int val) {
for (int i = 0, len = a.length; i < len; i++)
a[i] = val;
}
// 给从 fromIndex 开始的下标,toIndex-1结尾的下标都赋值 val,左闭右开
public static void fill(int[] a, int fromIndex, int toIndex, int val) {
rangeCheck(a.length, fromIndex, toIndex);// 判断范围是否合理
for (int i = fromIndex; i < toIndex; i++)
a[i] = val;
}
7、toString 和 deepToString
toString 用来打印一维数组的元素,而 deepToString 用来打印多层次嵌套的数组元素。
源码分析:
public static String toString(int[] a) {
if (a == null)
return "null";
int iMax = a.length - 1;
if (iMax == -1)
return "[]";
StringBuilder b = new StringBuilder();
b.append('[');
for (int i = 0; ; i++) {
b.append(a[i]);
if (i == iMax)
return b.append(']').toString();
b.append(", ");
}
}
本文借鉴处:https://www.cnblogs.com/ysocean/p/8616122.html
Java 面向对象(十)的更多相关文章
- JavaSE学习总结(四)——Java面向对象十分钟入门
面向对象编程(Object Oriented Programming,OOP)是一种计算机模拟人类的自然思维方式的编程架构技术,解决了传统结构化开发方法中客观世界描述工具与软件结构的不一致性问题.Ja ...
- 20155322 2016-2017-2 《Java面向对象程序设计》第十二周课堂练习之Arrays和String单元测试
20155322 2016-2017-2 <Java面向对象程序设计>第十二周课堂练习之Arrays和String单元测试 练习目地 在IDEA中以TDD的方式对String类和Array ...
- Java学习笔记二十九:一个Java面向对象的小练习
一个Java面向对象的小练习 一:项目需求与解决思路: 学习了这么长时间的面向对象,我们只是对面向对象有了一个简单的认识,我们现在来做一个小练习,这个例子可以使大家更好的掌握面向对象的特性: 1.人类 ...
- Java学习笔记二十五:Java面向对象的三大特性之多态
Java面向对象的三大特性之多态 一:什么是多态: 多态是同一个行为具有多个不同表现形式或形态的能力. 多态就是同一个接口,使用不同的实例而执行不同操作. 多态性是对象多种表现形式的体现. 现实中,比 ...
- Java学习笔记十八:Java面向对象的三大特性之封装
Java面向对象的三大特性之封装 一:面向对象的三大特性: 封装 继承 多态 二:封装的概念: 将类的某些信息隐藏在类内部,不允许外部程序直接访问,而是通过该类提供的方法来实现对隐藏信息的操作和访 ...
- Java面向对象----个人参考资料
Java面向对象 :什么是面向对象.类与对象.封装.构造方法.static关键字.继承.抽象类.接口.多态 一.什么是面向对象 1.面向过程思想 面向过程:(PO,Procedure Oriented ...
- JAVA面向对象编程课程设计——网络版单机斗地主
一.团队介绍 成员姓名 任务分配 成员课程设计博客链接 兰泽祥(组长) 数据库,斗地主规则的实现,人机自动出牌的算法,实体类的设计 JAVA面向对象编程课程设计--web版斗地主 吴修恩 JSP界面的 ...
- 2017-2018-2 20165301 实验四《Java面向对象程序设计》实验报告
2017-2018-2 20165301 实验四<Java面向对象程序设计>实验报告 一.Android Stuidio的安装测试 实验要求: 参考<Java和Android开发学习 ...
- 20155201 实验四《Java面向对象程序设计》实验报告
20155201 实验四<Java面向对象程序设计>实验报告 一.实验内容 1.基于Android Studio开发简单的Android应用并部署测试; 2.了解Android.组件.布局 ...
- 20155217 实验四《Java面向对象程序设计》实验报告
20155217 实验四<Java面向对象程序设计>实验报告 一.实验内容 1.基于Android Studio开发简单的Android应用并部署测试; 2.了解Android.组件.布局 ...
随机推荐
- 2743711 - Possible Unexpected Results When Using Query With an ORDER BY Clause on a Rowstore Table With a Parallelized Search on a Cpbtree-Type Index
2743711 - Possible Unexpected Results When Using Query With an ORDER BY Clause on a Rowstore Table W ...
- linux查看日志报错
查看运行时错误: tail -f catalina.out | grep -C 10 'Exception' 10是行数: 单引号里面的是要查找的关键字:
- Python实现YOLO目标检测
作者:R语言和Python学堂 链接:https://www.jianshu.com/p/35cfc959b37c 1. 什么是目标检测? YOLO目标检测的一个示例 啥是目标检测? 拿上图 (用YO ...
- iOS 内存管理的一点小问题
现在大家的项目应该基本都是ARC了,如果还是MRC的话,赶紧转换到ARC吧!最近被临时拉过去开发iPad,由于项目原因,还是使用的MRC.今天在调部分界面的时候,发现一段代码,我怎么看都怎么觉得怪怪的 ...
- redis连接数高居不下,怎么破?。。。。这么破
最近项目一直在使用redis,首次用redis,随便从网上找了例子就用了,一开始用的还挺正常,后来发现,当客户端访问量一上来,redis的连接数居高不下,一开始以为是客户端没有关闭,开始怀疑redis ...
- Django中实现单表和多表接口
基础接口 序列化:course/serializers.py from rest_framework import serializers from .models import CourseCate ...
- Linux动态连接器
转自:Chapter 9. Dynamic Linking 参考:Linux动态链接器 Linux加载启动可执行程序的过程(一)内核空间加载ELF的过程 Linux加载启动可执行程序的过程(二)解释器 ...
- OpenStack环境搭建
实验环境 CentOS-7-x86_64-Minimal-1708.iso openstack_N.tar.gz 创建虚拟机 controller部署 computer网络配置 OpenStack环境 ...
- Oracle基础知识【1】
目录: 1.Oracle创建库.表 2.Oracle数据怎删查改操作 3.Oracle数据约束条件 Oracle创建库.表: create user user05 identified by 1234 ...
- JDK环境变量配置window
下面开始配置环境变量,右击[我的电脑]---[属性]-----[高级]---[环境变量],如图: 选择[新建系统变量]--弹出“新建系统变量”对话框,在“变量名”文本框输入“JAVA_HOME”,在 ...