一、什么是反射
Java反射机制是在运行状态中,对于任意一个类,都能知道这个类的所有属性和方法,对于任意一个对象,都能够调用它的任意一个方法和属性,这种动态获取的信息以及动态调用对象方法的功能称为反射。
二、Class类:
Class类-------很多的类
得到Class类的对象有三种方式:
1、Object类中的getClass()方法
2、类.class
3、通过Class类的forName方法
import org.junit.Test;
//显示程序包org.junit不存在,重启解决
import java.lang.reflect.*;
//测试类,导入junit4-12包
public class Refliction {
//获取包
@Test
public void test05(){
Dog d=new Dog("heihei",5,"black");
Class<Dog> dogClass = Dog.class;
Package aPackage = dogClass.getPackage();
System.out.println(aPackage);
Method[] methods = dogClass.getMethods();
for (int i = 0; i < methods.length; i++) {
//获取所有公共的方法,包括继承的方法
System.out.println(methods[i].getName());
if(methods[i].getName().equals("toString")){
try {
String invoke = (String)methods[i].invoke(d);//invoke第一个参数指定调用方法的对象
System.out.println(invoke);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
//获取本类中公有+私有的方法,不包括父类的方法
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(d);//抛出一个异常,调用私有方法
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
}
//获取所有的属性
@Test
public void test04(){
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].getName());
}
}
//获取所有构造方法
@Test
public void tets03(){
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("xiaobai", 3, "black");
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
//通过反射来实例化对象
@Test
public void test02(){
Class<Dog> dogClass = Dog.class;
try {
//通过Class对象实例化类对象,调用默认无参构造方法
Dog dog = dogClass.newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
//获取Class的三种方式
@Test
public void test01(){
//通过对象的getClass方法
Dog dog=new Dog("huahua",1,"white");
Class class1 =dog.getClass();
//通过类.class
Class<Dog> dogClass = Dog.class;
//通过Class.forName方法
try {
Class<?> aClass = Class.forName("com.vince.Dog");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
//Dog类
public class Dog{
public int Type;
private String name;
private int age;
private String color;
private void set(){
System.out.println("私有set方法");
}
protected void get(){
System.out.println("保护get方法");
}
@Override
public String toString() {
return "Dog{" +
"name='" + name + '\'' +
", age=" + age +
", color='" + color + '\'' +
'}';
}
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 String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public Dog(String name, int age, String color) {
this.name = name;
this.age = age;
this.color = color;
}
public Dog() {
}
}
三、动态代理
所谓动态代理,即通过代理类:Proxy的代理,接口和实现类之间不可以直接发生联系,而可以在运行期实现动态关联。
Java动态代理主要是使用java.lang.reflict包中的两个类。
InvocationHandler类 、Proxy类
动态代理在运行时生成class,所以我们必须提供一组interface,然后告诉他class已经实现了这些interface,而且在生成Proxy时,必须给它提供一个handler,r让他接管实际的工作。
//interface Subject
package proxy;
public interface Subject {
void shopping();
}
//class Person
package proxy;
public class Person implements Subject{
public void shopping(){
System.out.println("付款,拿下一辆BBA");
}
}
//Class CreateProxy
package proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
//动态生成一个代理对象
public class CreateProxy implements InvocationHandler {
public Object target;
//创建代理对象的方法
public Object createProxy(Object target){
this.target=target;
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 {
System.out.println("寻找客户所需要的产品...");
System.out.println("跟客户确定要买的产品...");
method.invoke(target,args);
System.out.println("完成本次寻找");
return null;
}
}
//class TestDemo
import org.junit.Test;
import proxy.CreateProxy;
import proxy.Person;
import proxy.Subject;
public class TestDemo {
@Test
public void testProxy(){
CreateProxy cp=new CreateProxy();//创建代理对象的对象
Subject person=new Person();
Subject proxy = (Subject) cp.createProxy(person);
proxy.shopping();
}
}
四、类加载器原理分析
1、类的加载过程
三个步骤:
装载:查找并加载类的二进制数据
链接:验证(确保被加载类的正确性)、准备(为类的静态变量分配内存,并将其初始化为默认值)、解析(把类中的符号引用转换为直接引用)
初始化:为类的静态变量赋予正确的初始值
2、类的初始化
(1)创建类的实例,也就是new一个对象时。
(2)访问某个类或接口的静态变量,或者对该静态变量赋值。
(3)调用类的静态方法。
(4)反射。
(5)初始化一个类的子类。
(6)JVM启动时标明的启动类,即文件名和类名相同的那个类。
3、类的加载
指的是将类的class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个这个类的java.lang.Class对象,用来封装类在方法区类的对象。
五、JavaBean
Java组件,广泛的理解就是一个类,对于组件来说,关键在于要具有“能够被IDE构建工具(Maven等)侦测其属性和事件”的能力。
Bean的普通方法必须是public的
对于事件,要使用Swing中处理监听器的方式。如addWindowListener,removeWindowListener
//class Emp
package bean;
public class Emp {
private String name;
private int age;
private int salary;
@Override
public String toString() {
return "Emp{" +
"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 Emp(String name, int age, int salary) {
this.name = name;
this.age = age;
this.salary = salary;
}
public Emp() {
}
}
//class BeanTestDemo
package bean;
import org.apache.commons.beanutils.BeanUtils;
import org.junit.Test;
import java.lang.reflect.InvocationTargetException;
public class BeanTestDemo {
@Test
public void test(){
String name="bin";
String age="19";
String salary="10000";
Emp e=new Emp();
try {
BeanUtils.setProperty(e,"name",name);
BeanUtils.setProperty(e,"age",age);
BeanUtils.setProperty(e,"salary",salary);
} catch (IllegalAccessException ex) {
ex.printStackTrace();
} catch (InvocationTargetException ex) {
ex.printStackTrace();
}
System.out.println(e.toString());
}
}
六、内省
内省是Java语言对Bean类属性、事件的一种缺省处理方法。
Introspector类为通过工具学习有关受目标JavaBean支持的属性、事件和方法的知识提供了一个标准方法。
BeanInfo类
PropertyDescriptor类
MethodDescriptor类
//config.properties
bean.name=introspector.Config
bean.username=admin
bean.password=123
bean.url=http://www.baidu.com
//class Config
package introspector;
public class Config {
private String username;
private String password;
private String url;
@Override
public String toString() {
return "Config{" +
"username='" + username + '\'' +
", password='" + password + '\'' +
", url='" + 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() {
}
}
//class BeanFactory
package introspector;
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Properties;
import static java.lang.Class.forName;
//通过内省API装配一个Bean对象,其值通过配置文件获取
public class BeanFactory {
private static Properties pp=new Properties();
//使用静态代码块读取配置文件
static{
InputStream resourceAsStream = Thread.currentThread().getContextClassLoader().
getResourceAsStream("introspector/Config.properties");
try {
pp.load(resourceAsStream);
} catch (IOException e) {
e.printStackTrace();
}
}
public static Object getBean(String name){
Object bean=null;
String property = pp.getProperty(name);
try {
Class<?> aClass = Class.forName(property);
bean = aClass.newInstance();
//内省,通过类信息获取JavaBean的描述信息
BeanInfo beanInfo = Introspector.getBeanInfo(aClass);
//通过Javabean描述信息,获取该类的所有属性描述器
PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
for (int i = 0; i < propertyDescriptors.length; i++) {
String name1 = propertyDescriptors[i].getName();
Method writeMethod = propertyDescriptors[i].getWriteMethod();
if("username".equals(name1)){
//调用属性set方法
writeMethod.invoke(bean,pp.getProperty("bean.username"));
}else if("password".equals(name1)){
writeMethod.invoke(bean,pp.getProperty("bean.password"));
}else if("url".equals(name1)){
writeMethod.invoke(bean,pp.getProperty("bean.url"));
}
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IntrospectionException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return bean;
}
}
//class BeanTest
package introspector;
import org.junit.Test;
public class BeanTest {
@Test
public void getBeanTest(){
Config bean = (Config) BeanFactory.getBean("bean.name");
System.out.println(bean.toString());
}
}
七、AOP
AOP的概念:Aspect Oriented Programming(面向切面编程),不是核心代码。
可配置AOP框架实现
AOP框架的简单实现:
核心业务(一个接口,一个实现类)
切面(一个接口,一个实现类)
配置文件
动态代理类(ProxyFactoryBean)
装配对象类 (BeanFactory)
测试类
//配置文件
bean.target=aop.ImanagerImpl
bean.advice=aop.LogAdvice
bean=aop.ProxyFactoryBean
//核心业务接口
package aop;
public interface Imanager {
public void add(String item);
}
//核心业务实现类
package aop;
import java.util.ArrayList;
import java.util.List;
//核心业务类
public class ImanagerImpl implements Imanager{
private ArrayList<String> list=new ArrayList<>();
@Override
public void add(String item) {
//将切面代码交给代理完成
// System.out.println("add start--"+System.currentTimeMillis());
list.add(item);
System.out.println("item");
// System.out.println("add end--"+System.currentTimeMillis());
}
}
//切面接口
package aop;
//进入业务之前通知
public interface Advice {
public void beforeAdvice();
public void afterAdvice();
}
//切面实现类
package aop;
//切面类
public class LogAdvice implements Advice{
@Override
public void beforeAdvice() {
System.out.println("开始时间:"+System.currentTimeMillis());
}
@Override
public void afterAdvice() {
System.out.println("结束时间:"+System.currentTimeMillis());
}
}
//动态代理类
package aop;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
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;
}
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;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
advice.beforeAdvice();
Object obj = method.invoke(target, args);
advice.afterAdvice();
return obj;
}
}
//装配对象类
package aop;
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Properties;
public class BeanFactory {
Properties prop=new Properties();
public BeanFactory(InputStream in){
try {
prop.load(in);
} catch (IOException e) {
e.printStackTrace();
}
}
//获取一个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) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IntrospectionException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return bean;
}
}
//测试类
package aop;
import org.junit.Test;
import java.io.InputStream;
public class AOPTest {
@Test
public void test(){
//读取配置文件
InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream("aop/bean.properties");
//创建bean的工厂类对象
BeanFactory beanFactory = new BeanFactory(in);
//获取代理对象
ProxyFactoryBean proxyFactoryBean =(ProxyFactoryBean) beanFactory.getBean("bean");
Imanager proxy = (Imanager) proxyFactoryBean.getProxy();
proxy.add("我真棒 ");
}
}
AOP使用场景:封装横切关注点
具体场景:权限、缓存、 错误处理、调试、记录跟踪、持久化、同步、事务等。
八、单例模式优化
/*单例模式优化:
1、使用同步保证多线程安全问题
2、让单例类序列化安全
3、防止反射调用私有构造方法
4、volatile关键字保证变量一致性*/
package singleton;
import java.io.Serializable;
public class Singleton implements Serializable {//让单例类可以被序列化
private volatile static Singleton singleton;//volatile关键字保证变量的一致性
private Singleton() {
//防止反射调用私有构造方法
if(singleton!=null){
throw new RuntimeException("此类对象是单例模式,已经被实例化!");
}
}
public static Singleton getInstance(){
//解决多线程访问的安全问题
if(singleton==null) {//判断防止已经new过
synchronized (Singleton.class) {
if (singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
}