注解和反射(摘录)

注解和反射(摘录),第1张

注解和反射(摘录)

注解
注解 Annotation ==》给人看 也给程序看 也可被其他程序读取

什么是注解?
Annotation是从JDK5.0开始引入的新技术。
Annotation其实就是代码里的特殊标记, 它用于替代配置文件,
也就是说,传统方式通过配置文件告诉类如何运行,有了注解技术后,
开发人员可以通过注解告诉类如何运行。

在Java技术里注解的典型应用是:
可以通过反射技术去得到类里面的注解,以决定怎么去运行类。

Annotation的作用:

  • 不是程序本身,可以对程序作出解释。
    (这一点和注释(comment)没什么区别)
  • 可以被其他程序(比如:编译器等)读取。

Annotation的格式:
➢注解是以"@注释名"在代码中存在的,还可以添加一些参数值,
例如:@SuppressWarnings(value=“unchecked”). .

Annotation在哪里使用?

  • 可以附加在package , class , method,field等上面,
    相当于给他们添加了额外的辅助信息,
    我们可以通过反射机制编程实现对这些元数据的访问

内置注释:

  1. @Override (重写的注解):
    定义在java.lang.Override中,此注释只适用于修辞方法

表示一个方法声明打算重写超类中的另一个方法声明。

  1. @Deprecated :
    定义在java.lang.Deprecated中,
    此注释可以用于修辞方法,属性,类,

表示不鼓励程序员使用这样的元素,通常是因为它很危险或者存在更好的选择。

  1. @SuppressWarnings :
    定义在java.lang.SuppressWarnings中,用来抑制编译时的警告信息。
    与前两个注释有所不同,你需要添加一个参数才能正确使用,
    这些参数都是已经定义好了的, 我们选择性的使用就好了。
    @SuppressWaingsl(all")
    @SuppressWarnings(“unchecked”)
    @SuppressWarnings(value={“unchecked” “deprecation”)
public class Tset01 extends Object{
    @Override
    public String toString() { return super.toString(); }

    //Deprecated 不推荐程序员使用,但是可以使用,或者存在更好的方式
    @Deprecated
    public  static void test(){ System.out.println("Deprecated"); }

    @SuppressWarnings("all")   //把警告的信息清除
    public void test02(){ List list = new ArrayList(); }
    public static void main(String[] args) { test();//Deprecated  }
}

元注解
元注解的作用: 负责注解其他注解 ,
Java定义了4个标准的meta-annotation类型,
他们被用来提供对其他annotation类型作说明。
这些类型和它们所支持的类在java.lang.annotation包中可以找到。

( @Target , @Retention,@documented , @Inherited )

  1. @Target:
    用于描述注解的使用范围(即:被描述的注解可以用在什么地方)

  2. @Retention:
    表示需要在什么级别保存该注释信息,用于描述注解的生命周期
    (SOURCES < CLASS < RUNTIME) 源码级别《 编译时《 运行时

反射只能通过RUNTIME获得注解(运行时)

  1. @document:说明该注解将被包含在javadoc中

  2. @Inherited:说明子类可以继承父类中的该注解

import java.lang.annotation.*;

//测试元注解
@MyAnnotation
public class test01 {
    public void test(){ }
}
//定义一个注解
//Target表示我们的注解可以用在哪些地方
//可以在方法和类上使用 如下。
@Target(value = {ElementType.METHOD,ElementType.TYPE})
//Retention 表示我们的注解在什么地方还有效。
//Runtime > class > sources
@Retention(value = RetentionPolicy.RUNTIME)
//documented 表示是否将我们的注解生成在JAVAdoc中
@documented
//Inherited 子类可以继承父类的注解
@Inherited
@interface MyAnnotation{ }

自定义注解
使用@interface自定义注解时,
自动继承了java.lang.annotation.Annotation接口

分析:

  • @ interface用来声明一个注解,
    格式: public @ interface 注解名{定义内容}
    其中的每一个方法实际上是声明了一个配置参数。

  • 方法的名称就是参数的名称。

  • 返回值类型就是参数的类型
    (返回值只能是基本类型,Class , String , enum )

  • 可以通过default来声明参数的默认值

  • 如果只有一个参数成员,一般参数名为value
    比如String value(); 可以不写value,只能是value

  • 注解元素必须要有值,我们定义注解元素时,
    经常使用空字符串,0作为默认值.

(无顺序)

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

//自定义注解
public class Test02 {
    //注解可以显示赋值,如果没有默认值,我们就必须给注解赋值
    @MyAnnotation2(age = 18,name = "张伞")
    public void test(){}
    @MyAnnotation3("下载")
    public void test2(){}
}
@Target({ElementType.TYPE,ElementType.METHOD})//可以在类和方法上写该注解
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation2{
    //注解的参数:参数类型 + 参数名();
    String name() default "";
    //String name(); 那么上面的test方法name必须有个值 @MyAnnotation2(name = "xx")
//    有默认值就可以不用加  ==》 default "" default来表示一个默认值
    int age();
    int id() default -1;//如果默认值为-1,代表不存在
    String[] schools() default {"北京大学","清华大学"};
    //也可以直接在这边加 不一定要在方法上加
}

@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation3{
    String value();
    //如果一个注解只有一个值 并用value命名的情况下 上面方法可以省略value =
}

注意点:
Servlet==》
使用注解@MultipartConfig意思是:将一个Servlet标识为支持文件上传

反射
1.Java反射机制概述
1.1 Reflection (反射)是被视为动态语言的关键,
反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息,
并能直接 *** 作任意对象的内部属性及方法。

1.2 加载完类之后,在堆内存的方法区中就产生了一个Class类型的对象
(一个类只有一个Class对象),这个对象就包含了完整的类的结构信息。
我们可以通过这个对象看到类的结构。这个对象就像一面镜子,
透过这个镜子看到类的结构,所以,我们形象的称之为:反射。

1.3 动态语言vs 静态语言
动态语言是一类在运行时可以改变其结构的语言:
例如新的函数、对象、甚至代码可以被引进,
已有的函数可以被删除或是其他结构上的变化。
通俗点说就是在运行时代码可以根据某些条件改变自身结构。

主要动态语言:
Object-C、 C#、Javascript、 PHP、Python、 Erlang。

静态语言
与动态语言相对应的,运行时结构不可变的语言就是静态语言。
如Java、C、C++。

Java不是动态语言,但Java可以称之为“准动态语言”。
即Java一定的动态性,
我们可以利用反射机制、字节码 *** 作获得类似动态语言的特性。
Java的动态性让编程的时候更加灵活!

1.4 Java反射机制提供的功能

  1. 在运行时判断任意一个对象所属的类
  2. 在运行时构造任意一个类的对象
  3. 在运行时判断任意一个类所具有的成员变量和方法
  4. 在运行时获取泛型信息
  5. 在运行时调用任意一个对象的成员变量和方法
  6. 在运行时处理注解
  7. 生成动态代理

1.5 Java反射优点和缺点
优点:
可以实现动态创建对象和编译,体现出很大的灵活性
缺点:
对性能有影响。使用反射基本上是一种解释 *** 作,
我们可以告诉JVM,我们希望做什么并且它满足我们的要求。
这类 *** 作总是慢于直接执行相同的 *** 作。

1.6 反射相关的主要API
java.lang.Class:代表一个类
java.lang.reflect.Method:代表类的方法
java.lang.reflect.Field:代表类的成员变量
java.lang.reflect.Constructor:代表类的构造器

问题:
疑问1:
通过直接new的方式或反射的方式都可以调用公共的结构,
开发中到底用那个? ==》建议:直接new的方式。

疑问2:
什么时候会使用:反射的方式?
==》 反射的特征: 动态性

疑问3:
反射机制与面向对象中的封装性是不是矛盾的?如何看待两个技术?
不矛盾。相当于防君子不防小人,一种提示。

2. 理解Class类并获取Class实例(重点)

Class是描述类的类

关于java.Lang.Class类的理解
1.类的加载过程:
程序经过javac.exe命令以后,会生成一个或多个字节码文件(.class结尾)。
接着我们使用java.exe命令对某个字节码文件进行解释运行。
相当于将某个字节码文件加载到内存中。此过程就称为类的加载。
加载到内存中的类,我们就称为运行时类,
此运行时类,就作为Class的一个实例。

2. 换句话说,Class的实例就对应着一个运行时类。

3. 加载到内存中的运行时类,会缓存一定的时间。
在此时间之内,我们可以通过不同的方式来获取此运行时类。

举例:
有个Person类,省略

获取class的实例的方式(前三种最重要)

package com.a.java;
import org.junit.Test;

public class ReflectionTest {
	@Test
    public void test1() throws ClassNotFoundException {
        //方式一:调用运行时类的属性:.class
        Class aClass = Person.class;//赋给大的Class变量
        System.out.println(aClass);
        
        //方式二:通过运行时类的对象,调用getClass()
        Person p1 = new Person();
        Class bClass = p1.getClass();//获取这个对象是哪个类造的
        System.out.println(bClass);
        
        //方式三:调用Class的静态方法:forName(String classPath)
        Class cClass = Class.forName("com.a.java.Person");
        //Class.forName方法此方法含义是:加载参数指定的类,并且初始化它。
        System.out.println(cClass);
        //类的全类名 以包包含内的全部路径的
        
		//方式四:使用类的加载器:ClassLoader 不常用  了解
        ClassLoader classLoader = ReflectionTest.class.getClassLoader();
        Class DClass4 = classLoader.loadClass("com.a.java.Person");
        System.out.println(DClass4);
    }
}

四个的地址都是一样的,指向同一个对象
==》class com.a.java.Person

调用hashCode方法四个的hashcode值都一样

哪些类型可以有Class对象?

(1) class:
外部类,成员(成员内部类,静态内部类),局部内部类,匿名内部类

(2) interface: 接口 ==>Class c = Comparable.class;

(3) []: 数组
Class c = String[].class;
Class c = int[ ][ ].class;
注意:
只要数组的元素类型与维度一样,就是同一个Class

(4) enum: 枚举

(5) annotation:注解@interface

(6)primitivetype:基本数据类型

(7) void

Class c1 = Class.class 也是

Class类的常用方法

  • static ClassforName(String name)
    返回指定类名name的Class对象
  • Object newInstance()
    调用缺省构造函数,返回Class对象的一个实例
  • getName()
    返回此Cass对象所表示的实体(类,接口,数组类或vold)的名称。
  • Class getSuperClass()
    返回当前Cass对象的父类的Class对象
  • ClassI getinterfaces()获取当前Class对象的接口
  • ClassLoader getClassLoader()返回该类的类加载器
  • Constructorl getConstructors()
    返回一个包含某些Constructor对象的数组
  • Field[] getDeclaredFields()返回Field对象的一个数组

3. 类的加载与ClassLoader的理解

类的加载过程(了解)

初始化的时候,静态代码块和显式赋值谁后写后执行。

类的加载器

类加载器的作用是用来把类(class)装载进内存的。

JVM规范定义了如下类型的类的加载器
自定义加载器–系统类加载器–扩展类加载器–引导类加载器
系统类加载器是最常用的加载器,那些自定义的类

扩展类加载器负责jar包

引导类加载器
c++编写,是JVM自带的类加载器,负责java平台核心库,
用来装载核心类库。该加载器无法直接获取

案例: test2是重点
在工程下创建jdbc.properties,并复制一份到src下。

使用配置文件的时候,把勾勾上,防止出现读取乱码。
Setting –》Editor -》File Encodings

import org.junit.Test;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
public class ClassLoaderTest {
    @Test
    public void test1(){//了解
        //对于自定义的类,使用系统类加载器进行加载
        ClassLoader classLoader = ClassLoaderTest.class.getClassLoader();
        System.out.println(classLoader);
//        sun.misc.Launcher$AppClassLoader@18b4aac2

        //调用系统类加载器的getParent():获取扩展类加载器
        ClassLoader classLoader1 = classLoader.getParent();//上一层
        System.out.println(classLoader1);
//        sun.misc.Launcher$ExtClassLoader@54bedef2

//        调用扩展类加载器的getParent():无法获取引导类加载器
//        引导类加载器主要负责加载java的核心类库,无法加载自定义类的
        ClassLoader classLoader2 = classLoader1.getParent();
        System.out.println(classLoader2);
//null 没有办法直接获取到 引导类加载器 所以呢 也不可能主动地去加载自定义的类

// 举个例子 String获取大的class然后获得类的加载器  此时就是引导类加载器
//     但结果还是null  说明String类是引导类加载器加载的 但还是获取不到的!
        ClassLoader classLoader3 = String.class.getClassLoader();
        System.out.println(classLoader3);
    }
   
    
    @Test
    public void test2() throws IOException {
        Properties pros = new Properties();
//       此时的文件默认在当前的module(工程)下
        //读取配置文件的方式一:
//        FileInputStream fis = new FileInputStream("jdbc.properties");//相对路径
//下面是获取src下的配置文件
//        FileInputStream fis = new FileInputStream("src\jdbc1.properties");
//        pros.load(fis);

        //读取配置文件的方式二:使用ClassLoader
        //配置文件默认识别为:当前module的src下  不然你会报空指针异常
        //如果还是不行,记得重启
        ClassLoader classLoader = ClassLoaderTest.class.getClassLoader();
        InputStream is = classLoader.getResourceAsStream("jdbc1.properties");
//        以流的方式获取资源 返回个输入流
        pros.load(is);

        String user = pros.getProperty("user");
        String password = pros.getProperty("password");
        System.out.println("user = " + user + ",password =" + password);
		
		//user = 爬,password =abc12
    }
}

4. 创建运行时类的对象(重点)

import org.junit.Test;
import java.util.Random;

//通过发射创建对应的运行时类的对象
public class NewInstanceTest {
    @Test
    public void test1() throws Exception {
        Class a = Person.class;
         
	//只要是造对象,都得是用构造器来造,只是形式不一样 
	//有的直接new+构造器 或调方法
        Person o = a.newInstance();//Person类的对象
//        类的泛型决定了上面这个方法的返回值 不用强转了
        System.out.println(o);
    }

    //体会反射的动态性
    @Test
    public void test2(){
        for (int i = 0; i < 5; i++) {
            int num = new Random().nextInt(3);//0  1  2
            String classPath = "";
            switch (num){
                case 0:
                    classPath = "java.util.Date";
                    break;
                case 1:
                    classPath = "java.lang.Object";
                    break;
                case 2:
                    classPath = "com.a.java.Person";
                    break;
            }
            try {
                Object obj = getInstance(classPath);
                System.out.println(obj);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    //创建一个指定类的对象。 classPath:指定类的全类名
    public Object getInstance(String classPath) throws Exception {
        Class a = Class.forName(classPath);
        return a.newInstance();
    }
}


5. 获取运行时类的完整结构(了解)
1.创建Creature

import java.io.Serializable;
public class Creature implements Serializable {
    private char gender;
    public double weight;

    private void breath(){ System.out.println("生物呼吸"); }
    public void eat(){ System.out.println("生物吃东西"); }
}

2.创建注解

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.ElementType.LOCAL_VARIABLE;

@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation { String[] value() default "hello"; }

3.创建个接口

public interface MyInterface { void info(); }

4.Person类

@MyAnnotation(value = "hi")
public class Person extends Creature implements Comparable,MyInterface {
    private String name;
    int age;
    public int id;

    public Person(){}
    
    @MyAnnotation(value = "abc")
    private Person(String name){ this.name = name; }

    Person(String name, int id) {
        this.name = name;
        this.id = id;
    }

    @Override
    public int compareTo(String o) { return 0; }
    @Override
    public void info() { System.out.println("我是一个人"); }
    @MyAnnotation
    private String show(String nation){
        System.out.println("我的国籍是:" + nation);
        return nation;
    }
    public String display(String interests,int age) throws NullPointerException,ClassCastException{
        return interests + age;
    }
    private static void showDesc(){ System.out.println("我是一个可爱的人"); }

    @Override
    public String toString() {
        return "Person{" + "name='" + name + ''' +
                ", age=" + age +", id=" + id + '}';
    }
}

FieldTest

import com.a.java1.Person;
import org.junit.Test;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;

public class FieldTest {
    @Test
    public void test1(){
        Class aClass = Person.class;//大的Class的实例
		//获得属性结构
        //getFields():获取当前运行时类及其父类中声明为public访问权限的属性
        Field[] fields = aClass.getFields();//用数组去接收
        for (Field f : fields) {
            System.out.println(f);
        }
        System.out.println();
        //getDeclaredFields():获取当前运行时类中声明的所有属性。(不包含父类中的声明的属性)
        Field[] declaredFields = aClass.getDeclaredFields();
        for (Field f : declaredFields) { System.out.println(f); }
    }


//    上面只是输出, 如果你想获得属性里面具体的某个结构
    //权限修饰符 数据类型 变量名
    @Test
    public void test2(){
        Class aClass = Person.class;
        Field[] declaredFields = aClass.getDeclaredFields();
        for (Field f : declaredFields) {
            //1.权限修饰符
            int modifier = f.getModifiers();
			// modifier  2 private  0默认  1 public
            System.out.print(Modifier.toString(modifier) + "t");
            //三个值 private 默认 public

            //2.数据类型
            Class type = f.getType(); //getType() 当前变量是哪个类的
            System.out.print(type.getName() + "t");//获取当前Class的名
			//java.lang.String int int  自己也可以定义一个类为String 得和lang包下得区分开

            //3.变量名
            String FName = f.getName();
            System.out.println(FName);
//            name   age   id
        }
    }
}

MothodTest

import com.a.java1.Person;
import org.junit.Test;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;


public class MethodTest {
    @Test
    public void test1(){
        Class aClass = Person.class;
        //getMethods():获取当时运行时类及其所有父类中声明为public权限的方法
        Method[] methods = aClass.getMethods();
        for (Method m : methods ) { System.out.println(m); }
        System.out.println();
        //getDeclaredMethods():获取当前运行时类中声明的所有方法。(不包含父类中声明的方法)
        Method[] declaredMethods = aClass.getDeclaredMethods();
        for (Method m : declaredMethods ) { System.out.println(m); }
    }
	//省略 

    //@Xxx 注解只有runtime才能拿到 运行时
    //权限修饰符 返回值类型 方法名(参数类型1 形参名1,。。。 )throws XxxExeption{}
    @Test
    public void test2(){
        Class aClass = Person.class;
        Method[] declaredMethods = aClass.getDeclaredMethods();
        for (Method m: declaredMethods ) {
            //1.获取方法声明的注解
            Annotation[] annos = m.getAnnotations();
            for (Annotation a:annos) { System.out.println(a); }
            //2.权限修饰符
            System.out.print(Modifier.toString(m.getModifiers()) + "t");
            //3.返回值类型
            System.out.print(m.getReturnType().getName() + "t");
            //4.方法名
            System.out.print(m.getName());
            System.out.print("(");
            //5.形参列表
            Class[] parameterTypes = m.getParameterTypes();
            if (!(parameterTypes == null && parameterTypes.length == 0)){
                for (int i = 0; i < parameterTypes.length; i++) {
                    if (i == parameterTypes.length -1){
                        System.out.print(parameterTypes[i].getName() + " args_" + i);
                        break;
                    }
                    System.out.print(parameterTypes[i].getName() + " args_" + i + ",");
                }
            }
            System.out.print(")");

            //6.抛出的异常
            Class[] exceptionTypes = m.getExceptionTypes();
            if (exceptionTypes.length > 0){
                System.out.print("throws ");
                for (int i = 0; i < exceptionTypes.length; i++) {
                    if (i == exceptionTypes.length-1){
                        System.out.print(exceptionTypes[i].getName());
                        break;
                    }
                    System.out.print(exceptionTypes[i].getName() + ",");
                }
            }

            System.out.println();
        }
    }
}

OtherTest

import com.a.java1.Person;
import org.junit.Test;

import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

public class OtherTest {
    //获取构造器结构
    @Test
    public void test1(){
        Class aClass = Person.class;
        //getConstructors():获取当前运行时类中声明为public的构造器
        Constructor[] constructors = aClass.getConstructors();
        for (Constructor c: constructors) { System.out.println(c); }
        System.out.println();
        //getDeclaredConstructors():获取当前运行时类中声明的所有的构造器
        Constructor[] de = aClass.getDeclaredConstructors();
        for (Constructor c: de) { System.out.println(c); }
    }



    //获取运行时类的父亲
    @Test
    public void test2(){
        Class aClass = Person.class;
        Class superclass = aClass.getSuperclass();
        System.out.println(superclass);
    }


    //获取运行时类的带泛型的父类
    @Test
    public void test3(){
        Class aClass = Person.class;
        Type genericSuperclass = aClass.getGenericSuperclass();
        System.out.println(genericSuperclass);
    }


    //获取运行时类的带泛型的父类的泛型
    //代码: 逻辑性代码  vs 功能性代码
    @Test
    public void test4(){
        Class aClass = Person.class;
        Type genericSuperclass = aClass.getGenericSuperclass();
        ParameterizedType paramType = (ParameterizedType)genericSuperclass;
        //获取泛型类型
        Type[] actualTypeArguments = paramType.getActualTypeArguments();
        System.out.println(actualTypeArguments[0].getTypeName());
        //等价于下面的
        //System.out.println(((Class)actualTypeArguments[0]).getName());
    }


    //获取运行时类实现的接口
    @Test
    public void test5(){
        Class aClass = Person.class;
        Class[] interfaces = aClass.getInterfaces();
        for (Class c : interfaces) { System.out.println(c); }
        System.out.println();
        //获取运行时类的父类实现的接口
        Class[] interfaces1 = aClass.getSuperclass().getInterfaces();
        for (Class c : interfaces1) {  System.out.println(c); }
    }


    //获取运行时类所在的包
    @Test
    public void test6(){
        Class aClass = Person.class;
        Package pack = aClass.getPackage();
        System.out.println(pack);
    }

    //获取运行时类声明的注解
    @Test
    public void test7(){
        Class aClass = Person.class;
        Annotation[] annotations = aClass.getAnnotations();
        for (Annotation annos : annotations) { System.out.println(annos); }
    }
}

6. 调用运行时类的指定结构 (重点)

import com.a.java1.Person;
import org.junit.Test;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;


public class ReflectionTest {
    //通常不采用此方法  不需要掌握
    @Test
    public void  testField() throws Exception {
        Class aClass = Person.class;
        //创建运行时类的对象
        Person p = (Person)aClass.newInstance();
        //获取指定的属性:要求运行时类中的属性声明为public
        Field id = aClass.getField("id");
        //设置当前属性的值 set():参数1:指明设置哪个对象的属性 参数2:将此属性值设置为多少
        id.set(p,1001);
        //获取当前属性的值
        //get():参数1:获取哪个对象的当前属性值
        int pId = (int)id.get(p);
        System.out.println(pId);
    }
	//结果   1001

    //使用这种方法 如何 *** 作运行时类中的指定的属性(需掌握哦)
    @Test
    public void  testField1() throws Exception {
        Class aClass = Person.class;
        Person p = (Person)aClass.newInstance();
		//1.getDeclaredField(String fieldName):
 		//获取运行时类中指定变量名的属性
        Field name = aClass.getDeclaredField("name");
        //2.保证当前属性是可访问的
        name.setAccessible(true);
        //3.获取、设置指定对象的此属性值
        name.set(p,"Tom");
        System.out.println(name.get(p));
    }
	//结果   Tom

    //如何 *** 作运行时类中的指定的方法(需掌握哦)
    @Test
    public void  testMehod() throws Exception {
        Class aClass = Person.class;
//        非静态的方法一定要有运行时类的对象
        Person p = (Person)aClass.newInstance();
        //1.获取指定的某个方法
        //getDeclaredMethod(): 
        //参数1 :指明获取的方法的名称 参数2:指明获取的方法的形参列表
        //show这个方法可能有很多,所以告诉我用的是哪个参数的
        Method show = aClass.getDeclaredMethod("show", String.class);
        //2.保证当前属性是可访问的
        show.setAccessible(true);
        //3.调用方法的invoke():
        //参数1:方法的调用者 参数2:给方法形参赋值的实参
        //invoke()的返回值即为对应类中调用的方法的返回值
        Object returnValue  = show.invoke(p,"CHN");
        System.out.println(returnValue);
        System.out.println("********************如何调用静态方法*****************************");
        //private static void showDesc()
        Method showDesc = aClass.getDeclaredMethod("showDesc");
        showDesc.setAccessible(true);
        //如果调用的运行时类中的方法没有返回值,则此invoke()返回null
        Object returnVal = showDesc.invoke(Person.class);
        //但因为是静态方法 aClass知道你调的是啥 直接调就行 只有非静态方法需要知道你是哪个对象的
//            静态方法每个对象调都一样
//        Object returnVal2 = showDesc.invoke(null);
        System.out.println(returnVal);//null
    }



    //如何 *** 作运行时类中的指定的构造器(不重要)
    @Test
    public void  testConstructor() throws Exception {
        //private Person(String name)
        Class aClass = Person.class;
        //1.获取指定的构造器
        //getDeclaredConstructor():参数:指明构造器的参数列表
        Constructor constructor = aClass.getDeclaredConstructor(String.class);
        //2. 保证此构造器是可访问的
        constructor.setAccessible(true);
        //3.调用此构造器创建运行时类的对象
        Person per = (Person)constructor.newInstance("Tom");
        System.out.println(per);
    }
}
//结果  Person{name='Tom', age=0, id=0}

7. 反射的应用:动态代理

代理设计模式的原理:
使用一个代理将对象包装起来,然后用该代理对象取代原始对象。
任何对原始对象的调用都要通过代理。
代理对象决定是否以及何时将方法调用转到原始对象上。

静态代理:
代理类和目标对象的类都是在编译期间确定下来,不利于程序的扩展。
同时,每一个代理类只能为一个接口服务,
这样一来程序开发中必然产生过多的代理。
最好以通过一个代理类完成全部的代理功能。

动态代理
指客户通过代理类来调用其它对象的方法,
并且是在程序运行时根据需要动态创建目标类的代理对象。

动态代理使用场合: 调试 远程方法调用

动态代理相比于静态代理的优点:
抽象角色中(接口)声明的所有方法都被转移到
调用处理器一个集中的方法中处理,
这样,我们可以更加灵活和统一的处理众多的方法。

静态代理举例
特点: 代理类和被代理类再编译期间,就确定下来了。

interface ClothFactory{ void produceCloth(); }
//代理类
class ProxyClothFactory implements ClothFactory {
    private ClothFactory factory;//用被代理类对象进行实例化
    public ProxyClothFactory(ClothFactory factory){
    //对上面的属性进行初始化 里面的参数作用
        this.factory=factory;
    }
    @Override
    public void produceCloth() {
        System.out.println("代理工厂做一些准备工作");
        factory.produceCloth();
        System.out.println("代理工厂做一些后续的收尾工作");
    }
}
//被代理类
class NikeClothFactory implements ClothFactory {
    @Override
    public void produceCloth() { System.out.println("Nike工厂生产一批运动服"); }
}
public class StaticProxyTest {
    public static void main(String[] args) {
        //创建被代理类的对象
        ClothFactory nike = new NikeClothFactory();
        //创建代理类的对象
        ClothFactory proxyClothFactory = new ProxyClothFactory(nike);
        proxyClothFactory.produceCloth();
    }
}

结果:
代理工厂做一些准备工作
Nike工厂生产一批运动服
代理工厂做一些后续的收尾工作

动态代理类 目前太难,跳过

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

interface Human{
    String getBelief();
    void eat(String food);
}
//被代理类
class SuperMan implements Human {
    @Override
    public String getBelief() { return "I believe I can fly!"; }

    @Override
    public void eat(String food) { System.out.println("我喜欢吃" + food); }
}

class ProxyFactory{
    //调用此方法。返回一个代理类的对象。解决问题一:
    public static Object getProxyInstance(Object obj){//obj 被代理类的对象
        MyInvocationHandler handler = new MyInvocationHandler();
        handler.bind(obj);
        //创建代理类的对象
        return Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(),handler);
        //获得类的加载器 代理类和被代理类实现的接口是一样的
    }
}
class MyInvocationHandler implements InvocationHandler {
    private Object obj;
    public void bind(Object obj){ this.obj=obj; }
    //当我们通过代理类的对象,调用方法a时,就会自动的调用如下的方法:invoke()
    //将被代理类要执行的方法a的功能就声明再invoke()中
    // 回答问题2
    @Override //代理类的对象 调什么方法
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //method:即为代理类对象调用的方法,此方法也就作为了被代理类对象要调用的方法
        // obj:被代理对象
        Object returnValue = method.invoke(obj,args);
        //上诉方法的返回值就作为当前类中的invoke()的返回值。
        return returnValue;
    }
}
public class ProxyTest {
    public static void main(String[] args) {
        SuperMan superMan = new SuperMan();
        //proxyInstance:代理类对象
        Human proxyInstance = (Human) ProxyFactory.getProxyInstance(superMan);
        //当通过代理类对象调用方法时,会自动的调用被代理类中同名的方法
        String belief = proxyInstance.getBelief();
        System.out.println(belief);
        proxyInstance.eat("四川火锅");
        System.out.println("******");
        NikeClothFactory nikeClothFactory = new NikeClothFactory();
        ClothFactory ProxyClothFactory = (ClothFactory)ProxyFactory.getProxyInstance(nikeClothFactory);//代理类的对象 动态造的
        ProxyClothFactory.produceCloth();
    }
}
  

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5573612.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-14
下一篇 2022-12-14

发表评论

登录后才能评论

评论列表(0条)

保存