4,160
社区成员




方法相关问题
public class Main {
static void changeStr(String x) {
x = "xyz";
}
static void changeArr(String[] strs) {
for (int i = 0; i < strs.length; i++) {
strs[i] = strs[i]+""+i;
}
}
public static void main(String[] args) {
String x = "abc";
changeStr(x);
System.out.println(x);
changeArr(args);
System.out.println(Arrays.toString(args));
}
}
对于如上代码:
1.1 changeStr与changeArr的功能各是什么?changeStr方法用于修改传入的字符串参数x,将其改为"xyz";changeArr方法用于修改传入的字符串数组参数strs,将每个元素增加后缀字符串。
1.2 main方法的x有没有被改变?为什么?main方法中的x并没有被改变,因为changeStr方法中操作的是局部变量x,并不会对main方法中的变量产生影响。
1.3 main方法的args数组的内容有没有被改变?为什么?main方法中的args数组的内容被改变了,因为在changeArr方法中对数组元素进行了修改,而且这里修改的是原数组中的元素。
1.4 args数组中的值是从哪里来的?要怎么才能给他赋值。
args数组中的值是从程序运行时命令行传入的,可以在运行时使用命令行参数来给它赋值,比如在命令行中输入 java Main arg1 arg2 arg3,args数组就会包含三个元素 arg1、arg2 和 arg3。
数组相关问题
对于如下程序
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 这段程序输出结果是什么?为什么?
这段程序输出的结果是:
[2, 1, 0] [2, 1, 0]
原因是,首先创建了长度为3的int类型数组arr,然后将其第一个和第二个元素分别赋值为1。接着,将arr的引用赋给了arrX,此时arr和arrX指向同一个数组对象。然后又将arr的第一个元素修改为2。最后分别打印输出arr和arrX数组的内容,发现两个数组都被修改了,并且都是[2, 1, 0]。这是因为arr和arrX指向的是同一个数组对象,修改其中一个数组中的元素,另一个数组也会受到影响。
String[] strArr = {"aa","bb","cc"};
strArr[1] = "xx";
System.out.println(Arrays.toString(strArr));
2.2 字符串是不可变类,为什么可以对strArr[1]赋值"xx"。
虽然字符串被称为不可变类,但实际上这里的赋值操作并没有直接修改原始的字符串对象。在Java中,当执行 strArr[1] = "xx"
这样的赋值操作时,实际上是将新的字符串对象 "xx"
赋值给了数组中的对应位置 strArr[1]
,而不是修改原来的字符串对象 "bb"
。
在 Java 中,字符串是通过字符串常量池(String Pool)来管理的。当创建字符串字面量时(例如 "aa"
、"bb"
、"cc"
),如果字符串常量池中已经存在相同内容的字符串对象,那么会直接返回该对象的引用,而不会重复创建新的字符串对象。这就是为什么我们可以对字符串数组中的某个元素进行赋值,因为实际上是将字符串常量池中的另一个现有的字符串对象的引用赋给了该数组元素。
由于字符串是不可变的,因此任何对字符串的修改都会创建一个新的字符串对象,而不是修改原来的字符串对象。这也是为什么我们不能直接修改字符串中的字符,但可以通过赋值操作来替换整个字符串。
使用int[5][] 定义一个二维数组,其第二维到底有多长?尝试补全代码,然后使用foreach获其他循环方法遍历这个二维数组?
使用int[5][]
定义的二维数组,第二维的长度可以是不确定的,即每个一维数组的长度可以不同。
下面是补全代码并使用不同的循环方法遍历这个二维数组的示例:
int[5][] twoDimArray = new int[5][]; // 初始化二维数组的每个一维数组 twoDimArray[0] = new int[] {1, 2, 3}; twoDimArray[1] = new int[] {4, 5}; twoDimArray[2] = new int[] {6, 7, 8, 9}; twoDimArray[3] = new int[] {10}; twoDimArray[4] = new int[] {11, 12, 13}; // 使用foreach循环遍历二维数组 for (int[] arr : twoDimArray) { for (int num : arr) { System.out.print(num + " "); } System.out.println(); } // 使用普通for循环遍历二维数组 for (int i = 0; i < twoDimArray.length; i++) { for (int j = 0; j < twoDimArray[i].length; j++) { System.out.print(twoDimArray[i][j] + " "); } System.out.println(); } // 使用while循环遍历二维数组 int i = 0; while (i < twoDimArray.length) { int j = 0; while (j < twoDimArray[i].length) { System.out.print(twoDimArray[i][j] + " "); j++; } System.out.println(); i++; }
这段代码定义了一个大小为5的二维数组,并初始化了每个一维数组的内容。然后使用foreach循环、普通for循环和while循环分别遍历二维数组并打印每个元素。
输出结果:
1 2 3 4 5 6 7 8 9 10 11 12 13 1 2 3 4 5 6 7 8 9 10 11 12 13 1 2 3 4 5 6 7 8 9 10 11 12 13
三种不同的循环方法都可以正确遍历这个二维数组。
类与对象的区别是什么? Math类有对象吗?String类有什么属性是private的,有什么方法是public的,为什么这样设计(尝试举两例说明)?
类(Class)是一种抽象的概念,它是对一类具有相同属性和行为的对象进行描述。类定义了对象的特征(属性)和行为(方法),是创建对象的模板。
对象(Object)是类的具体实例化,它是类的一个具体个体,可以拥有类定义的属性和行为,并且可以通过调用对象的方法来执行相关操作。
Math类是Java提供的一个工具类,其中包含了一些数学相关的静态方法,如常见的数学运算、三角函数等。Math类本身是一个抽象的工具类,不需要创建具体的对象来使用其中的方法,因此 Math类没有对象。
String类是Java中表示字符串的类,它属于引用类型。String类内部的许多属性和方法都是通过关键字进行修饰的,例如 private、public 等。
String类的属性中,其中一个私有的属性是 private final char value[]
,该属性是用于存储字符串的字符数组。将该属性声明为私有的,可以保证外部无法直接修改字符串的字符数组,从而确保字符串的不可变性。
String类的方法中,其中一个公开的方法是 public int length()
,该方法用于返回字符串的长度。将该方法设为公开的,可以方便用户获取字符串的长度信息,以便进行后续的处理。
设计 String 类中的属性和方法时采用私有和公开的方式,主要考虑了封装的原则和字符串的不可变性。私有属性可以保护对象内部的数据,只允许通过公开方法进行访问和修改,从而隐藏内部实现细节。同时,将一些常用的操作方法设为公开,方便用户使用,同时强调字符串的不可变性。
举例说明:私有属性 private final char value[]
的设计: 将字符串的字符数组属性声明为私有,确保字符串内容的不可变性。如果允许外部直接修改字符数组,那么字符串的内容就可能被篡改,违反了字符串的不可变性。公开方法 public int length()
的设计: 该方法返回字符串的长度,方便用户获取字符串的长度信息。字符串的长度是一个常见的操作需求,将该方法设为公开可以提供便利,同时强调了字符串类的使用方式,即获取信息而不是直接修改字符串内容。
将类的属性设置为public可以方便其他类访问,但为什么Java中普遍使用setter/getter模式对对象的属性进行访问呢?这与封装性又有什么关系?
在Java中,尽管可以将类的属性设置为public来直接访问和修改,但是普遍使用setter/getter模式对对象的属性进行访问有以下原因: 封装性(Encapsulation):封装是面向对象编程的重要原则之一,它将数据和操作数据的方法封装在类内部,通过公开的接口来控制对数据的访问。使用setter/getter方法可以提供对属性的间接访问,封装了对象内部的属性,并且可以在方法内进行逻辑校验、权限控制等操作,保证了数据的安全性和一致性。 控制访问级别:使用setter/getter方法可以灵活地控制属性的访问级别。通过将属性声明为private,只能在类内部访问,而通过公开的setter/getter方法,可以控制属性的读取和设置的操作,实现了对属性的控制和限制。可以进行验证和逻辑处理:通过setter方法,可以在设置属性值的过程中进行验证和逻辑处理。例如,可以在setter方法中对输入的值进行合法性检查,确保传入的值符合预期范围,从而保证数据的有效性。可以实现延迟加载和懒加载:使用getter方法可以实现属性的延迟加载或懒加载,即在需要的时候才获取属性的值。这种方式可以提高性能和内存的利用效率。提供了更好的封装和兼容性:使用setter/getter方法可以为属性提供更好的封装,可以方便地修改属性的实现细节,而不需要对外部的使用者进行改动。同时,setter/getter方法也提供了更好的兼容性,在后续版本中可以对属性的实现进行修改,而不会对使用该类的外部代码造成影响。
对象的属性可在什么时候进行初始化?都有哪些进行初始化的办法?
对象的属性可以在以下几个时机进行初始化:声明时初始化:在属性声明的同时,直接给属性赋初值。例如:public class MyClass {
private int number = 0;
private String name = "John";
}
构造方法中初始化:在类的构造方法中对属性进行初始化。构造方法是创建对象时调用的方法,可以在其中为属性赋予初始值。例如:
public class MyClass {
private int number;
private String name;
public MyClass() {
number = 0;
name = "John";
}
}
初始化代码块中初始化:使用初始化代码块对属性进行初始化。初始化代码块是在构造方法执行之前被调用的代码块,可以在其中对属性进行赋值操作。例如:
public class MyClass {
private int number;
private String name;
{
number = 0;
name = "John";
}
public MyClass() {
// 构造方法
}
}
实例化代码块中初始化:在类中定义实例化代码块(也称为静态初始化代码块),在创建对象时会先执行实例化代码块,然后再执行构造方法。实例化代码块可以对属性进行初始化。例如:
public class MyClass {
private int number;
private String name;
// 实例化代码块
{
number = 0;
name = "John";
}
public MyClass() {
// 构造方法
}
}
写的不错,下回注意格式.
比如问题要和答案有区隔