反射
Reflection(反射)反射机制允许程序在执行期借助Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法。
Class理解
在Object中定义了以下方法,此方法被所有子类继承:
public final native Class<?> getClass();
//用于获取运行时的Class对象
通过Class对象我们可以做如下的事情:
- 在运行时判断任意一个对象所属的类;
- 在运行时构造任意一个类的对象;
- 在运行时判断任意一个类所具有的成员变量和方法;
- 在运行时调用任意一个类的成员变量和方法;
- 生成动态代理。
我们知道每一个类都会生成对应的。class文件,之后当JVM加载.class的时候就会生成对象的运行时类而这个运行时类本身就是一个Class对象,实际上所谓的反射机制就是Class对象所提供的方法。
获取Class实例的几种方式
- 调用类本身的属性.class
Class<TestEntity> testEntityClass = TestEntity.class;
- 通过对象的getClass()方法获取
TestEntity testEntity = new TestEntity();
Class<? extends TestEntity> aClass1 = testEntity.getClass();
- 通过Class的静态方法获取
Class<?> aClass = Class.forName("com.li.test.TestEntity");
- 通过类加载器获取
ClassLoader classLoader = this.getClass().getClassLoader();
Class<?> aClass2 = classLoader.loadClass("com.li.test.TestEntity");
反射的具体使用方法
//用于实例化的测试类
public class TestEntity {
private String name;
private String sex;
public TestEntity() {
}
public TestEntity(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
@Override
public String toString() {
return "TestEntity{" +
"name='" + name + '\'' +
", sex='" + sex + '\'' +
'}';
}
}
@Test
public void init() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchFieldException {
//获取Class对象
Class<?> aClass = Class.forName("com.li.test.TestEntity");
//newInstance 创建的前提是该类要有无参构造器且权限足够
//Object o = aClass.newInstance();
//调用Class提供的方法获取构造器(根据参数不同可获取无参,有参相对应的构造器)
Constructor<?> constructor = aClass.getConstructor();
//设置访问权限防止因权限不够无法创建
constructor.setAccessible(true);
TestEntity o = (TestEntity) constructor.newInstance();
//获取指定成员变量
Field name = aClass.getDeclaredField("name");
name.setAccessible(true);
name.set(o,"小马");
//获取指定方法
Method setSex = aClass.getDeclaredMethod("setSex", String.class);
setSex.setAccessible(true);
setSex.invoke(o, "男");
//打印输出
System.out.print(o);
}
//输出结果为
TestEntity{name='小马', sex='男'}
生成动态代理的具体使用方法
//TestEntity2 中有成员变量TestEntity 正常情况下调用getEntityName方法会获取到通过setEntity方法设置进来的TestEntity 对象的name
public class TestEntity2 {
public TestEntity entity;
public TestEntity2(){
}
public void setEntity(TestEntity entity) {
this.entity = entity;
}
public String getEntityName(){
return entity.getName();
}
}
//通过反射动态代理TestEntity 变量
@Test
public void init() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchFieldException {
TestEntity2 testEntity2 = new TestEntity2();
TestEntity testEntity = new TestEntity("小明");
testEntity2.setEntity(testEntity);
System.out.print(testEntity2.getEntityName());
System.out.print("----------------------------------");
//构建代理对象
TestEntity proxy = new TestEntity("小马");
//获取testEntity2 Class对象
Class<? extends TestEntity2> aClass1 = testEntity2.getClass();
//获取testEntity2 entity成员变量
Field entity = aClass1.getDeclaredField("entity");
entity.setAccessible(true);
//对testEntity2 entity成员变量重新赋值
entity.set(testEntity2,proxy);
System.out.print(testEntity2.getEntityName());
System.out.print("----------------------------------");
}
输出结果为:
小明----------------------------------小马----------------------------------
Java网络编程
Java是Internet上的语言,它从语言级上提供了对网络应用程序的支持。
Java提供的网络类库可以实现无痛的网络连接,联网的底层细节被隐藏在Java的本机安装系统里由JVM进行控制,并且Java实现了一个跨平台的网络库程序员面对的是一个统一的网络编程环境。
- 网络编程中有两个主要的问题:
- 如何准确地定位网络上一台或多台主机
- 找到主机后如何可靠高效地进行数据传输
- 如何准确地定位网络上一台或多台主机
- 必须知道通信双方的地址
- 遵守一定的规则:OSI参考模型该模型过于理想化,未能在因特网上进行广泛推广;TCP/IP参考模型该模型是现在国际标准。
网络通信协议参照
通讯要素之IP和Port
-
IP地址(InetAddress)是一台计算机在Internet上的唯一标识。本地回环地址(hostAddress)127.0.0.1主机名(hostName)localhost
-
Port是用来标识正在计算机上运行的进程或程序,
不同的进程有不同的Port,其中Port被被规定为一个16位的整数0~65535。0-1023被预先定义的服务通信占用(如http占用Port80等)除非我们需要访问这些特殊服务否则应该使用1024-65535这些Port中的某一个进行通信,以免发生冲突。 -
IP与Port的组合就是Socket即网络套接字。
通讯要素之通信协议
- 计算机网络中实现通信必须要有一些约定,即通信协议,对速率、传输代码、代码结构、传输控制步骤、出错控制等制定标准。
传输层中两个重要的协议
- TCP(传输控制协议 Transmission Control Protocol)
- UDP (用户数据报协议 User Datagram Protocol)
TCP/IP 以其两个主要协议:传输控制协议(TCP)和网络互联协议(IP)而得名,实际上是一组协议包括多个具有不同功能且互为关联的协议。
IP(Internet Protocol)协议是网络层的主要协议,支持网络间互连的数据通信。
TCP/IP协议模型从更实用的角度出发,形成了高效的四层体系结构,即物理链路层、IP层、传输层、应用层。
TCP协议
- 使用TCP协议前,必须建立TCP连接形成传输数据通道;
- 传输前,采用“三次握手”方式是可靠的;
- TCP协议进行通信的两个应用进程:客户端、服务端;
- 在连接中可进行大数据量的传输;
- 传输完毕需释放已建立的连接效率低。
UDP协议
- 将数据、源、目的地封装成数据包,不需要建立连接;
- 每个数据报的大小限制在64K内;
- 因为无需建立连接故是不可靠的;
- 发送数据结束时无需释放资源,速度快。
利用Socket进行网络编程
Socket允许程序把网络连接当成一个流,数据在两个Socket间通过IO传输。一般主动发起通信的应用程序属于客户端,等待通信请求的为服务端。
这里使用本地回环地址进行编写示例:
//客户端
public class Client {
public static void connect() throws IOException {
//创建socket对象
Socket socket = new Socket(InetAddress.getLocalHost(),10009);
//获取输出流
OutputStream outputStream = socket.getOutputStream();
String s = "我是客户端,你已连接成功";
//写入要发送的内容
outputStream.write(s.getBytes());
//关闭流等资源
outputStream.close();
socket.close();
}
}
//服务端
public class Server {
public static void connect() throws IOException {
//创建服务端socket
ServerSocket serverSocket = new ServerSocket(10009);
//开启端口监听
Socket accept = serverSocket.accept();
//获取对应的输入流
InputStream inputStream = accept.getInputStream();
//解析输入流
byte[] buffer = new byte[1024];
int read = inputStream.read(buffer);
while (read!=-1){
String s = new String(buffer);
//打印到控制台
System.out.print(s);
read = inputStream.read(buffer);
}
//关闭资源
inputStream.close();
accept.close();
serverSocket.close();
}
}
//注意必须要先启动服务端再启动客户端
@Test
public void testNet1() {
try {
Server.connect();
} catch (IOException e) {
e.printStackTrace();
}
}
@Test
public void testNet() {
try {
Client.connect();
} catch (IOException e) {
e.printStackTrace();
}
}
//打印结果
我是客户端,你已连接成功
示例二当服务端收到信息后给客户端一个响应:
//客户端
public class Client {
public static void connect() throws IOException {
//创建socket对象
Socket socket = new Socket(InetAddress.getLocalHost(),10009);
//获取输出流
OutputStream outputStream = socket.getOutputStream();
String s = "我是客户端,你已连接成功";
//写入要发送的内容
outputStream.write(s.getBytes());
socket.shutdownOutput();//告诉服务端我已写入完毕
//获取输入流
InputStream inputStream = socket.getInputStream();
//解析输入流
byte[] buffer = new byte[1024];
int read = inputStream.read(buffer);
while (read!=-1){
String content = new String(buffer);
//打印到控制台
System.out.print(content);
read = inputStream.read(buffer);
}
//关闭流等资源
outputStream.close();
//关闭资源
inputStream.close();
socket.close();
}
}
//服务端
public class Server {
public static void connect() throws IOException {
//创建服务端socket
ServerSocket serverSocket = new ServerSocket(10009);
//开启端口监听
Socket accept = serverSocket.accept();
//获取对应的输入流
InputStream inputStream = accept.getInputStream();
//解析输入流
byte[] buffer = new byte[1024];
int read = inputStream.read(buffer);
while (read!=-1){
String s = new String(buffer);
//打印到控制台
System.out.print(s);
read = inputStream.read(buffer);
}
//获取输出流写入内容
OutputStream outputStream = accept.getOutputStream();
String content = "我是服务端已经读取到你给的内容";
outputStream.write(content.getBytes());
accept.shutdownOutput();
outputStream.close();
//关闭资源
inputStream.close();
accept.close();
serverSocket.close();
}
}
//先启动服务端再启动客户端
@Test
public void testNet1() {
try {
Server.connect();
} catch (IOException e) {
e.printStackTrace();
}
}
@Test
public void testNet() {
try {
Client.connect();
} catch (IOException e) {
e.printStackTrace();
}
}
//执行结果
我是客户端,你已连接成功
我是服务端已经读取到你给的内容
UDP网络编程示例
//发送端
public class UDPClient {
public static void send() throws IOException {
//创建socket
DatagramSocket socket = new DatagramSocket();
//准备要发送的数据
String s = "我是通过UDP发送的数据";
//创建发送数据报
DatagramPacket datagramPacket = new DatagramPacket(s.getBytes(),s.getBytes().length,InetAddress.getLocalHost(),10008);
//发送数据
socket.send(datagramPacket);
//关闭资源
socket.close();
}
}
//接收端
public class UDPServer {
public static void receiver() throws IOException {
//创建接收端口
DatagramSocket datagramSocket = new DatagramSocket(10008);
//接收数据
byte[] receiverByte = new byte[1024];
DatagramPacket datagramPacket = new DatagramPacket(receiverByte,receiverByte.length);
datagramSocket.receive(datagramPacket);
//解析数据
String content = new String(datagramPacket.getData(),0,datagramPacket.getLength());
System.out.print(content);
//关闭资源
datagramSocket.close();
}
}
//先启动接收端再启动发送端
@Test
public void testUDP1() {
try {
UDPClient.send();
} catch (IOException e) {
e.printStackTrace();
}
}
@Test
public void testUDP2() {
try {
UDPServer.receiver();
} catch (IOException e) {
e.printStackTrace();
}
}
//打印输出
我是通过UDP发送的数据
个人微信公众号,欢迎关注及时获取技术干货!