当前位置: 首页 > wzjs >正文

公司网站建设价格贵吗数据分析师

公司网站建设价格贵吗,数据分析师,中央气象台卫星云图,做商城网站一般用什么java反射机制是java语言的核心特性之一,允许程序在运行时动态获取类的内部信息并操作其成员。其核心在于绕过编译时的静态检查,实现动态加载和类结构探知的能力。 反射的优点: 1、动态性与灵活性 1.1) 运行时类操作 反射可以在运行时动态加…

        java反射机制是java语言的核心特性之一,允许程序在运行时动态获取类的内部信息并操作其成员。其核心在于绕过编译时的静态检查,实现动态加载和类结构探知的能力。

反射的优点:

1、动态性与灵活性

1.1) 运行时类操作

       反射可以在运行时动态加载类、创建对象、调用方法、访问字段,无需在编译时确定具体类型。比如下面的例子

       我们先定义一个Student类,类中成员变量包括如下信息

package com.test.demo;public class Student {private String name;private int age;public String address;public Student(String name, int age, String address) {this.name = name;this.age = age;this.address = address;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public String getAddress() {return address;}public void setAddress(String address) {this.address = address;}private void eat(String name) {System.out.println(name + "在吃饭");}private void eat(String name, int age) {System.out.println("姓名:"name + ", 年龄:" + age + ", 正在吃饭";}
}

        下面是获取字节码Class对象的三种方式 

//方法一:通过全类名我们就可以获取这个类的Class对象,这个在编译阶段就可以拿到Class对象
Class<?> clazz = Class.forName("com.test.demo.Student");
//另外获取Class对象还有另外两种方法
//方法二: 直接通过类名.class来获取,这个在加载阶段可以拿到Class对象
Class<?> clazz2 = Student.class;
//方法三:先实例化Student的一个实例对象,然后通过实例对象的getClass()方法获取Class对象,这个是在运行阶段
Student stu = new Student();
Class<?> clazz3 = stu.getClass();

        下面是通过反射获取构造方法的例子,如下:

//拿到clazz之后,就可以通过clazz.getDeclaredConstructor()获取类的无参构造方法,获取构造方法有好几个方式: 
//clazz.getDeclaredConstructors()可以获取类中所有的构造方法(包括public修饰的也包括其它类型修饰的,比如protected、private等);
//clazz.getConstructors()可以获取类中所有public修饰的构造方法。
//我们还可以通过指定参数类型来获取指定的一个构造方法,比如clazz.getDeclaredConstructor(String.class)这个就是获取只有一个String类型入参的构造方法
//在拿到构造方法后,我们就可以通过构造方法获取类的一个实例,如下所示
Constructor<?> constructor = clazz.getDeclaredConstructor();
Object student = constructor.newInstance();
//那如果我们获取到的构造方法是个private修饰的构造方法的话,我们要创建实例对象还得加一步,就是设置构造方法可以被访问,代码如下所示
Constructor<?> constructor = clazz.getDeclaredConstructor(String.class);
constructor.setAccessible(true);
Object student = constructor.newInstance();

         下面是通过反射获取字段和修改字段的例子,如下:

//接下来就是获取类的成员变量,如下所示,这个是获取所有用public修饰的成员变量
Field[] fields = clazz.getFields();
//如果要获取全部修饰符修饰的成员变量(public、protected、private等),那么可以通过如下方法获取,如下所示
Field[] fields = clazz.getDeclaredFields();
//如果只想获取某个指定的成员变量,那么可以通过指定字段名称来获取,比如我们的Student类中有个用private修饰的name成员变量,那么可以通过如下方式获取
Field name = clazz.getDeclaredField("name");
//如果我们想要获取这个name成员变量的值,需要先实例化一个Student对象
Student student = new Student("zhangsan", 23, "河北保定");
//然后通过name.get(obj)的方式获取成员变量name的值
Object value = name.get(student);
//打印成员变量
System.out.println(value);
//如果我们运行上面打印value的动作发现报异常了,说是没有权限访问私有成员变量的值。那么我们如何获取这个成员变量的值呢,跟上面构造方法的处理一样,我们给Field对象设置访问权限即可,代码如下Student student = new Student("zhangsan", 23, "河北邯郸");name.setAccessible(true);Object value = name.get(student);System.out.println(value);

        下面是通过反射获取成员方法和调用成员方法的例子,如下:

//接下来就是获取成员方法
//获取成员方法与获取成员变量稍有不同,通过clazz.getMethods()获取的不仅包含当前类的成员方法,还包含了父类的成员方法
Method[] methods = clazz.getMethods();
//那如果我们只想要当前类的成员方法,那么使用getDeclaredMethods方法来获取
Method[] methods = clazz.getDeclaredMethods();
//如果只想获取单个成员方法,那么我们可以通过成员方法名+参数类型的方式来获取,比如我们上面Student类中有两个私有的eat方法,两个eat方法参数不同,假如我们想要获取那个只有一个String类型参数的方法,那么就可以通过如下方式获取
Method eatMethod = clazz.getDeclaredMethod("eat", String.class);
//如果想获取有两个参数的eat方法,我们可以通过如下方式获取
Method eatMethod = clazz.getDeclaredMethod("eat", String.class, int.class);
//拿到method之后,我们还可以获取方法的参数
Parameter[] parameters = eatMethod.getParameters();
//还可以获取方法抛出的异常
Class<?>[] exceptionTypes = eatMethod.getExceptionTypes();
//最重要的是方法的执行,也就是invoke
//invoke主要包含两个入参以及返回值处理。第一个参数是obj对象,也就是我们实例化出来的实例对象,第二个参数是调用方法传递的参数。对于返回值要根据方法具体的情况来定,如果有返回值那么我们可以用一个Object对象来接收返回值,如果没有返回值,则我们不用接收即可。假如我们想要给有两个参数的eat方法设置新的参数值,然后执行一下eat方法查看打印的信息(由于eat方法是私有的,因此要执行的话必须先给eatMethod设置访问权限eatMethod.setAccessible(true)才可以)这样就可以打印出我们指定参数的执行日志了
Student student = new Student("zhangsan", 23, "河北邯郸");
Method eatMethod = clazz.getDeclaredMethod("eat", String.class, int.class); eatMethod.setAccessible(true);
eatMethod.invoke(student, "lisi", 20);
1.2)支持框架和库的开发

       反射是许多框架,比如Spring、Hibernate、Junit等的核心机制,实现依赖注入、动态代理、注解解析等。

      依赖注入的核心原理:

依赖注入的核心目标:将对象的创建和依赖关系的管理从代码中解耦。

通过反射实现依赖注入的关键步骤:

1)扫描类路径:找到需要被管理的类(如标记了特定注解的类)

2)实例化对象:通过反射创建对象。

3)递归解析依赖:检查对象的字段或构造方法,自动注入依赖的其他对象。

4)管理单例:确保同一类只被实例化一次(可选)

下面用最简单的代码来手写一个依赖注入的案例

步骤一:定义注解

       Component注解上面@Target(ElementType.TYPE)的意思是它作用于接口、类、枚举、注解。而Autowired注解上面@Target(ElementType.FIELD)的意思是它作用于字段

       @Retention包含如下几种类型

1)RetentionPolicy.SOURCE 这种类型的Annotations只在源代码级别保留,当java文件编译成class文件的时候注解被遗弃。

2)RetentionPolicy.CLASS 这种类型的注解会被保留到class文件,但jvm加载class文件的时候被遗弃,这是默认的生命周期。

3)RetentionPolicy.RUNNING 这种类型的注解不仅被保留到class文件中,jvm加载class文件之后依然保留。

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Component {
}@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Autowired {
}

 步骤二:下面我们模拟实现一个容器

public class DIContainer {//存储单例对象的容器(key是类名 value是实例)private final Map<String, Object> singletonMap = new ConcurrentHashMap<>();//扫描指定包并初始化所有Component类public void scan(String basePackage) throws Exception {//通过类路径扫描获取所有类(此处简化,实际需要实现类扫描逻辑)Set<Class<?>> classes = findClass(basePackage);for (Class<?> clazz : classes) {if (clazz.isAnnotationPresent(Component.class)) {//创建实例并注入依赖Object instance = createInstance(clazz);singletonMap.put(clazz.getName(), instance);}}}//创建对象并注入依赖private Object createInstance(Class<?> clazz) throws Exception {//1.通过无参构造方法创建实例Object instance = clazz.getDeclaredConstructor().newInstance();//2.注入字段依赖for (Field field : clazz.getDeclaredFields()) {//检查字段上是否添加了@Autowired注解if (field.isAnnotationPresent(Autowired.class)) {//获取字段类型对应的实现类(此处简化,实际需处理接口和实现类映射)Class<?> fieldType = field.getType();Object dependency = getOrCreateBean(fieldType);//突破private限制并注入值field.setAccessible(true);field.set(instance, dependency);}}return instance;}//获取或创建Bean(支持单例)private Object getOrCreateBean(Class<?> type) throws Exception {//查找已存在的实例Object bean = singletonMap.get(type.getName());if (bean != null) {return bean;}//创建新实例并递归注入依赖bean = createInstance(type);singletonMap.put(type.getName(), bean);return bean;}//获取Beanpublic <T> getBean(Class<?> type) {return (T) singletonMap.get(type.getName));}//模拟类扫描(实际需使用类加载遍历包路径)private Set<Class<?>> findClasses(String basePackage) {//示例直接返回预设类型(实际需实现扫描逻辑)Set<Class<?>> classes = new HashSet<>();classes.add(UserService.class);classes.add(UserRepository.class);return classes;}
}

步骤三:定义被管理的类

@Component
public class UserService {@Autowiredprivate UserRepository userRepository;public void saveUser(String user) {userRepository.save(user);}
}@Component
public class UserRepository {public void save(String user) {System.out.println("保存用户:" + user);}
}

步骤四:使用容器

public class Test1 {public static void main(String[] args) throws Exception {DIContainer container = new DIContainer();container.scan("com.example");UserService userService = container.getBean(UserService.class);userService.saveUser("zhangsan");}
}

        关键点解析:

1)类扫描与实例化

        通过反射查找所有标记了@Component的类,并递归创建他们的实例。

2)依赖注入

        检查@Autowired注解的字段,动态注入已创建的依赖对象。

3)单例管理

        使用Map缓存实例,确保每个类只有一个实例。

4)简化假设

        假设@Autowired字段的类型有且仅有一个实现类。

        实际框架(如Spring)会处理接口与实现类的映射、构造方法注入、循环依赖等问题。

        反射在依赖注入中的作用

1)动态创建对象

        通过clazz.newInstance()或构造方法反射创建对象。

2)访问私有字段

        通过field.setAccessible(true)突破访问权限,注入依赖。

3)递归解析依赖

        检查字段类型,递归创建并注入依赖的Bean

2、突破访问权限

        反射可以绕过修饰符比如private、protected的限制,强制访问或修改类的私有属性和方法。

        反射是实现动态代理的基础,支持面向切面编程(AOP)。

3、通用工具开发

        3.1) 通用序列化和反序列化

        反射可以用于实现通用的JSON、XML序列化工具,如Jackson、Gson

        3.2) 调试和监控

        通过反射获取类的元数据,用于调试工具或性能监控。

反射的缺点如下:

1、性能开销

        运行效率低:反射操作需要JVM在运行时动态解析类信息,涉及方法调用、字段访问的权限检查等,性能显著低于直接代码调用。

        JIT优化受限:反射调用的代码难以被JIT编译器优化,尤其是在高频调用时可能成为性能瓶颈。

2、安全隐患

        破坏封装性:反射可以强制访问私有成员,破坏类的封装性,可能导致数据不一致或安全漏洞。

        权限管理绕过:通过反射调用setAccessible(true)可以绕过安全管理器的检查(SecurityManager),威胁系统安全。

3、代码可维护性差

        可读性差:反射代码通常冗长且难以理解,IDE难以提供代码提示和重构支持。

        编译时检查缺失:反射调用的方法或字段在编译时无法检查是否存在或类型是否匹配,错误只能在运行时暴露。

4、兼容性问题

        版本敏感性:反射代码依赖于类的内部(如方法名、参数列表、字段名),如果类发生变更(如方法重命名),反射代码会直接失效。

5、反射破坏单例

       本来我们通过双重校验模式获取单例对象只会拿到一个对象实例,但是通过反射的话,就可以调用私有方法,然后通过私有方法创建新的实例对象,这样就破坏了单例模式。

http://www.dtcms.com/wzjs/227066.html

相关文章:

  • 高端网站建设四川产品软文是什么
  • 石岩网站建设 0755太原seo推广
  • 涟水做网站查找网站
  • 如何让网站收录百度seo公司一路火
  • 上海网站建设公司费用搜索百度指数
  • 江苏网站建设官网什么是seo如何进行seo
  • 简单房地产网站在哪seo网站编辑是做什么的
  • wordpress 网页滚轮翻页信息流优化
  • 利用博客做网站搜索引擎网络排名
  • 重庆智能网站建设设计网络营销就是seo正确吗
  • 毕业设计代做网站 知乎百度贴吧网页版登录入口
  • 做网站前需要做什么准备互联网营销师是什么
  • 国家建设人才网站怎么在腾讯地图上添加自己的店铺
  • 怎样买网站建设做网络推广有哪些平台
  • 响应式网站 做搜索推广缺点重庆好的seo平台
  • 浙江疫情又严重了win10系统优化软件
  • 宇讯网站建设长沙官网seo分析
  • 瀑布流响应式网站模板简述网站建设的流程
  • 北京展示型网站推广普通话奋进新征程手抄报
  • 网站如果实现微信支付吗东莞网站seo推广
  • 星月教你做网站松原头条新闻今日新闻最新
  • 什么做网站的公司好报个电脑培训班要多少钱
  • 公共图书馆门户网站建设总结注册公司网站
  • 如何申请自己的个人网站百度推广计划
  • wordpress做阿里巴巴国际站上海百度公司总部
  • 刚成立公司如何做网站dw网站制作
  • 做啊网站关键词小说
  • 秦皇岛网站建设sem推广
  • 易语言做网站登陆绍兴seo排名收费
  • 一个网站需要几个人做百度广告联盟网站