【Java技术专题】「攻破技术盲区」带你攻破你很可能存在的Java技术盲点之技术功底指南(鲜为人知的技术)

news2025/1/11 5:51:51

带你攻破你很可能存在的Java技术盲点之技术功底指南

  • 基本类型的包装类
    • 技术盲点:基本类型的比较
    • 技术盲点:字符串内部化(string interning)
      • 字符串内部化的示例
    • 技术盲点:类型缓存机制(空间换时间)
      • String、Short和int、Byte等类型的扩展机制
      • valueOf方法的缓存触发
      • 使用了内部缓存的示例
        • Integer 类的内部化的示例
      • 调整内部缓存范围
  • 进程使用技术实战
    • 技术盲点:进程输入输出
    • 技术盲点:ProcessBuilder处理进程
      • 创建进程
      • 进程的输入和输出的继承式处理方式
        • 继承方式
          • redirectOutput(Redirect.INHERIT)的方式
        • 文件方式
  • Thread类的特性分析
    • 技术盲点:Thread是否可以clone以及参数校验
    • 技术盲点:Thread的线程的注意要点
  • Objects对象操作
    • Objects的compare方法
      • Objects 类的 compare 方法的使用示例
      • 集合的排序
    • Objects的equals方法
      • Objects的equals的判断逻辑
      • Objects的deepEquals的判断逻辑
      • Objects 类的 equals 方法的使用示例
    • Objects的hashCode 方法
      • Objects 类的 hash 和 hashCode 方法的使用示例
    • Objects的toString方法
      • Objects 类的 toString 方法的使用示例

Java.lang包经常进行更新,主要涉及基本类型的包装类、进程管理和线程类。本章节内容的主要要点和方向:
在这里插入图片描述

基本类型的包装类

技术盲点:基本类型的比较

通常对于基本类型的比较我们都是用的是 == 或者 equals方法进行处理,但是在基本类型的比较方面,Boolean、Byte、Short、Integer、Long 和 Character 类都添加了一个静态 compare 方法,用于比较两个基本类型值的大小。

例如,Long 类的 compare 方法可以用来比较两个 long 类型的值。这个 compare 方法主要作为“语法糖”存在,可以简化进行基本类型数值比较时的代码。

如果需要对两个 int 数值 x 和 y 进行比较,一般的做法是使用代码“Integer.valueOf(x).compareTo(Integer.valueOf(y))”,而其实可以直接使用“Integer.compare(x, y)”来实现同样的功能。

技术盲点:字符串内部化(string interning)

对于字符串内部化(string interning)技术,开发人员可能并不陌生。采用这种技术是常见的优化策略,可以提高字符串比较时的性能,是一种典型的空间换时间的做法。而 Java 也采用了这种技术

在 Java 中,包含相同字符的字符串字面量引用的是相同的内部对象。此外,String 类还提供了 intern 方法,用于返回与当前字符串内容相同但已经被包含在内部缓存中的对象引用。当对被内部缓存的字符串进行比较时,可以直接使用“==”操作符,而无需使用更加耗时的 equals 方法。

字符串内部化的示例

public void stringIntern() {
	boolean test1= "test" == "test";
	boolean test2= (new String("test") == "test");
	boolean test3= (new String("test").intern() == "test");
}
  • 第一个字符串比较的结果为 true
  • 第二个字符串比较的结果为 false
  • 第三个字符串比较的结果为 true。

如果使用 equals 方法来进行第二个字符串的比较,结果也会是 true。

技术盲点:类型缓存机制(空间换时间)

String、Short和int、Byte等类型的扩展机制

根据Java语言规范,Java将字符串内部化机制扩展到了 -128 到 127 之间的数字。对于short类型和 int 类型在 -128 到 127 范围内的值,以及 char 类型在 \u0000 到 \u007f 范围内的值,它们对应的包装类对象始终指向相同的对象。因此,当通过“==”进行判断时,结果一定是 true。

valueOf方法的缓存触发

为了满足这个要求,Byte、Short 和 Integer 类的 valueOf 方法会对 -128 到 127 范围内的值进行内部缓存。而对于 Character 类,valueOf 方法会对 0 到 127 范围内的值进行内部缓存。

使用了内部缓存的示例

Integer 类的内部化的示例

public void numberCache() {
	boolean value1 = Integer.valueOf(3) == Integer.valueOf(3);
	boolean value2 = Integer.valueOf(129) == Integer.valueOf(129);
}

由于第一个比较操作的数值在 -128 到 127 之间,所以 Integer 类的 valueOf 方法会返回同一个缓存对象,因此 value1 的值为 true。而第二个比较操作的数值超出了默认的缓存范围,所以 valueOf 方法会返回两个不同的对象,因此 value2 的值为 false。

调整内部缓存范围

如果希望缓存更多的值,可以通过 Java 虚拟机启动参数"java.lang.Integer.IntegerCache.high"进行设置。例如,通过使用"-Djava.lang.Integer.IntegerCache.high=256",可以将数值缓存的范围扩大至-128到256。当重新运行上面的代码时,会发现value2的值变为true,因为129位于修改后的缓存范围内。


进程使用技术实战

Java标准API提供了创建运行于底层操作系统上的进程的能力。只需提供正确的命令和相关参数,即可启动一个进程。启动进程后,Java程序可以向进程输入数据,并读取进程生成的输出数据。

技术盲点:进程输入输出

在Java程序中启动其他进程时,最重要的是处理输入和输出。通常的做法是将Java程序的内部运行结果作为输入传递给新创建的进程,然后等待进程执行完成。在获取进程输出的运行结果后,再继续后续处理。通过这种方式,底层操作系统上的其他进程可以与Java程序很好地集成。对于Java程序来说,进程的输入是通过输出流传递给进程的。程序向输出流中写入的数据会通过管道传递给进程。进程的输出对于Java程序来说是通过输入流获取的。

技术盲点:ProcessBuilder处理进程

通过读取输入流的内容,可以获得进程的输出。标准的创建新进程的过程是使用java.lang.ProcessBuilder类来设置新进程的属性,然后通过start方法来启动进程的执行。

ProcessBuilder类的start方法返回一个表示进程的java.lang.Process类的对象。通过Process类的getOutputStream方法,可以获取用于向进程写入数据的输出流;而通过getInputStreamgetErrorStream方法,可以分别获取包含进程正常执行和出错时输出内容的输入流。

创建进程

下面是一个创建进程的示例代码:

public void startProcessNormal() throws IOException { 
	ProcessBuilder pb = new ProcessBuilder("cmd.exe", "/c", "netstat", "-a"); 
	Process process = pb.start();
	InputStream input = process.getInputStream();
	Files.copy(input, Paths.get("netstat.txt"), StandardCopyOption.REPLACE_EXISTING);
}

以上示例代码展示了如何在Windows上启动命令行工具,并执行"netstat -a"命令,将结果保存到一个文件中。

进程的输入和输出的继承式处理方式

Java又有了两种对于进程的输入和输出的处理方式。

  • 继承方式,即即新创建进程的输入和输出与当前的 Java 进程相同。
  • 文件式,即将文件作为进程的输入来源和输出目的地

继承方式

以下是使用继承方式的示例代码:

ProcessBuilder processBuilder = new ProcessBuilder("cmd.exe", "/c", "dir");
processBuilder.inheritIO();

Process process = processBuilder.start();

int exitCode = process.waitFor();
if (exitCode == 0) {
    System.out.println("进程执行成功");
} else {
    System.out.println("进程执行出错");
}

以上示例代码展示了如何启动一个进程,在Windows上使用命令行工具执行"dir"命令,并通过ProcessBuilder类的inheritIO方法将进程的输出设置为继承自父进程。运行结果会显示在Java程序默认的输出控制台中。

redirectOutput(Redirect.INHERIT)的方式
public void dir() throws IOException  { 
	ProcessBuilder pb =new ProcessBuilder("cmd.exe", "/c", "dir");
	pb.redirectOutput(Redirect.INHERIT);
	pb.start();
}

上面启动的进程通过 Windows 上的命令行工具来执行 dir 命令,通过 ProcessBuilder 类的 redirectOutput 方法把进程的输出
设置为继承自父进程,运行的结果就是 dir 命令的输出内容,会显示在 Java 程序默认的输出控制台中。

文件方式

如果需要将进程的或输出更改为文件,可以使用ProcessBuilder类中的redirectInputOutput方法其他重载形式。下面是基于文件的示例。

public void listProcesses() throws IOException { 
	ProcessBuilder pb = new ProcessBuilder("wmic", "process");
	File output = Paths.get("tasks.txt").toFile();
	pb.redirectOutput(output);
	pb.start();
}

上面展示了如将进的文件中。只需将一个java.io.File类对象作为Output方法的参数即可。这种方式当于管道方式读取输入流获取进程的输出,然后将其写入文件。通过标准API提供方式实现比自己编写实现要更简洁和可靠。


Thread类的特性分析

技术盲点:Thread是否可以clone以及参数校验

  • Thread类的 clone 方法改为始终抛出 NotSupportedException 异常。这因为对 Thread 类对象进行克隆是没有意义的。Java自身显式禁止了对 Thread 类对象的克隆操作。

  • Thread 类的 join 方法和 sleep 方法可以接收一个 long 类型的参数,表示等待的时间。然而,当这个参数值为负数时,并没有定义相应的处理方式。Java规定:如果这两个方法的等待时间参数的值为负数,则会抛出 IllegalArgumentException 异常。

技术盲点:Thread的线程的注意要点

在创建 Thread 类对象时,可以使用的参数包括:表示 Thread 类对象所在线程组的 java.lang.ThreadGroup 类的对象、表示需要运行的任务的 java.lang.Runnable 接口的现对象,以及表示线程名称的 String 类的对象。

  • ThreadGroup:如果传入的 ThreadGroup 类对象为 null,那么会先尝试调用当前配置好的安全管理器(java.lang.SecurityManager 类的对象)的 getThreadGroup 方法来获取 ThreadGroup 类对象;

  • Thread参数校验:如果没有配置安全管理器或 getThreadGroup 方法也返回 null,那么会使用当前线程线程组的 ThreadGroup 类对象。如果传入的 Runnable 接口的实现对象为 null,那么会调用 Thread 类对象本身的 run 方法。传入的线程名称为 null,会抛出 NullPointerException 异常。

  • setClassLoader:在调用 Thread 类的 setClassLoader 方法设置线程上下文类加载器时,如果传入的参数为 null,则表示使用系统类加载器。如果无使用系统类加载器,则使用启动类加载器。

同样地,如果当前线程的上下文类加载器是系统类加载器或启动类加载器,那么 getContextClassLoader 方法的返回值是 null


Objects对象操作

java.util 包中新增了一个用于操作对象的工具类java.util.ObjectsObjects 类中包含的都是静态方法,通过这些方法可以快速对对象进行操作对象的比较操作时,可以使用 Objectscompare 方法。

Objects的compare方法

在进行两个对象的比较操作时,可以使用 Objects 类的 compare 方法。一般来说,进行对象比较是先由 Java 类实现java.lang.Comparable 接口,再通过 compareTo 方法来进行比较。

Objects 类的 compare 方法的使用示例

一个简单的对 Long 对象进行比较的 Comparator接口的实现,以使用Objects类的compare` 方法的示例:

private static class ReverseComparator implements Comparator<Long> {
	public int compare(Long num1, Long num2) {
		return num2.compareTo(num1);
	}
}
public void compare() {
	int value1 = Objects.compare(1L, 2L, new ReverseComparator());
}

通过使用类的 compare 方法,我们可以方便地对 Long 对象进行比较,而无需手动处理 null 值或实现比较逻辑。

集合的排序

如果要对集合中的元素进行排序,还会使用到 java.util.Comparator 接口的实现。Objects 类的 compare 方法可以通过特定的 `` 接口的实现对象来比较两个对象。

import java.util.Comparator;
import java.util.Objects;

public class LongComparator implements Comparator<Long> {
    @Override
    public int compare(Long o1, Long o2) {
        return Objects.compare(o1, o2, Comparator.naturalOrder());
    }
}

public class Main {
    public static void main(String[] args)        
    	Long a = Long.valueOf(10);
        Long b = Long.valueOf(5);
        LongComparator comparator = new LongComparator();
        int result = comparator.compare(a, b);
        System.out.println(result);: 1
    }
}

Objects的equals方法

判断对象相等的方式般是调用 Object 类的 equals 方法。例如,要判断两个对象 a 和 b 是否相等,可以使用代码a.equals(b)。Objects类的equals方法可以直接判断两个对象是否相等,如Objects.equals(a,)。该方法的一个好处是会对 null值进行处理。

Objects的equals的判断逻辑

如果直接调用一个对象的equals方法,需要先判断该对象是否为null,而使用 Objects类的equals方法则不需要。调用Objects类的equals方法时,两个参数的值都是null,则判断结果是 true;而如果只有一个参数为 null,则判断结果是 false;如果两个参数都不为 null,则调用第一个参数的 equals` 方法进行判断。

Objects的deepEquals的判断逻辑

Objects 类中与 equals 方法作用相似的方法是 deepEquals 方法,利用该方法也可以对两个对象进行相等性判断。

不同之在于,如果 deepEquals 方法两个参数是数组,则会调用 java.util 类的deepEquals方法进行比较。
Arrays 类的 deepEquals 方法在进行数组比较时,会考虑数组中的所有元素的相等性。在其他情况下,deepEquals 方法和 equals 方法的作用是相同的。

Objects 类的 equals 方法的使用示例

public void equals() {
	boolean value1 = Objects.equals(new Object(), new Object()); 
	Object[] array1 = new Object[] {"Hello", 1, 1.0};
	Object[] array2 = new Object[] {"Hello", 1, 1.5};
	boolean value2 = Objects.deepEquals(array1, array2);
}

Objects的hashCode 方法

Objects 类中 hashCode 方法可以用来获取对象哈希值。如果参数为 null,则返回值是 0;否则返回值是参数对象的 hashCode 方法结果。

如果需要计算一组对象的哈希,可以使用 Objects 类的 hash 方法。Objects的 hash 方法的实现使用的是 Arrays 类中 hashCode 方法。

注意,调用 hash 方法传入单个对象作为的返回结果,并不相同于使用同的参数调用 hashCode 方法的结果。

Objects 类的 hash 和 hashCode 方法的使用示例

public void hash() {
	int hashCode1 = Objects.hashCode("Hello");
	int hashCode2 = Objects.hash("Hello", "World");
	int hashCode3 = Objects.hash("Hello");
}

Objects的toString方法

Objects类还提供了一不同重载形式的toString方法,用于获取对象的字符串表示。当参数为null时,toString方法返回null";而在其他情况下,相当于调用参数对象的toString方法。希望在参数为null时返回特定内容作为提示信息,可以使用toString方法的另一种重载形式,该形式通过额外的参数来指定参数值为null时的返回结果。

Objects 类的 toString 方法的使用示例

public void useToString() {
	String str1 = Objects.toString("Hello");
	String str2 = Objects.toString(null, " 空对象 ");
}

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

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

相关文章

微信小程序border-radius不圆滑

border-radius可以设置&#xff1a;百分比或者像素值 1.使用像素值比较圆滑 2.使用百分比不够圆滑

习题1.25

对吗?实践出真知,运行看看。代码如下。 (defn square [x] (* x x))(defn fast-expt[b n](println "call iter" n)(cond (= 1 n) b(= 2 n) (square b)(even? n) (square (fast-expt b (/ n 2))):else (* b (fast-expt b (- n 1)))))(defn expmod [base exp m](mod…

pytest 结合logging输出日志保存至文件

API_log.py import loggingclass loger():def logering(self):# 创建logger对象logger logging.getLogger(test_logger)# 设置日志等级logger.setLevel(logging.DEBUG)# 追加写入文件a &#xff0c;设置utf-8编码防止中文写入乱码test_log logging.FileHandler(test.log, a,…

Java:基于JDBC数据连接池方式同步第三方数据库表信息数据

前言 最近遇到一个需求就是要拉取第三方的数据信息&#xff0c;但是第三方那边又没有对外暴露对接接口&#xff0c;只给出了具体的数据库连接信息和具体表信息基于第三方给出的有效信息&#xff0c;我采取了用 JDBC 传统的方式去进行数据拉取注意&#xff1a;前置条件两端的网…

收费站对讲广播系统方案

收费站对讲广播系统方案 收费站对讲广播系统是一种用于收费站内部通信和广播传输的系统。它能够实现不同收费站点之间的语音通信和广播&#xff0c;以便快速、准确地传达信息和指令。该系统通常由以下几个核心组件组成&#xff1a;1. 主控台&#xff1a;主控台是系统的中心控制…

cocos shader在编辑器正常,浏览器上不显示

问题出在需要将图片的package属性取消勾选。如果用的单色精灵&#xff0c;那么可以将系统的白色图片复制一份再取消勾选。 相关链接&#xff1a; shader在浏览器上不显示 - Creator 2.x - Cocos中文社区

Redis高级篇(一)

分布式缓存 -- 基于Redis集群解决单机Redis存在的问题 单机的Redis存在四大问题&#xff1a; 1.Redis持久化 Redis有两种持久化方案&#xff1a;RDB持久化、AOF持久化 1.1.RDB持久化 什么是RDB持久化 RDB全称Redis Database Backup file&#xff08;Redis数据备份文件&am…

第一章 JavaScript --下

第一章 JavaScript --下 2.5.6 DOM操作 由于实际开发时基本上都是使用JavaScript的各种框架来操作&#xff0c;而框架中的操作方式和我们现在看到的原生操作完全不同&#xff0c;所以下面罗列的API仅供参考&#xff0c;不做要求。 2.5.6.1 在整个文档范围内查询元素节点 功…

XUbuntu22.04之vim无法复制内容到系统(一百八十四)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 人生格言&#xff1a; 人生…

2023年7月14日,ArrayList

集合框架图&#xff1a; 集合和数组的区别 AarrayList ArrayList底层实现原理 ArrayList的底层实现是基于数组的动态扩容。 初始容量&#xff1a;当创建一个新的ArrayList对象时&#xff0c;它会分配一个初始容量为10的数组。这个初始容量可以根据需求进行调整。 //表示默认的初…

CS162 9-10

lecture9 thread lecture10 I/O层 调度 1.最小化响应时间 2.最大化吞吐量 3.分配时间公平 FCFS 后面的短请求&#xff0c;要等待前面的长请求。 Round Robin Scheduling Each process gets a small unit of CPU time (time quantum), usually 10-100 milliseconds – …

layui会议OA项目数据表格新增改查

文章目录 前言一、后台代码编写1.1 数据表优化1.2 R工具类1.3 UserDao新增改查1.4 Servlet的编写 二、前台页面的编写2.1 userManege.jsp2.2 userManage.js2.3 新增、修改用户共用jsp2.4add、edit的js 三、演示3.1 查询3.2 新增3.3 修改3.4 删除 前言 在上篇博客我们实现了左侧…

山东农信:一云多芯助力金融活水普惠齐鲁大地

农业金融正走在发展的关键路口。 一方面&#xff0c;我国全面推进乡村振兴、加快建设农业强国&#xff0c;需要形成和健全金融支农服务体系&#xff0c;为三农发展提供多元金融服务&#xff1b;另一方面&#xff0c;在大数据、云计算、人工智能等数字化的驱动下&#xff0c;数…

实战 ➾【Red Hat 搭建部署VSFTPd服务】

实战 ➾【Red Hat 搭建部署VSFTPd服务】 &#x1f53b; 前言&#x1f53b; 一、vsFTPd服务部署&#x1f6a5; 1.1 vsFTPd服务安装&#x1f6a5; 1.2 vsFTPd服务的启动与关闭 &#x1f53b; 二、vsFTPd相关配置&#x1f6a5; 2.1 vsFTPd的相关配置文件&#x1f6a5; 2.2 配置匿名…

【无标题】使用html2canvas和jspdf生成的pdf在不同大小的屏幕下文字大小不一样

问题&#xff1a;使用html2canvas和jspdf生成的pdf在不同大小的屏幕下文字大小不一样&#xff0c;在mac下&#xff0c;一切正常&#xff0c;看起来很舒服&#xff0c;但是当我把页面放在扩展屏幕下&#xff08;27寸&#xff09;&#xff0c;再生成一个pdf&#xff0c;虽然排版一…

深入理解Windows操作系统机制(二)

我是荔园微风&#xff0c;作为一名在IT界整整25年的老兵&#xff0c;今天我们来重新审视一下Windows这个我们熟悉的不能再熟悉的系统。 我们每天都在用Windows操作系统&#xff0c;但是其实我们每天直接在打交道的并不是Windows操作系统的内核&#xff0c;而是Windows操作系统…

Linux 磁盘满了的解决方案

步骤说明&#xff1a; 第一步&#xff1a;查看磁盘情况 我们要知道哪个磁盘&#xff0c;我们首先要知道各个磁盘占用情况&#xff01;可以使用以下命令 # 查看磁盘状态 df -h 解释一下&#xff1a; df: 用于显示目前在Linux系统上的文件系统的磁盘使用情况统计。 -h&…

为 GitHub 设置 SSH 密钥

1. 起因 给自己的 github 改个名&#xff0c;顺便就给原来 Hexo 对应的仓库也改了个名。然后发现 ubhexo clean && hexo generate && hexo deploy 失败了&#xff0c;报错如下&#xff1a; INFO Deploying: git INFO Clearing .deploy_git folder... INFO …

【淘宝API接口系列】,商品详情接口响应参数有哪些?响应示例是否满足

商品数据&#xff1a;淘宝提供了商品的基本信息&#xff0c;包括商品名称、描述、规格、价格、销量、库存等信息。此外&#xff0c;也可以通过淘宝提供的API接口来获取商品的图片、评价、物流信息等详细数据。 响应参数 Version: Date:2022-04-04 名称类型必须示例值描述 ite…

设计模式概述及七大原则

一、设计模式的目的 编写软件过程中&#xff0c;我们会面临着来自耦合性&#xff0c;内聚性以及可维护性&#xff0c;可扩展性&#xff0c;重用性&#xff0c;灵活性等多方面的挑战&#xff0c;设计模式是为了让程序(软件)&#xff0c;具有更好&#xff1a; 代码重用性 (即&a…