Java高级

1.反射

每个类都有一个唯一的类对象,该对象是 java.lang.Class 类型。【是 Java 类的元数据(metadata)对象,包含了该类的结构信息和其他相关数据】

获取类对象

1.什么是类对象

public class Daughter extends Parent{        }

public class Son extends Parent {        }

Daughter 、Son 都是 parent对象,区别不同的名称,年龄,速度。

Parent 和 Person都是类,区别在于不同方法,不同属性。

类对象,就是描述类有什么属性,什么方法的。

2.获取类对象

3种方式

1. Class.forName(String className)
2. 类名.class
3. getClass() 方法

在一个JVM中,一种类,只会有一个类对象存在。所以以上三种方式取出来的类对象,都是一样的。

 public static void main(String[] args) throws ClassNotFoundException {
        Class<?> clazz = Class.forName("com.test.example.Parent");
        System.out.println(clazz.getName()); //com.test.example.Parent
        Class<Parent> pClass = Parent.class;
        System.out.println(pClass.getName());  //com.test.example.Parent
        Parent pp=new Parent();
        Class<? extends Parent> methordClass = pp.getClass();
        System.out.println(methordClass.getName());  //com.test.example.Parent
    
        System.out.println(clazz ==pClass); //true
}

3.获取类对象的时候,会导致类属性被初始化

为 Parent 类增加一个静态属性,并且在静态初始化块里进行初始化。

        按照2中再次执行。无论什么途径获取类对象,都会导致静态属性被初始化,而且只会执行一次。只会显示  [一句 parent静态代码块!]

(除了直接使用 Class c = Parent.class 这种方式,这种方式不会导致静态属性被初始化)

总结:

        静态代码块初始化就一次!

        类名.class 方式不会执行静态代码块!

创建对象

与传统的new 关键字 来获取对象方式不同

反射机制,先获取Parent 的 类对象,再由 类对象获取构造器对象,然后通过构造器对象创建一个对象。

   try {
            // 类对象
            Class<?> pClass = Class.forName("com.test.example.Parent");
            //构造器
            Constructor pc= pClass.getConstructor();
            //构造器实例化
            Parent parent = (Parent) pc.newInstance();
            System.out.println(parent);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

访问属性

Parent 中 添加两个属性 

private int age; // 私有
public String smart; // 公用
public String getSmart() {
    return this.smart;
}
public int getAge() {
    return this.age;
}

//=================================

try {
    //对象-实例
    Parent pObj=new Parent();
    // 类对象
    Class<?> pClass = pObj.getClass();
    //获取 public 修饰的smart字段
    Field smart = pClass.getField("smart");
    System.out.println(smart.getName());// 字段名
    System.out.println(smart.getType());  // 字段属性
    // 获取private修饰的 age字段
    Field age = pClass.getDeclaredField("age");
    System.out.println(age.getName());
    // 因为age字段属性private set方法赋值会报错。必须setAccessible 赋值为true
    age.setAccessible(true);
    age.set(pObj, 23);
    System.out.println(pObj.getAge());
} catch (Exception e) {
    throw new RuntimeException(e);
}

1.对于private修饰的成员,需要使用setAccessible(true)才能修改。

getField和getDeclaredField的区别

这两个方法都是用于获取字段

getField 只能获取public的,包括从父类继承来的字段。

getDeclaredField 可以获取本类所有的字段,包括private的,但是不能获取继承来的字段

调用方法

Parent 中 添加两个set方法

public void setSmart(String smart) { // 公共
    this.smart = smart;
}

private void setAge(int age) { //私有
    this.age = age;
}

//=====================================================

try {
    //对象-实例
    Parent pObj = new Parent();
    // 类对象
    Class<?> pClass = pObj.getClass();
    //获取 public 修饰的 方法
    Method setSmart = pClass.getMethod("setSmart", String.class);
    //输出setSmart方法的返回值,这里返回 null,因为 setSmart 没有返回值)
    Object obj = setSmart.invoke(pObj, "平凡");
    System.out.println(obj); // null
    System.out.println(pObj.getSmart()); // 平凡
    // private 修饰的方法
    Method ageSet = pClass.getDeclaredMethod("setAge", int.class);
    // 私有 设置可被访问
    ageSet.setAccessible(true);
    ageSet.invoke(pObj, 12);
    System.out.println(pObj.getAge()); // 12
} catch (Exception e) {
    throw new RuntimeException(e);
}

有什么用  [约定优于配置,配置优于实现]

反射非常强大,但是学习了之后,会不知道该如何使用,反而觉得还不如直接调用方法来的直接和方便。
需要学习了Spring 的依赖注入,反转控制之后,才会对反射有更好的理解
简单举例:两个业务类 Service1 + Service2 

public class Service1 {
 
    public void doService1(){
        System.out.println("业务方法1");
    }
}

package reflection;

public class Service2 {

	public void doService2(){
		System.out.println("业务方法2");
	}
}

非反射方式

public class Test {
 
    public static void main(String[] args) {
//      new Service1().doService1();
        new Service2().doService2();
    }
}

        当需要从第一个业务方法切换到第二个业务方法的时候,使用非反射方式,必须修改代码,并且重新编译运行,才可以达到效果

反射方式

准备一个spring.txt文件,里面存类名+ 调用的方法名

class=reflection.Service1    # 类的全名称
method=doService1           #方法名

测试类代码

    @SneakyThrows
    public static void main(String[] args) {

        //从spring.txt中获取类名称和方法名称
        File springConfigFile = new File("e:\\project\\getwork\\spring.txt");
        Properties springConfig = new Properties();
        springConfig.load(new FileInputStream(springConfigFile));
        String className = springConfig.getProperty("class"); // 返回结果只是String
        String methodName = (String) springConfig.get("method"); // 返回结果Object,需要强转

        //根据类名称获取类对象
        Class clazz = Class.forName(className);
        //根据方法名称,获取方法对象
        Method m = clazz.getMethod(methodName);
        //获取构造器
        Constructor c = clazz.getConstructor();
        //根据构造器,实例化出对象
        Object obj = c.newInstance();
        //调用对象的指定方法
        m.invoke(obj);
    }

2.注解

将注解与反射放一起,因为反射用于解析注解中的信息。

基本内置注解

@Override 用在方法上,表示这个方法重写了父类的方法,如toString()。
如果父类没有这个方法,那么就无法编译通过

@Deprecated 表示这个方法已经过期,不建议开发者使用。(暗示在将来某个不确定的版本,就有可能会取消掉)

@SuppressWarnings Suppress英文的意思是抑制的意思,这个注解的用处是忽略警告信息。

比如大家使用集合的时候,有时候为了偷懒,会不写泛型,像这样:
List heros = new ArrayList();

那么就会导致编译器出现警告,而加上

@SuppressWarnings({ "rawtypes", "unused" })  

对这些警告进行了抑制,即忽略掉这些警告信息。

@SuppressWarnings 有常见的值,分别对应如下意思
1.deprecation:使用了不赞成使用的类或方法时的警告(使用@Deprecated使得编译器产生的警告);
2.unchecked:执行了未检查的转换时的警告,例如当使用集合时没有用泛型 (Generics) 来指定集合保存的类型; 关闭编译器警告
3.fallthrough:当 Switch 程序块直接通往下一种情况而没有 Break 时的警告;
4.path:在类路径、源文件路径等中有不存在的路径时的警告;
5.serial:当在可序列化的类上缺少 serialVersionUID 定义时的警告;
6.finally:任何 finally 子句不能正常完成时的警告;
7.rawtypes 泛型类型未指明
8.unused 引用定义了,但是没有被使用
9.all:关于以上所有情况的警告。

@FunctionalInterface这是Java1.8 新增的注解,用于约定函数式接口。
函数式接口概念: 如果接口中只有一个抽象方法(可以包含多个默认方法或多个static方法),该接口称为函数式接口。函数式接口其存在的意义,主要是配合 Lambda表达式来使用。

自定义注解

1.非注解方式DBUtil

通常来讲,在一个基于JDBC开发的项目里,都会有一个DBUtil这么一个类,在这个类里统一提供连接数据库的IP地址,端口,数据库名称, 账号,密码,编码方式等信息。

举个例子:获取一个连接数据库test的连接Connection实例

package util;
  
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
  
public class DBUtil {
    static String ip = "127.0.0.1";
    static int port = 3306;
    static String database = "test";
    static String encoding = "UTF-8";
    static String loginName = "root";
    static String password = "admin";
    static{
        try {
            Class.forName("com.mysql.jdbc.Driver");// 版本8.0之后用 com.mysql.cj.jdbc.Driver
   // 自动加载驱动(对于 Java 6 或更高版本不需要显式加载) 无需这段代码意思
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
  
    public static Connection getConnection() throws SQLException {
        String url = String.format("jdbc:mysql://%s:%d/%s?characterEncoding=%s", ip, port, database, encoding);
        return DriverManager.getConnection(url, loginName, password);
    }
    public static void main(String[] args) throws SQLException {
		System.out.println(getConnection());
	}
}

2.自定义注解@JDBCConfig

创建注解类型不使用class也不使用interface,而是使用@interface

public @interface JDBCConfig

元注解:

@Target({METHOD,TYPE}) 表示这个注解可以用用在类/接口上,还可以用在方法上
@Retention(RetentionPolicy.RUNTIME) 表示这是一个运行时注解,即运行起来之后,才获取注解中的相关信息,而不像基本注解如@Override那种不用运行,在编译时eclipse就可以进行相关工作的编译时注解。
@Inherited 表示这个注解可以被子类继承
@Documented 表示当执行javadoc的时候,本注解会生成相关文档

package anno;

import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.TYPE;

import java.lang.annotation.Documented;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({METHOD,TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface JDBCConfig {
     String ip(); 
     int port() default 3306; 
     String database(); 
     String encoding(); 
     String loginName(); 
     String password(); 
}

3.注解方式DBUtil

有了自定义注解@JDBCConfig之后,我们就把非注解方式DBUtil改造成为注解方式DBUtil。

package util;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

import anno.JDBCConfig;
//相当于赋值
@JDBCConfig(ip = "127.0.0.1", database = "test", encoding = "UTF-8", loginName = "root", password = "admin")
public class DBUtil {
	static {
		try {
			Class.forName("com.mysql.jdbc.Driver");
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
	}



	public static Connection getConnection() throws SQLException, NoSuchMethodException, SecurityException {
 // 相当于解析  取值
 // 通过反射,获取这个DBUtil这个类上的注解对象
		JDBCConfig config = DBUtil.class.getAnnotation(JDBCConfig.class);

		String ip = config.ip();
		int port = config.port();
		String database = config.database();
		String encoding = config.encoding();
		String loginName = config.loginName();
		String password = config.password();

		String url = String.format("jdbc:mysql://%s:%d/%s?characterEncoding=%s", ip, port, database, encoding);
		return DriverManager.getConnection(url, loginName, password);
	}
	
	public static void main(String[] args) throws NoSuchMethodException, SecurityException, SQLException {
		Connection c = getConnection();
		System.out.println(c);
	}
}

元注解

 元数据在英语中对应单词 metadata:解释为【为其他数据提供信息的数据】

这样元注解就好理解了,元注解 meta annotation用于注解 自定义注解 的注解。
元注解有这么几种:
@Target
@Retention
@Inherited
@Documented
@Repeatable (java1.8 新增)

@Target 表示注解的位置
可以选择的位置列表如下:
ElementType.TYPE:能修饰类、接口或枚举类型
ElementType.FIELD:能修饰成员变量
ElementType.METHOD:能修饰方法
ElementType.PARAMETER:能修饰参数
ElementType.CONSTRUCTOR:能修饰构造器
ElementType.LOCAL_VARIABLE:能修饰局部变量
ElementType.ANNOTATION_TYPE:能修饰注解
ElementType.PACKAGE:能修饰包

@Retention  表示生命周期
RetentionPolicy.SOURCE: 注解只在源代码中存在,编译成class之后,就没了。@Override 就是这种注解。
RetentionPolicy.CLASS: 注解在java文件编程成.class文件后,依然存在,但是运行起来后就没了。@Retention的默认值,即当没有显式指定@Retention的时候,就会是这种类型。
RetentionPolicy.RUNTIME: 注解在运行起来之后依然存在,程序可以通过反射获取这些信息,自定义注解@JDBCConfig 就是这样。

@Inherited 表示该注解具有继承性。

@Documented  在用javadoc命令生成API文档后,DBUtil的文档里会出现该注解说明

@Repeatable 是 Java 8 引入的一个注解,允许你在同一个元素(类、方法、字段等)上使用多个相同类型的注解

@Repeatable 注解是一个元注解,它标注在容器注解上,容器注解是用来包裹重复的注解的。

1. 创建重复注解

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

// 定义一个重复注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Repeatable(Supervisors.class)  // 使用 @Repeatable 注解指定容器注解
public @interface Supervisor {
    String value();
}

2. 创建容器注解

容器注解是用来存储多个相同类型注解的注解。它必须使用 @interface 定义,并且使用 @Repeatable 来标注。

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Supervisors {
    Supervisor[] value();  // 容器注解内部包含多个 Supervisor 注解
}

3. 使用重复注解

public class Employee {

    @Supervisor("Alice")
    @Supervisor("Bob")
    public void work() {
        System.out.println("Working...");
    }
}

4. 访问重复注解

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

public class Test {

    public static void main(String[] args) throws Exception {
        Method method = Employee.class.getMethod("work");

        // 获取所有 Supervisor 注解
        Supervisor[] supervisors = method.getAnnotationsByType(Supervisor.class);

        // 输出注解的值
        for (Supervisor supervisor : supervisors) {
            System.out.println(supervisor.value());
        }
    }
}

3.hutool

在大家日常工作中,都常常会做如下这些非常繁琐的工作:
日期与字符串转换
文件操作
转码与反转码
随机数生成
压缩与解压
编码与解码
CVS文件操作
缓存处理
加密解密
定时任务
邮件收发
二维码创建
FTP 上传与下载
图形验证码生成
等等等等

工欲善其事必先利其器! Hutool 就是这么一款超级强力的工具类。

任何第三方jar包先导进项目,才能使用。

编码工具

public static void main(String[] args) {
        // 16进制工具
        String encodeStrs = HexUtil.encodeHexStr("nihao明天!");
        System.out.println(encodeStrs);
        String decodeStr = HexUtil.decodeHexStr(encodeStrs);
        System.out.println(decodeStr);

        //转义工具
        String s1 = "<script>location.href='http://baidu.com';</script>";
        String s2 = EscapeUtil.escapeHtml4(s1);//转义
        String s3 = EscapeUtil.unescapeHtml4(s2); // 反转

        //hash工具 import cn.hutool.core.util.HashUtil;

        //URL工具
        URL url = URLUtil.toUrlForHttp("http:/www.baidu.com");
        System.out.println(url);
        String url2 = "https://blog.csdn.net/weixin_43543654/article/details/130481664";
        String urle = URLUtil.encode(url2);
        String urld = URLUtil.decode(urle);
        System.out.println(urle);
        System.out.println(urld);

        //Base32_64 转换
        String charset = "utf-8";
        String content = "模拟课程java教程";
        
        String code32 = Base32.encode(content, charset); //编码
        content = Base32.decodeStr(code32, charset); // 解码

        String code64 = Base64.encode(content, charset);  //64 编码
        content = Base64.decodeStr(code64, charset);   // 64解码

}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

HarmonyOS NEXT 实战之元服务:静态案例效果---我的热门应用服务

背景&#xff1a; 前几篇学习了元服务&#xff0c;后面几期就让我们开发简单的元服务吧&#xff0c;里面丰富的内容大家自己加&#xff0c;本期案例 仅供参考 先上本期效果图 &#xff0c;里面图片自行替换 效果图1完整代码案例如下&#xff1a; Index import { authentica…

libvirt学习

文章目录 libvirt 简介节点、Hypervisor和域libvirt 安装和配置libvirt的XML配置文件libvirt APIMain libvirt APIsError handlingSpecial specific APIs 建立到Hypervisor的连接libvirt API使用编译libvirt工具virshvirt-clonevirt-dfvirt-imagevirt-installvirt-topvirt-what…

“进制转换”公式大集合

咱们都知道十进制是“逢10进1 ”&#xff0c;同理&#xff0c;N进制就是 “逢N进1”。进制其实就这么简单。它的麻烦之处在于各种进制之间的转换。 一、十进制整数转N进制 1&#xff0e;十进制转二进制 除2取余法&#xff1a;连续除以2&#xff0c;直到商为0&#xff0c;逆序…

线程-3-线程控制

线程资源共享 线程间绝大部分资源都是共享的&#xff08;堆栈共享区&#xff09; 线程间堆空间是共享的 谁拿着堆空间的入口地址&#xff0c;谁就能访问 共享区也是共享的&#xff08;cout&#xff0c;printf库都在共享区&#xff09; 线程间有权限访问/修改其他线程栈数据&…

1、ELK的架构和安装

ELK简介 elk&#xff1a;elasticsearch logstash kibana&#xff0c;统一日志收集系统。 elasticsearch&#xff1a;分布式的全文索引引擎的非关系数据库&#xff0c;json格式&#xff0c;在elk中存储所有的日志信息&#xff0c;架构有主和从&#xff0c;最少需要2台。 …

MetaRename for Mac,适用于 Mac 的文件批量重命名工具

在处理大量文件时&#xff0c;为每个文件手动重命名既耗时又容易出错。对于摄影师、设计师、开发人员等需要频繁处理和整理文件的专业人士来说&#xff0c;找到一款能够简化这一过程的工具是至关重要的。MetaRename for Mac 就是这样一款旨在提高工作效率的应用程序&#xff0c…

方正畅享全媒体新闻采编系统 imageProxy.do 任意文件读取漏洞复现

0x01 产品简介 方正畅享全媒体新闻生产系统是以内容资产为核心的智能化融合媒体业务平台,融合了报、网、端、微、自媒体分发平台等全渠道内容。该平台由协调指挥调度、数据资源聚合、融合生产、全渠道发布、智能传播分析、融合考核等多个平台组成,贯穿新闻生产策、采、编、发…

【Unity3d】C#浮点数丢失精度问题

一、float、double浮点数丢失精度问题 Unity3D研究院之被坑了的浮点数的精度&#xff08;一百零三&#xff09; | 雨松MOMO程序研究院 https://segmentfault.com/a/1190000041768195?sortnewest 浮点数丢失精度问题是由于大部分浮点数在IEEE754规范下就是无法准确以二进制…

Flink CDC 自定义函数处理 SQLServer XML类型数据 映射 doris json字段方案

Flink CDC 自定义函数处理 SQLServer XML类型数据方案 1. 背景 因业务使用SQLServer数据库&#xff0c;CDC同步到doris 数仓。对于SQLServer xml类型&#xff0c;doris没有相应的字段对应&#xff0c; 可以使用json来存储xml数据。需要进行一步转换。从 flink 自定义函数入手…

详解云桌面3种主流架构

本文简要介绍下云桌面&#xff08;云电脑&#xff09;的3种主流架构&#xff1a;VDI、IDV和VOI&#xff0c;概念、原理和区别&#xff0c;欢迎阅读。 云桌面作为桌面办公和云计算融合发展的产物&#xff0c;在一定程度上替代了传统的办公形式。目前阿里云、华为云、移动云、电…

按照人们阅读Excel习惯来格式化BigDecimal

1、环境/问题描述 使用springboot发送邮件(附件)的方式将月度报表发送给领导查阅&#xff0c;数据是准确的&#xff0c;领导基本满意。 就是对一些数字的格式化提出了改进建议&#xff0c;比如不要让大数字自动转为科学计数法、浮点数小数点后都是0就不要带出来&#xff0c;根…

深入解析:谱分解、SVD与PCA在算法中的应用与实现

特征值分解&#xff08;EVD&#xff09;、奇异值分解&#xff08;SVD&#xff09;和主成分分析&#xff08;PCA&#xff09;是矩阵分解技术的三种重要形式&#xff0c;它们在人工智能中扮演了关键角色。随着数据维度的快速增长和信息复杂度的提升&#xff0c;这些技术为处理高维…

连接Milvus

连接到Milvus 验证Milvus服务器正在侦听哪个本地端口。将容器名称替换为您自己的名称。 docker port milvus-standalone 19530/tcp docker port milvus-standalone 2379/tcp docker port milvus-standalone 192.168.1.242:9091/api/v1/health 使用浏览器访问连接地址htt…

记录一个我在idea启动时的报错

这几天我的idea突然就不能用了我就想着下一个新的&#xff0c;但是却一直报错报错内容如下 这个是我在网上截的pycharm的。 我在网上查了很多方法都不能用&#xff0c;今天重写安装发现我点了关联.java 和.pom和创建环境变量 这几个只需要创建一个快捷方式就行。我重新安装之…

使用maven-mvnd替换maven大大提升编译打包速度

先上结论&#xff01;&#xff01;&#xff01; 多模块清理并打包提升&#xff1a;约3.5倍 多模块不清理打包提升&#xff1a;约5.5倍 单模块提升&#xff1a;约2倍 从计算结果来看&#xff0c;多模块提升的效率更高。在使用mvnd package打包多模块式&#xff0c;可在控制台…

【从零开始入门unity游戏开发之——C#篇43】C#补充知识——值类型和引用类型汇总补充、变量的生命周期与性能优化、值类型和引用类型组合使用

文章目录 一、值类型和引用类型汇总补充1、值类型和引用类型汇总2、值类型和引用类型的区别3、简单的判断值类型和引用类型 二、变量的生命周期与性能优化1、**栈和堆的区别**2、**变量生命周期**3、**垃圾回收&#xff08;GC&#xff09;机制**4、**代码示例与优化**4.1. 临时…

65.基于SpringBoot + Vue实现的前后端分离-阿博图书馆管理系统(项目 + 论文PPT)

项目介绍 随着社会的发展&#xff0c;计算机的优势和普及使得阿博图书馆管理系统的开发成为必需。阿博图书馆管理系统主要是借助计算机&#xff0c;通过对图书借阅等信息进行管理。减少管理员的工作&#xff0c;同时也方便广大用户对所需图书借阅信息的及时查询以及管理。 本站…

系统报错:由于找不到msvcp140.dll msvcp140_1.dll无法继续执行问题解决

Java资深小白&#xff0c;不足之处&#xff0c;或者有任何错误欢迎指出。 --蓝紫电脑重装后安装mysql&#xff0c;在执行时mysqld -install时出现系统报错:由于找不到msvcp140.dll无法继续执行、由于找不到msvcp140_1.dll无法继续执行。 尝试了其他博主提出的解决方案要么无效…

【再谈设计模式】策略模式 ~ 算法与行为的灵活调度员

本章内容思维导图&#xff1a; ​ 一、引言 在软件工程&#xff0c;软件开发过程中&#xff0c;我们常常会遇到这样的情况&#xff1a;需要根据不同的条件或者用户输入来执行不同的算法或者操作流程。例如&#xff0c;在一个电商系统中&#xff0c;根据用户的会员等级&#xff…

019-spring-基于aop的事务控制原理

1、事务配置&#xff1a; <tx:annotation-driven transaction-manager"transactionManager"/> transaction-manager 默认是找这个bean&#xff1a;transactionManager 2、从命名空间开始找到对应的解析配置如下&#xff1a; 对应的是这个 后续跟源码没有搞明…