千峰JAVA逆战班Day34

今天的主要内容有:UDP编程:发送数据包和接受数据包;反射:类对象的三种获取方式,通过反射获取构造方法,属性,方法并使用。

Day34

*UDP编程:发送者和接受者,两者直接不会产生连接。(不安全的,在信息传输过程中可能会发生数据包的丢失)

package com.qianfeng.am.demo1;

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;

/**
 * @author 吴一凡
 *	UDP里的发送者
 */
public class TestUDPSend {

	public static void main(String[] args) {
		
		try {
			//·1.构建一个UDPsocket对象,发射器
			DatagramSocket ds = new DatagramSocket();
			
			//·需要发送的信息
			String msg = "大仙的头发呢?";
			//·2.构建一个数据包
			//·两个参数:第一个是发送消息的字节数组,第二个是发送消息的长度
			DatagramPacket dp = new DatagramPacket(msg.getBytes(), msg.getBytes().length);
			//·给数据包设定地址
			dp.setSocketAddress(new InetSocketAddress("129.28.161.", 7777));
			
			//·3发送这个数据包,用发射器发射数据包
			ds.send(dp);
			
			//·4.关闭udp对象
			ds.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

package com.qianfeng.am.demo1;

import java.net.DatagramPacket;
import java.net.DatagramSocket;

/**
 * @author 吴一凡
 *	UDPb的接受者
 */
public class TestUDPreceive {

	public static void main(String[] args) {
		try {
			//·1.构建一个UDP对象,指定一个端口,接收器
			DatagramSocket ds = new DatagramSocket(7777);
			
			//·2构建一个接受数据的数据包
			byte[] bts = new byte[1024*10];
			//·数据包对象存不了信息,而是存到字节数组中,0是起始位置
			DatagramPacket dp = new DatagramPacket(bts,0,bts.length);
			
			//·3.读取数据包里面的内容,在没有接收到数据时,这里会阻塞等待接受数据
			ds.receive(dp);//·用接收器接受发送端传过来的信息,放到数据包中并保存在字节数组中
			
			//·4读取数据,这里用dp.getLength代表接受到的数据的长度
			String msg = new String(bts, 0, dp.getLength());
			
			//·5关闭udp
			ds.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
		
	}

}

*反射: 通过.class来得到对象,属性,方法的一种手段

  • 类对象和它的三种获取方式:类对象就是类加载时的产物(.class文件),封装了一个类的所有信息(类名,父类,接口,属性,方法,构造方法)
public class Person {
}

public class Test {
	//·单例模式:程序运行期间,Person这个类只有一个对象
	public static void main(String[] args) throws ClassNotFoundException {
		//·正常获得对象的方式
		Person p = new Person();
		//·三种获取Person的类对象
		//·方法1:通过对象.getClass() 来获取
		Class c1 = p.getClass();
		
		//·方法2:通过类名.class来获取
		Class c2 = Person.class;
		
		//·方法3:通过静态方法来获取
		Class c3 = Class.forName("com.qianfeng.am.demo2.Person");
	}
}
  • 通过反射获取构造器并且创建对象。
import java.lang.reflect.Constructor;
/**
 * @author 吴一凡
 *	通过.class对象获取类的构造器
 */
public class Demo1 {

	public static void main(String[] args) throws Exception {
		Class c = Person.class;
		//·获取所有公开的构造器
		Constructor[] ct = c.getConstructors();
		//·获取所有的构造器(全部都能拿到)
		Constructor[] ct1 = c.getDeclaredConstructors();
	}
}

package com.qianfeng.pm.demo1;

import java.lang.reflect.Constructor;

/**
 * @author 吴一凡
 *	通过获取构造器来创建对象
 */
public class Demo2 {

	public static void main(String[] args) throws Exception {
		Class c = Person.class;
		//·获取公共的无参构造
		Person p1 = (Person) c.newInstance();//·默认用无参构造器创建对象
		//·获取无参的构造器
		Constructor constructor1 = c.getConstructor();
		Person p2 = (Person) constructor1.newInstance();
		//·获取带有参数的构造器
		Constructor constructor2 = c.getConstructor(int.class);
		Person p3 = (Person) constructor2.newInstance(6);//·这里的实参必须和获取构造器时的数据类型一致
	}
}

package com.qianfeng.pm.demo1;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

/**
 * @author 吴一凡
 *	获取私有的构造器,并且能够实例化对象
 */
public class Demo3 {
	public static void main(String[] args) {
		Class c = Person.class;
		try {
			//·得到私有的构造器
			Constructor dc = c.getDeclaredConstructor(String.class);
			//·在JVM的底层如果一个方法、属性、构造器是私有的,访问开关的boolean值为false
			//·而这里就是强制将这个开关改为true,这样就可以访问私有的了。
			dc.setAccessible(true);
			Person p = (Person) dc.newInstance("jack");
		} catch (NoSuchMethodException e) {
			e.printStackTrace();
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		}
	}
}
  • 通过反射获取属性,并且修改对象的属性的
package com.qianfeng.pm.demo2;

public class Person {
	public String name;
	private int age = 20;
	char sex;
	protected int id;
}

package com.qianfeng.pm.demo2;

import java.lang.reflect.Field;

/**
 * @author 吴一凡
 *	通过反射来获取所有属性
 */
public class Demo1 {

	public static void main(String[] args) throws Exception {
		Class c = Person.class;
		//·根据属性的名称,来获取这个属性对象
		Field field = c.getField("name");//·只能获取到public修饰的属性
		Field field1 = c.getDeclaredField("age");//·不管这个属性是什么修饰的都能访问到
		
		//·获取所有被public修饰的属性
		Field[] fields = c.getFields();
		
		//·获取所有的属性
		Field[] fields1 = c.getDeclaredFields();
	}
}

package com.qianfeng.pm.demo2;

import java.lang.reflect.Field;

/**
 * @author 吴一凡
 *	修改私有属性的值,访问一个私有属性
 */
public class Demo2 {

	public static void main(String[] args) throws Exception {
		//·1 得到这个属性
		Class c = Person.class;
		
		//得到一个属性对象
		Field f = c.getDeclaredField("age");
		
		//·破解私有属性的开关
		f.setAccessible(true);
		
		//·必须用对象才能访问这个对象的属性
		Person p = (Person) c.newInstance();
		
		//·使用属性对象调用方法获得实参对象的该属性的值
		int p_Age = f.getInt(p);//·通过f对象调用getInt方法(实参为p),来获取p的age属性的值
		System.out.println(p_Age);
		
		//对这个对象的属性的值进行修改
		f.setInt(p, 100);
		Object obj = f.get(p);
		System.out.println(obj);
	}
}
  • 通过反射获取方法,并且调用对象的属性
package com.qianfeng.pm.demo3;

public class Person {
	public void test1() {
		System.out.println("test1");
	}
	
	protected void test2() {
		System.out.println("test2");
	}
	
	void test3() {
		System.out.println("test3");
	}
	
	private void test4() {
		System.out.println("test4");
	}
}

package com.qianfeng.pm.demo3;

import java.lang.reflect.Method;

/**
 * @author 吴一凡
 *	通过反射获取方法
 */
public class Demo1 {

	public static void main(String[] args) throws Exception {
		Class c = Person.class;
		//·根据方法名获取public修饰的方法
		Method m1 = c.getMethod("test1");
		//·根据方法名来获取任意一个方法
		Method m2 = c.getMethod("test2");
		
		//·获取所有公开的方法
		Method[] me1 = c.getMethods();
		//·获取所有的方法
		Method[] me2 = c.getDeclaredMethods();
	}
}

package com.qianfeng.pm.demo3;

import java.lang.reflect.Method;

/**
 * @author 吴一凡
 *	调用通过反射获取到的方法
 */
public class Demo2 {

	public static void main(String[] args) throws Exception {
		Class c = Person.class;
		//·获取到了一个私有方法
		Method m1 = c.getDeclaredMethod("test4");
		//·如果调用这个方法?必须通过对象调用
		Object obj = c.newInstance();//·调用默认的无参构造创建对象
		//·因为是私有方法,所以必须打开访问权限
		m1.setAccessible(true);
		//·用invoke方法去执行obj对象的方法
		m1.invoke(obj);
		
		//·如果获取的方法有返回值,有参数怎么办?
		//·首先在获取方法时,形参列表要一致
		Method m2 = c.getDeclaredMethod("add",int.class,int.class);
		m2.setAccessible(true);
		//·其次调用invoke方法时传参,并接受返回值(用object类型接受,多态)
		Object result = m2.invoke(obj,10,20);
		System.out.println(result);
	}
}

*反射的两个使用案例

  • 案例1:通过反射,获取报名,并且获取这个包下面所有的.class文件
import java.io.File;
import java.io.FileFilter;

public class Demo1 {
	public static void main(String[] args) {
		test(Demo1.class);
	}
	
	//·找到c下面同包的所有.class文件
	public static void test(Class c) {
		//·获取这个字节码文件所在包的包对象
		Package package1 = c.getPackage();
		//·获取这个包的包名
		String pkName = package1.getName();
//		System.out.println(pkName);
		/*
		 * 此时pkName = com.qianfeng.pm.demo4
		 * 需要改成 bin\\com\\qianfeng\\pm\\demo4
		 */
		pkName = "bin\\"+pkName.replace(".", "\\");
		
		//·得到一个file对象
		File file = new File(pkName);
		//·得到以.class结尾的文件
		File[] lf = file.listFiles(new FileFilter() {
			@Override
			public boolean accept(File file) {
				if(file.getName().endsWith(".class")) {
					if(file.isFile()) {
						return true;
					}
				}
				return false;
			}
		});
		
		for (File file2 : lf) {
			System.out.println(file2.getName());
		}
	}
}
  • 案例2:在不知道数组类型的情况下,对数组进行扩容
import java.lang.reflect.Array;

public class Demo2 {
	public static void main(String[] args) {
		String[] a = {"a","b","c"};
		String[] b = (String[]) copyArrays(a, 5);
		for (String string : b) {
			System.out.println(string);
		}
	}
	
	public static Object copyArrays(Object obj, int newLength) {
		Class cls = obj.getClass();
		//·判断是不是数组
		if(cls.isArray()) {
			//·获取这个数组的类型的类对象
			Class type = cls.getComponentType();
			//·根据这个类型和传进来的新长度创建一个新数组
			Object newArray = Array.newInstance(type, newLength);
			//·将旧数组的元素,copy到新数组中去
			System.arraycopy(obj, 0, newArray, 0, Array.getLength(obj));
			return newArray;
		}
		return null;
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值