Java的字符串,String
Java.lang.String使用了final修饰,不能被继承
String是不可变对象
Java字符串中在内存中采用Unicode编码方式
在一般常见的对象中, == 比较的是内存地址是否相同,而equal是比较值
1.==,判断对象是否是同一个,地址是否相同
2.equals,判断对象的而内容是否相同,默认调用的object的equals()方法,
而该方法判断的仍然是地址是否相同
3.如果没有重写equals方法,效果和==相同。
字符串的赋值和比较
如果在内存中已经存在某个字符串,Java就不会去创建新的,而是直接地址指向到已存在的字符串,
除非用new,才会创建一个新的字符串
public class Demo1 {
public static void main(String[] args) {
String s1 = "123abc";
String s2 = "123abc";
String s3 = new String("123abc"); 强制new一个对象
System.out.println(s1 == s2); ----true
System.out.println(s1 == s3); ----false
s1 = s1 + "!";
System.out.println(s1); ----123abc!
System.out.println(s2); ----123abc
字符串是不可修改的,既然修改,java就重建一个,每次修改都重新建立一个字符串
String s4 = "123" + "abc";
System.out.println(s4 == s2); ----true
编译器的一个优化措施,
当一个计算表达式计算符两边都是字面量时,会直接计算结果,然后将结果编译到class文件中
编译器发现 "123" 和 "abc" 都是字面量,直接转成 String s4 = "123abc"
String str1 = "123";
String str2 = "abc";
String s5 = str1 + str2;
System.out.println(s5 == s2); ----false
str1 和 str2 都是变量,就没有转换
}
}
字符串长度
String str = "libai";
System.out.println(str.length());
打印:
5
查找某个字符串是否在某个字符串里面
返回 "in" 中的 “i” 在字符串 "thinking in java" 中第一个的位置,也就是 2,没有则返回 -1
String str = "thinking in java";
int index = str.indexOf("in");
System.out.println(index);
打印:
2
重载方法允许从指定位置处开始查找
index = str.indexOf("in", 3);
System.out.println(index);
打印:
5
查找最后一次出现指定字符串的位置
index = str.lastIndexOf("in");
System.out.println(index);
打印:
9
substring 截取字符串
String substring(int start, int end)
截取字符串,从指定位置(start)开始截取到指定的位置(end)
java api有一个特定,通常用两个数字表示范围时,都是 含头不含尾 的。
传入两个参数
String str = "thinking in java";
String sub = str.substring(4, 8); ----结果:king
传入一个参数,截取到结束位置
String sub = str.substring(4); ----结果:king in java
常用方法
trim() 去掉空格
startsWith("think") 判断字符串是不是以 "think" 开头的
endsWith("java") 判断字符串是不是以 "java" 结尾的
toUpperCase() 全大写,只对英文有效
toLowerCase() 全小写,只对英文有效
将其他类型转换成字符串
int a = 11;
String str1 = String.valueOf(a);
Java的字符串连接利用 StringBuilder
在线程中最好使用StringBuffer,StringBuffer 考虑到了线程安全的问题,而 StringBuilder 没有考虑。
StringBuiler提供了用于修改字符串内容的相关方法。
其内部维护的是一个可变的字符数组,所以修改都是在当前对象内部完成的。
当频繁修改字符串内容时应当使用当前类来完成
public class Demo2 {
public static void main(String[] args) {
String str = "libai";
将String转换为StringBuilter
可以使用有参的构造方法
StringBuliter也有无参构造方法,默认表示空字符串
StringBuilder builder = new StringBuilder(str);
从StringBuilder转换为String
使用StringBuilder的头toString方法即可
str = builder.toString();
StringBuilder append(String str)
向当前字符串末尾追加指定内容。
有若干重载方法,参数类型不同,这些重载方法
允许追加其他内容(先转换为字符串再追加)
builder.append(" hello");
System.out.println(builder); ---- libai hello
StringBuilder replace( int start, int end, String str)
将指定范围内的字符串替换为指定的内容
builder.replace(4, 11, " world");
System.out.println(builder); ---- libai world
StringBuilder delete(int start,int end)
删除特定区间字符串
StringBuilder insert(int index,String str)
将给定字符串插入到指定位置,原位置及后续字符串顺序向后移动
reverse()反转
}
}
Java 的正则表达式---略
Java Object 的方法
toString() 方法
通常我们需要使用一个类的 toString 方法时,就应当重写该方法。
Object自身的toString方法返回的是:类名+地址(内存地址)
重写该方法后,返回的字符串没有严格的格式限制
将来可以根据需求而定。但是原则上该字符串中应当包含当前对象的属性信息。
只有我们自定义的类需要重写该方法,JAVA API提供的类通常都已经重写了该方法。
System.out.println(Object obj) ---输出的是给定对象toString返回的字符串
public class Point {
private int x;
private int y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
public String toString() { ---- 重写该方法
return ("x = "+x+", y = "+y);
}
}
equals(),在Object 内部默认就是用 == 符号实现的,需要使用时重写该方法
public class Point {
private int x;
private int y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
通常,当我们需要使用一个类的 equals 方法时,就应当重写它。
equals 方法的作用是比较当前对象与给定对象内容是否一样(长得像不像)
Object 提供的 equals 方法内部就是用 “==” 实现的所以并没有意义。
equals 比较时不一定要求所有属性值都要相同,这要结合实际需求而定。
只有自己定义的类需要重写,JAVA API 提供的类基本上都重写了 equals 方法
public boolean equals(Object obj) { ----重写equals一般的格式
if(obj == null) {
return false;
}
if(obj == this) {
return true;
}
if(obj instanceof Point) {
Point p = (Point)obj;
return this.x==p.x && this.y==p.y;
}
return false;
}
java的包装类,解决基本类型不能参与面向对象开发的问题。
java对8个基本类型分别定义了对应的包装类
而包装类出现的原因是为了解决基本类型不能参与面向对象开发的问题。
所有类都是object的子类
Java的8个基本类型: byte,short,int,long,float,double,char,boolean
是以值的形式直接存在的,所以他们并没有面向对象的特性,
自然也不继承Object,所以不能使用多态, 用Object的角度去接收基本类型。
把一个基本类型包装成一个对象,这个类就叫包装类。也就是 int-->对象
数字类型的包装类继承自Number
其提供了如: intValue,doubleValue这样的方法,
作用是可以将当前包装类表示的数字以其他数字类型的形式返回。
public class Demo1{
将基本类型转换为包装类有两种方式:
1.调用构造方法
2.调用静态方法valueOf(推荐)
public static void main(String[] args) {
Integer i1 = Integer.valueOf(128);
Integer i2 = Integer.valueOf(128);
System.out.println(i1 == i2); ---- false
System.out.println(i1.equals(i2)); --- true
}
}
注意:当 i1 = 127, i2 = 127 时,也就是都值小于128时不会重建对象,而是复用之前存在的对象
上面的结果就都为 true,而大于128后就会重建一个新的对象
* 数字类型包装类都支持两个常量:MAX_VALUE,MIN_VALUE
* 分别保存了对应基本类型的最大值和最小值
字符串转换成特定基本类型
包装类提供了一个静态方法 parseXXX(String str)
可以将给定的字符串转换为对应的基本类型。
前提是该字符串必须正确的描述基本类型可以保存的值。
public class Demo1{
public static void main(String[] args) {
String str = "123";
int i = Integer.parseInt(str);
System.out.println(i++); --- 123
}
}
自动拆装箱
自动拆装箱,JDK1.5开始有的新特性
编译器认可,而不是虚拟机认可。
编译器在将源程序编译时自动补充代码来完成基本类型与包装类之间的转换。
public class Demo1{
public static void main(String[] args) {
int i = Integer.valueOf(124);
上面代码触发了自动装箱:在class文件中,代码被编译器改为:
---- Integer i = Integer.valueOf(124);
Integer ii = 124;
上面代码触发了自动拆箱:在class文件中,代码被编译器改为:
---- int ii = new Integer(124).intValue();
}
}
java的Date函数,其内置的大部分方法都过时了,不建议使用
import java.util.Date;
java.util.Date
Date的每一个实例用于表示一个确切的时间点。
内部维护了一个long值,该值 记录的是从1970年1月1日000000
到表示的时间点之间所经历的毫秒值,正数是70年以后的日期,负数是70年以前的日期。
由于Date设计上存在缺陷(时区,千年虫),所以它的大部分方法被设置为"过时的",不再建议使用
表示当前系统时间
public class Demo1 {
public static void main(String[] args) {
Date now = new Date(); ---表示当前系统时间
Date内部重写了toString方法
System.out.println(now); ---- Mon Sep 03 09:20:38 CST 2018
获取Date内部维护的的long值
System.out.println(now.getTime()); ---- 1535937638425
System.out.println((now.getYear())); ---- 118
设置时间::now.setTime(time)
}
}
Date 字符转化为特定格式的字符串
import java.text.SimpleDateFormat;
import java.util.Date;
java.text.SimpleDateFormat
根据一个给定的日期格式将String与Date相互转换。
* Date-->String
* String format(Date date)
* format方法可以将给定的date对象说表示的时间
* 按照SimpleDateFormat指定的日期格式转换为字符串。
public class Demo2 {
public static void main(String[] args) {
Date date = new Date();
System.out.println(date);
SimpleDateFormat d = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String str = d.format(date);
System.out.println(str);
}
}
打印:
Tue Jul 31 21:39:05 CST 2018
2018-07-31 21:39:05
字符串转换成Date对象
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
* 从字符串转换为Date,Date parse(String str)
* 将给定的字符串按照SimpleDateFormat指定的日期格式解析为一个Date对象。
public class Demo2 {
public static void main(String[] args) throws ParseException {
String str = "2018-08-08 20:08:08";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
// String ----> Date
Date date = sdf.parse(str);
System.out.println(date);
}
}
Calendar 日历类
import java.util.Calendar;
import java.util.Date;
* 日历类,该类是一个抽象类,封装了对时间的相关操作。
* 常用的实现类格里高里历(阳历)
* 使用日历类是为了对时间进行相关操作。
public class Demo3 {
public static void main(String[] args) {
* 使用Calendar的静态方法创建实例,
* 该方法会根据当前系统是在地区创建一个相应的实现。
* 通常是GregorianCanlendar
* 默认创建的日历实例表示当前系统时间。
Calendar calendar = Calendar.getInstance();
* toString不能直观反应表示的日期
System.out.println(calendar);
* Calendar与Date之间的转换
*
* Calendar --> Date
* Date getTime()
* Calendar提供了方法getTime(),该方法返回一个Date对象,
* 该对象表示的时间就是当前Calendar表示的时间。
Date date = calendar.getTime();
System.out.println(date);
* setTime() 可设置时间
}
}
import java.util.Calendar;
import java.util.Date;
* Calendar提供了针对不同时间分量单独设置值的方法
* void set(int field, int value)
* 其中第一个参数为:时间分量,例如:年,月,日等等
* 第二个参数就是对应的值。
* 时间分量是一个int值,使用Calendar提供的常量。
public class Demo3 {
public static void main(String[] args) {
Calendar calendar = Calendar.getInstance();
System.out.println(calendar.getTime());
//设置年
calendar.set(Calendar.YEAR, 2008);
System.out.println(calendar.getTime());
//获取年
calendar.get(Calendar.YEAR);
}
}
集合,ArrayList,可重复,有序,增添数据十分方便
import java.util.ArrayList;
import java.util.Collection;
* java.util.Collection
* 集合,用于存储一组元素,提供了维护集合的相关操作。
* 其派生了两个子接口:
* List--->可重复集
* Set---->不可重复集
* 元素是否重复是依靠元素自身equals方法比较的结果而定的。
public class Demo4 {
public static void main(String[] args) {
Collection c = new ArrayList();
* boolean add(E e) 向集合中添加元素
* 当元素成功添加到集合后返回true
c.add("one");
c.add("two");
c.add("three");
System.out.println(c.size());
System.out.println(c);
* boolean isEmpty() 判断当前集合是否是空
* c.clear() 清空集合
* 集合判断是否包含指定元素是依靠元素的equals比较的结果
* boolean c.contains(p);
* 集合存放的是地址
* boolean remove(E e)
* 从集合中删除指定元素,删除成功返回true
* 只删除集合中第一个与给定元素equals比较为true的元素。
* equals的方法可以自己写,也可以按java自带的
c.remove("one");
}
}
HashSet,不重复,无序(内部是通过HashMap)实现的
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
public class Demo4 {
public static void main(String[] args) {
Collection c1 = new ArrayList();
c1.add("one");
c1.add("one");
c1.add("two");
c1.add("three");
System.out.println(c1); ---- [one, one, two, three]
Collection c2 = new HashSet();
c2.add("two");
* 取并集
* boolean addAll(Collection c)
* 将给定集合中的所有元素添加到当前集合中
* 添加后只要当前集合元素数量发生了变化,则返回true
c2.addAll(c1);
* boolean containsAll(Collection c)
* 判断当前集合是否包含给定集合中的所有元素
* c1.removeALL(Collection c)
* 从c1集合中删除两个集合共有的元素
System.out.println(c2); ---- [one, two, three]
}
}
Iterator,迭代器,遍历集合,要遵循 问,取,删的步骤
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
* 遍历集合
* Collection提供了统一的遍历集合元素的方式:迭代器模式
* Iterator iterator()
* 获取用于遍历当前集合的迭代器
*
* java.util.Iterator是一个接口,规定了用于遍历集合元素
* 的相关方法,不同的集合提供了相应的实现类。
* 无序记住那些实现类的名字,只将他们当作Iterator即可。
*
* 遍历集合遵循:问,取,删的步骤,其实删除不是必须操作
public class Demo4 {
public static void main(String[] args) {
Collection c = new ArrayList();
c.add("one");
c.add("#");
c.add("two");
c.add("#");
c.add("three");
c.add("#");
* 获取用于遍历当前集合的迭代器
Iterator it = c.iterator();
* boolean hasNext() 问的过程
* 该方法是判断集合中是否还有元素可以取出
*
* E next() 取的过程
* 获取集合中的下一个元素
while(it.hasNext()){
String str = (String)it.next();
if("#".equals(str)) {
* 用字面量去 equals变量、避免变量为null引发空指针异常
* 在使用迭代器遍历集合时,不要使用集合的方法增删元素,否则会引发异常。
-----> c.remove(str); 会引发异常
迭代器提供了remove方法,用来删除.next方法取出的元素
it.remove();
}
}
System.out.println(c);
}
}
打印:
[one, two, three]
for each 循环,增强for循环
* JDK5.0之后推出了一个新的特性:
* 增强for循环,又叫做新循环,for each
* 新循环不能替代传统循环,作用仅仅是用来遍历集合或数组的。
* 新循环并非新的语法,新循环是编译器认可,而不是虚拟机认可。
* 使用新循环遍历集合时,编译器会将它改为迭代器方式遍历。
* 所以在使用新循环遍历集合时,不能通过集合的方式增删元素。
public class Demo1 {
public static void main(String[] args) {
String[] array = {"one","two","three"};
for(String str:array) {
System.out.println(str);
}
}
}
打印:
one
two
three
for each 对对象操作
import java.util.ArrayList;
import java.util.Collection;
public class Demo1 {
public static void main(String[] args) {
Collection c = new ArrayList();
c.add("one");
c.add("two");
c.add("three");
for(Object o:c) {
String str = (String)o; ----加上一个强转就行了
System.out.println(str);
}
}
}
泛型
是将当前类的属性的类型,方法参数的类型及方法的返回值的类型的定义权移交给使用者。
class Point<T>{
private T x;
private T y;
public Point(T i, T j) {
this.x = i;
this.y = j;
}
public T getX() {
return x;
}
public void setX(T x) {
this.x = x;
}
public T getY() {
return y;
}
public void setY(T y) {
this.y = y;
}
}
*泛型
*泛型又称为参数化类型,是将当前类的属性的类型、方法参数的类型
*及方法的返回值的类型的定义权移交给使用者。
*使用者在创建当前类的同时将泛型的实际类型传入
* 泛型的原型是Object
* 定义了泛型只是编译器在做一些验证工作。
* 当我们对泛型类型设置值时,会检查是否满足类型要求。
* 当我们获取一个泛型类型的值时,会自动进行类型转换。
public class Demo2 {
public static void main(String[] args) {
Point<Double> p1 = new Point<Double>(2.2,3.3);
Point<String> p2 = new Point<String>("a","b");
* 这里指定泛型的实际类型为Integer
* 但实际上,创建的Point对象中,x,y属性是Object类型
* 这里只是应当将它当作 Integer看待。
Point<Integer> p3 = new Point<Integer>(1,2);
* 由于参数是T,这里会验证实参是否为Integer,若不是,则编译失败!
* 可以传入基本类型,因为还会自动装箱。
p3.setX(2);
* 获取时,也会自动进行造型,这里无需显式的进行类型转换。
int x3 = p3.getX();
---- 不写泛型类型,默认为Object
Point p4 = p3; --- p4 和 p3指向同一个地址
p4.setX("hello");
System.out.println(p4.getX()); ---打印:hello
---- x3 = p3.getX() 报错类造型异常
System.out.println(p3.getX());
}
}
Collection 集合使用泛型, 约束集合类型
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
* 集合支持泛型,而泛型是用来约束集合中的元素的类型。
public class Demo3 {
public static void main(String[] args) {
-- 约束集合类型
Collection<String> c = new ArrayList();
c.add("one");
c.add("22");
for(String str1:c){
System.out.println(str1);
}
* 迭代器也应当指定泛型,而泛型的实际类型应当
* 与它遍历的集合的泛型类型一致。
Iterator<String> it = c.iterator();
while(it.hasNext()) {
String str2 = it.next(); ---获取元素时不需要再造型了。
System.out.println(str2);
}
}
}
List ,可重复集,并且有序,特点是可以根据下标操纵元素。
import java.util.ArrayList;
import java.util.List;
* java.util.List
* 可重复集,并且有序,特点是可以根据下标操纵元素。
* 常用实现类:
* ArrayList:使用数组实现,查询更快
* LinkedList:使用链表实现,增删更快(首尾增删效果明显)
public class Demo4 {
public static void main(String[] args) {
* E set(int index, E e)
* 将给定元素设置到指定位置上,返回值为原位置的元素。
* 所以是替换元素操作
List<String> list = new ArrayList<String>();
list.add("one");
list.add("two");
list.add("three");
list.add("four");
System.out.println(list);
String old = list.set(1, "2");
System.out.println(old);
System.out.println(list);
// list.set(4,"five")---->下标越界
注意:在原有数据上修改,不要下标越界
取特定下标
String str1 = list.get(2);
}
}
打印:
[one, two, three, four]
two
[one, 2, three, four]
List 的add,set,get,remove 方法
import java.util.ArrayList;
import java.util.List;
* List集合提供了一对重载的add,remove方法
* void add(int index, E e)
* 将给定元素插入到指定位置
*
* E remove(int index)
* 从集合中删除指定位置的元素,并将其返回。
public class Demo5 {
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
list.add("one");
list.add("two");
list.add("three");
System.out.println(list);
-----指定位置插入元素
list.add(1,"2");
System.out.println(list);
------删除
String old = list.remove(2);
System.out.println("删除的元素--"+old+" list="+list);
}
}
打印:
[one, two, three]
[one, 2, two, three]
删除的元素--two list=[one, 2, three]
List 删除元素,subList() 方法
import java.util.ArrayList;
import java.util.List;
* 取子集
* List subList(int start, int end)
* 获取当前集合中指定范围内的子集,同样含头不含尾
* subList 获取的子集,对子集的修改,就是对原集合进行修改
public class Demo6 {
public static void main(String[] args) {
List<Integer> list = new ArrayList<Integer>();
for(int i=0; i<10; i++) {
list.add(i);
}
System.out.println(list);
System.out.println(list.subList(3, 8));
for(int i:list) { ----集合元素的值扩大10倍
list.set(i, list.get(i)*10);
}
System.out.println(list);
----- 删除集合中2-8的元素
list.subList(2, 9).clear();
System.out.println(list);
}
}
打印:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
[3, 4, 5, 6, 7]
[0, 10, 20, 30, 40, 50, 60, 70, 80, 90]
[0, 10, 90]
集合提供了一个方法 toArray,可以将当前集合转换为数组
数组转换为集合
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
* 数组转换为集合
* 需要注意,转换只能转换为List集合
* 使用的是数组的工具类Arrays的静态方法asList
* 只能转换为List集合的主要原因是:set不能存放重复元素。
* 所以若转换为Set集合可能出现丢失元素的情况。
public class Demo7 {
public static void main(String[] args) {
String[] array = {"one","two","three"};
List<String> list = Arrays.asList(array);
* 向集合中添加一个元素
* 实际上下面的代码会抛出异常,原因在于,该集合是由数组转换过来的,
* 那么该集合就表示原来的数组,所以对集合的操作就是对数组的操作。
* 那么添加元素会导致原数组扩容,那么就不能表示原来的数组了。
* 所以不允许向该集合添加新元素。
// ---- list.add("four");
---- 修改集合元素,数组元素也会改变
list.set(1, "2");
System.out.println(list);
---- 输出数组元素
for(String str:list) {
System.out.print(str+" ");
}
* 若希望增删元素,需要另外创建一个集合
List<String> list1 = new ArrayList<String>();
list1.addAll(list);
list1.add("four");
System.out.println();
System.out.println(list1);
}
}
打印:
[one, 2, three]
one 2 three
[one, 2, three, four]
数组排序,Collections 的 sort 方法,
Collections 是工具类
Collection 是一个集合接口
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;
* 排序集合元素
* 排序集合使用的是集合的工具类Collections的静态方法sort。
* 排序仅能对List集合进行,因为Set部分实现类是无序的。
public class Demo8 {
public static void main(String[] args) {
List<Integer> list = new ArrayList<Integer>();
Random random = new Random();
for(int i=0; i<10; i++) {
list.add(random.nextInt(100));
}
System.out.println(list);
* 对集合进行自然排序,从小到大
Collections.sort(list);
System.out.println(list);
}
}
打印:
[57, 45, 48, 72, 74, 64, 85, 24, 3, 3]
[3, 3, 24, 45, 48, 57, 64, 72, 74, 85]
sort方法的侵入性
public class Demo1 implements Comparable{
@Override
public int compareTo(Object arg0) {
return 0;
}
}
* 对于对象来说,
* sort方法要求集合元素必须实现Comparable接口,该接口用于规定实现类是可以比较的。
* 其中有一个抽象方法是用来定义比较大小的规则。
*
* 当实现了Comparable接口后,需要重写下面的方法
* 该方法的作用是定义当前接口与给定对象比较大小的规则。
*
* 返回值为一个int值,该值表示大小关系。它不关注具体的取值是多少,而关注的是取值范围。
* 当返回值>0时:当前对象比参数对象大
* 当返回值<0时:当前对象比参数对象小
* 当返回值=0时,两个对象相等。
* 我们想使用sort方法排序集合,但是该方法要求我们的集合元素
* 必须实现Comparable借口并且定义比较规则,这种我们想使用
* 某个功能,而它要求我们修改程序的现象称为”倾入性“。
* 修改的代码越多,侵入性越强,越不利于程序的扩展。
可以使用重载的sort方法,侵入性不是很大
实现Comparable接口,TreeSet利用比较方法排序元素
package demo;
public class Student implements Comparable{
private String no;
private int age;
public Student(String no, int age) {
this.no = no;
this.age = age;
}
public String getNo() {
return no;
}
public void setNo(String no) {
this.no = no;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student [no=" + no + ", age=" + age + "]";
}
@Override
public int compareTo(Object o) {
System.out.println("调用compareto方法");
if(o == null) {
return 1;
}
if(o instanceof Student) {
Student s = (Student)o;
return s.getNo().compareTo(no);
}
return 1;
}
}
TreeSet排序,也可以使用ComParator比较器,传入到TreeSet中
package demo;
import java.util.Iterator;
import java.util.TreeSet;
public class TreeSetDemo {
public static void main(String[] args) {
TreeSet<Student> ts = new TreeSet<Student>();
ts.add(new Student("tom",360));
ts.add(new Student("tom1",40));
Iterator<Student> it = ts.iterator();
while(it.hasNext()) {
System.out.println(it.next());
}
}
}
打印排序结果:
调用compareto方法
调用compareto方法
Student [no=tom1, age=40]
Student [no=tom, age=360]
队列,先进先出,入队-->offer,出队-->poll,取值-->peek
import java.util.LinkedList;
import java.util.Queue;
* java.util.Queue
* 队列也可以存放一组元素,但是存取元素必须遵循先进先出原则。
public class Demo2 {
public static void main(String[] args) {
* LinkedList也实现了队列接口,因为它可以保存一组元素,
* 并且首尾增删快,正好符合队列的特点。
Queue<String> queue = new LinkedList<String>();
queue.offer("one");
queue.offer("two");
queue.offer("three");
System.out.println(queue);
* E poll()
* 出队操作,从队首获取元素,获取后该元素就从队列中被删除了
String str1 = queue.poll();
System.out.println(str1);
System.out.println(queue);
System.out.println("--------------------");
* E peek()
* 引用队首元素,但是不做出队操作。
String str2 = queue.peek();
System.out.println(str2);
System.out.println(queue);
}
}
打印:
[one, two, three]
one
[two, three]
--------------------
two
[two, three]
栈,先进后出,入栈-->push,出栈-->pop,取值-->peek
import java.util.Deque;
import java.util.LinkedList;
* 栈
* 存储一组元素,但是存取元素必须遵循先进后出原则。
* 通常为了实现后退这类功能时会使用栈
public class Demo3 {
public static void main(String[] args) {
* java.util.Deque
* 双端队列,两端都可以进出队。
* 当只调用从一端进出队操作时,就形成了栈结构。
* 因此,双端队列为栈提供了两个方法:push,pop
Deque<String> stack = new LinkedList<String>();
* void push(E e)
* 入栈操作,最后入栈的元素在栈顶(第一个元素的位置)
stack.push("one");
stack.push("two");
stack.push("three");
System.out.println(stack);
* 出栈操作
* E pop()
String str = stack.pop();
System.out.println(str);
System.out.println(stack);
* 取第一个值
* E peek()
}
}
打印:
[three, two, one]
Map,类似于python中的字典,key-value形式,无序,key不可重复
Map接口定义的集合又称查找表
import java.util.HashMap;
import java.util.Map;
* java.util.Map
* Map看起来像是一个多行两列的表格。
* 以key-value对的形式存放元素。
* 在Map中可以不允许重复(重复是依靠key的equals判断)
* 常用的实现类为:HashMap
public class Demo1 {
public static void main(String[] args){
Map<String,Integer> map = new HashMap<String,Integer>();
* V put(K k,V v)
* 将给定的key-value对存入Map
* 由于Map要求key不允许重复
* 所以使用Map已有的key存入一个新的value时的操作是替换value,
* 那么返回值为该key原来对应的value。
* 若是一个新的key,则返回值为null。
map.put("语文", 99);
map.put("数学", 88);
map.put("英语", 56);
--------- 这里最好用包装类来引用,如果用 int 可能会引发空指针异常
Integer value = map.put("物理", 80);
System.out.println(value);
System.out.println(map);
System.out.println(map.put("语文",60));
System.out.println(map);
}
}
打印:
null
{物理=80, 语文=99, 英语=56, 数学=88}
99
{物理=80, 语文=60, 英语=56, 数学=88}
get,remove 方法
* V get(k k)
* 根据给定的key获取对应的value,若当前Map中没有给定的key,
* 则返回值为null
Integer value = map.get("数学");
System.out.println(value);
Integer novalue = map.get("化学");
System.out.println(novalue);
* V remove(K k)
* 删除给定的key所对应的key-value对。
* 返回值为被删除的key-value对中的value。
遍历Map的三种方式,key,key-value,value
* 遍历Map有三种方式:
* 遍历所有的key
* 遍历所有的key-value对
* 遍历所有的value(相对不常用)
import java.security.KeyStore;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class Demo2 {
public static void main(String[] args){
Map<String, Integer> map = new HashMap<String, Integer>();
map.put("语文",95);
map.put("数学",58);
map.put("英语",96);
System.out.println(map);
* 遍历所有的key
* Set<K> keyset()
* 该方法会将当前Map中所有的key存入一个Set集合后返回。
* 那么遍历该集合就等于遍历了所有的key
Set<String> keyset = map.keySet();
for(String str:keyset){
System.out.println("key = " + str);
}
System.out.println("------------------");
* 遍历每一组键值对
* Map中每一组键值对都是由Map的内部类:
* java.util.Map.Entry的一个实例表示的。
* Entry有两个方法:getKey,getValue,可以分别获取
* 这一组键值对中的 key 与 value。
* Set<Entry> entrySet
* 该方法会将Map中每一组键值对(Entry实例)存入一个Set集合后返回。
Set<Map.Entry<String,Integer>> entrySet = map.entrySet();
for(Map.Entry<String,Integer> e:entrySet){
String key = e.getKey();
Integer value = e.getValue();
System.out.println(key + ":" + value);
}
System.out.println("------------------");
* 遍历所有的value
* Collection values()
* 该方法会将当前Map中所有的value存入一个集合后返回。
Collection<Integer> values = map.values();
for(Integer value : values){
System.out.println("value:" + value);
}
}
}
打印:
{语文=95, 英语=96, 数学=58}
key = 语文
key = 英语
key = 数学
------------------
语文:95
英语:96
数学:58
------------------
value:95
value:96
value:58
HashMap 要点
* 当一个类的实例作为HashMap的key时,它的equals方法与hashcode方法
* 的重写直接影响着散列表(HashMap)的查询性能。
* 在API文档中Object对这两个方法的重写做了说明:
* 当我们重写一个类的equals方法时,就应当连同重写hashcode方法。
* 这两个方法重写应当遵循:
* 1. 一致性,当两个对象equals比较为true时,hashcode方法返回的数字必须相等。
* 反过来虽然不是必须的,但也应当遵循,否则在HashMap中会形成链表影响查询性能。
* 2. 稳定性,hashcode方法多次调用后返回的数字应当相同,不应是一个变化的值,
* 除非参与equals比较的属性发生了改变。
* 当HashMap的size占到整个长度的0.75时,HashMap会扩容一倍,所有数据重新计算位置
* 这样会影响性能,可以在创建HashMap时指定创建长度 number
* Map<String, Integer> map = new HashMap<String, Integer>(number);
变长参数 String...
变长参数必须是方法的最后一个参数
public void addTels(String s1, String... str);
for(String tel : tels) {
this.tels.add(tel);
}
}
ArrayList --查询快,写入慢,
LinkList --链表,手拉手
Vector --线程安全
HashMap --线程不安全
HashTable --线程安全
TreeMap --对键进行排序,排序原理与TreeSet相同
数组的copy
基本类型复制是用副本
引用类型是地址