Socket
一、Java 网络编程
网络编程是指编写运行在多个设备(计算机)的程序,这些设备都通过网络连接起来。
java.net 包中 J2SE 的 API 包含有类和接口,它们提供低层次的通信细节。
端口:port 有65535个门
java.net 包中提供了两种常见的网络协议的支持:
-
TCP:TCP(英语:Transmission Control Protocol,传输控制协议) 是一种面向连接的、可靠的、基于字节流的传输层通信协议,TCP 层是位于 IP 层之上,应用层之下的中间层。TCP 保障了两个应用程序之间的可靠通信。通常用于互联网协议,被称 TCP / IP。
-
UDP:UDP (英语:User Datagram Protocol,用户数据报协议),位于 OSI 模型的传输层。一个无连接的协议。提供了应用程序之间要发送数据的数据报。由于UDP缺乏可靠性且属于无连接协议,所以应用程序通常必须容许一些丢失、错误或重复的数据包。
以下步骤在两台计算机之间使用套接字建立TCP连接时会出现:
1、服务器实例化一个 ServerSocket 对象,表示通过服务器上的端口通信。
2、服务器调用 ServerSocket 类的 accept() 方法,该方法将一直等待,直到客户端连接到服务器上给定的端口。
3、服务器正在等待时,一个客户端实例化一个 Socket 对象,指定服务器名称和端口号来请求连接。
4、Socket 类的构造函数试图将客户端连接到指定的服务器和端口号。如果通信被建立,则在客户端创建一个 Socket 对象能够与服务器进行通信。
5、在服务器端,accept() 方法返回服务器上一个新的 socket 引用,该 socket 连接到客户端的 socket。
2、Socket整体流程
Socket编程主要涉及到客户端和服务端两个方面,首先是在服务器端创建一个服务器套接字(ServerSocket),并把它附加到一个端口上,服务器从这个端口监听连接。端口号的范围是0到65536,但是0到1024是为特权服务保留的端口号,我们可以选择任意一个当前没有被其他进程使用的端口。
3、Socket 类的方法
java.net.Socket 类代表客户端和服务器都用来互相沟通的套接字。客户端要获取一个 Socket 对象通过实例化 ,而 服务器获得一个 Socket 对象则通过 accept() 方法的返回值。
4、InetAddress 类的方法
这个类表示互联网协议(IP)地址。
反射
一、反射概念
反射 (Reflection) 是 Java 的特征之一,它允许运行中的 Java 程序获取自身的信息,并且可以操作类或对象的内部属性。
编译期是指把源码交给编译器编译成计算机可以执行的文件的过程。在 Java 中也就是把 Java 代码编成 class 文件的过程。编译期只是做了一些翻译功能,并没有把代码放在内存中运行起来,而只是把代码当成文本进行操作,比如检查错误。
运行期是把编译后的文件交给计算机执行,直到程序运行结束。所谓运行期就把在磁盘中的代码放到内存中执行起来。
类型 | 访问方法 | 返回值类型 | 说明 |
---|---|---|---|
包路径 | 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 动态编译相结合,可以实现无比强大的功能。 对于 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)
四、通过反射执行方法
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 对象代表一个成员变量。例如,要访问一个名称为 price 的成员变量,示例代码如下:
object.getDeciaredField("price");
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() | 获得可以解析出该方法所采用修饰符的整数 |
六、获取继承关系
当我们获取到某个Class
对象时,实际上就获取到了一个类的类型:
Class cls = String.class; // 获取到String的Class
还可以用实例的getClass()
方法获取:
String s = ""; Class cls = s.getClass(); // s是String,因此获取到String的Class
最后一种获取Class
的方法是通过Class.forName("")
,传入Class
的完整类名获取:
Class s = Class.forName("java.lang.String");
这三种方式获取的Class
实例都是同一个实例,因为JVM对每个加载的Class
只创建一个Class
实例来表示它的类型。
Integer
实现的接口有:
-
java.lang.Comparable
-
java.lang.constant.Constable
-
java.lang.constant.ConstantDesc
要特别注意:getInterfaces()
只返回当前类直接实现的接口类型,并不包括其父类实现的接口类型:
小结:
通过Class
对象可以获取继承关系:
-
Class getSuperclass()
:获取父类类型; -
Class[] getInterfaces()
:获取当前类实现的所有接口。
通过Class
对象的isAssignableFrom()
方法可以判断一个向上转型是否可以实现。
七、动态代理
我们来比较Java的class
和interface
的区别:
-
可以实例化
class
(非abstract
); -
不能实例化
interface
。
所有interface
类型的变量总是通过某个实例向上转型并赋值给接口类型变量的:
CharSequence cs = new StringBuilder();
有没有可能不编写实现类,直接在运行期创建某个interface
的实例呢?这是可能的,因为Java标准库提供了一种动态代理(Dynamic Proxy)的机制:可以在运行期动态创建某个interface
的实例。
这种没有实现类但是在运行期动态创建了一个接口对象的方式,我们称为动态代码。
JDK提供的动态创建接口对象的方式,就叫动态代理。
小结
Java标准库提供了动态代理功能,允许在运行期动态创建一个接口的实例;
动态代理是通过Proxy
创建代理对象,然后将接口方法“代理”给InvocationHandler
完成的。