2000字范文,分享全网优秀范文,学习好帮手!
2000字范文 > JAVA基础03-Object类 常用类 基本的数据结构 Collection常用体系 泛型-泛型通配符

JAVA基础03-Object类 常用类 基本的数据结构 Collection常用体系 泛型-泛型通配符

时间:2022-09-02 19:50:14

相关推荐

JAVA基础03-Object类 常用类 基本的数据结构  Collection常用体系 泛型-泛型通配符

1.object类

1.概述

java.lang.object类是java语言中的根类,即所有类的超类(基类)他描述的所有的方法子类都可以使用,在对象实例化的时候最终找到的类就是object

如果一个类没有特别指定父类,那么默认则继承自object类例如

public class Test01 /*extends object*/ {}

object 类当中包含方法有11个

public String tostring(); 返回该对象的字符串表示public boolean equals(Object obj):指示其他某个实例,是否与此实例相等

2.toString方法

1.摘要

介绍:

toString方法返回该对象的字符串表示, 其实该字符串内容就是对象的类型+@+内存地址值.

由于toString方法返回的结果是内存地址, 我们经常按照对象的属性得到相应的字符串表现形式, 因此我们需要重写他.

2.覆盖重写

如果不希望使用toString方法的默认行为则可以对它进行重写 , 例:

public class Person {String name;int age;@Overridepublic String toString() {return "Person{" +"name='" + name + '\'' +", age=" + age +'}';}}

3.equals方法

1.摘要

equals() 方法, 判断其他某个对象是否和子对象相等.

调用成员方法equals并指定参数为另一个对象,则可以判断这两个对象是否是相同的

默认地址比较

如果没有覆盖重写equals 方法, 那么Object类中默认进行== 运算符的对象进行比较, 只要不是同一个对象结果必为false.

对象内容比较

如果希望进行对象的内容比较, 所有或者指定的部分成员变量相同就判定两个对象相同, 则可以重写equals方法

public class Person {String name;int age;@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;Person person = (Person) o;return age == person.age &&Objects.equals(name, person.name);}}

4.Object类

在jdk7 中添加了一个Object工具类, 他提供了一些方法来操作对象, 他由一些静态的实例方法组成, 这些方法是null-save(空指针安全的)或者null-tolerant(容忍空指针的),用于计算对象的hashcode,返回对象的字符串表示形式, 计较两个对象.

public static boolean equals(Object o , Object b ) 判断两个对象是否相等,

源码

public static boolean equals(Object a, Object b) {return (a == b) || (a != null && a.equals(b));}

2.常用类

1.System类

java.lang.System类中提供了大量的静态方法,可以获取与系统香瓜你的信息或系统级操作, 在System类的API文档中常用的方法有:

public static long currentTimeMillis():返回以毫秒为单位的当前时间.public static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length):将数组中指定的数据拷贝到另一个数组中

1.1,currentTimeMillis 方法

currentTimeMillis 方法就是获取当前系统时间与1970年01月01日00:00点之间的毫秒差值

public static void main(String[] args) {long l = System.currentTimeMillis();for (int i = 0; i < 10000; i++) {System.out.println(i);}long l1 = System.currentTimeMillis();System.out.println("耗时:"+(l1-l)); //耗时:256 毫秒}

1.2.arraycopy方法

将数组中的指定数据拷贝到另一个数组中,

数组的拷贝动作是系统级的, 性能很高,其中有五个参数:

参数名称 参数类型 参数含义

src Object 原数组

srcPos int 原数组索引其起始位置

dest Object 目标数组

destPos int 目标数组索引起始位置

length int 复制元素的个数

public static void main(String[] args) {int[] arr01 = {1,2,3,4,5};int[] arr02 = {6,7,8,9,10};System.arraycopy(arr01,0,arr02,0,2);//将arr01的索引为0出开始拷贝到arr02从索引为0出粘贴, 拷贝出的数量为2System.out.println(Arrays.toString(arr02));//[1, 2, 8, 9, 10]}

2.StringBuilder类

2.1 字符串拼接问题

由于strign类的对象内容是不可变的,所以每当进行字符串拼接时,总是会在内存中创建一个新的对象:例如

public static void main(String[] args) {String str01 = "Hello";System.out.println(str01.hashCode());//69609650str01 += "world";System.out.println(str01.hashCode());//468881952System.out.println(str01);//Helloworld}

在api中对string类的描述是:java中所有的自付出那蚊子(例如:“abc”)都被时限为此实例.字符后才能不变,他们的值在创建后不能被更改,字符串缓冲区支持可变字符串, 因为String对象是不可能变得 ,他们可以被共享.

上面代码可以用下图表示:

由图片可知, 如果对字符串进行拼接操作,每次拼接都会在内存中开辟空间,创建一个新的string对象, 既耗时又消耗空间,为了解决这种问题, 可以使用java.lang.StringBuilder类

2.2 StringBuilder

javaAPI:StringBulider又称为可变字符序列, 他是一个类似String的字符串缓冲区, 通过某些方法调用可以改变该序列的长度和内容,

StringBuilder相当于一个容器, 可以装很多的字符串, 并且能够对字符串进行相应的操作,它的内部拥有一个数组来存放字符字符串内容, 进行字符串拼接时, 直接在数组中插入新的内容,StringBuilder会自动维护数组的扩容,

2.2.1构造方法

常用的构造方法有两个:

public StringBuilder():构造一个空的StirngBuilder容器.public StringBulider(String str):构造一个空的StirngBuilder容器,并将字符串添加进去

2.2.2 常用方法

StringBuilder常用方法有两个:

public StringBuilder append():添加任意类型数据的字符串形式,并返回当前对象自身.

public StringBulider toString(): 将当前StringBuilder 对象转换为String对象.

public static void main(String[] args) {

//创建对象

StringBuilder stringBuilder = new StringBuilder();

//添加任意类型数据

stringBuilder.append(“hello”);

System.out.println(stringBuilder.hashCode());//1163157884

stringBuilder.append(“world”);

System.out.println(stringBuilder.hashCode());//1163157884

stringBuilder.append(1);

stringBuilder.append(true);

stringBuilder.append(1.1f);

System.out.println(stringBuilder.toString());

//上面写法可以写成

System.out.println(stringBuilder.append(“hello”).append(“world”).append(1).append(true).append(1.1f).toString());

}

3.包装类

3.1 概述

java的数据类型基本有两种, 基本类型与引用类型, 基本类型的话效率比较高 , 但是我们一般会使用引用类型, 这样我们创建对象可以进行更多的操作, 我们也可以把基本类型转换成引用类型, 就可以使用基本类型的包装类;

基本类型 对应包装类 java.lang包中

byte Byte

short Short

int Integer

long Long

float Float

double Double

char Character

boolean Boolean

3.2 拆箱与装箱

基本类型与引用类型之间转换的过程,我们称之为"装箱"与"拆箱"

装箱 :从基本类型转换为引用类型拆箱 :从引用类型转换为基本类型.

基本类型->包装类;

Integer i = new Integer(4);//使用构造器方法Integer i1 = Integer.valueOf(4);//使用包装类的valueOf() 方法

包装类->基本类型

int i2 = i.intvalue();

因为我们平时经常基本类型与包装类之间转换 ,从 jkd1.5开始, 基本类型与包装类之间不用手动进行拆装箱, 可以自动完成

Integer i = 8 ;int a = i + 8;

4.基本类型与字符转之间的转换

4.1 基本类型转换为引用类型;

有三种方式:

基本类型直接+"" 例如: 3+"";调用类的串转换方法:X.toString();使用String的方法:String.valueOf(X);

4.2 String 类型转换为基本类型

除了Character 类之外, 其他所有的包装类都具有parseXxx 静态方法可以将字符串转换为基本数据类型;

public static byte parseByte(String s ) :将字符串转换为对应的byte类型public static short parseShort(String s ):将字符串转换为对应的 shord 类型public static int parseInt(String s ):将字符串转换为对应的int 类型public static long parseLong(String s ):将字符串转换为对应的 long 类型public static float parseFloat(Stirng s):将字符串转换为对应的 float 类型public static double parseDouble (String s);将字符串转换为对应的 double 类型public static boolean parseDoolean (String s ):将字符串转换为对应的 boolean 类型

//举个例子:

public static void main(String[] args) {

String s = “true00000”;

boolean b = Boolean.parseBoolean(s);

System.out.println(b);//false

if (b) {

System.out.println(“222”);

}

String s1 = “12324”;

int i = Integer.parseInt(s1);

System.out.println(i);//12324

}

如果无法正确转换 会抛出

java.lang.NumberFormatException.异常

5.日期时间类

5.1 Date类

5.1.1 概述

java.util.Date 类 表示指定的瞬间,精确到毫秒

jdk文档 介绍:一个大约一毫秒值的薄包装,允许JDBC将其标识为SQL DATE值。 毫秒值表示1970年1月1日00:00:00.000 GMT之后的毫秒数。

为了符合SQL DATE ,由java.sql.Date实例包装的毫秒值必须通过在实例关联的特定时区中将小时,分钟,秒和毫秒设置为零来“归一化”。

构造方法 : 例

Date(int year, int month, int day) 已弃用 而是使用构造Date(long date)

Date(long date) 使用给定的毫秒时间值构造一个 Date对象。

Date 拥有多个构造方法, 只是大部分已经过时, 但是其中有未过时的函数可以吧毫秒值转换成日期

public Date():分配Date对象并初始化此对象, 以表示分配他的时间(精确到毫秒)public Date(long date):分配Date对象并初始化此对象, 以表示自从标准时间(成为"历元(epoch)", 即使1970年01月01日00:00:00 GMT) 以来的毫秒数.

tips: 由于中国处于东八区(GMT+08:00)是比世界协调时间/格林尼治时间(GMT)快8小时的时区,当格林尼治标准时间为0:00时,东八区的标准时间为08:00。

使用无参构造器,可以自动设置当前系统时间的毫秒时刻; 指定long类型的构造参数, 可以定义毫秒时刻,例如:

public static void main(String[] args) {System.out.println(new Date());//Mon Jun 29 16:06:19 CST System.out.println(new Date(0L));//Thu Jan 01 08:00:00 CST 1970 }//在使用println方法时,会自动调用Date类中的toString方法。Date类对Object类中的toString方法进行//了覆盖重写,所以结果为指定格式的字符串。

5.1.2 常用方法

Date类中有很多方法已经过时, 常用的方法有:

public long getTime(): 把日期对象转换成对象的时间毫秒值

5.2 DateFormat类

java.text.DateFormat: 是日期/时间格式化子类的抽象类,我们通过这个类可以帮我们完成日期和文本之间的转换,也就是可以在Date对象与String对象之间进行来回转换。

格式化: 按照指定的格式, 从Date对象转换为String对象.解析: 按照指定的格式,从String 转换成Date对象.

5.2.1 构造方法

由于DataFormat 为抽象类 , 不能被实例化, 所以我们经常使用他的子类,java.text.SimpleDateFormat:这个类需要一个格式来指定格式化或解析的标准, 构造方法为:

public SimpleDateFormat(String pattern):用于给定的模式和默认语言环境的日期格式符号构造SimpleDateFormat.参数patterm 是一个字符串, 代表日期时间的定义格式;

5.2.2 格式规则

表示字母(区分大小写) 含义 例子

Y

y 年 1997;07

M 月 7月;8月

m 分

D

d 日

H 时

h

S

s 秒

W

w

K

k

Z

z

F

E

G 文本 AD

X

L

a

u

具体介绍参考JDK文档

5.2.3 常用方法

DateFormat类的常用方法有:

public String format(Date date):将Date对象格式化为字符串;

public Date parse(String source):将字符串转换为Date 对象;

public static void main(String[] args) throws ParseException {

//将当前日期转换为字符串

SimpleDateFormat sl = new SimpleDateFormat(“yyyy-MM-dd”);

String format = sl.format(new Date());

System.out.println(format);

//将当前时间转换为日期类型

SimpleDateFormat sl1 = new SimpleDateFormat(“yyyyMMddhhmmss");

Date parse = sl1.parse("19971130231032”);

//将日期类型转化为Stirng

String format1 = sl1.format(parse);

System.out.println(format1);

}

5.3Calender类

5.3.1概念

java.util.Calendar 是日历类, 在Date之后出现, 替换掉许多Date的方法, 该类将所有可能用到的时间信息封装为静态成员变量,日历类就是方便获取各个时间属性的.

5.3.2 获取方式

Calendar 为抽象类, 不能直接创建, 而是通过静态方法创建,返回子类对象

Calendar 静态方法

public static Calendar getInstance():使用默认失去和语言环境获得一个日历

Calendar calendar = Calendar.getInstance();

5.3.3 常用方法

常用的方法有:

public int get(int field):返回给定日期字段的值;public void set (int field , int value):将制定的日期字段设置为给定值.public abstract void add(int field , int amount):根据日历的规则, 为给定的日历字段添加或减去指定的时间量.public Date getTime():返回一个标识此Calendar 时间值(从历元到现在的毫秒的偏移量)的Date对象.

Calendar类中提供很多成员常量, 代表给定的日期字段:

常用:

字段值 含义

YEAR 年

MONTH 月(从0开始,可以+1使用)

DAY_OF_MONTH 用中的第几天(几号)

HOUR 时(12小时)

HOUR_OF_DAY 时(24小时)

MINUTE 分

SECOND 秒

DAY_OF_WEEK 周中的天(周几,周日为1, 可以用-1使用)

JDK提供:

Modifier and Type Field and Description

static int ALL_STYLES getDisplayNames的样式说明符, 表示所有样式的名称,如“1月”和“1月”。

static int AM AM_PM字段的值表示从午夜到中午之前的一天中的一段时间。

static int AM_PM 对于现场数 get和 set指示是否 HOUR是前或中午之后。

static int APRIL MONTH字段的价值 指示了格里高利和朱利安日历中的第四个月。

protected boolean areFieldsSet 如果 fields[]与当前设置的时间同步,则为真。

static int AUGUST MONTH领域的价值 指示了公历和朱利安日历中的第八个月。

static int DATE get和 set字段编号表示该月的日期。

static int DAY_OF_MONTH get字段编号和 set本月的日期。

static int DAY_OF_WEEK get字段编号和 set表示一周中的日期。

static int DAY_OF_WEEK_IN_MONTH get字段编号和 set当月的 set几的序号。

static int DAY_OF_YEAR get和 set字段编号, set本年度的日数。

static int DECEMBER MONTH字段的值表示公历和朱利安日历中的第十二个月。

static int DST_OFFSET get和 set字段编号 get夏令时偏移量(以毫秒为单位)。

static int ERA get和 set字段号表示时代,例如在儒略历中的AD或BC。

static int FEBRUARY MONTH字段的价值表示今年第二个月在公历和朱利安日历。

static int FIELD_COUNT get和 set的不同字段的数量。

protected int[] fields 该日历的当前设置时间的日历字段值。

static int FRIDAY DAY_OF_WEEK字段的值表示周五。

static int HOUR get和 set字段编号, get上午或下午的小时。

static int HOUR_OF_DAY get字段编号和 set当天的小时数。

protected boolean[] isSet 说明是否设置日历的指定日历字段的标志。

protected boolean isTimeSet 如果那么那么 time的值是有效的。

static int JANUARY MONTH字段的价值表示今年首次在公历和朱利安日历。

static int JULY MONTH字段的值代表了 公历和朱利安日历中的第七个月。

static int JUNE MONTH字段的价值 指示了公历和朱利安日历中的第六个月。

static int LONG getDisplayName和 getDisplayNames相当于 LONG_FORMAT的样式说明 符 。

static int LONG_FORMAT getDisplayName和 getDisplayNames的样式说明 符 , 表示用于格式的长名称。

static int LONG_STANDALONE 一个 getDisplayName和 getDisplayNames的样式说明 符 , 表示一个独立使用的长名称,例如月份名称作为日历头。

static int MARCH MONTH字段的值代表了 公历和朱利安日历中的第三个月。

static int MAY MONTH领域的价值 指示了公历和朱利安日历中的第五个月。

static int MILLISECOND get和 set字段号表示 get内的 set数。

static int MINUTE get和 set字段编号表示小时内的分钟。

static int MONDAY DAY_OF_WEEK字段的值表示星期一。

static int MONTH get和 set字段号表示月份。

static int NARROW_FORMAT getDisplayName和 getDisplayNames的样式说明 符 , 表示用于格式的窄名称。

static int NARROW_STANDALONE getDisplayName和 getDisplayNames的样式说明 符 独立地表示一个狭义的名称。

static int NOVEMBER MONTH领域的价值 指示了公历和朱利安日历中的第十一个月。

static int OCTOBER MONTH字段的价值表示在公历和朱利安日历中的一年中的第十个月。

static int PM AM_PM字段的值表示从中午到午夜之前的一天中的一段时间。

static int SATURDAY DAY_OF_WEEK字段的值表示星期六。

static int SECOND get和 set字段编号表示分钟内的第二个。

static int SEPTEMBER MONTH字段的值代表了 公历和朱利安日历中的第九个月。

static int SHORT getDisplayName和 getDisplayNames的样式说明 符 , 相当于 SHORT_FORMAT 。

static int SHORT_FORMAT getDisplayName和 getDisplayNames的样式说明 符 , 表示用于格式的短名称。

static int SHORT_STANDALONE 一个用于 getDisplayName和 getDisplayNames的样式说明 符 , 表示一个简单的名称,例如一个月缩写作为日历头。

static int SUNDAY DAY_OF_WEEK字段的值表示星期天。

static int THURSDAY DAY_OF_WEEK字段的值表示星期四。

protected long time 这个日历的当前设定时间,以1970年1月1日,格林尼治标准时间0:00:00之后的毫秒表示。

static int TUESDAY DAY_OF_WEEK字段的值表示周二。

static int UNDECIMBER MONTH字段的值表示一年的第十三个月。

static int WEDNESDAY DAY_OF_WEEK字段的值表示周三。

static int WEEK_OF_MONTH get和 set字段编号, set当月的周数。

static int WEEK_OF_YEAR get和 set字段编号, set本年度的周数。

static int YEAR get现场编号和 set表示年份。

static int ZONE_OFFSET get和 set字段编号, get GMT以毫秒为 get的原始偏移量。

public static void main(String[] args) {//获取Calendar对象Calendar cal = Calendar.getInstance();//获取年int i = cal.get(Calendar.YEAR);System.out.println(i);////设置年cal.set(Calendar.YEAR,);int i1 = cal.get(Calendar.YEAR);System.out.println(i1);////将年份修改为cal.add(Calendar.YEAR,-20);int i2 = cal.get(Calendar.YEAR);System.out.println(i2);//SimpleDateFormat sl = new SimpleDateFormat("yyyy-MM-dd");String format = sl.format(cal.getTime());System.out.println(format);//-06-29}

西方星期的开始为周日,中国为周一。

在Calendar类中,月份的表示是以0-11代表1-12月。

日期是有大小关系的,时间靠后,时间越大。

6.BigDecimal类

6.1BigDecimal 类概述

java.math.BigDecimal类: 他可以标识一个不可变的, 任意精度的有符号10进制数,同时他也提供了对这种数据运算的一些方法, 以及各种舍入模式, 它尤其可以避免基本数据类型进行浮点运算时损失精度的问题,

public static void main(String[] args) {float f1 = 0.1f;double f2 = 0.05;System.out.println(f1+f2);//0.1500000014901161}

6.2 BigDecimal 使用

构造方法: public BigDecimal(Double d):将double 转换成BigDecimal [不建议]public BigDecimal(String s):将String 转换为BigDecimal [建议]BigDecimal(BigInteger val) 将 BigInteger转换成 BigDecimal 。

BigDecimal(BigInteger unscaledVal, int scale) 将BigInteger的 BigInteger值和 int等级转换为 BigDecimal 。

BigDecimal(BigInteger unscaledVal, int scale, MathContext mc) 将 BigInteger未缩放值和 int扩展转换为 BigDecimal ,根据上下文设置进行舍入。

BigDecimal(BigInteger val, MathContext mc) 根据上下文设置将 BigInteger转换为 BigDecimal舍入。

BigDecimal(char[] in) 一个转换的字符数组表示 BigDecimal成 BigDecimal ,接受字符作为的相同序列 BigDecimal(String)构造。

BigDecimal(char[] in, int offset, int len) 一个转换的字符数组表示 BigDecimal成 BigDecimal ,接受字符作为的相同序列 BigDecimal(String)构造,同时允许一个子阵列被指定。

BigDecimal(char[] in, int offset, int len, MathContext mc) 一个转换的字符数组表示 BigDecimal成 BigDecimal ,接受字符作为的相同序列 BigDecimal(String)构造,同时允许指定一个子阵列和用根据上下文设置进行舍入。

BigDecimal(char[] in, MathContext mc) 一个转换的字符数组表示 BigDecimal成 BigDecimal ,接受相同的字符序列作为 BigDecimal(String)构造与根据上下文设置进行舍入。

BigDecimal(double val) 将 double转换为 BigDecimal ,这是 double的二进制浮点值的精确十进制表示。

BigDecimal(double val, MathContext mc) 将 double转换为 BigDecimal ,根据上下文设置进行舍入。

BigDecimal(int val) 将 int成 BigDecimal 。

BigDecimal(int val, MathContext mc) 将 int转换为 BigDecimal ,根据上下文设置进行舍入。

BigDecimal(long val) 将 long成 BigDecimal 。

BigDecimal(long val, MathContext mc) 将 long转换为 BigDecimal ,根据上下文设置进行舍入。

BigDecimal(String val) 将BigDecimal的字符串表示 BigDecimal转换为 BigDecimal 。

BigDecimal(String val, MathContext mc) 一个转换的字符串表示 BigDecimal成 BigDecimal ,接受相同的字符串作为 BigDecimal(String)构造,利用根据上下文设置进行舍入。 常用方法: public BigDecimal add(BigDecimal augend):与参数相加.public BigDecimal subract(BigDecimal subtranhend):与参数相减;public BigDecimal multiply(BigDecimal multiplicand):与参数相乘public BigDecimal divide(BigDecimal divisor): 与参数做除法, 除不尽会抛出异常`public BigDecimal divide(BigDecimal divisor, int scale ,int roundingMode):与参数做除法;

参数1:除数;

参数2:小数点后保留的位数;

参数2:舍入模式;

public static void main(String[] args) {

BigDecimal bd1 = new BigDecimal(“1000”);

BigDecimal bd2= new BigDecimal(“3”);

System.out.println(bd1.add(bd2));//加法

System.out.println(bd1.subtract(bd2));//减法

System.out.println(bd1.multiply(bd2));//乘法

//bd3/bd4 保留五位小数,2舍 3入

BigDecimal divide = bd1.divide(bd2, 5, 2);

System.out.println(divide);

}

3.常见数据结构

3.1数据结构介绍

数据结构的含义即是 : 数据用什么样的方式排列在一起

3.2常见数据结构

常用的数据结构分为: 栈, 队列, 数组, 链表, 红黑树, 其余不一一列举

3.2.1 栈

栈(stack): 又称为堆栈 ,他是运算受限的线性代表, 其限制是仅允许在标的一端进行插入和删除操作,不允许在其他任何位置进行添加,查找, 删除等操作.

采用该结构的集合, 对元素的存取有一下特点

先进后出: 存进去的元素,要在他后面的元素依次取出后, 才能取出该元素.就好比子弹夹,往里面压入子弹, 射击的时候最上面的先击发;栈的入口和出口都是在栈的最顶端位置压栈 : 就是存入元素, 即把元素存储到栈的顶端位置, 栈中已有元素依次向栈底移动一个位置.弹栈: 就是取出元素,即把栈的顶端位置元素取出, 栈中已有元素依次向栈的顶端移动一个位置.

3.2.2 队列

队列(queue) ,简称队, 他从堆栈一样, 也是一种运算受限的线性表, 其限制是仅允许在表的一端进行插入, 而在表的另一端进行删除.

采用该结构的集合,对元素的存取有如下特点:

先进先出:存进去的元素,要在他的前面的元素依次取出后, 他能求出该元素; 比如显示生活中的隧道;队列的入口出口,各占一半,

3.2.3 数组

数组(array) 是有序的元素序列, 数组是在内存中开辟一端连续的空间, 并在此空间存放元素; 酒店,每个房间都有房间号;可以根据房间号查看每个房间是否有客人;

采用该结构的集合,对元素有一下特点

查找元素快: 通过索引,可以快速访问指定位置的元素增删元素比较慢 :

指定索引位置增加元素: 需要创建一个新数组,将指定新元素存储在指定索引位置 , 再把原数组根据索引,复制到新数组对应的索引位置;

指定索引位置删除元素: 需要创建一个新数组,把原数组元素根据索引,复制到新数组对应索引的位置, 原数组中指定索引位置元素不复制到新数组,

3.2.4 链表

链表(linked list) , 由一些列节点node(链表中每一个元素成为一个节点)组成, 节点可以在运行时动态生成,每个节点包括两部分:一个时存储数据元素的数据域, 另一个是存储下一个节点地址的指针域.链表结构有单向链表和双向链表, 单向链表

采用该结构的集合,对元素的存储有一下特点:

多个节点之间,通过地址进行连接, 例如自行车链条增删元素比较快

3.2.5 红黑树

二叉树(binary tree) , 是每个节点不超过2的有序树(tree).

就是类似于我们现实中的数目结构, 只不过每个树枝最多有两个叉, 顶上的叫根节点, 两边被称为"左子树" 和"右子树"

红黑树本质就是一颗二叉查找树,将节点插入后, 该树仍然是一颗二叉查找树

红黑树可以通过红色节点和黑色节点尽可能的保证二叉树的平衡, 从而提高效率, 查找速度恐怖!

具体什么是红黑树, 是很大一门学问, 需要另起文章,一一讲解;

4.Collection-集合框架

集合的概述: 集合: 集合使java中提供的一种容器, 可以用来存储多个数据.集合与数组的区别: 数组长度是固定的, 集合的长度是可变的.数组中存储的是同一种元素, 可以存储任意类型的数据, 集合中存储的都是引用数据类型,如果想存储基本数据类型需要存储对应的包装类 集合的继承体系

Collection:单列集合的根接口,用于存储一系列符合某种规则的元素, 他有两个重要的子接口, 分别是java.util.List和java.util.Set其中, List的特点是有序,元素可重复, Set的特点是元素不可重复.List接口的主要实现类有java.util.ArrayList和java.util.LinkedList,Set接口的主要实现类有java.util.HashSet和’LinedHashSet.

上面这张图包括我们经常使用到的集合框,并不是说仅仅只有这些

集合本身就是一个工具, 它存放在java.util包中,在Collection接口中定义了单例集合框架中共性的部分

Collection 常用的功能;

Collection ,是所有单列集合的父接口, 因此在Collection 中定义了单列集合(List/Set)通用的一些方法, 这些方法可以用于操作所有的单列集合 public boolean add(E e): 把给定的对象添加到当前集合中.public void clear():清空所有的元素.public boolean remove(E e) : 把给定的对象在当前集合中删除.public boolean contains(Object obj):判断当前集合中是否包含给定的对象.public boolean isEmpty(): 判断当前集合是否为空.public int size():返回当前集合中元素的个数.public Object[] toArray: 把集合中的元素,存储到数组中

常用的方法基本就以上这么多,还有很多方法可以查看java API 文档

Iterator 迭代器,增强for

Iterator 接口

在程序开发中,经常需要遍历集合中所有元素, 针对这种需求,JDK专门提供了一个接口

java.util.Iterator

想要遍历Collection集合, 那么就要获取该集合迭代器完成迭代操作, pubic Iterator iterator():获取集合对应的迭代器, 用来遍历集合中的元素的迭代 : 即Collection 集合元素通用的获取方式, 在取元素之前要先判断集合里面有没有元素, 如果有则取出来,继续判断有的话再取出, 直到把集合中元素全部取出来, 这种方式专业术语叫做迭代 Iterator 接口的常用方法如下:

public E next() :返回迭代的下一个元素.

public boolean hasNext(): 如果有下一个元素可以迭代, 返回true.

public static void main(String[] args) {

ArrayList arr = new ArrayList<>();

arr.add(“test01”);

arr.add(“test02”);

arr.add(“test03”);

arr.add(“test04”);

//获取集合的迭代器

Iterator iterator = arr.iterator();

//判断是否有下一个元素

while (iterator.hasNext()) {

String next = iterator.next();

System.out.print(next+"\t");//test01 test02 test03 test04

}

}

PS:

在进行集合元素获取时, 如果集合中已经没有元素了,还继续调用迭代器的next() 方法, 将会抛出异常:java.util.NoSuchElementException 没有元素异常.

在进行集合元素获取时, 如果天剑或移除集合中的元素, 将无法继续迭代,将会抛出

ConcurrentModificationException并发修改异常

迭代器的实现原理

当遍历集合时,首先通过调用集合的iterator()方法获取迭代器对象, 然后使用hasNest()方法判断集合中是否有下一个元素,如果存在, 则调用next()方法取出,否则证明已经全部取出, 停止循环遍历

Iterator 迭代器对象在遍历集合时, 内部采用指针的方式来跟踪集合中的元素;

在调用iterator 的next()方法之前,迭代器的索引位于第一个元素之前, 不指向任何元素, 当第一次调用迭代器的next()方法之后,迭代器的索引为向后移动一位, 指向第一个元素并返回, 以此类推,知道hasNext()方法返回false; 终止遍历

增强for

也称为foreach 循环, 是jkd5之后, 出现的一个高级for循环 , 主要用来遍历元素,内部其实是一个Iterator迭代器, 所以在遍历的时候不能对元素进行增删操作;

格式:

for(元素类型 变量名 : 集合或者数组)

{}

它用于遍历Collection 和数组, 通常只进行遍历,不要在遍历过程中对集合中的元素进行增删操作;

public static void main(String[] args) {

int[] arr = {1, 3, 5, 7, 8};

for (int a : arr) {

System.out.print(a+"\t");//1 3 5 7 8

}

System.out.println();

ArrayList arrayList = new ArrayList<>();

for (int i = 0; i < 10; i++) {

arrayList.add(i + “”);

}

for (String s : arrayList) {

System.out.print(s+"\t");

//0 1 2 3 4 5 6 7 8 9

}

}

PS:

foreach 循环必须有被遍历的目标, 目标只能是Collection 或者数组;

仅仅可以遍历不能增删元素否则会抛出ConcurrentModifcationException并发异常

4.1 List

4.1.1 List介绍

java.util.List接口实现Collection接口, 是单列结合的一个重要分支, 一般将实现List接口的对象成为List集合, 在List集合中允许出现重复的元素, 所有的元素是以一种线性方式进行存储的, 在程序中可以通过索引来访问集合中指定的元素, List集合是有序的, 即元素的存入顺序和取出顺序一致

List接口特点:

他是一个元素存取有序的集合, 例如,存入的是 1,2,3 那么集合中元素的存储顺序就是1,2,3

他是一个带有索引的集合, 通过索引就可以精确的操作集合中的元素(与数组的索引一样).

集合中可以有重复的元素, 通过元素的equals 方法, 来比较是否为重复元素.

4.1.2 List 接口中常用方法

List作为Collection 子接口, 不但继承了Collection 接口中的全部方法, 而且还增加了一些根据元素索引来操作集合的特有方法:

public void add(int index ,E element):将指定的元素,添加到该集合中的指定位置上public E get(int index):返回集合中指定位置的元素.public E remove(int index): 移除列表中指定位置的元素, 返回的是被移除的元素.pubic E set(int index ,E element): 用指定的元素替换集合中指定位置的元素, 返回替换之前的元素

4.1.3 ArrayList 集合

java.util.ArrayList集合数据的存储结构是数组结构, 元素增删慢, 查找快, 因为日常操作都是查询数据,遍历数据,所以ArrayList 经常使用;

4.1.4 LinkedList 集合

java.util.LinkedList 集合数据存储结构是链表结构,方便元素添加,删除的集合;

LinkList 是一个双向链表结构

LindedList 提供了大量首尾操作的方法:

public void addFirst(E e): 将指定的元素插入此列表的开头public void addLast(E e):将指定的元素插入此列表的结尾public E getFirst():返回此列表开头第一个的元素public E getLast():返回此列表结尾最后一个元素public E removeFirst():移除并返回此列表的第一个元素public E removeLast(): 移除并返回此列表的最后一个元素public E pop():从此列表锁表示的堆栈处弹出一个元素public void push(E e):将元素推入此列表所表示的堆栈.public boolean isEmpty():如果列表不包含元素则返回true.

LinkedList是List的子类, List中的方法LinkedList 中都可以使用 , LinkedList 可以被当做堆栈, 队列来使用;

public static void main(String[] args) {LinkedList<String> linkedList = new LinkedList<>();linkedList.add("str01");linkedList.add("str02");linkedList.add("str03");linkedList.add("str04");System.out.println(linkedList.toString());String first = linkedList.getFirst();System.out.println(first);String last = linkedList.getLast();System.out.println(last);String s = linkedList.removeFirst();System.out.println(s);String s1 = linkedList.removeLast();System.out.println(s1);System.out.println(linkedList.toString());linkedList.addFirst("str01");linkedList.addLast("str04");System.out.println("========================");System.out.println(linkedList.toString());boolean empty = linkedList.isEmpty();System.out.println(empty);System.out.println("========================");String pop = linkedList.pop();System.out.println(pop);System.out.println(linkedList.toString());linkedList.push("test999");System.out.println(linkedList.toString());/*[str01, str02, str03, str04]str01str04str01str04[str02, str03]========================[str01, str02, str03, str04]false========================str01[str02, str03, str04][test999, str02, str03, str04]*/}

4.2 Set

java.util.Set接口和java.util.List接口一样都是Collection的子接口与, 他与Collection 接口中的方法基本一致, 并没有对Collection 接口进行功能上的扩充 , 只是比Collection接口更加的严格, 与List接口不同的是, Set 接口中的元素是无序的, 并且都会以某种规则保证存入的元素不出现重复;Set集合有多个子类, 主要的两个为java.util.hashSet,java.util.LinkedHashSet这两个集合,

取出元素的方式可以采用: 迭代器, 增强for

4.2.1HashSet集合

java.util.HashSet 是Set接口的一个实现类, 他所存储的元素是不可重复的, 并且元素都是无序的(存取顺序无法保证)java.util.HashSet 底层是一个java.util.HashMap 支持,

HashSet 是根据对象的哈希值来确定元素在集合中的存储位置, 因此查找性能比较好, 保证元素唯一性的方式采用 hashcode 和equals方法

public static void main(String[] args) {HashSet<String> hashSet = new HashSet<>();hashSet.add("str1");hashSet.add("str1");hashSet.add(new String("str1"));for (String s : hashSet) {System.out.println(s);}/** str1* str11* */}//不同对象, 数据相同也不会储存

4.2.2 HashSet集合存储数据的结构(哈希表)

哈希表是什么?

在jkd1.8之前, 哈希表底层采用数组+链表来实现, 即使用数组处理冲突, 同一hash 值的链表都存储在一个数组里, 但是当位于一个桶中的元素较多, 即hash值相同的元素较多是,通过key 值依次查找效率比较低,在jdk1.8时哈希表存储数据采用数组+链表+红黑树实现,当链表长度超过阈值(8)时, 将链表转换为红黑树,来降低查找时间.

HashSet唯一性通过hashCode和equals 方法来决定的, 如果往集合中添加自定义对象, 要保证其唯一性,就必须重写hashCode和equals 方法简历属于当前对象的比较方式

4.2.3 HashSet 存储自定义类型元素

public class Student {String name ;String sex ;public Student(String name, String sex) {this.name = name;this.sex = sex;}@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;Student student = (Student) o;return Objects.equals(name, student.name) &&Objects.equals(sex, student.sex);}@Overridepublic int hashCode() {return Objects.hash(name, sex);}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", sex='" + sex + '\'' +'}';}}public class Test_Student {public static void main(String[] args) {HashSet<Student> hashSet = new HashSet<>();hashSet.add(new Student("小红", "23"));hashSet.add(new Student("小红", "23"));hashSet.add(new Student("小红", "23"));hashSet.add(new Student("小红", "23"));for (Student student1 : hashSet) {System.out.println(student1);//Student{name='小红', sex='23'}}}}

4.2.4 LinkedHashSet

HashSet保证元素的唯一性, 但是无法保证放入元素的顺序, 如果要保证顺序的话,在HashSet下面有一个子接口java.util.LinkedHashSet , 他是链表和哈希表组合的一种数据存储结构.

public static void main(String[] args) {LinkedHashSet<String> set = new LinkedHashSet<String>();set.add("aaa");set.add("bbb");set.add("ccc");set.add("ddd");set.add("ddd");for (String s : set) {System.out.println(s);}/*aaabbbcccddd*/}

4.3 Map

4.3.1 什么是Map

>现实生活中,我们每个人都有每个人的身份证号, 像这中一一对象的关系叫做映射, java提供了专门的集合类来存放这些具有映射关系的元素,`java.util.Map` 接口, `Map`和`Collection`存储数据的方式不同, Map是双列的集合结构

collection集合中元素是独立存在的Map 集合中元素是成对出现的, 每个元素都由两个部分组成, 通过键可以找到对应的值'Collection 集合成为单列集合, Map集合称为多列集合(每个键都是唯一的,值可以重复).

4.3.2 Map的常用子类

HashMap<K,V> : 存储数据采用的哈希表结构, 元素的存取顺序不能保证一致 ,由于要保证键的唯一性,不可重复, 需要重写键的hashcode() 和equals() 方法,LinkedHashMap: HashMap 下的子类, 存储数据采用哈希表+链表结构, 通过链表结构可以保证元素存取顺序一致, 通过哈希表结构可以保证键的唯一,不重复, 需要重写键的 hashcode() 和 equals()方法Map 集合中都有两个泛型变量 <K,V> , 在定义时 ,两个泛型变量类型可以相同也可以不同, 一般都是这样定义Map<String,Object> 为了方便使用;

具体每个集合的底层以后一一研究 这里就不做赘述, 没和集合底层都是一门学问;

4.3.3 Map 的常用方法

Map 接口中定义了很多种方法, 比较常用的有:

public v put(k key ,v value): 把指定的键与指定的值添加到Map中 , 若Map中没有这个K则返回null, 如果有的话就返回原先的值,把新值插进去;

public v remove(Object key): 把指定的键所对应的键值在集合中删除, 返回被删除的值

public v get(Object key): 根据指定的键, 在Map 集合中获取对应的值

public Set keySet(): 获取Map集合中所有的键, 存储到Set 集合中.

public Set<Map.Entry<K,V>> entrySet(): 获取到Map集合中所有的键值对对象的集合(Set集合)。

public boolean containKey(Object key) :判断该集合中是否有此键。

public static void main(String[] args) {

HashMap<String, Object> hashMap = new HashMap<>();

hashMap.put(“1”, “test01”);

hashMap.put(“2”, “test02”);

hashMap.put(“3”, “test03”);

hashMap.put(“4”, “test04”);

System.out.println(hashMap);//{1=test01, 2=test02, 3=test03, 4=test04}

Object remove = hashMap.remove(“1”);//test01

System.out.println(remove);

System.out.println(hashMap);//{2=test02, 3=test03, 4=test04}

hashMap.put(“1”, “test01”);

System.out.println(hashMap);//{1=test01, 2=test02, 3=test03, 4=test04}

Object o = hashMap.get(“1”);

System.out.println(o);//test01

Set set = hashMap.keySet();

System.out.println(set);//[1, 2, 3, 4]

Set<Map.Entry<String, Object>> entries = hashMap.entrySet();

System.out.println(entries);//[1=test01, 2=test02, 3=test03, 4=test04]

boolean b = hashMap.containsKey(“1”);

System.out.println(b);//true

}

4.3.4 Map的遍历方式

Map的遍历, 因为键值唯一的,我们可以用keySet() 方法获取到所有的键的set集合,然后遍历set集合根据get()方法将key传进去, 取出值

public static void main(String[] args) {HashMap<String, Object> hashMap = new HashMap<>();hashMap.put("1", "test01");hashMap.put("2", "test02");hashMap.put("3", "test03");Set<String> set = hashMap.keySet();for (String s : set) {String ss = (String) hashMap.get(s);System.out.println(ss);}/*test01test02test03*/}

还有一种就是用entrySet()方法, 获取Set集合, 通过遍历set 集合获取每一个entry对象, 在通过entry 的getKey(), 和 getValue()方法来获取键和值;

public static void main(String[] args) {HashMap<String, Object> hashMap = new HashMap<>();hashMap.put("1", "test01");hashMap.put("2", "test02");hashMap.put("3", "test03");Set<Map.Entry<String, Object>> entries = hashMap.entrySet();for (Map.Entry<String, Object> entry : entries) {String key = entry.getKey();Object value = entry.getValue();System.out.println(key+"==="+value);}/*1===test012===test023===test03*/}

4.3.5 LinkedHashMap

hashMap的查询速度很快, 可以保证成对元素的唯一性, 但是无法保证元素存放的顺序, 要想保证元素的顺序, 就得使用HashMap下的子类, LikendHashMap 他的底层是采用链表加哈希表组合的数据结构

public static void main(String[] args) {LinkedHashMap<String, Object> linkedHashMap = new LinkedHashMap<>();for (int i = 1; i <= 5; i++) {linkedHashMap.put("" + i + "", "Test" + i);}Set<Map.Entry<String, Object>> entries = linkedHashMap.entrySet();for (Map.Entry<String, Object> entry : entries) {System.out.println(entry.getKey()+"->"+entry.getValue());}/*1->Test12->Test23->Test34->Test45->Test5*/}

4.4 collections工具类

java.util.Collections 是集合的工具类,主要用来操作集合

public static void shuffle(List<?> list) : 打乱集合顺序.

public static void main(String[] args) {ArrayList<Integer> integers = new ArrayList<>();integers.add(11);integers.add(22);integers.add(33);integers.add(44);System.out.println(integers);//[11, 22, 33, 44]Collections.shuffle(integers);System.out.println(integers);//[11, 33, 22, 44]}

public static void sort(List list):将集合中的元素按照默认规则排序

public static void main(String[] args) {ArrayList<Integer> integers = new ArrayList<>();integers.add(1);integers.add(97);integers.add(43);integers.add(22);System.out.println(integers);//[1, 97, 43, 22]Collections.sort(integers);System.out.println(integers);//[1, 22, 43, 97]}

public static void sort(List list , Comparator<? super T>):将集合中元素按照指定规则排序.

public class Student {

private String name;

private int age;

public Student(String name, int age) {this.name = name;this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}@Overridepublic String toString() {return "Strdent{" +"name='" + name + '\'' +", age=" + age +'}';}}public static void main(String[] args) {ArrayList<Student> objects = new ArrayList<>();objects.add(new Student("小王",66));objects.add(new Student("小红", 1));objects.add(new Student("小狗", 9));objects.add(new Student("小猪", 5));System.out.println(objects);//[Student{name='小王', age=66}, Student{name='小红', age=1}, Student{name='小狗', age=9}, Student{name='小猪', age=5}]Collections.sort(objects, new Comparator<Student>() {@Overridepublic int compare(Student o1, Student o2) {return o2.getAge() -o1.getAge() ;//前减后 由小到大, 后减前 由大到小}});System.out.println(objects);//[Student{name='小王', age=66}, Student{name='小狗', age=9}, Student{name='小猪', age=5}, Student{name='小红', age=1}]}

5.泛型, 泛型通配符

5.1 泛型(Geneic)

在JDK1.5之前, 我们定义集合的时候 是可以随意往里面赋值的, 但是取出的时候我们无法确定是什么类型, 有时候就会导致异常的发生java.lang.ClassCasetException, 类型转换异常, 但是才JDK1.5 之后引入了泛型,就不会导致这种异常的发生,因为我们实例集合的时候已经指定了类型,这样的话如果存入的数据类型匹配的话就会导致编译报错

泛型的定义与使用;

可以定义泛型类, 方法, 接口,

定义含有泛型类

public class Test01 {

public void add(E e){

}

}

在实例化类的时候在能确定泛型的类型;

public class Test {public static void main(String[] args) {Test01<String> stringTest01 = new Test01<>();stringTest01.add("d");}}

定义含有泛型方法

//修饰符 <代表泛型的变量> 返回值类型 方法名(参数){}

public class Test02 {

public E query(E e){

return e;

}

}

在调用方法的时候才能确定泛型的类型

Test02 test02 = new Test02();test02.query("fd");

定义含有泛型接口

public interface Test03 {

void add(E e);

E query();

}

调用时指明类型

public class Test implements Test03<String> {public static void main(String[] args) {}@Overridepublic void add(String o) { }@Overridepublic String query() { return null; }}

没有创建时不能确定的类型叫做泛型

public class Test01<E> implements Test03<E>{public void add(E e){ }@Overridepublic E query() { return null; }}

5.2 泛型通配符

当使用泛型类或者接口是, 传递的数据中,泛型类型不能确定, 可以通过通配符<?> 表示 , 使用通配符后, 只能使用Object中的共性方法 , 集合中元素自身的方法无法使用,

5.2.1 通配符的基本使用

泛型通配符:不知道该用什么类型接收的时候可以使用泛型通配符? 表示未知通配符.此时只能接收数据, 不能我那个集合中存入数据.

public static void main(String[] args) {LinkedHashMap<Object, Object> objectObjectLinkedHashMap = new LinkedHashMap<>();get(objectObjectLinkedHashMap);}public static void get(Map< ?,? > collection){}

泛型不存在继承关系

如上图, 这种实例定义泛型定义String 类型, 但是接收用Object 的话就编译报错

5.2.2 通配符高级使用–受限泛型

java中泛型存在上限和下限

泛型的上限

格式 类型<? extends 类> 对象名称含义: 只能接收该类型及其子类

泛型的下限

格式:类型<? super 类> 对象名称

含义:只能接收本类及其父类

public class Test01 {

public static void main(String[] args) {

HashSet objects = new HashSet();

HashSet integers = new HashSet();

HashSet strings = new HashSet();

HashSet numbers = new HashSet();

//getElements(objects); 会编译报错, 因为 getElements 接收的只能是Number类 及其他的子类

//getElements(strings); 同上

getElements(numbers);

getElements(integers);

//getElements1(integers); 编译报错, getElements1 泛型只能接收Number 类型的及其的他父类型

//getElements1(strings);

getElements1(numbers);

getElements1(objects);

}

public static void getElements(Collection<? extends Number> collection) { }public static void getElements1(Collection<? super Number> collection) { }

}

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。