一、线程池 Executors
先新建一个任务
public class Task implements Runnable{
@Override
public void run() {
for(int i=1;i<=5;i++){
System.out.println(Thread.currentThread().getName()+"..."+i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
下面是四种常用线程池
package com.qf.threadpool;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class ThreadPool {
public static void main(String[] args) {
//1.第一种
// 创建只有一个线程的线程池对象,任务按照提交的先后顺序依次执行
//让任务按顺序执行
ExecutorService executorService = Executors.newSingleThreadExecutor();
// executorService.execute(new Task());
// executorService.execute(new Task());
// executorService.execute(new Task());
//2.第二种
//创建固定个数线程的线程池,该线程池中最多3个线程,如果某个线程异常了,会在补充一个新的线程
//任务的数量和线程的数量相同,这些任务同时执行,任务数量大于线程数量,多出来的任务需要等待已有线程
//空闲下来执行
ExecutorService executorService1 = Executors.newFixedThreadPool(3);
//
// executorService1.execute(new Task());
// executorService1.execute(new Task());
// executorService1.execute(new Task());
// executorService1.execute(new Task());
//3.第三种
//创建缓冲的线程池对象,线程数量是没有限制的,初始线程池会创建一定数量的线程,如果线程的数量
//大于了任务的数量,线程池会自动销毁空闲的线程(60秒没有执行任务),随着任务的增加,线程池会自动增加线程
//适合于任务量大,且任务执行时间短的情况
ExecutorService executorService2 = Executors.newCachedThreadPool();
// executorService2.execute(new Task());
// executorService2.execute(new Task());
// executorService2.execute(new Task());
// executorService2.execute(new Task());
// executorService2.execute(new Task());
//4.第四种
//适合定时或周期执行的任务,需要指定线程的个数
// ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(3);
//4.1
//延迟5秒执行任务,任务只执行1次
// scheduledExecutorService.schedule(new Task(),5, TimeUnit.SECONDS);
//4.2
//第2参数是任务第一次执行的延迟时间,第3个参数是任务上一次执行的开始时间到任务下一次执行的开始时间的间隔时间
// scheduledExecutorService.scheduleAtFixedRate(new Task(),3,1,TimeUnit.SECONDS);
//4.3
//第2参数是任务第一次执行的延迟时间,第3个参数是任务上一次执行的结束时间到任务下一次执行的开始时间的间隔时间
// scheduledExecutorService.scheduleWithFixedDelay(new Task(),3,10,TimeUnit.SECONDS);
}
}
总结
二、反射
反射预备知识
首先新建一个Person类用于测试
public class Person {
private String name;
private int age;
public Person(){
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public static void ff(int b)
{
System.out.println(b);
}
public void fun(String name,int age)
{
System.out.println(name+","+age);
}
public void show()
{
System.out.println("show");
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
1.反射获取字节码的三种方式
public class Demo1 {
public static void main(String[] args)throws ClassNotFoundException {
//getClaz();
//getClaz2();
//getClaz3();
}
//3.
//只需要提供一个字符串
public static void getClaz3() throws ClassNotFoundException {
//让JVM去指定的包下边找指定的类的字节码
Class<?> claz= Class.forName("com.qf.reflect.Person");//字符串是包名.类名
Class<?> claz2= Class.forName("com.qf.reflect.Person");
System.out.println(claz==claz2);
}
//2.
//使用属性class,得到字节码
//要求Person类是事先存在的
public static void getClaz2()
{
Class<Person> claz = Person.class;
Class<Person> claz2 = Person.class;
System.out.println(claz==claz2);
//Class aa=int.class;
}
//1.
//动态获取字节码 Class类型的对象:使用Object中提供的getClass()方法得到字节码对象
//缺点:需要先创建对象
public static void getClaz()
{
Person ren=new Person();
Class<? extends Person> aClass = ren.getClass();//Person.class
Class<? extends Person> aClass2 = ren.getClass();//Person.class
System.out.println(aClass==aClass2);
}
}
2.使用字节码创建对象的两种方式
public class Demo2 {
public static void main(String[] args) throws IllegalAccessException, InstantiationException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException {
//newObj();
newObj2();
}
// 2.
public static void newObj2() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
//得到字节码 Person.class
Class<?> claz = Class.forName("com.qf.reflect.Person");
//从字节码中得到构造方法,构造方法是Constructor类型的对象
Constructor<?> constructor = claz.getConstructor(String.class, int.class);
//Constructor这个类应该提供创建对象的功能
Person obj = (Person)constructor.newInstance("张三", 20);
System.out.println(obj);
}
// 1.
public static void newObj() throws ClassNotFoundException, IllegalAccessException, InstantiationException {
//得到字节码 Person.class
Class<?> claz = Class.forName("com.qf.reflect.Person");
//使用的是Class提供的newInstance()方法创建对象
Person ren=(Person)claz.newInstance();//使用的是空参的构造函数来创建对象
System.out.println(ren);
}
}
3.根据字节码获取属性,并给属性赋值
public class Demo3 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException, InstantiationException {
//得到字节码对象
Class<?> aClass = Class.forName("com.qf.reflect.Person");
//给属性赋值
//得到属性
//Field name = aClass.getField("name");//只能得到权限是public的属性
//System.out.println(name);//NoSuchFieldException: name
//得到的是类中声明的属性,不管是什么权限的
Field field = aClass.getDeclaredField("name");
//使用Field提供的赋值的功能 void set(Object obj, Object value)
//因为name是非静态属性,需要通过对象来访问,所以需要先创建个对象
Person obj = (Person)aClass.newInstance();
//把属性设置为可访问的
field.setAccessible(true);
field.set(obj,"李四");
System.out.println(obj.getName());
}
}
4.通过字节码执行方法的三种方式
public class Demo4 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
//m1();
//m2();
m3();
}
public static void m3() throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class<?> aClass = Class.forName("com.qf.reflect.Person");
Method method = aClass.getMethod("ff", int.class);
method.invoke(null,66);
}
public static void m2() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
Class<?> aClass = Class.forName("com.qf.reflect.Person");
Method method = aClass.getMethod("fun", String.class, int.class);
Person obj = (Person) aClass.newInstance();
method.invoke(obj,"黄文强",21);
}
public static void m1() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
Class<?> aClass = Class.forName("com.qf.reflect.Person");
//从字节码中得到方法对象,Method类型的对象
Method method = aClass.getMethod("show", null);
//方法是非静态方法,需要通过对象来执行
Person obj = (Person) aClass.newInstance();
//执行方法 Object invoke(Object obj, Object... args)
method.invoke(obj,null);
}
}
总结
三、网络编程
1.把IP面向对象
public class Demo1 {
public static void main(String[] args) throws UnknownHostException {
//得到本机的IP地址的对象
InetAddress ip = InetAddress.getLocalHost();
System.out.println(ip.getHostAddress());//得到IP地址
System.out.println(ip.getHostName());//得到主机名
//得到任意一台主机的IP地址的对象
InetAddress byName = InetAddress.getByName("10.20.152.61");
System.out.println(byName);
}
}
2.UDP编程数据接收方式
接收端要指定接收端口,随时监听
public class UdpReceive {
public static void main(String[] args) throws IOException {
//1.创建Socket,同时监听端口
DatagramSocket socket=new DatagramSocket(14444);
//2.接收 void receive(DatagramPacket p)
//使用数据报包来接收数据 DatagramPacket(byte[] buf, int length)
byte[] arr=new byte[1024];
DatagramPacket packet=new DatagramPacket(arr,arr.length);//创建一个空的数据报包
//3.使用Socket的void receive(DatagramPacket p) 接收
socket.receive(packet);
byte[] data = packet.getData();
String str=new String(data,0,packet.getLength());
String ip = packet.getAddress().getHostAddress();
System.out.println(ip+":"+str);
socket.close();
}
}
3.UDP编程发送方式
发送端要指定接收端的ip和端口
public class UdpSend {
public static void main(String[] args) throws IOException {
//使用UDP协议,发送数据
//1.建立Socket对象
DatagramSocket socket=new DatagramSocket();
//2:确定要发送的数据
String str="hello,你好";
byte[] data=str.getBytes();
//DatagramPacket(byte[] buf, int length, InetAddress address, int port)
//第三个参数是接收数据的主机的IP地址,第4个参数是接收数据的主机使用的端口
//把发送的数据封装成数据报包
DatagramPacket packet=new DatagramPacket(data,data.length, InetAddress.getByName("10.20.152.61"),14444);
//3.发送
socket.send(packet);
socket.close();
}
}