Java基础知识学习,一文掌握Java基础知识文集。

2023-12-22 12:37:48

在这里插入图片描述

🏆作者简介,普修罗双战士,一直追求不断学习和成长,在技术的道路上持续探索和实践。
🏆多年互联网行业从业经验,历任核心研发工程师,项目技术负责人。
🎉欢迎 👍点赞?评论?收藏

🔎 一、Java基础知识文集(1)

🍁🍁 01. JDK 和 JRE 有什么区别?

JDK(Java Development Kit)和JRE(Java Runtime Environment)是Java开发中常见的两个术语,它们之间有以下区别:

JDK包含了完整的Java开发工具集,用于开发和编译Java程序。它包括了JRE的所有内容,并且还包含了Java编译器(javac)、调试工具(jdb)、Java文档生成工具(javadoc)等各种开发工具。对于开发者来说,安装JDK是必要的,因为它提供了开发所需的所有工具和库。

JRE是Java应用程序的运行环境,用户在运行Java应用程序时需要安装JRE。它包含了Java虚拟机(JVM)、Java类库和其他运行Java程序所需的基础组件。JRE不包含开发工具,只提供了运行Java程序的功能。

简而言之,JDK面向Java开发者,提供了开发、编译和调试工具,而JRE面向Java应用程序的用户,提供了Java程序的运行环境。

在开发Java应用程序时,开发者需要先安装JDK,并使用其中的编译器(javac)将Java源代码编译为字节码(.class文件)。然后,用户可以在安装了JRE的计算机上运行这些已编译的Java应用程序。

需要注意的是,JRE是JDK的一个子集,也就是说JDK中包含了JRE的所有内容。因此,如果只需要运行Java程序而不进行开发,则只需安装JRE即可。但如果想要进行Java应用程序的开发,则需要安装JDK。

特性JDKJRE
包含内容包含完整的Java开发工具集包含Java运行时环境及基础组件
面向对象面向Java应用程序的开发者面向Java应用程序的用户
包含工具包括编译器、调试工具、文档生成工具等仅包含Java虚拟机和基础类库
安装需求需要安装JDK进行Java程序的开发与编译需要安装JRE进行Java程序的运行
关系JDK包含JRE,JRE是JDK的一个子集JRE是JDK的一个子集

以上表格总结了JDK和JRE之间的区别,包括其包含内容、面向对象、包含工具、安装需求和它们之间的关系。这些区别表明了JDK主要面向Java的开发者,而JRE主要面向Java应用程序的最终用户。

🍁🍁 02. JDK1.7 与 JDK1.8 的区别?

JDK 1.7和JDK 1.8是Java平台的两个主要版本,它们之间有一些显著的区别:

  1. Lambda 表达式和函数式接口:JDK 1.8引入了Lambda表达式和函数式接口的支持,使得编写函数式风格的代码更加简洁和方便。这为并发编程和集合操作带来了很大的改进。

  2. Stream API:JDK 1.8引入了Stream API,这是对集合框架的增强,让我们可以通过流式操作来对集合进行处理,例如过滤、映射、归约等,使得集合操作变得更加简洁和灵活。

  3. 接口的默认方法和静态方法:JDK 1.8允许在接口中定义默认方法和静态方法,这使得接口在evolution过程中更加灵活,可以向已有的接口中添加新的方法,而不会破坏实现该接口的类。

  4. 类型注解:JDK 1.8引入了类型注解,允许在使用类型时添加注解,这为编写更加安全和动态的代码提供了更多的可能性。

  5. 新的日期和时间API:JDK 1.8引入了新的日期和时间API,包括java.time包,提供了更好的日期和时间处理支持,使得在处理日期时间上更加方便和安全。

  6. PermGen空间移除:JDK 1.8移除了永久代(PermGen),取而代之的是使用元数据区(元空间),这样可以避免了一些常见的性能问题和内存溢出异常。

这些是JDK 1.7和JDK 1.8之间的一些主要区别。总体来说,JDK 1.8引入了许多重要的新特性和改进,使得Java编程更加现代化、灵活和高效。

特性JDK 1.7JDK 1.8
Lambda 表达式和函数式接口不支持支持
Stream API不支持支持
接口的默认方法和静态方法不支持支持
类型注解不支持支持
新的日期和时间API有限的java.util.Date和java.util.Calendar类引入java.time包,提供更现代的日期和时间API
PermGen空间移除有PermGen空间移除PermGen空间,使用元数据区(元空间)

以上表格总结了JDK 1.7和JDK 1.8之间的区别,包括Lambda表达式和函数式接口、Stream API、接口的默认方法和静态方法、类型注解、新的日期和时间API以及PermGen空间移除等方面的差异。这些改进使得JDK 1.8相比JDK 1.7拥有更多的现代化特性和性能优势。

🍁🍁 03. 两个对象的 hashCode() 相同,则 equals() 也一定为 true,对吗?

在 Java 中,如果两个对象的 hashCode() 返回值相同,equals() 方法不一定为 true。这是因为 hashCode() 方法用于计算对象的哈希码,而 equals() 方法用于判断两个对象是否相等。

举个例子来说明:

public class Person {
    private String name;
    private int age;

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

    @Override
    public int hashCode() {
        return 1; // 简化起见,假设所有对象的 hashCode 都相同
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null || getClass() != obj.getClass()) {
            return false;
        }
        Person person = (Person) obj;
        return age == person.age && Objects.equals(name, person.name);
    }
}

在这个例子中,尽管两个不同的 Person 对象的 hashCode() 都返回相同的值(这里都返回 1),但它们的 equals() 方法会根据它们的实际内容来判断相等性,因此并不一定相等。

因此,可以得出结论:hashCode() 相同,并不代表equals() 一定为 true。

🍁🍁 04. Java 中的 Math. round(-1. 5) 等于多少?

Java 中的 Math.round(-1.5) 结果为 -1。这是因为 Math.round() 方法会对传入的浮点数进行四舍五入操作。

对于负数,Math.round() 方法会遵循以下规则:如果小数部分大于或等于 0.5,向绝对值更大的整数方向进行舍入;如果小数部分小于 0.5,向绝对值更小的整数方向进行舍入。

在这个例子中,-1.5 的小数部分为 0.5,因此根据规则,会向绝对值更大的整数方向进行舍入,即 -1。

所以,Math.round(-1.5) 的结果是 -1。

🍁🍁 05. String str="i"与 String str=new String(“i”)一样吗?

在Java中,String str = "i"String str = new String("i")是不完全相同的。

String str = "i"是使用字符串字面量直接赋值的方式创建字符串对象。在Java中,字符串字面量的使用会被编译器优化,在内存中创建一个字符串常量(String Pool),如果已经存在相同内容的字符串,则直接引用该常量,而不会创建新的对象。因此,如果之前已经有相同内容的字符串"i"存在于字符串常量池中,那么String str = "i"会直接指向该常量。

String str = new String("i")是使用new关键字显式地创建一个新的字符串对象,无论字符串常量池中是否存在相同内容的字符串。即使字符串常量池中已经存在了字符串"i",new String("i")仍然会创建一个新的字符串对象。

所以,虽然在某些情况下,String str = "i"String str = new String("i")的结果相同,都表示字符串"i",但实际上它们是两种不同的方式创建字符串对象,并在内存中的位置和使用方式上有所区别。

当使用String str = "i"时,如果之前已经有相同内容的字符串"i"存在于字符串常量池中,那么str会直接指向该字符串常量,而不会创建新的对象。这意味着如果其他地方也使用了相同的字符串字面量"i",那么它们实际上都引用的是同一个字符串对象。

而使用String str = new String("i")时,无论字符串常量池中是否存在相同内容的字符串"i",都会创建一个新的字符串对象,即使内容相同,它们在内存中也是不同的对象。

因此,String str = "i"String str = new String("i")的主要区别在于内存中创建的方式和位置不同,前者优先在字符串常量池中查找并引用已存在的字符串常量,而后者则以显式方式创建新的字符串对象。

🍁🍁 06. String 属于基础的数据类型吗?

在Java中,String不是基础的数据类型。基础的数据类型包括intdoubleboolean等,而String是一种引用数据类型(也称为类类型)。

引用数据类型是指由用户定义的类或Java提供的类,它们在内存中存储的是对象的引用(地址),而不是对象的实际内容。而基础的数据类型直接在内存中存储值本身。

String是Java提供的字符串类,它表示一串字符序列。在Java中,字符串是不可变的,即创建后不能被修改。当我们创建一个字符串对象时,实际上是在内存中分配了一块空间来存储该字符串的字符序列,并提供了一系列方法来操作和访问这个字符串。由于String是一个类,我们可以使用它的方法来进行字符串的操作,如连接、截取、查找等。

因此,String不是基础的数据类型,而是属于引用数据类型。

🍁🍁 07. String 类的常用方法都有那些?

String类在Java中有很多常用的方法,以下是其中一些常用的方法和它们的用法示例:

  1. length(): 用于获取字符串的长度。

    String str = "Hello";
    int len = str.length(); // len 的值为 5
    
  2. charAt(int index): 用于获取字符串中指定位置的字符。

    String str = "Hello";
    char ch = str.charAt(1); // ch 的值为 'e'
    
  3. substring(int beginIndex) / substring(int beginIndex, int endIndex): 用于获取字符串的子串。

    String str = "Hello";
    String sub1 = str.substring(2); // sub1 的值为 "llo"
    String sub2 = str.substring(1, 3); // sub2 的值为 "el"
    
  4. indexOf(String str) / indexOf(String str, int fromIndex): 用于查找指定字符串在原字符串中首次出现的位置索引。

    String str = "Hello";
    int index1 = str.indexOf("l"); // index1 的值为 2
    int index2 = str.indexOf("l", 3); // index2 的值为 3
    
  5. toUpperCase() / toLowerCase(): 用于将字符串转换为全大写或全小写。

    String str = "Hello";
    String upper = str.toUpperCase(); // upper 的值为 "HELLO"
    String lower = str.toLowerCase(); // lower 的值为 "hello"
    
  6. trim(): 用于去除字符串两端的空白字符。

    String str = "  Hello  ";
    String trimmed = str.trim(); // trimmed 的值为 "Hello"
    
  7. replace(CharSequence target, CharSequence replacement): 用于替换字符串中的指定字符或子串。

    String str = "Hello, world!";
    String replaced = str.replace("o", "0"); // replaced 的值为 "Hell0, w0rld!"
    

以上是String类的一些常用方法及其示例,String类还有很多其他方法可以用来处理字符串,如拼接、判断开头结尾、分割等。

🍁🍁 08. Java 中操作字符串都有哪些类?它们之间有什么区别?

在Java中,常用的用于操作字符串的类有StringStringBuilderStringBuffer。以下是它们之间的区别的详细比较表格:

类名可变性线程安全性性能举例
String不可变线程安全一般String str = “Hello”;
StringBuilder可变非线程安全较高StringBuilder sb = new StringBuilder(“Hello”);
StringBuffer可变线程安全较低StringBuffer sbf = new StringBuffer(“Hello”);

可变性

  • String是不可变的。一旦创建了String对象,就不能修改它的值。
  • StringBuilderStringBuffer是可变的。它们内部的字符序列可以进行修改。

线程安全性

  • String是线程安全的。由于不可变性,String对象可以被多个线程安全地共享,不需要额外的同步措施。
  • StringBuilder是非线程安全的。StringBuilder的方法没有进行同步,如果多个线程同时访问它,需要额外的同步措施。
  • StringBuffer是线程安全的。StringBuffer的方法都是同步的,可以在多线程环境下安全使用。

性能

  • 由于String对象的不可变性,每次对String进行修改操作时都会创建一个新的String对象,会产生大量的临时对象,对性能有一定的影响。
  • StringBuilderStringBuffer是可变的,可以直接对它们的内部字符序列进行修改,避免了创建新的对象,因此性能较高。
  • StringBuilder相对于StringBuffer具有更好的性能,因为不需要同步措施,但它不是线程安全的。

根据需求的不同选择适合的类进行字符串操作:

  • 如果字符串是不经常改变的,并且在多线程环境下使用,可以选择使用StringStringBuffer
  • 如果字符串需要频繁进行修改,并且在单线程环境下使用,可以选择使用StringBuilder

举例说明其使用方式

// 使用String
String str = "Hello";
str = str + " World";

// 使用StringBuilder
StringBuilder sb = new StringBuilder("Hello");
sb.append(" World");

// 使用StringBuffer
StringBuffer sbf = new StringBuffer("Hello");
sbf.append(" World");

在上面的示例中,可以看到使用StringStringBuilder来拼接字符串的方式有所不同。对于String来说,每次操作都会创建一个新的String对象,而StringBuilder允许我们直接修改其内部的字符序列,避免了额外的对象创建,因此在大量字符串拼接的情况下,使用StringBuilder会更有效率。

总之,根据具体的需求和情况选择合适的字符串操作类是很重要的。如果需要进行大量的字符串拼接操作,特别是在单线程环境下,推荐使用StringBuilder;如果涉及多线程环境,则应该选择StringBuffer。而对于不经常改变的字符串,可以考虑使用String类。

🍁🍁 09. final 在 Java 中有什么作用?

在Java中,final关键字有以下几种作用:

  1. 修饰类:当final修饰一个类时,表示该类是最终类,不能被继承。
final class FinalClass {
    // 类的内容
}
  1. 修饰方法:当final修饰一个方法时,表示该方法是最终方法,子类不能覆盖重写这个方法。
class BaseClass {
    final void finalMethod() {
        // 方法的内容
    }
}
  1. 修饰变量:当final修饰一个变量时,表示该变量是一个常量,只能被赋值一次,之后不能再改变其值。
final int CONSTANT_VALUE = 100;

final关键字的作用在于提供了更严格的约束,能够确保类、方法或变量在程序中的使用符合特定的需求。通过使用final可以有效地防止类被继承、方法被重写和变量被修改,从而增强了程序的可靠性和安全性。

举例说明:

// final修饰类的例子
final class FinalClass {
    // 类的内容
}

// final修饰方法的例子
class BaseClass {
    final void finalMethod() {
        // 方法的内容
    }
}

// final修饰变量的例子
class Example {
    final int CONSTANT_VALUE = 100;

    void modifyConstant() {
        // 尝试修改常量值,会导致编译错误
        // CONSTANT_VALUE = 200;
    }
}

在上面的例子中,可以看到final关键字的作用。FinalClass被标记为final,因此不能被其他类继承;finalMethod被标记为final,因此不能被子类重写;CONSTANT_VALUE被标记为final,因此不能被再次赋值。

🍁🍁 10. == 和 equals 的区别是什么?

在Java中,==equals()是用于比较对象的操作符,但它们在比较对象时有着不同的行为和区别。

==比较运算符

  • 在比较基本数据类型时,例如intfloatboolean等,==比较的是它们的值是否相等。
  • 在比较引用类型时,==比较的是对象引用的地址,即比较两个对象是否指向同一个内存地址。

equals()方法

  • equals()是一个定义在Object类中的方法,用于比较两个对象的内容是否相等,默认实现是比较两个对象的引用是否相等,与==操作符的效果相同。
  • 对于许多类,例如StringInteger等,它们会重写equals()方法来比较对象的内容是否相等。重写后的equals()方法可以根据对象内部的属性值来确定对象是否相等。

下面是一个示例来说明==equals()的区别:

String str1 = "Hello";
String str2 = new String("Hello");

System.out.println(str1 == str2);           // false
System.out.println(str1.equals(str2));      // true

在上面的示例中,str1str2是两个不同的String对象,它们的引用地址不同,因此str1 == str2的结果是false。但是,它们的内容是相同的,因此str1.equals(str2)的结果是true。这是因为String类重写了equals()方法,以比较字符串的内容而不是引用地址。

总结来说,==用于比较基本数据类型的值或者比较对象的引用地址,equals()用于比较对象的内容是否相等。对于大多数情况下,应该使用equals()来比较对象的内容。但是需要注意的是,当比较对象时,应该确保该类已经重写了equals()方法来定义对象相等的判断规则。

🍁🍁 11. 如何将字符串反转?

在Java中,有多种方法可以将字符串进行反转。下面列举了一些常见的方法:

  1. 使用 StringBuilder(推荐):

    String original = "Hello";
    StringBuilder reversed = new StringBuilder(original).reverse();
    String result = reversed.toString();
    System.out.println(result);  // 输出 "olleH"
    
  2. 使用字符数组:

    String original = "Hello";
    char[] chars = original.toCharArray();
    int left = 0;
    int right = chars.length - 1;
    
    while (left < right) {
        char temp = chars[left];
        chars[left] = chars[right];
        chars[right] = temp;
        left++;
        right--;
    }
    
    String result = new String(chars);
    System.out.println(result);  // 输出 "olleH"
    
  3. 使用递归:

    public static String reverseString(String str) {
        if (str.isEmpty()) {
            return str;
        }
        return reverseString(str.substring(1)) + str.charAt(0);
    }
    
    String original = "Hello";
    String result = reverseString(original);
    System.out.println(result);  // 输出 "olleH"
    

无论使用哪种方法,最终都可以得到字符串的反转形式。选择合适的方法取决于具体的需求和性能要求。其中,使用 StringBuilder 是一种简便且性能高效的方法,特别适用于频繁操作字符串的场景。而使用字符数组或递归则提供了其他一些灵活的思路和方式。

🍁🍁 12. 抽象类必须要有抽象方法吗?

不一定,抽象类并不一定非要包含抽象方法。抽象类可以包含抽象方法,也可以包含非抽象方法,甚至可以不包含任何抽象方法。

下面是一个不包含抽象方法的抽象类的示例:

public abstract class Animal {
    private String name;

    public Animal(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void makeSound() {
        System.out.println("The animal makes a sound");
    }
}

在这个示例中,Animal 类被声明为抽象类,但它并不包含任何抽象方法。它包含一个构造函数和一些普通的方法,包括一个普通的方法makeSound()来模拟动物的叫声。因此,可以看出抽象类并非需要包含抽象方法。

抽象方法的存在使得抽象类具有更灵活的特性,可以将一些方法的实现交给其具体的子类去完成,同时抽象类也可以包含普通的方法和字段。这样的设计让抽象类更具通用性,能够为其子类定义一些通用的行为和属性。

🍁🍁 13. 普通类和抽象类有哪些区别?

普通类(非抽象类)和抽象类之间有几个关键的区别,它们如下:

  1. 实例化:普通类可以被实例化,而抽象类不能直接被实例化。也就是说,你可以创建普通类的对象,但不能创建抽象类的对象。

  2. 方法:普通类中的所有方法都有具体的实现,而抽象类中可以包含抽象方法(没有具体实现,只有方法签名),同时也可以包含具体方法。子类必须实现抽象类中的抽象方法,但对于普通类则没有这个要求。

  3. 继承:一个类只能继承一个普通类,但是可以实现多个接口。而对于抽象类来说,一个类可以继承一个抽象类,并且在Java中,类只能单继承,因此它也遵循这一规则。

  4. 设计目的:普通类用于具体的对象创建,而抽象类更多用于作为子类的模板,提供一些通用的方法和行为,以便子类继承或实现。

基本上,抽象类是对一组相关的类的抽象,其中可能包含一些通用的方法,而普通类则是用来创建对象和表示具体的实体。因此,选择使用普通类还是抽象类,取决于你的设计需求和模型的抽象程度。

🍁🍁 14. 抽象类能使用 final 修饰吗?

在Java中,抽象类是可以使用 final 修饰的。

使用 final 关键字修饰一个抽象类表示该类不能被继承。也就是说,如果一个抽象类被声明为 final,则不能再有子类来继承它。这通常用于防止对抽象类的进一步扩展和修改。

示例代码如下:

final abstract class AbstractClass {
    // Class members and methods
}

在这个示例中,AbstractClass 被声明为 final abstract,表示该抽象类是最终的,不能再有子类来继承它。这样其他类就不能继承这个抽象类。

需要注意的是,虽然抽象类可以被声明为 final,但抽象方法不能被同时声明为 finalabstract,因为 final 表示方法不能被重写,而 abstract 表示方法必须被重写。这两者是冲突的。

总之,抽象类可以使用 final 修饰符来限制它的继承性,但需要注意不能将 finalabstract 同时用于同一个方法。

🍁🍁 15. 接口和抽象类有什么区别?

接口和抽象类是面向对象编程中两种不同的机制,它们有一些重要的区别,主要体现在以下几个方面:

  1. 方法实现

    • 抽象类可以包含具体方法的实现,而接口只能包含方法的声明而没有方法的实现。
    • 在 Java 8 之后,接口也可以包含默认方法的实现,但默认方法并非强制要求实现类重写,而抽象类中的方法可以选择性地由子类重写。
  2. 继承与实现

    • 类可以实现多个接口,但只能继承一个抽象类。
    • 接口之间可以通过扩展(extends)来建立继承关系,一个接口可以继承多个其他接口,而抽象类只能继承一个类或抽象类。
  3. 构造函数

    • 抽象类可以有构造函数,而接口不能拥有构造函数。因为接口是对行为的抽象,而不是对对象的抽象。
  4. 成员变量

    • 接口中的成员变量默认会被设置为 public static final 类型,即常量;而抽象类中可以包含各种类型的成员变量。
  5. 设计目的

    • 接口主要用于定义类之间的接口,强调的是对行为的抽象;而抽象类更多地用于作为子类的模板,提供一些通用的方法和行为,强调的是对对象的抽象。

总之,抽象类和接口在使用上有一些细微的差别,具体取决于设计的需求和模型的抽象程度。通常情况下,应该根据具体的情况来选择接口或抽象类,或者两者结合使用,以便更好地实现面向对象的设计原则。

以下是关于接口和抽象类区别,用表格列举如下:

区别接口抽象类
方法实现只能包含方法的声明,无方法实现。可以包含具体方法的实现。
多继承支持多继承,可以实现多个接口。只能通过单继承,继承一个抽象类。
构造函数无法拥有构造函数。可以拥有构造函数。
成员变量默认为 public static final 类型,即常量。可以包含各种类型的成员变量。
设计目的主要用于定义类之间的接口,强调对行为的抽象。主要用于作为子类的模板,提供通用方法和行为,强调对对象的抽象。
强制实现实现接口时,必须实现接口中的所有方法。可以选择性实现抽象类中的方法。
构造函数接口中不能定义构造函数。抽象类中可以定义构造函数。
实例化无法直接实例化接口。无法直接实例化抽象类。
扩展性可以通过接口的扩展来添加新的方法。可以通过继承抽象类来添加新的方法和属性。

这个表格总结了接口和抽象类在各个方面的区别,包括方法实现、多继承、构造函数、成员变量、设计目的、强制实现、构造函数、实例化和扩展性。通过对比表格中的不同,你可以更清晰地了解接口和抽象类之间的区别和适用场景。

🍁🍁 16. BIO、NIO、AIO 有什么区别?

BIO(Blocking I/O)、NIO(Non-blocking I/O)和AIO(Asynchronous I/O)是三种不同的 I/O 模型,它们在处理 I/O 操作时有一些区别。

  1. BIO

    • 也称为传统的阻塞式 I/O。
    • 在进行 I/O 操作时,线程会被阻塞,直到操作完成。
    • 每个连接都需要独立的线程进行处理,因此在高并发环境下会造成线程资源的浪费。
    • 适用于连接数较少且对并发性要求不高的场景,如传统的客户端/服务器模型。
  2. NIO

    • 也称为非阻塞式 I/O。
    • 引入了 Channel(通道)和 Buffer(缓冲区)的概念。
    • 可以通过一个线程处理多个连接,不再需要为每个连接创建单独的线程。
    • 通过选择器(Selector)进行事件驱动,实现了非阻塞的 I/O 操作。
    • 适用于高并发环境下的网络编程,如聊天室、多人在线游戏等。
  3. AIO

    • 也称为异步非阻塞式 I/O。
    • 在进行 I/O 操作时,不会阻塞线程,而是通过回调机制在操作完成后通知线程。
    • 适用于高并发、大量连接的场景,如高性能服务器、实时音视频传输等。

以下是它们的主要区别总结:

模型阻塞与非阻塞并发性可扩展性应用场景
BIO阻塞传统的客户端/服务器模型,连接数少
NIO非阻塞高并发环境,如聊天室、多人在线游戏等
AIO异步非阻塞高并发、大量连接的场景

综上所述,BIO、NIO 和 AIO 分别适用于不同的 I/O 编程场景,你可以根据具体的需求选择合适的 I/O 模型。

🍁🍁 17. Files的常用方法都有哪些?

Java 中的 Files 类提供了许多用于操作文件系统的常用方法。以下是 Files 类的一些常用方法:

  1. 文件操作

    • createFile(Path path, FileAttribute<?>... attrs): 创建文件。
    • copy(Path source, Path target, CopyOption... options): 复制文件或目录。
    • move(Path source, Path target, CopyOption... options): 移动文件或目录。
    • delete(Path path): 删除文件或目录。
  2. 目录操作

    • createDirectory(Path dir, FileAttribute<?>... attrs): 创建目录。
    • walkFileTree(Path start, Set<FileVisitOption> options, int maxDepth, FileVisitor<? super Path> visitor): 遍历文件树。
    • list(Path dir): 列出目录中的文件和子目录。
  3. 文件属性

    • isDirectory(Path path, LinkOption... options): 判断是否为目录。
    • isRegularFile(Path path, LinkOption... options): 判断是否为普通文件。
    • isReadable(Path path): 判断文件是否可读。
    • isWritable(Path path): 判断文件是否可写。
  4. 文件读写

    • readAllLines(Path path, Charset cs): 读取文件的所有行。
    • write(Path path, byte[] bytes, OpenOption... options): 写入字节数组到文件。
    • readAllBytes(Path path): 读取文件的所有字节。
  5. 文件信息

    • size(Path path): 获取文件大小。
    • getLastModifiedTime(Path path, LinkOption... options): 获取文件最后修改时间。
  6. 其他

    • exists(Path path, LinkOption... options): 判断文件是否存在。
    • isSameFile(Path path, Path path2): 判断两个路径是否指向同一文件。

这些方法涵盖了 Java Files 类中一些常用的文件和目录操作。使用这些方法可以进行文件的创建、复制、移动、删除,目录的创建、遍历以及文件属性的获取等操作。根据具体的需求,你可以选择合适的方法来操作文件系统。

🍁🍁 18. final 在 java 中有什么作用?

在 Java 中,final 关键字有多种作用,主要用于修饰类、方法和变量,其作用如下:

  1. 修饰类

    • 当一个类被声明为 final 时,表示该类不可被继承,即不能有子类。
    • 例如:public final class MyClass { ... }
  2. 修饰方法

    • 当一个方法被声明为 final 时,表示该方法不可被子类重写(覆盖)。
    • 例如:public final void myMethod() { ... }
  3. 修饰变量

    • 当一个变量被声明为 final 时,表示该变量的值只能被赋值一次,即成为一个常量。一旦被赋值后,就不能再更改。
    • 对于基本类型,其数值不能改变;对于对象引用,不能再指向另一个对象,但对象自身的状态是可以改变的。
    • 例如:final int x = 10;final MyClass obj = new MyClass();

final 的作用主要是为了实现不可改变性(immutability)和安全性,可以用于确保类、方法或变量的稳定性和安全性。在设计中如果需要避免子类对某个方法或变量的修改,或者确保变量值的稳定性,就可以使用 final 关键字。

🍁🍁 19. 如何判断 List 集合是否为空?

在 Java 中,可以使用以下方法来判断 List 集合是否为空:

  1. 使用 size() 方法

    • 通过调用 List 的 size() 方法,判断 List 的大小是否为 0。
    • 如果 List 的大小为 0,即为空集合;否则,不为空集合。
    • 例如:
      List<String> myList = new ArrayList<>();
      if (myList.size() == 0) {
          System.out.println("List is empty");
      } else {
          System.out.println("List is not empty");
      }
      
  2. 使用 isEmpty() 方法

    • List 接口提供了一个 isEmpty() 方法,用于判断集合是否为空。
    • 如果 List 为空,则返回 true;否则,返回 false。
    • 例如:
      List<String> myList = new ArrayList<>();
      if (myList.isEmpty()) {
          System.out.println("List is empty");
      } else {
          System.out.println("List is not empty");
      }
      

无论是使用 size() 方法还是 isEmpty() 方法,都可以有效地判断 List 集合是否为空。推荐使用 isEmpty() 方法,因为它更加简洁和语义明确。

🍁🍁 20. Java 中 IO 流分为几种?举例说明?

在Java中,IO流主要分为以下两种类型:

  1. 字节流(Byte Streams)

    • 字节流以字节为单位进行读取和写入操作,主要用于处理二进制数据或者字节流形式的文本数据。
    • 字节流类主要位于 java.io 包中,并且以 InputStreamOutputStream 为核心类。
    • 示例:
      InputStream inputStream = new FileInputStream("example.txt");
      int data = inputStream.read();
      while (data != -1) {
          // 处理数据
          System.out.print((char) data);
          data = inputStream.read();
      }
      inputStream.close();
      
      OutputStream outputStream = new FileOutputStream("example.txt");
      outputStream.write("Hello, World!".getBytes());
      outputStream.close();
      
  2. 字符流(Character Streams)

    • 字符流以字符为单位进行读取和写入操作,主要用于处理文本数据。
    • 字符流类主要位于 java.io 包中,并且以 ReaderWriter 为核心类。
    • 示例:
      Reader reader = new FileReader("example.txt");
      int data = reader.read();
      while (data != -1) {
          // 处理数据
          System.out.print((char) data);
          data = reader.read();
      }
      reader.close();
      
      Writer writer = new FileWriter("example.txt");
      writer.write("Hello, World!");
      writer.close();
      

无论是字节流还是字符流,它们均可通过输入流(InputStream、Reader)进行数据读取,通过输出流(OutputStream、Writer)进行数据写入。根据实际的需求,选择适当的流进行操作。在使用 IO 流时,要注意及时关闭流对象,以避免资源泄露。

在这里插入图片描述

文章来源:https://blog.csdn.net/m0_50308467/article/details/135119061
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。