---------------------- android培训、java培训、期待与您交流! ------------------------------------------------------------------------------------------------------------------------------------------------
Java中的网络编程
TCP和UDP概念:
UDP:
将数据以及源和目的封装成数据包中,不需要建立连接。
每个数据报的大小限制在64K内。
因为无连接,是不可靠的协议。
不需要建立连接,速度快。
TCP:
建立连接,形成传输数据的通道。
在连接中进行大数据量的传输。
通过三次握手完成连接,是可靠协议。
必须建立连接,效率会稍低。
Socket:
Socket就是为网络服务提供的一种机制。通信的两端都是Socket。网络通信其实就是Socket间的通信。
数据在两个Socket之间通过IO传输。
IP:
InetAddress:
此类表示互联网协议 (IP) 地址.该类没有构造函数,通过静态方法访问该类的对象。
public static InetAddressgetLocalHost()
返回本地主机IP地址对象。包括主机名和点分十进制IP。
public StringgetHostName()
获取此IP地址的主机名。
public StringgetHostAddress()
返回IP地址的点分十进制字符串。
通过给定的主机名获取该主机的ip地址对象。
public staticInetAddressgetByName(String host)
例子如下:
public class IpDemo {
public static void main(String[] args) throws Exception {
InetAddress i = InetAddress.getLocalHost();
System.out.println(i.toString());
System.out.println("HostAddress:" + i.getHostAddress());
System.out.println("HostName:" + i.getHostName());
System.out.println("***************************");
InetAddress ii = InetAddress.getByName("lenovo-PC");
System.out.println("HostAddress" + ii.getHostAddress());
}
}
InetAddress ia=InetAddress.getByName("www.baidu.com");
这样写也是可以的。字符串部分不一定非要写IP字符串的形式。
通过给定的主机名获取多个IP地址对象。
public static InetAddress[]getAllByName(String host)
UDP编程步骤:
1.DatagramSocket和DatagramPacket
2.建立发送端,接收端。
3.建立数据包。
4.调用Socket的发送接收方法。
5.关闭Socket。
发送端与接收端是两个独立的运行程序。
类DatagramSocket:
网络应用程序没有指定端口的话,系统会随机给程序分配一个端口号。
在定义udpsocket服务的接收端的时候,一般都会监听一个端口号。其实就是给这个接收程序定义数字标识。方便于明确哪些数据过来该应用程序可以处理。
这里所说的监听实际上也就是可以理解为将该逻辑端口号分配给了该程序。
public DatagramSocket(int port)
此类表示用来发送和接收数据报包的套接字。
public void send(DatagramPacket p)
public void receive(DatagramPacket p)
这两个方法是阻塞式的方法。
类DatagramPacket:
此类表示数据报包。
用来接收长度为length
的数据包
public DatagramPacket(byte[] buf, int length);
用来将长度为length
的包发送到指定主机上的指定端口号:
public DatagramPacket(byte[] buf,int length,InetAddress address,int port);
常用方法:
InetAddress getAddress()
返回某台机器的 IP 地址,此数据报将要发往该机器或者是从该机器接收到的。
byte[] getData()
返回数据缓冲区。
int getLength()
返回将要发送或接收到的数据的长度。
int getOffset()
返回将要发送或接收到的数据的偏移量。
int getPort()
返回某台远程主机的端口号,此数据报将要发往该主机或者是从该主机接收到的。
UDP的例子:
public class UdpSend {
public static void main(String[] args) throws Exception {
DatagramSocket ds = new DatagramSocket();
BufferedReader bufr = new BufferedReader(new InputStreamReader(
System.in));
String line = null;
while ((line = bufr.readLine()) != null) {
if ("886".equals(line))
break;
byte[] buf = line.getBytes();
DatagramPacket dp = new DatagramPacket(buf, buf.length, InetAddress
.getByName("111.6.145.105"), 10025);
ds.send(dp);
}
ds.close();
}
}
public class UdpReceive {
public static void main(String[] args) throws Exception {
DatagramSocket ds = new DatagramSocket(10025);
while (true) {
byte[] buf = new byte[1024];
DatagramPacket dp = new DatagramPacket(buf, buf.length);
ds.receive(dp);
String ip = dp.getAddress().getHostAddress();
String data = new String(dp.getData(), 0, dp.getLength());
System.out.println(ip + "....." + data);
}
}
}
TCP编程步骤:
1.Socket和ServerSocket。
2.建立客户端和服务器端。
3.建立连接后,通过Socket中的IO流进行数据的传输。
4.关闭Socket。
同样,客户端和服务器端的两个独立的应用程序。
客户端:
public class Socket 此类实现客户端套接字
常用的构造函数:
public Socket(String host, int port)
public Socket(InetAddress address, int port)
创建一个流套接字并将其连接到指定 IP地址的指定端口号。
如果是使用无参数的构造函数
public Socket()
要配合该类的方法public void connect(SocketAddress endpoint) 一并使用。
因为TCP是面向连接的,所以一开始就要构建连接。
因为TCP是面向连接的,所以在建立socket服务时,就要有服务端存在,并连接成功,形成通路后,在通道上进行数据传输。
一旦客户端和服务端连接成功后,就出现了Socket流,也就是网络流。
具体的Socket流是具体的客户端Socket产生的。
当客户端A和服务端建立连接以后,服务端就获取A对象。服务端利用客户端A的流和客户端A进行通信。这样客户端通过输出流写出数据,而服务端利用A的输入流读取数据。
而服务端利用A的输出流将数据写出,客户端通过输入流读取数据。
服务端:
常用的构造方法:
public ServerSocket(int port)
常用的方法:
public Socketaccept()
侦听并接受到此套接字的连接。
该方法是阻塞式方法,没有监听到连接就会等待。
以下是示例:
public class TCPServer {
public static void main(String[] args) throws Exception {
//创建服务端,监听10005端口。
ServerSocket ss=new ServerSocket(10005);
//接收客户端。
Socket s=ss.accept();
//获取客户端的IP
String ip=s.getInetAddress().getHostAddress();
System.out.println(ip+"....connected");
InputStream in=s.getInputStream();
byte[]buf=new byte[1024];
int len=in.read(buf);
System.out.println(new String(buf,0,len));
//客户端要关闭,因为一直连着客户端的话,就会浪费资源。
s.close();
ss.close();
}
}
public class TCPClient {
public static void main(String[] args) throws Exception, IOException {
Socket s =new Socket("127.0.0.1",10005);
OutputStream out=s.getOutputStream();
out.write("TCP 我来了".getBytes());
//此处流就不用关闭了,因为该输出流是Socket产生的。
s.close();
}
}
例子:
/*
* 需求:建立一个文本转换服务器。
* 客户端给服务端发送文本数据,服务端会将文本转换成大写返回给
* 客户端。而且客户端可以不断的进行文本处理,当客户端输入over
* 转换结束。
* 分析:
* 客户端:
* 既然是操作设备上的数据,那么就可以使用io技术,并按照IO操作的规律来思考。
* 源:键盘录入。
* 目的:网络设备,网络输出流。
* 而且是文本数据,所以选择字符流。
*/
public class TransClient {
public static void main(String[] args) throws Exception {
Socket s=new Socket("127.0.0.1",10006);
//定义字符读取流从键盘读取文本数据。
BufferedReader bufr=
new BufferedReader(new InputStreamReader(System.in));
//第一目的,将数据写入到socket输出流,发给服务端。
BufferedWriter bufOut=
new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
//第一一个socket读取流,读取服务端返回的大写文本数据。
BufferedReader bufIn=
new BufferedReader(new InputStreamReader(s.getInputStream()));
String line=null;
while((line=bufr.readLine())!=null)
{
if("over".equals(line))
break;
bufOut.write(line);
bufOut.newLine();
bufOut.flush();
String str=bufIn.readLine();
System.out.println("Server:"+str);
}
bufr.close();
s.close();
}
}
public class TransServer {
public static void main(String[] args) throws Exception {
ServerSocket ss=new ServerSocket(10006);
Socket s=ss.accept();
String ip=s.getInetAddress().getHostAddress();
System.out.println(ip+"....connected");
//从服务端的socket的输入流中读取数据。
BufferedReader bufIn=
new BufferedReader(new InputStreamReader(s.getInputStream()));
//socket输出流。将大写数据写入到服务端的输出流中。
BufferedWriter bufOut=
new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
String line=null;
while((line=bufIn.readLine())!=null)
{
bufOut.write(line.toUpperCase());
bufOut.newLine();
bufOut.flush();
}
s.close();
ss.close();
}
}
TCP上传文件案例:
public class TCPcopyFileClient {
public static void main(String[] args) throws Exception {
Socket s =new Socket("127.0.0.1",10007);
BufferedReader bufr=
new BufferedReader(new FileReader("F:\\demo1.txt"));
PrintWriter out =new PrintWriter(s.getOutputStream(),true);
String line=null;
while((line=bufr.readLine())!=null)
{
out.println(line);
}
s.shutdownOutput();//将客户端的输出流关闭。同时也是通知服务端的输入流关闭。
BufferedReader bufIn=new BufferedReader(new InputStreamReader(s.getInputStream()));
String str=bufIn.readLine();
System.out.println(str);
bufr.close();
s.close();
}
}
public class TCPcopyfileServer {
public static void main(String[] args) throws Exception {
ServerSocket ss = new ServerSocket(10007);
Socket s = ss.accept();
String ip = s.getInetAddress().getHostAddress();
System.out.println(ip + "....connected");
BufferedReader bufIn = new BufferedReader(new InputStreamReader(s
.getInputStream()));
PrintWriter out = new PrintWriter(new FileWriter("F:\\tcpcoyfile.txt"),
true);
String line = null;
while ((line = bufIn.readLine()) != null) {
out.println(line);
}
PrintWriter pw = new PrintWriter(s.getOutputStream(), true);
Thread.sleep(10000);
pw.println("上传成功!");
out.close();
s.close();
ss.close();
}
}
TCP图片上传案例:
public class PicClient {
public static void main(String[] args) throws Exception, IOException {
Socket s = new Socket("127.0.0.1", 10008);
FileInputStream fis = new FileInputStream("F:\\1.bmp");
OutputStream out = s.getOutputStream();
byte[] buf = new byte[1024];
int len = 0;
while ((len = fis.read(buf)) != -1) {
out.write(buf, 0, len);
}
s.shutdownOutput();
InputStream in = s.getInputStream();
byte[] bufIn = new byte[1024];
int num = in.read(bufIn);
System.out.println(new String(bufIn, 0, num));
fis.close();
s.close();
}
}
public class PicServer {
public static void main(String[] args) throws Exception {
ServerSocket ss = new ServerSocket(10008);
Socket s = ss.accept();
String ip = s.getInetAddress().getHostAddress();
System.out.println(ip + "....connected");
InputStream in = s.getInputStream();
FileOutputStream fos = new FileOutputStream("F:\\server.bmp");
byte[] buf = new byte[1024];
int len = 0;
while ((len = in.read(buf)) != -1) {
fos.write(buf, 0, len);
}
OutputStream out = s.getOutputStream();
Thread.sleep(10000);
out.write("上传成功!".getBytes());
fos.close();
s.close();
ss.close();
}
}
多线程访问服务端的案例:
public class PicClient {
public static void main(String[] args) throws Exception, IOException {
Socket s = new Socket("127.0.0.1", 10009);
FileInputStream fis = new FileInputStream("F:\\1.bmp");
OutputStream out = s.getOutputStream();
byte[] buf = new byte[1024];
int len = 0;
while ((len = fis.read(buf)) != -1) {
out.write(buf, 0, len);
}
s.shutdownOutput();
InputStream in = s.getInputStream();
byte[] bufIn = new byte[1024];
int num = in.read(bufIn);
System.out.println(new String(bufIn, 0, num));
fis.close();
s.close();
}
}
public class PicThread implements Runnable {
private Socket s;
public PicThread(Socket s) {
this.s = s;
}
public void run() {
int count=1;
String ip = s.getInetAddress().getHostAddress();
try {
System.out.println(ip + "....connected");
InputStream in = s.getInputStream();
File file=new File("F:\\"+ip+"("+(count)+")"+".jpg");
while(file.exists())
file= new File("F:\\"+ip+"("+(count++)+")"+".jpg");
FileOutputStream fos = new FileOutputStream(file);
byte[] buf = new byte[1024];
int len = 0;
while ((len = in.read(buf)) != -1) {
fos.write(buf, 0, len);
}
OutputStream out = s.getOutputStream();
Thread.sleep(10000);
out.write("上传成功!".getBytes());
fos.close();
s.close();
} catch (Exception e) {
throw new RuntimeException(ip + "上传失败!");
}
}
}
Java中的集合框架:
集合类:
public int hashCode()
返回该对象的哈希码值。支持此方法是为了提高哈希表(例如 java.util.Hashtable 提供的哈希表)的性能。
hashCode 的常规协定是:
@1.
在 Java 应用程序执行期间,在对同一对象多次调用 hashCode 方法时,必须一致地返回相同的整数,前提是将对象进行 equals 比较时所用的信息没有被修改。从某一应用程序的一次执行到同一应用程序的另一次执行,该整数无需保持一致。
@2.
如果根据 equals(Object) 方法,两个对象是相等的,那么对这两个对象中的每个对象调用 hashCode 方法都必须生成相同的整数结果。
@3.
如果根据 equals(java.lang.Object) 方法,两个对象不相等,那么对这两个对象中的任一对象上调用 hashCode 方法不 要求一定生成不同的整数结果。但是,程序员应该意识到,为不相等的对象生成不同整数结果可以提高哈希表的性能。
实际上,由 Object 类定义的 hashCode 方法确实会针对不同的对象返回不同的整数。(这一般是通过将该对象的内部地址转换成一个整数来实现的,但是 JavaTM 编程语言不需要这种实现技巧。)
这个地方在String中,只要是声明相同的两个不同的对象,返回的就是相同的hashcode值。
常规协定的意思是:就是重写时候要遵循的原则。
总的来说:equals相等,hashcode就相等。但是hashcode相等的,equals不一定就想等。
hashcode和内存地址值没有必然的联系,hashcode是为了更方便的从内存中找到对象。在特定的内存区域是特定的hashcode值。这样就可以不再从头至尾的遍历对象数据了。
hashcode是根据对象的信息,用hash算法计算得来的。如果hashcode相同,但是内容不同,会顺延从第二个位置开始存储起来。
Hash,一般翻译做“散列”,也有直接音译为"哈希"的,就是把任意长度的输入(又叫做预映射, pre-image),通过散列算法,变换成固定长度的输出,该输出就是散列值。这种转换是一种压缩映射,也就是,散列值的空间通常远小于输入的空间,不同的输入可能会散列成相同的输出,而不可能从散列值来唯一的确定输入值。
如果是基本变量,没有hashcode和equals方法,基本变量的比较方式就只有==;
如果是变量,由于在java中所有变量定义都是一个指向实际存储的一个句柄(你可以理解为c++中的指针),在这里==是比较句柄的地址(你可以理解为指针的存储地址),而不是句柄指向的实际内存中的内容,如果要比较实际内存中的内容,那就要用equals方法。
从而我认为所有的引用型的对象,和对象的实例,都是用hashMap或是HashTable的形式在内存中存储的。
这个时候,如果再存取对象的时候,先计算出来该对象的hashcode值,判断该值在内存中的哪个区域中,然后在调用equals方法进行比较查找。缩短了查询的周期,这样就提高了效率。
注意的是:hashcode对于Hash结构才有意义。
如果是集合Arraylist的话,实现hashcode对Arraylist集合来说,是没有任何意义的。
但是对于HashSet来说,如果不重写hashcode方法的话,那么会调用Object中的hashcode方法(是根据内存地址值来得到hashcode值的,在hashcode的常规协定中有提到)。就算出来的hashcode值都是不同的,所以就会令实际上我们认为相同的元素,却存储在不同的区域中。
假设Person类就一个属性 name。
这样的话,如果Hashset集合中本来有一个对象new Person(“张三”),当再次插入一个new Person(“张三”)。
按照内存地址值来计算了,所以这两个Person对象就不再存储在相同的区域中了,这时候就无需再调用equals方法了,因为hashcode本来就不相同,所以更不不必要调用了。这就违背了现实中的意义。从而也和set集合的初衷,保持元素的唯一性违背了。
所以,为了Hash结构,java中有对hashcode的常规协定,如果equals方法相同,则必须要有相同的hashcode,这就是为了在插入元素的时候,能够在该对象hashcode所指定的区域中查找是否已经存在了相同的元素。从而保证了Set集合中元素的唯一性。
Object 类的 equals 方法实现对象上差别可能性最大的相等关系;即,对于任何非空引用值 x 和 y,当且仅当 x 和 y 引用同一个对象时,此方法才返回 true(x == y 具有值 true)。
注意:当此方法被重写时,通常有必要重写 hashCode 方法,以维护 hashCode 方法的常规协定,该协定声明相等对象必须具有相等的哈希码。
add方法的参数类型是Object。以便于接收任意类型的对象。
集合中存储的都是对象的引用。
迭代器:
把取出方式定义在集合的内部,
这样取出方式就可以直接访问集合内容的元素。
另外取出的方式不足以用一个函数表示,要用多个动作来表示(例如判断还有没有元素,取出数据等等)。
那么取出方式就被定义为内部类。
而每一个容器的数据结构不一样,所以取出的动作细节也不相同。但是都有共性内容:判断和取出。那么可以将共性抽取。
这些内部类都符合一个规则,该规则就是Iterator。
如何获取集合的取出对象呢?
通过一个对外提供的方法。Iterator().
Collection
|-----------List:元素是有序的,元素可以重复。因为该集合体系有索引。
|-----------Set :元素是无序的,不可以重复。
List:凡是操作角标的方法都是该体系的特有方法。
增:
add(index,element);
addAll(index,Collection);
删:
remove(index);
改:
set(index,element);
查:
get(index);
subList(from,to);
listIterator();
如果是迭代器引用和集合引用指向同一个集合,就不能同时使用集合的方式,迭代器方式来操作数据。
另外Iterator具有局限性,只能删除元素而不能增加元素等等。
List集合特有的迭代器ListIterator是Iterator的子接口。
在迭代时,如果二者都指向一个集合,不可以通过集合对象的方式操作集合中的元素。因为会发生并发修改异常。
所以,在迭代的时候,只能用迭代器的方法操作元素,可是Iterator方式具有局限性
只能对元素进行判断,取出,删除等等。
如果想要其他的操作如添加,修改等,就需要使用其子接口,ListIterator.
该接口只能通过List集合的listIterator方法获取。
ArrayList:底层的数据结构使用的是数组结构。查询速度很快。增删很慢。线程不同步。
LinkedList:底层使用的链表数据结构。增删很快,查询很慢。
Vector: 底层是数组数据结构。增删和查询都很慢。被ArrayList所取代。线程同步。
Set接口的具体子类对象:
HashSet:底层数据结构是哈希表。
TreeSet:底层用的是二叉树数据结构。可以对Set集合中的元素进行排序。
对于List接口“是有序的”是说存储的顺序和取出的顺序是一致的。即先存的数据先取。
对于Set接口。是无序的,是说存入和取出的顺序不一致。
List和Set可以通过构造函数相互转化。如果是将List转化为了Set,就会将List中重复的元素去掉。
HashSet(Collection<? extends E> c)
构造一个包含指定 collection中的元素的新 set。
TreeSet(Collection<? extends E> c)
构造一个包含指定 collection元素的新 TreeSet,它按照其元素的自然顺序进行排序。
在Object中的toString()方法的实现是:
哈希值是根据内存地址值计算出来的。
getClass().getName() + '@' + Integer.toHexString(hashCode())
具体存储的时候,是根据哈希值来存储的,所以存储在表中的顺序和存储时候的顺序不一定是一致的。取出的时候,按照哈希表顺序来取。
如果两个对象的哈希值是相同的,那么再调用equals()方法对两个对象内容进行比较。看两个对象的内容是否是相同的,如果不相同,第二个对象顺延第一个对象存储。两个都存储。如过相同,则第二个不存储。
如果哈希值不同,则不用调用equals()方法。
一般hashCode()方法都是用到比较的条件来覆写的。
ArrayList和LinkedList判断对象是否存在contains以及删除remove对象依赖的仅是equals()方法。
public class ListIteratorDemo {
public static void main(String[] args) {
List<String>list=new ArrayList<String>();
list.add("java01");
list.add("java02");
list.add("java04");
System.out.println(list);
ListIterator<String>lit=list.listIterator();
while(lit.hasNext()){
if("java02".equals(lit.next())){
lit.add("java03");
}
}
System.out.println(list);
}
list.contains(obj).调用的时候是obj.equals(list.get(i))。
是contains方法的参数调用equals方法和list中的元素进行比较。
remove方法相同。
而HashSet集合判断对象是否存contains在以及删除remove对象依赖的hashCode()和equals().先计算比较hashCode()方法的结果,再进行equals()方法比较。
TreeSet可以对集合中过得元素进行排序。
如果是按照存储时的顺序来取出:则compareTo()方法返回的是1.
如果是按照存储时相反的顺序取出:则compareTo()方法返回的是-1.
如果只取一个元素,则compareTo返回0;
TreeSet的两种排序方式:
集合元素实现Comparable接口,覆写compareTo()方法。
目的就是让元素具有比较性。
此种方式也称为元素的自然顺序,或者叫做默认顺序。
对应的是TreeSet的空参数的构造函数。
当元素自身不具备比较性或元素具备的比较性不是所需要的。
这时就需要让集合自身具备比较性。
具体做法是:让集合初始化时就具有比较方式。
对应的是参数为 比较器对象 的构造函数。
定义一个类,实现Comparator接口,覆盖compare方法。
public class TreeSetFirst {
public static void main(String[] args) {
Set<Male> ts = new TreeSet<Male>();
ts.add(new Male("zhang1", 21));
ts.add(new Male("zhang2", 22));
ts.add(new Male("zhang3", 21));
System.out.println(ts);
}
}
class Male implements Comparable<Male> {
private String name;
private int age;
public Male(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return this.name;
}
public int getAge() {
return this.age;
}
public String toString() {
return this.name + ".." + this.age;
}
@Override
public int compareTo(Male obj) {
Male male = (Male) obj;
int num = new Integer(this.age).compareTo(new Integer(male.getAge()));
if (num == 0) {
return this.name.compareTo(male.getName());
}
return num;
}
}
public class TreeSetSecond {
public static void main(String[] args) {
Set<Student> ts = new TreeSet<Student>(new MyComparator());
ts.add(new Student("aa", 21));
ts.add(new Student("ab", 21));
ts.add(new Student("a" , 21));
ts.add(new Student("aa", 20));
System.out.println(ts);
}
}
class MyComparator implements Comparator<Student> {
@Override
public int compare(Student s1, Student s2) {
int num = new Integer(s1.getName().length()).compareTo(new Integer(s2
.getName().length()));
if (num == 0) {
int num1 = s1.getName().compareTo(s2.getName());
if (num1 == 0) {
return new Integer(s1.getAge()).compareTo(new Integer(s2
.getAge()));
}
return num1;
}
return num;
}
}
class Student {
private String name;
private int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return this.name;
}
public int getAge() {
return this.age;
}
public String toString() {
return this.name + ".." + this.age;
}
}
Map集合:
该集合存储键值对。一对一对往里存储。而且要保证键的唯一性。
Hashtable:
底层是哈希表数据结构,不可以存入null作为键,null作为值。该集合时线程同步的。jdk1.0.效率低
HashMap:
底层是哈希表数据结构,可以存入null作为键,null作为值。该集合非线程同步的。
jdk1.2.效率高。
TreeMap:
底层是二叉树结构。线程是非同步的。可以对map集合中的键进行排序。
Set结合底层调用的是Map集合,只是将值的部分忽略掉了。
第一个返回的打印的结果是:null。
第二个返回的结果是:zhangsan1.
public class HashMapFirst {
public static void main(String[] args) {
Map<Big, String> map = new HashMap<Big, String>();
map.put(new Big("zhangsan1", 21), "beijing");
map.put(new Big("zhangsan2", 22), "tianjin");
map.put(new Big("zhangsan3", 23), "wuhang ");
System.out.println(map);
map.put(new Big("zhangsan1", 21), "xxxxxxx");
System.out.println(map);
}
}
class Big {
private String name;
private int age;
public Big(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return this.name;
}
public int getAge() {
return this.age;
}
public String toString() {
return this.name + "........." + this.age;
}
@Override
public int hashCode() {
System.out.println(this.name + "... workout hashcode..");
final int prime = 31;
int result = 1;
result = prime * result + age;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof Big)) {
throw new RuntimeException("Transform Error!");
}
Big big = (Big) obj;
System.out.println(this.name + "...compare to..." + big.name);
return this.name.equals(big.getName()) && this.age == big.getAge();
}
}
Map集合添加时。如果添加数据对的键是相同的,后添加的值会覆盖之前的值。并且put()
方法会返回被覆盖的值。
Map集合将所有的键值对取出:
方式1:keySet:
将map中所有的键存入到Set集合,因为set具备迭代器,根据get()方法,获取每一个键的值。
方式2:entrySet:
Set<Map.Entry<k,v>>entrySet:将集合中的映射关系存入到了Set集合中。而这个关系的数据类型是:Map.Entry.
public class MapFirst {
public static void main(String[] args) {
Map<String, String> map = new HashMap<String, String>();
map.put("01", "zhangsan1");
map.put("02", "zhangsan2");
map.put("03", "zhangsan3");
map.put("04", "zhangsan4");
getElement(map);
System.out.println("********************************");
getElement_1(map);
}
private static void getElement(Map<String, String> map) {
Set<String> keySet = map.keySet();
Iterator<String> it = keySet.iterator();
while (it.hasNext()) {
String key = it.next();
String value = map.get(key);
System.out.println(key + "....." + value);
}
}
private static void getElement_1(Map<String, String> map) {
Set<Map.Entry<String, String>> entrySet = map.entrySet();
Iterator<Map.Entry<String, String>> it = entrySet.iterator();
while (it.hasNext()) {
Map.Entry<String, String> entry = it.next();
String key = entry.getKey();
String value = entry.getValue();
System.out.println(key + "------------------" + value);
}
}
}
注意:
在HashMap中,Map的键的存储结构是哈希表结构,但是和HashSet不同的是,HashMap中如果键相同的话,是将这个键对应的值覆盖之前的值,而在hashSet中,如果hashcode相同,equals也相同的话,就会不存储新的元素。
同时,比较的时候的细节,如果是数组或哈希表为底层数据结构的集合容器的话,调用contians,remove是顺序比较目标之前所有的元素。
而以二叉树为数据结构的容器,则不是目标之前的全部比完,假设一个节点是21,21左边有个节点是19. 那么再次插入一个节点22的话,只用和21比就好了,没必要和19比较。
TreeMap 的键的存储结构是二叉树,但是和TreeSet不同的是。
Map集合的特点就是,如果键相同,新的值覆盖旧的值。
Comparable<E e>这个泛型应该填什么类型呢,一般是哪个类继承这个接口,泛型就是哪个类。
public class CollectionsSortFirst {
public static void main(String[] args) {
List<Foot> list=new ArrayList<Foot>();
list.add(new Foot("bbb"));
list.add(new Foot("a"));
list.add(new Foot("cc"));
System.out.println(list);
Foot f=Collections.max(list);
System.out.println("Max:"+f);
Collections.sort(list);
System.out.println(list);
}
}
class Foot implements Comparable<Foot> {
private String name;
public Foot(String name) {
this.name = name;
}
public String getName() {
return name;
}
public String toString(){
return this.name;
}
@Override
public int compareTo(Foot o) {
int num=this.name.compareTo(o.getName());
return num;
}
}
Comparator<E e >这个泛型对于Set集合而言,添加的是什么类型的元素,泛型就是什么类型。
public class CollectionsSortSecond {
public static void main(String[] args) {
List<Foot> list = new ArrayList<Foot>();
list.add(new Foot("aaa"));
list.add(new Foot("b"));
list.add(new Foot("cc"));
System.out.println(list);
Foot f = Collections.max(list, new StringLength());
System.out.println("Max:" + f);
Collections.sort(list, new StringLength());
System.out.println(list);
}
}
class StringLength implements Comparator<Foot> {
@Override
public int compare(Foot o1, Foot o2) {
int num = new Integer(o1.getName().length()).compareTo(new Integer(o2
.getName().length()));
if (num == 0) {
return o1.getName().compareTo(o2.getName());
}
return num;
}
}
对于Map集合而言,因为TreeMap集合的键是以二叉树为基础的,所以键是什么类型的,泛型就是什么类型的。
言语匮乏,用心领悟。
Utils包中的Collections和Arrays工具类。
Collections中常用的方法:
Collections工具类中提供的涉及到排序的,都没有Set,因为Set集合有TreeSet,但是其他的例如最值,二分查找等传入的接口参数为Collection.
sort方法:
public static <T extends Comparable<? super T>> void sort(List<T> list)
该方法接收一个类型为T的List集合,
T extends Comparable<? super T>
是对泛型进行了限制。因为是要排序,所以List集合中的元素就要具备比较性,所以T必须是Comparable接口的子类。同时为了更大的扩展。Comparable的泛型中的对象可以是T的父类类型。? super T 所表示的类型是T及其T以上的类型。
(T extends Comparable< T> 这个就是一个最特殊的了,容易理解)
例如Person类实现了Comparable接口,而Student类继承了Person类
这样上述情况实际的含义就是表示:
public static< Student extends Person> void sort( List<Student> list)
只能给List排序。
该方法时用元素实现Comparable接口来实现排序的,也是自然排序的。
public static <T> void sort(List<T> list,Comparator<? super T> c)
该方法是根据指定的比较器进行排序的。这个T不用做限定,因为有了比较器,就不用再用元素内部的比较性了。
max方法:
public static <T extends Object &Comparable<? super T>> Tmax(Collection<? extends T> coll)
和上边的类似,传入的对象只是一个集合,集合中的元素就要有自然的比较性。
| max |
根据指定比较器产生的顺序,返回给定 collection的最大元素。
binarySearch:折半查找
public static <T> intbinarySearch(List<? extends Comparable<? super T>> list, T key)
强调一点的是调用binarySearch()方法传入的集合必须是有序的集合。返回的是角标值。
Fill方法。
将集合中所有的值都替换为obj.
public static <T> void fill(List<? super T> list, T obj)
replaceAll方法。
将某一个旧值替换为新值。
public static <T> boolean replaceAll(List<T> list, T oldVal, T newVal)
reverse方法。
public static void reverse(List<?> list)
反转指定列表中元素的顺序。
public class CollectionsMethod {
@Test
public void SortList() {
List<String> list = new ArrayList<String>();
list.add("java01");
list.add("java03");
list.add("java02");
System.out.println(list);
String max = Collections.max(list);
System.out.println("Max:" + max);
Collections.sort(list);
System.out.println(list);
int index = Collections.binarySearch(list, "java02");
System.out.println("java02index:" + index);
}
@Test
public void FillMethod() {
List<String> list = new ArrayList<String>();
list.add("java01");
list.add("java03");
list.add("java02");
System.out.println(list);
Collections.fill(list, "zwt");
System.out.println(list);
}
@Test
public void ReplaceAllDemo() {
List<String> list = new ArrayList<String>();
list.add("java01");
list.add("java03");
list.add("java02");
list.add("java01");
System.out.println(list);
Collections.replaceAll(list, "java01", "wt");
System.out.println(list);
}
@Test
public void ReverseDemo() {
List<String> list = new ArrayList<String>();
list.add("java01");
list.add("java02");
list.add("java03");
System.out.println(list);
Collections.reverse(list);
System.out.println(list);
}
}
reverseOrder方法。
1.public static <T> Comparator<T> reverseOrder()
返回一个比较器,它强行逆转实现了Comparable接口的对象 collection的自然顺序(自然顺序是通过对象自身的compareTo方法强行排序的。)。
2.public static <T> Comparator<T> reverseOrder(Comparator<T> cmp)
返回一个比较器,它强行逆转指定比较器的顺序。如果指定比较器为 null,则此方法等同于reverseOrder().
代码示例:
public class CollectionsReverseOrder {
@Test
public void reverseDemo1() {
Set<Foot> ts=new TreeSet<Foot>(Collections.reverseOrder());
ts.add(new Foot("zzzzz"));
ts.add(new Foot("aaaa"));
ts.add(new Foot("kk"));
System.out.println(ts);
}
@Test
public void reverseDemo2(){
Set<Foot>ts=new TreeSet<Foot>(Collections.reverseOrder(new StringLength()));
ts.add(new Foot("zzzzz"));
ts.add(new Foot("aaaa"));
ts.add(new Foot("kk"));
System.out.println(ts);
}
}
Arrays工具类多看看
提供了对数组操作的很多方法。
将数组变为字符串。
将数组转换为字符串。
asList方法。
将数组转换为集合。
public static <T> List<T>asList(T... a)
为什么要将数组变为list集合呢?
可以使用集合的思想和方法来操作数组中的元素。
例如:判断字符数组arr中是否包含某个字符 m.如果直接操作数组的话,会很麻烦,要遍历要判断,效率会很低。
但是如果转换为list的时候,就会有很简单的方法contains()方法来判断是否包含m.
但是数组转化而成的list集合不可以使用集合的增删方法。因为数组的长度是固定的。
将集合变为数组。在Collection接口中的方法。
toArray();
T[] toArray(T[] a)
示例代码:
public class CollectionArrayTransform {
@Test
public void CollectiontoArray_1() {
List<String> list = new ArrayList<String>();
list.add("java01");
list.add("java02");
list.add("java03");
Object[] obj = list.toArray();
System.out.println("********pattern1***********");
for (int i = 0; i < obj.length; i++) {
System.out.print(obj[i]);
}
System.out.println();
System.out.println("********pattern2***********");
String strarr = Arrays.toString(obj);
System.out.println(strarr);
}
@Test
public void CollectiontoArray_2() {
List<String> list = new ArrayList<String>();
list.add("java01");
list.add("java02");
list.add("java03");
String[] listarr = list.toArray(new String[list.size()]);
String arrstr = Arrays.toString(listarr);
System.out.println(arrstr);
}
@Test
public void ArraytoList() {
String[] arr = { "zhang1", "zhang2", "zhang3" };
List<String> list = new ArrayList<String>();
list = Arrays.asList(arr);
System.out.println(list);
}
}
------------------------android培训、java培训、期待与您交流! -----------------------------------------------------------------------------------------------------------------------------------------------