Java超全面笔记(十二)--- 反射

自己学习时记的笔记整理

//反射后可以做的操作

@Test

public void test2() throws Exception{

    //1. 通过反射,创建Person类对象

    Class clazz = Person.class;

    Constructor cons = clazz.getConstructor(String.class, int.class);

    Object obj = cons.newInstance("Tom",12);

    Person p = (Person) obj;

    System.out.println(p);

    //2. 通过反射,调用对象指定的属性、方法

    Field age = clazz.getDeclaredField("age");

    age.set(p,10);

    System.out.println(p);

    Method show = clazz.getDeclaredMethod("show");

    show.invoke(p);

    //3. 通过反射,可以调用Person类的私有结构。私有的构造器、属性、方法

    Constructor cons1 = clazz.getDeclaredConstructor(String.class);

    cons1.setAccessible(true);

    Person p1 = (Person) cons1.newInstance("Jerry");

    System.out.println(p1);



    Field name = clazz.getDeclaredField("name");

    name.setAccessible(true);

    name.set(p1,"Han");

    System.out.println(p1);



    Method showNation = clazz.getDeclaredMethod("showNation", String.class);

    showNation.setAccessible(true);

    showNation.invoke(p1,"中国");

//        String nation = (String)showNation.invoke(p1,"中国");//相当于返回一个String

//        System.out.println(nation);

    System.out.println(nation);

}

Tip1:开发中尽量用直接new的方式调用公共结构【编译时就可以检查】

当不能确定要创建什么类的对象时选择反射的方式

Tip2:反射和封装性不矛盾【封装性中的private表明不建议外部使用,但是非要用通过反射调用也行】

java.lang.Class

  1. 类的加载过程
    程序经过javac.exe命令后,会生成一个或多个字节码文件(.class结尾),接着使用java.exe命令对某个字节码文件进行解释运行。相当于将某个字节码文件加载到内存中,此过程就称为类的加载。加载到内存中的类,即为运行时类,就作为Class的一个实例。
  2. Class的实例就对应着一个运行时类。
  3. 加载到内存中的运行时类,会缓存一段时间。在此时间内,可以通过不同方法获取此运行时类。

获取Class实例☆

方式一:调用运行时类的属性:.class

Class<Person> clazz1 = Person.class;//Class的泛型可加可不加

System.out.println(clazz1);

方式二:通过运行时类的对象

Person p1 = new Person();

Class clazz2 = p1.getClass();

System.out.println(clazz2);

方式三:调用Class的静态方法:forName(String classPath)【常用】

classPath要写出能唯一标识指定类的位置】

Class clazz3 = Class.forName("p1.Person");

System.out.println(clazz3);

方式四:使用类的加载器:ClassLoader(了解)

ClassLoader classLoader = ReflectionTest.class.getClassLoader();

Class clazz4 = classLoader.loadClass("p1.Person");

System.out.println(clazz4);

可以有Class对象的类型:

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

interface

数组:只要数组的元素类型和维度相同,就是同一个class(int [10]和int[100])

enum

annotation

基本数据类型

void

ClassLoader

对于自定义类,使用系统类加载器进行加载

调用系统类加载器的getParent():获取扩展类加载器

调用扩展类加载器的getParent():无法获得引导类加载器【引导类加载器主要负责加载java的核心类库,无法加载自定义类】

通过ClassLoader获取配置文件(.properties)信息

public void test2() throws IOException {

    Properties pros = new Properties();

    //方式一:此时文件路径默认识别在当前module下

    FileInputStream fis = new FileInputStream("jdbc.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+password);

}

创建运行时类的对象

通过反射创建对应的运行时类的对象

newInstance():调用此方法,创建对应的运行时类的对象。实际内部调用了运行时类的空参构造器

要求:

  1. 运行时类必须提供空参的构造器
  2. 空参构造器的访问权限得够。通常设置为public
Class<Person> clazz = Person.class;

Person p = clazz.newInstance();

System.out.println(p);

获取运行时类的完整结构(了解)

getModifiers():权限修饰符(输出012形式,可加上.toString()输出public,private…)

getType():数据类型

getName():变量名、方法名

属性

getFields():获取当前运行时类及其所有父类中声明为public的属性

getDeclaredFields():获取当前运行时类中声明的所有属性【所有权限的】

方法

getMethods():获取当前运行时类及其所有父类中声明为public的方法

getDeclaredMethods():获取当前运行时类中声明的所有方法【所有权限的】

getAnnotations():获取方法声明的注解(返回一个数组)

getReturnType():返回值类型

getParameterType():形参列表类型(返回数组)【数组[i].getName()获取形参名】

getExceptionTypes():抛出的异常(返回数组)【数组[i].getName()获取异常名】

构造器

getConstructors():获取当前运行时类中声明为public的构造器

getDeclaredConstructors():获取当前运行时类中声明的所有构造器

父类

getSuperClass():获取父类

getGenericSuperClass():带泛型的父类

getActualTypeArguments():父类的泛型(返回数组)【(ParameterizedType)带泛型的父类的对象.该方法】

接口

getInterfaces():获取接口(返回数组)

getPacket():获取所在的包

getAnnotations():获取声明的注解

调用运行时类的指定结构

创建运行时类的对象

不常用↓

获取指定的属性:要求运行时类中属性声明为public

Field id = clazz.getField("id");

set(参数1,参数2):参数1:指明设置哪个对象的属性  参数2:将此属性值设置为多少

id.set(p,10011);

get(参数1):参数1:获取哪个对象的当前属性值

int pId = (int) id.get(p);

常用方法

Field id = clazz.getDeclaredField("id");
id.setAccessible(true);

setAccessible():设置对获取的属性的操作权限【不设置的话private的属性不能操作】

获取指定方法同理

方法名.invoke(参数1,参数2):参数1:方法的调用者  参数2:给方法形参赋值的实参

Method show = clazz.getDeclaredMethod("show",String.class);
show.setAccessible(true);
show.invoke(p,"CHN");

获取静态方法

//private static void showDesc()
Method showDes = clazz.getDeclaredMethod("showDesc");
showDes.setAccessible(true);
Object returnVal = showDes.invoke(null); //方法没有返回值则传一个null
Object returnVal = showDes.invoke(Person.class);//两种参数都可以

获取指定构造器

getDeclaredConstructor():参数:指明构造器的参数列表

Constructor constructor = clazz.getDeclaredConstructor(String.class);
constructor.setAccessible(true);
Person per = (Person) constructor.newInstance("Tim");

动态代理

静态代理:代理类和被代理类在编译期间,就确定下来了

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("代理工厂1");
        factory.produceCloth();

        System.out.println("代理工厂2");
    }
}

//被代理类
class NikeClothFactory implements ClothFactory{

    @Override
    public void produceCloth() {
        System.out.println("Nike");
    }
}

public class StaticProxtTest {
    public static void main(String[] args) {
        //被代理类
        NikeClothFactory nike = new NikeClothFactory();
        //代理类
        ProxyClothFactory proxyClothFactory = new ProxyClothFactory(nike);

        proxyClothFactory.produceCloth();
    }
}

实现动态代理需要解决的问题:

Q1:如果根据加载到内存中的被代理类,动态地创建一个代理类及其对象

Q2:当通过代理累的对象调用方法a时,如何动态地去调用被代理类中的同名方法a

interface Human{
    String getBelief();
    void eat(String food);
}
//被代理类
class SuperMan implements Human{

    @Override
    public String getBelief() {
        return "fly";
    }

    @Override
    public void eat(String food) {
        System.out.println("吃"+food);
    }
}
//代理类
class ProxyFactory{
    //调用此方法,返回一个代理类的对象。解决问题一
    public static Object getProxyInstance(Object obj){
        MyInvocationHandler handler = new MyInvocationHandler();
        handler.setObj(obj);
        return Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(),handler);

    }
}

class MyInvocationHandler implements InvocationHandler{
    private Object obj;//需要使用被代理类的对象进行赋值

    public void setObj(Object obj) {
        this.obj = obj;
    }

    //当我们通过代理类的对象,调用方法a时,就会自动调用如下的方法:invoke()
    //将被代理类要执行的方法a的功能就声明在invoke中
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //method:即为代理类对象调用的方法,此方法也就作为了被代理类对象要调用的方法
        //obj:被代理类的对象
        Object returnVal = method.invoke(obj,args);
        //上述方法的返回值就作为当前类中的invoke()的返回值
        return returnVal;
    }
}

public class ProxyTest {
    public static void main(String[] args) {
        SuperMan superMan = new SuperMan();
        //proxyInstance:代理类的对象
        Human proxyInstance = (Human) ProxyFactory.getProxyInstance(superMan);//不能写成是SuperMan的对象,否则就成自己代理自己了。
        // 默认是Object,可以写成是他们的共同接口
        //当通过代理类对象调用方法时,会自动调用被代理类中同名的方法
        String belief = proxyInstance.getBelief();
        System.out.println(belief);
        proxyInstance.eat("cake");
        System.out.println("**************************************");
        NikeClothFactory nikeClothFactory = new NikeClothFactory();
        ClothFactory proxyClothFactory = (ClothFactory) ProxyFactory.getProxyInstance(nikeClothFactory);
        proxyClothFactory.produceCloth();
    }
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值