Java预习任务
Java预习任务完成报告
第一部分:引用类型、数组、类和方法
方法相关问题
1.1 changeStr与changeArr的功能各是什么?
changeStr方法接收一个 String 参数x,并尝试将x重新赋值为 "xyz"。但由于 String 是不可变类,且 Java 采用值传递,该方法不会改变原始字符串变量的值。changeArr方法接收一个 String 数组参数strs,并遍历数组,将每个元素修改为原始值加上索引号(例如strs[i] + "" + i)。这会修改数组的内容,因为数组是引用类型,传递的是引用的副本,但通过引用可以修改原始数组的元素。
1.2 main方法的x有没有被改变?为什么?
- main 方法的
x没有被改变。因为changeStr方法中的参数x是局部变量,接收了 main 方法中x的值的副本(即引用的副本)。当在changeStr中重新赋值时,只是改变了局部变量x的引用,而不是原始变量。因此 main 中的x仍然指向 "abc"。
1.3 main方法的args数组的内容有没有被改变?为什么?
- main 方法的
args数组的内容被改变了。因为changeArr方法接收的是数组的引用副本,但通过这个引用副本可以直接访问和修改原始数组的元素。因此,当changeArr修改数组元素时,原始args数组被修改。
1.4 args数组中的值是从哪里来的?要怎么才能给他赋值?
args数组中的值来自命令行参数。当运行 Java 程序时,可以通过命令行传递参数。例如,使用命令java Main arg1 arg2 arg3,那么args数组就会包含["arg1", "arg2", "arg3"]。在 IDE(如 IntelliJ IDEA 或 Eclipse)中,可以通过运行配置设置命令行参数。
数组相关问题
2.1 这段程序输出结果是什么?为什么?
int[] arr = new int[3];
arr[0] = 1; arr[1] = 1;
int[] arrX = arr;
arr[0] = 2;
System.out.println(Arrays.toString(arr));
System.out.println(Arrays.toString(arrX));
- 输出结果:
[2, 1, 0][2, 1, 0]
- 原因:
arrX被赋值为arr的引用,因此arrX和arr指向同一个数组对象。当修改arr[0]为 2 时,通过arrX访问同一个数组,所以arrX[0]也是 2。数组是引用类型,赋值操作共享引用。
2.2 字符串是不可变类,为什么可以对strArr[1]赋值"xx"?
String[] strArr = {"aa","bb","cc"};
strArr[1] = "xx";
System.out.println(Arrays.toString(strArr));
- 字符串是不可变类,意味着 String 对象一旦创建就不能被修改。但
strArr是一个数组,数组的元素是 String 引用。当执行strArr[1] = "xx"时,并不是修改了原有的 String 对象"bb",而是将strArr[1]这个引用重新指向了一个新的 String 对象"xx"。因此,这是改变了数组元素存储的引用,而不是修改了 String 对象本身。
2.3 使用int[5][]定义一个二维数组,其第二维到底有多长?尝试补全代码,然后使用foreach或其他循环方法遍历这个二维数组?
- 使用
int[5][]定义一个二维数组时,第一维的长度是 5,但第二维的长度没有指定,因此每个第二维数组可以是不同的长度,或者为 null。需要单独初始化每个第二维数组。
补全代码示例:
import java.util.Arrays;
public class TwoDArrayExample {
public static void main(String[] args) {
int[][] twoDimArray = new int[5][]; // 第二维未初始化
// 初始化第二维数组,长度各不相同
twoDimArray[0] = new int[3];
twoDimArray[1] = new int[2];
twoDimArray[2] = new int[4];
twoDimArray[3] = new int[1];
twoDimArray[4] = new int[5];
// 使用foreach遍历
for (int i = 0; i < twoDimArray.length; i++) {
int[] innerArray = twoDimArray[i];
if (innerArray != null) {
for (int value : innerArray) {
System.out.print(value + " ");
}
System.out.println();
} else {
System.out.println("null");
}
}
}
}
类与对象的区别是什么? Math类有对象吗?String类有什么属性是private的,有什么方法是public的,为什么这样设计(尝试举两例说明)?
- 类与对象的区别:类是一个模板或蓝图,定义了对象的属性和行为。对象是类的实例,是具体的数据。例如,String 类定义了字符串的属性和方法,而 String 对象是具体的字符串值。
- Math类有对象吗? Math 类没有对象。Math 类中的所有方法和属性都是 static 的,因此不需要创建对象就可以使用。Math 类设计为不可实例化,通常通过类名直接调用方法,如
Math.abs()。 - String类有什么属性是private的,有什么方法是public的,为什么这样设计?
- String 类内部使用 private 属性来存储字符数据,例如在 Java 8 中,String 类有
private final char value[]字段来存储字符数组。这些属性是 private 的,以防止外部直接修改,确保 String 的不可变性。 - String 类提供了许多 public 方法,如
length()、charAt()、substring()等,这些方法允许读取字符串的内容而不修改它(因为不可变),或者返回新的字符串。 - 为什么这样设计?为了封装和不可变性。封装保护了内部数据不被意外修改,不可变性使得字符串在多线程环境下安全,并且可以缓存哈希值等。例如:
private字段value被封装,外部不能直接访问,只能通过 public 方法操作。- public 方法如
toUpperCase()返回新字符串,而不是修改原字符串,确保了不可变性。
- String 类内部使用 private 属性来存储字符数据,例如在 Java 8 中,String 类有
将类的属性设置为public可以方便其他类访问,但为什么Java中普遍使用setter/getter模式对对象的属性进行访问呢?这与封装性又有什么关系?
- 使用 setter/getter 模式的主要原因是为了封装。封装是面向对象编程的基本原则之一,它隐藏了对象的内部状态,并通过方法来控制对状态的访问和修改。
- 好处:
- 控制访问:可以通过 getter 和 setter 添加验证逻辑。例如,在 setter 中检查输入值是否有效。
- 灵活性:可以在不改变类的外部接口的情况下修改内部实现。例如,如果将来需要计算某个值而不是直接存储,可以修改 getter 方法。
- 只读或只写属性:可以通过只提供 getter 或只提供 setter 来实现。
- 调试和维护:可以在 setter 或 getter 中添加日志或调试代码。
- 与封装性的关系:封装性要求对象的状态不被直接暴露,而是通过方法间接访问。setter/getter 模式正是实现这种间接访问的标准方式。
对象的属性可在什么时候进行初始化?都有哪些进行初始化的办法?
- 对象的属性可以在以下时机进行初始化:
- 声明时直接初始化:例如
private int age = 0; - 在构造器中初始化:通过构造函数赋值。
- 在初始化块中初始化:使用实例初始化块或静态初始化块(对于静态属性)。
- 通过 setter 方法初始化:在对象创建后,通过调用 setter 方法设置值。
- 懒初始化:在 getter 方法中检查属性是否已初始化,如果没有则初始化。
- 声明时直接初始化:例如
示例代码:
public class Example {
private int a = 10; // 直接初始化
private int b;
private int c;
{ // 实例初始化块
b = 20;
}
public Example() {
c = 30; // 构造器初始化
}
public void setC(int value) {
c = value; // 通过方法初始化
}
}
第二部分:Java基本概念、命令行运行、Scanner和字符串比较
使用Java能编写哪些类型的程序?试举至少两个例子。
- Java可以编写多种类型的程序,例如:
- 桌面应用程序:使用Swing或JavaFX构建图形用户界面(GUI)程序,如文本编辑器、计算器等。
- Web应用程序:使用Java EE或Spring框架构建服务器端Web应用,如电子商务网站、社交网络等。
- 移动应用程序:使用Android SDK开发Android应用。
- 企业级应用:如客户关系管理系统(CRM)、企业资源规划(ERP)系统。
- 嵌入式系统:如智能卡、传感器等。
Java号称“一次编译、处处运行”(Write Once, Run Anywhere!),怎么理解这句话?为使编译好的程序能运行,需先在操作系统安装什么?
- "一次编译、处处运行"意味着Java代码只需编译一次,生成的字节码(.class文件)可以在任何支持Java虚拟机(JVM)的平台上运行,而不需要重新编译。这是因为JVM充当了字节码和底层操作系统之间的中介,字节码在JVM上执行,JVM负责将字节码翻译成特定平台的机器码。
- 为使编译好的程序能运行,需要在操作系统上安装Java运行时环境(JRE)或Java开发工具包(JDK),其中包含JVM。
对比c版本的与Java版本HelloWorld代码,有何不同?
C版本的HelloWorld代码:
#include <stdio.h>
int main() {
printf("Hello, World!\n");
return 0;
}
Java版本的HelloWorld代码:
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello, World!");
}
}
不同点:
- 语法结构:C代码使用预处理指令
#include,而Java代码使用类定义。 - 入口点:C程序的入口点是
main函数,返回int类型;Java程序的入口点是main方法,位于类中,返回void,但接受String数组参数。 - 输出语句:C使用
printf,Java使用System.out.println。 - 编译和运行:C代码编译成机器码,直接运行;Java代码编译成字节码,在JVM上运行。
- 面向对象:Java是面向对象的语言,所以代码必须放在类中;C是过程式语言。
怎么比较两个字符串内容是否相同?可以直接用吗?为什么对基本数据类型可以直接使用?对引用数据类型不行?
- 比较两个字符串内容是否相同,应该使用
equals()方法,例如:str1.equals(str2)。 - 不能直接使用
==因为==对于引用类型比较的是引用是否指向同一个对象,而不是内容是否相同。对于基本数据类型,==比较的是值是否相等。 - 对于基本数据类型(如int、char),
==直接比较值,因为变量存储的就是值本身。 - 对于引用数据类型(如String、Object),变量存储的是对象的引用(地址),所以
==比较的是引用是否相同,即是否指向同一个对象。如果要比较内容,需要重写equals()方法。
下面这段代码,本意是要达到什么效果?能运行成功吗?为什么?怎么获得String的trim()方法的说明?
代码:
String x = null;
int length = x.length();
System.out.println("x.length = "+length +", content = "+x.trim());
- 本意可能是想获取字符串
x的长度和修剪后的内容,但x是null。 - 不能运行成功,因为会抛出
NullPointerException。调用x.length()和x.trim()时,x是null,所以会尝试在null引用上调用方法,导致异常。 - 要获得String的trim()方法的说明,可以查看Java官方文档,或使用IDE的文档提示(如Ctrl+Q在IntelliJ IDEA中),或在命令行使用
javadoc。
阅读如下代码
代码:
Integer x = Integer.valueOf("10");
Integer y = x + 1;
int z = x + y;
x是Integer类型,1是int类型,为什么他们可以相加?使用了自动拆箱(autounboxing)技术。当Integer对象与int值相加时,Integer对象自动拆箱为int值,然后进行加法运算。z是int,x与y是Integer类型,却可以直接将x + y赋给z,同样使用了自动拆箱技术。在表达式中,Integer对象自动拆箱为int值,所以x + y结果是int类型,可以直接赋值给int变量z。

浙公网安备 33010602011771号