java进阶学习笔记

学习java深度学习,提升编程思维,适合掌握基础知识的工作者学习

  • 1.反射和代理
    • 1.1 概念介绍
    • 1.2应用场景
    • 1.3 反射-reflect
      • 1.3.1 获得类-Class
      • 1.3.2 获得类的字段-Field
      • 1.3.3 动态访问和修改对象实例的字段
      • 1.3.4 获得类方法-Method
      • 1.3.5 调用方法.invoke
      • 1.3.6 类实例化-构造函数Constructor
      • 1.3.7 instanceof
      • 1.3.8 利用反射来解析spring配置
    • 1.4 代理
      • 1.4.1 代理模式
      • 1.4.2 准备工作
      • 1.4.3 静态代理
      • 1.4.4 动态代理

1.反射和代理

1.1 概念介绍

在Java编程中,反射和代理是两个强大的特性,能够在运行时动态地操作和扩展类的行为。通过反射,我们可以在不知道类的具体信息的情况下操作类的属性和方法;而代理则允许我们创建一个代理类来拦截并增强目标对象的行为

1.2应用场景

像咱们平时大部分时候都是在写业务代码,很少会接触到直接使用反射机制的场景。
但是,这并不代表反射没有用。相反,正是因为反射,你才能这么轻松地使用各种框架。像 Spring/Spring Boot、MyBatis 等等框架中都大量使用了反射机制,掌握反射和代理机制,有利于我们了解这些框架的内核原理,提升编程思维

  • xml的bean配置的注入
  • AOP拦截
  • 数据库事务
  • springMVC
  • Java注解
  • 开发工具如IDEA,提供一个类的属性方法展示给我们智能快捷选择

这些内核都是反射和代理机制在其作用

1.3 反射-reflect

由于JVM为每个加载的class创建了对应的Class实例,并在实例中保存了该class的所有信息,包括类名、包名、父类、实现的接口、所有方法、字段等,因此,如果获取了某个Class实例,我们就可以通过这个Class实例获取到该实例对应的class的所有信息。这种通过Class实例获取class信息的方法称为反射(Reflection)。

我们正常得到一个对象实例是通过new方法创建对象;反射就是通过class来实现,
1.获得类class
2.获得类的字段属性和方法
3.获得类的实例对象
4.获得对方法的调用

准备工作

Food.java

public class Food {private Integer id;private  String name;// ....省略get set 等
}

1.3.1 获得类-Class

获得类有三种方式,看代码演示

类.class
对象.getClass();
Class.forName(“类名”)

 /**** @Description: 得到Class*/@Testpublic void t1() throws ClassNotFoundException {Class cls=null;//1.通过类名直接获得cls= Food.class;//2.通过实例获得cls=new Food(1, "火锅").getClass();//3.通过路径+类名的字符串获得cls=Class.forName("com.jsoft.reflection.Food");printClassInfo(cls);}/**** @Description: 读取类的信息*/static void printClassInfo(Class cls) {System.out.println("Class name: " + cls.getName());System.out.println("Simple name: " + cls.getSimpleName());if (cls.getPackage() != null) {System.out.println("Package name: " + cls.getPackage().getName());}System.out.println("is interface: " + cls.isInterface());System.out.println("is enum: " + cls.isEnum());System.out.println("is array: " + cls.isArray());System.out.println("is primitive: " + cls.isPrimitive());}

打印效果

Class name: com.jsoft.reflection.Food
Simple name: Food
Package name: com.jsoft.reflection
is interface: false
is enum: false
is array: false
is primitive: false

1.3.2 获得类的字段-Field

演示代码

public class Father  extends Man{private Integer age;public  String job;}public class Man{private Integer id;private String name;public String address;}

对任意的一个Object实例,只要我们获取了它的Class,就可以获取它的一切信息。
我们先看看如何通过Class实例获取字段信息。Class类提供了以下几个方法来获取字段:

方法说明
Field getField(name)根据字段名获取某个public的field(包括父类)
Field[] getFields()获取所有public的field(包括父类)
Field getDeclaredField(name)根据字段名获取当前类的某个field(不包括父类)
Field[] getDeclaredFields():获取当前类的所有field(不包括父类)

注意:
Declared修饰就只管当前类字段,和private、public无关
否则就包含父类的public

测试代码

 @Testpublic void t2() throws NoSuchFieldException {Class cls= Father.class;//1.得到当前类的所有字段,不包含父类Field[] fs=cls.getDeclaredFields();System.out.println("1.得到当前类的所有字段,不包含父类");for (Field f : fs) {printFeild(f);}//2.得到当前类某个字段System.out.println("2.得到当前类某个字段,不包含父类");Field f=cls.getDeclaredField("job");printFeild(f);//3.得到当前类及父类的所有public字段System.out.println("3.得到当前类及父类的所有public字段");fs=cls.getFields();for (Field f1 : fs) {printFeild(f);}//4.得到当前类及父类的public字段System.out.println("4.得到当前类及父类的public字段,如果是private,则要报错");f=cls.getField("address");printFeild(f);}/**** @Description: 打印字段信息*/public  void printFeild(  Field f){System.out.println("//------------字段信息 start");System.out.println("字段名称:"+f.getName());System.out.println("字段类型:"+f.getType().getName());int m = f.getModifiers();System.out.println("field is final:"+Modifier.isFinal(m));; // trueSystem.out.println("field is Public:"+Modifier.isPublic(m));; // trueSystem.out.println("field is Protected:"+Modifier.isProtected(m));; // trueSystem.out.println("field is Private:"+Modifier.isPrivate(m));; // trueSystem.out.println("field is Static:"+Modifier.isStatic(m));; // trueSystem.out.println("//------------字段信息 end");}

1.3.3 动态访问和修改对象实例的字段

我们可以通过一个对象对应的class去动态访问或修改对象的字段
Field.set(vo对象,修改值) //修改字段值
Feild.get(vo对象) //获得字段值
Feild.setAccessible(true); //私有字段,需要设置这个允许访问,否则报异常

  @Testpublic void t3() throws NoSuchFieldException, IllegalAccessException {Food food=new Food(1, "火锅");System.out.println("food.getName:"+food.getName());Class cls=food.getClass();Field f=cls.getDeclaredField("name");f.setAccessible(true); //不设置这个private 字段要抛出异常//通过field获得值Object name= f.get(food);System.out.println("name:"+name);//通过field设置值f.set(food, "西北风");System.out.println("name:"+food.getName());}

1.3.4 获得类方法-Method

方法说明
Method getMethod(name, Class…)获取某个public的Method(包括父类)
Method[] getMethods()获取所有public的Method(包括父类)
Method getDeclaredMethod(name, Class…)获取当前类的某个Method(不包括父类)
Method[] getDeclaredMethods():获取当前类的所有Method(不包括父类)

示例代码

@Data
public class Father  extends Man{private Integer age;public  String job;public  String play(int type){System.out.println("param value:"+type);return type+"";}public  String sleep(String type, Date date){System.out.println("param value type:"+type+";date:"+date);return type+"";}private  void self(){System.out.println("this is private method");}public void dd(){System.out.println("没有参数方法()");}}@Data
public class Man{private Integer id;private String name;public String address;@Overridepublic Food eat() {return new Food(1,"火锅");}
}

测试代码

@Testpublic void t4() throws IllegalAccessException, NoSuchMethodException {Class cls= Father.class;System.out.println("1. 获取所有public的Method(包括父类)");Method[] methods=cls.getMethods();for (Method method : methods) {printMethod(method);}System.out.println("2. 获取某个public的Method(包括父类)");//第一个参数为方法名,第二参数是可变参数,传递方法的参数类型,如果无参数则不传递Method m= cls.getMethod("getName");printMethod(m);//方法有1个参数//注意int foat double这些基本类型对用的类是int.class,不是Integer.classm=cls.getMethod("play", int.class);printMethod(m);//方法有多个参数m=cls.getMethod("sleep", String.class, Date.class);printMethod(m);System.out.println("3. 获取当前类的的Method(不包括父类)");m= cls.getDeclaredMethod("getJob");printMethod(m);//私有方法也可以m= cls.getDeclaredMethod("self");//父类方法不可以,要报java.lang.NoSuchMethodExceptionm= cls.getDeclaredMethod("eat");printMethod(m);printMethod(m);}public void printMethod(Method addMethod){System.out.println("---------方法名称: 【" + addMethod.getName()+"】---相关属性------------");System.out.println("修饰符: " + Modifier.toString(addMethod.getModifiers())); //public private等System.out.println("返回值: " + addMethod.getReturnType()); //返回值类型的class数组Class[] paramsCls= addMethod.getParameterTypes(); //参数值类型对应的class数组}

1.3.5 调用方法.invoke

我们可以用Method.invoke(vo,参数)来调用方法

代码

@Testpublic void t5() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {Father father=new Father();Class cls= father.getClass();Method m=null;//无参无返回方法m=cls.getMethod("dd");m.invoke(father);//有参数,有返回值m=cls.getMethod("sleep", String.class,Date.class);String ret=(String)m.invoke(father, "1",new Date());System.out.println("返回值:"+ret);//private方法调用m=cls.getDeclaredMethod("self");//私有方法必须设置为m.setAccessible(true);m.setAccessible(true);m.invoke(father);}

jdk内置对象的方法调用的另外一种写法

  @Testpublic void t6() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {String s="abcde";String sub=s.substring(0,2);System.out.println(sub);//通过类加载Class   cls=String.class;Method method=cls.getMethod("substring",int.class,int.class);sub=(String) method.invoke(s, 0,2);System.out.println(sub);}

Method m =Father.class.getMethod(“dd”);
m.invoke(new Father());

其实就相当于

Father f=new Father();
f.dd();

1.3.6 类实例化-构造函数Constructor

实例化对象有3中方法
1.我们都知道的new 对象Father father=new Father();
2.通过类class:newInstance
3.构造方法:Constructor

准备类

public class Const {private Integer id;private String name;public Const() {System.out.println("无参数构造方法");}public Const(Integer id, String name) {System.out.println("有参数构造方法");this.id = id;this.name = name;}
}

在很多框架里,我们为了足够的扩展,都通过配置来实现类的实例化

Class.newInstance()

  @Testpublic void t7() throws ClassNotFoundException, InstantiationException, IllegalAccessException {Class cls =Class.forName("com.jsoft.reflection.Const");Const aConst = (Const) cls.newInstance();}

Class.newInstance()最大的问题是只能实例化无参的构造方法,如果我们把无参构造方法屏蔽掉,代码会出错,所以我们需要使用Constructor类来实现有参的构造方法

这里是引用一共有4种方法,全部都在Class类中:

  1. getConstructors():获取类中的公共方法
  2. getConstructor(Class[] params): 获取类的特定构造方法,params参数指定构造方法的参数类型
  3. getDeclaredConstructors(): 获取类中所有的构造方法(public、protected、default、private)
  4. getDeclaredConstructor(Class[] params): 获取类的特定构造方法,params参数指定构造方法的参数类型

代码示例

    @Testpublic void t8() throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {Class cls =Class.forName("com.jsoft.reflection.Const");//得到所有构造函数Constructor[] constructors=  cls.getConstructors();for (Constructor constructor : constructors) {System.out.println("修饰符: " + Modifier.toString(constructor.getModifiers()));System.out.println("构造函数名: " + constructor.getName());System.out.println("参数列表: " );Class[] cs= constructor.getParameterTypes();for (Class c : cs) {System.out.println(c.getName());}}//获得具体一个(无参)Constructor cst=cls.getConstructor();//newInstance实例化Const const1=(Const) cst.newInstance();//获得具体一个(有参)cst=cls.getConstructor(Integer.class,String.class);//传入构造函数的参数的类型//newInstance实例化const1=(Const) cst.newInstance(1,"蒋增奎");}

1.3.7 instanceof

instanceof是判断一个实例对象是不是一个类的实例,是则返回true
对象 instanceof 类

class Person{
}class Teacher extends Person{
}class Student extends Person{
}

测试

public class test01 {public static void main(String[] args) {Object obj = new Student(); // 主要看这个对象是什么类型与实例化的类名System.out.println(obj instanceof Student); // trueSystem.out.println(obj instanceof Person); // trueSystem.out.println(obj instanceof Object); // trueSystem.out.println(obj instanceof String); // falseSystem.out.println(obj instanceof Teacher); // false  无关系System.out.println("========================");Person person = new Student();System.out.println(person instanceof Person); // trueSystem.out.println(person instanceof Object); // true// System.out.println(person instanceof String); // 编译错误System.out.println(person instanceof Teacher); // false 无关系}
}

1.3.8 利用反射来解析spring配置

<bean id="employee" class="com.jsoft.po.Employee"><property name="id" value="1" /><property name="name" value="蒋增奎" /><property name="deptId" value="001" />
</bean>

解析思路

1.用dom4j解析xml得到xml数据
2.创建类:Class cls=Class.forName(“Employee”);
3.创建对象:Employee obj=(Employee)cls.newInstance();
4.调用修改字段或者方法给字段注入值

1.4 代理

1.4.1 代理模式

代理模式是一种比较好理解的设计模式。简单来说就是 我们使用代理对象来代替对真实对象(real object)的访问,这样就可以在不修改原目标对象的前提下,提供额外的功能操作,扩展目标对象的功能。

代理模式的主要作用是扩展目标对象的功能,比如说在目标对象的某个方法执行前后你可以增加一些自定义的操作。

举个例子:
boy向girl求婚
(1)现代:boy和girl直接发生通信,girl迫不及待的同意了
(2)古代:boy不能直接和girl发生关系,需要通过媒婆,boy向媒婆发起请求,媒婆转告girl,gilr同意,媒婆觉得女孩如果同意,婚前应该收彩礼10万,婚后不能家暴,媒婆就是代理,在原始的反馈上增加了自己的要求,提升了框架的健壮性。
在这里插入图片描述
代理分为静态代理和动态代理两种类型

1.4.2 准备工作

public interface Love {/**** @Description: 结婚请求*/public void marray();
}/**
接口实现类
**/
public class LoveImpl implements Love {@Overridepublic void marray() {System.out.println("我同意");}
}

1.4.3 静态代理

静态代理实现步骤:
1.定义一个接口及其实现类;
2.创建一个代理类同样实现这个接口
3.将目标对象注入进代理类,然后在代理类的对应方法调用目标类中的对应方法。这样的话,我们就可以通过代理类屏蔽对目标对象的访问,并且可以在目标方法执行前后做一些自己想做的事情。

代码:

//代理类要实现接口
public class LoveProxy implements Love {private Love target;//代理的接口/**** @Description: 构造方法注入代理的接口*/public LoveProxy(Love love){target=love;}@Overridepublic void marray(){System.out.println("要彩礼10万");target.marray();System.out.println("不能家暴");}public static void main(String[] args) {//实际应用:代理的应用Love love=new LoveImpl();LoveProxy proxy=new LoveProxy(love);proxy.marray();}}

效果:在以前的需求上扩展了功能

要彩礼10万
我同意
不能家暴

1.4.4 动态代理

静态代理:通过手动编写代理类来实现,需要为每个目标对象编写一个代理类。
动态代理:通过Java提供的相关接口和类,在运行时动态生成代理类,无需手动编写代理类。

我们仍然先定义了接口,但是我们并不去编写实现类,而是直接通过JDK提供的一个Proxy.newProxyInstance()创建了一个Hello接口对象。这种没有实现类但是在运行期动态创建了一个接口对象的方式,我们称为动态代码。JDK提供的动态创建接口对象的方式,就叫动态代理。

动态代理三个重要的java类

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/241221.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

评论回复功能数据库设计

1. 评论的场景 类似csdn博客评论 2. 建表sql CREATE TABLE comment (id varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT id,parent_id varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT 父级评论id&#xff08;…

Kubernetes pod ip 暴露

1. k8s pod 和 service 网络暴露 借助 iptables 的路由转发功能&#xff0c;打通k8s集群内的pod和service网络&#xff0c;与外部网络联通 # 查看集群的 pod 网段和 service 网段 kubectl -n kube-system describe cm kubeadm-config networking:dnsDomain: cluster.localpod…

Vue2和Vue3组件间通信方式汇总(2)------$emit

组件间通信方式是前端必不可少的知识点&#xff0c;前端开发经常会遇到组件间通信的情况&#xff0c;而且也是前端开发面试常问的知识点之一。接下来开始组件间通信方式第二弹------$emit,并讲讲分别在Vue2、Vue3中的表现。 Vue2Vue3组件间通信方式汇总&#xff08;1&#xff0…

JavaEE进阶学习:Spring MVC 程序开发

1.什么是 Spring MVC Spring Web MVC 是基于Servlet API 构建的原始 Web 框架&#xff0c;从一开始就包含在Spring 框架中。它的正式名称 “Spring Web MVC” 来自其源模块的名称(Spring-webmvc)&#xff0c;但它通常被称为“Spring MVC”。 从上述定义我们可以得出两个关键信…

如何改善与 Next Paint (INP) 的交互

但谷歌也会关注访问者到达后你的网站体验有多好。 在过去的几年里&#xff0c;谷歌已经彻底改变了哪些页面体验信号被收集并用作排名因素。 在引入核心网络指标后&#xff0c;谷歌逐渐调整了它们的衡量方式&#xff0c;以便更好地反映真实的用户体验。 然而&#xff0c;随着…

Unity中获取时间戳、日期、时间、毫秒、秒以相互转换、自定义格式时间

Unity中获取时间戳、日期、时间、毫秒、秒以相互转换、自定义格式时间 介绍时间戳是什么什么时候用时间戳 获取时间获取当前时间获取时间戳日期转时间戳时间戳转日期将时间戳转换为多久之前星期自定义格式时间 总结 介绍 这里附带一个时间戳和时间转换的网址 时间戳是什么 时…

【Spring实战】01 配置单数据源

文章目录 1. 定义2. 准备3. 打印连接信息4. 实战1&#xff09;创建表2&#xff09;添加数据3&#xff09;查询数据3&#xff09;执行 5. 详细代码总结 在我们常见的应用程序中&#xff0c;与数据库的交互是不可避免的一部分。Spring 提供了简单而强大的数据访问抽象&#xff0c…

九州金榜|家庭教育幼小衔接家长如何做?

孩子从幼儿园升入小学&#xff0c;很多家长会非常忧虑&#xff0c;进入小学便是孩子学校生涯正式开始&#xff0c;这个阶段作为家长会非常焦虑&#xff0c;会考虑孩子能不能适应小学生活&#xff1f;学习跟不跟得上&#xff0c;一般这个时候&#xff0c;大部分家长就会考虑给孩…

数值分析期末复习

第一章 科学计算 误差 解题步骤 先求绝对误差: ∣ x − x ∗ ∣ |x - x^*| ∣x−x∗∣求相对误差限: ∣ x − x ∗ ∣ x ∗ \frac{|x\,\,-\,\,x^*|}{x^*} x∗∣x−x∗∣​求有效数字 ∣ x − x ∗ ∣ 需要小于它自身的半个单位 |x-x^*|\text{需要小于它自身的半个单位} ∣…

Python入门学习篇(六)——for循环while循环

1 for循环 1.1 常规for循环 1.1.1 语法结构 for 变量名 in 可迭代对象:# 遍历对象时执行的代码 else:# 当for循环全部正常运行完(没有报错和执行break)后执行的代码1.1.2 示例代码 print("----->学生检查系统<------") student_lists["张三",&qu…

MLX vs MPS vs CUDA:苹果新机器学习框架的基准测试

如果你是一个Mac用户和一个深度学习爱好者&#xff0c;你可能希望在某些时候Mac可以处理一些重型模型。苹果刚刚发布了MLX&#xff0c;一个在苹果芯片上高效运行机器学习模型的框架。 最近在PyTorch 1.12中引入MPS后端已经是一个大胆的步骤&#xff0c;但随着MLX的宣布&#x…

在Excel中,如何简单快速地删除重复项,这里提供详细步骤

当你在Microsoft Excel中使用电子表格时&#xff0c;意外地复制了行&#xff0c;或者如果你正在制作其他几个电子表格的合成电子表格&#xff0c;你将遇到需要删除的重复行。这可能是一项非常无脑、重复、耗时的任务&#xff0c;但有几个技巧可以让它变得更简单。 删除重复项 …

Android Canvas画布saveLayer与对应restoreToCount,Kotlin

Android Canvas画布saveLayer与对应restoreToCount&#xff0c;Kotlin private fun mydraw() {val originBmp BitmapFactory.decodeResource(resources, R.mipmap.pic).copy(Bitmap.Config.ARGB_8888, true)val newBmp Bitmap.createBitmap(originBmp.width, originBmp.heigh…

【Win10安装Qt6.3】安装教程_保姆级

前言 Windows系统安装Qt4及Qt5.12之前版本和安装Qt.12之后及Qt6方法是不同的 &#xff1b;因为之前的版本提供的有安装包&#xff0c;直接一路点击Next就Ok了。但Qt5.12版本之后&#xff0c;Qt公司就不再提供安装包了&#xff0c;不论是社区版&#xff0c;专业版等&#xff0c…

并发控制工具类CountDownLatch、CyclicBarrier、Semaphore

并发控制工具类CountDownLatch、CyclicBarrier、Semaphore 1.CountDownLatch 可以使一个或多个线程等待其他线程各自执行完毕后再执行。 CountDownLatch 是多线程控制的一种工具&#xff0c;它被称为 门阀、 计数器或者闭锁。这个工具经常用来用来协调多个线程之间的同步&…

项目从vue2 升级vue3,项目大迁移 ,UI组件库更换

目录 背景描述 开发准备 第一步&#xff1a;升级环境 第二步&#xff1a;划分功能迁移顺序 第三步&#xff1a;详细了解需要迁移的业务页面 第四步&#xff1a;项目的一些配置的准备 详细开发流程 总结/分析&#xff1a; 背景描述 之前的版本&#xff1a;vue 2.6.8 i…

【PHY6222】绑定详解

1.函数详解 bStatus_t GAPBondMgr_SetParameter( uint16 param, uint8 len, void* pValue ) 设置绑定参数。 bStatus_t GAPBondMgr_GetParameter( uint16 param, void* pValue ) 获取绑定参数。 param&#xff1a; GAPBOND_PAIRING_MODE&#xff0c;配对模式&#xff0c;…

【postgres】8、Range 类型

文章目录 8.17 Range 类型8.17.1 内置类型8.17.2 示例8.17.3 开闭区间8.17.4 无穷区间 https://www.postgresql.org/docs/current/rangetypes.html 8.17 Range 类型 Range 类型&#xff0c;可以描述一个数据区间&#xff0c;有明确的子类型&#xff0c;而且子类型应该能被排序…

计算机网络——数据链路层(三)

前言: 前面我们已经对计算机网络的物理层有了一个大概的了解&#xff0c;今天我们学习的是物理层服务的上一层数据链路层&#xff0c;位于物理层和网络层之间。数据链路层在物理层提供的服务的基础上向网络层提供服务&#xff0c;其最基本的服务是将源自物理层来的数据可靠地传…

Mac使用Vmware Fusion虚拟机配置静态ip地址

一、设置虚拟机的网络为NAT 二、修改虚拟机的网络适配器网络 1、查看虚拟机的网卡 cd /etc/sysconfig/network-scripts#有些系统显示的是ens33&#xff0c;ens160等等 #不同的系统和版本&#xff0c;都会有所不同 #Centos8中默认是ens160,在RedHat/Centos7则为ens33 2、查看网…