java之ReetrantLock锁中的 Condition对象(await和signal方法),类的加载和反射(获取Class文件对象的3种方式,获取构造方法,成员变量和方法)

一.ReetrantLock锁中的 Condition对象

Condition对象中提供方法

  • await();等待
  • signal();唤醒(指定某一个线程被唤醒)
需求:使用lock锁 间隔打印三个线程

代码:

public class Kll {
	public static void main(String[] args) {
		Thread t1 = new Thread(new PrintA());
		Thread t2 = new Thread(new PrintB());
		Thread t3 = new Thread(new PrintC());
		t1.start();
		t2.start();
		t3.start();
	}

}
// 声明锁
class MyLockA {
	private MyLockA() {
	}
	// 声明lock锁
	public static final ReentrantLock LOCK_A = new ReentrantLock();
	// 声明三个Condition对象(从使用的lock锁中获取)
	public static final Condition  c1 = LOCK_A.newCondition();
	public static final Condition  c2 = LOCK_A.newCondition();
	public static final Condition  c3 = LOCK_A.newCondition();
	// 声明标记
	public static int flag = 1;
	// 计数
	public static int num = 0;	
}
class PrintA implements Runnable {

	@Override
	public void run() {
		while (true) {
			// 加锁
			MyLockA.LOCK_A.lock();
			try {
				// 循环结束条件
				if (MyLockA.num == 150) {
					break;
				}
				MyLockA.num++;
				// 判断标记
				if (MyLockA.flag != 1) {
					// 利用Condition对象将1号线程等待了
					try {
						MyLockA.c1.await();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
				System.out.println(Thread.currentThread().getName() + " " + MyLockA.num);
				// 修改标记
				MyLockA.flag = 2;
				// 唤醒指定的线程
				MyLockA.c2.signal();
			} finally {
				// 关锁
				MyLockA.LOCK_A.unlock();
			}
		}
	}
}
class PrintB implements Runnable {
	
	@Override
	public void run() {
		while (true) {
			// 加锁
			MyLockA.LOCK_A.lock();
			try {
				// 循环结束条件
				if (MyLockA.num == 150) {
					break;
				}
				MyLockA.num++;
				// 判断标记
				if (MyLockA.flag != 2) {
					// 利用Condition对象将1号线程等待了
					try {
						MyLockA.c2.await();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
				System.out.println(Thread.currentThread().getName() + " " + MyLockA.num);
				// 修改标记
				MyLockA.flag = 3;
				// 唤醒指定的线程
				MyLockA.c3.signal();
			} finally {
				// 关锁
				MyLockA.LOCK_A.unlock();
			}
		}
	}
	
}
class PrintC implements Runnable {
	
	@Override
	public void run() {
		while (true) {
			// 加锁
			MyLockA.LOCK_A.lock();
			try {
				// 循环结束条件
				if (MyLockA.num == 150) {
					break;
				}
				MyLockA.num++;
				// 判断标记
				if (MyLockA.flag != 3) {
					// 利用Condition对象将1号线程等待了
					try {
						MyLockA.c3.await();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
				System.out.println(Thread.currentThread().getName() + " " + MyLockA.num);
				// 修改标记
				MyLockA.flag = 1;
				// 唤醒指定的线程
				MyLockA.c1.signal();
			} finally {
				// 关锁
				MyLockA.LOCK_A.unlock();
			}
		}
	}
}

二.类的加载

1.类是如何加载的?

  • 1.加载
    • 将类的.class文件加载到方法区
    • 创建一个Class对象(表示的就是.class文件) 相当于文件的对象
  • 2.连接
    • 验证 验证一下类的内部结构(成员变量 和 方法)
    • 准备 为静态变量开辟空间,赋初始值
    • 解析 将局部变量进行替换 替换成对应的值
    • int a = 10 下面将所有的a 直接替换成 10
  • 3.初始化
    • 创建对象 new对象(堆内存开辟空间,与之前一样)
  • 2.类是什么时候加载的?(加载时机)
    • 使用时,该类一定会被加载
    • 加载该类时,会先加载该类的父类
    • 不重复加载
  • 3.类是用什么加载的?(使用类加载器加载的)
    • 1.根加载器 加载JDK的lib文件夹下的jar文件
    • 2.扩展加载器 加载ext文件夹下的文件
    • 3.系统加载器 咱们自定义类或者导入jar都是用系统加载器

三.反射

反射可以将正在运行的类(加载完成的类),
通过这个class文件的对象 ,可以直接获取类内部的所有成员方法和成员变量(包括私有的).
1.获取Class文件对象的3种方法
1.通过对象获取
2.通过类获取
3.通过class中的静态方法获取(class.forName() 常用)

person类

public class Person {
	public String name;
	private int age;
	public Person(String name, int age) {
		super();
		this.name = name;
		this.age = age;
	}
	public Person() {
		super();
		// TODO Auto-generated constructor stub
	}
	// 私有构造方法
	private Person(int age, String name) {
		super();
		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;
	}
	@Override
	public String toString() {
		return "[name=" + name + ", age=" + age + "]";
	}
	
	// 吃饭方法
	public void eat() {
		System.out.println("吃饭");
	}
	// 说话
	public void speak(String string) {
		System.out.println("说的是:" + string);
	}
	// 打游戏
	private int play(String game) {
		System.out.println("玩的是:" + game);
		return 123;
	}
}

获取Class对象文件的方式代码:

public class Kll {
	public static void main(String[] args) throws Exception {
		// 1.通过对象获取
		Person p = new Person();
		// 获取Person类的Class文件对象
		Class<? extends Person> c1 = p.getClass();
		System.out.println(c1);
		// 2.通过类获取
		Class<Person> c2 = Person.class;
		System.out.println(c2);
		// 3.常用的 (只需用一个字符串 就能获取该类的class对象)
		// 注意参数要填全类名 包名+类名
		Class<?> c3 = Class.forName("com.lanou3g.reflect.Person");
		System.out.println(c3);
	}
}

通过class文件对象,快速创建对象

  • 前提:
    • 1.类必须是用Public修饰
    • 2.必须提供无参构造方法
    • 3.该无参的构造方法必须是public修饰
public class Kll {
	public static void main(String[] args) throws Exception {
		Class<?> c = Class.forName("com.lanou3g.reflect.Person");
		// 快速创建对象(直接使用类中无参构造方法创建的)
		Object object = c.newInstance();
		System.out.println(object);
	}
}

获取构造方法, 利用获取的创建对象.
代码如下:

public class Kll {
	public static void main(String[] args) throws Exception {
		// 通过Class文件对象获取 类中构造方法
		Class<?> c = Class.forName("com.lanou3g.reflect.Person");
		// 获取所有public修饰的构造方法
		Constructor<?>[] constructors = c.getConstructors();
		// 遍历
		for (Constructor<?> constructor : constructors) {
			System.out.println(constructor);
		}
		// 获取指定的构造方法
		Constructor<?> constructor = c.getConstructor();
		System.out.println(constructor);
		// 利用该构造方法创建对象
		Object object = constructor.newInstance();
		System.out.println(object);
		
		// 有参的构造方法创建对象(参数是 参数类的文件类型)
		Constructor<?> constructor2 = c.getConstructor(String.class, int.class);
		// 创建对象
		Object object2 = constructor2.newInstance("kll", 20);
		System.out.println(object2);
		// 获取类中所有的构造方法(包括私有)
		Constructor<?>[] constructors1 = c.getDeclaredConstructors();
		for (Constructor<?> constructor : constructors1) {
			System.out.println(constructor);
		}
		// 获取私有构造方法
		Constructor<?> constructorp = c.getDeclaredConstructor(int.class, String.class);
		// 打开私有方法使用权限
		constructorp.setAccessible(true);
		// 创建对象
		Object object1 = constructorp.newInstance(20, "kll");
		// 打印对象
		System.out.println(object1);
	}
}

获取所有成员变量,代码如下:

public class Kll {
	public static void main(String[] args) throws Exception {
		// 获取所有公开的成员变量
		Class<?> c = Class.forName("com.lanou3g.reflect.Person");
		Field[] fields = c.getFields();
		for (Field field : fields) {
			System.out.println(field);
		}
		// 单独获取指定的成员变量
		Field field = c.getField("name");
		System.out.println(field);
		// 创建person对象
		Object object = c.newInstance();
		// 通过反射给该属性赋值
		field.set(object, "会给");
		System.out.println(object);
		// 获取私有成员变量 age 并且赋值打印
		Field field2 = c.getDeclaredField("age");
		// IllegalAccessException异常 需要打开权限 打开访问使用权限
		field2.setAccessible(true);
		// 赋值
		field2.set(object, 20);
		System.out.println(object);
	}
}

获取所有成员方法代码:

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;

import org.omg.CORBA.PUBLIC_MEMBER;

public class Kll {
	public static void main(String[] args) throws Exception {
		Class<?> c = Class.forName("com.lanou3g.reflect.Person");
		// 获取类中所有的公开的方法(包括父类的)
		Method[] methods = c.getMethods();
		for (Method method : methods) {
			System.out.println(method);
		}
		// 获取指定公开的成员方法
		// 参数1:方法名
		// 参数2:获取的方法的参数的Class类型
		Method method = c.getMethod("eat");
		System.out.println(method);
		// 创建对象
		Object obj = c.newInstance();
		// 调用该方法
		// 参数1:调用该方法的对象
		// 参数2:调用该方法,要传入的参数
		// 返回值:调用该方法 方法的返回值
		Object invoke = method.invoke(obj);
		System.out.println(invoke);
		Method method2 = c.getMethod("speak", String.class);
		Object invoke2 = method2.invoke(obj, "国语教学");
		System.out.println(invoke2);
		// 获取指定方法
		Method method3 = c.getDeclaredMethod("play", String.class);
		// 开权限
		method3.setAccessible(true);
		// 调用方法,接收返回值
		Object invoke3 = method3.invoke(obj, "王者");
		// 打印返回值
		System.out.println(invoke3);
	}
}

猜你喜欢

转载自blog.csdn.net/KongLingLei_08225/article/details/82844357