分析网络编程,对反射的概括性讲解

Socket
一、Java网络编程
网络编程是指编写运行在多个设备(计算机)的程序,这些设备都通过网络连接起来。
有两种常见的网络协议:
TCP:TCP(英语:Transmission Control Protocol,传输控制协议)
是一种面向连接的、可靠的、基于字节流的传输层通信协议,TCP 层是位于 IP 层之上,应用层之下的中间层。
TCP 保障了两个应用程序之间的可靠通信。通常用于互联网协议,被称 TCP / IP。
UDP:UDP (英语:User Datagram Protocol,用户数据报协议)
位于 OSI 模型的传输层。一个无连接的协议。
提供了应用程序之间要发送数据的数据报。
由于UDP缺乏可靠性且属于无连接协议,所以应用程序通常必须容许一些丢失、错误或重复的数据包。
1、Socket编程
Socket,套接字,就是两台主机之间逻辑连接的端点。
套接字使用TCP提供两台计算机之间的通信机制。客户端程序创建一个套接字,并尝试连接服务器的套接字。
java.net.Socket 类代表一个套接字
java.net.ServerSocket 类为服务器程序提供了一种来监听客户端
下列是在两台计算机之间使用套接字建立TDP连接时会出现:
(1)、服务器实例化一个 ServerSocket 对象,表示通过服务器上的端口通信。
​ (2)、服务器调用 ServerSocket 类的 accept() 方法,该方法将一直等待,直到客户端连接到服务器上给定的端口。
​ (3)、服务器正在等待时,一个客户端实例化一个 Socket 对象,指定服务器名称和端口号来请求连接。
​ (4)、Socket 类的构造函数试图将客户端连接到指定的服务器和端口号。如果通信被建立,则在客户端创建一个 Socket 对象能够与服务器进行通信。
​ (5)、在服务器端,accept() 方法返回服务器上一个新的 socket 引用,该 socket 连接到客户端的 socket。
TCP/IP协议是传输层协议,主要解决数据如何在网络中传输;
而HTTP是应用层协议,主要解决如何包装数据。
Socket是通信的基石,是支持TCP/IP协议的网络通信的基本操作单元。
它是网络通信过程中端点的抽象表示,包含进行网络通信必须的五种信息:连接使用的协议、本地主机的IP地址、本地进程的协议端口、远程主机的IP地址、远程进程的协议端口。
Socket本身不是协议,是为了方便程序员使用TCP/IP协议栈。
2、Socket整体流程
Socket编程主要涉及到客户端和服务端两个方面,首先是在服务器端创建一个服务器套接字(ServerSocket),并把它附加到一个端口上,服务器从这个端口监听连接。端口号的范围是0到65536(建议8000以上),但是0到1024是为特权服务保留的端口号,我们可以选择任意一个当前没有被其他进程使用的端口。
客户端请求与服务器进行连接的时候,根据服务器的域名或者IP地址,加上端口号,打开一个套接字。当服务器接受连接后,服务器和客户端之间的通信就像输入输出流一样进行操作。
创建客户端方式:
Socket client = new Socket(“服务器IP地址”,端口号)
3.ServerSocker类的方法
通过此类获取一个端口,并且侦听客户端请求。
ServerSocker类有以下的构造方法:
public ServerSocket(int port) throws IOException 创建绑定到特定端口的服务器套接字。
public ServerSocket(int port, int backlog) throws IOException利用指定的 backlog 创建服务器套接字并将其绑定到指定的本地端口号。
public ServerSocket(int port, int backlog, InetAddress address) throws IOException使用指定的端口、侦听 backlog 和要绑定到的本地 IP 地址创建服务器。
public ServerSocket() throws IOException 创建非绑定服务器套接字。

Socket类的五个构造方法:
socket构造方法
常用及感兴趣的方法
4、InetAddress 类的方法:这个类表示互联网协议(IP)地址。
常用的方法
5、Socket 客户端实例

package com.zpark.socket.chat01;

import java.io.*;
import java.net.Socket;

/**
 * 聊天室客户端
 */
public class Client {
    // 定义socket
    private Socket socket;

    // 初始化socket
    public Client(){
        try {
            System.out.println("正在与服务器建立连接....");
            socket = new Socket("localhost", 8082);
            System.out.println("连接服务器成功");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void start(){

        try {
            // 获取套接字输出流
            OutputStream outputStream = socket.getOutputStream();
            OutputStreamWriter osw = new OutputStreamWriter(outputStream, "utf-8");
            BufferedWriter bw = new BufferedWriter(osw);
            PrintWriter w = new PrintWriter(bw, true);
            // 发送数据
            w.println("你好");

            // 关闭资源
            w.close();
            socket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }


    public static void main(String[] args) {
        // 启动客户端
        Client c = new Client();
        c.start();
    }
}

6、Socket服务端实例

package com.zpark.socket.chat01;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * 聊天室服务端
 */
public class Server {
    // 定义ServerSocket
    private ServerSocket server;

    // 初始化serversocket
    public Server(){
        try {
            System.out.println("正在启动服务器....");
            server = new ServerSocket(8082);
            System.out.println("服务器启动成功");
        } catch (Exception e) {
            System.out.println("服务器启动失败");
            e.printStackTrace();
        }
    }

    public void start(){
        System.out.println("等待客户端建立连接....");
        try {
            Socket socket = server.accept();
            System.out.println("一个客户端连接成功");

            // 读取客户端发送的数据
            InputStream inputStream = socket.getInputStream();
            InputStreamReader isr = new InputStreamReader(inputStream, "utf-8");
            BufferedReader br = new BufferedReader(isr);

            while (true){
                String result = br.readLine();
                System.out.println("客户端说:" + result);
                Thread.sleep(30000);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    public static void main(String[] args) {
        // 创建服务端
        Server server = new Server();
        server.start();
    }
}

反射
一、反射概念(当一个语言有反射,则标志它进入成熟)
反射机制指的是程序在运行时能够获取自身的信息。
在 Java 中,只要给定类的名字,就可以通过反射机制来获得类的所有信息。
Java 反射机制主要提供了以下功能,这些功能都位于java.lang.reflect包。
​ 1、在运行时判断任意一个对象所属的类。
​ 2、在运行时构造任意一个类的对象。
​ 3、在运行时判断任意一个类所具有的成员变量和方法。
​ 4、在运行时调用任意一个对象的方法。
​ 5、生成动态代理。
要想知道一个类的属性和方法,必须先获取到该类的字节码文件对象。

类型访问方法返回值类型说明
包路径getPackage()Package 对象获取该类的存放路径
类名称getName()String 对象获取该类的名称
继承类getSuperclass()Class 对象获取该类继承的类
实现接口getlnterfaces()Class 型数组获取该类实现的所有接口
构造方法getConstructors()Constructor 型数组获取所有权限为 public 的构造方法
所有构造方法getDeclaredContruectors()Constructor 对象获取当前对象的所有构造方法
方法getMethods()Methods 型数组获取所有权限为 public 的方法
所有方法getDeclaredMethods()Methods 对象获取当前对象的所有方法
成员变量getFields()Field 型数组获取所有权限为 public 的成员变量
所有成员变量getDeclareFileds()Field 对象获取当前对象的所有成员变量
内部类getClasses()Class 型数组获取所有权限为 public 的内部类
所有内部类getDeclaredClasses()Class 型数组获取所有内部类
内部类的声明类getDeclaringClass()Class 对象如果该类为内部类,则返回它的成员类,否则返回 null
	与 Java 动态编译相结合,可以实现无比强大的功能。
	对于 Java 这种先编译再运行的语言,能够让我们很方便的创建灵活的代码,这些代码可以在运行时装配,无需在组件之间进行源代码的链接,更加容易实现面向对象。
	获取类的class对象方法:1、Class  cla1 = Demo01.Class;
	                      2、Class  cls = Class.forName

Java 反射机制的优缺点
优点:
能够运行时动态获取类的实例,大大提高系统的灵活性和扩展性。
与 Java 动态编译相结合,可以实现无比强大的功能。
对于 Java 这种先编译再运行的语言,能够让我们很方便的创建灵活的代码,这些代码可以在运行时装配,无需在组件之间进行源代码的链接,更加容易实现面向对象。
缺点:

​ 反射会消耗一定的系统资源,因此,如果不需要动态地创建一个对象,那么就不需要用反射;
​ 反射调用方法时可以忽略权限检查,获取这个类的私有方法和属性,因此可能会破坏类的封装性而导致安全问题。

Java 反射机制在一般的 Java 应用开发中很少使用,即便是 Java EE 阶段也很少使用。
二、反射机制API
实现 Java 反射机制的类都位于 java.lang.reflect 包中,java.lang.Class 类是 Java 反射机制 API 中的核心类。
1、java.lang.Class 类
java.lang.Class 类是实现反射的关键所在,Class 类的一个实例表示 Java 的一种数据类型,包括类、接口、枚举、注解(Annotation)、数组、基本数据类型和 void。Class 没有公有的构造方法,Class 实例是由 JVM 在类加载时自动创建的。

2、java.lang.reflect 包

java.lang.reflect 包提供了反射中用到类,主要的类说明如下:

  • Constructor 类:提供类的构造方法信息。
  • Field 类:提供类或接口中成员变量信息。
  • Method 类:提供类或接口成员方法信息。
  • Array 类:提供了动态创建和访问 Java 数组的方法。
  • Modifier 类:提供类和成员访问修饰符信息。

三、通过反射访问构造方法

​ 为了能够动态获取对象构造方法的信息,首先需要通过下列方法之一创建一个 Constructor 类型的对象或者数组。
​ getConstructors()
​ getConstructor(Class<?>…parameterTypes) ​ getDeclaredConstructors() ​ getDeclaredConstructor(Class<?>…parameterTypes)

方法名称说明
isVarArgs()查看该构造方法是否允许带可变数量的参数,如果允许,返回 true,否则返回 false
getParameterTypes()按照声明顺序以 Class 数组的形式获取该构造方法各个参数的类型
getExceptionTypes()以 Class 数组的形式获取该构造方法可能抛出的异常类型
newInstance(Object … initargs)通过该构造方法利用指定参数创建一个该类型的对象,如果未设置参数则表示 采用默认无参的构造方法
setAccessiable(boolean flag)如果该构造方法的权限为 private,默认为不允许通过反射利用 netlnstance() 方法创建对象。如果先执行该方法,并将入口参数设置为 true,则允许创建对 象
getModifiers()获得可以解析出该构造方法所采用修饰符的整数
静态方法名称说明
isStatic(int mod)如果使用 static 修饰符修饰则返回 true,否则返回 false
isPublic(int mod)如果使用 public 修饰符修饰则返回 true,否则返回 false
isProtected(int mod)如果使用 protected 修饰符修饰则返回 true,否则返回 false
isPrivate(int mod)如果使用 private 修饰符修饰则返回 true,否则返回 false
isFinal(int mod)如果使用 final 修饰符修饰则返回 true,否则返回 false
toString(int mod)以字符串形式返回所有修饰符

四、通过反射执行方法

​ 要动态获取一个对象方法的信息,首先需要通过下列方法之一创建一个 Method 类型的对象或者数组。
​ getMethods()
​ getMethods(String name,Class<?> …parameterTypes) ​ getDeclaredMethods() ​ getDeclaredMethods(String name,Class<?>…parameterTypes)

​ 如果是访问指定的构造方法,需要根据该方法的入口参数的类型来访问。例如,访问一个名称为 max,入口参数类型依次为 int 和 String 类型的方法。
Method 类的常用方法如下:

静态方法名称说明
getName()获取该方法的名称
getParameterType()按照声明顺序以 Class 数组的形式返回该方法各个参数的类型
getReturnType()以 Class 对象的形式获得该方法的返回值类型
getExceptionTypes()以 Class 数组的形式获得该方法可能抛出的异常类型
invoke(Object obj,Object…args)利用 args 参数执行指定对象 obj 中的该方法,返回值为 Object 类型
isVarArgs()查看该方法是否允许带有可变数量的参数,如果允许返回 true,否则返回 false
getModifiers()获得可以解析出该方法所采用修饰符的整数

五、通过反射访问成员变量

​ 通过下列任意一个方法访问成员变量时将返回 Field 类型的对象或数组。
​ getFields()
​ getField(String name)
​ getDeclaredFields()
​ getDeclaredField(String name)

​ 上述方法返回的 Field 对象代表一个成员变量。
Field 类的常用方法如下:

方法名称说明
getName()获得该成员变量的名称
getType()获取表示该成员变量的 Class 对象
get(Object obj)获得指定对象 obj 中成员变量的值,返回值为 Object 类型
set(Object obj, Object value)将指定对象 obj 中成员变量的值设置为 value
getlnt(0bject obj)获得指定对象 obj 中成员类型为 int 的成员变量的值
setlnt(0bject obj, int i)将指定对象 obj 中成员变量的值设置为 i
setFloat(Object obj, float f)将指定对象 obj 中成员变量的值设置为 f
getBoolean(Object obj)获得指定对象 obj 中成员类型为 boolean 的成员变量的值
setBoolean(Object obj, boolean b)将指定对象 obj 中成员变量的值设置为 b
getFloat(Object obj)获得指定对象 obj 中成员类型为 float 的成员变量的值
setAccessible(boolean flag)此方法可以设置是否忽略权限直接访问 private 等私有权限的成员变量
getModifiers()获得可以解析出该方法所采用修饰符的整数

六、动态代理

我们来比较Java的classinterface的区别:

  • 可以实例化class(非abstract);
  • 不能实例化interface

在运行期动态创建一个interface实例的方法如下:

​ 1、定义一个InvocationHandler实例,它负责实现接口的方法调用;
​ 2、通过Proxy.newProxyInstance()创建interface实例,它需要3个参数:
​ 2.1、使用的ClassLoader,通常就是接口类的ClassLoader;
​ 2.2、需要实现的接口数组,至少需要传入一个接口进去;
​ 2.3、用来处理接口方法调用的InvocationHandler实例。
​ 3、将返回的Object强制转型为接口。

小结

​ Java标准库提供了动态代理功能,允许在运行期动态创建一个接口的实例;

​ 动态代理是通过Proxy创建代理对象,然后将接口方法“代理”给InvocationHandler完成的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值