--------------android培训、java培训、期待与您交流! --------------
String(字符串)
1、String类
java.lang
类 String
String 类代表字符串。
Java程序中的所有字符串字面值(如"abc")都作为此类的实例实现。
字符串是常量;
它们的值在创建之后不能更改。字符串缓冲区支持可变的字符串。
因为 String 对象是不可变的,所以可以共享。
String name="张三";
2、连接字符串
连接字符串是字符串操作中较简单的一种。可以对多个字符串进行连接,也可以使字符串与其他数据类型进行连接。
(1)字符串连接,使用符号"+"
(2)字符串也可以与基本数据类型进行连接,这些基本数据类型会被直接转换为字符串。
实例:
public class StringDemo {
public static void main(String[] args) {
String s1="hello ";
String s2="world";
int num=1;
String s3=s1+s2;//多个字符串连接
String s4=s1+num;//字符串与基本数据类型进行连接
System.out.println(s3);//输出hello world
System.out.println(s4);//输出hello 1
}
}
3、获取字符串信息
(1)获取字符串长度
语法:str.length();返回字符串str的长度值
(2)字符串查找
语法:str.indexOf(substr);获取指定字符串substr在字符串str中的首次出现索引位置,找不到,则返回-1
(3)获取指定索引位置的字符。
语法:str.charAt(int index);index:用于指定要返回字符的下标。
实例:
public class StringDemo {
public static void main(String[] args) {
String s="hello world";
//获得字符串s的长度
System.out.println(s.length());//输出11
//获取字符“o”在s中首次出现的索引位置
System.out.println(s.indexOf("o"));//输出4
//获取指定索引位置的字符
System.out.println(s.charAt(4));//输出o
}
}
4、字符串操作
(1)获取子字符串
通过String类的substring()方法可对字符串进行截取,获得原字符串的子字符串。
substring(int beginIndex):
返回从指定索引位置开始截取直到字符串结尾的子串。
substring(int beginIndex,int endIndex):
返回从字符串指定开始索引位置开始截取直到指定结束索引位置的子串。
实例:
public class StringDemo {
public static void main(String[] args) {
String s="hello world";
String s1=s.substring(5);//从s的索引位置5处开始截取直到结尾。
System.out.println(s1);//输出world
String s2=s.substring(1,5);//从s的索引位置1处开始截取直到索引位置5处。
System.out.println(s2);//输出ello
}
}
(2)字符串替换
replace方法可将字符串中指定的字符或字符串换成新字符或字符串
语法:str.replace(char oldChar ,char newChar)
实例:
public class StringDemo {
public static void main(String[] args) {
String s="java";
String s1=s.replace("a", "A");
System.out.println(s);//输出原字符串
System.out.println(s1);//输出替换后的字符串,输出jAvA
}
}
(3)判断字符串是否相等
判断两个字符串地址值是否相等用“==”
判断两个字符串地址值是否相等用equals
class StringDemo{
public static void main(String[] args) {
String s1 = new String("hello");
String s2 = "hello";
String s3 = "hello";//s1、s2、s3内容相同,但s1的地址值与s2、s3不相同。s2和s3地址值相同。
//==比较的是两个字符串的地址值是否相同,equals比较的是两个字符串的内容是否相同
System.out.println(s1==s2);//false
System.out.println(s1==s3);//false
System.out.println(s1.equals(s2));//true
}
}
5、StringBuffer
StringBuffer是字符串缓冲区,是一个容器。
特点:
长度是可变化的。
可以字节操作多个数据类型。
最终会通过toString方法变成字符串。
(1)存储
StringBuffer append():将指定数据作为参数添加到已有数据结尾处。
StringBuffer insert(index,数据):可以将数据插入到指定index位置。
(2)删除
StringBuffer delete(start,end):删除缓冲区中的数据,包含start,不包含end。
StringBuffer deleteCharAt(index):删除指定位置的字符。
(3)获取。
char charAt(int index)
int indexOf(String str)
int lastIndexOf(String str)
int length()
String substring(int start, int end)
(4)修改
StringBuffer replace(start,end,string);
void setCharAt(int index, char ch) ;
(5)反转
StringBuffer reverse();
(6)将缓冲区中指定数据存储到指定字符数组中。
void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin)
JDK1.5 版本之后出现了StringBuilder.
StringBuffer是线程同步。
StringBuilder是线程不同步。
以后开发,建议使用StringBuilder
升级三个因素:
(1)提高效率。
(2)简化书写。
(3)提高安全性。
集合
集合概念
集合可以看作是一个容器,对于集合类中的各个对象很容易将其存放入集合中,也很容易将其从集合中取出来,还可以将其按照一定的顺序摆放。
Java中提供了不同的集合类,这些类具有不同的存储对象的方式,并提供了相应的方法以方便用户对集合进行遍历、添加、删除以及查找指定的对象。
(1)为什么出现集合类?
面向对象语言对事物的体现都是以对象的形式,所以为了方便对多个对象的操作,就对对象进行存储,集合就是存储对象最常用的一种方式。
(2)数组和集合类都是容器,不同点:
数组虽然也可以存储对象,但长度是固定的;集合长度是可变的。数组中可以存储基本数据类型,集合只能存储对象。
(3)集合类的特点:集合只用于存储对象,集合长度是可变的,集合可以存储不同类型的对象。
Collection接口
Collection接口是集合框架中的根接口,下面有两个集合类对它进行了继承,List和Set。
Collcetion集合体系
|-List 列表:内部元素是有序的,元素可以重复。因为该集合体系有索引。
| |-ArrayList:底层的数据结构使用的是数组结构。
| | 特点:查询速度很快,但是增删很慢,线程不同步。
| |-LinkedList:底层使用的是链表数据结构。
| | 特点,增删速很度快,但是查询稍慢。
| └-Vector:底层是数组数据结构,线程同步,被ArrayList代替了。
|
|-Set集:内部元素是无序的(存入和取出的顺序不一定一致)。不可以重复,线程不同步。
| |-HashSet:是如何保证元素唯一性的呢?
| | 答:是通过判断元素的两个方法hashCode()和equals()来完成。
| | 如果元素的HashCode值相同,才会判断epuals()是否为true。
| | 如果元素的HashCode值不同,不会调用epuals()。
| |
| | 注意:对于判断元素是否存在,以及增删等操作,依赖的方法是元素的
| | hashCode()和epuals()方法。
| |
| └-TreeSet:-可以对Set集合中的元素进行排序。
| -底层数据结果是二叉树。
| -保证元素唯一性的依据:compareTo方法return 0。
| -TerrSet排序的第一种方式:让元素自身具备比较性。
| 元素需要实现Comparable接口,覆盖compareTo方法。
|
└-Map 映射:内部元素是无序的,该集合存储键值对,一对一对存储的,保证键的唯一性。
|-Hashtable:底层是哈希表数据结构,不能存入null键null值,此集合线程同步。JDK1.0 效率低。
|-HashMap:底层是哈希表数据结构,可以存入null键null值,此集合线程不同步。JDK1.2 效率高。
└-TreeMap:底层是二叉树数据结构,此集合线程不同步,可以用于给map集合中的键进行排序。
Collection定义了集合框架的共性功能。
(1)添加
add(e);
addAll(collection);
add方法的参数类型是Object。以便于接收任意类型对象。
(2)删除
remove(e);
removeAll(collection);
clear();
(3)判断。
contains(e);
isEmpty();
(4)获取
iterator();
size();
(5)获取交集。
retainAll();
(6)集合变数组。
toArray();
集合中存储的都是对象的引用(地址)。
迭代
什么是迭代器呢?
其实就是集合的取出元素的方式。
如同抓娃娃游戏机中的夹子。
迭代器是取出方式,会直接访问集合中的元素。
所以将迭代器通过内部类的形式来进行描述。
通过容器的iterator()方法获取该内部类的对象。
迭代的常见操作
(1) hasNext();有下一个元素,返回真
(2)next();取出下一个元素,注意循环时next运行一次,就要hasNext一次,防止元素超出
(3) remove();移除元素
例:
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
public class Demo {
public static void main(String[] args) {
Collection<String> list=new ArrayList<>();//实例化集合类对象
list.add("a");//向集合添加数据
list.add("b");
Iterator<String> it=list.iterator();//创建迭代器
while(it.hasNext()){
System.out.println(it.next());
}
}
}
注意:
迭代器在Collcection接口中是通用的,它替代了Vector类中的Enumeration(枚举)。
迭代器的next方法是自动向下取元素,要避免出现NoSuchElementException。
迭代器的next方法返回值类型是Object,所以要记得类型转换。
List集合
1、list集合结构
|--List:元素是有序的,元素可以重复,类似java数组。因为该集合体系有索引。
|--ArrayList:底层的数据结构使用的是数组结构。特点:查询速度很快。但是增删稍慢。线程不同步。
|--LinkedList:底层使用的链表数据结构。特点:增删速度很快,查询稍慢。线程不同步。
|--Vector:底层是数组数据结构。线程同步。被ArrayList替代了。因为效率低。
2、list特有方法
特有方法。凡是可以操作角标的方法都是该体系特有的方法。
(1)增
add(index,element);在指定位置上添加元素,如果没有指定位置,则在当前集合中依次添加元素
addAll(index,Collection);在指定位置上添加指定集合中的所有元素
(2)删
remove(index);删除指定位置上的元素
(3)改
set(index,element);修改指定位置上的元素
(4)查
get(index):获取指定位置上的元素
subList(from,to);//获取一个子集合,子集合中的元素是原集合根据两个指定位置截取的
(5)迭代
listIterator();List集合特有的迭代器。ListIterator是Iterator的子接口。
int indexOf(obj):获取指定元素的位置。
实例:
import java.util.*;
class ListDemo
{
public static void show(Object obj)
{
System.out.println(obj);
}
public static void main(String[] args)
{
ArrayList al = new ArrayList();//建立list集合
//添加元素
al.add("java01");
al.add("java02");
al.add("java03");
al.add("java04");
al.add("java05");
al.add("java06");
show("原来的集合 "+al);
//在指定位置添加元素。
al.add(1,"java001");//在集合的索引1处增加元素
show("索引1处增加元素后"+al);
//删除指定位置的元素。
al.remove(2);//将集合的索引2处的元素删除
show("索引2处删除元素后"+al);
//修改指定位置的元素。
al.set(2,"java003");//将集合的索引2处的元素修改为“java003”
show("索引2处修改元素后"+al);
//获取指定位置的元素
show("索引0处的元素"+al.get(0));
//获取指定元素在集合的索引位置。
show("index="+al.indexOf("java06"));
//获取一个子集合
List sub = al.subList(1,3);
show("截取原集合的索引1处直到索引3处的子集合"+sub);
System.out.println("用get获取所有元素");
for(int x=0; x<al.size(); x++)
{
System.out.println("al("+x+")="+al.get(x));
}
System.out.println("用迭代器遍历所有元素");
ListIterator li = al.listIterator();创建list集合特有迭代器
//遍历集合元素
while(it.hasNext())
{
show("next:"+it.next());
}
}
}
3、
ListIterator
listIterator();List集合特有的迭代器。ListIterator是Iterator的子接口。
int indexOf(obj):获取指定元素的位置。
ListIterator listIterator();
在迭代时,不可以通过集合对象的方法操作集合中的元素。
因为会发生ConcurrentModificationException异常。
所以,在迭代器时,只能用迭代器的方法操作元素,可是Iterator方法是有限的,只能对元素进行判断,取出,删除的操作,
如果想要其他的操作如添加,修改等,就需要使用其子接口,ListIterator。该接口只能通过List集合的listIterator方法获取。
ListIterator特有的方法
add(obj);//增加
set(obj);//修改为obj
hasPrevious();//判断前面有没有元素
previous();//取前一个元素
4、枚举(Vector)
枚举就是Vector特有的取出方式。
发现枚举和迭代器很像。
其实枚举和迭代是一样的。
因为枚举的名称以及方法的名称都过长。
所以被迭代器取代了,枚举郁郁而终了。
特有方法:
addElement(obj);//添加元素,相当于add(obj);
Enumerationelements();//Vector特有取出方式(枚举)
hasMoreElements();//相当于Iterator的hasNext()方法
nextElements();//相当于Iterator的next()方法
例:
class VectorDemo
{
public static void main(String[] args)
{
Vector v = new Vector();
v.add("java01");
v.add("java02");
v.add("java03");
v.add("java04");
Enumeration en = v.elements();//相当于迭代器
while(en.hasMoreElements())
{
System.out.println(en.nextElement());
}
}
}
5、LinkedList
LinkedList:底层使用的链表数据结构。特点:增删速度很快,查询稍慢。线程不同步。
LinkedList:特有方法:
(1)增
addFirst();
addLast();
(2)获取
getFirst();
getLast();
获取元素,但不删除元素。如果集合中没有元素,会出现NoSuchElementException
(3)删
removeFirst();
removeLast();
获取元素,并删除元素。如果集合中没有元素,会出现NoSuchElementException
在JDK1.6以后,出现了替代方法。
(1)增
offFirst();
offLast();
(2)获取
//获取元素,但是不删除。如果集合中没有元素,会返回null。
peekFirst();
peekLast();
(3)删
//获取元素,并删除元素。如果集合中没有元素,会返回null。
pollFirst();
pollLast();
实例:需求:使用LinkedList模拟一个堆栈或者队列数据结构。
堆栈:先进后出 如同一个杯子。
队列:先进先出 First in First out FIFO 如同一个水管。
import java.util.*;
class LinkedListTest
{
//堆栈
public static void stack(LinkedList l)
{
System.out.println("堆栈输出");
while (!l.isEmpty())//当集合不为空
{
show(l.removeLast());
}
}
//队列
public static void queue(LinkedList l)
{
System.out.println("队列输出");
while(!l.isEmpty())
{
show(l.removeFirst());
}
}
//输出
public static void show(Object obj)
{
System.out.println(obj);
}
public static void main(String[] args)
{
LinkedList l=new LinkedList();// 建立LinkedList集合
l.addLast("java01");
l.addLast("java02");
l.addLast("java03");
l.addLast("java04");
l.addLast("java05");
l.addLast("java06");
//堆栈输出
stack(l);
//队列输出
//queue(l);
}
}
Set集合
1、set集合
Set:无序,不可以重复元素。
|--HashSet:数据结构是哈希表。线程是非同步的。
保证元素唯一性的原理:判断元素的hashCode值是否相同。
如果相同,还会继续判断元素的equals方法,是否为true。
|--TreeSet:可以对Set集合中的元素进行排序。
底层数据结构是二叉树。
保证元素唯一性的依据:
compareTo方法return 0.
Set集合的功能和Collection是一致的。
2、HashSet
HashSet:底层数据结构是哈希表。是线程不安全的。不同步。
HashSet是如何保证元素唯一性的呢?
是通过元素的两个方法,hashCode和equals来完成。
如果元素的HashCode值相同,才会判断equals是否为true。
如果元素的hashcode值不同,不会调用equals。
注意,对于判断元素是否存在,以及删除等操作,依赖的方法是元素的hashcode和equals方法。
在添加元素的时候,虚拟机会自动将新元素与集合内元素用hashcode和equals方法进行比较。
实例1:
import java.util.HashSet;
import java.util.Iterator;
class HashSetDemo
{
public static void sop(Object obj)
{
System.out.println(obj);
}
public static void main(String[] args)
{
HashSet hs = new HashSet();//建立Hashset集合
//add()返回布尔型true和false,添加成功返回true,失败返回false
sop(hs.add("java01"));//true
sop(hs.add("java01"));//set中的元素具有唯一性,已经存在过的元素不能再添加。false
hs.add("java02");
hs.add("java03");
hs.add("java03");
hs.add("java04");
Iterator it = hs.iterator();//建立迭代器
while(it.hasNext())
{
sop(it.next());//输出的元素顺序并不一定和元素排序相同
}
}
}
实例2:
在hashSet集合中存入自定义对象
姓名和年龄相同为同一个人,重复元素,则不能存入
系统会自动调用hashcode和equals方法判断新元素在集合内存不存在,如果存在,则不存入。确保元素的唯一性。
import java.util.HashSet;
import java.util.Iterator;
//描述人
class Person
{
private String name;
private int age;
Person(String name,int age)
{
this.name = name;
this.age = age;
}
public String getName()
{
return name;
}
public int getAge()
{
return age;
}
public boolean equals(Object obj)
{
if(!(obj instanceof Person))
return false;
Person p=(Person)obj;
return this.name.equals(p.name)&&this.age==p.age;
}
public int hashCode()
{
return this.name.hashCode()+this.age;
}
}
class HashSetDemo
{
public static void sop(Object obj)
{
System.out.println(obj);
}
public static void main(String[] args)
{
HashSet hs = new HashSet();
hs.add(new Person("张三",20));
hs.add(new Person("李四",18));
hs.add(new Person("王五",25));
hs.add(new Person("王五",25));//集合中已有该元素,不能存入
Iterator it = hs.iterator();
while(it.hasNext())
{
Person p = (Person)it.next();
sop(p.getName()+"....."+p.getAge());
}
}
}
3、TreeSet
特点:底层的数据结构为二叉树结构;可以对Set集合中的元素进行排序。
TreeSet类实现了Comparable接口,该接口强制让增加到集合中的对象进行了比较,需要复写compareTo方法,才能让对象按指定需求(如人的年龄大小比较等)进行排序,并加入集合。
java中的很多类都具备比较性,其实就是实现了Comparable接口。
注意:排序时,当主要条件相同时,按次要条件排序。
保证数据的唯一性的依据:通过compareTo方法的返回值,是正整数、负整数或零,则两个对象较大、较小或相同。相等时则不会存入。
TreeSet的第一种排序方式:让元素自身具备比较性。
元素需要实现Comparable接口,覆盖compareTo方法。
这种方式也称为元素的自然顺序,或者叫做默认顺序。
实例1:
import java.util.Iterator;
import java.util.*;
public class TreeSetTest {
public static void main(String[] args) {
Set ts = new TreeSet();
ts.add("abc");
ts.add("xyz");
ts.add("rst");
Iterator it = ts.iterator();
while (it.hasNext()) {
System.out.println(it.next());//输出的字符串顺序并不是按照添加顺序,而是按照字母的排序法排序的,因为String实现了Comparable接口。输出abc、rst、xyz
}
}
}
实例2:
import java.util.*;
//学生类
class Student implements Comparable
{
private String name;
private int age;
Student(String name,int age)
{
this.name=name;
this.age=age;
}
public String getName()
{
return name;
}
public int getAge()
{
return age;
}
//复写hashCode以便HashSet集合调用
public int hashCode()
{
return name.hashCode()+age;
}
//复写equals以便HashSet集合调用
public boolean equals(Object obj)
{
if(!(obj instanceof Student))
throw new RuntimeException();
Student s = (Student)obj;
return this.name.equals(s.name)&&this.age==s.age;
}
//复写compareTo以便TreeSet集合调用
public int compareTo(Object obj)
{
Student s=(Student)obj;
if(this.age==s.age)//排序时,当主要条件年龄相同,则按次要条件姓名排序。
return this.name.compareTo(s.name);
return this.age-s.age;
}
}
class TreeSetTest
{
public static void main(String[] args)
{
TreeSet<Student> t=new TreeSet<Student>();
t.add(new Student("fgh",10));
t.add(new Student("weras",6));
t.add(new Student("acjsad",12));
t.add(new Student("ui",8));
t.add(new Student("rrfs",12));
Iterator<Student> it=t.iterator();
while(it.hasNext())
{
Student s=it.next();
System.out.println(s.getName()+"....."+s.getAge());
}
}
}
TreeSet的第二种排序方式。
当元素自身不具备比较性时,或者具备的比较性不是所需要的。
这时就需要让集合自身具备比较性。
在集合初始化时,就有了比较方式。
定义一个比较器,将比较器对象作为参数传递给TreeSet集合的构造函数。
比较器构造方式:定义一个类,实现Comparator接口,覆盖compare方法。
当两种排序都存在时,以比较器为主。
需求:在TreeSet集合中存储学生对象,按照学生姓名的长短排序,定义比较器实现。
import java.util.*;
//学生类
class Student implements Comparable
{
private String name;
private int age;
Student(String name,int age)
{
this.name=name;
this.age=age;
}
public String getName()
{
return name;
}
public int getAge()
{
return age;
}
//复写hashCode以便HashSet集合调用
public int hashCode()
{
return name.hashCode()+age;
}
//复写equals以便HashSet集合调用
public boolean equals(Object obj)
{
if(!(obj instanceof Student))
throw new RuntimeException();
Student s = (Student)obj;
return this.name.equals(s.name)&&this.age==s.age;
}
//复写compareTo以便TreeSet集合调用
public int compareTo(Object obj)
{
Student s=(Student)obj;
if(this.age==s.age)
return this.name.compareTo(s.name);
return this.age-s.age;
}
}
//定义比较器
class StrLenComparator implements Comparator<Student>
{
public int compare(Student s1,Student s2)
{
int num=new Integer(s1.getName().length()).compareTo(new Integer(s2.getName().length()));
if (num==0)//若学生姓名长度相同,则将学生姓名用字符串比较方式比较
{
return new Integer(s1.getAge()).compareTo(s2.getAge());
}
return num;
}
}
class TreeSetTest
{
public static void main(String[] args)
{
TreeSet<Student> t=new TreeSet<Student>(new StrLenComparator());
t.add(new Student("fgh",10));
t.add(new Student("weras",6));
t.add(new Student("acjsad",12));
t.add(new Student("ui",8));
t.add(new Student("rrfs",12));
Iterator<Student> it=t.iterator();
while(it.hasNext())
{
Student s=it.next();
System.out.println(s.getName()+"....."+s.getAge());
}
}
}
Map集合
1、Map集合
Map集合没有继承Collection接口,其提供的是key到value的映射。
Map中不能包含相同的key,每个key只能映射一个value。
Map集合:该集合存储键值对。一对一对往里存。而且要保证键的唯一性。
Map
|--Hashtable:底层是哈希表数据结构,不可以存入null键null值。该集合是线程同步的。jdk1.0.效率低。
|--HashMap:底层是哈希表数据结构,允许使用 null 值和 null 键,该集合是不同步的。将hashtable替代,jdk1.2.效率高。
|--TreeMap:底层是二叉树数据结构。线程不同步。可以用于给map集合中的键进行排序。
和Set很像。
其实大家,Set底层就是使用了Map集合。
2、Map集合常用方法
(1)添加。
put(K key, V value) 向集合中添加指定的key与value的映射关系,如果添加的键已存在,则新值会覆盖原有键的旧值,且返回旧值。
putAll(Map<? extends K,? extends V> m) 添加一个map集合
(2)删除。
clear() 清空键值
remove(Object key)删除指定的键值
(3)判断。
containsValue(Object value) 判断指定的键是否存在
containsKey(Object key) 判断指定的值是否存在
isEmpty() 判断集合是否为空
(4)获取。
get(Object key) 获取指定键对应的值
size() 获取集合的长度
values() 获取Map集合中所有的值,返回一个Collection集合
entrySet() 返回该集合中包含的映射关系的Set集合
keySet() 返回该集合中的所有key形成的Set集合
3、map集合取出方式
Map集合的取出原理:将map集合转成set集合。再通过迭代器取出。
map集合的两种取出方式:
(1)Set<k> keySet:将map中所有的键存入到Set集合。因为set集合具备迭代器。
然后用迭代方式取出所有的键,再根据get方法。获取每一个键对应的值。
(2)Set<Map.Entry<k,v>> entrySet:
将map集合中的映射关系存入到了set集合中,而这个关系的数据类型就是:Map.Entry
Entry其实就是Map中的一个static内部接口。
interface Map
{
public static interface Entry
{
public abstract Object getKey();//获得键
public abstract Object getValue();//获得值
}
}
为什么要定义在内部呢?因为只有有了Map集合,有了键值对,才会有键值的映射关系。
关系属于Map集合中的一个内部事物。
而且该事物在直接访问Map集合中的元素。
实例:
每一个学生都有对应的归属地。
学生Student,地址String。
学生属性:姓名,年龄。
注意:姓名和年龄相同的视为同一个学生。
保证学生的唯一性。
描述学生。
定义map容器。将学生作为键,地址作为值。存入。
获取map集合中的元素。
import java.util.*;
class Student implements Comparable<Student>
{
private String name;
private int age;
Student(String name,int age)
{
this.name = name;
this.age = age;
}
//复写compareTo方法,比较年龄,若年龄相同,比较姓名
public int compareTo(Student s)
{
int num = new Integer(this.age).compareTo(new Integer(s.age));
if(num==0)
return this.name.compareTo(s.name);
return num;
}
//复写hashCode()方法
public int hashCode()
{
return name.hashCode()+age*34;
}
//复写equals,比较对象内容
public boolean equals(Object obj)
{
if(!(obj instanceof Student))
throw new ClassCastException("类型不匹配");
Student s = (Student)obj;
return this.name.equals(s.name) && this.age==s.age;
}
public String getName()
{
return name;
}
public int getAge()
{
return age;
}
public String toString()
{
return name+":"+age;
}
}
class MapTest
{
public static void main(String[] args)
{
HashMap<Student,String> hm = new HashMap<Student,String>();
hm.put(new Student("lisi1",21),"beijing");
hm.put(new Student("lisi1",21),"tianjin");//若添加的键已存在,则将已存在的键值覆盖
hm.put(new Student("lisi2",22),"shanghai");
hm.put(new Student("lisi3",23),"nanjing");
hm.put(new Student("lisi4",24),"wuhan");
//第一种取出方式 keySet
System.out.println("第一种取出方式 keySet");
Set<Student> keySet = hm.keySet();//map集合调用keyset方法将集合中所有key形成set集合
Iterator<Student> it = keySet.iterator();//建立迭代器
while(it.hasNext())
{
Student stu = it.next();//遍历key
String addr = hm.get(stu);//通过key取出map集合键值
System.out.println(stu+".."+addr);
}
//第二种取出方式 entrySet
System.out.println("第二种取出方式 entrySet");
Set<Map.Entry<Student,String>> entrySet = hm.entrySet();//map集合调用entrySet方法将集合中的映射关系形成set集合
Iterator<Map.Entry<Student,String>> iter = entrySet.iterator();//建立迭代器
while(iter.hasNext())
{
Map.Entry<Student,String> me = iter.next();
Student stu = me.getKey();//用getKey方法从映射关系中取出key
String addr = me.getValue();//用getValue方法从映射关系中取出Value
System.out.println(stu+"........."+addr);
}
}
}
4、TreeMap排序
TreeMap:底层是二叉树数据结构。线程不同步。可以用于给map集合中的键进行排序。和TreeSet很像。
实例:
对学生对象的年龄进行升序排序。
因为数据是以键值对形式存在的。
所以要使用可以排序的Map集合。TreeMap。
import java.util.*;
class Student implements Comparable<Student>
{
private String name;
private int age;
Student(String name,int age)
{
this.name = name;
this.age = age;
}
//复写compareTo方法,比较年龄,若年龄相同,比较姓名,供TreeMap排序调用
public int compareTo(Student s)
{
int num = new Integer(this.age).compareTo(new Integer(s.age));
if(num==0)
return this.name.compareTo(s.name);
return num;
}
//复写hashCode()方法
public int hashCode()
{
return name.hashCode()+age*34;
}
//复写equals,比较对象内容
public boolean equals(Object obj)
{
if(!(obj instanceof Student))
throw new ClassCastException("类型不匹配");
Student s = (Student)obj;
return this.name.equals(s.name) && this.age==s.age;
}
public String getName()
{
return name;
}
public int getAge()
{
return age;
}
public String toString()
{
return name+":"+age;
}
}
class MapTest
{
public static void main(String[] args)
{
TreeMap<Student,String> hm = new TreeMap<Student,String>();//建立TreeMap实例
//TreeMap会按照compareTo方法进行键的排序
hm.put(new Student("lisi1",21),"beijing");
hm.put(new Student("lisi1",21),"tianjin");//若添加的键已存在,则将已存在的键值覆盖
hm.put(new Student("lisi2",22),"shanghai");
hm.put(new Student("lisi3",23),"nanjing");
hm.put(new Student("lisi4",24),"wuhan");
System.out.println("entrySet取出方式");
Set<Map.Entry<Student,String>> entrySet = hm.entrySet();//map集合调用entrySet方法将集合中的映射关系形成set集合
Iterator<Map.Entry<Student,String>> iter = entrySet.iterator();//建立迭代器
while(iter.hasNext())
{
Map.Entry<Student,String> me = iter.next();//遍历映射关系
Student stu = me.getKey();//用getKey方法从映射关系中取出key
String addr = me.getValue();//用getValue方法从映射关系中取出Value
System.out.println(stu+"........."+addr);
}
}
}
5、Map应用及扩展
什么使用map集合呢?
当数据之间存在这映射关系时,就要先想map集合。
需求:"jkhsjkd,h-qaio+qcmSH"获取该字符串中的字母出现的次数。希望打印结果:a(1)c(2).....
分析:通过结果发现,每一个字母都有对应的次数。说明字母和次数之间都有映射关系。
注意了,当发现有映射关系时,可以选择map集合。因为map集合中存放就是映射关系。
思路:
(1)将字符串转换成字符数组。因为要对每一个字母进行操作。
(2)定义一个map集合,因为打印结果的字母有顺序,所以使用treemap集合。
(3)遍历字符数组。
将每一个字母作为键去查map集合。
如果返回null,将该字母和1存入到map集合中。
如果返回不是null,说明该字母在map集合已经存在并有对应次数。
那么就获取该次数并进行自增。,然后将该字母和自增后的次数存入到map集合中。覆盖调用原理键所对应的值。
(4)将map集合中的数据变成指定的字符串形式返回。
import java.util.*;
class MapTest
{
public static void main(String[] args)
{
String s= charCount("jkhsjkd,h-qaio+qcmSH");
System.out.println(s);
}
//处理字符串函数
public static String charCount(String str)
{
char[] chs = str.toCharArray();//将字符串转为字符数组
TreeMap<Character,Integer> tm = new TreeMap<Character,Integer>();//建立TreeMap实例,
int count = 0;//定义count变量计数
for(int x=0; x<chs.length; x++)
{
if(!(chs[x]>='a' && chs[x]<='z' || chs[x]>='A' && chs[x]<='Z'))//若检查字符为字母才会进行计数,否则不计数
continue;
Integer value = tm.get(chs[x]); //将字母作为键,去查询集合中对应的计数值
//若计数值为空,说明集合中没有该字母,将字母存入键,计数值0存入值
if(value!=null)
count = value;
//若计数值不为空,说明集合中已有该字母,将计数值+1
count++;
tm.put(chs[x],count);//将字母和新的计数值存入集合,覆盖旧值
count = 0;//将计数值置零,继续计数
}
StringBuilder sb = new StringBuilder();//建立StringBuilder字符串缓冲区
Set<Map.Entry<Character,Integer>> entrySet = tm.entrySet();//将map集合中的映射关系转为set集合
Iterator<Map.Entry<Character,Integer>> it = entrySet.iterator();//建立迭代器
while(it.hasNext())
{
Map.Entry<Character,Integer> me = it.next();
Character ch = me.getKey();
Integer value = me.getValue();
sb.append(ch+"("+value+") ");//将字母和计数值存入字符串缓冲区
}
return sb.toString();//返回处理后的字符串
}
}
map扩展:
map扩展知识。
map集合被使用是因为具备映射关系,map集合中还可以嵌套集合。
例:班级对应学生,学生对应学号和姓名。
"yureban" Student("01" "zhangsan");
"yureban" Student("02" "lisi");
"jiuyeban" "01" "wangwu";
"jiuyeban" "02" "zhaoliu";
一个学校有多个教室。每一个教室都有名称。
import java.util.*;
class MapDemo
{
public static void main(String[] args)
{
//预热班map集合
HashMap<String,String> yureban=new HashMap<String,String>();
//就业班map集合
HashMap<String,String> jiuyeban=new HashMap<String,String>();
//学校map集合
HashMap<String,HashMap<String,String>> czbk=new HashMap<String,HashMap<String,String>>();
//学校中班级名称和班级集合成为映射,学校集合中嵌套班级集合
czbk.put("yureban",yureban);
czbk.put("jiuyueban",jiuyeban);
//预热班中学号和姓名成为映射
yureban.put("01","zhangsan");
yureban.put("02","lisi");
//预热班中学号和姓名成为映射
jiuyeban.put("01","wangwu");
jiuyeban.put("02","zhouqi");
//显示学校中全部学生信息
getAllStudentInfo(czbk);
}
//定义一个方法获取全部学生信息,班级、学号、姓名
public static void getAllStudentInfo(HashMap<String ,HashMap<String,String>> hm)
{
Iterator<String> it=hm.keySet().iterator();//map集合调用返回key的set集合,再创建迭代器
while (it.hasNext())
{
String s= it.next();//班级名称
System.out.println(s+":");
HashMap<String,String> stu=hm.get(s);//获得班级集合
getStudentInfo(stu);
}
}
//获取班级中学生信息,姓名、学号
public static void getStudentInfo(HashMap<String,String> hm)
{
Iterator<String> it=hm.keySet().iterator();
while(it.hasNext())
{
String key=it.next();//学号
String value=hm.get(key);//姓名
System.out.println(key+"..."+value);
}
}
}
泛型
1、泛型:JDK1.5版本以后出现新特性。用于解决安全问题,是一个类型安全机制。
好处
(1)将运行时期出现问题ClassCastException,转移到了编译时期。,
方便于程序员解决问题。让运行时问题减少,安全。,
(2)避免了强制转换麻烦。
泛型格式:通过<>来定义要操作的引用数据类型。
在使用java提供的对象时,什么时候写泛型呢?
通常在集合框架中很常见,
只要见到<>就要定义泛型。
其实<> 就是用来接收类型的。
当使用集合时,将集合中要存储的数据类型作为参数传递到<>中即可。
泛型类前期做法:工具类接收Object类型对象,为了调用者传入的数据都能接收。然后调用类想取出工具类中的对象就需要强转(也就是调用者类型),这时没有泛型。
泛型类出现后做法:改变了格局,使程序员方便了很多。工具类前期指定类型,调用时就避免了强转。
2、定义泛型类
格式:类名<T>,T代表一个类型的名称
class GenericDemo<T>//定义泛型类
{
private T t;//定义泛型成员变量
public void setObject(T t)//设置set方法
{
this.t = t;
}
public T getObject()//设置get方法
{
return t;
}
public static void main(String[] args)
{
//实例化一个Boolean型的对象
GenericDemo<Boolean> gd1=new GenericDemo<Boolean>();
//实例化一个Float型的对象
GenericDemo<Float> gd2=new GenericDemo<Float>();
gd1.setObject(true);//不需要进行类型转换
gd2.setObject(10.2f);
Boolean b=gd1.getObject();
Float f=gd2.getObject();
System.out.println(b);
System.out.println(f);
}
}
3、泛型方法
为了让不同方法可以操作不同类型,而且类型还不确定。那么可以将泛型定义在方法上。
静态方法不可以访问类上定义的泛型。如果静态方法操作的应用数据类型不确定,可以将泛型定义在方法上。
泛型方法的特点:
1、位置:用于放置泛型的类型参数的<>应出现在方法的其他所有修饰符之后和在方法的返回类型之前,也就是紧邻返回值之前,按照惯例,类型参数通常用单个大写字母表示。
2、只有引用类型才能作为泛型方法的实际参数。
3、除了在应用泛型时可以使用extends限定符,在定义泛型时也可以使用extends限定符。例如,Class.getAnnotation()方法的定义。并且可以用&来指定多个边界,如<V extends Serializable& cloneable> void method(){}。
4、普通方法、构造函数和静态方法中都可以使用泛型。
5、可以用类型变量表示异常,称之为参数化的异常,可用于方法的throws列表中,但是不能用于catch子句中。
6、在泛型中可同时有多个类型参数,在定义它们的<>中用逗号分开。例如:
public static <K,V> V getValue(K key) { return map.get(key);}