反射
- java反射机制是在运行状态中,对于任意一个类,都能知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性,这种动态获取的信息以及动态调用对象方法的功能称为反射
- 把类信息映射成对象
Class类
- Class类是一切的反射根源
得到Class对象
- Object类中的getClass()方法
- 类.class
- 通过Class类的forName方法
public class ReflectionDemo {
public void test1(){
//通过对象的getClass()方法
Dog dog = new Dog("wangwang",4,"白色");
Class aClass = dog.getClass();
//通过类.class
Class dogClass = Dog.class;
//通过Class.forName方法
try {
Class aClass1 = Class.forName("com.vince.Dog");
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
}
}
对象的实例化操作
- 调用无参构造进行实例化
public T newInstance() throws InstantiationException,IllegalAccessException
- 调用有参构造进行实例化
public Constructor<?>[] getConstructors() throws SecurityException
public class ReflectionDemo {
/**
* 获取Class对象的三种形式
*/
@Test
public void test1(){
//通过对象的getClass()方法
Dog dog = new Dog("wangwang",4,"白色");
Class aClass = dog.getClass();
//通过类.class
Class dogClass = Dog.class;
//通过Class.forName方法
try {
Class aClass1 = Class.forName("com.vince.Dog");
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
}
/**
* 通过反射来实例化对象
*/
@Test
public void test2(){
Class<Dog> dogClass = Dog.class;
try {
//通过Class对象实例化类对象,调用默认无参构造方法
Dog dog = ((Dog) dogClass.newInstance());
} catch (InstantiationException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
@Test
public void test3(){
Class<Dog> dogClass = Dog.class;
Constructor<?>[] constructors = dogClass.getConstructors();
for (int i = 0; i < constructors.length; i++) {
System.out.println(constructors[i].getName());
System.out.println(constructors[i].getParameterCount());
}
try {
//获取一个指定的构造方法
Constructor<Dog> constructor = dogClass.getConstructor(String.class, int.class, String.class);
//调用带参数的构造器来实例化对象
Dog dog = constructor.newInstance("小白", 5, "白色");
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
} catch (InstantiationException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
@Test
public void test4(){
Class<Dog> dogClass = Dog.class;
//获取非私有属性
Field[] fields = dogClass.getFields();
System.out.println(fields.length);
//获取所有属性(包括私有属性)
Field[] declaredFields = dogClass.getDeclaredFields();
System.out.println(declaredFields.length);
for (int i = 0; i < declaredFields.length; i++) {
int modifiers = declaredFields[i].getModifiers();
System.out.println(Modifier.toString(modifiers)+" "+declaredFields[i].getType()+" "+declaredFields[i].getName());
}
}
}
通过Class类取得类信息
- 取得类所在的包
public Package getPackage() //得到一个类所在的包
public String getName() //得到名字
- 取得一个类中的全部方法
public Method[] getMethods();
public int getModifiers(); //Modifier.toString(mod); //还原修饰符
public Class<?> getReturnType();
public Class<?>[] getParameterTypes();
public Class<?>[] getExceptionTypes();
public static String toString(int mod);
- 取得一个类中的全部属性
public Field[] getFields();
public Field[] getDeclaredFields();
public Class<?> getType();
public int getModifiers();
public String getName()
- 通过Class类调用属性或方法
//调用类中的方法 传入实例化对象,以及具体的参数内容
public Object invoke(Object obj,Object..args);
//直接调用属性
public Object get(Object obj);
//设置属性,等同于使用“=”完成操作
public void set(Object obj,Object value)
//让属性对外部可见
public void setAccessible(boolean flag)
@Test
public void test5(){
Dog dog = new Dog("wangwang",4,"white");
Class<Dog> dogClass = Dog.class;
//获取类的包名
Package aPackage = dogClass.getPackage();
System.out.println(aPackage.getName());
//获取公共的方法,包括继承的公有方法
Method[] methods = dogClass.getMethods();
for (int i = 0; i < methods.length; i++) {
System.out.println(methods[i]);
if(methods[i].getName().equals("toString")){
try {
String s = (String) methods[i].invoke(dog);
System.out.println(s);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
}
}
}
//访问私有方法 获取到本类中定义的所有方法(不包括父类)
Method[] declaredMethods = dogClass.getDeclaredMethods();
for (int i = 0; i < declaredMethods.length; i++) {
System.out.println(declaredMethods[i]);
if(declaredMethods[i].getName().equals("set")){
//设置 私有方法可以被访问(去除访问修饰符的检查)
declaredMethods[i].setAccessible(true);
try {
declaredMethods[i].invoke(dog);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
}
}
}
}
动态代理模式
- 通过代理类:Proxy的代理,接口和实现类之间可以不直接发生联系,而可以在运行期(Runtime)实现动态关联
- 主要是使用java.lang.reflect包中的两个类
- 动态代理:在运行时生成class
//InvocationHandler类 [代理类、被代理的方法、被代理的方法的参数组]
public Object invoke(Object obj,Method method,Object[] obs)
//Proxy类
protected Proxy(InvocationHandler h);
static Class getProxyClass(ClassLoader loader,Class[] interfaces);
static Object newProxyInstance(ClassLoader loader,Class[] interfaces,InvocationHandler)
/**
* 动态生成一个代理对象
*/
public class CreateProxy implements InvocationHandler {
private Object target; //被代理的对象
//创建代理对象的方法
public Object create(Object target){
this.target = target;
Object o = Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
return o;
}
/**
* 代理对象要执行的方法
* @param proxy 代理类对象
* @param method 被代理对象的方法
* @param args 被代理对象方法的参数
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("上海外寻找客户需要的产品...");
System.out.println("跟客户确定物品");
method.invoke(target,args);
System.out.println("完成本次海淘");
return null;
}
}
public interface Subject {
public void shopping();
}
/**
* 动态生成一个代理对象
*/
public class CreateProxy implements InvocationHandler {
private Object target; //被代理的对象
//创建代理对象的方法
public Object create(Object target){
this.target = target;
Object o = Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
return o;
}
/**
* 代理对象要执行的方法
* @param proxy 代理类对象
* @param method 被代理对象的方法
* @param args 被代理对象方法的参数
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("上海外寻找客户需要的产品...");
System.out.println("跟客户确定物品");
method.invoke(target,args);
System.out.println("完成本次海淘");
return null;
}
}
@Test
public void testProxy(){
CreateProxy cp = new CreateProxy(); //创建代理对象的对象
Subject person = new Person();
Subject proxy = (Subject) cp.create(person);
proxy.shopping();
}
类加载器
- JVM将类加载分为三个步骤:
- 装载【Load】—— 查找并加载类的二进制数据
- 链接【Link】
- 验证——确保被加载类的正确性
- 准备——为类的静态变量分配内存,并将其初始化为默认值
- 解析——把类中的符号引用转换为直接引用
- 初始化【Initialize】——为类的静态变量赋予正确的初始值
- 类的初始化
- 创建类的实例,new一个对象
- 访问某个类或接口的静态变量,或者对该静态变量赋值
- 调用类的静态方法
- 反射【Class.forName(“”)】
- 初始化一个类的子类(会首先初始化子类的父类)
- JVM启动时标明的启动类,即文件名和类名相同的那个类
- 类的加载
- 将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个这个类的java,lang,Class对象,用来封装类在方法区中类的对象
JavaBean
-
java组件,一个类【能够被IDE构建工具侦测其属性和事件】
-
getXxx()和setXxx()方法
-
对于布尔型属性,get可以替换为is
-
普通方法必须是public
-
对于事件,要使用Swing中的处理监听器的方式,addWindowListener、removeWindowListener
public class Emp {
private String name;
private int age;
private int salary;
public String getInfo(){
return "name="+name+",age="+age+",salary="+salary;
}
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 int getSalary() {
return salary;
}
public void setSalary(int salary) {
this.salary = salary;
}
}
public class BeanTest {
@Test
public void test(){
//从客户端获取到的数据是这样的
String name = "bin";
String age = "18";
String salary = "20000";
Emp emp = new Emp();
try {
BeanUtils.setProperty(emp,"name",name);
BeanUtils.setProperty(emp,"age",age);
BeanUtils.setProperty(emp,"salary",salary);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
}
System.out.println(emp.getInfo());
}
}
内省
-
Introspector是java语言对Bean类属性、事件的一种缺省处理方法
-
java中提供了一套API用来访问某个属性的getter/setter方法,通过这些API可以使你不需要了解这个规则,这些API存放于包java.beans中,一般的做法是通过类Introspector的getBeanInfo方法来获取某个对象的BeanInfo信息,然后通过BeanInfo来获取属性的描述器(PropertyDescriptor),通过这个属性描述器就可以获取某个属性对应的getter/setter方法,然后我们就可以通过反射机制来调用这些方法
-
相关API
- Introspector类
static BeanInfo getBeanInfo(Class<?> beanClass); //在java bean上进行内省,了解其所有属性、公开的方法和事件
- BeanInfo类——提供有关其bean的方法、属性、事件等显式信息
MethodDescriptor[] getMethodDescriptor(); //获得beans MethodDescriptor PropertyDescriptor[] getPropertyDescriptor(); //获得beans getPropertyDescriptor
-
PropertyDescriptor类
- 描述Java Bean通过应对存储器方法导出的一个属性
Method getReadMethod(); //获得应该用于读取属性值的方法 Method getWriteMethod(); //获得应该用于写入属性值的方法
-
MethodDescriptor类
- 描述一种特殊方法——Java Bean支持从其他组件对其进行外部访问
Method getMethod() //获得此MethodDescriptor封装的方法
public class Config {
private String username;
private String password;
private String url;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public Config(String username, String password, String url) {
this.username = username;
this.password = password;
this.url = url;
}
public Config() {
}
@Override
public String toString() {
return "Config{" +
"username='" + username + '\'' +
", password='" + password + '\'' +
", url='" + url + '\'' +
'}';
}
}
bean.name=com.vince.Introspector.Config
bean.username=admin
bean.password=123
bean.url=http://www.163.com
public class BeanFactory {
private static Properties prop = new Properties();
//使用静态代码块读取配置文件
static {
InputStream in = Thread.currentThread().getContextClassLoader()
.getResourceAsStream("com/vince/Introspector/config.properties");
try {
prop.load(in);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
/**
* 获取一个Bean
*/
public static Object getBean(String name){
Object bean = null;
String beanName = prop.getProperty(name);
try {
Class<?> aClass = Class.forName(beanName);
bean = aClass.newInstance();
//通过类信息获取javaBean的描述信息
BeanInfo beanInfo = Introspector.getBeanInfo(aClass);
//通过javaBean描述信息,获取该类的所有属性描述器
PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
for (int i = 0; i < propertyDescriptors.length; i++) {
String propertyName = propertyDescriptors[i].getName();
Method writeMethod = propertyDescriptors[i].getWriteMethod();
if("username".equals(propertyName)){
//调用属性的set方法
writeMethod.invoke(bean,prop.getProperty("bean.username"));
}else if("password".equals(propertyName)){
writeMethod.invoke(bean,prop.getProperty("bean.password"));
}else if("url".equals(propertyName)){
writeMethod.invoke(bean,prop.getProperty("bean.url"));
}
}
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
} catch (InstantiationException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (IntrospectionException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
}
return bean;
}
}
public class BeanTest {
@Test
public void getBeanTest(){
Config bean = (Config) BeanFactory.getBean("bean.name");
System.out.println(bean);
}
}
AOP框架
- 面向切面编程
- 使用场景:权限、缓存、错误处理、调试、记录跟踪、持久化、同步、事务
public interface IManager {
public void add(String item);
}
public class IManagerImpl implements IManager {
private ArrayList<String> list = new ArrayList<>();
@Override
public void add(String item) {
list.add(item);
System.out.println(item);
}
}
/**
* 通知
*/
public interface Advice {
public void beforeAdvice();
public void afterAdvice();
}
public class LogAdvice implements Advice{
@Override
public void beforeAdvice() {
System.out.println("start time:"+System.currentTimeMillis());
}
@Override
public void afterAdvice() {
System.out.println("end time:"+System.currentTimeMillis());
}
}
public class ProxyFactoryBean implements InvocationHandler {
private Object target;
private Advice advice;
public Object getProxy(){
Object proxy = Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),
this);
return proxy;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
advice.beforeAdvice();
Object obj = method.invoke(target,args);
advice.afterAdvice();
return obj;
}
public Object getTarget() {
return target;
}
public void setTarget(Object target) {
this.target = target;
}
public Advice getAdvice() {
return advice;
}
public void setAdvice(Advice advice) {
this.advice = advice;
}
}
public class BeanFactory {
Properties prop = new Properties();
public BeanFactory(InputStream in) {
try {
prop.load(in);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
/**
* 获取一个bean示例
*/
public Object getBean(String name){
String className = prop.getProperty(name);
Object bean = null;
try {
//获取ProxyFactoryBean的class对象
Class<?> aClass = Class.forName(className);
//实例化对象
bean = aClass.newInstance();
//根据配置文件实例化target和advice对象
Object target = Class.forName(prop.getProperty(name+".target")).newInstance();
Object advice = Class.forName(prop.getProperty(name+".advice")).newInstance();
//通过内省实现对ProxyFactoryBean的属性赋值
BeanInfo beanInfo = Introspector.getBeanInfo(aClass);
PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
for(PropertyDescriptor pd:propertyDescriptors){
String propertyName = pd.getName();
Method writeMethod = pd.getWriteMethod();
if("target".equals(propertyName)){
writeMethod.invoke(bean,target);
}else if("advice".equals(propertyName)){
writeMethod.invoke(bean,advice);
}
}
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
} catch (InstantiationException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (IntrospectionException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
}
return bean;
}
}
bean.target=com.vince.aop.IManagerImpl
bean.advice=com.vince.aop.LogAdvice
bean=com.vince.aop.ProxyFactoryBean
public class AOPTest {
@Test
public void test(){
//读取配置文件
InputStream in = Thread.currentThread().getContextClassLoader()
.getResourceAsStream("com/vince/aop/bean.properties");
//创建Bean的工厂对象
BeanFactory beanFactory = new BeanFactory(in);
//获取代理对象
ProxyFactoryBean proxyFactoryBean = (ProxyFactoryBean) beanFactory.getBean("bean");
IManager proxy = (IManager) proxyFactoryBean.getProxy();
proxy.add("我是一只猫");
}
}
单例模式优化
- 使用同步保证线程安全 synchronized
- 使用volatile关键字 【volatile提醒编译器它后面定义的变量随时都可能改变,因此编译后的程序每次需要存储或读取这个变量的时候,都会直接从变量地址中读取数据,如果没有volatile关键字,编译器可能优化读取和存储,可能暂时使用寄存器中的值,如果这个变量由别的程序更新了的话,将出现不一致的现象】
- 防止反射调用私有构造方法
- 让单例类序列化安全
public class Singleton {
private volatile static Singleton singleton = null;
private Singleton(){
if(singleton != null){
throw new RuntimeException("此对象为单例模式,已经被实例化了");
}
}
public static Singleton getInstance(){
if(singleton == null){
synchronized (Singleton.class){
if(singleton == null){
singleton = new Singleton();
}
}
}
return singleton;
}
}