0%

情况分析

  1. 先判断是否为一组对象或者一组键值对,判断使用单列的集合还是双列
  2. 一组对象中,允许重复的我们使用List,对于增删多的使用LinkedList(底层维护了双向链表),而不允许重复的我们使用Set,对于无序使用HashSet(数组+链表+红黑树),排序的通TreeSet,抽出和取出的顺序一致,我们使用LinkedHashSet,底层维护了数组+双向链表
  3. 一组键值对Map,键无序,使用HashMap(数组+链表+红黑树),键排序,使用TreeMap,键插入和取出顺序一致:LinkedHashMap

集合的好处

  1. 可以动态保存任意多个对象,使用比较方便
  2. 提供了一系列方便的操作对象的方法:add,remove,set,get等
  3. 使用集合添加,删除新元素的示意代码,简介明了

集合的框架体系

下面是我们Collection集合(单列集合)常见的重要的子类,在集合放的是单个的子类

image-20220704180327305还有Map(双列集合)集合的重要的框架图,存放的k-V的集合,即可以存放两个集合。

image-20220704180334057

ArrayList注意事项

  • 可以存储空值,但是遍历会出错
  • ArrayList存储数据底层由数组来实现
  • ArrayList基本等同于Vector,但是ArrayList是线程不安全的,多线程不建议使用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;

public class Test {
public static void main(String [] args){

Dog dog1=new Dog("ahhua",12);
Dog dog2=new Dog("a",15);
Dog dog3=new Dog("ah",13);
Dog dog4=new Dog("ah",13);

List list=new ArrayList();
list.add(dog2);
list.add(dog1);
list.add(dog2);
list.add(null);
for (Object o :list) {
//可以存储,但是不可以遍历
System.out.println(o.toString());
}



}
}
class Dog{
private String name;
private int age;

public Dog(String name, int age) {
this.name = name;
this.age = age;
}

@Override
public String toString() {
return "Dog{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}

image-20220615102549866

ArrayList的底层结构和源码分析

无参构造器的扩容

首先我们运行以下代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;

public class Test {
public static void main(String [] args){
//先调用ArrayList的无参构造其
ArrayList arrayList=new ArrayList();
//第一个for不扩容,<=10
for (int i=0;i<=10;i++){
arrayList.add(i);
}
//第二个for扩容,已经大于默认的10
for (int i=11;i<15;i++){
arrayList.add(i);
}


}
}

但我们调用无参构造器时,调用了以下方法,并且定义的类型为Object[]数组类型,我们可以确认ArrayList的底层使用的是数组存储

image-20220615102633892

image-20220615102641148

我们可以看到在运行到add方法时,进入到了一个boolean的方法,此方法先决定是否要进行扩容,而add方法的第一行的函数如下一张图

image-20220615102658151

首先判断该存储的数组是否为空,如果为空,则进行比较,并且选取两个数的一个最大数作为初始集合的大小,应该为10。而该方法的最后一行的代码,则是确定是否还进行底层扩容,大于minCapacity则进行扩容。

image-20220615102758224

当我们决定扩容时,则调用下面的函数,扩容为原来的1.5倍,而copyof方法会保持地址不变,直接增加数。

image-20220615102827255

当我们运行之后

image-20220615102840971

15个空间不够时,我们许需要扩容,扩容之后

image-20220615102850520

其实在这个过程中进行扩容这么大,是因为在这个arraylist添加和删除的过程中,成本比较大,每一次添加个删除都要不可避免的移动元素,保证空间的连续性,每一次大小变为原来的两倍,避免不得不再一次改变容量

有参构造器

有参构造器,我们可以给他附上初始值,而每一次扩容依然是原来的1.5倍,运行的原理和上面的一样,只是初始值为我们赋值的那个数,而不是10.

System常见的方法和案例解析

  1. 退出当前程序EXIT,0表示正常状态退出
  2. 获取当前的时间
  3. 拷贝,数组拷贝底层用此代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package Learn;

import java.util.Arrays;

public class Test {
public static void main(String[] args) {
/**
*
src – the source array.原数组
srcPos – starting position in the source array.在原数组的开始位置
dest – the destination array.目标数组
destPos – starting position in the destination data.在目标数组的开始位置
length – the number of array elements to be copied从原数组拷贝多少个数
*/
int a[] = {1, 2};
int b[] = new int[10];
System.arraycopy(b, 0, a, 0, 2);
System.out.println(Arrays.toString(b));
//获取当前时间到1970.1.1的时间,毫秒为单位
//the difference, measured in milliseconds, between the current time and midnight, January 1, 1970 UTC.
long time=System.currentTimeMillis();
System.out.println(time);
System.exit(0);
}
}


image-20220302160950870

针对8中基本数据类型相应的引用类型——包装类,有了类的特点,就可以调用类中的方法是

基本数据类型 包装类
boolean Boolean
char Character
byte Byte
short Short
int Interger
long Long
float Float
double Double
  • 案例展示

int与Interger之间的转换,jdk5之前采用手动装箱与拆箱,其中装箱:基本数据类型——>包装类型,相反的则为拆箱。而jdk5之后采用自动装箱与拆箱的方法。自动装箱底层掉哦用的valueof()方法,比如Interger.valueOf()。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
package Learn;
public class Test{
public static void main(String[] args) {
//手动装箱
int i=1000;
//Integer integer=new Integer(i);
//或者
Integer integer1=Integer.valueOf(i);


//手动拆箱
int g=integer1.intValue();

/*jdk5之后,就可以自动装箱和自动拆箱了,从本质上来说,其底层还是调用的valueOf()方法
这是jdk5之后的源码,仍旧可以方法返回了一个valueOf方法
*@IntrinsicCandidate
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
*
* */

Integer integer2=i;

//自动拆箱
int n1=integer2;
}

}
  • 练习

结果为1.0,其中三元运算符为一个整体,所以最终要进行类型提升,最终的输出类型为double类型。

1
2
3
4
5
6
7
package Learn;
public class Test{
public static void main(String[] args) {
Object obj=false;
System.out.println(obj.equals(false)?new Integer(1):new Double(1.2));
}
}

image-20220317190943341

  • 包装类型与String类型的转换
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package Learn;
public class Test{
public static void main(String[] args) {
//自动装箱
Integer i=1;
//第一种转换方式
String n1=i+"";
//第二种转换方法
String n2=i.toString();
//第三种方法,使用valueof方法,由于此方法需要传入一个对象,而我们包装之后便是存在一个对象
String n3=String.valueOf(i);

String n4="12345";
//String类型转换成int类型
//第一种public static int parseInt(String s) throws NumberFormatException {
// return parseInt(s,10);
// }
Integer n5=Integer.parseInt(n4);
//第二种,利用Integer自带的构造器
Integer n6=new Integer(n4);
}
}
  • 常用的方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package Learn;
public class Test{
public static void main(String[] args) {
Integer n1=100;
Integer n2=1000;
System.out.println(Integer.MAX_VALUE);
//输出Integer范围的最大值与最小值
System.out.println(Integer.MIN_VALUE);
//判断是不是字母,数字
System.out.println(Character.isDigit('a'));
System.out.println(Character.isLetter('a'));
System.out.println(Character.isUpperCase('a'));
System.out.println(Character.isLowerCase('a'));
//转换大小写
System.out.println(Character.toUpperCase('a'));
System.out.println(Character.toLowerCase('a'));
}
}
  • 练习
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package Learn;
public class Test{
public static void main(String[] args) {
Integer n1=new Integer(100);
Integer n2=new Integer(100);
//在这里将其封装new一个对象,但是n1与n2对象不相等,但是值相等,===比较的是对象,equal比较值
System.out.println(n1==n2);
System.out.println(n1.equals(n2));
/*在这里我们知道自动转换类型使用了valueof方法,在这里当我们传输的i对象在范围(-128-127)之间时,
我们返回的是数字,但是当不满足源码中的条件时,则返回一个new对象,这也就解释了下面两组数据同样的赋值方法,结果不同的原因
* public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}*/
Integer integer = 100;
Integer integer1 = 100;
System.out.println(integer==integer1);
System.out.println(integer.equals(integer1));

Integer integer3= 1000;
Integer integer4 = 1000;
System.out.println(integer3==integer4);
System.out.println(integer3.equals(integer4));

}
}

点击并拖拽以移动

但是注意只要存在基本数据类型,==就是判断的值是否相等,就不要去管对象的事情了。

第一代日期类

  • Date:精确到毫秒i,代表特定的瞬间

  • SimpleDateFormate:格式和解析日期的类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package Learn;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class Test {
public static void main(String[] args) throws ParseException {
Date date=new Date();
System.out.println(date);
//格式转换
SimpleDateFormat simpleDateFormat=new SimpleDateFormat("yyyy年MM月dd日 hh:mm:ss E");
String format=simpleDateFormat.format(date);
System.out.println(format);

String s="2022年03月02日 05:10:37 周三";
Date parse =simpleDateFormat.parse(s);
System.out.println(parse);
}
}


image-20220302171411298

第二代日期类

Calendar日历类,是一种抽象类,构造器私有化,通过getInstance得到实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package Learn;

import java.text.ParseException;
import java.util.Calendar;

public class Test {
public static void main(String[] args) throws ParseException {
Calendar calendar =Calendar.getInstance();
System.out.println(calendar.get(Calendar.YEAR));
//月份从0开始,所以我们要+1
System.out.println(calendar.get(Calendar.MONTH)+1);
System.out.println(calendar.get(Calendar.DAY_OF_MONTH));
//输出24进制的时间
System.out.println(calendar.get(Calendar.HOUR_OF_DAY));

}
}


image-20220302172357501

第三代日期类

jdk8之后存在

  • LocalDate(只有年月日)
  • LocalTime(只有时间)
  • LocalDateTime(日期+时间)
  • DateTimeFormat格式化日期类
  • Instant 时间戳
  • 除了上述之外还增加了是否闰年,增加时间等等方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package Learn;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;

public class Test {
public static void main(String[] args) {
System.out.println(LocalDate.now());
System.out.println(LocalTime.now());
System.out.println(LocalDateTime.now());
//英文月
System.out.println(LocalDateTime.now().getMonth());
//数字日
System.out.println(LocalDateTime.now().getMonthValue());
DateTimeFormatter dateTimeFormatter=DateTimeFormatter.ofPattern("yyyy年MM月dd日 hh:mm:ss");
System.out.println(dateTimeFormatter.format(LocalDateTime.now()));
//与第一代日期类的转换
Instant instant=Instant.now();
System.out.println(instant);
Date date=Date.from(instant);
System.out.println(date);
//转换回来
instant =date.toInstant();
}
}


BigInteger和BigDecimal

  1. BigInteger适合保存比较大的整型(同时他的也就只能专用的加减乘除来操作,而且也是这个类型)
  2. BigDecimal适合保存精度更高的浮点型(小数)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package Learn;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Arrays;

public class Test {
public static void main(String[] args) {
BigInteger bigInteger=new BigInteger("654655646565154484846546546548");
BigInteger bigInteger1=new BigInteger("100");
System.out.println(bigInteger);
bigInteger1= bigInteger1.add(bigInteger);
System.out.println(bigInteger1);

BigDecimal bigDecimal=new BigDecimal("1.256465156165484986465165");
BigDecimal bigDecimal1=new BigDecimal("1.2564651561654849");
System.out.println(bigDecimal);
bigDecimal= bigDecimal.add(bigDecimal1);
System.out.println(bigDecimal);
}
}


image-20220420161941537

应用

在实际应用中double类型进行相加减,会存在精度的问题,比如image-20220420162048073

此时我们就需要运行BigDecimal来进行运算

1
2
3
4
5
6
7
8
9
private Double xj;

public Double getXj() {
BigDecimal bigDecimalPrice=new BigDecimal(""+getBook().getPrice());
BigDecimal bigDecimalBuyCount=new BigDecimal(""+getBuyCount());
BigDecimal bigDecimalxj=bigDecimalPrice.multiply(bigDecimalBuyCount);
xj=bigDecimalxj.doubleValue();
return xj;
}

image-20220420163718264

Arrays常见方法案例与解析

  • toString返回数组的字符串形式

toString源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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(", ");
}
}

使用tostring与不使用的区别

1
2
3
4
5
6
7
8
9
10
11
package Learn;

import java.util.Arrays;

public class Test {
public static void main(String[] args) {
int []array={1,2,3,4,5};
System.out.println(array);
System.out.println(Arrays.toString(array));
}
}

image-20220302141507939

  • sort排序

首先我们排序的对象为数组,数组在堆中存储,我们排序之后就会影响到其中的实参,位置不变,储存的顺序改变

1
2
3
4
5
6
7
8
9
10
11
12
13
package Learn;

import java.util.Arrays;

public class Test {
public static void main(String[] args) {
int []array={1,2,3,5,6,9,2,5};
System.out.println(array);
Arrays.sort(array);
System.out.println(Arrays.toString(array));
System.out.println(array);
}
}

image-20220302142406501

sort方法是重载的,也可以传入一个接口Comparadetor,要求实现compare方法,从而改变排序的规则,在这里debug中,我们可以发现其中会进入到二分排序方法中(如下),而二分排序中0与1会影响到最终的排序结果。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
private static <T> void binarySort(T[] a, int lo, int hi, int start,
Comparator<? super T> c) {
assert lo <= start && start <= hi;
if (start == lo)
start++;
for ( ; start < hi; start++) {
T pivot = a[start];

// Set left (and right) to the index where a[start] (pivot) belongs
int left = lo;
int right = start;
assert left <= right;
/*
* Invariants:
* pivot >= all in [lo, left).
* pivot < all in [right, start).
*/
while (left < right) {
int mid = (left + right) >>> 1;
if (c.compare(pivot, a[mid]) < 0)
right = mid;
else
left = mid + 1;
}
assert left == right;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package Learn;

import java.util.Arrays;
import java.util.Comparator;

public class Test {
public static void main(String[] args) {
Integer []array={5,2,3,5,6,9,2,5};
//将匿名类当作参数传入
Arrays.sort(array, new Comparator() {
@Override
public int compare(Object o1, Object o2) {
Integer n1=(Integer) o1;
Integer n2=(Integer) o2;
//该处返回的结果会影响排序的结果
return n2-n1;
}

});
System.out.println(Arrays.toString(array));
}
}


image-20220302145033780

  • 二分搜索查找

通过二分搜索查找,要求必须排好序(而且是正序),如果没有找到,则返回-(low+1),low表示查找的目标应该在的位置。注意有时候二分查找法不一定找出第一个数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package Learn;

import java.util.Arrays;
import java.util.Comparator;

public class Test {
public static void main(String[] args) {
Integer []array={5,2,3,5,6,9,2,5};
Arrays.sort(array);
System.out.println(Arrays.toString(array));
System.out.println(Arrays.binarySearch(array,2));
System.out.println(Arrays.binarySearch(array,7));
}
}

image-20220302151329506

  • 数组元素的赋值copyOf

当范围不超出时,进行正常的赋值,当大于时,则用null来代替

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package Learn;

import java.util.Arrays;

public class Test {
public static void main(String[] args) {
Integer []array={5,2,3,5,6,9,2,5};
Integer []array2=Arrays.copyOf(array,5);
System.out.println(Arrays.toString(array2));

Integer []array3=Arrays.copyOf(array,11);
System.out.println(Arrays.toString(array));
System.out.println(Arrays.toString(array3));
}
}


image-20220302152027875

  • 数组填充

1
2
3
4
5
6
7
8
9
10
11
package Learn;

import java.util.Arrays;

public class Test {
public static void main(String[] args) {
Integer []array={5,2,3,5,6,9,2,5};
Arrays.fill(array,99);
System.out.println(Arrays.toString(array));
}
}

image-20220302152219943

  • 比较两个数组是否相等

也是包含顺序的

1
2
3
4
5
6
7
8
9
10
11
package Learn;

public class Test {
public static void main(String[] args) {
Integer []array={5,2,3,5,6,9,2,5};
Integer []array1={5,2,3,5,6,9,5,2};
System.out.println(array.equals(array1));
}
}


image-20220302152502110

  • 将一组数据转换成list集合

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package Learn;

import java.util.Arrays;
import java.util.List;

public class Test {
public static void main(String[] args) {
Integer []array={5,2,3,5,6,9,2,5};
List list= Arrays.asList(array);
System.out.println(list);
//他的运行类型为
System.out.println(list.getClass());
}
}


image-20220302153007270

练习:按照书的价格大小顺序输出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
package Learn;

import java.util.Arrays;
import java.util.Comparator;

public class Exercise {
public static void main(String[] args) {
Book []books=new Book[4];
books[0]=new Book("ho",45);
books[1]=new Book("h7",450);
books[2]=new Book("h4737",272);
books[3]=new Book("737",753);
Arrays.sort(books, new Comparator() {
@Override
public int compare(Object o1, Object o2) {
Book book1=(Book) o1;
Book book2=(Book) o2;
return book1.price-book2.price;
}
});
for (int i=0;i< books.length;i++){
System.out.println(books[i].name+books[i].price);
}
System.out.println(Arrays.toString(books));
}
}
class Book{
String name;
int price;
public Book(String name,int price){
this.name=name;
this.price=price;
}

@Override
public String toString() {
return "Book{" +
"name='" + name + '\'' +
", price=" + price +
'}';
}
}

image-20220302155533439

Java中Type

Type时Java语言中所有类型的公共高级接口,也就是Java中所有类型的“爹”;其中所有的类型并不是我们经常使用的int,String等类型,而是对基本数据类型,引用类型向上的抽象。

Type体系中的类型包括:原始类型(Class)、参数化类型(ParameterizedType)、数组类型(GenericArrayType)、类型变量(TypeVariable)、基本类型(Class);

原始类型,不仅仅包含我们平常所指的类,还包括枚举、数组、注解等;

参数化类型,就是我们平常所用到的泛型List、Map;

数组类型,并不是我们工作中所使用的数组String[] 、byte[],而是带有泛型的数组,即T[] ;

基本类型,也就是我们所说的java的基本类型,即int,float,double等

image-20220402174243766

ParameterizedType

image-20220402205408958

分别为获得实际的类型,获得前面的类型,这个类型是否某个类型所属,获得这个所有者的类型,否则返回null

参数泛型化,即泛型;例如List等带有参数化的对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package com.zss.test;

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Set;

/**
* @author zss
*/
public class Test<T> implements Type {
private List<T> list=null;
private Set<T> set=null;
public static void main(String[] args) throws NoSuchFieldException {
Field field= Test.class.getDeclaredField("list");
//获取该属性的泛型类型
Type typeList= field.getGenericType();
System.out.println(typeList.getClass().getName());

Field field1=Test.class.getDeclaredField("set");
Type typeSet=field1.getGenericType();
System.out.println(typeSet.getClass().getName());
}

}

image-20220402175104947

getActualTypeArguments

当我们包含有多个泛型的时候,会返回一个数组用来保存这些数组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class Test<T> implements Type {
private Map<String,Integer> map=null;
public static void main(String[] args) throws NoSuchFieldException {

Field fieldMap=Test.class.getDeclaredField("map");

Type typeMap= fieldMap.getGenericType();
ParameterizedType parameterizedType=(ParameterizedType) typeMap;

Type []types= parameterizedType.getActualTypeArguments();
System.out.println(types[0].getClass().getName());
System.out.println(types[1]);

}

}

image-20220402202515214

getRawType

获取声明泛型或者接口,就是泛型中<>前面的值

1
2
Type types= parameterizedType.getRawType();
System.out.println(types);

image-20220402202731695

getOwnerType

获得内部类的拥有者

1
2
3
4
5
6
7
8
9
10
11
12
13
public class Test<T> implements Type {
private Map.Entry<String,Integer> map=null;
public static void main(String[] args) throws NoSuchFieldException {
Field fieldMap=Test.class.getDeclaredField("map");
Type typeMap= fieldMap.getGenericType();
ParameterizedType parameterizedType=(ParameterizedType) typeMap;
Type types= parameterizedType.getOwnerType();
System.out.println(types);


}

}

image-20220402203021430

GenericArrayType

泛型数组类型List[]等

1
2
3
4
5
6
7
8
9
10
11
12
public class Test<T> implements Type {
private Map<String,Integer> []map=null;
public static void main(String[] args) throws NoSuchFieldException {
Field fieldMap=Test.class.getDeclaredField("map");
Type typeMap= fieldMap.getGenericType();

System.out.println(typeMap);


}

}

image-20220402203344305

getGenericComponentType

返回数组中元素的Type类型,即去除数组之后的

1
2
3
4
5
6
7
8
9
public class Test<T> implements Type {
private Map<String,Integer> []map=null;
public static void main(String[] args) throws NoSuchFieldException {
Field fieldMap=Test.class.getDeclaredField("map");
Type typeMap= fieldMap.getGenericType();
GenericArrayType genericArrayType=(GenericArrayType) typeMap;
System.out.println(genericArrayType);
}
}

image-20220402203711073

TypeVariable

指List等值的概念

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Test<T> implements Type {
private List<String> list=null;
public static void main(String[] args) throws NoSuchFieldException {
Field fieldMap=Test.class.getDeclaredField("list");
Type type=fieldMap.getGenericType();
System.out.println(type);

ParameterizedType parameterizedType=(ParameterizedType) type;
System.out.println(parameterizedType);

Type[] types=parameterizedType.getActualTypeArguments();
System.out.println(types[0].getClass().getName());
}
}

当然还有别的方法进行调整

在TypeVariable接口中,有3个方法,分别为getBounds()、getGenericDeclaration()、getName();

Class

Type接口的实现类,是我们工作中常用到的一个对象;在Java中,每个.class文件在程序运行期间,都对应着一个Class对象,这个对象保存有这个类的全部信息;因此,Class对象也称之为Java反射的基础;

1
2
3
4
5
6
7
8
public class Test<T> implements Type {
private List<String> list=null;
public static void main(String[] args) throws NoSuchFieldException {
Field field=Test.class.getDeclaredField("list");
Type type=field.getGenericType();
System.out.println(type);
}
}

image-20220402205125524

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
package com.zss.test;

import java.lang.reflect.*;

class Person<T,W>{

}

public class Test extends Person<Integer, Boolean> {

@SuppressWarnings("rawtypes")
public static void main(String[] args) {

Test student = new Test();
Class clazz = student.getClass();
System.out.println(clazz);
System.out.println("获取父类对象:" + clazz.getSuperclass());
/**
* getGenericSuperclass()获得带有泛型的父类
* Type是 Java 编程语言中所有类型的公共高级接口。它们包括原始类型、参数化类型、数组类型、类型变量和基本类型。
*/
Type type = clazz.getGenericSuperclass();
System.out.println(type);

//ParameterizedType参数化类型,即泛型
ParameterizedType p = (ParameterizedType)type;
//getActualTypeArguments获取参数化类型的数组,泛型可能有多个
Class c1 = (Class)p.getActualTypeArguments()[0];
System.out.println(c1);
Class c2 = (Class)p.getActualTypeArguments()[1];
System.out.println(c2);
}



}

/**
* 运行结果:
* 获取父类对象:class com.mycode.test.Person
* com.mycode.test.Person<java.lang.Integer, java.lang.Boolean>
* class java.lang.Integer
* class java.lang.Boolean
*/

image-20220402210538555

我们现在需要一个枚举出四季以及他们各自的特点,四季只有春夏秋冬这四个季节,而且特点固定,所以我们不需要用户去创建新的季节对象。

自定义枚举

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package Learn;
public class Test {
public static void main(String[] args) {
System.out.println(Season.SPRING.toString());
System.out.println(Season.SUMMER.toString());
System.out.println(Season.AUTUMN.toString());
System.out.println(Season.WINTER.toString());
}
}
class Season{
private String season, characteristic;
/**将构造其私有化,防止在main方法中直接new对象*/
private Season(String season,String characteristic){
this.season=season;
this.characteristic=characteristic;
}
/**定义四个季节的特点,使用static使得在main方法中不用创建实例对象,但是会造成类的加载,所以再加上final变成常量值,避免了类的加载*/
public static final Season SPRING =new Season("春天","温暖");
public static final Season SUMMER =new Season("夏天","炎热");
public static final Season AUTUMN =new Season("秋天","凉爽");
public static final Season WINTER =new Season("冬天","寒冷");

@Override
public String toString(){
return season+characteristic;
}

}

image-20220322084509210

  1. 不需要提供set方法,因为枚举对象值通常为只读。
  2. 对枚举对象属性使用final+static共同修饰,实现底层优化
  3. 枚举对象属于常量,通常全部大写

enum关键字枚举

将定义的常量对象定义在最前面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package Learn;
public class Test {
public static void main(String[] args) {
System.out.println(Season.SPRING.toString());
System.out.println(Season.SUMMER.toString());
System.out.println(Season.AUTUMN.toString());
System.out.println(Season.WINTER.toString());
}
}
enum Season{
SPRING("春天","温暖"),
SUMMER ("夏天","炎热"),
AUTUMN ("秋天","凉爽"),
WINTER ("冬天","寒冷");
private String season, characteristic;
/**将构造其私有化,防止在main方法中直接new对象*/
private Season(String season,String characteristic){
this.season=season;
this.characteristic=characteristic;
}


@Override
public String toString(){
return season+characteristic;
}

}

image-20220322084543249

注意事项:

  • 当我们使用enum关键字时,默认会继承enum类,我们反编译一下文件,可以发现同时也是final类型点击并拖拽以移动image-20220322084630144

  • 如果使用无参构造器,则实参列表与小括号都可以省略。例如下面的OTHER

image-20220322084718169

  • img点击并拖拽以移动这个也是正确的,默认调用的无参构造器。

枚举中常用的方法

上面我们说到,enum其实是继承了ENUM类的,所以也会继承其方法

方法名 作用
name 输出对象的名字
ordinal 输出该对象在枚举中的位置(从0开始)
hascode 输出对应的对象地址编号
value 将枚举填入数组中
valueof 到对应的对象中去寻找,如果找到了,返回该对象,否则为false
compareTo 比较两个对象的枚举编号,是他们顺序号的差值,可以crtl+B查看源码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
package Learn;
public class Test {
public static void main(String[] args) {
System.out.println(Season.SPRING.toString());
System.out.println(Season.SUMMER.toString());
System.out.println(Season.AUTUMN.toString());
System.out.println(Season.WINTER.toString());
System.out.println(Season.SPRING.name());
System.out.println(Season.SPRING.hashCode());
//输出相应的编号,编号从0开始
System.out.println(Season.SPRING.ordinal());
Season []values=Season.values();
for (Season A :values){
System.out.println(A);
}
System.out.println(Season.valueOf("SPRING"));
//System.out.println(Season.valueOf("dj"));
System.out.println(Season.SPRING.compareTo(Season.AUTUMN));

}
}
enum Season{
SPRING("春天","温暖"),
SUMMER ("夏天","炎热"),
AUTUMN ("秋天","凉爽"),
WINTER ("冬天","寒冷"),
OTHER;
private String season, characteristic;
/**将构造其私有化,防止在main方法中直接new对象*/
private Season(){}
private Season(String season,String characteristic){
this.season=season;
this.characteristic=characteristic;
}


@Override
public String toString(){
return season+characteristic;
}

}

image-20220322084756180

练习:输出每一周的星期

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package Learn;

public class Exercise {
public static void main(String[] args) {
Week [] weeks= Week.values();
for (Week week :weeks){
System.out.println(week.toString());
}

}
}
enum Week{
Monday("星期一"),
Tuesday("星期二"),
Wednesday("星期三"),
Thursday("星期四"),
Friday("星期五"),
Saturday("星期六"),
Sunday("星期日");

private String week;
Week(String week){
this.week=week;
}

@Override
public String toString() {
return week ;
}
}

image-20220322084840211

注意:

如果我们使用enum关键字之后,就不可以继承其他类了,Java是单继承机制。但是实质上enum还是一个类,所以可以继承实现接口。