1012-2019学习记录(P596-P690)-反射

程序 专栏收录该内容
17 篇文章 0 订阅

反射

  1. 反射机制的概述
  2. 理解class类并获取classs实例
  3. 类的加载与ClassLoader实例
  4. 创建运行时的对象
  5. 获取运行时类的完整结构
  6. 调用运行时类的指定结构
  7. 反射的应用:动态代理

使用反射之前,在类的外部,没法调用私有的。

通过反射调用person类的对象。

通过反射可以调用类的私有的构造器。

反射机制和之前面向对象的封装性是不是有冲突?

不冲突。封装性是建议使用公共的方法,不建议在外部使用私有的方法。、
反射要调用私有的,那就调好了。

以后通过new还是通过反射新建对象?
服务跑起来了,不知道你要干什么,就是一个动态的过程。

编译的时候没法确定要用new那个对象?

Java.lang.Class类的理解

  1. 类的加载过程
    源码经过Javac命令后就会生成 一个或多个字节码文件。(.class文件)
    真正的加载过程:使用java 命令对某个字节码文件进行解释运行。相当于将某个字节码文件加载到内存中。此过程就称为类的加载。加载到内存中的类就称为运行时类。
    就称为Class的实例。类本身也是对象,是大Class的对象。

重新理解万事万物皆对象。大Class的实例化就是直接把一个运行时的类赋值过去就行。

获取Class的实例的方式
//方式一:调用运行时类的属性.class
Class clazz = Person.class;
System.out.println(clazz);
//方式二:通过调用运行时类的对象的getClass()方法
Person p1 = new Person();
Class<? extends Person> clazz2 = p1.getClass();
System.out.println(clazz2);
//方式三用的最多:通过调用class的静态方法
Class<?> clazz3 = Class.forName(“Person”);
//clazz3 = Class.forName(“java.lang.String”);
System.out.println(clazz3);

    //方式四:使用类的加载器ClassLoader(不要求掌握,但是可以了解)

    ClassLoader classLoader = Solution.class.getClassLoader();
    Class clazz4 = classLoader.loadClass("Person");


    System.out.println(clazz == clazz2);
    System.out.println(clazz == clazz3);
    System.out.println(clazz == clazz4);

    ClassLoader classLoader1 = Solution.class.getClassLoader();
    System.out.println(classLoader1);

Solution指的是当前类名。

哪些类型可以有Class对象?
基本都可以。外部类内部类包装类注解数组等等。

在这里插入图片描述
理解类的加载过程:
类的加载和类的链接和类的初始化

有静态的变量:就在链接中设置为0,在初始化再重新初始化。

在这里插入图片描述
注意在进入类的加载器之前,要先将源程序进入到Java编译器编译成字节码文件,然后再进入了类的加载器。

通过类的加载器可以加载到内存中,会持续一段时间。
有三类加载器:引导类加载器(用c++编写的Java核心库),扩展类加载器(EXTEND)(jre/lib/ext下的jar包就是用这个加载器生成的),还有系统类加载器(自定义类的加载就用这个)

配置文件的加载:
Properties的测试

@Test
方式一
public void test1() throws Exception {

    Properties pro = new Properties();
    FileInputStream fis = new FileInputStream("src\\jdbc.properties");
    pro.load(fis);

方式二:使用classloader的getResourceAsStream来读取配置文件
/*ClassLoader loader = Solution.class.getClassLoader();
InputStream is = loader.getResourceAsStream(“jdbc.properties”);
pro.load(is);
*/

    String user = pro.getProperty("user");
    String password = pro.getProperty("password");
    System.out.println("user = " + user + "," + "password = " + password);
    
}

Class clazz = Person.class;
Person o = clazz.newInstance();
System.out.println(o);
注意:要想此方法正常的创建运行时类的对象,要求:

  1. 运行时类必须提供一个空参数的构造器。
  2. 空参数的构造器的权限必须够用,default或者是·public

空参数构造器的意义:

1便于通过反射来创建一个运行时类的对象。属性值之后再赋值
2便于子类在继承此运行时类时,默认调用super()时不会有异常,保证父类一定有构造器。

理解反射的动态性

比如给随机数对应的是classPath这样的话,newInstance时就不知道到底是new的哪个类
体现了反射的动态性。

GetField();
能获取当前运行时类及其父类中声明为public访问权限的属性
所有声明过的变量:
getDeclaredFields();

获取方法:
GetMethod所有方法包括父类
GetDeclaredMethods;自己声明的

获取形参类型、名字

获取异常

调用运行时类的指定结构

属性,获取指定的属性
GetField(String name);或者中间加一个Declared
如果是private或者是默认的
那么就必须设置成setAccessible(true)
设置当前属性的值:set方法(要求是public)
参数一:指明设置哪个对象的属性。
参数二:设置为多少。

获取方法,指明获取方法的名称,然后获取形参列表。

setAccessbile(true);
执行,invoke(p,”abc”);
调用静态方法:
还是指明方法的名字就好。

调用构造器:
Clazz.getDeclaredConstructor
保证此构造器是可以访问的
调用此构造器创建运行时类的对象
一般来说,只调用空参构造器。

写的时候一定要考虑利用反射的动态性:
对Class类的理解:
Class实例对应着加载到内存中的一个运行时类。
Object obj = clazz.newInstance();

反射在干什么?
为了体现JAVA的动态性,框架 = 反射 + 注解 + 设计模式。
获取一个类的内部信息。
不知道用户想访问什么,就在用反射,告诉我你要访问什么然后再创建对应的对象。

反射的应用:动态代理

AOP的原理就是动态代理

代理类与被代理类

静态代理模式:编译期的模式,一对一的模式。
动态代理模式:运行期间加载,通过加载的被代理类,然后再实现通用的代理类

静态代理:代理类中有被代理类。
JAVA8的新特性:

Lambda表达式的写法
方法引用的写法
作为接口的匿名实现类。

Function接口就是只包含一个抽样方法
通过Lambda表达式创建 @FunctionInterface
之前用匿名实现类后来都用函数式接口(lambda表达式)
Java内置的四大函数式接口
消费型接口
供给型接口
函数式接口
断定型接口

方法引用
::
什么时候使用方法引用?或者说使用的要求。
接口中的抽样方法和返回值类型与方法引用的方法的形参列表和返回值类型相同的话。

当要传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用
方法引用本质上就是Lambda表达式
使用格式: ::

写法的难度:匿名实现类 < Lambda表达式 < 方法引用

都是函数式接口(一个接口中只实现了一个函数式接口)的实例

Java8还有一个Stream API 对集合数据进行操作,类似于SQL的操作。
关系型数据库和分布式数据库
创建Stream,中间操作,终止操作
只有执行了终止操作才会执行中间操作。
Stream也是用来操作容器用的。
实例化
Skip(3);limit(3);
Stream.Sort()自然排序,定制排序。
对象的排序必须实现排序接口
Stream有各种的方法检查和匹配的方法。
归约:
Reduce:计算1到10自然数的和。就是计算各种数据的结合。
收集:把Stream放到集合中
Optional
为了避免空指针异常而创建的
Nullof
Orelse方法

public String getGirlName(Boy boy){

    Optional<Boy> boyOptional = Optional.ofNullable(boy);

    Boy boy1 = boyOptional.orElse(new Boy(new Girl("倪妮")));

    Girl girl = boy1.getGirl();
    Optional<Girl> girlOptional = Optional.ofNullable(girl);
    Girl girl1 = girlOptional.orElse(new Girl("汤唯"));
    return girl1.getName();




}
@Test
public void test(){

    Boy boy = null;
    boy = new Boy(new Girl("韦永丽"));

    String name = getGirlName(boy);
    System.out.println(name);

}

使用Runnable接口来创建多线程就是一种静态代理

  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 打赏
    打赏
  • 扫一扫,分享海报

参与评论 您还未登录,请先 登录 后发表或查看评论
©️2022 CSDN 皮肤主题:大白 设计师:CSDN官方博客 返回首页

打赏作者

皮蛋zzz

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值