黑马程序员_JavaSE的网络编程和反射

------- <a href="http://www.itheima.com" target="blank">android培训</a>、<a href="http://www.itheima.com" target="blank">java培训</a>、期待与您交流! ----------


1.网络编程

(1)每台机子有一个IP,找到对方的IP,然后本机某端口的进程发送数据过去。对方有着相应端口号的进程获取数据。

IP地址:网络中设备的标识。本地回环地址:127.0.0.1主机名:localhost
端口:标识进程的逻辑地址。
有效端口:0~65535,其中0~1024是系统使用或保留的端口。
(2)数据在网络上传输的常见协议:
UDP: 1,将数据,源和目的封装在数据包中 2,数据大小限制在64K内 3,不需要建立连接,故不可以靠,但速度快。
TCP: 1,点对点之间的通信,需要建立连接 2,在连接中可以进行大量数据的传输 3,通过三次握手来确保链接成功,协议可靠,但效率不高。

(3)net包 InetAddress类:没有构造函数,不需要new。静态方法返回该类,非静态方法进行使用。

常用方法:getLocalHost() 返回本地主机。

getByName(String host) 在给定主机名的情况下确定主机的 IP 地址。
InetAddress[] getAllByName(String host) 在给定主机名的情况下,根据系统上配置的名称服务返回其 IP 地址所组成的数组
非静态: String getHostAddress() 返回 IP 地址字符串(以文本表现形式)。
String getHostName() 获取此 IP 地址的主机名  
class IPDemo
{
public static void main(String[] args)throws Exception
{
InetAddress i = InetAddress.getLocalHost();
//获取本地主机IP
System.out.println("address:"+i.getHostAddress());
//获取主机名称。
System.out.println("name:"+i.getHostName());
}
}
(4)Socket类:为网络服务提供的机制。
UDP传输:DatagramSocket类:
void receive(DatagramPacket p) 从此套接字接收数据报包。 
void send(DatagramPacket p)  从此套接字发送数据报包。
void close() 关闭此套接字。 
DatagramPacket类:用来封装和接受数据。构造函数中:
DatagramPacket(byte[] buf, int length)  接受长度为length的数据包
DatagramPacket(byte[] buf, int length, InetAddress address, int port)  构造数据报包,用来将长度为 length 的包发送到指定主机上的指定端口号。

发送端:1,建立服务 DatagramSocket ds = new DatagramSocket(6666);

2,将数据封装成数据包byte[] buf = "发送的数据".getBytes();

3,发送 ds.send(dp);

4,关闭资源 ds.close();
接收端:1,建立服务 DatagramSocket ds = new DatagramSocket(10000);
2,定义一个数据包,用来存储数据。 byte[] buf = new byte[1024]; DatagramPacket dp = new DatagramPacket(buf, buf.length) ;
3,   接受数据,存储到dp数据包中。  ds.receive(dp);//阻塞式方法。

4,用数据包中的方法获取其中数据。int port = dp.getPort();String ip = dp.getAddress().getHostAddress();

String data = new String(dp.getData(),0,dp.getLength());System.out.println(ip+":"+data+":"+port);

ds.close();
TCP传输:
客户端对应的对象是Socket
服务端对应的对象是ServerSocket
Socket(InetAddress address, int port)     创建一个网络流并将其连接到指定 IP 地址的指定端口号。
Socket(String host, int port)    创建一个网络流并将其连接到指定主机上的指定端口号
InetAddress getInetAddress() 返回网络流连接的地址。 

ServerSocket:ServerSocket(int port, int backlog)  利用指定的 backlog 创建服务器套接字并将其绑定到指定的本地端口号。

Socket accept()   侦听并接受到此网络流的连接 

客户端: 1,建立链接:Socket s = new Socket("192.168.1.255",10002);
2,发送数据,获取输出流:OutputStream os = s.getOutputStream(); os.write("客户端数据".getBytes());
3,获取服务端的数据 InputStream in = s.getInputStream(); byte[] buf =new byte[1024]; int len = in.read(buf); new String(buf,0,len)
4,释放资源。 s.close();
服务端: 1.建立链接,并监听一个端口。:ServerSocket ss = new ServerSocket(10002);
2,通过accept方法获取连接过来的客户端对象。 Socket s = ss.accept(); String ip =s.getInetAddress().getHostAddress()
3,获取客户端发过来的数据,使用客户端对象的读取流来读取数据(该源是网络流)
InputStream in = s.getInputStream(); byte[] buf = new byte[1024]; int len = in.read(buf); new String(buf,0,len);
4,给客户端发数据 OutputStream out = s.OutputStream(); out.write("好的收到".getBytes());

5,释放资源 s.close();

6,关闭服务端 ss.close();

class TcpClient
{
public static void main(String[] args)throws Exception
{
//建立Socket对象,目标指向指定IP和端口。
Socket s = new Socket("192.168.1.110",10001);
//输出语句
OutputStream out = s.getOutputStream();
out.write("你好中国".getBytes());
//读取服务端发过来的信息
InputStream in = s.getInputStream();
byte[] buf = new byte[1024];
int len = in.read(buf);
System.out.println(new String(buf,0,len));
s.close();
}
}
class TcpServer
{
public static void main(String[] args)throws Exception
{
//建立服务监听。
ServerSocket ss = new ServerSocket(10001);
Socket s = ss.accept();//获取服务端的socket对象,
String ip = s.getInetAddress().getHostAddress();
System.out.println(ip+"....is connected");
//输入流读取客户端发来的信息
InputStream in = s.getInputStream();
byte[] buf = new byte[1024];
int len = in.read(buf);
System.out.println(new String(buf,0,len));
//输出流将信息发给客户端。
OutputStream out = s.getOutputStream();
out.write("你也好".getBytes());
s.close();
}

}

2.反射

(1)把JAVA类中的各种成分映射成对应的java类。
Class类:反射的基础。Class cl1 = Date.class//Class类型变量cl1指向的是Date.class在内存中的字节码
Class cl2 = Person.class//Class类型变量cl2指向的是Date.class在内存中的字节码
Person p = new Person();
(2)一个对象获取其本身类的字节码,有三种方式
1,可以用p.getClass();
2,Class.forName("一个类的全称")。当这个字节码被加载过,可以直接返回。如果没有被加载过,就被类加载器加载,缓存到虚拟机里面。这一种方法用来做反射。
3,类名.class。例如System.class

  (3八中基本数据类型,加上void返回类型都有对象的Class对象。只要是在源程序中出现的类型,都有各自的Class实例对象。
String str = "abc";Class cl1 = str.getClass()Class cl2 = String.class;Class cl3 = Class.forName("java.lang.String");
System.out.println(cl1==cl2);System.out.println(cl3==cl2);
System.out.println(cl1.isPrimitive());//false判断使否是基本数据类型。

System.out.println(int.class == Integer.class);//false
System.out.println(int.class == Integer.TYPE);//true   Integer.TYPE返回的是int的class实例对象。
System.out.println(int[].class.isArray());
Class<?>[] getParameterTypes() 获取构造函数的参数类型。
 
(4)得到某个类所有的构造方法:Constructor[] con = String.class.getConstructors(); getDeclaredConstructors得到某个类中的指定构造方法

getConstructor(构造方法参数的class对象) 

getDeclaredConstructor(构造方法参数的class对象)可以获取被保护的构造函数。用setAccessible(true);使被保护的构造函数可见。
Constructor con = String.class.getConstructor(StringBuffer.class);//获取String类中构造参数为StringBuffer类的构造函数。
String s = (String)con.newInstance(new StringBuffer("abcd"));用指定的构造函数创建一个实例对象。
注意:因为没有指定泛型,所以需要反射建立的对象强转成String类型。
(5)Field类,获取对象中的字段。成员变量
FieldDemo f = new FieldDemo(20, "Fack");
Field f1 = f.getClass().getDeclaredField("age");//获取指定"age"名称的字段
f1.setAccessible(true);
System.out.println(f1.get(f));//获取某个对象中"age"名称字段的内容。

   方法:getField(),getFields():获取全部公共字段,存入数组中,
getDeclaredField(),getDeclaredFields():获取所有声明的字段,存入数组
setAccessible(boolean):是否强制访问调用的对象所指的成员。
static setAccessible(AccessibleObject[] array,boolean flag)
public static void changeChar(Object obj) {
Field[] f1 = obj.getClass().getDeclaredFields();
Field.setAccessible(f1,true);
System.out.println(f1.length);
for(Field field : f1){
if(field.getType()==String.class)//因为字节码是唯一的,用==比用equals方法好。
{
try {
String oldString = (String) field.get(obj);
String newString = oldString.replace("b", "z");
field.set(obj, newString);
} catch (Exception e) {
e.getStackTrace();
}
}
}
}
}
class FieldDemo{
private int age;
public String name;

String str1 = "abcd";
String str2 = "abbd";
String str3 = "abbb";

public FieldDemo(int age, String name) {
super();
this.age = age;
this.name = name;
}
}
(6)Method类:得到某个类中的成员方法。
Method me = String.class.getMethod("charAt", int.class);//获取String类中的char(int)方法
System.out.println(me.invoke(f.str1, 2));//使用该方法。获取f.str1中的第三个字符。
如果invoke()方法的第一个参数为Null,则表示该方法为静态方法
getParameterTypes()获取方法中的参数的类型
反射MainDemo类中的main方法Method mainMethod = MainDemo.class.getMethod("main", String[].class);
mainMethod.invoke(null, (Object)new String[]{"123","1234","12321"});//其中,编译器会对传入的数组进行拆包,导致编译失败(传入的参数不匹配)
解决方式:1,将数组转成Object类;2,将数组装入新数组中new String[]{new String[]{"123","1234","12321"}};
class MainDemo
{
public static void mian(String[] args)
{
System.out.println("反射出来了"):
}
}
class Run
{
public static void main(String[] args)
{
Method m = Maindemo.class.getMethod("main",String[]);
m.invoke(null,(Object)new String[]{});
}
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值