笔记整理自B站尚硅谷JavaSE视频,其中可能有记录内容不正确,望诸位指出
作者:Vison
31、网络编程
IP 地址:InetAddress
唯一的标识 Internet上的计算机(通信实体)
本地回环地址(hostAddress):127.0.0.1主机名(hostName):localhost
IP地址分类方式1:IPV4 和 IPV6
√IPV4:4个字节组成,4个0-255。大概42亿,30亿都在北美,亚洲4亿。2011年初已经用尽。以点分十进制表示,如192.168.0.1
√IPV6:128位(16个字节),写成8个无符号整数,每个整数用四个十六进制位表示,数之间用首号(:)分开, 如:3fe:3201:1401:1280:c8fe4d:db39:1984
IP地址分类方式2:公网地址(万维网使用)和私有地址(局域网使用)。192.168开头的就是私有址址,范围即为192.168.0.0--192168255.255,专门为组织机构内部使用
特点:不易记忆
●端口号标识正在计算机上运行的进程(程序)
不同的进程有不同的端口号
被规定为一个 16 位的整数 0~65535。
端口分类:
公认端口:0-1023。被预先定义的服务通信占用(如:HTTP占用端口80,FTP占用端口21,Telnet占用端口23)
注册端口:1024-49151。分配给用户进程或应用程序。(如:Tomcat占用端口8080,MySQL占用端口3306,Oracle占用端口1521等)。
动态/私有端口:49152-65535。
●端口号与IP地址的组合得出一个网络套接字:Socket
InetAddress类
Intemet上的主机有两种方式表示地址:
域名(hostName):www.baidu.com
IP 地址(hostAddress):202.108 35.210
·InetAddress类主要表示IP地址,两个子类:Inet4Address、Inet6Address
InetAddress 类对象含有一个Internet主机地址的域名和IP地址: www.baidu.com和202.108.35.210
●域名容易记忆,当在连接网络时输入一个主机的域名后,域名服务器(DNS)负责将域名转化成IP地址,这样才能和主机建立连接。 -------域名解析
InetAdress类
InetAddress类没有提供公共的构造器,而是提供了如下几个静态方法来获取 InetAddress实例
public static inetAddress getLocalHost()
public static inetAddress getByName(String host)
InetAddress提供了如下几个常用的方法
public String getHostAddress():返回 IP地址字符串(以文本表现形式)
public String getHostName():获取此IP地址的主机名
public boolean isReachable(int timeout):测试是否可以达到该地址
InetAdress代码示例
InetAddress address_1=InetAddress.getByName("www.baidu.com");
System.out.println(address_1):// 获取InetAddress 对象所含的城名
System.out.println(address_1.getHostName0));// 获取InetAddress 对象所含的IP地址
System.out.printIn(address 1.getHostAddress0));
// 获取本机的域名和IP 地址。
InetAddress address_2=InetAddress.getLocalHost(); System.out.println(address_2);
TCP和UDP
TCP协议:
使用TCP协议前,须先建立TCP连接,形成传输数据通道传输前,采用“三次握手”方式,点对点通信,是可靠的
TCP协议进行通信的两个应用进程:客户端、服务端。
在连接中可进行大数据量的传输
传输完毕,需释放已建立的连接,效率低 UDP协议:
将数据、源、目的封装成数据包,不需要建立连接、每个数据报的大小限制在64K内发送不管对方是否准备好,接收方收到也不确认,故是不可靠的可以广播发送
发送数据结束时无需释放资源,开销小,速度快
Socket
利用套接字(Socket)开发网络应用程序早已被广泛的采用,以至于成为事实上的标准。
网络上具有唯一标识的IP地址和端口号组合在一起才能构成唯一能识别的标识符套接字。
通信的两端都要有Socket,是两台机器间通信的端点。
网络通信其实就是Socket间的通信。
Socket允许程序把网络连接当成一个流,数据在两个Socket间通过1O传输。
一般主动发起通信的应用程序属客户端,等待通信请求的为服务端。
Socket分类:
流套接字(stream socket):使用TCP提供可依赖的字节流服务
数据报套接字(datagram socket):使用UDP提供“尽力而为”的数据报服务
Socket类的常用构造器:
public SocketlInetAddress address.int port)创建一个流套接字并将其连接到指定IP地址的指定端口号。 public Socket(String host,int port)创建一个流套接字并将其连接到指定主机上的指定端口号
Socket类的常用方法:
public inputstream getinputStream() 返回此套接字的输入流。可以用于接收网络消息
public OutputStream getOutputStream() 返回此套接字的输出流。可以用于发送网络消息
public inetAddress getinetAddress() 此套接字连接到的远程IP 地址;如果套接字是未连接的,则返回 null
public inetAddress getLocalAddress() 获取套接字绑定的本地地址。即木端的IP地址 public intgetPort()此套接字连接到的远程端口号:如果尚未连接套接字,则返回0。
public int getLocalPort() 返回此套接字绑定到的本地端口。 如果尚未绑定套接字,则返回 -1。即本端的端口号。
public void close() 关闭此套接字。套接字被关闭后,便不可在以后的网络连接中使用(即无法重新连接或重新绑定)。需要创建新的套接字对象。 关闭此套接字也将会关闭该套接字的 InputStream 和 OutputStream.
public void shutdowninout() 如果在套接字上调用 shutdowninput0后从套接字输入流读取内容,则流将返回 EOF(文件结束符)。即不能在从此套接字的输入流中接收任何数据。
public void shutdownOutput() 禁用此套接字的输出流。对于 TCP 套接字,任何以前写入的数据都将被发送,并且后跟 TCP 的正常连接终止序列。 如果在套接字上调用 shutdownOutout()后写入套接字输出流则该流将抛出IOException。 即不能通过此套接字的输出流发送任何数据。
32、反射
什么是反射?
Java反射就是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;并且能改变它的属性。而这也是Java被视为动态(或准动态,为啥要说是准动态,因为一般而言的动态语言定义是程序运行时,允许改变程序结构或变量类型,这种语言称为动态语言。从这个观点看,Perl,Python,Ruby是动态语言,C++,Java,C#不是动态语言。)语言的一个关键性质。
反射能做什么?
我们知道反射机制允许程序在运行时取得任何一个已知名称的class的内部信息,包括包括其modifiers(修饰符),fields(属性),methods(方法)等,并可于运行时改变fields内容或调用methods。那么我们便可以更灵活的编写代码,代码可以在运行时装配,无需在组件之间进行源代码链接,降低代码的耦合度;还有动态代理的实现等等;但是需要注意的是反射使用不当会造成很高的资源消耗!
反射的具体实现
package com.ys.reflex;
public class Person {
//私有属性
private String name = "Tom";
//公有属性
public int age = 18;
//构造方法
public Person() {
}
//私有方法
private void say(){
System.out.println("private say()...");
}
//公有方法
public void work(){
System.out.println("public work()...");
}
}
得到Class的三种方法
//1、通过对象调用 getClass() 方法来获取,通常应用在:比如你传过来一个 Object
// 类型的对象,而我不知道你具体是什么类,用这种方法
Person p1 = new Person();
Class c1 = p1.getClass();
//2、直接通过 类名.class 的方式得到,该方法最为安全可靠,程序性能更高
// 这说明任何一个类都有一个隐含的静态成员变量 class
Class c2 = Person.class;
//3、通过 Class 对象的 forName() 静态方法来获取,用的最多,
// 但可能抛出 ClassNotFoundException 异常
Class c3 = Class.forName("com.ys.reflex.Person");
需要注意的是:一个类在 JVM 中只会有一个 Class 实例, 即我们对上面获取的 c1,c2,c3进行 equals 比较,发现都是true
②、通过 Class 类获取成员变量、成员方法、接口、超类、构造方法等
查阅 API 可以看到 Class 有很多方法:
getName():获得类的完整名字。
getFields():获得类的public类型的属性。
getDeclaredFields():获得类的所有属性。包括private 声明的和继承类
getMethods():获得类的public类型的方法。
getDeclaredMethods():获得类的所有方法。包括private 声明的和继承类
getMethod(String name, Class[] parameterTypes):获得类的特定方法,name参数指定方法的名字,parameterTypes 参数指定方法的参数类型。
getConstructors():获得类的public类型的构造方法。
getConstructor(Class[] parameterTypes):获得类的特定构造方法,parameterTypes 参数指定构造方法的参数类型。
newInstance():通过类的不带参数的构造方法创建这个类的一个对象。
例子:
//获得类完整的名字
String className = c2.getName();
System.out.println(className);//输出com.ys.reflex.Person
//获得类的public类型的属性。
Field[] fields = c2.getFields();
for(Field field : fields){
System.out.println(field.getName());//age
}
//获得类的所有属性。包括私有的
Field [] allFields = c2.getDeclaredFields();
for(Field field : allFields){
System.out.println(field.getName());//name age
}
//获得类的public类型的方法。这里包括 Object 类的一些方法
Method [] methods = c2.getMethods();
for(Method method : methods){
System.out.println(method.getName());//work waid equls toString hashCode等
}
//获得类的所有方法。
Method [] allMethods = c2.getDeclaredMethods();
for(Method method : allMethods){
System.out.println(method.getName());//work say
}
//获得指定的属性
Field f1 = c2.getField("age");
System.out.println(f1);
//获得指定的私有属性
Field f2 = c2.getDeclaredField("name");
//启用和禁用访问安全检查的开关,值为 true,则表示反射的对象在使用时应该取消 java 语言的访问检查;反之不取消
f2.setAccessible(true);
System.out.println(f2);
//创建这个类的一个对象
Object p2 = c2.newInstance();
//将 p2 对象的 f2 属性赋值为 Bob,f2 属性即为 私有属性 name
f2.set(p2,"Bob");
//使用反射机制可以打破封装性,导致了java对象的属性不安全。
System.out.println(f2.get(p2)); //Bob
//获取构造方法
Constructor [] constructors = c2.getConstructors();
for(Constructor constructor : constructors){
System.out.println(constructor.toString());//public com.ys.reflex.Person()
}
根据反射获取父类属性
public class Parent {
public String publicField = "parent_publicField";
protected String protectField = "parent_protectField";
String defaultField = "parent_defaultField";
private String privateField = "parent_privateField";
}
public class Son extends Parent {
}
public class ReflectionTest {
@Test
public void testGetParentField() throws Exception{
Class c1 = Class.forName("com.ys.model.Son");
//获取父类私有属性值
System.out.println(getFieldValue(c1.newInstance(),"privateField"));
}
public static Field getDeclaredField(Object obj,String fieldName) {
Field field = null;
Class c = obj.getClass();
for(; c != Object.class ; c = c.getSuperclass()){
try {
field = c.getDeclaredField(fieldName);
field.setAccessible(true);
return field;
}catch (Exception e){
//这里甚么都不要做!并且这里的异常必须这样写,不能抛出去。
//如果这里的异常打印或者往外抛,则就不会执行c = c.getSuperclass(),最后就不会进入到父类中了
}
}
return null;
}
public static Object getFieldValue(Object object,String fieldName) throws Exception{
Field field = getDeclaredField(object,fieldName);
return field.get(object);
}
}
通过执行上述代码,我们获得了父类的私有属性值,这里要注意的是直接通过反射获取子类的对象是不能得到父类的属性值的,必须根据反射获得的子类 Class 对象在调用 getSuperclass() 方法获取父类对象,然后在通过父类对象去获取父类的属性值。