第02周 Java基础语法2、面向对象入门

1.方法相关问题

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的功能是接收一个字符串参数,尝试将其值改为 “xyz”,但实际上这种修改不会影响到传入的原始字符串对象。
changeArr的功能是接收一个字符串数组参数,遍历数组,将每个元素加上其对应的下标组成新的字符串,从而修改了传入的字符串数组中的元素内容。

  • 1.2 main方法的x有没有被改变?为什么?

main 方法的 x 没有被改变。在 Java 中,方法参数的传递对于基本数据类型和引用数据类型是不同的。对于基本数据类型是值传递,对于引用数据类型是引用传递,但传递的也是引用的值(即地址的拷贝)。在changeStr方法中,虽然接收了字符串的引用,但将其重新指向了新的字符串 “xyz”,而不会影响到原来传入的字符串引用所指向的对象 “abc”。

  • 1.3 main方法的args数组的内容有没有被改变?为什么?

main 方法的 args 数组的内容被改变了。因为在changeArr方法中,接收的是字符串数组的引用,通过这个引用可以直接操作数组中的元素,所以对数组元素的修改会反映到原始的数组上。

  • 1.4 args数组中的值是从哪里来的?要怎么才能给他赋值。

args 数组中的值是从程序运行时的命令行参数中获取的。可以在运行 Java 程序时在命令行中指定参数,例如:java Main arg1 arg2 arg3,这里的arg1、arg2、arg3就会作为 args 数组的元素。

2.数组相关问题

对于如下程序:

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
原因如下:在 Java 中,数组是引用类型。当执行int[] arrX = arr;时,arrX和arr指向了同一个数组对象在内存中的地址。所以当通过arr修改了数组中的元素值,比如将arr[0]改为 2 时,由于arrX和arr指向同一个数组,所以通过arrX访问这个数组时也会看到修改后的结果。因此,输出的两个数组的内容是一样的。

String[] strArr = {"aa","bb","cc"};
strArr[1] = "xx";
System.out.println(Arrays.toString(strArr));
  • 2.2 字符串是不可变类,为什么可以对strArr[1]赋值"xx"。

在 Java 中,字符串是不可变类,这意味着一旦一个字符串对象被创建,它的内容不能被改变。但是在你的代码中,看起来像是改变了字符串,实际上并不是改变了字符串本身,而是改变了字符串数组中的引用。
当执行String[] strArr = {“aa”,“bb”,“cc”};时,字符串数组中的每个元素都是对一个字符串对象的引用。当执行strArr[1] = “xx”;时,只是将数组中索引为 1 的元素的引用从原来指向的字符串 “bb” 改为指向新创建的字符串 “xx”,而不是改变了原来的字符串 “bb”。
所以,这并不是改变了字符串的不可变性,而是改变了数组中存储的引用所指向的对象。

3.使用int[5][]定义一个二维数组,其第二维到底有多长?尝试补全代码,然后使用foreach获其他循环方法遍历这个二维数组?

在 Java 中,使用int[5][]定义一个二维数组时,只确定了第一维的长度为 5,而第二维的长度是不确定的,可以在后续为每一个第一维的元素分别指定不同长度的第二维数组。

代码补全:

public class TwoDimensionalArrayExample {
    public static void main(String[] args) {
        // 定义二维数组并初始化第一维
        int[][] twoDArray = new int[5][];
        twoDArray[0] = new int[]{1, 2, 3};
        twoDArray[1] = new int[]{4, 5};
        twoDArray[2] = new int[]{6, 7, 8, 9};
        twoDArray[3] = new int[]{10};
        twoDArray[4] = new int[]{11, 12, 13, 14, 15};

        // 使用增强 for 循环遍历二维数组
        for (int[] oneDArray : twoDArray) {
            for (int element : oneDArray) {
                System.out.print(element + " ");
            }
            System.out.println();
        }
    }
}

在上述代码中,首先定义了一个二维数组但未确定第二维的长度。然后分别为每一个第一维的元素指定了不同长度的第二维数组,并使用嵌套的增强 for 循环遍历并输出二维数组中的元素。

4.类与对象的区别是什么? Math类有对象吗?String类有什么属性是private的,有什么方法是public的,为什么这样设计(尝试举两例说明)?

  • 类与对象的区别:

类是一种抽象的概念,是对具有相同属性和行为的一组对象的描述和定义。它定义了对象的属性(成员变量)和行为(方法)。
对象是类的具体实例。是根据类的定义创建出来的具体实体。

  • Math 类有对象吗?

Math 类不能被实例化,即不能通过new Math()的方式创建对象。但是可以直接通过类名来调用其静态方法和静态常量。

  • String类有什么属性是private的,有什么方法是public的,为什么这样设计?

String 类中的字符数组private final char value[]是私有的。这样设计是为了保证字符串的不可变性。如果这个字符数组可以被外部直接访问和修改,那么就无法保证字符串在创建后不会被意外地改变。
String 类中有很多 public 方法,比如length()用于获取字符串的长度,substring()用于截取字符串等。这样设计是为了让用户能够方便地操作字符串对象,同时又通过将内部的字符数组设为私有来保证字符串的安全性和不可变性。

5.将类的属性设置为public可以方便其他类访问,但为什么Java中普遍使用setter/getter模式对对象的属性进行访问呢?这与封装性又有什么关系?

  • 使用 setter/getter 模式的好处:

· 增强代码的可维护性
当属性的实现细节需要改变时,只需要在 setter 和 getter 方法中进行修改,而不会影响到其他使用该属性的代码。例如,如果一个表示日期的类最初使用整数表示年份属性,后来需要改为使用更复杂的日期对象来表示年份,通过 setter/getter 方法可以在不影响其他代码的情况下完成这个改变。
如果直接访问 public 属性,那么所有使用该属性的地方都需要进行修改,这会增加代码维护的难度和风险。
· 提供数据验证和控制
通过 setter 方法,可以在设置属性值之前进行数据验证。比如,对于表示人的年龄的属性,可以在 setter 方法中检查传入的年龄是否合法(大于等于 0),如果不合法可以抛出异常或者进行适当的处理,从而保证数据的正确性。
可以控制属性的读写权限。例如,可以提供一个只读属性,只提供 getter 方法而不提供 setter 方法,这样可以确保该属性的值在对象创建后不能被修改。
· 提高代码的可扩展性
可以在 getter 和 setter 方法中添加额外的逻辑,以满足未来可能出现的新需求。比如,可以在获取属性值时进行一些计算或者转换,或者在设置属性值时触发一些事件或通知其他对象。

  • 与封装性的关系:

封装性是面向对象编程的重要特性之一,它将数据和操作数据的方法封装在一个类中,隐藏内部的实现细节,只对外提供必要的接口。使用 setter/getter 模式是实现封装性的一种重要方式。

6.对象的属性可在什么时候进行初始化?都有哪些进行初始化的办法?

  • 初始化的时机:

· 声明时初始化
· 构造方法中初始化
· 对象创建后立即初始化

  • 初始化的办法:

· 直接赋值
· 使用初始化块
· 调用其他方法进行初始化

7.尝试使用作用域来说明封装性。

在 Java 中,作用域可以很好地说明封装性。封装性是面向对象编程的重要概念之一,它通过将数据和操作数据的方法封装在类中,限制对内部数据的直接访问,从而提高代码的安全性、可维护性和可扩展性。

- 成员变量的作用域与封装性

· 私有成员变量(private)
私有成员变量只能在其所属的类内部被访问。这体现了封装性的核心原则,即隐藏内部实现细节。
· 受保护成员变量(protected)
受保护成员变量可以在其所属的类、子类以及同一个包中的其他类中被访问。
虽然它的作用域比私有变量大一些,但仍然体现了一定程度的封装性。子类可以访问父类的受保护变量,这使得在继承关系中可以实现一定程度的代码复用,同时又不会完全暴露给外部的无关类。
· 公共成员变量(public)
公共成员变量可以在任何地方被访问。虽然这提供了最大的可见性,但也破坏了封装性。
一般情况下,应该尽量避免使用公共成员变量,因为这会使内部数据容易受到外部代码的意外修改,降低了代码的安全性和可维护性。

- 方法的作用域与封装性

· 私有方法(private)
私有方法只能在其所属的类内部被调用。这可以用于封装一些内部的辅助操作,不希望被外部代码直接调用。
· 受保护方法(protected)
受保护方法可以在其所属的类、子类以及同一个包中的其他类中被调用。与受保护成员变量类似,它在继承关系中提供了一定的代码复用性,同时也体现了一定程度的封装性。
· 公共方法(public)
公共方法是对外提供的接口,外部代码可以通过这些方法来访问和操作对象的内部数据。公共方法应该遵循封装性的原则,只暴露必要的功能,隐藏内部实现细节。

综上所述,通过合理地使用不同作用域的成员变量和方法,可以实现封装性,保护内部数据,提高代码的安全性、可维护性和可扩展性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值