javaday15

 

 

 

1   第十五天:高级:注解+反射

 

1.1    反射 Reflect

文本配置文件

------------------

day15.A;a

day15.B;b

day15.C;c

 

要根据配置文件配置的流程,来执行

 

 

 

加载到方法区的“类对象”的反射操作,可以

l  获得一个类的定义信息

l  反射新建实例

l  反射调用成员

1.1.1    获取“类对象”

l  Class.forName("day1801.A")

l  A.class

l  a1.getClass()

 

1.1.2    获得包名、类名

c1.getPackage().getName()

包名

 

c1.getName()

完整类名

 

c1.getSimpleName()

类名,不含包名

 

 

1.1.3    成员变量定义信息

getFields()

获得所有公开的成员变量,包括继承的变量

 

getDeclaredFields()

获得本类定义的成员变量,包括私有

不包括继承的变量

 

getField(变量名)

 

getDeclaredField(变量名)

 

 

1.1.4    构造方法定义信息

getConstructors()

获得所有公开的构造方法

 

getDeclaredConstructors()

获得所有构造方法,包括私有

 

getConstructor(参数类型列表)

 

getDeclaredConstructor(int.class, String.class)

 

1.1.5    方法定义信息

getMethods()

获得所有可见的方法,包括继承的方法

 

getDeclaredMethods()

获得本类定义的方法,包括私有

不包括继承的方法

 

getMethod(方法名,参数类型列表)

 

getDeclaredMethod(方法名, int.class, String.class)

 

 

1.1.6    反射新建实例

l  新建实例时,执行无参构造

Object obj = c.newInstance();

 

l  新建实例时,执行有参构造

获取构造方法

Constructor t = c.getConstructor(int.class, String.class);

 

新建实例,并执行该构造方法

Object obj = t.newInstance(6, "abc");

 

 

1.1.7    反射调用成员变量

获取变量

Field f = c.getDeclaredField(变量名);

 

使私有成员允许访问

f.setAccessible(true);

 

反射给变量赋值

为指定实例的变量赋值,静态变量,第一参数给 null

f.set(实例, 值);

 

反射访问变量的值

访问指定实例的变量的值,静态变量,第一参数给 null

Object v = f.get(实例);

 

 

1.1.8    反射调用成员方法

获取方法

Method m = c.getDeclaredMethod(方法名, 参数类型列表);

 

使私有方法允许被调用

m.setAccessible(true)

 

反射调用方法

让指定的实例来执行该方法

Object returnValue = m.invoke(实例, 参数数据)

 

 

 

 

package day15;

 

public class A {

    private int i;

 

    public int getI() {

       return i;

    }

 

    public void setI(int i) {

       this.i = i;

    }

   

    public void a() {

       System.out.println("好嗨哟~");

    }

}

 

 

package day15;

 

public class B {

    public void b() {

       System.out.println("感觉人生已经达到了高潮~");

    }

 

}

 

 

package day15;

 

public class C {

    public void c() {

       System.out.println("感觉人生已经达到了巅峰~");

    }

 

}

 

 

package day15;

 

public class D {

    public void d() {

       System.out.println("好炫彩~");

    }

}

 

 

package day15;

 

public class Test1 {

    public static void main(String[] args) throws Exception {

       //A

       Class<A> c1 = A.class;

      

       //B

       Class<B> c2 =

        (Class<B>) Class.forName("day1801.B");

      

       //C

       C c = new C();

       Class<C> c3 = (Class<C>) c.getClass();

      

       System.out.println(c1);

       System.out.println(c2);

       System.out.println(c3);

    }

}

 

 

package day15;

 

import java.lang.reflect.Constructor;

import java.lang.reflect.Field;

import java.lang.reflect.Method;

import java.util.Arrays;

import java.util.Scanner;

 

public class Test2 {

    public static void main(String[] args) throws Exception {

       System.out.println("输入类名:");

       String s = new Scanner(System.in).nextLine();

       Class<?> c = Class.forName(s);

      

       System.out.println(c.getPackage().getName());

       System.out.println(c.getName());

       System.out.println(c.getSimpleName());

       /*

        * day1801.A

        * java.lang.String

        * java.util.ArrayList

        * java.io.File

        */

      

       System.out.println("\n--成员变量------------------");

       f1(c);

       System.out.println("\n--构造方法------------------");

       f2(c);

       System.out.println("\n--方法------------------");

       f3(c);

    }

 

    private static void f1(Class<?> c) {

       // private static final int v1;

       //Field实例,封装一个变量的定义信息

       Field[] a = c.getDeclaredFields();

       for (Field f : a) {

           String t = f.getType().getSimpleName();

           String n = f.getName();

           System.out.println(t+" "+n);

       }

      

    }

 

    private static void f2(Class<?> c) {

       //public A(int i, String s) throws ...

       //Constructor实例,封装构造方法的定义信息

       Constructor<?>[] a =

           c.getDeclaredConstructors();

       for (Constructor<?> t : a) {

           String n = c.getSimpleName();

           Class<?>[] p = t.getParameterTypes();

           System.out.println(

            n+"("+ Arrays.toString(p) +")");

       }

      

    }

 

    private static void f3(Class<?> c) {

       //public static String f1(int i) throws ...

       //Method实例,封装方法的定义信息

       Method[] a = c.getDeclaredMethods();

       for (Method t : a) {

           String n = t.getName();

           Class<?>[] p = t.getParameterTypes();

           System.out.println(

            n+"("+ Arrays.toString(p) +")");

       }

    }

}

 

 

package day15;

 

import java.lang.reflect.Constructor;

import java.util.Scanner;

 

public class Test3 {

    public static void main(String[] args) throws Exception {

       /*

        * 反射新建两个实例

        * 1. 无参构造

        * 2. int参数构造

        */

       System.out.println("输入类名:");

       String s = new Scanner(System.in).nextLine();

       Class<?> c = Class.forName(s);

      

       Object o1 = null;

       Object o2 = null;

      

       System.out.println("--执行无参构造------------");

       try {

           o1 = c.newInstance();

           System.out.println(o1);

       } catch (Exception e) {

           System.out.println("不能执行无参构造");

       }

      

       System.out.println("--执行有参构造------------");

       try {

           Constructor<?> t = c.getConstructor(int.class);

           o2 = t.newInstance(6);

           System.out.println(o2);

       } catch (Exception e) {

           System.out.println("不能执行int参数构造方法");

       }

    }

}

 

 

 

 

 

package day15;

 

import java.lang.reflect.Field;

import java.lang.reflect.Method;

 

public class Test4 {

    public static void main(String[] args) throws Exception {

       A a = new A();

       Class<A> c = (Class<A>) a.getClass();

      

       Field f = c.getDeclaredField("i");

       f.setAccessible(true);//私有可访问

      

       f.set(a, 6);//反射赋值

       System.out.println(a.getI());

      

       int i = (int) f.get(a);//反射取值

       System.out.println(i);

      

       ////

      

       Method geti = c.getMethod("getI");

       Method seti = c.getMethod("setI", int.class);

      

       int r = (int) geti.invoke(a);

       System.out.println(r);

      

       seti.invoke(a, 666);

       System.out.println(a.getI());

      

    }

}

 

 

 

l  d:/config.txt

day15.A;a

day15.B;b

day15.C;c

day15.D;d

 

 

package day15;

//运行器,根据配置文件来执行

 

import java.io.BufferedReader;

import java.io.FileInputStream;

import java.io.InputStreamReader;

import java.lang.reflect.Method;

import java.util.ArrayList;

 

public class Runner {

    private static ArrayList<String> list =

           new ArrayList<>();

    static {

       try {

           BufferedReader in =

            new BufferedReader(

            new InputStreamReader(

            new FileInputStream("d:/config.txt"), "GBK"));

          

           String line;

           while((line = in.readLine()) != null) {

              line = line.replaceAll(" ", "");

              if(line.length() == 0) {

                  continue;

              }

              list.add(line);

           }         

           in.close();

           System.out.println(list);       

       } catch (Exception e) {

           throw new RuntimeException(e);

       }

    }

   

   

    public static void launch() throws Exception {

       for (String s : list) {

           String[] a = s.split(";");//拆分字符串

           Class<?> c = Class.forName(a[0]);//获取“类对象”

           Object obj = c.newInstance();//新建实例执行无参构造

           Method m = c.getMethod(a[1]);//获取方法

           m.invoke(obj);//反射调用该方法

       }

    }

   

   

    public static void main(String[] args) throws Exception {

       Runner.launch();

    }

}

 

 

1.2    注解

注解为其他开发工具,或其他java程序,来提供代码的额外信息

 

@Override

public String toString() {

    ...

}

 

l  Override注解,告诉编译器,这里实在重写一个方法,让编译器来检查,重写语法是否正确

 

l  自定义注解,要自己编写处理代码

 

 

1.2.1    概念

注解很厉害哦,它可以增强我们的java代码,同时利用反射技术可以扩充实现很多功能。它们被广泛应用于三大框架底层。传统我们通过xml文本文件声明方式,而现在最主流的开发都是基于注解方式,代码量少,框架可以根据注解去自动生成很多代码,从而减少代码量,程序更易读。例如最火爆的SpringBoot就完全基于注解技术实现。

注解设计非常精巧,初学时觉得很另类甚至多余,甚至垃圾。有了java代码干嘛还要有@注解呢?但熟练之后你会赞叹,它竟然可以超越java代码的功能,让java代码瞬间变得强大。大家慢慢体会吧。

常见的元注解:@Target、@Retention,jdk提供将来描述我们自定义的注解的注解。听起来好绕,别着急,做两个例子,立刻清晰。现在现有“元注解”这个概念。

1.2.2    分类

l  JDK自带注解

l  元注解

l  自定义注解

1.2.3    JDK注解

JDK注解的注解,就5个:

l  @Override、

l  @Deprecated标记就表明这个方法已经过时了,但我就要用,别提示我过期

l  @SuppressWarnings(“deprecation”) 忽略警告

l  @SafeVarargs jdk1.7出现,堆污染,不常用

l  @FunctionallInterface jdk1.8出现,配合函数式编程拉姆达表达式,不常用

1.2.4    元注解

描述注解的注解,就5个:

l  @Target 注解用在哪里:类上、方法上、属性上

l  @Retention 注解的声明周期:源文件中、class文件中、运行中

l  @Inherited 允许子注解继承

l  @Documented 生成javadoc时会包含注解,不常用

l  @Repeatable注解为可重复类型注解,可以在同一个地方多次使用,不常用

1.3    元注解

1.3.1    @Target

描述注解的使用范围:

l  ElementType.ANNOTATION_TYPE      应用于注释类型

l  ElementType.CONSTRUCTOR          应用于构造函数

l  ElementType.FIELD               应用于字段或属性

l  ElementType.LOCAL_VARIABLE       应用于局部变量

l  ElementType.METHOD              应用于方法级

l  ElementType.PACKAGE             应用于包声明

l  ElementType.PARAMETER            应用于方法的参数

l  ElementType.TYPE                应用于类的任何元素

1.3.2    @Retention

定义了该注解被保留的时间长短,某些注解仅出现在源代码中,而被编译器丢弃;而另一些却被编译在class文件中;编译在class文件中的注解可能会被虚拟机忽略,而另一些在class被装载时将被读取。

为何要分有没有呢?没有时,反射就拿不到,从而就无法去识别处理。

l  SOURCE        在源文件中有效(即源文件保留)

l  CLASS         在class文件中有效(即class保留)

l  RUNTIME       在运行时有效(即运行时保留)

1.4    自定义注解

 

新建项目: day15-myUnit

 

package day15;

 

import java.lang.annotation.ElementType;

import java.lang.annotation.Retention;

import java.lang.annotation.RetentionPolicy;

import java.lang.annotation.Target;

/*

 * 元注解:对注解的注解

 *

 * @Target 设置注解目标:类、方法、成员变量、参数变量...

 *

 * @Retention 保留范围:源码、字节码、运行期内存

 *      源码:编译成字节码时被丢弃

 *      字节码:类被加载到内存时丢弃

 *      运行期内存:在内存中保留

 */

//@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER})

 

@Target(ElementType.METHOD)

@Retention(RetentionPolicy.RUNTIME)

public @interface Test {

  // 如果没有默认值,使用注解时,就必须赋值

  // 有默认值,可以不赋值

  int id() default 0;

 

  String title() default "";

 

  /*

   * 特殊的属性名  value,

   * 有特殊待遇,单独赋值时,可以不写value=

   * 可以作为一个有意义属性名的别名

   * @Test("sdfsdfs")

   * @Test(id=5, value="dfgsdf")

   * @Test(id=5, title="dfgsdf")

   */

 

  //title的别名

  String value() default "";

}

 

package day15;

 

public class A {

  @Test(id=1, title="测试a")

  public void a() {

      System.out.println("A.a");

  }

  public void b() {

      System.out.println("A.b");

  }

  @Test("测试b")

  public void c() {

      System.out.println("A.c");

  }

  @Test(id=3)

  public void d() {

      System.out.println("A.d");

  }

}

 

package day15;

 

import java.lang.reflect.InvocationTargetException;

import java.lang.reflect.Method;

 

public class Runner {

  //在指定的类中,自动发现自动运行有@Test注解的方法

  public static void launch(Class c) throws Exception{

      Object obj = c.newInstance();

      Method[] a = c.getMethods();

      for (Method m : a) {

          //在方法上,是否存在Test类型的注解

          if (m.isAnnotationPresent(Test.class)) {

             //获取 Test 注解数据

             Test t = m.getAnnotation(Test.class);

             System.out.println("id: "+t.id());

             System.out.println("title: "

               +(t.title().length()!=0?t.title():t.value()));

           

             m.invoke(obj);

             System.out.println("\n\n-------------------");

          }

      }

  }

 

  public static void main(String[] args) throws Exception {

      Runner.launch(A.class);

  }

}

 

 

猜你喜欢

转载自www.cnblogs.com/ou-yang/p/12957663.html