[关闭]
@w460461339 2016-11-16T07:10:32.000000Z 字数 5088 阅读 821

Java学习Day16 (反射,代理(反射的应用),枚举)

Java基础


今天学习的是Java基础的最后一课,内容是有关于反射的。呃,虽然不是很明白为什么要用反射这个词,但反射的大意就是用类的class文件强行调用该类的方法,不管它的访问属性。

1、反射

1.1反射的定义

通过字节码文件对象,去使用成员变量,构造方法,成员方法

1.2获取字节码文件(.class)文件的三种方法
  1. package reflect_01;
  2. public class ReflectDemoTest {
  3. /**
  4. * @param args
  5. * @throws ClassNotFoundException
  6. */
  7. public static void main(String[] args) throws ClassNotFoundException {
  8. // 获取.class文件方法一
  9. //创建对应的实例对象,利用实例对象获取
  10. ReflectDemo rd1=new ReflectDemo(10);
  11. Class c1=rd1.getClass();
  12. //获取.class文件方法二
  13. //直接利用类名来获取
  14. Class c2=ReflectDemo.class;
  15. //获取.class文件方法三
  16. //通过Class类中的forname方法来获取
  17. Class c3=Class.forName("reflect_01.ReflectDemo");
  18. System.out.println((c1==c2) &&(c2==c3));
  19. }
  20. }

自己玩的时候用第二种,因为方便;但是开发的时候用第三种,因为易更改

1.3利用反射调用构造函数
  1. package reflect_01;
  2. import java.lang.reflect.Constructor;
  3. public class ConstructionDemo {
  4. /**
  5. * @param args
  6. */
  7. public static void main(String[] args) throws Exception{
  8. Class c=Class.forName("reflect_01.ReflectDemo");
  9. //只能拿所有public訪問屬性的構造方法
  10. Constructor[] con0=c.getConstructors();
  11. for(Constructor cor:con0){
  12. System.out.println(cor);
  13. }
  14. //只能拿一個public訪問屬性的構造方法
  15. Constructor con=c.getConstructor(int.class);
  16. Object obj= con.newInstance(10);
  17. System.out.println(obj);
  18. //能拿private或者default修飾的構造方法,并使用
  19. Constructor con1=c.getDeclaredConstructor();
  20. con1.setAccessible(true);
  21. Object obj2=con1.newInstance();
  22. System.out.println(obj2);
  23. }
  24. }
1.4利用反射调用构成员变量
  1. package reflect_01;
  2. import java.lang.reflect.Constructor;
  3. import java.lang.reflect.Field;
  4. public class FieldDemo {
  5. /**
  6. * @param args
  7. */
  8. public static void main(String[] args) throws Exception{
  9. // TODO Auto-generated method stub
  10. Class c=Class.forName("reflect_01.ReflectDemo");
  11. //创建构造方法,并构造实例
  12. Constructor con=c.getConstructor(int.class);
  13. Object obj=con.newInstance(16);
  14. //利用反射得到对应的成员变量,并将上述obj中的对应成员变量赋值
  15. Field f1=c.getField("age");
  16. f1.set(obj, 20);
  17. //输出
  18. System.out.println(obj);
  19. //获取私有成员变量
  20. Field f2=c.getDeclaredField("address");
  21. f2.setAccessible(true);
  22. f2.set(obj, "haven");
  23. //输出
  24. System.out.println(obj);
  25. }
  26. }
1.5利用反射调用成员方法
  1. package reflect_01;
  2. import java.lang.reflect.Constructor;
  3. import java.lang.reflect.Method;
  4. public class MehtodDemo {
  5. /**
  6. * @param args
  7. */
  8. public static void main(String[] args) throws Exception{
  9. // TODO Auto-generated method stub
  10. //获得字节码文件对象
  11. Class c=Class.forName("reflect_01.ReflectDemo");
  12. //利用反射创建实例对象
  13. Constructor con=c.getConstructor(int.class);
  14. Object obj= con.newInstance(22);
  15. //利用反射调用包括private在内的所有方法
  16. Method me=c.getDeclaredMethod("require");
  17. me.setAccessible(true);
  18. me.invoke(obj);
  19. }
  20. }
1.6利用反射越过泛型
  1. package reflect_02;
  2. import java.lang.reflect.Method;
  3. import java.util.ArrayList;
  4. public class ReflectArrayDemo {
  5. public static void main(String[] args) throws Exception{
  6. //创建ArrayList对象并测试
  7. ArrayList<Integer> array=new ArrayList<Integer>();
  8. array.add(10);
  9. //获得Array的.class文件对象
  10. Class c=array.getClass();
  11. //获得add方法的对象,注意最后的参数类型是Object
  12. Method me=c.getDeclaredMethod("add", Object.class);
  13. //利用该add方法写入Hello
  14. me.invoke(array, "Hello");
  15. //输出
  16. System.out.println(array);
  17. }
  18. }
1.7动态代理

动态代理
代理:本来应该自己做的事情,却请了别人来做,被请的人就是代理对象。
举例:春季回家买票让人代买
动态代理:在程序运行过程中产生的这个对象
而程序运行过程中产生对象其实就是我们刚才反射讲解的内容,所以,动态代理其实就是通过反射来生成一个代理

在Java中java.lang.reflect包下提供了一个Proxy类和一个InvocationHandler接口,通过使用这个类和接口就可以生成动态代理对象。JDK提供的代理只能针对接口做代理。我们有更强大的代理cglib
Proxy类中的方法创建动态代理类对象
public static Object newProxyInstance(ClassLoader loader,Class[] interfaces,InvocationHandler h)
最终会调用InvocationHandler的方法
InvocationHandler
Object invoke(Object proxy,Method method,Object[] args)

简而言之,就是不对原本类中的方法进行修改的情况下,在该方法的前后增添内容。

另外需要注意,动态代理只能代理接口对象

接口

  1. package reflect_03;
  2. public interface Tool {
  3. public abstract void print();
  4. }

接口实现

  1. package reflect_03;
  2. public class ToolImpl implements Tool{
  3. @Override
  4. public void print() {
  5. System.out.println("Right");
  6. }
  7. }

动态代理类

  1. package reflect_03;
  2. import java.lang.reflect.InvocationHandler;
  3. import java.lang.reflect.Method;
  4. public class MyInvocationHandler implements InvocationHandler{
  5. //创建目标对象对应的成员变量
  6. private Object target;
  7. //获取目标对象
  8. public MyInvocationHandler(Object target){
  9. this.target=target;
  10. }
  11. @Override
  12. public Object invoke(Object proxy, Method method, Object[] args)
  13. throws Throwable {
  14. // TODO Auto-generated method stub
  15. //目标对象前面要加的语句(是在该类所有的方法前加上下列语句)
  16. System.out.println("Test One");
  17. //获取代理对象
  18. Object result=method.invoke(target, args);
  19. //目标对象后面要加的语句(是在该类所有的方法后加上下列语句)
  20. System.out.println("Test Two");
  21. //返回代理对象
  22. return result;
  23. }
  24. }

测试类

  1. package reflect_03;
  2. import java.lang.reflect.Proxy;
  3. public class TestDemo {
  4. public static void main(String[] args) {
  5. //获取接口对象
  6. Tool t=new ToolImpl();
  7. //将接口对象传入动态代理类
  8. MyInvocationHandler mih=new MyInvocationHandler(t);
  9. //获取动态代理对象
  10. Tool proxyt=(Tool) Proxy.newProxyInstance(
  11. t.getClass().getClassLoader(),
  12. t.getClass().getInterfaces(), mih);
  13. //运行接口中方法
  14. proxyt.print();
  15. }
  16. }

2.枚举

枚举概述
是指将变量的值一一列出来,变量的值只限于列举出来的值的范围内。举例:一周只有7天,一年只有12个月等。
回想单例设计模式:单例类是一个类只有一个实例
那么多例类就是一个类有多个实例,但不是无限个数的实例,而是有限个数的实例。这才能是枚举类。

注意事项
定义枚举类要用关键字enum
所有枚举类都是Enum的子类
枚举类的第一行上必须是枚举项,最后一个枚举项后的分号是可以省略的,但是如果枚举类有其他的东西,这个分号就不能省略。建议不要省略
枚举类可以有构造器,但必须是private的,它默认的也是private的。枚举项的用法比较特殊:枚举(“”);
枚举类也可以有抽象方法,但是枚举项必须重写该方法
枚举在switch语句中的使用

枚举类

  1. package emumDemo;
  2. public enum EmumTest {
  3. FRONT("F"){
  4. @Override
  5. public void show() {
  6. System.out.println("前");
  7. }
  8. },BEHIND("B"){
  9. @Override
  10. public void show() {
  11. System.out.println("后");
  12. }
  13. },LEFT("L"){
  14. @Override
  15. public void show() {
  16. System.out.println("左");
  17. }
  18. },RIGHT("R"){
  19. @Override
  20. public void show() {
  21. System.out.println("右");
  22. }
  23. };
  24. private String direction;
  25. private EmumTest(String dir){
  26. direction=dir;
  27. }
  28. public abstract void show();
  29. }

枚举类使用

  1. package emumDemo;
  2. public class MyEmum {
  3. public static void main(String[] args) {
  4. EmumTest.BEHIND.show();
  5. }
  6. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注