10.13-队列、Collections工具类与内部类
ArrayList
与Vector
差异
ArrayList
与Vector
差异ArrayList
是在Java1.2版本以后采用变长数组算法实现的,线程不安全,但效率高速度快Vector
在Java1.0版本出现,底层也是采用变长数组算法实现的,线程安全但效率低
ArrayList
和LinkedList
差异
ArrayList
和LinkedList
差异ArrayList
是采用变长数组算法来实现的,更适合查询数据LinkedList
是采用双向链表结构来实现的,更适合频繁的增删操作
新循环(增强for循环[for each])
JDK1.5版本后的新特性。
语法
for(元素类型 e:集合/数组){
//循环体
}
新循环有别于传统循环,其出现的目的是用于简化遍历集合/数组的。
例子
package day10_13;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class ForEachDemo {
public static void main(String[] args) {
String[] array = {"a","b","c","d","e"};
//传统方式
for(int i=0;i<array.length;i++) {
System.out.println(array[i]);
}
//新循环方式
for(String str:array){
System.out.println(str);
}
List<String> list= new ArrayList();
list.add("one");
list.add("two");
list.add("three");
//传统方式
for(int i=0;i<list.size();i++) {
System.out.println(list.get(i));
}
//迭代器方式
Iterator<String> it = list.iterator();
while(it.hasNext()) {
System.out.println(it.next());
}
//新循环方式
for(String s:list) {
System.out.println(s);
}
/*
* 新循环是通过迭代器实现的
* Java在编译时,会将新循环转换为迭代器的方式
* 那么在新循环遍历集合时,同样也不可以通过集合的方法增删元素
*/
}
}
队列(Queue)
队列也是用于保存一组数据的,但与数组和集合不一样的是,队列存取元素必须遵循先进先出的原则(FIFO)
LinkedList具有存取效率高的特点,所以Java使用该类作为队列的实现类来使用
队列的遍历是一次性的,想要获取队列中的某个元素,就必须先将改队列中该元素之前的所有元素取出后才可以访问与使用
队列中的方法
boolean offer(E e)
向队列末尾增加新元素(入队操作)
E pool()
获取并删除队首元素(出队操作)
E peek()
仅获取队首元素,但不将其从队列中删除
package day10_13;
import java.util.LinkedList;
import java.util.Queue;
public class QueueDemo {
/**
* 队列遵循先进先出原则
*/
public static void main(String[] args) {
Queue<String> queue = new LinkedList<>();
//入队操作
queue.offer("one");
queue.offer("two");
queue.offer("three");
queue.offer("four");
System.out.println(queue);
//打印队列长度
System.out.println(queue.size());
//获取队首元素(不同时删除)
System.out.println(queue.peek());
/*
* E poll()
* 如果队列中不包含任何元素,那么此方法会返回null
*/
//for循环
// for(int i=queue.size();i>0;i++) {
// System.out.println(queue.poll());
// }
// System.out.println(queue.poll());
//while循环
// String str = null;
// while((str=queue.poll())!=null) {
// System.out.println(str);
// }
//新循环,遍历完成后队列内仍存在
for(String e:queue) {
System.out.println(e);
}
System.out.println(queue);
}
}
双端队列(Deque)
双端队列指的是队列两端都可以出队/入队
当我们使用双端队列来存取元素且只从一侧操作时,就形成了一种存取模式:先进后出;这是一种经典的数据结构:栈结构。
使用栈结构通常是为了操作具有可追溯性,例如常见的后退功能。
package day10_13;
import java.util.Deque;
import java.util.LinkedList;
public class DqueDemo {
/**
* 双端队列
* 该队列两端都可以出/入队
* 当我们只从一端操作时,就实现了栈结构(FILO)
*/
public static void main(String[] args) {
Deque<String> stack= new LinkedList<>();
/*
* void push(E e)
* 向栈中压入元素(压栈/入栈操作)
*/
stack.push("one");
stack.push("two");
stack.push("three");
stack.push("four");
System.out.println(stack);//[four, three, two, one]
//获取栈顶元素 peek()
System.out.println(stack.peek());//four
/*
* E pop()
* 获取栈顶元素,同时从栈中移除该元素
* 当栈中不包含元素时,调用此方法会抛出异常(NoSuchElementException)
*/
for(int i=stack.size();i>0;i--) {
System.out.println(stack.pop());
}
System.out.println(stack);
}
}
Collections工具类
Collections是集合的工具类
sort()方法
静态方法sort()用于针对List集合的元素排序
默认比较规则
Comparable接口:该接口的实现类具备可比较性
实现该接口必须重写其中的compareTo()
方法,该方法用于定义具体的比较规则
返回值
返回的证书并不关心具体值的大小,关心的是取值范围
当返回值>0 当前对象比给定对象大
当返回值<0 当前对象比给定对象小
当返回值=0 当前对象与给定对象相等
例子
比较队列中点到原点的距离,并根据距离排序队列
首先,创建Point类
package day10_13;
/**
* Point作为Comparable接口的实现类,
* 该接口的实现类是具有可比较性的
*
*/
public class Point implements Comparable<Point>{//点类
private int x;
private int y;
public Point(int x, int y) {
super();
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
@Override
public String toString() {
return "(" + x + ", " + y + ")";
}
@Override
//覆盖比较规则
public int compareTo(Point o) {//this
int thisLen= this.x*this.x+this.y*this.y;
int oLen= o.x*o.x+o.y*o.y;
return thisLen-oLen;
}
}
其次,创建SortDemo测试类
package day10_13;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class SortDemo {
/**
* 排序集合
* Collections是集合的工具类
* 其中的静态方法sort()用于排序集合中的元素的
* 这里排序仅针对于List集合
*/
public static void main(String[] args) {
List<Point> list= new ArrayList<>();
list.add(new Point(1,5));
list.add(new Point(3,4));
list.add(new Point(2, 2));
System.out.println(list);
/*
* 报错原因:
* list集合中的Point对象不具备可比较性
*/
Collections.sort(list);
System.out.println(list);
}
}
临时比较规则
待补充
内部类
将一个类声明在类体当中,这样的类叫内部类
分类
根据位置的不同,Java的内部类分为四种
静态内部类
使用static来修饰,声明在类体中
静态内部类可以访问外部类的静态成员
成员内部类
声明在类体中,不使用static修饰,具有类的成员特征,也就是必须有外部类的实例才能创建成员内部类的实例
成员内部类可以访问共享外部类的成员变量
局部内部类
把类声明在方法中(很少见)
匿名内部类
匿名内部类非常常见,可以写在任何地方,就是一般语句
语法更像创建对象
new Comparator<String>(){}
匿名类是对原类的一个继承,同时还创建了原类的子类实例,
{}
就是继承以后的类体,类体中可以使用所有类的语法匿名内部类中不能书写构造器
匿名类可以从抽象类或接口中继承、实现,必须提供抽象方法的实例
例子-静态内部类
package day05;
//import day05.Foo.Koo;
//静态内部类
public class StaticInnerClassDemo01 {
public static void main(String[] args) {
//类名全称
Foo.Koo koo = new Foo.Koo();
System.out.println(koo.add());
}
}
/*
* Koo就是Foo的静态内部类,Foo就相当于是Koo的包
* 为Koo声明了一个命名空间,静态内部类的作用域
* 类似于静态变量,类加载以后就已经存在了,可以
* 在静态内部类中访问外部类的静态成员
*/
class Foo{
int a = 1;
static int b = 2;
static class Koo{
int add() {
return 1+b;
}
}
}
例子-成员内部类
package day05;
import day05.Goo.Moo;
//成员内部类
public class InnerClassDemo {
public static void main(String[] args) {
/*
* 成员变量必须有外部类的实例才能调用
* 若想创建成员内部类的实例必须要先创建
* 外部类的实例
*/
Goo goo1 = new Goo();
Moo moo1 = goo1.new Moo();
System.out.println(moo1.add());
Goo goo2 = new Goo();
goo2.a = 3;
Moo moo2 = goo2.new Moo();
System.out.println(moo2.add());
}
}
/*
* Moo就是Goo的成员内部类,但是不加static修饰,成员
* 内部了就是普通的内部类,成员内部类与实例变量具有
* 相同的作用域
*/
class Goo{
int a = 1;
static int b = 2;
class Moo{
int add() {
//成员内部类的优点:可以共享外部类的成员变量
return a+b;
}
}
}
例子-局部内部类
package day10_13;
import java.util.Arrays;
import java.util.Comparator;
//局部内部类
public class LocalInnerClassDemo {
public static void main(String[] args) {
/*
* 在方法中声明的类就是一个局部内部类
* 在局部内部类中,可以访问共享外部方法的局部变量
* 但是局部变量必须是final修饰的
* 在JDK1.8以后final可以省略不写
*/
/*final*/ int a = 2;
class Foo{
int b=1;
public int add() {
return a+b;
}
}
Foo foo = new Foo();
System.out.println(foo.add());
String[] names= {"Jack","Jerry","Tom","Li","Anna"};
//定义局部内部类(定义临时比较规则)
class foo1 implements Comparator<String>{
@Override
public int compare(String o1, String o2) {
char o1LastChar = o1.charAt(o1.length()-1);
char o2LastChar = o2.charAt(o2.length()-1);
return o1LastChar-o2LastChar;
}
}
Arrays.sort(names, new foo1());
System.out.println(Arrays.toString(names));
}
}
例子-匿名内部类
package day10_13;
public class AnnInnerClassDemo01 {
public static void main(String[] args) {
/*
* 匿名内部类
* new Xoo(){}是对Xoo这个原类的继承
* 同时创建了Xoo这个原类的子类对象
* {}就是子类的类体
*/
Xoo xoo = new Xoo() {
int a = 1;
public String toString() {
return "I am Xoo Son";
}
};
System.out.println(xoo);
}
}
class Xoo{
}
例子-匿名内部类继承
匿名内部类可以继承抽象类或者实现接口
package day10_13;
//匿名内部类可以继承抽象或实现接口
public class AnnInnerClassDemo02 {
public static void main(String[] args) {
int a = 1;
//从抽象类继承的匿名内部类
Yoo yoo = new Yoo() {
int add() {
return 1+a;
}
};
System.out.println(yoo.add());
//从接口实现的匿名内部类
Koo koo = new Koo() {
public int add() {
return 1+a;
}
};
System.out.println(koo.add());
}
}
//抽象类
abstract class Yoo{
abstract int add();
}
//接口
interface Koo{
int add();
}
任何的内部类都会被编译成独立的.class文件
内部类最大的作用是"封装"
最后更新于