10.24
内存管理
由JVM来管理
1.内存管理:
-
堆:
-
存储new出来的对象(包括实例变量,数组的元素)
-
垃圾:没有任何引用所指向的对象(垃圾回收期GC会不定时到内存中清扫垃圾),回收过程透明的,不一定一发现垃圾就立刻回收,通过调用System.GC可以建议虚拟机尽快调度GC来回收
-
实例变量的生命周期
- 创建对象时存储在堆中,对象被回收时一并回收
-
内存泄漏:
- 不再使用的内存还没有被及时的回收就叫泄漏
- 建议:不再使用的对象应及时将引用设置为null
-
-
栈:
- 存储正在调用的方法中的局部变量(包括方法的参数)
- 调用方法时,会在栈中为该方法分配一块对应的栈帧,栈帧中存储局部变量(包括方法中的参数),方法调用结束时,栈帧会自动清理,局部变量一并被清除。
- 局部变量的生命周期:
- 调用方法时存储在栈中,方法调用结束时与栈帧一并被清除
-
方法区:
- 存储.class字节码文件(包括静态变量,所有方法),只存储一份
- 方法只有一份,用this来区分具体的调用对象
面向对象三大特征
-
封装:
- 类:封装的是对象的属性和行为
- 方法:封装的是具体的业务逻辑功能实现
- 访问控制修饰符:封装的是具体的访问权限同时也保护了数据安全
-
继承(体现在重写和重载上):
-
作用:代码复用
-
超类:所有派生类说共有的属性和行为
接口:部分派生类所共有的属性和行为
派生类/实现类/子类:派生类所特有的属性和行为
-
单一继承,多接口实现,具有传递性
-
-
多态:多种形态
-
所有对象都是多态的——通过向上造型来体现
所有抽象方法都是多态的——通过方法的重写来体现
-
向上造型、强制类型转换(向下转换)
-
-
String字符串类型:
- java.lang.String类使用final修饰,不能被继承
- String的底层封装是一个字符数组
- String在内存中采用的是Unicode编码格式,每个字符占用两个字节的空间
- 字符串对象一旦创建,对象内容无法改变,但是字符串引用可以重新赋值
- 将String称为不变对象
-
字符串常量池:
-
java对String字符串有一个优化方式:字符串常量池
-
java推荐我们使用字面量/直接量(直接“”)的方式创建字符串对象,并且会缓存所有以字面量方式创建的字符串对象到常量池中,
当使用相同字面量再创建字符串对象时将会复用常量池中的对象,以减少内存的开销
/** 使用字面量来创建字符串对象时,JVM会检查常量池中是否有该对象 若没有,则会创建字符串对象,并将其引用存入到常量池中 若有,则直接将常量池中的对象(引用)返回,并不会创建新的字符串对象 */ String s1 = "123abc"; String s2 = "123abc"; String s3 = "123abc"; /**引用类型==,比较的是地址是否相同--这是规定*/ sout(s1==s2); sout(s2==s3); s1 = s1+"!"; //用拼接方式创建新的字符串对象 并将地址赋给s1 System.out.println(s1 == s2);//false String s1 = "123abc";//堆中创建“123abc”字面量对象,并缓存到常量池中 String s2 = "123"+"abc";//编译器在编译时,若发现时两个字面量相连,则会直接连接好并将对象保存起来 System.out.println(s1 == s2)//复用常量池中的对象 String s3 = "123" String s4 = s3 + "abc";//s3是一个变量,所以在编译期不会直接编译好,所以创建一个新的对象存储123abc System.out.println(s1 == s4);
-
10.24补充
public class Test {
public static void main(String[] args) {
Aoo o1=new Aoo();
Boo o2 = new Boo();
Aoo o3 = new Boo();
}
}
class Aoo{
static {
System.out.println("我是静态块");
}
{
System.out.println("我是语句块");
}
Aoo(){
System.out.println("我是构造方法");
}
}
class Boo extends Aoo{
static {
System.out.println("我是Boo静态块");
}
{
System.out.println("我是Boo语句块");
}
Boo(){
System.out.println("我是Boo静态方法");
}
}
输出结果:
-
只输出Aoo o1 = new Aoo()
我是静态块
我是语句块
我是构造方法 -
只输出Boo o2 = new Boo();
我是静态块
我是Boo静态块
我是语句块
我是构造方法
我是Boo语句块
我是Boo静态方法 -
只输出Aoo o3 = new Boo();
我是静态块
我是Boo静态块
我是语句块
我是构造方法
我是Boo语句块
我是Boo静态方法
总结:超类静态块>派生类静态块>超类语句块>超类静态方法>派生类语句块>派生类静态方法
文档注释
- 是一种功能性的注释,用于描述某个东西
10.25
String的常用方法
- length():获取字符串长度
- trim():消除字符串两端的空白字符
- boolean startsWith(String s)/boolean endsWith(String s):判断指定的字符串是否为字符串的开头或结尾
- toUpperCase/toLowerCase():将当前字符串的英文部分全部转换为大小写,比如验证码不区分大小写
- charAt();字符串具体的位置是哪一个字符
- IndexOf();/lastIndexOf(); 检索指定字符串在当前字符串中第一次或最后一次出现的位置
- substring(); (包头不包尾)截取当前字符串中指定范围的字符串
- 静态方法 valueOf() 将其它数据类型转化为String
StringBuilder
- 由于String是不变对象,每次修改都会创建新的对象,因此String不适合频繁修改操作,为了解决这个问题就提供了StringBuilder类
- StringBuilder是专门用于修改字符串的一个类,内部维护一个可变的char数组,所做操作都是在这个数组之上进行的,修改速度、性能优秀,并且提供了修改字符串的常见方式:增删插改。
StringBuilder常用方法
-
append():追加内容——增
-
delete():删除部分内容——删
-
replace():替换部分内容——改
-
insrt():插入内容——插
补充
-
数组是length类型,String字符串是length方法
-
字符串内容若是需要查看,则建议String——————实际应用一般都是查看
字符串内容若需要频繁修改,则建议StringBuilder
-
StringBuilder和StringBuffer的区别:——————常见面试题 周五讲
getter/setter
public class Point {
/*
数据私有,设计getter/setter的原因:
1)很多框架都是基于getter/setter来配置获取数据的,可以理解为它是一种行业的标准
2)getter/setter时可以对数据进行控制,而public权限时无法对数据进行控制
3)getter/setter并非一定要同时出现,可以只getter或只setter,需要根据需求自行选择
*/
private int x;
private int y;
public int getX(){ //getter
return x;
}
public void setX(int x){ //setter
this.x = x;
}
public int getY(){
return y;
}
public void setY(int y){
this.y = y;
}
}
public class GetterSetterDemo {
public static void main(String[] args) {
Point p = new Point();
p.setX(100);
p.setY(200);
System.out.println(p.getX()+","+p.getY());
}
}
10.25晚间
面试自我介绍
10.26
正则表达式
- 用于描述字符串的内容格式,使用它通常用于匹配一个字符串是否符合格式要求
- 正则表达式语法:(只用记不用深入)
1.[]:表示一个字符,该字符可以是[]中指定的内容
例如:2.预定义字符:
.:表示任意一个字符,没有范围限制
\d:表示任意一个数字,等同于[0-9]
\w:表示任意一个单词字符,等同于a-zA-Z0-9_----单词字符指字母、数字和_
\s:表示任意一个空白字符
\D:不是数字
\W:不是单词字符
\S:不是空白字符
3.量词:
?:表示前面的内容出现0-1次
例如: abc? 可以匹配:a 或 b 或 c 或什么也不写
但是不能匹配:m或aaa
+:表示前面的内容最少出现1次
例如: abc+ 可以匹配:b或aaaaaaaaaa…或abcabcbabcbabcba…
但是不能匹配:什么都不写 或 abcfdfsbbaqbb34bbwer…
:表示前面的内容出现任意次(0-多次)—匹配内容与+一致,只是可以一次都不写
例如: abc 可以匹配:b或aaaaaaaaaa…或abcabcba…或什么都不写
但是不能匹配:abcfdfsbbaqbb34bbwer…
{n}:表示前面的内容出现n次
例如: abc{3} 可以匹配:aaa 或 bbb 或 aab 或abc 或bbc
但是不能匹配: aaaa 或 aad
{n,m}:表示前面的内容出现最少n次最多m次
例如: abc{3,5} 可以匹配:aaa 或 abcab 或者 abcc
但是不能匹配:aaaaaa 或 aabbd
{n,}:表示前面的内容出现n次以上(含n次)
例如: abc{3,} 可以匹配:aaa 或 aaaaa… 或 abcbabbcbabcba…
但是不能匹配:aa 或 abbdaw…
4.()用于分组,是将小括号里面的内容看做是一个整体
例如: (abc){3} 表示abc整体出现3次. 可以匹配abcabcabc
但是不能匹配aaa 或abc 或abcabccba
(abc|def){3}表示abc或def整体出现3次.
可以匹配: abcabcabc 或 defdefdef 或 abcdefabc
但是不能匹配abcdef 或abcdfbdef
String支持的正则表达式的相关方法
-
matches(String regex):使用给定的正则表达式验证当前字符串的格式是否符合要求,若符合则返回true,否则返回false
public class MatchesDemo { public static void main(String[] args) { /* 邮箱正则表达式: [a-zA-Z0-9_]+@[a-zA-Z0-9]+(\.[a-zA-Z]+)+ 注意: \.中的\是正则表达式中的转义符 \\.中的第1个\,是在转义正则表达式中的\ */ String email = "wangkj@tedu.cn"; String regex = "[a-zA-Z0-9_]+@[a-zA-Z0-9]+(\\.[a-zA-Z]+)+"; //使用regex匹配email是否符合格式要求 boolean match = email.matches(regex); if(match){ System.out.println("是正确的邮箱格式"); }else{ System.out.println("不是正确的邮箱格式"); } } }
-
replaceAll():将当前字符串中满足正则表达式的部分给替换为给定的字符串
public class ReplaceAllDemo { public static void main(String[] args) { String line = "abc123def456ghi78"; //将数字部分给替换为#NUMBER# line = line.replaceAll("[0-9]+","***"); System.out.println(line); } }
-
String[] split():将当前字符串按照满足正则表达式的部分进行拆分,将拆分出的以String[]形式来返回
public class SplitDemo { public static void main(String[] args) { String line = "abc123def456ghi"; String[] data = line.split("[0-9]+"); //按数字拆分(数字就拆没了) System.out.println(Arrays.toString(data)); //将data数组转换为字符串并输出 line = "123.456.78"; data = line.split("\\."); //按.拆(.就拆没了) System.out.println(Arrays.toString(data)); //最开始就是可拆分项(.),那么数组第1个元素为空字符串-----------"" //如果连续两个(两个以上)可拆分项,那么中间也会拆出一个空字符串----"" //如果末尾连续多个可拆分项,那么拆出的空字符串被忽略 line = ".123.456..78........"; data = line.split("\\."); //按.拆(.就没有了) System.out.println(Arrays.toString(data)); System.out.println(data.length); //5 } }
object(toString,equals)
-
所有类的鼻祖,所有类都直接或间接继承了Object,万物皆对象
-
object中有两个经常被派生类重写的方法
-
toString:调用object的toString时默认会返回类的全称@地址,没有参考意义,所有我们常常重写toString()来返回具体的属性值
注意:String,StringBuilder已经重写了toString()类型
-
调用object的equals()内部还是在比较地址,若想比较对象的属性值是否相同,我们认为Object的equals()并不能满足需求,因此常常需要重写equals()
注意:
- String已经重写了toString()类型,但是StringBuilder没有重写
- 重写equal()的基本原则:
- 原则上要比较两个对象的属性值是否相同
- 两个对象必须是同一类型的,若类型不同则返回false
-
包装类(使基本类型向引用类型转换)
-
java定义了8个包装类,目的就是为了解决基本类型不能直接参与面向对象的问题,使基本类型可以通过包装类的形式出现
-
包括:Integer,Character,Byte,Short,Long,Float,Double,Boolean,其中Charater和Boolean是直接继承自Object的,其余六个包装类继承自
java.lang.Number类
- 以下代码是Interger中的底层源码IntegerCache,当Integer i2 = 100时 cache数组会从里面返回一个100,当Integer i1 = 100时 cache数组会从里面返回一个100 所以两者i1 == i2 ,100换成200时则错误
private static class IntegerCache { static final int low = -128; static final int high; static final Integer cache[]; static { // high value may be configured by property int h = 127; String integerCacheHighPropValue = sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high"); if (integerCacheHighPropValue != null) { try { int i = parseInt(integerCacheHighPropValue); i = Math.max(i, 127); // Maximum array size is Integer.MAX_VALUE h = Math.min(i, Integer.MAX_VALUE - (-low) -1); } catch( NumberFormatException nfe) { // If the property cannot be parsed into an int, ignore it. } } high = h; cache = new Integer[(high - low) + 1]; int j = low; for(int k = 0; k < cache.length; k++) cache[k] = new Integer(j++); // range [-128, 127] must be interned (JLS7 5.1.7) assert IntegerCache.high >= 127; }
Integer i1 = new Integer(500); // Integer i2 = new Integer(500); // System.out.println(i1 == i2);//false // System.out.println(i1.equals(i2));//true 已经重写了equals()来比较值 // // Integer i3 = Integer.valueOf(500); // Integer i4 = Integer.valueOf(500); // System.out.println(i3 == i4); //false // System.out.println(i3.equals(i4));//true Integer i1 = new Integer(5); Integer i2 = new Integer(5); System.out.println(i1 == i2);//false System.out.println(i1.equals(i2));//true 已经重写了equals()来比较值 //Interger.value()会复用-128到127范围内的数据————使用valueOf()更多一些 Integer i3 = Integer.valueOf(5); Integer i4 = Integer.valueOf(5); System.out.println(i3 == i4); //true System.out.println(i3.equals(i4));//true
-
jdk1.5推出了一个新的特性:自动拆装箱。当编译器编译时若发现时基本类型与包装类型之间的相互赋值,则自动补齐代码完成转换工作,这个过程叫做自动拆装箱
//触发了一个自动装箱的特性,会被编译为:Integer i = Integer.valueOf(5); Integer i = 5; //基本类型到包装类型---装箱 //触发了自动拆箱的特性,会被编译为:int j = i.intValue(); int j = i;//包装类型到基本类型---拆箱
补充
- 常见面试题:
- ==和equals()的区别:
- ==可以作用于基本类型和引用类型
- ==作用于基本类型,是在比较值是否相同
- ==作用于引用类型,实在比较地址是否相同
- equals()只能作用于引用类型
- 若没有重写equals(),则默认调用的是Object类的equals()来比较地址是否相同,若想比较对象的属性值是否相同,需要重写equals()方法。在java中String重写了equals()来比较字符串内容是否相同
- ==可以作用于基本类型和引用类型
- ==和equals()的区别:
10.27
集合
-
什么是集合
- 集合和数组一样,可以保存一组数据,并且提供了操作集合元素的相关方法,使用更方便(与数组相比更方便不需要缩容扩容,但是数组效率更高)
-
java集合框架中的相关接口:
-
java.util.Collection接口:是所有集合的顶层接口,封装了所有集合所共有的方法,下面有很多种实现类,因此我们可有更多的数据结构选择
Object封装了所有类所共有的方法 Collection所有集合所共有的方法
-
Collection接口下还有两种常见的子接口:
- java.util.List:线性表,是可以重复的集合,并且有序
- java.util.Set:不可重复集合,大部分实现类是无序的
-
-
Collection常用方法(集合中重写了Object的toString()方法)
-
add():向集合中添加一个元素,成功添加则返回true
-
size():返回当前集合的元素个数
-
isEmpty():判断当前集合是否为空集,当且仅当size()为0时返回true
-
clear():清空集合
public class CollectionDemo { public static void main(String[] args) { Collection c = new ArrayList(); c.add("one"); c.add("two"); c.add("three"); c.add("four"); c.add("five"); //集合中重写了Object的toString()方法,格式如下: //[元素1.toString(), 元素2.toString(), 元素3.toString(), ......] System.out.println(c); System.out.println("size:"+c.size()); //5,输出集合的元素个数 //isEmpty()判断集合是否是空集(size()为0表示为空集) System.out.println("是否是空集:"+c.isEmpty()); //false c.clear(); //清空集合 System.out.println("集合已清空"); System.out.println(c); System.out.println("size:"+c.size()); //0 System.out.println("是否为空集:"+c.isEmpty()); //true } }
-
contains():判断集合是否包含给定元素
-
boolean remove():从集合中删除给定元素,成功删除则返回true。从当前集合中删除与给定元素equals比较为true的元素,若存在重复元素则只删除一次
public class CollectionDemo { public static void main(String[] args) { Collection c = new ArrayList(); c.add(new Point(1,2)); c.add(new Point(3,4)); c.add(new Point(5,6)); c.add(new Point(7,8)); c.add(new Point(9,0)); c.add(new Point(1,2)); System.out.println(c); Point p = new Point(1,2); /** * boolean contains(Object o) * 判断当前集合是否包含给定元素(o) * 判断依据是给定元素是否与集合元素存在equals比较为true的情况 */ boolean contains = c.contains(p); System.out.println("是否包含:"+contains); /** * boolean remove(Object o) * 从当前集合中删除与给定元素equals比较为true的元素 * 若存在重复元素则只删除一次 */ c.remove(p); System.out.println(c); //集合中存放的是元素的引用 Collection cc = new ArrayList(); Point pp = new Point(1,2); cc.add(pp); //将pp添加到集合c中----将pp的引用装在了cc中 System.out.println("pp:"+pp); //(1,2) System.out.println("cc:"+cc); //[(1,2)] pp.setX(100); System.out.println("pp:"+pp); //(100,2) System.out.println("cc:"+cc); //[(100,2)] } }
-
boolean addAll():将参数组定集合中的元素添加到当前集合中,添加后当前集合发生改变则返回true
-
boolean containsAll():判断当前集合中是否包含参数集合中的所有元素
-
boolean retainAll():只取交集
-
boolean removeAll():删交集取剩下
public class CollectionOperDemo { public static void main(String[] args) { Collection c1 = new ArrayList(); c1.add("java"); c1.add("c++"); c1.add(".net"); System.out.println("c1:"+c1); //c1:[java, c++, .net] Collection c2 = new ArrayList(); c2.add("android"); c2.add("ios"); c2.add("java"); System.out.println("c2:"+c2); //c2:[android, ios, java] c1.addAll(c2); //将c2添加到c1中 System.out.println("c1:"+c1); //c1:[java, c++, .net, android, ios, java] System.out.println("c2:"+c2); //c2:[android, ios, java] Collection c3 = new ArrayList(); c3.add("c++"); c3.add("android"); c3.add("php"); System.out.println("c3:"+c3); //c3:[c++, android, php] boolean contains = c1.containsAll(c3); //判断c1中是否包含c3中的所有元素 System.out.println("包含所有:"+contains); //false //取交集,c1中仅保留c1与c3的共有元素,c3不变 //c1.retainAll(c3); //System.out.println("c1:"+c1); //c1:[c++, android] //System.out.println("c3:"+c3); //c3:[c++, android, php] //删交集,将c1中与c3共有的元素删除,c3不变 c1.removeAll(c3); System.out.println("c1:"+c1); //c1:[java, .net, ios, java] System.out.println("c3:"+c3); //c3:[c++, android, php] } }
-
-
集合的遍历:
- Collection接口提供了统一的遍历集合的方式:迭代器模式。通过iterator()方法可以获取一个用于遍历当前集合元素的迭代器
- java.util.Iterator接口:定义了迭代器遍历集合的相关操作,不同的集合都实现了用于遍历自身元素的迭代器实现类,但是我们无序记住他们的名字,从多态的角度把他们看成iterator即可
- 迭代器遍历遵循的步骤为:问(hasNext())、取(next())、删(remove())
-
增强for循环/新循环:
-
jdk1.5时推出了一个新的特性:增强for循环,也称为新循环,让我们使用相同的语法遍历集合和数组
-
语法:
for(元素类型 变量名 : 集合或数组){循环体}
-
-
泛型:
- jdk1.5时推出的一个新特性
- 泛型也称为参数化类型,允许我们在使用一个类时,传入某个类型来规定其内部的属性、方法参数或返回值类型,使得我们使用时更方便
- 泛型在集合中被广泛使用,用来指定集合中元素的类型
- 若不指定泛型的具体类型,则默认Object
- 若指定了泛型的具体类型,则获取泛型的具体值时,编译器会帮我们补充强转操作
public class GenericDemo { public static void main(String[] args) { Collection<Point> c = new ArrayList<>(); c.add(new Point(1,2)); c.add(new Point(3,4)); c.add(new Point(5,6)); c.add(new Point(7,8)); Iterator<Point> it = c.iterator(); while(it.hasNext()){ Point p = it.next(); System.out.println(p); } for(Point p : c){ System.out.println(p); } /* Collection<String> c = new ArrayList<>(); c.add("one"); c.add("two"); c.add("three"); c.add("four"); c.add("five"); //c.add(123); //编译错误,123的类型违背了集合c所指定的泛型的实际类型String //迭代器所指定的泛型应当与其遍历的集合的泛型一致 Iterator<String> it = c.iterator(); while(it.hasNext()){ String str = it.next(); System.out.println(str); } for(String str : c){ System.out.println(str); } */ } }
-
集合和数组的转换:
-
集合转换为数组:Collection接口的toArray() 所以是对象.toArray()
public class CollectionToArrayDemo { public static void main(String[] args) { Collection<String> c = new ArrayList<>(); c.add("one"); c.add("two"); c.add("three"); c.add("four"); c.add("five"); System.out.println(c); //[one, two, three, four, five] //若参数数组元素个数==集合元素个数,那就正常转换 //若参数数组元素个数<集合元素个数,那就正常转换(按照集合大小给数组) //若参数数组元素个数>集合元素个数,那就正常转换,同时末尾被默认值 String[] array = c.toArray(new String[6]); System.out.println(Arrays.toString(array)); } }
-
数组转换为集合:Arrays类的静态方法asList(),所以是Arrays.asList()
public class ArrayToCollectionDemo { public static void main(String[] args) { String[] array = {"one","two","three","four","five"}; System.out.println("array:"+Arrays.toString(array)); //asList()方法会返回内部的ArrayList //该ArrayList内部直接引用给定数组array List<String> list = Arrays.asList(array); System.out.println("List: "+list); //对数组操作后,集合也会做相应的改变 array[1] = "six"; System.out.println("array:"+Arrays.toString(array)); System.out.println("List: "+list); //对集合操作后,数组也会做相应的改变 list.set(2,"seven"); //将下标2的元素修改为seven---明天详细讲 System.out.println("array:"+Arrays.toString(array)); System.out.println("List: "+list); //添加元素/删除元素相当于要往数组中加元素/减元素 //而数组是定长的,不会自动扩容/缩容,因此会发生不支持操作的异常 //list.add("!!!!!!"); //运行时发生不支持操作异常 } }
-
10.28
List
-
List接口:
-
继承自Collection接口,List集合是可重复集合,并且有序,并且提供了一套可以通过下标操作元素的方法
-
常见的实现类:
-
java.util.ArrayList:内部使用数组实现,查询性能更好(直接下标查找物理地址),增删性能不太好
-
java.util.LinkedList:内部使用链表实现,查询性能不太好,首尾增删性能好
在对集合操作的增删性能没有特别苛刻的要求时,通常选择ArrayList
-
-
-
List集合常见方法:
-
get():根据下标获取元素
-
set():将指定元素设置到指定位置 ,并返回被替换的元素(用时再接收)
-
重载add():将指定元素添加到指定位置,理解为插入操作
-
重载remove():删除并返回指定位置元素
-
subList(): 原集合修改之后,子集将不能再进行任何操作了,操作则发生并发修改异常,但是可以重新获取子集
public class ListDemo { public static void main(String[] args) { List<String> list = new ArrayList<>(); list.add("one"); list.add("two"); list.add("three"); list.add("four"); list.add("five"); System.out.println("list:"+list); //[one, two, three, four, five] /** * E get(int index): * 获取指定下标所对应的元素 */ String e = list.get(2); //获取第3个元素 System.out.println(e); //three for(int i=0;i<list.size();i++){ System.out.println(list.get(i)); } for(String s : list){ System.out.println(s); } Iterator<String> it = list.iterator(); while(it.hasNext()){ System.out.println(it.next()); } System.out.println("-----------------------------"); /* E set(int index,E e): 将给定元素(e)设置到给定位置(index),返回被替换的元素 */ String old = list.set(2,"six"); //将下标为2的元素设置为six,返回原始元素 //list.set(2,"six"); //常规用法 System.out.println(old); //three System.out.println("list:"+list); //[one, two, six, four, five] /** * void add(int index, E e): * 将给定元素e添加到index所指定的位置,相当于插入操作 */ list.add(3,"three"); //将three插入到下标3的位置 System.out.println("list:"+list); //[one, two, six, three, four, five] /** * E remove(int index): * 删除指定位置元素,并返回该位置对应元素 */ String o = list.remove(2); //删除下标2的元素,并返回对应元素 System.out.println(o); //six System.out.println("list:"+list); //[one, two, three, four, five] } }
public class ListDemo2 { public static void main(String[] args) { List<Integer> list = new ArrayList<>(); for(int i=0;i<10;i++){ list.add(i*10); } System.out.println("list:"+list); //[0, 10, 20, 30, 40, 50, 60, 70, 80, 90] List<Integer> subList = list.subList(3,8); //获取下标3到7的子集 System.out.println("subList:"+subList); //[30, 40, 50, 60, 70] //将子集的每个元素扩大10倍 for(int i=0;i<subList.size();i++) { subList.set(i, subList.get(i) * 10); } System.out.println("subList:"+subList); //[300, 400, 500, 600, 700] //注意:对子集的操作就是对原集合元素的操作 System.out.println("list:"+list); //[0, 10, 20, 300, 400, 500, 600, 700, 80, 90] list.set(3,3000); //将下标为3的元素修改为3000 System.out.println("list:"+list); //[0, 10, 20, 3000, 400, 500, 600, 700, 80, 90] System.out.println("subList:"+subList); //3000, 400, 500, 600, 700 list.remove(0); //删除list中的第1个元素 System.out.println("list:"+list); //[10, 20, 3000, 400, 500, 600, 700, 80, 90] //原集合修改之后,子集将不能再进行任何操作了,操作则发生并发修改异常,但是可以重新获取子集 //System.out.println("subList:"+subList); //运行时并发修改发生异常 /** * java.util.Collections为集合的工具类,包含了集合相关的静态方法 */ Collections.reverse(list); //反转list集合(元素真实改变了) System.out.println("lisi:"+list); } }
-
-
集合的排序:
-
Collections为集合的工具类,里面定义了很多静态方法用于操作集合
public class ListSortDemo { public static void main(String[] args) { List<Integer> list = new ArrayList<>(); Random rand = new Random(); for(int i=0;i<10;i++){ list.add(rand.nextInt(100)); } System.out.println("list原始数据:"+list); Collections.sort(list); //对list集合进行自然排序(从小到大) System.out.println("list排序后数据:"+list); Collections.reverse(list); //反转list集合(数据已经变化了) System.out.println("list反转后:"+list); } }
-
Collections.sort(List list)方法:可以对list集合进行自然排序(从小到大)Collections.sort()方法要求List集合中的元素必须是可比较的,若不可比较则直接发生编译错误,不允许排序。判断是否可比较的标准为元素是否实现了java.util.Comparable接口。实际开发中,我们是不会让我们自己定义的类去实现Comparable接口,因为这对我们的程序有侵入性
侵入性:当我们调用某个API功能时,其要求我们为其修改其它额外代码,这个现象称为侵入性。侵入性越强越不利于我们程序的后期维护
-
建议使用重载的Collections.sort(List list,Comparator c)方法,可以通过Comparator来自定义比较规则
对英文字符串排序时,会按首字母的ASCII码排序 若首字母相同,则比较第2个字符的ASCII码,以此类推
-
public class ListSortStringDemo { public static void main(String[] args) { List<String> list = new ArrayList<>(); list.add("王克晶"); list.add("传奇djflajfdl"); list.add("苍松老师"); System.out.println("list原始数据:"+list); Collections.sort(list, new Comparator<String>() { /* compare()方法用于定义o1和o2比较大小的规则,并用返回值表达大小关系 返回值实现的要求:-------不用纠结,去记下面的结论即可 1)如果返回值>0,则表达的是o1>o2 2)如果返回值<0,则表达的是o1<o2 3)如果返回值=0,则表达的是o1=o2 结论: 1)前面的(o1)-后面的(o2)-----------升序 2)后面的(o2)-前面的(o1)-----------降序 */ public int compare(String o1, String o2) { return o1.length()-o2.length(); //升序 //return o2.length()-o1.length(); //降序 } }); System.out.println("list排序后数据:"+list); }
-
Set
- 继承自Collection接口,元素是不可重复的,并且大部分都是无序的
- 常见的实现类:java.util.HashSet()