一、反射的操作核心:Object
public final native Class<?> getClass():返回Class
二、反射中四大核心类(Class、Constructor、Method、Field)的常用操作方法
1、Class:描述其他类的结构
1)Class类的三种实例化(每个类的Class对象有且只有一个,由JVM在类加载时创建)
a、任意对象.getClass()
b、类名.class
c、Class.forName(String className)//注意:此处需要类的全名称(包名+类名)
2)利用class对象创建类的对象
public T newInstance()//根据反射实例化对象:调用类的无参构造
3)取得类的包名称
public Package getPackage();
4)取得父类的Class对象
public native Class<? super T> getSuperclass();
5)取得实现的父接口
public Class<?>[ ] getInterfaces();
6)应用:优化工厂设计模式,优化工厂类:增加子类实现接口时,不需要再在工厂类中实例化添加子类的实例化对象;工厂类不需要实例化多个子类对象。
package factorymodel;
interface IFruit{
void eat();
}
class Apple implements IFruit{
@Override
public void eat() {
System.out.println("eat a apple");
}
}
class Banana implements IFruit{
@Override
public void eat() {
System.out.println("eat a banana");
}
}
class Factory{
private Factory() {};
public static IFruit getInstance(String className) {
IFruit fruit = null;
try {
//取得类的Class对象
Class<?> cls = Class.forName(className);
//创建实例化对象
fruit = (IFruit) cls.newInstance();
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return fruit;
}
}
public class Test {
public static void main(String[] args) {
IFruit fruit = Factory.getInstance("factorymodel.Apple");
fruit.eat();
}
}
运行结果:传进任意一个实现接口的子类的类全名称,输出类中信息。
2、Constructor
1)Class提供的newInstance()默认调用类中的无参构造
2)Class提供的getConstructor(参数类型 ...):取得类中的构造方法
public Constructor<T> getConstructor(Class<?>... 参数类型);
取得类中所有构造方法
public Constructor<?>[ ] getConstructors();
注:以上两个取得构造的方法只能取得修饰符为public的构造
3)取得类中指定、所有构造方法,与修饰符无关
public Constructor<T> getDeclaredConstructor(Class<?>...参数类型);
public Constructor<T>[ ] getDeclaredConstructor();
3、Method
1)取得所有普通方法
public Method[ ] getMethod();//返回本类以及父类的所有public修饰的普通方法
public Method[ ] getDeclaredMethods();//返回本类所有普通方法,与修饰符无关
2)取得指定方法
public Method getMethod(方法名,方法参数);//类同 1)两种方法
public Method getDeclaredMethod(方法名,方法参数);
3)调用方法
Method类提供的方法:public Object invoke(类的实例化对象,方法具体参数);
4)应用
//反射取得构造方法
class MyClass{
private String name;
private Integer age;
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public MyClass(Integer age) {
super();
this.age = age;
}
public MyClass(String name, Integer age) {
super();
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "MyClass [name=" + name + ", age=" + age + "]";
};
}
public class Test {
public static void main(String[] args) throws Exception{
//取得Class对象
Class<MyClass> cls = MyClass.class;
//取得构造方法
Constructor<MyClass> constructor = cls.getConstructor(String.class,Integer.class);
//对象实例化
MyClass myClass = constructor.newInstance("zhang", 20);
//取得指定的普通方法
Method method = cls.getMethod("setAge", Integer.class);
Method method1 = cls.getMethod("getAge");
//调用普通方法
System.out.println(method1.invoke(myClass));
method.invoke(myClass, 10);
System.out.println(myClass);
}
}
4、Field
1)取得类中所有属性
public Field[ ] getFields();//类同方法3、1)
public Field[ ] getDeclaredFields();
2)取得类中指定属性
public Field getField(属性名);
public Field getDeclaredField(属性名);
3)属性调用,Field类提供
设置属性内容:public voidset(具体类的实例化对象,属性值);
取得属性内容:public Object get(具体类的实例化对象);
取得属性类型:Field.getType();
4)应用
class MyClass1{
private String name;
private Integer age;
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "MyClass [name=" + name + ", age=" + age + "]";
};
}
public class Test1 {
public static void main(String[] args) throws Exception{
//取得Class对象
Class<MyClass1> cls = MyClass1.class;
//对象实例化
MyClass1 myClass = cls.newInstance();
//取得Field
Field field = cls.getDeclaredField("age");
//动态设置封装,破坏封装性
field.setAccessible(true);//private age 也可访问设置
//设置以及取得属性
field.set(myClass, 20);
Object object = field.get(myClass);
System.out.println(object);
}
}
运行结果:输出属性年龄的内容:20
三、反射与单级VO操作
四、ClassLoader类加载器的作用范围以及双亲委派模型
1、类加载器:把类加载阶段中的“通过类的全名称获取此类的二进制字节流,这种操作的实现模块就叫类加载器。
2、分类:
1)BootStrapClassLoader(启动类加载器)
使用C++实现,是JVM自身的一部分;
负责加载存放于<Java_HOME>\lib目录中能被JVM识别的类库(按文件名识别);
无法被Java程序直接引用
2)ExtClassLoader(扩展类加载器)
Java实现;
负责加载<Java_HOME>\lib\ext目录中的类库;
可以在程序中直接使用
3)AppClassLoader(应用程序类加载器)
Java实现;
负责加载ClassPath的类库;
可在程序中直接使用;
如果在程序中无自定义类加载器,则AppClassLoader就是程序中的默认类加载器
4)自定义类加载器:继承ClassLoader
3、双亲委派模型:
1)概念:类加载器的层次关系称为类加载器的双亲委派模型
除了顶层的启动类加载器BootStrapClassLoader,其余类加载器都应有自己的父类加载器
2)工作流程
当一个类加载器收到了类加载请求,首先不会自己去加载这个类,而是将请求委托给父类加载器完成,只有当父类加载器无法完成这个请求时,子类加载器才会尝试自己去加载,即所有类加载请求都会传到顶层的启动类加载器。
3)主要作用
保证Java程序稳定运行:基础类库不会被其他自定义同名类所影响。
五、静态代理模式原理(包括反射工厂创建)、写出JDK提供的动态代理,知道cglib与JDK提供的动态代理之间的区别
1、静态代理模式
核心:一个接口+两个实现类(真实业务类+辅助业务类)
真实业务与辅助业务解耦
本质:所有的实现真实业务的子类都有一个辅助它的子类帮他实现
代码实现:
//代理设计模式
interface ISubject{
void eat();
}
//真实类
class RealSubject implements ISubject{
@Override
public void eat() {
System.out.println("eat");
}
}
//辅助类
class ProxySubject implements ISubject{
private ISubject subject;
public ProxySubject(ISubject subject) {
super();
this.subject = subject;
}
public void beforeEat() {
System.out.println("pre");
}
public void afterEat() {
System.out.println("aft");
}
@Override
public void eat() {
this.beforeEat();
this.subject.eat();
this.afterEat();
}
}
//通用工厂
class Factory{
@SuppressWarnings("unchecked")
public static <T> T getInstance(String proxyClassName, String realClassName) throws Exception {
T t = null;
//生成真实业务类的实例化对象
Class<?> cls = Class.forName(realClassName);
//取得真实业务类的实例化对象
Object obj = cls.newInstance();
//生成辅助业务类(代理类)的实例化对象
Class<?> pClass = Class.forName(proxyClassName);
//取得辅助类的实例化对象
Constructor<?> constructor = pClass.getDeclaredConstructor(cls.getInterfaces()[0]);
t = (T)constructor.newInstance(obj);
return t;
}
}
public class Test {
public static void main(String[] args) throws Exception {
// ISubject subject = new ProxySubject(new RealSubject());
ISubject subject = Factory.getInstance("Dmodel.ProxySubject", "Dmodel.RealSubject");
subject.eat();
}
}
2、动态代理代码实现
//动态代理模式
interface ISubect1{
void eat(int num, String food);
}
//真实业务实现类
class RealSubject1 implements ISubect1{
@Override
public void eat(int num, String food) {
System.out.println("eat "+num+" "+food);
}
}
//通用代理类
class ProxySubject1 implements InvocationHandler{
//传入真实业务类
private Object realSubject;
//将真实业务类与代理类绑定
public Object bind(Object realSubject) {
this.realSubject = realSubject;
return Proxy.newProxyInstance(realSubject.getClass().getClassLoader(),
realSubject.getClass().getInterfaces(), this);
}
public void before() {
System.out.println("bef");
}
public void after() {
System.out.println("aft");
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
this.before();
Object ret = method.invoke(this.realSubject, args);
this.after();
return ret;
}
}
public class Test1 {
public static void main(String[] args) {
ISubect1 subect1 = (ISubect1) new ProxySubject1().bind(new RealSubject1());
subect1.eat(1, "rice");
}
}
六、算法编程题
有5个人坐在一起,问第五个人多少岁?他说比第4个人大2岁。问第4个人岁数,他说比第3个人大2岁。问第三个人,又说比第2人大两岁。问第2个人,说比第一个人大两岁。最后问第一个人,他说是10岁。请问第五个人多大?
//递归思想
public class Test {
public static void main(String[] args) {
int[] dNum = new int[]{0, 10, 2, 2, 2, 2};
System.out.println(solution(dNum, dNum.length - 1));
}
private static int solution(int[] dNum, int index) {
if(index == 1) {
return dNum[1];
}
return dNum[index] + solution(dNum, --index);
}
}
运行结果:18