Java-Chapter 10 Thinking in Objects

问题 1:面向对象与面向过程的区别是什么?

答案

  • 面向过程:以方法为中心,解决问题时分解为具体的过程或步骤,强调方法的执行顺序。
  • 面向对象:以对象为中心,强调将数据和操作整合为一个整体,关注对象的状态和行为。

解释
面向对象的编程方式结合了面向过程的逻辑性,同时通过对象将数据和方法封装起来,便于维护和扩展。面向对象提供了更强的可扩展性、代码复用和模块化能力。

示例

  • 面向过程:

    1
    2
    3
    4
    // 计算两点之间的距离
    public static double calculateDistance(double x1, double y1, double x2, double y2) {
    return Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2));
    }
  • 面向对象:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    class Point {
    double x, y;

    Point(double x, double y) {
    this.x = x;
    this.y = y;
    }

    public double distance(Point other) {
    return Math.sqrt(Math.pow(other.x - this.x, 2) + Math.pow(other.y - this.y, 2));
    }
    }

问题 2:实例变量与静态变量的作用域是什么?

答案

  • 实例变量:作用域是整个类,但只能通过对象访问,与具体实例绑定。
  • 静态变量:作用域是整个类,与类绑定,而不是具体实例,可以通过类名访问。

解释
两者的作用域覆盖整个类,无论变量声明在类的何处,都能被访问。但静态变量被所有对象共享,而实例变量每个对象都有独立的拷贝。

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Demo {
static int staticVar = 0; // 静态变量
int instanceVar = 0; // 实例变量

public void show() {
System.out.println("Static: " + staticVar + ", Instance: " + instanceVar);
}
}

public class Main {
public static void main(String[] args) {
Demo obj1 = new Demo();
Demo obj2 = new Demo();

obj1.staticVar = 10;
obj1.instanceVar = 20;

obj2.staticVar = 30;
obj2.instanceVar = 40;

obj1.show(); // Static: 30, Instance: 20
obj2.show(); // Static: 30, Instance: 40
}
}

问题 3:关键字 this 的作用是什么?

答案

  • 用于引用当前调用对象。
  • 在构造方法中可以用 this 调用同类的其他构造方法。

解释
this 指向当前实例对象,用于在方法或构造方法中区分局部变量与实例变量。它还能实现构造方法之间的调用,避免重复代码。

示例

  1. 区分实例变量和局部变量

    1
    2
    3
    4
    5
    6
    7
    class Person {
    String name;

    Person(String name) {
    this.name = name; // this 引用当前实例的 name 变量
    }
    }
  2. 调用其他构造方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    class Person {
    String name;
    int age;

    Person(String name) {
    this(name, 0); // 调用另一个构造方法
    }

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

问题 4:Java如何将基本数据类型转换为对象类型?

答案
Java通过“装箱”(boxing)将基本数据类型转换为对象类型。例如,将 int 转换为 Integerdouble 转换为 Doublechar 转换为 Character,等等。

解释
在Java中,包装类(如 Integer, Double, Character 等)用于封装基本数据类型的值。当需要将基本类型值作为对象使用时,可以使用这些包装类。在一些情况下,Java会自动进行装箱(自动转换为对象)和拆箱(将对象转回基本类型)操作,称为自动装箱和自动拆箱。

示例

1
2
int num = 100;
Integer obj = Integer.valueOf(num); // 装箱:基本类型 int 转换为 Integer 对象

问题 5:Integer类的静态方法有哪些?

答案

  1. static int parseInt(String s):将字符串转换为整数。
  2. static Integer valueOf(String s):将字符串转换为 Integer 对象。
  3. static Integer valueOf(int i):将 int 转换为 Integer 对象。

解释

  • parseInt() 用于将字符串解析为原始 int 类型。
  • valueOf() 用于将 Stringint 转换为 Integer 对象。如果字符串可以转换为有效的整数,valueOf() 方法会返回一个 Integer 对象。

示例

1
2
3
String str = "123";
int num = Integer.parseInt(str); // 将字符串 "123" 转换为 int 类型
Integer obj = Integer.valueOf(str); // 将字符串 "123" 转换为 Integer 对象

问题 6:Integer a = 100; Integer b = 100; a == b 的结果是什么?

答案
a == b 的结果是 true

解释

  • 对于 Integer 类型,Java 会缓存 -128127 范围内的常用整数对象,因此在这个范围内,使用 Integer.valueOf() 方法时会返回缓存中的对象,而不是每次都创建新的对象。
  • 由于 ab 都被赋值为 100,而 100-128127 的范围内,因此它们引用的是同一个缓存对象,因此 a == b 返回 true

示例

1
2
3
Integer a = 100;
Integer b = 100;
System.out.println(a == b); // 输出 true,因为它们指向同一个对象

问题 7:什么是装箱(Boxing)和拆箱(Unboxing)?

答案

  • 装箱(Boxing):将基本数据类型转换为对应的包装类对象。例如,将 int 转换为 Integer
  • 拆箱(Unboxing):将包装类对象转换为对应的基本数据类型。例如,将 Integer 转换为 int

解释
Java 提供了自动装箱和拆箱的功能。装箱是指将基本数据类型自动包装为对象,拆箱是指将对象自动转换为基本数据类型。在许多情况下,Java 会自动进行这些转换。

示例

1
2
Integer a = 100;  // 自动装箱,将 int 转为 Integer
int b = a; // 自动拆箱,将 Integer 转为 int

问题 8:String类的不可变性如何影响它的性能?

答案
String 是不可变的,即一旦创建后其内容不能修改。这种设计提高了效率并节省内存,尤其在处理相同字符序列的多个字符串时。JVM 会对具有相同字符序列的字符串创建唯一的对象,这些对象被称为“字符串常量池”中的字符串对象。

解释

  • 不可变性:字符串一旦被创建,就无法更改其内容。如果对字符串进行修改,实际上会创建一个新的字符串对象。
  • 字符串常量池:JVM 会将相同的字符串字面量共享存储,避免重复的字符串对象,从而节省内存。

示例

1
2
3
String str1 = "hello";
String str2 = "hello";
System.out.println(str1 == str2); // 输出 true,因为它们指向常量池中的同一个对象

问题 9:正则表达式是什么?

答案
正则表达式是用于描述字符串模式的语法,它可以用来匹配、替换、或分割字符串。

解释
正则表达式通过特定的模式描述符,能够描述一个或多个字符的匹配规则。Java 提供了 PatternMatcher 类来支持正则表达式的操作。可以使用正则表达式执行诸如查找、替换和分割等操作。

示例

1
2
3
String text = "hello123world";
boolean match = text.matches("\\w+\\d+\\w+"); // 检查字符串是否符合正则表达式的规则
System.out.println(match); // 输出 true

这段代码的目的是检查字符串 "hello123world" 是否符合正则表达式 \\w+\\d+\\w+ 的规则。

  • \\w+:表示一个或多个字母、数字或下划线。\\w 是“word”的缩写,等价于 [a-zA-Z0-9_]+ 表示一个或多个。
  • \\d+:表示一个或多个数字。\\d 表示数字,等价于 [0-9]

正则表达式 \\w+\\d+\\w+ 需要满足以下条件:

  1. 字符串的开始部分由一个或多个字母、数字或下划线组成(\\w+)。
  2. 接下来紧跟着一个或多个数字(\\d+)。
  3. 最后是一个或多个字母、数字或下划线(\\w+)。

对于 "hello123world"

  • hello 部分符合 \\w+(字母组成)。
  • 123 部分符合 \\d+(数字组成)。
  • world 部分符合 \\w+(字母组成)。

因此,整个字符串符合这个正则表达式,text.matches("\\w+\\d+\\w+") 的返回值是 true,最终输出 true

这就是为什么代码会输出 true


问题 10:StringBuilder 和 StringBuffer 有什么区别?

答案

  • StringBuilder:是一个可变的字符序列,适用于单线程环境。操作字符串时,它的性能比 String 更高。
  • StringBuffer:也是一个可变的字符序列,类似于 StringBuilder,但它是线程安全的,因此它适用于多线程环境。

解释

  • StringBuilderStringBuffer 都允许对字符串进行修改(如添加、插入、删除等),但是由于线程安全的开销,StringBufferStringBuilder 稍慢。
  • 如果不涉及多线程,StringBuilder 是首选,因为它比 StringBuffer 更高效。

示例

1
2
3
StringBuilder sb = new StringBuilder("Hello");
sb.append(" World");
System.out.println(sb); // 输出 "Hello World"