常用类
Object类
package cn.timevaeless.任务十常用类;
import java.util.Objects;
/**
* Object类
* @author timevaeless
* @version 1.0
* @date 2020/8/17 11:25 AM
*/
public class OObject extends Object {
private String name;
/**
* equals方法要同时满足如下条件:
* ①reflexive: x.equals(x) should return true
* ②symmetric: x.equals(y) should return true, y.equals(x) returns true
* ③transitive: if x.equals(y) returns true and y.equals(z) returns true, then x.equals(z) should return true
* ④consistent: multiple invocations of x.equals(y) consistently return true or consistently return false
* @param obj
* @return
*/
@Override
public boolean equals(Object obj) {
// reflexive
if (this == obj) {
return true;
}
// 可比
if (obj == null || getClass() != obj.getClass()) {
return false;
}
OObject oobj = (OObject) obj;
return name != null ? name.equals(oobj.name): oobj.name == null;
}
/**
* hashcode方法要满足,当equals相等时,hashcode也需要相等,可以把hashcode理解为内存地址值。
* If two objects are equal according to the equals(Object) method,
* then calling the hashCode method on each of the two objects must produce the same integer result.
* @return
*/
@Override
public int hashCode() {
return Objects.hash(name);
}
/**
* toString
* It is recommended that all subclasses override this method.
* @return
*/
@Override
public String toString() {
return "OObject{" +
"name=" + name +
'}';
}
}
包装类
package cn.timevaeless.任务十常用类;
/**
* 包装类
* @author timevaeless
* @version 1.0
* @date 2020/8/17 12:36 PM
*/
public class Wrapper {
// int num = 10,基本数据类型不是对象,而java是面向对象语言
// 为了符合该理念,将基本数据类型包装为对象
static class MyInt {
private int num;
public MyInt(int num) {
this.num = num;
}
}
public static void main(String[] args) {
System.out.println(Integer.MAX_VALUE); // 2^31 - 1
System.out.println(Integer.MIN_VALUE); // -2^31
System.out.println(Integer.SIZE); // 所占位数
System.out.println(Integer.BYTES); // 所占字节数
System.out.println(Integer.TYPE); // int类型的Class实例名
// 装箱:从int类型转换成Integer类型
Integer integer = Integer.valueOf(10);
// 自动装箱 (since(jdk5))
integer = 10;
// 拆箱:从Integer类型转换成int类型
int i = integer.intValue();
// 自动拆箱
i = integer;
// 自动装箱池:默认将-128-127的整数装箱完毕,当使用该范围内的整数时,无需装箱,直接取自动装箱池中的对象即可。
Integer integer2 = 128;
Integer integer3 = 128;
Integer integer4 = 127;
Integer integer5 = 127;
Integer integer6 = new Integer(128);
Integer integer7 = new Integer(128);
System.out.println(integer2 == integer3); // false
System.out.println(integer4 == integer5); // true
System.out.println(integer6 == integer7); // false
// 进制
System.out.println(Integer.toBinaryString(200));
System.out.println(Integer.toHexString(200));
System.out.println(Integer.toOctalString(200));
// Number类是Byte, Double, Float, Integer, Long, Short的共同抽象父类
Number d = Double.valueOf("3.14");
System.out.println(d);
// Boolean
System.out.println(Boolean.parseBoolean("TRUE"));
// Character
System.out.println(Character.getNumericValue('a')); // 10
}
}
String类
/**
* String类
*
* @author timevaeless
* @version 1.0
* @date 2020/8/17 7:05 PM
*/
public class SString {
public static void main(String[] args) {
// 验证字符串常量池的存在
String str = "abs";
String str2 = "abs";
System.out.println(str == str2);
String s = new String(); // ""
System.out.println("s = " + s);
byte[] bytes = {'a', 98, 99, 'd'};
// 使用字节数组构造字符串
String s1 = new String(bytes, 0, bytes.length);
System.out.println(s1);
// 使用字符数组构造字符串
char[] chars = {'h', 'e', 'l', 'l', 'o'};
String s2 = new String(chars, 0, chars.length);
System.out.println(s2);
// 请问下面有几个对象? (2个,一个是字符串常量池中的abc对象,一个是堆中的)
String abc = new String("abc");
// 常量有优化机制,变量没有
String abc1 = "abc";
String abc2 = "ab" + "c";
System.out.println(abc1 == abc2);
String abc3 = "ab";
String abc4 = abc3 + "c";
System.out.println(abc1 == abc4);
// String转换为byte数组
// 先将字符串拆分为字符,再将字符转换为byte,也就是获取所有字符的ascii码。
byte[] bytes1 = "abc北京欢迎你".getBytes();
System.out.println(Arrays.toString(bytes1));
char[] chars1 = "abc北京欢迎你".toCharArray();
System.out.println(Arrays.toString(chars1));
// 利用ascii码将字符串12345转换为整数12345
String num = "12345";
int b = 0;
for (int i = 0; i < num.length(); i++) {
b = b * 10 + num.charAt(i) - '0';
}
System.out.println(b);
// 判断是否是回文
String t = "上海自来水来自海上";
int i;
for (i = 0; i < t.length() / 2; i++) {
if (t.charAt(i) != t.charAt(t.length() - 1 - i)) {
break;
}
}
if (i == t.length() / 2) {
System.out.println("是回文");
}
// 字符串之间大小比较
String str3 = "hello";
String str4 = "haha"; // e - a = 4
String str5 = "world"; // h - w = -15
String str6 = "heihei"; // l - i = 3
String str7 = "helloworld"; // -5 如果前面一样,则返回长度差 this.length()-anotherString.length()
System.out.println(str3.compareTo(str4));
System.out.println(str3.compareTo(str5));
System.out.println(str3.compareTo(str6));
System.out.println(str3.compareTo(str7));
// 找到所有day的索引位置
String str8 = "Day Day Up.";
// 方法一
int pos = str8.indexOf("Day");
while (pos != -1) {
System.out.print(pos + ", ");
pos = str8.indexOf("Day", pos + 1);
}
// 方法二
pos = 0;
while ((pos = str8.indexOf("Day", pos)) != -1) {
System.out.print(pos + ",");
pos = pos + "Day".length();
}
}
}
正则表达式
/**
* 正则表达式
* @author timevaeless
* @version 1.0
* @date 2020/8/17 10:41 PM
*/
public class RRegx {
// [abc] - 可以出现a、b、c任意一个字符
// [^abc] - 可以出现任意一个字符,除了a、b、c
// [a-zA-Z0-9]
// . - 任意一个字符,除了换行符
// \d - 可以出现任意一个数字字符
// \D - 可以出现任意一个非数字字符
// \s - 空白字符,如\t、\n、\xOB(垂直制表符)、\f(换页符)、\r(回车不换行)
// \S - 非空白字符
// \w - 任意一个单词,相当于[a-zA-Z_0-9]
// \W - 任意一个非单词字符
// X? - 表示X可以出现0-1次
// X* - 表示X可以出现0-n次
// X+ - 表示X可以出现1-n次
// X{n} - 表示X恰好出现n次
// X{n, } - 表示X可以出现>=n次
// X{n, m} - 表示X可以出现(n<=X<=m)次
public static void main(String[] args) {
// 判断用户是不是大于6位且首位必须是字母
String regex = "[a-zA-Z]\\w{5,}";
// 判断是不是QQ号
String regex2 = "[1-9]\\d{4,14}";
// 判断是不是手机号
String regex3 = "1[3456789]\\d{9}";
// 判断是不是身份证号
String regex4 = "(\\d{6})(\\d{4})(\\d{2})(\\d{2})(\\d{3})([0-9|X|x])";
String user = "_imevaeless";
String qq = "342623";
System.out.println(user.matches(regex));
System.out.println(qq.matches(regex2));
// Split
String str = "001SACGHA002BY";
String regex5 = "[G-Z]+";
String[] strArray = str.split(regex5);
for (String s : strArray) {
System.out.println(Long.parseLong(s, 16));
}
// replace 替换所有
String replace = str.replace('A', 'a');
System.out.println(replace);
// replaceFirst 可以使用正则
System.out.println(str.replaceFirst("[A-Z]+", "A"));
// replaceAll 可以使用正则
System.out.println(str.replaceAll("[A-Z]+", "#"));
}
}
StringBuilder类
/**
* StringBuilder类
*
* @author timevaeless
* @version 1.0
* @date 2020/8/18 8:48 AM
*/
public class SStringBuilder {
// 由于String类描述的字符串内容是个常量不可改变
// 当需要在Java代码中描述大量类似的字符串时,只能单独申请和存储,此时会造成内存空间的浪费。
public static void main(String[] args) {
StringBuilder sb = new StringBuilder(); // capacity = 16
sb = new StringBuilder(32); // capacity = 32
sb = new StringBuilder("Hello"); // capacity = 16 + "Hello".length
System.out.println(sb.capacity()); // 21
System.out.println(sb.length()); // 5
System.out.println(sb.append("EFGABD") // HelloEFGABD
.insert(sb.length() - 1, "C") // HelloEFGABCD offset是插在该位置前面,因为insert(0,) 肯定插在最前面
.deleteCharAt(sb.length() - 5) // HelloEFABCD
.delete(sb.length() - 6, sb.length() - 4) // HelloABCD
.replace(sb.length() - 4, sb.length(), "StringBuilder !") // Hello StringBuilder ! 左闭右开
);
// StringBuilder为什么要返回this?为了连续调用
}
}
日期类
/**
* Date类
* @author timevaeless
* @version 1.0
* @date 2020/8/18 9:24 AM
*/
public class DDate {
public static void main(String[] args) throws ParseException {
long currentTimeMillis = System.currentTimeMillis();
System.out.println(currentTimeMillis); // 从197001010000起到现在的毫秒值
// Date
Date date = new Date();
date = new Date(currentTimeMillis);
long time = date.getTime(); // 从197001010000起到现在的毫秒值
date.setTime(time);
System.out.println(date);
// SimpleDateFormat:Date展示的不符合我们的习惯
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println(sdf.format(date));
System.out.println(sdf.parse("2020-12-20 08:08:00"));
// Calendar:Date只适合美国,Calendar更适合全球化
Calendar calendar = Calendar.getInstance();
calendar.set(2020, 12, 20, 8, 8, 00);
calendar.set(Calendar.MONTH, 15);
calendar.add(Calendar.HOUR, 30);
date = calendar.getTime(); // 获得Date对象
System.out.println(sdf.format(date));
// 多态的使用场合
// 通过方法的参数传递形成多态: draw(new Rect(1, 2, 3, 4));
// 在方法体中直接使用多态的语法格式: Account acc = new FixedAccount();
// 通过方法的返回值类型形成多态:Calender getInstance(){return new GregorianCalendar(zone, aLocale);}
// JDK8新的日期类:Calendar使用麻烦,并且线程不安全
System.out.println(LocalDate.now());
System.out.println(LocalTime.now());
System.out.println(LocalDateTime.now());
// 自定义
LocalDateTime localDateTime = LocalDateTime.of(2020, 12, 21, 8, 8, 0);
System.out.println(localDateTime.getMonth().name()); // 返回枚举类型
System.out.println(localDateTime.getMonthValue());
System.out.println(localDateTime.getDayOfMonth());
// 设置值: 和String一样,源对象不可变,每次都产生新的对象
LocalDateTime localDateTime1 = localDateTime.withYear(2021).withMonth(Month.DECEMBER.getValue()).withDayOfMonth(8);
System.out.println(localDateTime == localDateTime1); // false 不是同一个对象,每次调用with都会生成新的对象
System.out.println(localDateTime1);
// 加减
LocalDateTime localDateTime2 = localDateTime1.plusDays(20).minusMonths(10);
System.out.println(localDateTime2);
// Instant: 获取当前系统的时间,并不是系统的默认时区,而是本初子午线的时间,东八区差8小时
Instant now = Instant.now();
OffsetDateTime offsetDateTime = now.atOffset(ZoneOffset.ofHours(8)); // 获取东八区系统时间
System.out.println(offsetDateTime);
System.out.println(offsetDateTime.toInstant().toEpochMilli()); // 获取197001010000到现在的毫秒值
Instant instant = Instant.ofEpochMilli(1597717402192L);
System.out.println(instant.atOffset(ZoneOffset.ofHours(8)));
// DateTimeFormatter
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String format = dateTimeFormatter.format(localDateTime);
System.out.println(format);
System.out.println(dateTimeFormatter.parse(format));
}
}
Collection接口
/**
* Collection类
* @author timevaeless
* @version 1.0
* @date 2020/8/18 10:40 AM
*/
public class CCollection {
public static void main(String[] args) {
// 当需要在Java程序中记录单个数据内容时,则声明一个变量。
// 当需要在Java程序中记录多个类型相同的数据内容时,声明一个一维数组。
// 当需要在Java程序中记录多个类型不同的数据内容时,则创建一个对象。
// 当需要在Java程序中记录多个类型相同的对象数据时,创建一个对象数组。
// 当需要在Java程序中记录多个类型不同的对象数据时,则准备一个集合。
// 接口的引用指向实现类对象,形成多态。
Collection collection = new ArrayList();
collection.add(1);
collection.add(2.0);
collection.add("Hello");
collection.add(true);
collection.add(collection); // 当成整体添加到原集合里
collection.addAll(collection); // 将元素添加到原集合里
System.out.println(collection); // [1, 2.0, Hello, true, (this Collection), 1, 2.0, Hello, true, (this Collection)]
// 判断是否包含指定对象
collection.contains(2.0); // true
// 判断是否包含参数指定的所有对象
Collection collection2 = new ArrayList();
collection2.add(1);
collection2.add(1);
collection2.add(2.0);
collection.contains(collection2); // false 判断整体是不是collection的一个元素
collection.containsAll(collection2); // 判断每个元素是不是都在collection里
// 交集: 保留当前集合中存在且参数集合中存在的所有对象
collection.retainAll(collection2); // 当前集合发生改变返回true,否则返回false
System.out.println(collection); // [1, 2.0, 1, 2.0] 会直接改变该集合本身
// 从集合中删除对象
collection.remove(1); // [2.0, 1, 2.0] 通过equals来删除相等的元素, 只删一次
// collection.removeAll(collection2); // []
// 其他方法
collection.size();
collection.isEmpty();
collection.clear();
// boolean equal = (o.getClass() == ArrayList.class) ? equalsArrayList((ArrayList<?>) o) : equalsRange((List<?>) o, 0, size)
collection.equals(collection);
Object[] objects = collection.toArray(); // 集合转数组
Arrays.asList(objects); // 数组转集合
// Iterator: java.util.Iterator接口主要用于描述迭代器对象,可以遍历Collection集合中的所有元素。
// java.util.Collection接口继承Iterator接口,因此所有实现Collection接口的实现类都可以使用该迭代器对象。
collection.add(1);
collection.add(2);
collection.add(3);
Iterator iterator = collection.iterator(); // 相当于指针,一开始指向最开头前面
iterator.hasNext(); // true
iterator.next(); // 1
iterator.hasNext(); // true
iterator.next(); // 2
iterator.hasNext(); // true
iterator.next(); // 3
iterator.hasNext(); // false
// iterator.next(); // NoSuchElementException
// 使用迭代器遍历每个元素
iterator = collection.iterator();
StringBuilder sb = new StringBuilder();
sb.append("[");
while (iterator.hasNext()) {
Object next = iterator.next();
if (! iterator.hasNext()) {
sb.append(next).append("]");
} else {
sb.append(next).append(", ");
}
}
System.out.println(sb.toString()); // [1, 2, 3]
// 使用迭代器遍删除元素
iterator = collection.iterator();
while (iterator.hasNext()) {
Object next = iterator.next();
if (next == Integer.valueOf(2)) {
iterator.remove();
// collection.remove(next);
// 检测到在并发修改该对象时可能产生ConcurrentModificationException
// 通常不允许一个线程修改Collection,而另一个线程对其进行迭代。
}
}
System.out.println(collection); // [1, 3]
// 使用断点
for (Object o: collection) {
System.out.println(o);
}
// List
// java.util.List集合是Collection集合的子集合,该集合中允许有重复的元素并且有先后放入次序。
// 该集合的主要实现类有:ArrayList类、LinkedList类、Stack类、Vector类。
// 其中ArrayList类的底层是采用动态数组进行数据管理的,支持下标访问,增删元素不方便。
// 其中LinkedList类的底层是采用双向链表进行数据管理的,访问不方便,增删元素方便。
// 可以认为ArrayList和LinkedList的方法在逻辑上完全一样,只是在性能上有一定的差别,
// ArrayList更适合于随机访问而LinkedList更适合于插入和删除;在性能要求不是特别苛刻的情形下可以忽略这个差别。
// 其中Stack类的底层是采用动态数组进行数据管理的,该类主要用于描述一种具有后进先出特征的数据结构,叫做栈(last in first out LIFO)。
// 其中Vector类的底层是采用动态数组进行数据管理的,该类与ArrayList类相比属于线程安全的类,效率比较低,以后开发中基本不用。
// ArrayList
// 用断点分析是如何进行扩容的
// 1.5倍进行扩容的,int newCapacity = oldCapacity + (oldCapacity >> 1);
ArrayList arrayList = new ArrayList();
arrayList.add("Hello");
arrayList.add(arrayList.size(), "World");
arrayList.addAll(collection); // [Hello, World, 1, 3]
Object o = arrayList.get(0);
arrayList.indexOf("World"); // 1
arrayList.lastIndexOf("World"); // 1
Object sourceValue = arrayList.set(2, "!"); // [Hello, World, !, 3]
List list = arrayList.subList(0, 2); ; // [Hello, World]
list.remove(0); // subList和arrayList仍共用同一块内存空间,所以修改subList,arrayList也会改变
System.out.println(list); // [World]
System.out.println(arrayList); // [World, !, 3]
for (int i=0; i<arrayList.size();) { // 依次删除每个元素
arrayList.remove(0);
}
System.out.println(arrayList);
// LinkedList
// 用断点分析是怎么实现双向链表的(通过Node)
Queue linkedList = new LinkedList();
linkedList.add("World");
// Stack类:继承自Vector,被Queue取代
Stack stack = new Stack();
stack.push("end");
stack.push("middle");
stack.push("top");
stack.pop(); // top
stack.pop(); // middle
stack.pop(); // end
// stack.pop(); // EmptyStackException
// stack.peek(); // EmptyStackException 看一下栈顶的值
stack.isEmpty(); // true
// Vector类
Vector vector = new Vector();
vector.add("Hello");
System.out.println(vector);
// Queue类
Queue queue = new LinkedList();
queue.offer("Hello");
queue.offer("Queue");
queue.offer("!"); // [Hello, Queue, !]
queue.peek(); // 队首 Hello
Object poll = queue.poll();// 出队 [Queue, !]
}
}
泛型
/**
* @author timevaeless
* @version 1.0
* @date 2020/8/20 1:01 AM
*/
public class Generic {
// ①集合中为什么能存放任意类型的数据?是因为集合把所有对象都当成Object类型放入的。
// 集合虽然支持放入不同的类型,但取数据的时候极容易发生数据类型转换异常。
// 泛型就是指定数据类型,泛型只在编译时期有效,在运行时期不区分是什么类型
// <E> 就好比形式参数,我们可以传入各种数据类型
public static void main(String[] args) {
Person person = new Person(); // 不使用泛型,所有元素保存为Object类
Person<Boolean> person2 = new Person<>();
person.setGender(true);
Person.printArray(new String[] {"Hello", "Genenic"});
// ④Student是Person子类,但是List<Student> 并不是List<Person>的子类
List<Person> list = new ArrayList<>();
List<Student> list2 = new ArrayList<>();
// list2 = list; // 编译错误
// ⑤通配符:那么List<Student>的父类是啥呢?
// <?>: 无限制的通配符
// <? extends E>
// <? super E>
List<?> list3 = list;
// list3.add(new Person()); // 编译错误,不能存?(只能取,不能存)
List<? extends Person> list4 = list;
// 依然只能取不能存
// 因为<? extends Person>只告诉了类型的上限,而没有给一个具体的类型
// 违背了泛型的初衷:保证编译阶段数据类型一致,防止运行期间类型转换异常
// list4.add("Hello");
List<? super Student> list5 = list;
// 可以存
// 都传下限的数据类型一定不会报错,所以允许传
// 但如果传父类,如果给传,则取出来的时候又会面临数据类型转换问题了,父到子可能转换错误
list5.add(new Student());
// list5.add(new Person());
// 结论:PECS (Producer Extends,Consumer Super)
// 生产者:只取数据用 ? extends E
// 消费者:只存数据用 ? super E,如 boolean addAll(Collection<? extends E> c)
}
}
class Person<E> {
private E name;
private E gender;
public void setGender(E gender) {
this.gender = gender;
}
// ③这不叫泛型方法, E只是占位符,必须等Person实例化后才能明确E是啥数据类型,所以该方法不能加static关键字
public E getName() {
return name;
}
// 泛型方法
public static <T> T printArray(T[] arr) {
for (T t : arr) {
System.out.println(t);
}
return arr[0];
}
}
class Student extends Person { // ②不保留父类的泛型
}
class Teacher<E> extends Person<E> { // 保留父类的泛型
}
class Man<K, V> extends Person<K> { // 保留父类的泛型,同时在子类增加一个泛型
}
Set集合
package cn.timevaeless.任务十一集合;
import java.util.Comparator;
import java.util.HashSet;
import java.util.TreeSet;
/**
* Set类
*
* @author timevaeless
* @version 1.0
* @date 2020/8/20 10:11 AM
*/
public class SSet {
public static void main(String[] args) {
// ①Set是Collection的子接口,与List接口平级。
// 元素没有先后放入次序,且不允许重复。
// HashSet -> 哈希表
// TreeSet -> 红黑树
// LinkedHashSet -> 哈希表+双向链表,双向链表中记录了元素的迭代顺序,也就是元素插入集合中的先后顺序,因此便于迭代。
// ②HashSet元素放入原理
// - 获取元素的hashCode,再由(tab.length - 1) & hash计算出该元素在数组中的索引位置。
// - 若数组该位置没有元素,则将该元素直接放到该位置。
// p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k))
// - 若该位置有元素,则使用新元素与已有元素依次比较哈希值,若哈希值不相同,则将该元素直接放入。
// - 若新元素与已有元素的哈希值相同,则使用新元素调用equals方法与已有元素依次比较。
// - 若相等则添加元素失败,否则将元素直接放入即可。
// ③为什么要求重写equals方法后要重写hashCode方法呢?
// 当两个元素调用equals方法相等时证明这两个元素相同,重写hashCode方法后保证这两个元
// 素得到的哈希码值相同,由同一个哈希算法生成的索引位置相同,此时只需要与该索引位置已有元
// 素比较即可,从而提高效率并避免重复元素的出现。
HashSet<String> hashSet = new HashSet<>();
hashSet.add("one");
boolean one = hashSet.add("one"); // false
hashSet.add("two");
hashSet.add("three");
hashSet.add("four");
hashSet.add("five");
hashSet.add("six");
System.out.println(hashSet); // 无序 [six, four, one, two, three, five]
// ④TreeSet
// 二叉树主要指每个节点最多只有两个子节点的树形结构。
// 满足以下3个特征的二叉树叫做有序二叉树。
// a.左子树中的任意节点元素都小于根节点元素值;
// b.右子树中的任意节点元素都大于根节点元素值;
// c.左子树和右子树的内部也遵守上述规则;
//
// TreeSet底层采用红黑树进行数据管理,红黑树是有序二叉树的一种实现,所以是有序的。
// 当有新元素插入到TreeSet集合时,需要能够比较大小。
//
// 比较元素大小的规则有两种方式:
// a.让元素类实现java.lang.Comparable接口;
// b.构造TreeSet集合时传入java.util.Comparator接口;
TreeSet<Person> treeSet = new TreeSet<>();
treeSet.add(new Person(18, "a"));
treeSet.add(new Person(33, "b"));
treeSet.add(new Person(22, "c"));
System.out.println(treeSet); // [Person{age=18, name='a'}, Person{age=33, name='b'}, Person{age=22, name='c'}]
treeSet = new TreeSet<>(new Comparator<Person>() {
@Override
public int compare(Person o1, Person o2) { // o1是新增的,o2是已有的
int i = o1.getAge() - o2.getAge();
return i != 0 ? i: o1.getName().compareTo(o2.getName());
}
});
treeSet.add(new Person(18, "a"));
treeSet.add(new Person(33, "b"));
treeSet.add(new Person(33, "b")); // 重复元素
treeSet.add(new Person(22, "c"));
System.out.println(treeSet); // [Person{age=18, name='a'}, Person{age=22, name='c'}, Person{age=33, name='b'}]
}
}
class Person implements Comparable<Person> {
private int age;
private String name;
public Person(int age, String name) {
this.age = age;
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public int compareTo(Person o) {
// 先按名字排序,再按年龄排序
int i = name.compareTo(o.getName());
return i != 0 ? i : age - o.getAge();
}
@Override
public String toString() {
return "Person{" +
"age=" + age +
", name='" + name + '\'' +
'}';
}
}
Map集合
/**
* Map类
* @author timevaeless
* @version 1.0
* @date 2020/8/20 10:55 AM
*/
public class MMap {
public static void main(String[] args) {
// ①java.util.Map<K,V>集合中存取元素的基本单位是:单对元素,其中类型参数如下:
// K - 此映射所维护的键(Key)的类型,相当于目录。
// V - 映射值(Value)的类型,相当于内容。
// key不允许重复的,而且一个key只能对应一个value。
// HashMap -> 哈希表。
// TreeMap -> 红黑树。
// LinkedHashMap -> 哈希表+内部维护了一个双向链表,链表中记录了元素的迭代顺序,也就是元素插入集合中的先后顺序,因此便于迭代。
// Hashtable类是古老的Map实现类,与HashMap类相比属于线程安全的类,且不允许null作为key或者value的数值。
// Properties类是Hashtable类的子类,该对象用于处理属性文件,key和value都是String类型的。
// Map集合是面向查询优化的数据结构, 在大数据量情况下有着优良的查询性能。
// 经常用于根据key检索value的业务场景。
// ②元素放入HashMap集合的原理
// - 使用元素的key调用hashCode方法获取对应的哈希码值,再由某种哈希算法计算在数组中的索引位置。
// - 若该位置没有元素,则将该键值对直接放入即可。
// - 若该位置有元素,则使用key与已有元素依次比较哈希值,若哈希值不相同,则将该元素直接放入。
// - 若key与已有元素的哈希值相同,则使用key调用equals方法与已有元素依次比较。
// - 若相等则将对应的value修改,否则将键值对直接放入即可。
HashMap<String, String> hashMap = new HashMap<>();
hashMap.put("1", "one");
hashMap.put("2", "two");
hashMap.put("3", "three");
String one = hashMap.put("1", "one2");// 重复的key,覆盖之前的
System.out.println("原来的值:" + one);
// ③HashMap相关的常量
// - DEFAULT_INITIAL_CAPACITY : HashMap的默认容量是16。
// - DEFAULT_LOAD_FACTOR:HashMap的默认加载因子是0.75。
// - threshold:扩容的临界值,该数值为:容量*填充因子,也就是12。即当数组size大于12时则进行扩容。
// !!!扩容的目的是让元素尽可能分散在不同的下标,即让每个链表链的元素尽可能少,遍历的时候效率就更好。
// - TREEIFY_THRESHOLD:若Bucket中链表长度大于该默认值则转化为红黑树存储,该数值是8。
// - MIN_TREEIFY_CAPACITY:桶中的Node被树化时最小的hash表容量,该数值是64。
String s = hashMap.get("1"); // one
boolean b = hashMap.containsKey("1"); // true
b = hashMap.containsValue("one");// 被覆盖了 false
String remove = hashMap.remove("1"); // one2
Set<String> set = hashMap.keySet(); // map不能直接迭代,因为没有实现Iterator接口
for (String key : set) {
System.out.println(key + ":" + hashMap.get(key));
}
Collection<String> values = hashMap.values();
for (String value: values) {
System.out.println(value);
}
Set<Map.Entry<String, String>> entries = hashMap.entrySet();
for (Map.Entry<String, String> entry: entries) {
System.out.println(entry);
}
}
}
Collections工具类
package cn.timevaeless.任务十一集合;
import java.util.*;
/**
* Collections类
* @author timevaeless
* @version 1.0
* @date 2020/8/20 11:29 AM
*/
public class CCollections {
public static void main(String[] args) {
List<Animal> animals = Arrays.asList(new Animal(20), new Animal(10), new Animal(30));
Animal max = Collections.max(animals);// Animal{age=30}
max = Collections.max(animals, new Comparator<Animal>() {
@Override
public int compare(Animal o1, Animal o2) {
return o2.getAge() - o1.getAge();
}
}); // Animal{age=10}
Collections.reverse(animals); // 不需要返回值 [Animal{age=30}, Animal{age=10}, Animal{age=20}]
Collections.swap(animals, 0, 1); // [Animal{age=10}, Animal{age=30}, Animal{age=20}]
Collections.sort(animals); // 根据其元素的自然顺序将指定列表按升序排序 [Animal{age=10}, Animal{age=30}, Animal{age=20}]
Collections.sort(animals, new Comparator<Animal>() {
@Override
public int compare(Animal o1, Animal o2) {
return o2.getAge() - o1.getAge();
}
}); // [Animal{age=30}, Animal{age=20}, Animal{age=10}]
Collections.shuffle(animals); // 随机打乱 [Animal{age=20}, Animal{age=10}, Animal{age=30}]
List<Animal> animals2 = new ArrayList<>(20);
animals2.size(); // 0 只是分配了内存,但实际没存放元素
animals2 = Arrays.asList(new Animal[3]);
Collections.copy(animals2, animals); // [Animal{age=20}, Animal{age=10}, Animal{age=30}]
}
}
class Animal implements Comparable<Animal> {
private int age;
public Animal(int age) {
this.age = age;
}
public int getAge() {
return age;
}
@Override
public int compareTo(Animal o) {
return age - o.age;
}
@Override
public String toString() {
return "Animal{" +
"age=" + age +
'}';
}
}