throw:在方法中认为抛出一个异常对象,该异常对象可以是自定义的异常,也可以是已存在的异常
(用在方法内)
throws:在方法的声明中使用,使用该方法时必须处理该异常
(用在方法上)
// 自定义异常类
class MyException extends Exception {
public MyException(String message) {
super(message);
}
}
//抛出自定义异常
throw new MyException("This is my exception.");
Java程序中许多对象在运行时会出现两种类型:编译时类型和运行时类型
编译时类型:由声明对象时实用的类型来决定
运行时类型:由实际赋值给对象的类型来决定
例:
Person p = new Student();
编译时类型为Person,运行时类型为Student
java.lang.Class:反射的核心类,Class对象可以获取某个类加载后在堆中的对象及对象属性
获取Class对象的两种方式:
java.lang.reflect.Field:反射类的成员变量,Field 对象可以获取/设置某个类的成员变量
获取Field对象的方式:
Class.getDeclaredField()
方法获取所有的字段对象Field.get()
方法获取字段的值。field.setAccessible(true)
字段若是私有的,需要设置可访问性java.lang.reflect.Method:反射类的方法,Method 对象可以获取某个类的方法信息
获取Method对象的两种方式:
java.lang.reflect.Constructor:反射类的构造方法,Constructor 对象可以获取某个类的构造器
获取Constructio类的两种方式:
获取类的泛型参数,使用Class.getTypeParameters();
获取方法的泛型参数,使用Class.getMethod()和method.getTypeParameters();
获取属性的泛型参数,使用Class.getDeclaredField()和field.getGenericType()和parameterizedType.getActualTypeArguments()
RetentionPolicy.SOURCE | 注解只在源码阶段保留,在编译器进行编译时它将被丢掉 |
---|---|
RetentionPolicy.CLASS | 注解只被保留到编译进行的时候,它并不会被加载到 JVM 中 |
RetentionPolicy.RUNTIME | 注解可以保留到程序运行中的时候,它会被加载进 JVM 中,在程序运行中也可以获取到它们 |
ElementType.ANNOTATION_TYPE | 给一个注解进行注解 |
---|---|
ElementType.CONSTRUCTOR | 给构造方法进行注解 |
ElementType.FIELD | 给属性进行注解 |
ElementType.LOCAL_VARIABLE | 给局部变量进行注解 |
ElementType.METHOD | 给方法进行注解 |
ElementType.PACKAGE | 给包进行注解 |
ElementType.PARAMETER | 给一个方法内的参数进行注解 |
ElementType.TYPE | 给一个类型进行注解,比如类、接口、枚举 |
自定义注解其步骤:
新建注解文件,@interface定义注解
public @interface MyAnnotate{}
添加参数、默认值
public @interface MyAnnotate{
String name( ) default "";
int value( ) default 0;
}
用元注解配置注解
@Retention(RetionPolicy.RUNTIME)
@Target(Element.TYPE)
public @interface MyAnnotate{
String name( ) default "";
int value( ) default 0;
}
public class Outer{
private static int a;
private int b;
public static class Inner{
public void print(){
System.out.println(a);
}
}
}
静态内部类可以访问外部类所有的静态变量和方法,即使是private也能访问到
静态内部类和正常的类一样,可以定义静态变量、方法、构造方法等
其他类使用静态内部类需要使用 外部类.静态内部类
外部类名.内部类名 变量名=new 外部类名.内部类();
Outer.Inner inner = new Outer.Inner();
inner.print();
Java集合类HashMap内部有一个静态内部类Entry,Entry是HashMap存放元素的抽象,HashMap内部维护Entry数组用了存放元素,但是Entry对使用者是透明的。
像这种和外部类关系密切的,且不依赖外部实例的,都可以使用静态内部类
public class Outer{
private static int a;
private int b;
public class Inner{
public void print(){
System.out.println(a);
System.out.println(b);
}
}
}
成员内部类时,语法格式:
外部类名.内部类名 变量名 = new 外部类名().new 内部类名();
Outer.Inner inner = new Outer().new Inner();
外部类名 变量名1 = new 外部类名();
外部类名.内部类名 变量名2 = 变量名1.new 内部类名();
当内部类的变量名和外部类的变量名相同时,优先访问自己的,而想调用外部类的成员,调用方法:外部类名.this.同名成员
外部类的任何成员都可以在成员内部类方法中直接访问
class Outer {
private static int a;
private int b;
public void test(final int c) {
final int d =1;
class Inner {
public void print() {
System.out.println(c);
}
}
//实例化局部内部类
Inner inner = new Inner();
inner.print();
}
}
public class TestClass {
public void Test(Bird bird){
System.out.println(bird.getName()+"能飞"+bird.fly()+"米");
}
public static void main(String[] args) {
TestClass testClass = new TestClass();
testClass.Test(new Bird() {
@Override
public int fly() {
return 1000;
}
public String getName(){
return "麻雀";
}
});
}
}
abstract class Bird{
private String name;
public String getName(){
return name;
}
public void setName(String name){
this.name=name;
}
public abstract int fly();
}
匿名内部类必须要继承一个父类或者实现一个接口,当然也仅能只继承一个父类或者实现一个接口。
且没有class关键字,因为匿名内部类是直接使用new来生成一个对象的引用
匿名内部类不能定义任何静态成员、方法、类,只能创建匿名内部类的一个实例
匿名内部类一定是在new的后面,用其隐含实现一个接口或实现一个类
匿名内部类不能有构造方法,且不能定义任何静态成员、静态方法
匿名内部类不能是public,protected,private,static
public class TestCollection {
public static void main(String[] args) {
//定义集合泛型
//这里定义的是一个只接受String类型的ArrayList集合
ArrayList<String> list = new ArrayList<>();
// list.add(100);
list.add("Hello World");
System.out.println(list);
//这里定义的是一个只接受Integer类型的HashSet集合
HashSet<Integer> set = new HashSet<>();
// set.add("Hello World");
set.add(100);
Iterator<Integer> iterator = set.iterator();
while (iterator.hasNext()){
Integer next = iterator.next();
System.out.println(next);
}
//这里定义的是一个限定Map集合的key是String类型,value是Integer类型
HashMap<String, Integer> map = new HashMap<>();
// map.put(11111,"value");
map.put("value",11111);
Integer value = map.get("value");
System.out.println(value);
}
指具有泛型类型参数的方法,通过使用泛型方法,可以在方法级别上使用类型参数,使方法能够处理不同类型的数据,提高代码的灵活性和复用性
方法限定符 <类型形参列表> 返回值类型 方法名称(形参列表) { … }
方法限定符 static <类型形参列表> 返回值类型 方法名称(形参列表) { … }
public static <E> void printArray(E[] inputArray){
for (E e : inputArray) {
System.out.printf("%s",e);
}
}
class Person<T>{
private T t;
public void add(T t){
this.t=t;
}
public T get(){
return t;
}
}
interface Factory<T> {
public int makeProduct(T t);
}
定义一个泛型接口:interface 泛型接口名<类型形参列表> {…}
是一种表示类型上限的通配符,其中T是一个类或接口,泛型类的类型必须实现或继承T这个接口或类
指定了可以使用的类型上限,主要是用于限制输入的参数类型
<? extends T>表示该通配符所代表的类型是T类型的子类
是一种表示类型下限的通配符,其中T是一个类或接口,指定了可以使用的类型下限,主要是用于限制输出的参数类型
<? super T>表示该通配符所代表的类型是T类型的父类
是一种表示未知类型的通配符,可以在需要一个类型参数的情况下使用。但由于没有限制,只能用于简单的情况
public static void print(List<?> data) {
for(int i=0;i<data.size();i++) {
//getSimpleName():用于获取某个类的类名
System.out.println(data.getClass().getSimpleName()+"--data: " + data.get(i));
}
}
在编译阶段,编译器会检查泛型类型的类型安全性,但在运行阶段,由于泛型类型参数被擦除了,就无法保证类型安全性
泛型擦除的基本过程
首先找到用来替换类型参数的具体类,该具体类一般是Object,若指定了类型参数的上限,则使用该上限,然后将代码中的类型参数都替换成具体的类
主要表现在以下:
是将字节流重新恢复为原始对象的过程,是对象序列化的逆过程
通过反序列化操作能够在接收端恢复出与发送端相同的对象
Java反序列化是一个将字节流转化为对象的过程
public class Person implements Serializable {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
}
public static void main(String[] args) {
// 序列化
try {
Person person = new Person("张三", 20);
FileOutputStream fileOut = new FileOutputStream("person.txt");
ObjectOutputStream out = new ObjectOutputStream(fileOut);
out.writeObject(person);
out.close();
fileOut.close();
System.out.println("Person对象已经被序列化并保存到person.txt文件中");
} catch (IOException i) {
i.printStackTrace();
}
// 反序列化
try {
FileInputStream fileIn = new FileInputStream("person.txt");
ObjectInputStream in = new ObjectInputStream(fileIn);
Person person = (Person) in.readObject();
in.close();
fileIn.close();
System.out.println("从person.txt文件中反序列化出来的Person对象:");
System.out.println("Name: " + person.getName());
System.out.println("Age: " + person.getAge());
} catch (IOException i) {
i.printStackTrace();
} catch (ClassNotFoundException c) {
System.out.println("Person类未找到");
c.printStackTrace();
}
}
class Person implements Serializable {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
}
public static void main(String[] args) throws IOException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, ClassNotFoundException {
Person person1 = new Person("John", 30, "California");
//写入文件
FileOutputStream fileOut = new FileOutputStream("person.ser");
ObjectOutputStream out = new ObjectOutputStream(fileOut);
out.writeObject(person1);
fileOut.close();
//通过文件读取
FileInputStream fileInput = new FileInputStream("person.ser");
ObjectInputStream input = new ObjectInputStream(fileInput);
Person person2 = (Person) input.readObject();
fileInput.close();
System.out.println(person2.getName());
System.out.println(person2.getAge());
System.out.println(person2.getAddress());
}
class Person implements Externalizable {
private String name;
private int age;
private String address;
public Person() {
}
public Person(String name, int age, String address) {
this.name = name;
this.age = age;
this.address = address;
}
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;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@Override
public void writeExternal(ObjectOutput out) throws IOException {
out.writeObject(name);
out.writeInt(age);
out.writeObject(address);
}
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
name=(String)in.readObject();
age=in.readInt();
address=(String)in.readObject();
}
}
private static final long serialVersionUID = 1L;
private transient 类型 变量名;
public static void main(String[] args) throws IOException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, ClassNotFoundException {
Person person1 = new Person("张三", 30, "China");
//直接赋值复制
Person person2 = person1;
System.out.println(person2.getName());
System.out.println(person2.getAge());
System.out.println(person2.getAddress());
System.out.println("-------------------");
person2.setName("李四");
System.out.println(person2.getName());
System.out.println(person2.getAge());
System.out.println(person2.getAddress());
}
class Person {
private String name;
private int age;
private String address;
public Person() {
}
public Person(String name, int age, String address) {
this.name = name;
this.age = age;
this.address = address;
}
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;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
public static void main(String[] args) throws CloneNotSupportedException {
Person person1 = new Person("张三", 30, "China");
//浅复制
Person person2 = (Person) person1.clone();
System.out.println(person1);
System.out.println(person2);
System.out.println("---------------------");
person1.setName("李四");
person1.setAge(22);
System.out.println(person1);
System.out.println(person2);
}
class Person implements Cloneable{
private String name;
private int age;
private String address;
public Person() {
}
public Person(String name, int age, String address) {
this.name = name;
this.age = age;
this.address = address;
}
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;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", address='" + address + '\'' +
'}';
}
}
public static void main(String[] args) throws CloneNotSupportedException {
Person person1 = new Person("张三", 30, "China");
//深复制
Person person2 = (Person) person1.clone();
System.out.println(person1);
System.out.println(person2);
System.out.println("---------------------");
person1.setName("李四");
person1.setAge(22);
System.out.println(person1);
System.out.println(person2);
}
class Person implements Cloneable{
private String name;
private int age;
private String address;
public Person() {
}
public Person(String name, int age, String address) {
this.name = name;
this.age = age;
this.address = address;
}
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;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public Person clone() throws CloneNotSupportedException {
Person person=(Person) super.clone();
return person;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", address='" + address + '\'' +
'}';
}
}
public static void main(String[] args) throws Exception {
Person person1 = new Person("张三", 30, "China");
//序列化
ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("person.ser"));
objectOutputStream.writeObject(person1);
objectOutputStream.close();
//反序列化
ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("person.ser"));
Person person2 = (Person) objectInputStream.readObject();
objectInputStream.close();
System.out.println(person1);
System.out.println(person2);
}
}
class Person implements Serializable {
private String name;
private int age;
private String address;
public Person() {
}
public Person(String name, int age, String address) {
this.name = name;
this.age = age;
this.address = address;
}
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;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", address='" + address + '\'' +
'}';
}
}
abstract
关键字定义的类,可以包含抽象方法和非抽象方法。抽象类不能被实例化,只能被继承,并且子类必须实现抽象类中的抽象方法。interface
关键字定义的结构,可以包含抽象方法和默认方法(自 Java 8 引入)。接口不能被实例化,只能被实现。抽象类可以有实例变量、静态变量和常量。
接口只能有常量(public static final
)。
Collection在接口中定义了一系列操作集合元素的方法
方法 | 作用 |
---|---|
add(Object obj) | 向集合增加元素 |
addAll(Collection coll) | 添加一个集合的全部元素 |
int size() | 获取有效元素个数 |
void clear() | 清空集合 |
boolean isEmpty() | 是否为空集合 |
boolean contains(Object obj) | 通过元素的equals方法来判断是否是同一个对象 |
boolean containsAll(Collection c) | 调用元素的equals方法来比较的。用两个集合的元素逐一比较 |
boolean remove(Object obj) | 通过元素的equals方法判断是否是要删除的那个元素。 只会删除找到的第一个元素 |
boolean removeAll(Collection coll) | 取当前集合的差集 |
boolean retainAll(Collection c) | 把交集的结果存在当前的集合中,不影响c |
boolean equals(Object obj) | 集合是否相等 |
Object [] toArray() | 转换成对象数组 |
hashCode() | 获取集合对象的哈希值 |
iterator() | 返回迭代器对象,用于集合遍历 |
//获取迭代器对象
Iterator iterator = 集合.iterator();
//判断索引下一个是否还有元素
while(iterator.hasNext()){
Object next = iterator.next();
System.out.println("next="+next);
}
Iterator itarator = collection.iterator();
得到一个集合的迭代器
hasNext()
判断是否还有下一个元素
while(iterator.hasNext()){
? next()
作用:1.下移获取后面的元素,2. 将下移以后集合位置上的元素返回
? System.out.println(iterator.next());
}
重置迭代器:iterator=collection.iterator();
在调用iterator.next()方法之前必须要调用iterator.hasNext()进行检测,若不调用,且下一条记录无效,直接调用iterator.next()会抛出
//迭代器遍历集合
1.先得到collection对应的迭代器
Iterator iterator = collection.Iterator();
2.使用while循环遍历
while(iterator.hasNext()){
//返回下一个元素,类型是Object
Object obj=iterator.next();
System.out.println("obj=",obj);
}
-------------------------------------------------------------------------------
//增强for循环遍历集合
for(Object obj : collection){
System.out.println("obj=",obj);
}
-------------------------------------------------------------------------------
//普通for循环遍历集合
for(int i=0;i<list.size();i++){
//Object object=list.get(i);
//System.out.println(object);
System.out.println(list.get(i));
}
方法 | 作用 |
---|---|
void add(int index, Object ele) | 在index位置插入ele元素 |
boolean addAll(int index, Collection eles) | 从index位置开始将eles中的所有元素添加进来 |
Object get(int index) | 获取指定index位置的元素 |
int indexOf(Object obj) | 返回obj在集合中首次出现的位置 |
int lastIndexOf(Object obj) | 返回obj在当前集合中末次出现的位置 |
Object remove(int index) | 移除指定index位置(0是第一个元素)的元素,并返回此元素 |
Object set(int index, Object ele) | 设置指定index位置的元素为ele |
普通for循环遍历
for(int i=0;i<list.size();i++){
System.out.println("list="+list.get(i));
}
增强for循环遍历
for (Object o :list) {
System.out.println("o="+o);
}
Iterator迭代器遍历
Iterator iterator=list.iterator();
while(iterator.hasNext()){
Object next=iterator.next();
System.out.println("next="+next);
}
JDK7:直接创建一个初始容量为10的数组
JDK8:一开始创建一个长度为0的数组,当添加第一个元素时再创建一个容量为10的数组。当数组超过初始容量时,接下来每次扩容都是前一次容量+前一次容量的二分之一
方法 | 作用 |
---|---|
void addFirst(E e) | 将指定元素添加到此集合的开头 |
void addLast(E e) | 将指定元素添加到此集合的末尾 |
E getFirst() | 返回此集合的第一个元素 |
E getLast() | 返回此集合的最后一个元素 |
E removeFirst() | 删除此集合中的第一个元素 |
E removeLast() | 删除此集合中的最后一个元素 |
与List接口同属Collection接口,所以常用方法类似
使用迭代器遍历
Iterator iterator = set.iterator();
while(iterator.hasNext()){
Object obj=iterator.next();
System.out.println("obj=",obj);
}
----------------------------------------------------------
使用增强for循环
for(Object obj : set){
System.out.println("obj=",obj);
}
添加一个元素时,先得到hash值,会转成索引值
找到存放数据表table,看这个索引的位置是否已经存放有元素
若没有,就将元素加入该索引位置
若有,则调用equals比较(区别于正常的equals方法,这里的equals方法可以自定义判断)
若相同,就放弃添加,若不相同,则以链表的形式添加到最后
在java8中,若一条链表的元素个数超过TREEIFY_THRESHOLD(默认是8),
并且table的大小>=MIN_TREEIFY_CAPACITY(默认64),就会进行树化(红黑树)
HashSet的底层是HashMap,第一次添加时,table数组扩容到16,
临界值(threshold)是16 * 加载因子(loadFactor)是0.75=12
若table数组使用到了临界值12,就会扩容到16*2=32,新的临界值就是32*0.75=24,以此类推
? tail.next=newElement
? newElement.pre=tail
? tail=newElement;
TreeSet treeset=new TreeSet(new Comparator(){
@Override
public int compare(Object o1,Object o2){
//调用String的compareTo方法进行字符串大小比较
//若出现key字符串相同的情况,是添加不进去元素的
return ((String) o2).compareTo((String) o1);
//按照长度大小排序
//若出现key长度相同的情况 是添加不进去元素的,但是可以替换value
return (((String) o2).length()).compareTo(((String) o1).length());
}
});
方法 | 作用 |
---|---|
void add(Object e) | 将指定元素加入此队列的尾部 |
Object element() | 获取队列头部的元素,但是不删除该元素。 |
boolean offer(Object e) | 将指定元素加入此队列的尾部。 当使用有容量限制的队列时,此方法通常比 add(Object e)方法更好 |
Object peek() | 获取队列头部的元素,但是不删除该元素。如果此队列为空,则返回null |
Object poll() | 获取队列头部的元素,并删除该元素。如果此队列为空,则返回null |
Object remove() | 获取队列头部的元素,并删除该元素 |
方法 | 作用 |
---|---|
void addFirst(Object e) | 将指定元素插入该双端队列的开头 |
void addLast(Object e) | 将指定元素插入该双端队列的末尾 |
Iterator descendingIterator() | 返回该双端队列对应的迭代器,该迭代器将以逆向顺序来迭代队列中的元素 |
Object getFirst() | 获取但不删除双端队列的第一个元素 |
Object getLast() | 获取但不删除刷过段队列的最后一个元素 |
Boolean offerFirst(Object e) | 将指定元素插入该双端队列的开头 |
Boolean offerLast(Object e) | 将指定元素插入该双端队列的末尾 |
Object peekFirst() | 获取但不删除该双端队列的第一个元素,若双端队列为空,则返回null |
Object peekLast() | 获取但不删除该双端队列的最后一个元素,若双端队列为空,则返回null |
Object pollFirst() | 获取并删除该双端队列的第一个元素,若双端队列为空,则返回null |
Object pollLast() | 获取并删除该双端队列的最后一个元素,若双端队列为空,则返回null |
Object pop() | pop出该双端队列所表示的栈的栈顶元素 |
void push(Object e) | 将一个元素push进该双端队列所表示的栈的栈顶,相当于addFirst(e) |
Object removeFirst() | 获取并删除该双端队列的第一个元素 |
Object removeFIrstOccurrence(Object o) | 删除该双端队列的第一次出现的元素o |
Object removeLast() | 获取并删除该双端队列的最后一个元素 |
boolean removeLastOccurrence(Object o) | 删除该双端队列的最后一次出现的元素o |
方法 | 作用 |
---|---|
void clear() | 删除该 Map 对象中的所有 key-value 对。 |
boolean containsKey(Object key) | 查询 Map 中是否包含指定的 key,如果包含则返回 true。 |
boolean containsValue(Object value) | 查询 Map 中是否包含一个或多个 value,如果包含则返回 true。 |
V get(Object key) | 返回 Map 集合中指定键对象所对应的值。V 表示值的数据类型 |
V put(K key, V value) | 向 Map 集合中添加键-值对,如果当前 Map 中已有一个与该 key 相等的 key-value 对,则新的 key-value 对会覆盖原来的 key-value 对。 |
void putAll(Map m) | 将指定 Map 中的 key-value 对复制到本 Map 中。 |
V remove(Object key) | 从 Map 集合中删除 key 对应的键-值对,返回 key 对应的 value,如果该 key 不存在,则返回 null |
boolean remove(Object key, Object value) | Java8新增的方法,删除指定 key、value 所对应的 key-value 对。如果从该 Map 中成功地删除该 key-value 对,该方法返回 true,否则返回 false。 |
Set entrySet() | 返回 Map 集合中所有键-值对的 Set 集合,此 Set 集合中元素的数据类型为 Map.Entry |
Set keySet() | 返回 Map 集合中所有键对象的 Set 集合 |
boolean isEmpty() | 查询该 Map 是否为空(即不包含任何 key-value 对),如果为空则返回 true。 |
int size() | 返回该 Map 里 key-value 对的个数 |
Collection values() | 返回该 Map 里所有 value 组成的 Collection |
//先取出所有的key,通过key获取对应的value
Set keyset=map.KeySet();
//增强for
for(Object key : keyset){
System.out.println(key +"-"+ map.get(key));
}
Set keyset=map.KeySet();
//迭代器
Iterator iterator = keyset.Iterator();
while(iterator.hasNext()){
Object key=iterator.next();
System.out.println(key +"-"+ map.get(key));
}
//把所有的values值取出来
Collection values =map.values();
//可以使用Collection使用的遍历方法
//增强for
for(Object value : values){
System.out.println(value);
}
Collection values =map.values();
//迭代器
Iterator iterator=values.iteartor();
while(iterator.hasNext()){
Object obj=iteartor.next();
System.out.println(value);
}
//通过EntrySet来获取 key-value
set entrySet=map.entrySet();
//增强for
for(Object entry : entrySet){
//将entry 转成 Map.Entry
Map.Entry m=(map.Entry) entry;
System.out.println(m.getKey() +"-"+ m.getValue());
}
set entrySet=map.entrySet();
//迭代器
Iterator iterator = entrySet.Iterator();
while(iterator.hasNext()){
//HashMap$Node 实现了 Map.Entry(getKey,getValue)
Object entry=iterator.next();
//向下转型 相当于Map.Entry调用了getKey()和getValue()方法
Map.Entry m=(Map.Entry) entry;
System.out.println(m.getKey() +"-"+ m.getValue());
}
? 若没有元素则直接添加,若该索引处有元素,继续判断该元素的key是否和准备加入的key相等
? 若相等,则直接替换value,若不相等,则需要判断是树结构还是链表结构,做出相应的处理。
? 若添加时发现容量不够,则需要扩容
? MIN_TREEIFY_CAPACITY(默认64),就会进行树化(红黑树),否则仍然采用数组扩容机制
TreeMap treemap=new TreeMap(new Comparator(){
@Override
public int compare(Object o1,Object o2){
//调用String的compareTo方法进行字符串大小比较
//若出现key字符串相同的情况,是添加不进去元素的
//return ((String) o2).compareTo((String) o1);
//按照长度大小排序
//若出现key的长度相同的情况 是添加不进去元素的,但是可以替换value
return ((String) o2).length() - ((String) o1).length();
}
});
方法 | 作用 |
---|---|
String getProperty(String key) | 获取Properties中键值为key的属性值 |
String getProperty(String s1,String s2) | 获取Properties中键为s1的属性值,若不存在s1的值,则获取键为s2的值 |
Object setProperty(String key,String value) | 设置属性值,类似于Map的put()方法 |
void load(InputStream inputStream) | 从属性中获取所有的键值对,将加载到的属性追加到properties里,不保证加载顺序 |
void store(OutputStream out,String s) | 将Properties中的键值对输出到指定文件中 |
有序(保证存储和取出的元素顺序一致)、不允许元素重复、无索引下标。
底层数据结构是哈希表,只是每个键值对元素又额外的多了一个双链表的机制记录存储的迭代顺序。该迭代顺序可以是插入顺序或者是访问顺序。
根据链表中元素的顺序可以分为:按插入顺序的链表,和按访问顺序(调用get方法)的链表。
默认是按插入顺序排序,如果指定按访问顺序排序,那么调用get方法后,会将这次访问的元素移至链表尾部,不断访问可以形成按访问顺序排序的链表。