java18章网络编程

OSI7层模型解释:

1:物理层:数据作为原始的比特流(bit),典型的设备包括集线器(Hub)

2:数据链路层:数据链路层负责两个相邻的节点间的线路上,无差错的传送以帧(Frame)为单位的数据
如果接收方检测到所传的数据中有差错,就要通知发送方重新发送这一帧,本层的典型设备是交换机。

3:网络层:源主机和目标主机的网络地址进行通信

4:传输层:传输和取消的连接功能以可靠方式传输的数据单位称为段,以不可靠的传输单位称为数据报

5:会话层:会话层管理进程之间的会话过程 负责建立,管理和连接进程之间的会话,比如说QQ我跟你说话就表示在会话这一层.

6:表示层:表示层对上层的数据进行转换,以保证一个主机的应用层的数据可以被另一个主机的应用层理解,表示层包括,加密-解密-压缩-解压和格式转换
7:应用层:应用层确定进程之间通信的实际用途,以满足用户的实际请求,例如浏览Web站点 收发E-mail,上传或下载文件等.

TCP/IP模型:程序员应要做的就是在应用这一层里面
TCP协议是面向连接的可靠的通信协议,
而UDP是非连接的不可靠的通信协议,
这两个协议位于TCP/IP模型的传输层,要在网络上找到另一台计算机的程序进行通讯需要提供IP地址和端口号.

Socke是客户端ServerSocke是服务器端,Socket和ServerSocke用于在两个java程序之间创建一个TCP/IP连接,程序之间的通讯通过IO类来执行

下面给大家贴一段代码f是服务器端f1是客服端

服务器端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
package ccc;
import java.awt.Container;
import java.awt.GridLayout;
import java.awt.LayoutManager;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketTimeoutException;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JTextArea;
import javax.swing.JTextField;


public class f extends JFrame implements Runnable {
ServerSocket svr;
JTextArea w;
public f(int port) throws IllegalArgumentException, IOException {
Container m = this.getContentPane();
m.setLayout(new GridLayout(3, 1));
this.setSize(300, 450);
this.setTitle("服务端");
this.setVisible(true);
this.setLocationRelativeTo(null);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
w = new JTextArea(100, 200);
this.add(w);
svr = new ServerSocket(port);
}
public void run() {
while (true) {
System.out.println("在端口" + svr.getLocalPort() + "上等待客户端...");
Socket server;
try {
server = svr.accept(); //服务器等待方法
System.out.println("刚连接" + server.getReuseAddress());
DataInputStream in = new DataInputStream(server.getInputStream());
w.setText(in.readUTF());
server.close();
} catch (SocketTimeoutException e) {
break;
} catch (IOException e) {
e.printStackTrace();
break;
}
}
}
public static void main(String[] args) {
try {
f x = new f(8088);
Thread f = new Thread(x);
f.start();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}

客服端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
package ccc;
import java.awt.Container;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.event.AncestorEvent;
import javax.swing.event.AncestorListener;
public class f1 extends JFrame {
JTextField s;
JButton an;
public f1() {

Container m = this.getContentPane(); //内容面板
m.setLayout(new GridLayout(2, 1)); //布局
this.setSize(300, 450); //大小
this.setTitle("客户端"); //名称
this.setVisible(true); //可见
this.setLocationRelativeTo(null); //居中
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //关闭
s = new JTextField();
an = new JButton("提交");
this.add(s);
m.add(an);
s.setBounds(10, 10, 150, 200);
an.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
ke();
}
});
}
public void ke() {
String serverNanme = "localhost";//客户端进行连接服务端
int prot = 8088; //端口
System.out.println("端口" + prot + "连接" + serverNanme);
try {
Socket ck = new Socket(serverNanme, prot);//NEW了一个Socket对象
System.out.println("本地主机:" + ck.getRemoteSocketAddress());
OutputStream ccc = ck.getOutputStream();
DataOutputStream cc1 = new DataOutputStream(ccc);
cc1.writeUTF(s.getText());
ck.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String [] args) {
new f1();
}
}

第17章I/O系统流

IO流:

IO流:当程序需要读取数据的时候,就会开启一个通向数据源设备的流

IO有具体的分类

1 根据处理的数据类型不同:字节流和字符流
2 根据流向不同:输入流和输出流

字节流和字符流的区别:

1 字节流读取的时候,读到一个字节就返回一个字节字符流使用了字节流读到一个或多个字节(中文对应的字节数是两个,在UTF-8码表中是3个字节)时.先去查指定的编码表,将查到的字符返回
2字节流可以处理所有类型数据,如图片,MP3,AVI而字符流只能处理字符数据.
结论:只有是处理纯文本数据,就要优先考虑使用字符流.除此之外都用字节流
IO的体系.所具备的基本功能就有两个:读和写

  1. 字节流:inputStream(读),OutputStream(写)
  2. 字符流: Reader(读),Writer(写)

比较常用的流有 文件流——处理流——对象流

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
 public static void main(String []args) throws FileNotFoundException,IOException {
FileInputStream w=new FileInputStream("D:\\CC.txt");//字节输入流 这是字节流输入流
BufferedInputStream d=new BufferedInputStream(w);//缓存区 这是缓存流
FileOutputStream c=new FileOutputStream("D:\\hhw.txt"); // 写出流 这是字节写出流
int b;
while((b = d.read())!=-1) {
c.write(b);
}
c.flush(); //刷新
d.close(); //关闭写出字节流
c.close(); //关闭写出缓存区字节流
}
}
字节流:
FileInputStream w=new FileInputStream("D:\\CC.txt");//字节输入流
FileOutputStream c=new FileOutputStream("D:\\hhw.txt"); // 写出流
InputStreamReader w=new InputStreamReader("D:\\CC.txt");//字符输入流
OutputStreamReader c=new OutputStreamReader("D:\\hhw.txt"); // 字符写出流

↓ ↑
FileInputStreamReader w=new FileInputStreamReader("D:\\CC.txt");//字符输入流
FileOutputStreamReader c=new FileOutputStreamReader("D:\\hhw.txt"); // 字符输出流

处理流:
BufferedInputStream d=new BufferedInputStream(w);//缓存区 可以整行读取 字节缓存流
BufferedOutputStream d=new BufferedOutputStream(w);//缓存区 可以整行写出 字节缓存流

对象流:
ObjectIputStream 对象序列化

第15章集合框架

集合框架:

java集合框架中的对象容器,按照对象在其中的存储方式,分为List -Set和Map三种类型.
Set类型对象容器中没有顺序,且不能重复;List类型对象容器中的对象按照索引顺序排序,而且可以有重复的对象;Map类型对象容器中的元素包含一对 ”键对象–值对象“映射,其中键对象不能重复,值对象可以重复。三种存储方式对应java集合框架中 Set List 和Map 三个接口.
java集合层次流程图:画黑色边框的是重点掌握的内容(1-Collection接>2-Map接口>Iterator迭代器)

第二版文字说明:

Collection

|--List:元素是有序的,元素可以重复。因为该集合体系有索引。
        |--ArrayList:底层的数据结构使用的是数组结构。特点:查询速度很快。但是增删稍慢。线程不同步。
        |--LinkedList:底层使用的链表数据结构。特点:增删速度很快,查询稍慢。线程不同步。
        |--Vector:底层是数组数据结构。线程同步。被ArrayList替代了。因为效率低。(特有的: 枚举)

|--Set:元素是无序(存入和取出的顺序不一定一致),元素不可以重复。
        |--HashSet:底层数据结构是哈希表。是线程不安全的。不同步。
                HashSet是如何保证元素唯一性的呢?
                是通过元素的两个方法,hashCode和equals来完成。
                如果元素的HashCode值相同,才会判断equals是否为true。
                如果元素的hashcode值不同,不会调用equals。
                注意,对于判断元素是否存在,以及删除等操作,依赖的方法是元素的hashcode和equals方法。
                Set集合的功能和Collection是一致的。
        |--TreeSet:可以对Set集合中的元素进行排序。
                底层数据结构是二叉树。
                保证元素唯一性的依据:compareTo方法return 0.
                TreeSet排序的第一种方式:
                        让元素自身具备比较性。
                        元素需要实现Comparable接口,覆盖compareTo方法。
                        这种方式也称为元素的自然顺序,或者叫做默认顺序。
                TreeSet的第二种排序方式:
                        当元素自身不具备比较性时,或者具备的比较性不是所需要的。
                        这时就需要让集合自身具备比较性。
                        在集合初始化时,就有了比较方式

Map

|--Hashtable:底层是哈希表数据结构,不可以存入null键null值。该集合是线程同步的。jdk1.0.效率低。
|--HashMap:底层是哈希表数据结构,允许使用 null 值和 null 键,该集合是不同步的。将hashtable替代,jdk1.2.效率高。
|--TreeMap:底层是二叉树数据结构。线程不同步。可以用于给map集合中的键进行排序。

map集合的两种取出方式:

1,Set keySet:将map中所有的键存入到Set集合。因为set具备迭代器。
所有可以迭代方式取出所有的键,在根据get方法。获取每一个键对应的值。

Map集合的取出原理:将map集合转成set集合。在通过迭代器取出。

2,Set> entrySet:将map集合中的映射关系存入到了set集合中,
而这个关系的数据类型就是:Map.Entry
Entry其实就是Map中的一个static内部接口。
为什么要定义在内部呢?
因为只有有了Map集合,有了键值对,才会有键值的映射关系。
关系属于Map集合中的一个内部事物。
而且该事物在直接访问Map集合中的元素。

第12章反射

反射加载类与垃圾回收

1 类的加载机制:

类的加载→连接→ 初始化
java类文件通过类加载器加载到内存中. 类加载器包括底层
[类加载器↔扩展类加载器↔应用类加载器]
1 JVM运行底层加载器,该加载器加载java核心API
2 扩展类加载器:加载搜索 JAVA_HOME/jre/lib/ext目录,加载扩展API
3 应用类加载器:加载搜索CLASSPATH目录,加载我们要运行的类
javaAPI中还提供了一个对应的Class对象有一个ClassLoader抽象类,可以通过继承ClassLoader基类来创建自定义的类加载器

2 反射:

使用反射查看类的信息
在java程序中获得Class对象的方式有3种
第一种 知道类的名称时:在编译期不知道类名,但在运行期可以获得该类名的时候使用Class类的forName()静态方法可以获得Class对象例如: Class c=Class.forName(“全限定类名”);
Class c=Class.forName(“java.lang.System”);这是第一种知道类的名称时.

第二种 在编译时知道类的名称:如果在编译期知道类名的情况,可以调用该类的class属性来获得该类对象的Class对象 例如:Class c = 类名.Class;
Class c= Student.Class 这是第二种在编译时知道类的名称来获取信息

第三种 知道对象的时候:如果一个类的实例对象以及得到,则调用该对象的getClass()方法返回该对象所属类对应的Class对象。getClass()方法是java.lang.Object类的方法之一,所以所有对象都可以调用该方法. 例如:Class c= 对象名.getClass(); 这是知道对象的时候用对象名称调用,比如说一个类的实例new扭了一个Student对象 Class c=Student.getClass();

3垃圾回收:

在java中,当对象被创建后,就会拥有一块内存。在程序运行时,JVM会陆续创很多对象,如果所有对象都永久占用内存,那么系统内存有可能很快被消耗,最好引发内存空间不足必须采用某种方法及时回收哪些无用对象的内存,以保证内存可以被重复利用。finalize()方法对象的finalize()方法可以帮助我们完成一些释放对象所占用的资源等收尾工作但是垃圾回收器是否会执行finalize方法以及何时执行该方法,都是不确定的.

1
2
3
4
5
6
7
publicclassA
{
public void finalize()
{
System.out.println("A finalized");
}
}

总结:

使用反射查看信息有3种方法

第1种知道类的名称时
第2种在编译时知道类的名称
第3种知道对象的时候
垃圾回收没有实例指向对象的时候就被回收 ###

反射的工作原理

JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
Java的反射机制的实现要借助于4个类:class,Constructor,Field,Method;其中class代表的是类对 象,Constructor-类的构造器对象,Field-类的属性对象,Method-类的方法对象。通过这四个对象我们可以粗略的看到一个类的各个组 成部分。
Reflection 是 Java 程序开发语言的特征之一,它允许运行中的 Java 程序对自身进行检查,或者说“自审”,并能直接操作程序的内部属性。
reflection的工作机制,如下简单的例子
Java代码

1
2
3
4
5
6
7
8
9
10
import java.lang.reflect.Method;  
public class ReflectTest {
public static void main(String args[]) throws ClassNotFoundException {
Class c = Class.forName("java.util.ArrayList");
Method[] m = c.getDeclaredMethods();
for (Method method : m) {
System.out.println(method.toString());
}
}
}

这个程序使用 Class.forName 载入指定的类,然后调用 getDeclaredMethods 来获取这个类中定义了的方法列表。java.lang.reflect.Methods 是用来描述某个类中单个方法的一个类。

Java类反射中的主要方法:

构造函数:

Constructor getConstructor(Class[] params) – 获得使用特殊的参数类型的公共构造函数,
Constructor[] getConstructors() – 获得类的所有公共构造函数
Constructor getDeclaredConstructor(Class[] params) – 获得使用特定参数类型的构造函数(与接入级别无关)
Constructor[] getDeclaredConstructors() – 获得类的所有构造函数(与接入级别无关)

字段:

Field getField(String name) – 获得命名的公共字段
Field[] getFields() – 获得类的所有公共字段
Field getDeclaredField(String name) – 获得类声明的命名的字段
Field[] getDeclaredFields() – 获得类声明的所有字段

方法:

Method getMethod(String name, Class[] params) – 使用特定的参数类型,获得命名的公共方法
Method[] getMethods() – 获得类的所有公共方法
Method getDeclaredMethod(String name, Class[] params) – 使用特写的参数类型,获得类声明的命名的方法
Method[] getDeclaredMethods() – 获得类声明的所有方法
JDK1.5以后关于注解的:
Annotation[] getAnnotations() – 获得所有公共注解
Annotation[] getDeclaredAnnotations() – 获得声明的所有注解
AnnotationType getAnnotationType() – 获得注解的类型
用于 reflection 的类,如 Method,可以在 java.lang.relfect 包中找到。使用这些类的时候必须要遵循三个步骤:

获得你想操作的类的 java.lang.Class 对象。
调用诸如 getDeclaredMethods 的方法,以取得该类中定义的所有方法的列表。
使用 reflection API 来操作这些信息。

反射的安全性:

在处理反射时安全性是一个较复杂的问题。反射经常由框架型代码使用,由于这一点,我们可能希望框架能够全面接入代码,无需考虑常规的接入限制。但是,在其它情况下,不受控制的接入会带来严重的安全性风险,例如当代码在不值得信任的代码共享的环境中运行时。由于这些互相矛盾的需求,Java编程语言定义一种多级别方法来处理反射的安全性。基本模式是对反射实施与应用于源代码接入相同的限制:
从任意位置到类公共组件的接入
类自身外部无任何到私有组件的接入
受保护和打包(缺省接入)组件的有限接入
不过至少有些时候,围绕这些限制还有一种简单的方法。我们可以在我们所写的类中,扩展一个普通的基本类 java.lang.reflect.AccessibleObject 类。这个类定义了一种setAccessible方法,使我们能够启动或关闭对这些类中其中一个类的实例的接入检测。唯一的问题在于如果使用了安全性管理 器,它将检测正在关闭接入检测的代码是否许可了这样做。如果未许可,安全性管理器抛出一个例外。
下面是一段程序:
Java代码

1
2
3
4
5
6
7
8
9
10
11
12
public static void main(String args[]) throws ClassNotFoundException {  
try {
String test = "";
Class clas = test.getClass();
Field field = clas.getDeclaredField("count");
// field.setAccessible(true);
System.out.println(field.get("test"));
} catch(Exception e) {
System.out.println("Exception");
e.printStackTrace(System.out);
}
}

如果我们编译这一程序时,不使用任何特定参数直接运行,它将在field .get(“test”)调用中抛出一个IllegalAccessException异常。如果我们不注释 field.setAccessible(true)代码行,那么重新编译并重新运行该代码,它将编译成功。最后,如果我们在命令行添加了JVM参数 -Djava.security.manager以实现安全性管理器,它仍然将不能通过编译,除非我们定义了ReflectSecurity类的许可权 限。

反射的性能:

写了个简单的测试程序,如下:
Java代码

import java.lang.reflect.Method;  

public class ReflectTest {  
    String name;  
    int age;  
    public static void main(String args[])  throws Exception {  

        Object o2 = javaCreate();  

        ReflectTest my = new ReflectTest();  

        long a = System.currentTimeMillis();  
        long b = System.currentTimeMillis();  
        a = System.currentTimeMillis();  
        for (int i = 0; i < 5000; i++) {  
            javaCreate();  
        }  
        b = System.currentTimeMillis();  
        System.out.println("javaCreate : " + (b - a));  

        a = System.currentTimeMillis();  
        for (int i = 0; i < 5000; i++) {  
            manualCreate();  
        }  
        b = System.currentTimeMillis();  
        System.out.println("manualCreate : " + (b - a));  

        a = System.currentTimeMillis();  
        for (int i = 0; i < 5000; i++) {  
            javaSet(o2);  
        }  
        b = System.currentTimeMillis();  
        System.out.println("javaSet : " + (b - a));  

        a = System.currentTimeMillis();  
        for (int i = 0; i < 5000; i++) {  
            manualSet(my);  
        }  
        b = System.currentTimeMillis();  
        System.out.println("manualSet : " + (b - a));  

        a = System.currentTimeMillis();  
        for (int i = 0; i < 5000; i++) {  
            javaGet(o2);  
        }  
        b = System.currentTimeMillis();  
        System.out.println("javaGet : " + (b - a));  

        a = System.currentTimeMillis();  
        for (int i = 0; i < 5000; i++) {  
             manualGet(my);  
        }  
        b = System.currentTimeMillis();  
        System.out.println("manualGet : " + (b - a));  
    }  

    // ===============下面是 java自身的直接反射的方法  
    public static Object javaCreate()  throws Exception {  
        Object ob = ReflectTest.class.newInstance();  
        return ob;  
    }  
    public static void javaSet(Object ob)  throws Exception {  
        Method m = ReflectTest.class.getDeclaredMethod("setName",  
                new Class[] { String.class });  
        m.invoke(ob, new Object[] { "旺旺旺" });  
    }  
    public static void javaGet(Object ob) throws Exception {  
        Method m = ReflectTest.class.getDeclaredMethod("getName", new Class[0]);  
        m.invoke(ob, new Object[0]);  
    }  
    // ===============下面是 手动的创建对象  
    public static ReflectTest manualCreate() {  
        ReflectTest my = new ReflectTest();  
        return my;  
    }  

    public static void manualSet(ReflectTest my) {  
        my.setName("旺旺旺");  
    }  
    public static void manualGet(ReflectTest my) {  
        my.getName();  
    }  
    public int getAge() {  
        return age;  
    }  
    public void setAge(int age) {  
        this.age = age;  
    }  
    public String getName() {  
        return name;  
    }  
    public void setName(String name) {  
        this.name = name;  
    }  
}

运行结果: 写道
javaCreate : 22
manualCreate : 0
javaSet : 40
manualSet : 0
javaGet : 9
manualGet : 0

由此可见,反射对性能的影响。

总结:

Java语言反射提供一种动态链接程序组件的多功能方法。它允许程序创建和控制任何类的对象(根据安全性限制),无需提前硬编码目标类。这些特性使得反射 特别适用于创建以非常普通的方式与对象协作的库。例如,反射经常在持续存储对象为数据库、XML或其它外部格式的框架中使用。Java reflection 非常有用,它使类和数据结构能按名称动态检索相关信息,并允许在运行着的程序中操作这些信息。Java 的这一特性非常强大,并且是其它一些常用语言,如 C、C++、Fortran 或者 Pascal 等都不具备的。
但反射有两个缺点。第一个是性能问题。用于字段和方法接入时反射要远慢于直接代码。性能问题的程度取决于程序中是如何使用反射的。如果它作为程序运行中相 对很少涉及的部分,缓慢的性能将不会是一个问题。即使测试中最坏情况下的计时图显示的反射操作只耗用几微秒。仅反射在性能关键的应用的核心逻辑中使用时性 能问题才变得至关重要。
许多应用中更严重的一个缺点是使用反射会模糊程序内部实际要发生的事情。程序人员希望在源代码中看到程序的逻辑,反射等绕过了源代码的技术会带来维护问 题。反射代码比相应的直接代码更复杂,正如性能比较的代码实例中看到的一样。解决这些问题的最佳方案是保守地使用反射——仅在它可以真正增加灵活性的地方 ——记录其在目标类中的使用。

11章异常处理

异常:

Thowable类有两个子类:运行时异常Exception和错误Error
异常的父类:Exception类
异常的常用关键字:throw、throws、 try catch 、finally
throw和throws是抛出异常,throw 是把新建的异常对象抛给调用者,而throws是把已经存在的异常抛给调用者去处理。
finally必须接在try catch 后面,try是用来捕获异常,catch是处理try捕获的异常,finally表示不管有没有执行try catch 语句,都要执行finally后面的代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
try{ 
eq(s);
}
catch(Exception e){
String t=e.getMessage();
System.out.println("s不是ioexception");
e.printStackTrace();
}
finally{
System.out.println("执行了finally语句");
}
}
public void eq(String s) throws Exception{ //throws已经存在的异常抛给调用者去处理
if(s.equals("ioexception")) System.out.println("s是"+s);
else{
Exception e=new Exception(s);
throw e;
}
}